Linux杂项设备驱动
生活随笔
收集整理的這篇文章主要介紹了
Linux杂项设备驱动
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、Linux雜項設備驅動簡介
Linux雜項驅動出現的意義在于:有很多簡單的外圍字符設備,它們功能相對簡單,一個設備占用一個主設備號對于內核資源來說太浪費。
所以對于這些簡單的字符設備它們共用一個主設備號,不同的設備使用不同的次設備號.
雜項驅動特點:
主設備號相同,次設備號不同
在文件系統中自動生成設備節點
雜項設備描述結構體
struct miscdevice ?{
int minor;//次設備號
const char *name;//設備的名字
const struct file_operations *fops;//設備的操作函數集
struct list_head list;//將miscdevice串成鏈表使用
struct device *parent;//父設備(設備模型有關)
struct device *this_device;//代表自己的設備(設備模型有關)
};
雜項設備驅動基本原理:
/devices/char/misc.c
static LIST_HEAD(misc_list);//保存所有注冊的雜項設備的鏈表頭
static DEFINE_MUTEX(misc_mtx);
#define DYNAMIC_MINORS 64 //最大可注冊的雜項設備數目
static unsigned char misc_minors[DYNAMIC_MINORS/8];//雜項設備位圖,每位代表該對應的次設備號是否使用
雜項設備注冊過程:
(1)在misc_minors[DYNAMIC_MINORS/8]找一個未使用的次設備號
(2)將新的雜項設備掛在misc_list鏈表中
(3)根據設備號(主設備10+次設備號)新建設備
雜項設備調用過程:
(1)應用程序打開雜項設備節點
(2)根據設備的主設備號得出是雜項設備,調用雜項設備的misc_open
(3)在misc_open中根據次設備號在misc_list鏈表中找出設備
(4)將設備的fops賦值給文件結構體struct file * filestatic?int?__init?misc_init(void)?? {????? ????int?err;????? #ifdef?CONFIG_PROC_FS????? ????/*創建一個proc入口項*/???? ????proc_create("misc",?0,?NULL,?&misc_proc_fops);????????????????????? #endif????? ????/*在/sys/class/目錄下創建一個名為misc的類*/???? ????misc_class?=?class_create(THIS_MODULE,?"misc");????? ????err?=?PTR_ERR(misc_class);????? ????if?(IS_ERR(misc_class))????? ????????goto?fail_remove;????? ????err?=?-EIO;???? ????/*注冊設備,其中設備的主設備號為MISC_MAJOR,為10。設備名為misc,misc_fops是操作函數的集合*/????? ????if?(register_chrdev(MISC_MAJOR,"misc",&misc_fops))????? ????????goto?fail_printk;????? ????return?0;????? ????? fail_printk:????? ????printk("unable?to?get?major?%d?for?misc?devices/n",?MISC_MAJOR);????? ????class_destroy(misc_class);????? fail_remove:????? ????remove_proc_entry("misc",?NULL);????? ????return?err;????? }??? /*misc作為一個子系統被注冊到linux內核中,系統開機后會自動調用misc_init*/???? subsys_initcall(misc_init);?????
當應用程序使用open打開雜項設備時,將根據設備節點的次設備號得到設備真正的操作函數集合
[cpp]?view plain?copystatic?int?misc_open(struct?inode?*?inode,?struct?file?*?file)?? {?? ????int?minor?=?iminor(inode);?? ????struct?miscdevice?*c;?? ????int?err?=?-ENODEV;?? ????const?struct?file_operations?*old_fops,?*new_fops?=?NULL;?? ?????? ????lock_kernel();?? ????mutex_lock(&misc_mtx);?? ????list_for_each_entry(c,?&misc_list,?list)?{//取出misc_list鏈表中次設備號為minor的設備?? ????????if?(c->minor?==?minor)?{?? ????????????new_fops?=?fops_get(c->fops);//獲得該設備的操作函數集合???? ????????????break;?? ????????}?? ????}?? ?????????? ????if?(!new_fops)?{?? ????????mutex_unlock(&misc_mtx);?? ????????request_module("char-major-%d-%d",?MISC_MAJOR,?minor);?? ????????mutex_lock(&misc_mtx);?? ?? ????????list_for_each_entry(c,?&misc_list,?list)?{?? ????????????if?(c->minor?==?minor)?{?? ????????????????new_fops?=?fops_get(c->fops);?? ????????????????break;?? ????????????}?? ????????}?? ????????if?(!new_fops)?? ????????????goto?fail;?? ????}?? ?? ????err?=?0;?? ????old_fops?=?file->f_op;?/*保存舊打開函數的地址*/???? ????file->f_op?=?new_fops;//讓設備的文件結構體中的操作函數指針指向設備的操作函數指針?? ????if?(file->f_op->open)?{?? ????????err=file->f_op->open(inode,file);//調用設備的open函數?? ????????if?(err)?{?? ????????????fops_put(file->f_op);?? ????????????file->f_op?=?fops_get(old_fops);?? ????????}?? ????}?? ????fops_put(old_fops);?? fail:?? ????mutex_unlock(&misc_mtx);?? ????unlock_kernel();?? ????return?err;?? }??
該函數供驅動人員調用。主要的功能有:給設備分配次設備號;根據設備號在/dev目錄下新建設備節點;將雜項設備加入misc_list鏈表
[cpp]?view plain?copyint?misc_register(struct?miscdevice?*?misc)?? {?? ????struct?miscdevice?*c;?? ????dev_t?dev;?? ????int?err?=?0;?? ????INIT_LIST_HEAD(&misc->list);/*初始化misc_list鏈表*/??? ????mutex_lock(&misc_mtx);?? ????????/*遍歷misc_list鏈表,看這個次設備號以前有沒有被用過,如果次設備號已被占有則退出*/???? ????list_for_each_entry(c,?&misc_list,?list)?{?? ????????if?(c->minor?==?misc->minor)?{?? ????????????mutex_unlock(&misc_mtx);?? ????????????return?-EBUSY;?? ????????}?? ????}?? ????????/*?? ?????????*#define?DYNAMIC_MINORS?64?? ?????????*static?unsigned?char?misc_minors[DYNAMIC_MINORS?/?8];???? ?????????*這里存在一個次設備號的位圖,一共64位,下邊是遍歷每一位;??? ?????????*如果這位為0,表示沒有被占有,可以使用,為1表示被占用。?????????? ?????????*/???? ????if?(misc->minor?==?MISC_DYNAMIC_MINOR)?{?? ????????int?i?=?DYNAMIC_MINORS;?? ????????while?(--i?>=?0)?? ????????????if?(?(misc_minors[i>>3]?&?(1?<<?(i&7)))?==?0)?? ????????????????break;?? ????????if?(i<0)?{?? ????????????mutex_unlock(&misc_mtx);?? ????????????return?-EBUSY;?? ????????}?? ????????misc->minor?=?i;//得到可用的次設備號?? ????}?? ?? ????if?(misc->minor?<?DYNAMIC_MINORS)?? ????????misc_minors[misc->minor?>>?3]?|=?1?<<?(misc->minor?&?7);//設置位圖中相應為1?? ????dev?=?MKDEV(MISC_MAJOR,?misc->minor);//計算出設備號?? ????????/*在/dev下創建設備節點,這就是有些驅動程序沒有顯式調用device_create,卻出現了設備節點的原因*/???? ????misc->this_device?=?device_create(misc_class,?misc->parent,?dev,?NULL,"%s",?misc->name);?? ????if?(IS_ERR(misc->this_device))?{?? ????????err?=?PTR_ERR(misc->this_device);?? ????????goto?out;?? ????}?? ?? ????/*將這個miscdevice添加到misc_list鏈表中*/?? ????list_add(&misc->list,?&misc_list);?? ?out:?? ????mutex_unlock(&misc_mtx);?? ????return?err;?? }??
該函數供驅動人員調用。主要功能和misc_register相反:將設備從misc_list中刪除;刪除/dev目錄下的設備
[cpp]?view plain?copyint?misc_deregister(struct?miscdevice?*misc)?? {?? ????int?i?=?misc->minor;//取得設備此設備號?? ????if?(list_empty(&misc->list))?? ????????return?-EINVAL;?? ????mutex_lock(&misc_mtx);?? ????list_del(&misc->list);//將misc從misc_list鏈表中取出?? ????device_destroy(misc_class,?MKDEV(MISC_MAJOR,?misc->minor));//將/dev目錄下的相應設備清除?? ????if?(i?<?DYNAMIC_MINORS?&&?i>0)?{?? ????????misc_minors[i>>3]?&=?~(1?<<?(misc->minor?&?7));//位圖相應為置0?? ????}?? ????mutex_unlock(&misc_mtx);?? ????return?0;?? }??
三、雜項驅動實例
[cpp]?view plain?copy#include?<linux/miscdevice.h>?? #include?<linux/delay.h>?? #include?<asm/irq.h>?? #include?<mach/regs-gpio.h>?? #include?<mach/hardware.h>?? #include?<linux/kernel.h>?? #include?<linux/module.h>?? #include?<linux/init.h>?? #include?<linux/mm.h>?? #include?<linux/fs.h>?? #include?<linux/types.h>?? #include?<linux/slab.h>?? #include?<linux/errno.h>?? #include?<linux/ioctl.h>?? #include?<linux/cdev.h>?? #include?<linux/string.h>?? #include?<linux/list.h>?? #include?<asm/uaccess.h>?? #include?<asm/atomic.h>?? #include?<asm/unistd.h>?? ?? #define?DEVICE_NAME?"led_test"/*注冊驅動時自動建立的設備名稱*/??? #define?IOCTL_GPIO_ON????1?? #define?IOCTL_GPIO_OFF??0?? /*?用來指定LED所用的GPIO引腳?*/?? static?unsigned?long?gpio_table?[]?=?? {?? ????S3C2410_GPB5,?? ????S3C2410_GPB6,?? ????S3C2410_GPB7,?? ????S3C2410_GPB8,?? };?? /*?用來指定GPIO引腳的功能:輸出?*/?? static?unsigned?int?gpio_cfg_table?[]?=?? {?? ????S3C2410_GPB5_OUTP,?? ????S3C2410_GPB6_OUTP,?? ????S3C2410_GPB7_OUTP,?? ????S3C2410_GPB8_OUTP,?? };?? ?? static?int?s3c2440_leds_open(struct?inode?*inode,struct?file?*filp)/*open函數實現的是led的燈的配置:輸出*/??? {?? ????int?i;?? ????for(i=0;i<4;i++)?? ????{?? ????????s3c2410_gpio_cfgpin(gpio_table[i],gpio_cfg_table[i]);?? ????}?? ????return?0;?? }?? ?? static?int?tq2440_gpio_ioctl(struct?inode?*inode,?struct?file?*file,?unsigned?int?cmd,?unsigned?long?arg)/*實現的是led燈的控制*/??? {?? ????if?(arg?>?4)?? ????{?? ????????return?-EINVAL;?? ????}?? ????switch(cmd)?? ????{?? ????????case?IOCTL_GPIO_ON:?? ????????????s3c2410_gpio_setpin(gpio_table[arg],?0);?//?設置指定引腳的輸出電平為0??? ????????????return?0;?? ????????case?IOCTL_GPIO_OFF:?? ????????????s3c2410_gpio_setpin(gpio_table[arg],?1);//?設置指定引腳的輸出電平為1??? ????????????return?0;?? ????????default:?? ????????????return?-EINVAL;?? ????}?? }?? ?? /*驅動框架必備,file_operations?是包含了對這個設備所能進行的操作*/?? static?struct?file_operations?dev_fops?=?{?? ???????.owner???=???THIS_MODULE,?? ???????.ioctl???=???tq2440_gpio_ioctl,?? ???????.open????=???s3c2440_leds_open,?? };?? ?? /*驅動框架必備,驅動信息的打包,用于該驅動程序的注冊*/?? static?struct?miscdevice?misc?=?{????? ????.minor?=?MISC_DYNAMIC_MINOR,?? ????.name?=?DEVICE_NAME,?? ????.fops?=?&dev_fops,?? };?? ?? /*驅動框架必備,驅動初始化函數*/?? static?int?__init?dev_init(void)?? {?? ????int?ret;?? ????ret?=?misc_register(&misc);?? ????printk?(DEVICE_NAME"?initialized\n");?? ????return?ret;?? }?? ?? /*驅動框架必備,驅動退出函數*/?? static?void?__exit?dev_exit(void)?? {?? ????misc_deregister(&misc);?? ????printk?(DEVICE_NAME"?is?over!\n");?? }?? /*驅動框架必備,模塊初始化入口函數*/?? module_init(dev_init);?? /*驅動框架必備,模塊結束入口函數*/?? module_exit(dev_exit);?? /*驅動框架必備,通用公共許可*/?? MODULE_LICENSE("GPL"); ?
Linux雜項驅動出現的意義在于:有很多簡單的外圍字符設備,它們功能相對簡單,一個設備占用一個主設備號對于內核資源來說太浪費。
所以對于這些簡單的字符設備它們共用一個主設備號,不同的設備使用不同的次設備號.
雜項驅動特點:
主設備號相同,次設備號不同
在文件系統中自動生成設備節點
雜項設備描述結構體
struct miscdevice ?{
int minor;//次設備號
const char *name;//設備的名字
const struct file_operations *fops;//設備的操作函數集
struct list_head list;//將miscdevice串成鏈表使用
struct device *parent;//父設備(設備模型有關)
struct device *this_device;//代表自己的設備(設備模型有關)
};
雜項設備驅動基本原理:
/devices/char/misc.c
static LIST_HEAD(misc_list);//保存所有注冊的雜項設備的鏈表頭
static DEFINE_MUTEX(misc_mtx);
#define DYNAMIC_MINORS 64 //最大可注冊的雜項設備數目
static unsigned char misc_minors[DYNAMIC_MINORS/8];//雜項設備位圖,每位代表該對應的次設備號是否使用
雜項設備注冊過程:
(1)在misc_minors[DYNAMIC_MINORS/8]找一個未使用的次設備號
(2)將新的雜項設備掛在misc_list鏈表中
(3)根據設備號(主設備10+次設備號)新建設備
雜項設備調用過程:
(1)應用程序打開雜項設備節點
(2)根據設備的主設備號得出是雜項設備,調用雜項設備的misc_open
(3)在misc_open中根據次設備號在misc_list鏈表中找出設備
(4)將設備的fops賦值給文件結構體struct file * file
二、雜項設備原理分析
Linux雜項設備注冊的使用了主設備號10,提供只有open函數,設備操作函數集的初始化就在該函數中完成。它主要是根據open函數
傳遞的struct inode * inode得到設備的次設備號,然后根據次設備號在misc_list鏈表中查詢得到具體設備的操作函數集。
/devices/char/misc.c
static const struct file_operations misc_fops = {
.owner ?= THIS_MODULE,
.open = misc_open,
};
將雜項設備注冊為字符驅動,主設備號為10,設備操作函數為misc_open
[cpp]?view plain?copy
[cpp]?view plain?copy
[cpp]?view plain?copy
[cpp]?view plain?copy
總結
以上是生活随笔為你收集整理的Linux杂项设备驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: register_chrdev深入分析
- 下一篇: Linux platform总线(1):