日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux杂项设备驱动

發(fā)布時間:2025/3/21 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux杂项设备驱动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、Linux雜項設備驅動簡介
Linux雜項驅動出現的意義在于:有很多簡單的外圍字符設備,它們功能相對簡單,一個設備占用一個主設備號對于內核資源來說太浪費。
所以對于這些簡單的字符設備它們共用一個主設備號,不同的設備使用不同的次設備號.

雜項驅動特點:
主設備號相同,次設備號不同
在文件系統(tǒng)中自動生成設備節(jié)點

雜項設備描述結構體
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)應用程序打開雜項設備節(jié)點
(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
  • static?int?__init?misc_init(void)??
  • {?????
  • ????int?err;?????
  • #ifdef?CONFIG_PROC_FS?????
  • ????/*創(chuàng)建一個proc入口項*/????
  • ????proc_create("misc",?0,?NULL,?&misc_proc_fops);?????????????????????
  • #endif?????
  • ????/*在/sys/class/目錄下創(chuàng)建一個名為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作為一個子系統(tǒng)被注冊到linux內核中,系統(tǒng)開機后會自動調用misc_init*/????
  • subsys_initcall(misc_init);?????
  • 當應用程序使用open打開雜項設備時,將根據設備節(jié)點的次設備號得到設備真正的操作函數集合

    [cpp]?view plain?copy
  • static?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目錄下新建設備節(jié)點;將雜項設備加入misc_list鏈表

    [cpp]?view plain?copy
  • int?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下創(chuàng)建設備節(jié)點,這就是有些驅動程序沒有顯式調用device_create,卻出現了設備節(jié)點的原因*/????
  • ????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?copy
  • int?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杂项设备驱动的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。