深入淺出+Linux字符設(shè)備驅(qū)動程序解析_第1頁
深入淺出+Linux字符設(shè)備驅(qū)動程序解析_第2頁
深入淺出+Linux字符設(shè)備驅(qū)動程序解析_第3頁
深入淺出+Linux字符設(shè)備驅(qū)動程序解析_第4頁
深入淺出+Linux字符設(shè)備驅(qū)動程序解析_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、深入淺出 Linux 字符設(shè)備驅(qū)動程序解析Linux 下的設(shè)備驅(qū)動程序被組織為一組完成不同任務(wù)的函數(shù)的集合,通過這些函數(shù)使得linux 的設(shè)備操作猶如文件一般。在應(yīng)用程序看來,硬件設(shè)備只是一個設(shè)備文件,應(yīng)用程序可以象操作普通文件一樣對硬件設(shè)備進(jìn)行操作,如open 、close 、read 、write 等。Linux 主要將設(shè)備分為二類:字符設(shè)備和塊設(shè)備。字符設(shè)備是指設(shè)備發(fā)送和接收數(shù)據(jù)以字符的形式進(jìn)行;而塊設(shè)備則以整個數(shù)據(jù)緩沖區(qū)的形式進(jìn)行。字符設(shè)備的驅(qū)動相對比較簡單。 下面我們來假設(shè)一個非常簡單的虛擬字符設(shè)備:這個設(shè)備中只有一個4個字節(jié)的全局變量int global_var,而這個設(shè)備的名字叫

2、做"globalvar" 。對"globalvar" 設(shè)備的讀寫等操作即是對其中全局變量global_var的操作。驅(qū)動程序是內(nèi)核的一部分,因此我們需要給其添加模塊初始化函數(shù),該函數(shù)用來完成對所控設(shè)備的初始化工作,并調(diào)用register_chrdev 函數(shù)注冊字符設(shè)備:static int _init globalvar_init(voidif (register_chrdev(MAJOR_NUM, " globalvar ", &gobalvar_fops/注冊失敗else/注冊成功其中,register_chrdev函數(shù)中

3、的參數(shù)MAJOR_NUM為主設(shè)備號, "globalvar" 為設(shè)備名,globalvar_fops為包含基本函數(shù)入口點的結(jié)構(gòu)體,類型為file_operations。當(dāng)globalvar 模塊被加載時,globalvar_init被執(zhí)行,它將調(diào)用內(nèi)核函數(shù)register_chrdev,把驅(qū)動程序的基本入口點指針存放在內(nèi)核的字符設(shè)備地址表中,在用戶進(jìn)程對該設(shè)備執(zhí)行系統(tǒng)調(diào)用時提供入口地址。與模塊初始化函數(shù)對應(yīng)的就是模塊卸載函數(shù),需要調(diào)用register_chrdev的" 反函數(shù)" unregister_chrdev:static void _exit gl

4、obalvar_exit(voidif (unregister_chrdev(MAJOR_NUM, " globalvar "/卸載失敗else/卸載成功隨著內(nèi)核不斷增加新的功能,file_operations結(jié)構(gòu)體已逐漸變得越來越大,但是大多數(shù)的驅(qū)動程序只是利用了其中的一部分。對于字符設(shè)備來說,要提供的主要入口有:open 、release 、read 、write 、ioctl 、llseek 、poll 等。open 函數(shù) 對設(shè)備特殊文件進(jìn)行open 系統(tǒng)調(diào)用時,將調(diào)用驅(qū)動程序的open 函數(shù):int (*open(struct inode * ,struct fil

5、e *; 其中參數(shù)inode 為設(shè)備特殊文件的inode (索引結(jié)點 結(jié)構(gòu)的指針,參數(shù)file 是指向這一設(shè)備的文件結(jié)構(gòu)的指針。open 的主要任務(wù)是確定硬件處在就緒狀態(tài)、驗證次設(shè)備號的合法性(次設(shè)備號可以用 MINOR(inode-> i - rdev 取得 、控制使用設(shè)備的進(jìn)程數(shù)、根據(jù)執(zhí)行情況返回狀態(tài)碼(0表示成功,負(fù)數(shù)表示存在錯誤 等;release 函數(shù) 當(dāng)最后一個打開設(shè)備的用戶進(jìn)程執(zhí)行close 系統(tǒng)調(diào)用時,內(nèi)核將調(diào)用驅(qū)動程序的release 函數(shù):void (*release (struct inode * ,struct file * ; release 函數(shù)的主要任務(wù)是清

6、理未結(jié)束的輸入/輸出操作、釋放資源、用戶自定義排他標(biāo)志的復(fù)位等。read 函數(shù) 當(dāng)對設(shè)備特殊文件進(jìn)行read 系統(tǒng)調(diào)用時,將調(diào)用驅(qū)動程序read 函數(shù):ssize_t (*read (struct file *, char *, size_t, loff_t *; 用來從設(shè)備中讀取數(shù)據(jù)。當(dāng)該函數(shù)指針被賦為NULL 值時,將導(dǎo)致read 系統(tǒng)調(diào)用出錯并返回-EINV AL ("Invalid argument,非法參數(shù)" )。函數(shù)返回非負(fù)值表示成功讀取的字節(jié)數(shù)(返回值為"signed size" 數(shù)據(jù)類型,通常就是目標(biāo)平臺上的固有整數(shù)類型)。globalv

7、ar_read函數(shù)中內(nèi)核空間與用戶空間的內(nèi)存交互需要借助第2節(jié)所介紹的函數(shù): static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *offcopy_to_user(buf, &global_var, sizeof(int;write( 函數(shù) 當(dāng)設(shè)備特殊文件進(jìn)行write 系統(tǒng)調(diào)用時,將調(diào)用驅(qū)動程序的write 函數(shù): ssize_t (*write (struct file *, const char *, size_t, loff_t *; 向設(shè)備發(fā)送數(shù)據(jù)。如果沒有這個函數(shù),wr

8、ite 系統(tǒng)調(diào)用會向調(diào)用程序返回一個-EINV AL 。如果返回值非負(fù),則表示成功寫入的字節(jié)數(shù)。globalvar_write函數(shù)中內(nèi)核空間與用戶空間的內(nèi)存交互需要借助第2節(jié)所介紹的函數(shù): static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *offcopy_from_user(&global_var, buf, sizeof(int;ioctl 函數(shù) 該函數(shù)是特殊的控制函數(shù),可以通過它向設(shè)備傳遞控制信息或從設(shè)備取得狀態(tài)信息,函數(shù)原型為:int (*ioctl (st

9、ruct inode * ,struct file * ,unsigned int ,unsigned long; unsigned int參數(shù)為設(shè)備驅(qū)動程序要執(zhí)行的命令的代碼,由用戶自定義,unsigned long參數(shù)為相應(yīng)的命令提供參數(shù),類型可以是整型、指針等。如果設(shè)備不提供ioctl 入口點,則對于任何內(nèi)核未預(yù)先定義的請求,ioctl 系統(tǒng)調(diào)用將返回錯誤(-ENOTTY ,"No such ioctl fordevice,該設(shè)備無此ioctl 命令" )。如果該設(shè)備方法返回一個非負(fù)值,那么該值會被返回給調(diào)用程序以表示調(diào)用成功。llseek 函數(shù) 該函數(shù)用來修改文件的

10、當(dāng)前讀寫位置,并將新位置作為(正的)返回值返回,原型為:loff_t (*llseek (struct file *, loff_t, int; poll函數(shù) poll 方法是poll 和select 這兩個系統(tǒng)調(diào)用的后端實現(xiàn),用來查詢設(shè)備是否可讀或可寫,或是否處于某種特殊狀態(tài),原型為:unsigned int (*poll (struct file *, struct poll_table_struct *; 我們將在" 設(shè)備的阻塞與非阻塞操作" 一節(jié)對該函數(shù)進(jìn)行更深入的介紹。設(shè)備"gobalvar" 的驅(qū)動程序的這些函數(shù)應(yīng)分別命名為gobalvar_

11、open、 gobalvar_ release 、gobalvar_read、gobalvar_write、gobalvar_ioctl,因此設(shè)備"gobalvar" 的基本入口點結(jié)構(gòu)變量gobalvar_fops 賦值如下:struct file_operations gobalvar_fops = read: gobalvar_read,write: gobalvar_write,;上述代碼中對gobalvar_fops的初始化方法并不是標(biāo)準(zhǔn)C 所支持的,屬于GNU 擴(kuò)展語法。完整的globalvar.c 文件源代碼如下:#include#include#include

12、#includeMODULE_LICENSE("GPL"#define MAJOR_NUM 254 /主設(shè)備號static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*;static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*;/初始化字符設(shè)備驅(qū)動的file_operations結(jié)構(gòu)體struct file_operations globalvar_fops =read: globalvar_read,

13、write: globalvar_write,;static int global_var = 0; /"globalvar"設(shè)備的全局變量static int _init globalvar_init(voidint ret;/注冊設(shè)備驅(qū)動ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops;if (retprintk("globalvar register failure"elseprintk("globalvar register succe

14、ss"return ret;static void _exit globalvar_exit(voidint ret;/注銷設(shè)備驅(qū)動ret = unregister_chrdev(MAJOR_NUM, "globalvar"if (retprintk("globalvar unregister failure"elseprintk("globalvar unregister success"static ssize_t globalvar_read(struct file *filp, char *buf, size_t l

15、en, loff_t *off/將 global_var 從內(nèi)核空間復(fù)制到用戶空間 if (copy_to_user(buf, &global_var, sizeof(int return - EFAULT; return sizeof(int; static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off /將用戶空間的數(shù)據(jù)復(fù)制到內(nèi)核空間的 global_var if (copy_from_user(&global_var, buf, sizeof(int

16、return - EFAULT; return sizeof(int; module_init(globalvar_init; module_exit(globalvar_exit; 運(yùn)行: gcc -D_KERNEL_ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o globalvar.o globalvar.c 編譯代碼,運(yùn)行: inmod globalvar.o 加載 globalvar 模塊,再運(yùn)行: cat /proc/devices 發(fā)現(xiàn)其中多出了"254 globalvar"一行,如下圖: 接

17、著我們可以運(yùn)行: mknod /dev/globalvar c 254 0 創(chuàng)建設(shè)備節(jié)點, 用戶進(jìn)程通過/dev/globalvar 這個路徑就可以訪問到這個全局變量虛擬設(shè) 備了。 我們寫一個用戶態(tài)的程序 globalvartest.c 來驗證上述設(shè)備: #include #include #include #include main int fd, num; /打開"/dev/globalvar" fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR; if (fd != -1 /初次讀 globalvar read(fd, &num, sizeof(int; printf("The globalvar is %dn", num; /寫 globalvar printf("Please input the num written to globalvarn" scanf("%d", # write(fd, &num, sizeof(int;

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論