(五)Linux之设备驱动模型
目錄
- (一)Linux內(nèi)核驅(qū)動(dòng)簡(jiǎn)介
- (二)雜項(xiàng)設(shè)備驅(qū)動(dòng)模型
- (1)相關(guān)接口
- (2)雜項(xiàng)設(shè)備注冊(cè)過程
- (三)早期經(jīng)典字符設(shè)備驅(qū)動(dòng)模型
- (1)相關(guān)接口
- (2)雜項(xiàng)設(shè)備注冊(cè)過程
- (二)雜項(xiàng)和早期經(jīng)典的區(qū)別
(一)Linux內(nèi)核驅(qū)動(dòng)簡(jiǎn)介
對(duì)于剛接觸linux驅(qū)動(dòng)的同學(xué)來(lái)說(shuō),應(yīng)該思考一個(gè)問題就是為什么要有Linux內(nèi)核驅(qū)動(dòng)呢?原因就是Linux內(nèi)核對(duì)設(shè)備的驅(qū)動(dòng)編寫進(jìn)行了規(guī)范。
我們?cè)趌inux系統(tǒng)的/dev目錄下可以查看設(shè)備節(jié)點(diǎn)文件,這些節(jié)點(diǎn)文件是怎么存在的也是值得思考的,本篇文章將會(huì)講解一個(gè)雜項(xiàng)設(shè)備驅(qū)動(dòng)模型、早期經(jīng)典字符設(shè)備驅(qū)動(dòng)模型,都是針對(duì)字符設(shè)備進(jìn)行講解的。
通過ls選項(xiàng)看到,文件權(quán)限前面的符號(hào)表示該文件是字符設(shè)備文件、塊設(shè)備文件或者其他的,每一個(gè)設(shè)備文件都有一個(gè)主設(shè)備號(hào)和一個(gè)次設(shè)備號(hào)
驅(qū)動(dòng)程序?yàn)槌绦騿T開發(fā)后放入內(nèi)核的功能模塊,所以驅(qū)動(dòng)程序本身不屬于內(nèi)核的一部分,導(dǎo)致在向內(nèi)核添加驅(qū)動(dòng)功能的時(shí)候需要向內(nèi)核提出申請(qǐng),即注冊(cè)操作。
(二)雜項(xiàng)設(shè)備驅(qū)動(dòng)模型
雜項(xiàng)設(shè)備:主設(shè)備號(hào)固定為10 的設(shè)備稱為在下個(gè)設(shè)備,Linux驅(qū)動(dòng)中把無(wú)法歸類的五花八門的設(shè)備定義為混雜設(shè)備(用miscdevice結(jié)構(gòu)體表述)。miscdevice共享一個(gè)主設(shè)備號(hào)MISC_MAJOR(即10),但次設(shè)備號(hào)不同。
(1)相關(guān)接口
int misc_register(struct miscdevice * misc)
int:返回值,成功返回0,失敗返回負(fù)數(shù) struct miscdevice * misc:設(shè)備結(jié)構(gòu)體struct miscdevice {int minor; //次設(shè)備號(hào) // 當(dāng)minor的值為255的時(shí)候內(nèi)核會(huì)自動(dòng)分配次設(shè)備號(hào),// 一般采用此方法,因?yàn)樽约褐付ㄈ菀缀鸵延械拇卧O(shè)備號(hào)沖突 const char *name; //設(shè)備節(jié)點(diǎn)名 const struct file_operations *fops;//文件操作指針結(jié)構(gòu)體struct list_head list; //雜項(xiàng)設(shè)備鏈表,使用者不用關(guān)心struct device *parent; //父設(shè)備類,無(wú)需關(guān)心struct device *this_device; //本設(shè)備,無(wú)需關(guān)心const char *nodename; //節(jié)點(diǎn)名umode_t mode; //權(quán)限};注冊(cè)雜項(xiàng)設(shè)備需要關(guān)心的參數(shù):
int minor; //次設(shè)備號(hào)
const char *name; //設(shè)備節(jié)點(diǎn)名
const struct file_operations *fops;//文件操作指針結(jié)構(gòu)體
struct file_operations結(jié)構(gòu)體如下:
struct file_operations {struct module *owner; //一般賦值為THIS_MODULEloff_t (*llseek) (struct file *, loff_t, int);/*ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);char __user *:內(nèi)核空間讀取到文件中的數(shù)據(jù),直接傳遞到用戶空間調(diào)用的read接口中ssize_t read(int fd, void *buf, size_t count);buf中的數(shù)據(jù)即來(lái)源于 char __user **//*ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);const char __user *:用戶層調(diào)用的write接口向文件寫入的數(shù)據(jù)ssize_t write(int fd, const void *buf, size_t count);buf中的數(shù)據(jù)直接傳遞到了const char __user *size_t:數(shù)據(jù)的大小loff_t *指的是寫入數(shù)據(jù)的偏移量 */unsigned int (*poll) (struct file *, struct poll_table_struct *);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);int (*open) (struct inode *, struct file *);int (*release) (struct inode *, struct file *);//內(nèi)核中的release等同于系統(tǒng)的closeint (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *); }; 以int (*open) (struct inode *, struct file *);為例: open指針指向的函數(shù)是用來(lái)接收系統(tǒng)層調(diào)用的open函數(shù)所傳遞的參數(shù)值 struct inode *:保存文件屬性的 struct file *:保存文件操作中的數(shù)據(jù)(2)雜項(xiàng)設(shè)備注冊(cè)過程
下面以一個(gè)例子講解,重點(diǎn)看注冊(cè)函數(shù)misc_register:
miscdevice.c
以上注冊(cè)和注銷都依賴于模塊化編程,不懂的可以參考:Linux內(nèi)核模塊化編程
編寫系統(tǒng)調(diào)用函數(shù)
misc_app.c
Makfile
CFLAG = -C TARGET = miscdevice APP=misc_app KERNEL = /mydriver/linux-3.5 obj-m +=$(TARGET).oall:make $(CFLAG) $(KERNEL) M=$(PWD)arm-linux-gcc -o $(APP) $(APP).c clean:make $(CFLAG) $(KERNEL) M=$(PWD) cleanrm $(APP)使用交叉編譯器編譯msic_app.c后,并且剛剛編寫的miscdevice.c編譯成模塊后
啟動(dòng)tiny4412開發(fā)板查看
注意:
- 1、注冊(cè)成功會(huì)在根文件系統(tǒng)的dev目錄下產(chǎn)生一個(gè)指定的節(jié)點(diǎn)文件
- 2、設(shè)備驅(qū)動(dòng)模型中的接口(文件操作接口)只有上層接口調(diào)用的時(shí)候才會(huì)有效果
- 3、操作驅(qū)動(dòng)模型對(duì)應(yīng)的設(shè)備只需序打開該設(shè)備對(duì)應(yīng)的節(jié)點(diǎn)文件名
(三)早期經(jīng)典字符設(shè)備驅(qū)動(dòng)模型
(1)相關(guān)接口
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops) {return __register_chrdev(major, 0, 256, name, fops); }* @major: major device number or 0 for dynamic allocation* 主設(shè)備號(hào)或者0用來(lái)自動(dòng)分配 * @baseminor: first of the requested range of minor numbers 默認(rèn)為0 * 申請(qǐng)?jiān)O(shè)備號(hào)的起始次設(shè)備號(hào),在此處默認(rèn)為0 * @count: the number of minor numbers required * 申請(qǐng)次設(shè)備號(hào)的個(gè)數(shù) * @name: name of this range of devices * 申請(qǐng)?jiān)O(shè)備號(hào)對(duì)應(yīng)的設(shè)備名 * @fops: file operations associated with this devices * 文件操作結(jié)構(gòu)體static inline void unregister_chrdev(unsigned int major, const char *name)
static inline void unregister_chrdev(unsigned int major, const char *name) {__unregister_chrdev(major, 0, 256, name); }(2)雜項(xiàng)設(shè)備注冊(cè)過程
下面以例子進(jìn)行講解,重點(diǎn)看注冊(cè)函數(shù)register_chrdev:
char_device.c: #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> int major =0; ssize_t chr_read (struct file * fp, char __user * buf, size_t size, loff_t * offset ) {printk(" this is read\n");return 0; } ssize_t chr_write (struct file * fp, char __user * buf, size_t size, loff_t * offset ) {printk(" this is write\n");return 0; } int chr_close (struct inode * node , struct file * file ) {printk(" this is close\n");return 0; } int chr_open (struct inode * node , struct file * file) {printk(" this is open\n");return 0; } struct file_operations fp={.read =chr_read, .write =chr_write,.release =chr_close,.open =chr_open, }; static int __init chardev_init(void) {major = register_chrdev(0, "ming", &fp);printk("this is module init,major =%d\n",major);return 0; } static void __exit chardev_cleanup(void) {unregister_chrdev(major,"ming");printk("this is module exit\n"); } module_init(chardev_init); module_exit(chardev_cleanup); MODULE_LICENSE("GPL");關(guān)于測(cè)試函數(shù)同雜項(xiàng)設(shè)備的misc_app.c和Makefile,在此不重復(fù)寫了,下面看現(xiàn)象
(二)雜項(xiàng)和早期經(jīng)典的區(qū)別
- 1、雜項(xiàng)設(shè)備的主設(shè)備號(hào)固定位10,,早期經(jīng)典設(shè)備的主設(shè)備號(hào)是0-255除10外
- 2、雜項(xiàng)設(shè)備的一個(gè)設(shè)備對(duì)應(yīng)一個(gè)次設(shè)備號(hào),而早期經(jīng)典的模型中,一旦申請(qǐng)成功,則該主設(shè)備號(hào)下的所有次設(shè)備號(hào)均對(duì)應(yīng)一個(gè)設(shè)備,次設(shè)備號(hào)的范圍為0-255
本文章僅供學(xué)習(xí)交流用禁止用作商業(yè)用途,文中內(nèi)容來(lái)水枂編輯,如需轉(zhuǎn)載請(qǐng)告知,謝謝合作
微信公眾號(hào):zhjj0729
微博:文藝to青年
總結(jié)
以上是生活随笔為你收集整理的(五)Linux之设备驱动模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 债券发行价格的计算公式 发行债券的形式
- 下一篇: 护理专科男生当兵在部队能考资格证吗?