linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)_第1頁(yè)
linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)_第2頁(yè)
linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)_第3頁(yè)
linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)_第4頁(yè)
linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)_第5頁(yè)
已閱讀5頁(yè),還剩15頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、linux設(shè)備驅(qū)動(dòng)程序之字符設(shè)備驅(qū)動(dòng)一、linux系統(tǒng)將設(shè)備分為3類(lèi):字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備字將設(shè)備文件t 套接字1、字符設(shè)備:是指只能一個(gè)字節(jié)一個(gè)字節(jié)讀寫(xiě)的設(shè)備,不能隨機(jī)讀取設(shè)備內(nèi)存 中的某一數(shù)據(jù),讀取數(shù)據(jù)需要按照先后數(shù)據(jù)。字符設(shè)備是面向流的設(shè)備,常見(jiàn)的 符設(shè)備有鼠標(biāo)、鍵盤(pán)、串口、led設(shè)備等。字符設(shè)備的上層沒(méi)有文件系統(tǒng),其中 file oprations是字符設(shè)備驅(qū)動(dòng)的核心。2、塊設(shè)備:是指可以從設(shè)備的任意位置讀取一定長(zhǎng)度數(shù)據(jù)的設(shè)備。塊設(shè)備包括 硬盤(pán)、磁盤(pán)、u盤(pán)和sd卡等。塊設(shè)備的上層奮磁盤(pán)文件系統(tǒng)(如ext2、jffs2、 fat等),這些文件系統(tǒng)對(duì)實(shí)現(xiàn)對(duì)vfs的file_oprat

2、ions的成員函數(shù),塊設(shè)備 驅(qū)動(dòng)層看不到file_oprations的存在,磁盤(pán)文件系統(tǒng)和設(shè)備驅(qū)動(dòng)會(huì)將對(duì)磁盤(pán)上 的文件的訪(fǎng)問(wèn)最終轉(zhuǎn)換為對(duì)磁盤(pán)上柱而和扇區(qū)的訪(fǎng)問(wèn)。每一個(gè)字符設(shè)備或塊設(shè)備都在/dev目錄卜*對(duì)應(yīng)一個(gè)設(shè)備文件(或稱(chēng)設(shè)備節(jié) 點(diǎn))。lirmx用戶(hù)程序通過(guò)設(shè)備文件來(lái)使用驅(qū)動(dòng)程序操作字符設(shè)備或塊設(shè)備。二、字符設(shè)備驅(qū)動(dòng)程序基礎(chǔ):1、主設(shè)備號(hào)和次設(shè)備號(hào)(二者一起為設(shè)備號(hào)):一個(gè)字符設(shè)備或塊設(shè)備都有一個(gè)主設(shè)備號(hào)和一個(gè)次設(shè)備號(hào)。主設(shè)備號(hào)是與驅(qū)動(dòng)對(duì)應(yīng)的概念,用來(lái)反映設(shè)備類(lèi)型,同一類(lèi)設(shè)備一般使用相同的主設(shè)備號(hào)(也不 排除在同一主設(shè)備號(hào)下包含一定差異的設(shè)備,因?yàn)橥或?qū)動(dòng)可以支持多個(gè)同類(lèi)設(shè) 備)。次設(shè)備g用

3、來(lái)區(qū)分同類(lèi)型的設(shè)備,用來(lái)描述使用該驅(qū)動(dòng)的設(shè)備的序兮(一 般從0開(kāi)始),即驅(qū)動(dòng)程序利用次設(shè)備號(hào)來(lái)辨別操作的是哪個(gè)設(shè)備。可利用cat /proc/devices查看中請(qǐng)到的設(shè)備號(hào)。linux內(nèi)核中,設(shè)備號(hào)用dev_t來(lái)描述,2. 6. 28中定義如下: typedef u long dev t; /在32位機(jī)中是4個(gè)字節(jié),高12位表示主設(shè) 備號(hào),低12位表示次設(shè)備號(hào)。可以使用下列宏從dev_t中獲得主次設(shè)備號(hào):major(dev_t dev) ; minor(dev_t dev);也可以使用下列宏通過(guò)主次設(shè)備號(hào)生成設(shè)備號(hào)dev_t:mkdev (int major, int minor);/宏定義

4、:define minorbitsdefine mixormasksdefine major (dev) #define minor(dev) #define mkdev(ma, mi)20(1u « minorbits) - 1)(unsigned int) (dev) minorbits) (unsigned int) (dev) & minormask) (ma) « minorbits) | (mi)2、分配設(shè)備號(hào)(兩種方法):(1)靜態(tài)中請(qǐng):int register chrdev region(dev t from, unsigned count, con

5、st char *namc);氺 register_chrdev_region() - register a range of device numbers 氺 from: the first in the desired range of device numbers; must include 氺the major number.* ©count: the number of consecutive device numbers required氺 ©name: the name of the device or driver.* return value is zer

6、o on success, a negative error code on failure.(2)動(dòng)態(tài)分配:int al 1 oc_chrdev_region(dev_t 氺dev, unsigned baseminor, unsigned count, const char *name);/*氺 alloc chrdev region() - register a range of char device numbers* dev: output parameter for first assigned number氺 baseminor: first of the requested r

7、ange of minor numbers* ©count: the number of minor numbers required* ©name: the name of the associated device or driver* allocates a range of char device numbers. the major number will be 氺 chosen dynamically, and returned (along with the first minor number) 氺 in dev. returns zero or a neg

8、ative error code.v3、注銷(xiāo)設(shè)備號(hào):void unregister chrdcv region(dev t from, unsigned count);4、創(chuàng)建設(shè)備文件(設(shè)備節(jié)點(diǎn)):(1) 設(shè)備文件在linux系統(tǒng)中“一切皆文件的思想”把一切都抽象為文件,其中設(shè)備文件 (實(shí)實(shí)在在可見(jiàn)的文件)用來(lái)代表設(shè)備。一般在設(shè)備驅(qū)動(dòng)加載之后創(chuàng)建,在設(shè)備 驅(qū)動(dòng)卸載后移除,對(duì)設(shè)備的操作可通過(guò)對(duì)設(shè)備文件的操作實(shí)現(xiàn),實(shí)現(xiàn)過(guò)程:設(shè)備 文件操作_系統(tǒng)內(nèi)核_設(shè)備驅(qū)動(dòng)_硬件設(shè)備。其中設(shè)備驅(qū)動(dòng)的作用:將對(duì)設(shè)備文 件的操作轉(zhuǎn)換為對(duì)具體硬件的操作(如打開(kāi)、讀、寫(xiě)、定位等)。(2) 創(chuàng)建設(shè)備文件1)、使用mknod

9、手工創(chuàng)建:mknod filename type major minor"type-設(shè)備類(lèi)型:c-字符設(shè)備、b-塊設(shè)備2)、自動(dòng)創(chuàng)建;利用udev(mdev)來(lái)實(shí)現(xiàn)設(shè)備文件的自動(dòng)創(chuàng)建,首先設(shè)保證支持udev(mdev), 由busybox配置。linux內(nèi)核為我們提供了一組函數(shù),可以用來(lái)在模塊加載的時(shí) 候自動(dòng)在/dev h錄下創(chuàng)建相應(yīng)設(shè)備節(jié)點(diǎn),并在卸載模塊時(shí)刪除該節(jié)點(diǎn)。在驅(qū)動(dòng) 初始化代碼里調(diào)用class_crcatc為該類(lèi)設(shè)備創(chuàng)建一個(gè)class,再為每個(gè)設(shè)備調(diào) 用device_create創(chuàng)建對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)。內(nèi)核中定義了 struct class結(jié)構(gòu)體,-個(gè)struct class結(jié)

10、構(gòu)體類(lèi)型變量對(duì) 應(yīng)一個(gè)類(lèi),內(nèi)核同時(shí)提供了 class_create()函數(shù)來(lái)創(chuàng)建一個(gè)類(lèi),存放于sysfs 下面見(jiàn)/sys/class目錄下,一旦創(chuàng)建好了這個(gè)類(lèi),再調(diào)用device create()函數(shù)來(lái)在/dev fi榮下創(chuàng)建相應(yīng)的設(shè)備節(jié)點(diǎn),并在sysfs中注冊(cè)這個(gè)設(shè)備(cremes a device and registers it wiih sysfs) o加載模塊的時(shí)候,用戶(hù)空間中的 udev會(huì)自動(dòng)響應(yīng)device_create ()函數(shù),去/sysfs下尋找對(duì)應(yīng)的炎從而創(chuàng)建 設(shè)備文件。區(qū)別/dev和/sys:1、/dev:該目錄卜是設(shè)備文件,應(yīng)用程序通過(guò)對(duì)這些文件的讀寫(xiě)控制就可 以訪(fǎng)問(wèn)

11、相應(yīng)的硬件設(shè)備了,般在設(shè)備驅(qū)動(dòng)加載的之后創(chuàng)建,在設(shè)備驅(qū)動(dòng)卸載后 移除。設(shè)備文件需要設(shè)備號(hào)才能夠創(chuàng)建,設(shè)備驅(qū)動(dòng)需要設(shè)備號(hào)才能夠被裝載。設(shè) 備文件通過(guò)主設(shè)備號(hào)(反應(yīng)設(shè)備類(lèi)型)冰能找到其對(duì)應(yīng)的驅(qū)動(dòng),設(shè)備驅(qū)動(dòng)利用次 設(shè)備號(hào)才知道他要操作具體哪一個(gè)設(shè)備。注:設(shè)備文件是通過(guò)設(shè)備號(hào)與驅(qū)動(dòng)程序 相關(guān)聯(lián)的。2、/sys: sysfs文件系統(tǒng)(專(zhuān)用于設(shè)備管理)被掛載在此0錄下。linux 設(shè)備驅(qū)動(dòng)模型中的總線(xiàn)(bus_type)、驅(qū)動(dòng)(device_driver)和設(shè)備(device)都可 以在sysfs文件系統(tǒng)中找到對(duì)應(yīng)的節(jié)點(diǎn)。當(dāng)內(nèi)核檢測(cè)到在系統(tǒng)中出現(xiàn)了新的設(shè)備 后,內(nèi)核自動(dòng)在sysfs文件系統(tǒng)中為該設(shè)備生成一

12、項(xiàng)新的記錄(記錄設(shè)備信息。/*氺 device classesvstruct class const char*name;struct module*owner;struct ksetsubsys;struct list_headdevices;struct 1ist_headinterfaces;struct ksetclass_dirs;struct semaphore sem;a locks children, devices,interfaces vstruct class attribute氺class attrs;struct device attribute 氺dev attrs

13、;int (dev uevent) (struct device 氺dev, struct kobj uevent env*cnv);void (*class_release)(struct class *class); void (*dev_release)(struct device *dev);int (suspend) (struct device *dev,pm_message_t state); int (resume) (struct device *dev);class一create ():/*氺 class_create - create a struct class str

14、ucture* owner: pointer to the module that is to "own" this struct class* namc: pointer to a string for the name of this class.* this is used to create a struct class pointer that can then beused氺 in calls to device create().氺 note, the pointer created here is to be destroyed when finished

15、by* making a call to class_destroy().vstruct class 氺class create (struct module 氺owner,const char 氺name)struct class 氺els; int retval;els = kzalloc(sizeof(*cls),gfp kernel); if (!cls) retval = -enomem;goto error;cls->name = name;els->owner = owner;cls->class release = class create release;r

16、etval = class_register(cis); if (retval)goto error;return cis;error:kfree(cls);return errptr(retval);第一個(gè)參數(shù)指定類(lèi)的所有者是哪個(gè)模塊,第二個(gè)參數(shù)指定類(lèi)名。在class, c中,還定義了 class destroy()函數(shù),用于在模塊卸載時(shí)刪除類(lèi)。device create ()函數(shù):/* device create - creates a device and registers it with sysfsclass that this device should bestruct devi

17、ce of this new device,device to be addedname氺 class: pointer to the struct registered to氺 ©parent: pointer to the parent if any* devt: the dev t for the char* fmt: string for the devices氺 this function can be used by char device classes- a struct device* will be created in sysfs, registered to

18、the specified class.* a"dev" file will be created, showing the dev_t for the device, ifthe dev t is not 0,0.* if a pointer to a parent struct device is passed in, the newlycreated氺 struct device will be a child of that device in sysfs.* the pointer to the struct device will be returned fro

19、m the call.* any further sysfs files that might be required can be created using* this pointer.* note: the struct class passed to this function must have previously 氺 been created with a call to class_create().vstruct device 氺device create (struct class 氺class, struct device 氺parent,dev t devt,const

20、 char 氺fmt,)valist vargs; struct device 氺dev;va_start(vargs, fmt);dev 二 device_create_vargs(class, parent, devt, null, fmt,vargs);va_end (vargs); return dev;第一個(gè)參數(shù)指定所要?jiǎng)?chuàng)建的設(shè)備所從屬的類(lèi),第二個(gè)參數(shù)是這個(gè)設(shè)備的父設(shè) 備,如果沒(méi)有就指定為null,第三個(gè)參數(shù)是設(shè)備號(hào),第四個(gè)參數(shù)是設(shè)備名稱(chēng), 第五個(gè)參數(shù)是從設(shè)備號(hào)。三、字符設(shè)備驅(qū)動(dòng)程序中三種重要的數(shù)據(jù)結(jié)構(gòu):(1) struct file(抽象文件):描述-個(gè)打開(kāi)的文件,并存放與文件操作

21、奮關(guān)的 數(shù)據(jù)。內(nèi)核在打開(kāi)一個(gè)文件時(shí)會(huì)為它創(chuàng)建一個(gè)的struct file的變量,存放與該 文件相關(guān)的操作函數(shù)。當(dāng)文件的所有實(shí)例都關(guān)閉之后,內(nèi)核釋放這個(gè)數(shù)據(jù)結(jié)構(gòu)。struct file的重要成員:const struct file_operations *f_op;/該操作是定義文件關(guān)聯(lián)的操作的。內(nèi)核在執(zhí)行open吋對(duì)這個(gè)指針賦值。指向edev的f i le_oprations off_t f_pos;/該文件讀寫(xiě)位置。void *private_data; /該成員是系統(tǒng)調(diào)用時(shí)保存狀態(tài)信息耶常有用的資源。文件的私有數(shù)據(jù)。(2) struct inode :其內(nèi)容由內(nèi)核填寫(xiě),是文件系統(tǒng)連接任何子

22、目錄、文件的 橋梁;內(nèi)核每創(chuàng)建,個(gè)文件就會(huì)定義,個(gè)inode結(jié)構(gòu)用來(lái)記錄文件的物理信息(文件位置、設(shè)備號(hào)等信息)。一個(gè)文件可以對(duì)應(yīng)多個(gè)file結(jié)構(gòu),但只有一個(gè) inode結(jié)構(gòu)。inode 一般作為file operations結(jié)構(gòu)中函數(shù)的參數(shù)傳遞過(guò)來(lái)。每個(gè)存儲(chǔ)設(shè)備或存儲(chǔ)設(shè)備的分區(qū)被格式化為文件系統(tǒng)后,包禽了兩部份.一 部份是block,block是用來(lái)存儲(chǔ)數(shù)據(jù)用的。而另一部份是inode (索引節(jié)點(diǎn)), inode用來(lái)存儲(chǔ)這些數(shù)據(jù)的信總,這些信息包括文件大小、屬主、歸屬的用戶(hù)組、讀寫(xiě)權(quán)限等。linux內(nèi)核每創(chuàng)建一個(gè)設(shè)備文件時(shí),就會(huì)定義一個(gè)struct inode結(jié) 構(gòu)體類(lèi)型的變量,用來(lái)存放該文

23、件的的信息(如該文件位置、設(shè)備號(hào)等物理信息)。 inode為每個(gè)文件進(jìn)行信息索引,所以就有/ inode的數(shù)值。操作系統(tǒng)根據(jù)指令, 能通過(guò)inode值最快的找到相對(duì)應(yīng)的文件。設(shè)備文件通過(guò)設(shè)備號(hào)與設(shè)備驅(qū)動(dòng)程序相關(guān)聯(lián)。dev_t i rdev; /若是設(shè)備文件,該字段記澩了真正的設(shè)備號(hào),在創(chuàng)建設(shè)備文件時(shí)把命令屮的設(shè)備號(hào)賦值給它。struct cdev *i_cdev; /若是字符設(shè)備,k值為其對(duì)應(yīng)的struct cdev結(jié)構(gòu) 指針,其內(nèi)容由驅(qū)動(dòng)程序填寫(xiě)。struct block device *i bdev; /若是塊設(shè)備,其值為其對(duì)應(yīng)的 block device結(jié)構(gòu)體指針i_rdev描述的是哪一

24、類(lèi)設(shè)備,而i_cdev描述的是inode結(jié)構(gòu)變量所描述的 設(shè)備文件的相關(guān)聯(lián)的設(shè)備。字符設(shè)備驅(qū)動(dòng)程序在創(chuàng)建時(shí)會(huì)定義一個(gè)struct cdev 結(jié)構(gòu)體變量,把自己相關(guān)的信息賦值給cdev變量的成員,在字符設(shè)備驅(qū)動(dòng)裝載 時(shí)cdev會(huì)被注冊(cè)到內(nèi)核中,在未打開(kāi)字符設(shè)備文件時(shí)struct inode中的i_cdev 的值為null,當(dāng)打開(kāi)字符設(shè)備文件時(shí),內(nèi)核會(huì)從已注冊(cè)到內(nèi)核中的所有struct cdev變景屮找出與當(dāng)前打開(kāi)的資字符設(shè)備文件具有相同蟲(chóng)設(shè)備號(hào)的struct cdev 變量的指針賦值給i_cdev。下列操作用于從一個(gè)inode結(jié)構(gòu)體變量中獲得主設(shè)備號(hào)和次設(shè)備號(hào): unsigned int ima

25、jor(struct inode 氺inode); unsigned int iminor(struct inode 氺inode);(3) struct file_operations:定義了字符設(shè)備驅(qū)動(dòng)提供給虛擬文件系統(tǒng)的接 口函數(shù)。struct file_operations 氺氺氺_ops=.owner = th1sj10dule, /擁有該結(jié)構(gòu)的模塊的指針,一般為this modules .llseek =* llseek,.read =* read,.write =氺氺氺_write,.ioctl =氺氺氺_ioctl,.open =氺氺氺 open,.release = * re

26、lease,;struct module 氺owner;/*第一個(gè)file operations成員根本不是一個(gè)操作;它是一個(gè)指向擁有這個(gè) 結(jié)構(gòu)的模塊的指針.這個(gè)成員用來(lái)在它的操作還在被使用時(shí)阻止模塊被卸載.幾 乎在所有的時(shí)間中,它被簡(jiǎn)單初始化為宏thts_module,并在irmx/module.h> 中定義。在進(jìn)行簡(jiǎn)單學(xué)習(xí)操作時(shí),一般初始化為this_module。v loff t (氺llseek) (struct file 氺 filp , loff t p, int orig);/* (指針參數(shù)filp為進(jìn)行讀取信息的目標(biāo)文件結(jié)構(gòu)體指針;參數(shù)p為文件定位 的目標(biāo)偏移量;參數(shù)or

27、ig為對(duì)文件定位的起始地址,這個(gè)值可以為文件開(kāi)頭 (seek_set,0,當(dāng)前位置(seek_cur, 1),文件末尾(seek_end,2) 11 seek 方法 用作改變文件中的當(dāng)前讀/寫(xiě)位置,并且新位置作為(正的)返回值.loff_t參數(shù) 是一個(gè)"long offset",并且就算在32位平臺(tái)上也至少64位寬.錯(cuò)誤由一個(gè) 負(fù)返回值指示.如果這個(gè)函數(shù)指針是null, seek調(diào)用會(huì)以潛在地?zé)o法預(yù)知的方 式修改file結(jié)構(gòu)屮的位置計(jì)數(shù)器(在"file結(jié)構(gòu)"一節(jié)屮描述).v ssize_t (氺read) (struct file 氺 filp, cha

28、r _user * buffer, size_t size , loff_t * p);/* (指針參數(shù)filp為進(jìn)行讀取信息的目標(biāo)文件,指針參數(shù)buffer為對(duì)應(yīng)放 置信息的緩沖區(qū)(即用戶(hù)空間內(nèi)存地址),參數(shù)size為要讀取的信息長(zhǎng)度,參 數(shù)p為讀的位置相對(duì)于文件頭的偏移值,在讀取信息后,這個(gè)指針一般都會(huì)移 動(dòng),移動(dòng)的值為讀取信息的長(zhǎng)度值)這個(gè)函數(shù)用來(lái)從設(shè)備中獲取數(shù)據(jù).在這個(gè)位 置的一個(gè)空指針導(dǎo)致read系統(tǒng)調(diào)用以-einval("invalid argument")失敗. 一個(gè)非負(fù)返回值代表了成功讀取的字節(jié)數(shù)(返回值是一個(gè)"signed size"類(lèi)

29、型, 常常是a標(biāo)平臺(tái)本地的整數(shù)類(lèi)型).*/ssize_t (*aio_read)(struct kioeb *, char user * buffer, size_tsize , loff_t p);卜可以看出,這個(gè)函數(shù)的第一、三個(gè)參數(shù)和木結(jié)構(gòu)體中的read()函數(shù)的第一、三個(gè)參數(shù)是不同的,異步讀寫(xiě)的第三個(gè)參數(shù)直接傳遞值,而同步讀寫(xiě)的第三個(gè) 參數(shù)傳遞的是指針,因?yàn)閍io從來(lái)不需要改變文件的位置。異步讀寫(xiě)的第一個(gè)參 數(shù)為指向kiocb結(jié)構(gòu)體的指針,而同步讀寫(xiě)的第一參數(shù)為指向file結(jié)構(gòu)體的指 針,每一個(gè)t/0請(qǐng)求都對(duì)成一個(gè)kiocb結(jié)構(gòu)體);初始化一個(gè)異步讀一可能在函 數(shù)返回前不結(jié)束的讀操作.如

30、果這個(gè)方法是null,所有的操作會(huì)由read代替 進(jìn)行(同步地).(有關(guān)linux異步1/0,可以參考有關(guān)的資料,linux設(shè)備驅(qū)動(dòng) 開(kāi)發(fā)詳解屮給出/詳細(xì)的解答)*/ssize_t (氺write) (struct file 氺 filp, const char _user 氺 buffer, size_t count, loff_t 氺 ppos);/* (參數(shù)hip為目標(biāo)文件結(jié)構(gòu)體指針,buffer為要寫(xiě)入文件的信息緩沖區(qū), count為要寫(xiě)入信息的長(zhǎng)度,ppos為當(dāng)前的偏移位置,這個(gè)值通常是用來(lái)判斷寫(xiě) 文件是否越界)發(fā)送數(shù)據(jù)給設(shè)備.如果null, -einval返回給調(diào)用write系統(tǒng)

31、調(diào)用的程序.如果非負(fù),返冋值代表成功寫(xiě)的字節(jié)數(shù).(注:這個(gè)操作和上面的對(duì) 文件進(jìn)行讀的操作均為阻塞操作)*/ssize t (氺aio write) (struct kiocb 氺,const char user 氺 buffer, size t count, loff t 氺 ppos);/*初始化設(shè)備上的一個(gè)異步寫(xiě).參數(shù)類(lèi)型同aio_read()函數(shù);*/int (*readdir) (struct file * filp, void *,fi 1 ldir_t);/*對(duì)于設(shè)備文件這個(gè)成員應(yīng)當(dāng)為null;它用來(lái)讀取目錄,并且僅對(duì)文件系統(tǒng)有 用.*/unsigned int (氺poll)

32、(struct file 氺filp, struct poll table struct 氺); /* (這是一個(gè)設(shè)備驅(qū)動(dòng)屮的輪詢(xún)函數(shù),第一個(gè)參數(shù)為file結(jié)構(gòu)指針,第二個(gè)為 輪詢(xún)表指針)這個(gè)函數(shù)返冋設(shè)備資源的可獲取狀態(tài),即polltn, pollout, pollpri, pollerr, p0llnval等宏的位“或”結(jié)果。每個(gè)宏都表明設(shè)備的一種 狀態(tài),如:p0llin (定義為0x0001)意味著設(shè)備可以無(wú)阻塞的讀,p0ll0ut (定 義為0x0004)意味著設(shè)備可以無(wú)阻塞的寫(xiě)。(poll方法是3個(gè)系統(tǒng)調(diào)用的后端: poll, epoll,和select,都用作查詢(xún)對(duì)一個(gè)或多個(gè)文件描述

33、符的讀或?qū)懯欠?會(huì)阻塞.poll方法應(yīng)當(dāng)返冋一個(gè)位掩碼指示是杏非阻塞的讀或?qū)懯强赡艿?,?且,可能地,提供給內(nèi)核信息用來(lái)使調(diào)用進(jìn)程睡眠直到1/0變?yōu)榭赡?如果一個(gè)驅(qū)動(dòng)的poll方法為null,設(shè)備假定為不阻塞地可讀可寫(xiě).(這里通常將設(shè)備 看作一個(gè)文件進(jìn)行相關(guān)的操作,而輪詢(xún)操作的取值直接關(guān)系到設(shè)備的響應(yīng)情況, 可以是阻塞操作結(jié)果,同時(shí)也可以是非阻塞操作結(jié)果)*/int (氺ioctl) (struct inode 氺inode, struct file 氺fip, unsigned int cmd, unsigned long arg);/* (inode和filp指針是對(duì)應(yīng)應(yīng)用程序傳遞的文件描

34、述符fd的值和傳遞給 open方法的相同參數(shù).cmd參數(shù)從用戶(hù)那里不改變地傳下來(lái),并丑可選的參數(shù) arg參數(shù)以一個(gè)unsigned long的形式借遞,不管它是么由用戶(hù)給定為一個(gè)整 數(shù)或一個(gè)指針.如果調(diào)用程序不傳遞第3個(gè)參數(shù),被驅(qū)動(dòng)操作收到的arg值是 無(wú)定義的.因?yàn)轭?lèi)型檢查在這個(gè)額外參數(shù)上被關(guān)閉,編譯器不能警告你如果一個(gè) 無(wú)效的參數(shù)被傳遞給ioctl,并且任何關(guān)聯(lián)的錯(cuò)誤將難以奔找.)ioctl系統(tǒng)調(diào) 用提供/發(fā)出設(shè)備特定命令的方法(例如格式化軟盤(pán)的一個(gè)磁道,這不是讀也不 是寫(xiě)).另外,幾個(gè)ioctl命令被內(nèi)核識(shí)別而不必引用fops表.如果設(shè)備不提 供ioctl方法,對(duì)于任何未事先定義的請(qǐng)求(

35、-en0tty,"設(shè)備無(wú)這樣的ioctl"), 系統(tǒng)調(diào)用返回一個(gè)錯(cuò)誤.vint (*mmap) (struct file 本,struct vm area struct 本);/* mmap用來(lái)請(qǐng)求將設(shè)備內(nèi)存映射到進(jìn)程的地址空間.如果這個(gè)方法是null, nimap系統(tǒng)調(diào)用返冋-enodrv.(如果想對(duì)這個(gè)函數(shù)奮個(gè)徹底的了解,那么請(qǐng)看奮 關(guān)“進(jìn)程地址空間”介紹的書(shū)籍)vint (*open) (struct inode * inode , struct file * filp );/* (inode為文件節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)只有一個(gè),無(wú)論用戶(hù)打開(kāi)多少個(gè)文件,都只是 對(duì)應(yīng)著一個(gè)in

36、ode結(jié)構(gòu);但是filp就不同,只要打開(kāi)一個(gè)文件,就對(duì)應(yīng)著一個(gè) file結(jié)構(gòu)體,file結(jié)構(gòu)體通常用來(lái)追蹤文件在運(yùn)行時(shí)的狀態(tài)信息)。盡管這常 常是對(duì)設(shè)備文件進(jìn)行的第一個(gè)操作,不要求驅(qū)動(dòng)聲明一個(gè)對(duì)應(yīng)的方法.如果這 個(gè)項(xiàng)是null,設(shè)備打開(kāi)一直成功,但是你的驅(qū)動(dòng)不會(huì)得到通知.與open 0函數(shù) 對(duì)應(yīng)的是release ()函數(shù)。*/int (*flush) (struct file *);/* flush操作在進(jìn)程關(guān)閉它的設(shè)備文件描述符的拷w時(shí)調(diào)用;它應(yīng)當(dāng)執(zhí)行(并 且等待)設(shè)備的任何未完成的操作.這個(gè)必須不要和用戶(hù)查詢(xún)請(qǐng)求的fsync操作混淆了.當(dāng)前,flush在很少驅(qū)動(dòng)中使用;scsi磁帶驅(qū)動(dòng)使

37、用它,例如,為確 保所有寫(xiě)的數(shù)據(jù)在設(shè)備關(guān)閉前寫(xiě)到磁帶上.如果flush為null,內(nèi)核簡(jiǎn)單地 忽略用戶(hù)應(yīng)用程序的請(qǐng)求.vint (release) (struct inode *, struct file *);/* release 0函數(shù)當(dāng)最后一個(gè)打開(kāi)設(shè)備的用戶(hù)進(jìn)程執(zhí)行close ()系統(tǒng)調(diào)用的時(shí) 候,內(nèi)核將調(diào)用驅(qū)動(dòng)程序release ()函數(shù):void release (struct inode inode, struct file *file),release函數(shù)的要任務(wù)是清理未結(jié)束的輸入輸出 操作,釋放資源,用戶(hù)自定義排他標(biāo)志的復(fù)位等。在文件結(jié)構(gòu)被釋放吋引用這個(gè) 操作.如同 open,

38、 release kt以為 null. */int(synch) (struct file 本,struct dentry 本,int datasync);/刷新待處理的數(shù)據(jù),允許進(jìn)程把所有的臟緩沖區(qū)刷新到磁盤(pán)。int (*aio_fsync)(struct kioeb *, int);/*這是fsync方法的異步版本.所謂的fsync方法是一個(gè)系統(tǒng)調(diào)用函數(shù)。系統(tǒng) 調(diào)用fsync把文件所指定的文件的所有臟緩沖區(qū)寫(xiě)到磁盤(pán)中(如果需要,還括 存有索引節(jié)點(diǎn)的緩沖區(qū))。相應(yīng)的服務(wù)例程獲得文件對(duì)象的地址,并隨后調(diào)用 fsync方法。通常這個(gè)方法以調(diào)用函數(shù)writeback single inodeo結(jié)束

39、,這個(gè) 函數(shù)把與被選屮的索引節(jié)點(diǎn)相關(guān)的臟頁(yè)和索引節(jié)點(diǎn)本身都寫(xiě)回磁盤(pán)。*/ int (*fasync) (int, struct file *, int);/這個(gè)函數(shù)是系統(tǒng)支持異步通知的設(shè)備驅(qū)動(dòng),下面是這個(gè)函數(shù)的模板: static int * fasync(int fd, struct file 氺filp, int mode)struct 氺氺氺 dev 氺 dev=filp->privatedata;return fasync_helper(fd, fi ip, mode, &dev-async_queue) ;/第四個(gè)參 數(shù)為fasync_struct結(jié)構(gòu)體指針的指針。/這

40、個(gè)函數(shù)是用來(lái)處理easync標(biāo)志的函數(shù)。(fasync:表沁兼容bsd的fcntl 同步操作)當(dāng)這個(gè)標(biāo)志改變時(shí),驅(qū)動(dòng)程序中的fasync ()函數(shù)將得到執(zhí)行。a此操作用來(lái)通知設(shè)備它的fasync標(biāo)志的改變.異步通知是一個(gè)高級(jí)的主題, 在第6章中描述.這個(gè)成員可以是null如果驅(qū)動(dòng)不支持異步通知.vint (木lock) (struct file *, int, struct file lock ;/ lock方法用來(lái)實(shí)現(xiàn)文件加鎖;加鎖對(duì)常規(guī)文件是必不可少的特性,但是設(shè) 備驅(qū)動(dòng)幾乎從不實(shí)現(xiàn)它.ssize_t (*readv) (struct file 氺,const struct iovec 氺

41、,unsigned long, loffj *);ssizc t (*writev) (struct file 氺,const struct iovcc 氺,unsigned long, loff_t ;/*這些方法實(shí)現(xiàn)發(fā)散/匯聚讀和寫(xiě)操作.應(yīng)用程序偶爾需要做-個(gè)包含多個(gè)內(nèi) 存ix的單個(gè)讀或?qū)懖僮?這些系統(tǒng)調(diào)用允許它們這樣做而不必對(duì)數(shù)據(jù)進(jìn)行額外拷 貝.如果這些函數(shù)指針為null, read和write方法被調(diào)用(可能多于一次)。*/ ssizc t (*scndfilc) (struct file 氺,loff t 氺,size t, read actor t, void *);/*這個(gè)方法實(shí)

42、現(xiàn)sendfile系統(tǒng)調(diào)用的讀,使用最少的拷w從一個(gè)文件描述符 搬移數(shù)據(jù)到另一個(gè).例如,它被一個(gè)需要發(fā)送文件內(nèi)容到一個(gè)網(wǎng)絡(luò)連接的web 服務(wù)器使用.設(shè)備驅(qū)動(dòng)常常使sendhle為null. vssizc t (sendpage) (struct file 氺,struct page 氺,int, size t, loff t *, int);/* sendpage是sendfile的另一半;它由內(nèi)核調(diào)用來(lái)發(fā)送數(shù)據(jù),一次一頁(yè),到對(duì)應(yīng)的文件.設(shè)備驅(qū)動(dòng)實(shí)際上不實(shí)現(xiàn)sendpage. vunsigned long (氺get unmapped area) (struct file 氺,unsigned

43、 long,unsigned long, unsigned long, unsigned long);/*這個(gè)方法的目的是在進(jìn)程的地址空間找一個(gè)合適的位置來(lái)映射在底層設(shè)備上 的內(nèi)存段中.這個(gè)任務(wù)通常由內(nèi)存管理代碼進(jìn)行;這個(gè)方法存在為了使驅(qū)動(dòng)能強(qiáng) 制特殊設(shè)備可能有的任何的對(duì)齊請(qǐng)農(nóng)大部分驅(qū)動(dòng)可以置這個(gè)方法null. 10 */ int (check flags)(int)/這個(gè)方法允許模塊檢奔傳遞給fnctl (f_setfl.)調(diào)用的標(biāo)志. int (*dir_notify)(struct file *, unsigned long);/這個(gè)方法在成用程序使用fcntl來(lái)請(qǐng)求0錄改變通知時(shí)調(diào)用.

44、只對(duì)文件系 統(tǒng)有用;驅(qū)動(dòng)不需要實(shí)現(xiàn)dir_notify.四、字符設(shè)備驅(qū)動(dòng)程序設(shè)計(jì):1、設(shè)備注冊(cè):在linux2. 6內(nèi)核屮,使用struct cdev來(lái)描述一個(gè)字符設(shè)備;struct cdevstruct kobject kobj;/ 內(nèi)嵌的 kobject 對(duì)象struct module *owner;/ 所屬模塊struct f i le_operat ions *ops; / 文件操作結(jié)構(gòu)體 struct list_head list;dev_t dev;/設(shè)備號(hào),長(zhǎng)度為32位,其中高12為主設(shè)備號(hào),低20位為次設(shè)備號(hào)unsigned int count;字符設(shè)備的注冊(cè)分為三個(gè)步驟:(1

45、) 分 酉己 cdev: struct cdev cdev alloc(void);(2) 初$臺(tái)化 cdev: void cdev init (struct cdcv 氺cdev, const structfile_operations 氺fops);(3) 添力口(注冊(cè))cdev: int cdev_add(struct cdev *p,dev_t dev, unsigned count)注:在注冊(cè)cdev前,應(yīng)該先申請(qǐng)?jiān)O(shè)備號(hào)(靜態(tài)分配或動(dòng)態(tài)分配)。氺 cdev add() - add a char device to the system 氺 p: the cdev structure

46、for the device* dev: the first device number for which this device is responsible 氺 ©count: the number of consecutive minor numbers corresponding to this* device氺 氺 cdev_add() adds the device represented by p to the system, making it * live immediately. a negative error code is returned on fail

47、ure.2、設(shè)備操作的實(shí)現(xiàn):file_0perati0ns函數(shù)集的實(shí)現(xiàn)(要明確某個(gè)函數(shù)什么 吋候被調(diào)用?調(diào)用來(lái)做什么操作?)特別注意:驅(qū)動(dòng)程序應(yīng)用程序的數(shù)據(jù)交換:驅(qū)動(dòng)程抒和應(yīng)用程抒的數(shù)據(jù)交換是非常重要的。file operations中read () 和writeo函數(shù),就是用來(lái)在驅(qū)動(dòng)程序和應(yīng)用程序間交換數(shù)據(jù)的。通過(guò)數(shù)據(jù)交換, 驅(qū)動(dòng)程序和應(yīng)用程序可以彼此了解對(duì)方的情況。但是驅(qū)動(dòng)程序和應(yīng)用程序?qū)儆诓?同的地址空間。驅(qū)動(dòng)程序不能直接訪(fǎng)問(wèn)應(yīng)用程序的地址空間;同樣應(yīng)用程序也不 能直接訪(fǎng)問(wèn)驅(qū)動(dòng)程序的地址空間,否則會(huì)破壞彼此令間中的數(shù)據(jù),從而造成系統(tǒng) 崩潰,或者數(shù)據(jù)損壞。安全的方法是使用內(nèi)核提供的專(zhuān)用函數(shù)

48、,完成數(shù)據(jù)在應(yīng)用 程序空間和驅(qū)動(dòng)程序空間的交換。這些函數(shù)對(duì)用戶(hù)程序傳過(guò)來(lái)的指針進(jìn)行丫嚴(yán)格 的檢查和必要的轉(zhuǎn)換,從而保證用戶(hù)程序與驅(qū)動(dòng)程序交換數(shù)據(jù)的安全性。這些函 數(shù)有:unsigned long copy to user (void user 氺to, const void 氺from, unsigned long n);unsigned long copy_from_user (void 氺to, const void user 氺from, unsigned long n);put_user(local, user);get user (local, user);3.設(shè)備注銷(xiāo):void cdev del (struct cdev *

溫馨提示

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

評(píng)論

0/150

提交評(píng)論