1.申請(qǐng)?jiān)O(shè)備號(hào)
? ? ? ?驅(qū)動(dòng)結(jié)構(gòu)體填充完畢后,需要注冊(cè)到內(nèi)核之中,其中有三種方法來注冊(cè)設(shè)備驅(qū)動(dòng):
(1) 動(dòng)態(tài)注冊(cè)申請(qǐng)?jiān)O(shè)備號(hào) + cdev? 注冊(cè)設(shè)備驅(qū)動(dòng)
? ? ? ?在不知道設(shè)備號(hào)的情況下,通過動(dòng)態(tài)注冊(cè)驅(qū)動(dòng)申請(qǐng)到的設(shè)備號(hào)并存到dev_t 類型中,通過cdev_init將驅(qū)動(dòng)結(jié)構(gòu)體ops賦值給cdev->ops,然后通過cdev_add將cdev結(jié)構(gòu)體與設(shè)備號(hào)關(guān)聯(lián)。
動(dòng)態(tài)注冊(cè)并申請(qǐng)?jiān)O(shè)備號(hào)API:
? ? alloc_chrdev_region(dev_t*dev, unsigned baseminor, unsigned count, constchar *name)
? ? dev:? ? ? ? ? ? ? ?alloc_chrdev_region函數(shù)向內(nèi)核申請(qǐng)下來的設(shè)備號(hào)結(jié)構(gòu)體
? ? baseminor :? ?次設(shè)備號(hào)的起始
? ? count:? ? ? ? ? ? 申請(qǐng)次設(shè)備號(hào)的個(gè)數(shù)
? ? name :? ? ? ? ? ?執(zhí)行cat?/proc/devices顯示的名稱
cdev的使用:
? ? a. 執(zhí)行cdev_init函數(shù),將cdev和file_operations關(guān)聯(lián)起來
? ? b. 使用cdev_add函數(shù),將cdev和設(shè)備號(hào)關(guān)聯(lián)起來
卸載API:
? ? unregister_chrdev_region(dev *dev, int num);
eg:??
? ? 驅(qū)動(dòng)動(dòng)態(tài)設(shè)備號(hào)注冊(cè)實(shí)例:? flashlight_devno為被賦值的結(jié)構(gòu)體變量

? ? cdev_init原型

? ? cdev_add原型

? ? cdev卸載API: void cdev_del(structcdev *p)
(2) 靜態(tài)申請(qǐng)?jiān)O(shè)備號(hào) + cdev 注冊(cè)設(shè)備驅(qū)動(dòng)
? ? 在已知驅(qū)動(dòng)主設(shè)備號(hào)的情況下,可以通過靜態(tài)注冊(cè)驅(qū)動(dòng)。其步驟與動(dòng)態(tài)注冊(cè)有些區(qū)別。需要先定義一個(gè)dev_t結(jié)構(gòu)體,然后通過MKDEV將主設(shè)備號(hào)與此設(shè)備號(hào)合成賦值給dev_t。
靜態(tài)注冊(cè)驅(qū)動(dòng)API:
? ? int register_chrdev_region(dev_t*dev, unsigned int count, char *name);
? ? dev: 由已知的主設(shè)備號(hào)合成的設(shè)備號(hào)結(jié)構(gòu)體MKDEV(major,mnior)的返回值
? ? count: 申請(qǐng)此設(shè)備號(hào)個(gè)數(shù)
? ? name: 設(shè)備名 出現(xiàn)在/proc/devices
卸載靜態(tài)注冊(cè)API:
? ? unregister_chrdev_region(dev *dev, int num);
eg.靜態(tài)注冊(cè)獲取設(shè)備號(hào),其中major為已經(jīng)被賦值的變量

(3) 自動(dòng)識(shí)別靜態(tài)、動(dòng)態(tài)分配
? ? 程序也可以自動(dòng)選擇靜態(tài)或動(dòng)態(tài)分配API:
? ? int register_chrdev(unsigned int num, const char *name,struct file_operations *ops)
? ? num:為0時(shí)動(dòng)態(tài)注冊(cè),非零時(shí)以num為主設(shè)備號(hào)靜態(tài)注冊(cè)。
? ? Name:設(shè)備名
? ? ops: 驅(qū)動(dòng)結(jié)構(gòu)體
卸載API:int unregister_chrdev(unsigned int major, const? char *name)
? ? 與上兩個(gè)注冊(cè)方法不同的是,int register_chrdev會(huì)自動(dòng)將ops與設(shè)備號(hào)關(guān)聯(lián),不用手動(dòng)cdev_init、cdev_add。且當(dāng)創(chuàng)建class節(jié)點(diǎn)需要設(shè)備號(hào)結(jié)構(gòu)體時(shí),需要MKDEV(major,minor)返回值。但是此API較為耗資源。
eg.自動(dòng)識(shí)別靜態(tài)、動(dòng)態(tài)分配

根據(jù)主次設(shè)備號(hào)獲取設(shè)備號(hào)結(jié)構(gòu)體API:
? ? dev_num=MKDEV(major,minor);? major是一個(gè)表示設(shè)備號(hào)的主設(shè)備號(hào),minor次設(shè)備號(hào)
根據(jù)設(shè)備號(hào)結(jié)構(gòu)體獲取主次設(shè)備號(hào)API:
? ? major = MAJOR(dev_num); 獲取主設(shè)備號(hào)
? ? minor = MINOR(dev_num); 獲取從設(shè)備號(hào)
? ? 設(shè)備注冊(cè)成功后,在/pro/device可查看
2.創(chuàng)建節(jié)點(diǎn)
? ? 設(shè)備注冊(cè)進(jìn)去后,需要?jiǎng)?chuàng)建節(jié)點(diǎn)才可以使驅(qū)動(dòng)被調(diào)用。
? ? 在/sys/class創(chuàng)建節(jié)點(diǎn)類API:
? ? struct class *class_create(structmodule *owner, const char *name)
?? ?owner:模塊所有者
? ? name: 指定類名?? //在/sys/下可見
? ? 在/sys/class/name已知類節(jié)點(diǎn)下創(chuàng)建設(shè)備節(jié)點(diǎn)API:
? ? struct device *device_create(struct class*cls, struct device *parent, dev_t devt, void *drvdata,const char *fmt, ...);
? ? eg.創(chuàng)建節(jié)點(diǎn)

? ? 注意:/sys/class/xx/device與/dev/device區(qū)別(xx表示設(shè)備類名,device表示設(shè)備名)
? ? 在驅(qū)動(dòng)注冊(cè)成功后,需要軟件創(chuàng)建設(shè)備節(jié)點(diǎn)。在設(shè)備節(jié)點(diǎn)創(chuàng)建成功后,內(nèi)核就會(huì)在/dev/下生成設(shè)備名。其中/dev/下存的是真實(shí)的設(shè)備,/sys/class/xx/存的是設(shè)備節(jié)點(diǎn)名,反映驅(qū)動(dòng)設(shè)備的層次。調(diào)用驅(qū)動(dòng)時(shí)需要將/dev下的設(shè)備作為路徑,也可以通過設(shè)備節(jié)點(diǎn)名再下一級(jí)的節(jié)點(diǎn)傳參。即”/sys/class/xx/device”不能作為調(diào)用路徑,”/dev/device”可以作為調(diào)用路徑。