Linux下的設備驅動程序被組織為一組完成不同任務的函數的集合,通過這些函數使得linux的設備操作猶如文件一般。在應用程序看來,硬件設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬件設備進行操作,如open()、close()、read()、write() 等。
Linux主要將設備分為二類:字符設備和塊設備。字符設備是指設備發送和接收數據以字符的形式進行;而塊設備則以整個數據緩沖區的形式進行。字符設備的驅動相對比較簡單。
下面我們來假設一個非常簡單的虛擬字符設備:這個設備中只有一個4個字節的全局變量int global_var,而這個設備的名字叫做"globalvar"。對"globalvar"設備的讀寫等操作即是對其中全局變量global_var的操作。
驅動程序是內核的一部分,因此我們需要給其添加模塊初始化函數,該函數用來完成對所控設備的初始化工作,并調用register_chrdev() 函數注冊字符設備:
|
其中,register_chrdev函數中的參數MAJOR_NUM為主設備號, "globalvar"為設備名,globalvar_fops為包含基本函數入口點的結構體,類型為file_operations。當globalvar模塊被加載時,globalvar_init被執行,它將調用內核函數register_chrdev,把驅動程序的基本入口點指針存放在內核的字符設備地址表中,在用戶進程對該設備執行系統調用時提供入口地址。
與模塊初始化函數對應的就是模塊卸載函數,需要調用register_chrdev()的"反函數"
|
隨著內核不斷增加新的功能,file_operations結構體已逐漸變得越來越大,但是大多數的驅動程序只是利用了其中的一部分。對于字符設備來說,要提供的主要入口有:open()、release()、read()、write()、ioctl()、llseek()、poll()等。
open()函數 對設備特殊文件進行open()系統調用時,將調用驅動程序的open() 函數:
int (*open)(struct inode * ,struct file *);
其中參數inode為設備特殊文件的inode (索引結點) 結構的指針,參數file是指向這一設備的文件結構的指針。open()的主要任務是確定硬件處在就緒狀態、驗證次設備號的合法性(次設備號可以用 MINOR(inode-> i - rdev) 取得)、控制使用設備的進程數、根據執行情況返回狀態碼(0表示成功,負數表示存在錯誤)等;
release()函數 當最后一個打開設備的用戶進程執行close ()系統調用時,內核將調用驅動程序的release() 函數:
void (*release) (struct inode * ,struct file *) ;
release 函數的主要任務是清理未結束的輸入/輸出操作、釋放資源、用戶自定義排他標志的復位等。
read()函數 當對設備特殊文件進行read() 系統調用時,將調用驅動程序read()函數:
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
用來從設備中讀取數據。當該函數指針被賦為NULL 值時,將導致read 系統調用出錯并返回-EINVAL("Invalid argument,非法參數")。函數返回非負值表示成功讀取的字節數(返回值為"signed size"數據類型,通常就是目標平臺上的固有整數類型)。
globalvar_read函數中內核空間與用戶空間的內存交互需要借助第2節所介紹的函數:
|
write( ) 函數 當設備特殊文件進行write () 系統調用時,將調用驅動程序的write () 函數:
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
向設備發送數據。如果沒有這個函數,write 系統調用會向調用程序返回一個-EINVAL。如果返回值非負,則表示成功寫入的字節數。
globalvar_write函數中內核空間與用戶空間的內存交互需要借助第2節所介紹的函數:
|
ioctl() 函數 該函數是特殊的控制函數,可以通過它向設備傳遞控制信息或從設備取得狀態信息,函數原型為:
int (*ioctl) (struct inode * ,struct file * ,unsigned int ,unsigned long);
unsigned int參數為設備驅動程序要執行的命令的代碼,由用戶自定義,unsigned long參數為相應的命令提供參數,類型可以是整型、指針等。如果設備不提供ioctl 入口點,則對于任何內核未預先定義的請求,ioctl 系統調用將返回錯誤(-ENOTTY,"No such ioctl fordevice,該設備無此ioctl 命令")。如果該設備方法返回一個非負值,那么該值會被返回給調用程序以表示調用成功。