- 論壇徽章:
- 0
|
一、linux的設(shè)備驅(qū)動(dòng)程序與外界的接口可以分為三個(gè)部分:
1.驅(qū)動(dòng)程序與操作系統(tǒng)內(nèi)核的接口。通過file_operations(include/linux/fs.h)數(shù)據(jù)結(jié)構(gòu)來完成的。
2.驅(qū)動(dòng)程序與系統(tǒng)引導(dǎo)的接口。這部分利用驅(qū)動(dòng)程序?qū)υO(shè)備進(jìn)行初始化。
3.驅(qū)動(dòng)程序與設(shè)備的接口。這部分描述了驅(qū)動(dòng)程序如何與設(shè)備進(jìn)行交互,與具體的設(shè)備密切相關(guān)。
二、根據(jù)功能劃分,設(shè)備驅(qū)動(dòng)程序的代碼有以下幾部分:
1.驅(qū)動(dòng)程序的注冊和注銷。
2.設(shè)備的打開和釋放。
3.設(shè)備的讀寫操作。
4.設(shè)備的控制操作。
5.設(shè)備的中斷和輪詢處理。
三、驅(qū)動(dòng)程序的注冊和注銷:
設(shè)備驅(qū)動(dòng)程序可以在系統(tǒng)啟動(dòng)的時(shí)候初始化,也可以在需要的時(shí)候動(dòng)態(tài)加載。字符設(shè)備的初始化由chr_dev_init()完成,包括對內(nèi)存(devfs_register_chrdev(MEM_MAJOR,"mem",&memory_fops)),終端(tty_init()),打印機(jī)(lp_init()),鼠標(biāo)(misc_init())等字符設(shè)備的初始化。
塊設(shè)備初始化由blk_dev_init()完成,這包括對IDE硬盤(ide_init()),軟盤(floppy_init()),光驅(qū)等塊設(shè)備的初始化。
每個(gè)字符設(shè)備或是塊設(shè)備的初始化都是通過devfs_register_chrdev()或是devfs_register_blkdev()向內(nèi)核注冊。在關(guān)閉字符設(shè)備或是塊設(shè)備時(shí),還需要通過devfs_unregister_chrdev()或是devfs_unregister_blkdev()從內(nèi)核中注銷設(shè)備。
四、設(shè)備的打開和釋放:
打開設(shè)備是由open()來完成的。例如,打印機(jī)是用lp_open()打開的,而硬盤是用hd_open()打開的。在大部分設(shè)備驅(qū)動(dòng)程序中,open完成如下工作:
1.增加設(shè)備的是用計(jì)數(shù)。
2.檢查設(shè)備的相關(guān)錯(cuò)誤,如設(shè)備尚未準(zhǔn)備好或是類似硬件的問題。
3.檢查是首次打開,則初始化設(shè)備。
4.識別次設(shè)備號,如有必要?jiǎng)t更新f_op指針。
5.如果需要,分配且設(shè)置要放在filp->private_data里的數(shù)據(jù)結(jié)構(gòu)。
釋放設(shè)備由release()來完成,例如釋放打印機(jī)是用lp_release(),而釋放終端設(shè)備是用tty_release()。釋放設(shè)備的一般步驟包括:
1.釋放在filp->private_data中的open分配的內(nèi)存。
2.如果是最后一次釋放,則關(guān)閉設(shè)備。
3.遞減設(shè)別的使用計(jì)數(shù)。
五、設(shè)備的讀寫操作:
字符設(shè)備使用各自的read()和write()來進(jìn)行數(shù)據(jù)讀寫。例如,對虛擬終端的讀寫是通過vcs_read()和vcs_write()來進(jìn)行數(shù)據(jù)讀寫的。
塊設(shè)備使用通用的generic_file_read()和generic_file_write()來進(jìn)行數(shù)據(jù)讀寫。這兩個(gè)通用函數(shù)向請求表添加讀寫請求,內(nèi)核可以通過ll_rw_block()優(yōu)化請求順序。由于是對內(nèi)存緩沖區(qū)而不是設(shè)備進(jìn)行操作的,因而可以加快讀寫請求。如果內(nèi)存緩沖區(qū)內(nèi)沒有要讀入的數(shù)據(jù)或是要將寫請求寫入設(shè)備,那么就要真正的執(zhí)行數(shù)據(jù)傳輸。這是通過數(shù)據(jù)結(jié)構(gòu)request_queue和request_fn()來完成 (include/linux/blkdev.h)。
六、設(shè)備的控制操作:
除了讀寫操作,有時(shí)還要控制設(shè)備。這可以通過設(shè)備驅(qū)動(dòng)程序中的ioctl()來完成。例如IDE硬盤的控制可以通過hd_ioctl(),對光驅(qū)的控制可以通過cdrom_ioctl()。
與讀寫操作不同,ioctl()的用法與具體設(shè)備密切相關(guān)。以軟驅(qū)的floppy_ioctl()為例(drivers/block/floppy.c):
static int fd_ioctl(struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long param);
其中,cmd的取值及含義都是與軟驅(qū)有關(guān)的,比如,F(xiàn)DEJECT表示彈出軟盤。
除了ioctl(),設(shè)備驅(qū)動(dòng)程序還可能有其他控制函數(shù),比如llseek()等。
七、設(shè)備的輪詢和中斷處理:
對于不支持中斷的設(shè)備,讀寫時(shí)需要輪詢設(shè)備狀態(tài),以及是否需要繼續(xù)進(jìn)行數(shù)據(jù)傳輸。例如,打印機(jī)。如果設(shè)備支持中斷,則可按照中斷方式進(jìn)行。
本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/72336/showart_1075397.html |
|