創(chuàng)建字符設(shè)備
~/study/linuxlerning/linux-4.9.37/driver_test
Linux字符設(shè)備是一種按字節(jié)來(lái)訪問(wèn)的設(shè)備陌僵,字符驅(qū)動(dòng)則負(fù)責(zé)驅(qū)動(dòng)字符設(shè)備荤堪,這樣的驅(qū)動(dòng)通常實(shí)現(xiàn)open良价、close庸汗、read和write系統(tǒng)調(diào)用柠座。例如:串口迄损、Led省有、按鍵等浩销。
創(chuàng)建字符設(shè)備文件的方法
1贯涎、使用命令 mknod /dev/文件名 c 主設(shè)備號(hào) 此設(shè)備號(hào)(查看主設(shè)備號(hào):cat /proc/devices)
文件系統(tǒng)與字符設(shè)備驅(qū)動(dòng)程序之間的關(guān)系
1慢洋、在Linux系統(tǒng)中塘雳,每一個(gè)打開的文件普筹,在內(nèi)核中都會(huì)關(guān)聯(lián)一個(gè)struct file結(jié)構(gòu),它是由內(nèi)核在打開文件時(shí)創(chuàng)建太防,在文件關(guān)閉后釋放
struct file結(jié)構(gòu)中的重要成員
struct file_operations* f_op; //文件操作函數(shù)集
loff_t f_pos; //文件讀寫指針
2妻顶、每一個(gè)存在于文件系統(tǒng)中的文件都會(huì)關(guān)聯(lián)一個(gè)inode結(jié)構(gòu),該結(jié)構(gòu)主要用來(lái)記錄文件物理上的信息杏头。因此,它和代表打開文件的file結(jié)構(gòu)是不同的呢燥,一個(gè)文件沒(méi)有被打開時(shí)不會(huì)關(guān)聯(lián)file結(jié)構(gòu),但是會(huì)關(guān)聯(lián)一個(gè)inode結(jié)構(gòu)(存于磁盤寓娩,操作文件是在內(nèi)存中建立相應(yīng)的映射結(jié)構(gòu))
3叛氨、系統(tǒng)實(shí)質(zhì)上是把字符設(shè)備的注冊(cè)表看成了文件呼渣。其中chrdevs[]在內(nèi)核的定義如下
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor;
int minorct;
char name[64];
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
4寞埠、 字符設(shè)備在內(nèi)核中使用struct cdev來(lái)描述
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops; //設(shè)備操作函數(shù)集
struct list_head list;
dev_t dev; //設(shè)備號(hào)
unsigned int count; //設(shè)備數(shù)
};
5、Linux內(nèi)核中使用dev_t類型來(lái)定義設(shè)備號(hào)仁连,dev_t其實(shí)質(zhì)為32位unsigned int類型,其中高12位為主設(shè)備號(hào)使鹅,低20位為次設(shè)備號(hào)昌抠。
(1)MKDEV(主設(shè)備號(hào)患朱,次設(shè)備號(hào))
(2)MAJOR(dev_t dev)
(3)MINOR(dev_t dev)
注:字符設(shè)備文件與字符設(shè)備驅(qū)動(dòng)是通過(guò)主設(shè)備號(hào)建立對(duì)應(yīng)關(guān)系炊苫;驅(qū)動(dòng)程序用次設(shè)備號(hào)來(lái)區(qū)分同類型的設(shè)備
設(shè)備號(hào)的申請(qǐng)與注銷
(1)靜態(tài)申請(qǐng):開發(fā)者自己選擇一個(gè)數(shù)字作為主設(shè)備號(hào),通過(guò)函數(shù) register_chardev_region 向內(nèi)核申請(qǐng)
(2)動(dòng)態(tài)分配:使用 alloc_chrdev_region 由內(nèi)核分配一個(gè)可用的主設(shè)備號(hào)(推薦使用)
(3)不論使用何種方法分配設(shè)備號(hào)执虹,都應(yīng)該在驅(qū)動(dòng)退出時(shí)蒋畜,使用 unregister_chrdev_region 函數(shù)釋放這些設(shè)備
字符設(shè)備描述結(jié)構(gòu)的分配、注冊(cè)與注銷
- 字符設(shè)備描述結(jié)構(gòu)的分配姻成、注冊(cè)與注銷
(1)cdev變量的定義可以采用靜態(tài)和動(dòng)態(tài)兩種方法
* 靜態(tài)分配:struct cdev mdev;
* 動(dòng)態(tài)分配:struct cdev* pdev = cdev_alloc();(可以通過(guò)命令:cat /proc/devices查看主設(shè)備號(hào))
(2)cdev變量的初始化使用cdev_init()函數(shù)來(lái)完成
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
cdev: 待初始化的cdev結(jié)構(gòu)
fops: 設(shè)備對(duì)應(yīng)的操作函數(shù)集
(3)字符設(shè)備的注冊(cè)使用cdev_add()函數(shù)來(lái)完成
(4)字符設(shè)備的注銷使用cdev_del()函數(shù)來(lái)完成
設(shè)計(jì)Linux字符設(shè)備驅(qū)動(dòng)程序的主要工作:
(1)根據(jù)外部設(shè)備的特點(diǎn),實(shí)現(xiàn)file_operations結(jié)構(gòu)所需要的函數(shù)
(2)調(diào)用函數(shù)cdev_alloc()函數(shù)向系統(tǒng)動(dòng)態(tài)申請(qǐng)一個(gè)cdev結(jié)構(gòu)實(shí)例
(3)調(diào)用函數(shù)cdev_init()初始化cdev實(shí)例均牢,并建立cdev實(shí)例與file_operations實(shí)例之間的連接
(4)調(diào)用函數(shù)alloc_chrdev_region()向系統(tǒng)申請(qǐng)一個(gè)設(shè)備號(hào)
(5)調(diào)用函數(shù)cdev_add()向系統(tǒng)添加一個(gè)設(shè)備
(6)調(diào)用函數(shù)cdev_del()從系統(tǒng)刪除一個(gè)cdev結(jié)構(gòu)實(shí)例
注:如果把驅(qū)動(dòng)程序制作成一個(gè)內(nèi)核模塊才睹,上述的第(2)、(3)琅攘、(4)、(5)步應(yīng)在模塊的初始化函數(shù)中實(shí)現(xiàn)哨查,而第(6)步應(yīng)在模塊的卸載函數(shù)中實(shí)現(xiàn)
一鍵創(chuàng)建
register_chrdev(major,fops)) 創(chuàng)建
1剧辐、第一個(gè)參數(shù)靜態(tài)申請(qǐng)?jiān)O(shè)備號(hào)邮府,如果是0溉奕,則系統(tǒng)隨機(jī)分配
2、fops
__unregister_chrdev() 注銷