- 論壇徽章:
- 0
|
本帖最后由 陳廟紅 于 2016-08-02 08:53 編輯
字符設(shè)備驅(qū)動(dòng)模型
一、驅(qū)動(dòng)初始化步驟
1.1分配設(shè)備描述結(jié)構(gòu)
1.2初始化設(shè)備描述結(jié)構(gòu)
1.3.注冊(cè)設(shè)備描述結(jié)構(gòu)
1.4.硬件初始化
二設(shè)備描述結(jié)構(gòu)
在任何一種驅(qū)動(dòng)模型,字符、網(wǎng)卡驅(qū)動(dòng)等,設(shè)備都會(huì)用內(nèi)核的一種結(jié)構(gòu)來(lái)描述。我們的字符設(shè)備在內(nèi)核中使用struct cdev來(lái)描述
struct cdev{
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_lead list;
dev_t dev;//設(shè)備號(hào)
unsigned int count;//設(shè)備數(shù)
};
三、設(shè)備號(hào)
1主設(shè)備號(hào)
字符設(shè)備文件如何與字符驅(qū)動(dòng)程序建立關(guān)系?
通過(guò)字符設(shè)備文件找到字符驅(qū)動(dòng)程序,字符設(shè)備文件與字符驅(qū)動(dòng)程序?qū)?yīng)數(shù)字相同,即主設(shè)備號(hào)設(shè)備相同
我們創(chuàng)建字符設(shè)備文件時(shí)。cat /proc/devices查看設(shè)備驅(qū)動(dòng)程序的主設(shè)備號(hào),然后在根據(jù)這個(gè)主設(shè)備下建立一個(gè)同樣主設(shè)備號(hào)的字符設(shè)備文件,主設(shè)備號(hào)反應(yīng)設(shè)備類(lèi)型。
2.次設(shè)備號(hào)
一個(gè)驅(qū)動(dòng)程序并不是只可以處理一個(gè)設(shè)備,例如開(kāi)發(fā)板上面的3個(gè)串口只有一個(gè)串口驅(qū)動(dòng)程序,但3個(gè)串口會(huì)對(duì)應(yīng)3個(gè)不同的設(shè)備文件,3個(gè)設(shè)備文件的不同之處是次設(shè)備號(hào),不同的次設(shè)備號(hào)區(qū)分同類(lèi)型的不同設(shè)備。應(yīng)用程序帶調(diào)用3個(gè)設(shè)備文件,所以次設(shè)備號(hào)不同,3個(gè)設(shè)備文件需要通過(guò)主設(shè)備號(hào)訪(fǎng)問(wèn)同一個(gè)驅(qū)動(dòng)程序,因而主設(shè)備號(hào)相同,如果3個(gè)設(shè)備文件沒(méi)有其他信息,則驅(qū)動(dòng)程序也無(wú)法區(qū)分是哪個(gè)文件,所以不同文件的次設(shè)備號(hào)不同。
3.linux內(nèi)核中使用dev_t,通過(guò)source insight查詢(xún)到即為32位的unsigned int, 其中高12位為主設(shè)備號(hào),低20位為次設(shè)備號(hào)。
主設(shè)備號(hào)和次設(shè)備號(hào)組合成dev_t類(lèi)型
dev_t dev = MKDEV(主設(shè)備號(hào),次設(shè)備號(hào));
dev_t分解主設(shè)備號(hào)
次設(shè)備號(hào)=NAJOR(dev_t dev);
dev_t分解次設(shè)備號(hào)
次設(shè)備號(hào)=MINOR(dev_t dev);
4.設(shè)備號(hào)分配
次設(shè)備號(hào)可以自己定義,但主設(shè)備分配的不對(duì)會(huì)造成沖突。
4.1.靜態(tài)申請(qǐng)
開(kāi)發(fā)者自己選擇一個(gè)數(shù)字作為主設(shè)備號(hào),然后通過(guò)函數(shù)register_chrdev_region向內(nèi)核申請(qǐng)使用。缺點(diǎn):如果申請(qǐng)
使用的設(shè)備號(hào)已經(jīng)被內(nèi)核中的其他驅(qū)動(dòng)使用了,則申請(qǐng)失敗。
4.2動(dòng)態(tài)分配
使用alloc_chrdev_region由內(nèi)核分配一個(gè)可用的主設(shè)備號(hào)。優(yōu)點(diǎn):因?yàn)閮?nèi)核知道哪些號(hào)已經(jīng)被使用了,所以不會(huì)導(dǎo)致分
配到已經(jīng)被使用的號(hào)。
5.設(shè)備號(hào)注銷(xiāo)
在退出來(lái)注銷(xiāo)設(shè)備號(hào),unregister_chrdev_region函數(shù)釋放設(shè)備號(hào)
四、操作函數(shù)集
struct file_operations是一個(gè)函數(shù)指針的集合,定義能在設(shè)備上進(jìn)行操作。結(jié)構(gòu)中的函數(shù)指針指向驅(qū)動(dòng)中的函數(shù)。
struct file_operations dev_fops{
.llseek = NULL;
.read = dev_read;
.write = dev_write;
.ioctl = dev_ioctl;
.open = dev_open;
.release = dev_release;
};
五、驅(qū)動(dòng)初始化
5.1分配設(shè)備描述結(jié)構(gòu)。字符設(shè)備是cdev
cdev變量的定義采用動(dòng)態(tài)和靜態(tài)分配
靜態(tài):struct cdev mdev
動(dòng)態(tài):struct cdev *pdev = cdev_alloc();
5.2描述結(jié)構(gòu)初始化
struct_cdev的初始化使用cdev_init函數(shù)來(lái)完成
cdev_init(struct cdev *cdev,const struct file_operation *fops)
參數(shù):
cdev:待初始化的cdev結(jié)構(gòu)
fops:設(shè)備對(duì)應(yīng)的操作函數(shù)集5.3
5.3字符設(shè)備注冊(cè)
字符設(shè)備注冊(cè)使用cdev_add函數(shù)來(lái)完成
cdev_add(struct cdev *p,dev_t dev,unsigned count)
參數(shù):
p:待添加到內(nèi)核的字符設(shè)備結(jié)構(gòu)
dev:設(shè)備號(hào)
count:該設(shè)備的設(shè)備個(gè)數(shù)
六.硬件初始化
實(shí)現(xiàn)設(shè)備操作
int (*open)(struct inode*,struct file *)
打開(kāi)設(shè)備,響應(yīng)open系統(tǒng)
int (*release)(struct inode *,struct file *)
關(guān)閉設(shè)備,響應(yīng)close系統(tǒng)調(diào)用
loff_t (*llseek) (struct file *, loff_t, int)
重定位讀寫(xiě)指針,響應(yīng)lseek系統(tǒng)調(diào)用
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)
從設(shè)備讀取數(shù)據(jù),響應(yīng)read系統(tǒng)調(diào)用
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)
向設(shè)備寫(xiě)入數(shù)據(jù),響應(yīng)write系統(tǒng)調(diào)用
設(shè)備操作函數(shù)參數(shù)分析,函數(shù)里面都使用了struct file類(lèi)型
linux系統(tǒng)中,每一個(gè)打開(kāi)的文件,在內(nèi)核中都會(huì)關(guān)聯(lián)一個(gè)struct file,它由打開(kāi)文件時(shí)創(chuàng)建,在文件關(guān)閉后釋放
重要成員:
loff_t f_pos/*文件讀寫(xiě)指針*/
struct file_operation *fop/*該文件所對(duì)應(yīng)的操作*/
struct inode
每一個(gè)存在于文件系統(tǒng)里面的文件都會(huì)關(guān)聯(lián)一個(gè)inode結(jié)構(gòu),該結(jié)構(gòu)主要用來(lái)記錄文件上的信息,因此,它和代表打開(kāi)文件的file結(jié)構(gòu)是不同的。一個(gè)文件沒(méi)有被打開(kāi)時(shí)不會(huì)關(guān)聯(lián)file結(jié)構(gòu),但是卻會(huì)關(guān)聯(lián)一個(gè)inode結(jié)果。
重要成員:
devt i_rdev:設(shè)備號(hào)
struct inode記錄文件物理信息
1.設(shè)備操作-open
open設(shè)備方法是驅(qū)動(dòng)程序用來(lái)為以后的操作完成初始化準(zhǔn)備工作的,在大部分驅(qū)動(dòng)程序中,open完成如下工作
標(biāo)明次設(shè)備號(hào)
啟動(dòng)設(shè)備
2.release方法的作用正好與open相反。這個(gè)設(shè)備方法有時(shí)也稱(chēng)為close,它應(yīng)該:
關(guān)閉設(shè)備
3.read設(shè)備方法通常完成2件事情:
從設(shè)備中讀取數(shù)據(jù)(屬于硬件訪(fǎng)問(wèn)類(lèi)操作)
將讀取到的數(shù)據(jù)返回給應(yīng)用程序
ssize_t (*read) (struct file *filp, char __user *buff, size_t count, loff_t *offp)
參數(shù)分析:
filp:與字符設(shè)備文件關(guān)聯(lián)的file結(jié)構(gòu)指針, 由內(nèi)核創(chuàng)建。
buff : 從設(shè)備讀取到的數(shù)據(jù),需要保存到的位置。由read系統(tǒng)調(diào)用提供該參數(shù)。
count: 請(qǐng)求傳輸?shù)臄?shù)據(jù)量,由read系統(tǒng)調(diào)用提供該參數(shù)。
offp: 文件的讀寫(xiě)位置,由內(nèi)核從file結(jié)構(gòu)中取出后,傳遞進(jìn)來(lái)。
buff參數(shù)是來(lái)源于用戶(hù)空間的指針,這類(lèi)指針都不能被內(nèi)核代碼直接引用,必須使用專(zhuān)門(mén)的函數(shù)
int copy_from_user(void *to, const void __user *from, int n)
int copy_to_user(void __user *to, const void *from, int n)//read使用
write設(shè)備方法通常完成2件事情:
1.從應(yīng)用程序提供的地址中取出數(shù)據(jù)
2.將數(shù)據(jù)寫(xiě)入設(shè)備(屬于硬件訪(fǎng)問(wèn)類(lèi)操作)
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)
其參數(shù)類(lèi)似于read
七、驅(qū)動(dòng)注銷(xiāo)
cdev_del函數(shù)來(lái)完成字符設(shè)備的注銷(xiāo)
|
|