多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開源 > 綜合技術(shù) > linux系統(tǒng)中misc子系統(tǒng)

linux系統(tǒng)中misc子系統(tǒng)

來(lái)源:程序員人生   發(fā)布時(shí)間:2015-01-23 08:59:14 閱讀次數(shù):8204次

misc子系統(tǒng)


轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/wang_zheng_kai

光源器件與系統(tǒng)研究所

個(gè)人學(xué)習(xí)總結(jié)

1、在linux系統(tǒng)中甚么是misc?

         在研究攝像頭驅(qū)動(dòng)的時(shí)候,發(fā)現(xiàn)攝像頭驅(qū)動(dòng)的路徑為:/driver/misc/jz_cim/文件目錄下,經(jīng)過(guò)查找結(jié)果以下:

         雜項(xiàng)裝備(misc device)

         雜項(xiàng)裝備也是嵌入式系統(tǒng)中用得比較多的1種裝備驅(qū)動(dòng)。在 Linux 內(nèi)核的include/linux目錄下有miscdevice.h文件,要把自己定義的misc device從裝備定義在這里。實(shí)際上是由于這些字符裝備不符合預(yù)先肯定的字符裝備范疇,所有這些裝備采取主編號(hào)10 ,1起歸于misc device,其實(shí)misc_register就是用主標(biāo)號(hào)10調(diào)用register_chrdev()的,只不過(guò)misc是將1些字符裝備寄存在misc類中。換句話說(shuō),misc裝備其實(shí)也就是特殊的字符裝備。

        

2、linux內(nèi)核雜項(xiàng)裝備驅(qū)動(dòng)源碼分析

       在Linux驅(qū)動(dòng)中把沒(méi)法歸類的5花8門的裝備定義為混雜裝備(用miscdevice結(jié)構(gòu)體表述)。miscdevice同享1個(gè)主裝備號(hào)MISC_MAJOR(即10),但次裝備號(hào)不同。所有的miscdevice裝備構(gòu)成了1個(gè)鏈表,對(duì)裝備訪問(wèn)時(shí)內(nèi)核根據(jù)次裝備號(hào)查找對(duì)應(yīng)的miscdevice裝備,然后調(diào)用其file_operations結(jié)構(gòu)中注冊(cè)的文件操作接口進(jìn)行操作。在內(nèi)核中用struct miscdevice表示miscdevice裝備,然后調(diào)用其file_operations結(jié)構(gòu)中注冊(cè)的文件操作接口進(jìn)行操作。miscdevice的API實(shí)現(xiàn)在drivers/char/misc.c中,misc裝備的初始化,注冊(cè),注銷都在這個(gè)文件中。在內(nèi)核中,misc雜項(xiàng)裝備驅(qū)動(dòng)接口是對(duì)1些字符裝備的簡(jiǎn)單封裝,他們同享1個(gè)主裝備號(hào),有不同的次裝備號(hào),同享1個(gè)open調(diào)用,其他的操作函數(shù)在打開后應(yīng)用linux驅(qū)動(dòng)程序的方法重載進(jìn)行裝載。

 

我們首先先來(lái)看misc裝備的結(jié)構(gòu)體的描寫:

         代碼位于:android⑷.1/kernel/include/linux/miscdevice.h,該文件中還有所有misc裝備的次裝備號(hào)的宏定義。

struct miscdevice { intminor; //次裝備號(hào) const char*name; //裝備的名稱 const structfile_operations *fops; //文件操作 structlist_head list; //misc_list的鏈表頭 struct device*parent; //父裝備(Linux裝備模型中的東東了,哈哈) struct device*this_device; //當(dāng)前裝備,是device_create的返回值,下邊會(huì)看到 constchar *nodename; mode_tmode; };

         這個(gè)結(jié)構(gòu)體是misc裝備基本的結(jié)構(gòu)體,在注冊(cè)misc裝備的時(shí)候必須要聲明并初始化1個(gè)這樣的結(jié)構(gòu)體,但其中1般只需填充name minor fops字段就能夠了。下面就是led驅(qū)動(dòng)程序中初始化miscdevice的代碼:

static struct miscdevice misc = { .minor =MISC_DYNAMIC_MINOR, .name =DEVICE_NAME, .fops =&dev_fops, };

    1般的時(shí)候在fops不用實(shí)現(xiàn)open方法,由于最初的方法misc_ops包括了open方法。其中minor如果填充MISC_DYNAMIC_MINOR,則是動(dòng)態(tài)次裝備號(hào),次裝備號(hào)由misc_register動(dòng)態(tài)分配的。

 

然后來(lái)看看misc子系統(tǒng)的初始化函數(shù):

static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL,&misc_proc_fops); /*創(chuàng)建1個(gè)proc入口項(xiàng)*/ #endif misc_class =class_create(THIS_MODULE, "misc"); /*在/sys/class/目錄下創(chuàng)建1個(gè)名為misc的類*/ err = PTR_ERR(misc_class); if(IS_ERR(misc_class)) gotofail_remove; err =-EIO; /*注冊(cè)裝備,其中裝備的主裝備號(hào)為MISC_MAJOR,為10。裝備名為misc,misc_fops是操作函數(shù)的集合*/ if(register_chrdev(MISC_MAJOR,"misc",&misc_fops)) gotofail_printk; misc_class->devnode= misc_devnode; return0; 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); returnerr; } subsys_initcall(misc_init); /*misc作為1個(gè)子系統(tǒng)被注冊(cè)到linux內(nèi)核中*/

         可以看出,這個(gè)初始化函數(shù),最主要的功能就是注冊(cè)字符裝備 ,所用的注冊(cè)接口是2.4內(nèi)核的register_chrdev。它注冊(cè)了主裝備號(hào)為MISC_MAJOR,次裝備號(hào)為0⑵55的256個(gè)裝備。并且創(chuàng)建了1個(gè)misc類。

 

下邊是register_chrdev函數(shù)的實(shí)現(xiàn):

int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops) { structchar_device_struct *cd; struct cdev*cdev; char *s; int err =-ENOMEM; /*主裝備號(hào)是10,次裝備號(hào)為從0開始,分配256個(gè)裝備*/ cd =__register_chrdev_region(major, 0, 256, name); if(IS_ERR(cd)) returnPTR_ERR(cd); /*分配字符裝備*/ cdev =cdev_alloc(); if(!cdev) gotoout2; cdev->owner = fops->owner; cdev->ops= fops; /*Linux裝備模型中的,設(shè)置kobject的名字*/ kobject_set_name(&cdev->kobj, "%s", name); for (s =strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) *s ='!'; /*把這個(gè)字符裝備注冊(cè)到系統(tǒng)中*/ err =cdev_add(cdev, MKDEV(cd->major, 0), 256); if (err) gotoout; cd->cdev =cdev; return major? 0 : cd->major; out: kobject_put(&cdev->kobj); out2: kfree(__unregister_chrdev_region(cd->major, 0, 256)); returnerr; } 來(lái)看看這個(gè)裝備的操作函數(shù)的集合: static const struct file_operations misc_fops = { .owner =THIS_MODULE, .open = misc_open, };

可以看到這里只有1個(gè)打開函數(shù),用戶打開miscdevice裝備是通過(guò)主裝備號(hào)對(duì)應(yīng)的打開函數(shù),在這個(gè)函數(shù)中找到次裝備號(hào)對(duì)應(yīng)的相應(yīng)的具體裝備的open函數(shù)。它的實(shí)現(xiàn)以下:

 

static int misc_open(struct inode * inode,struct file * file) { intminor = iminor(inode); structmiscdevice *c; interr = -ENODEV; const struct file_operations *old_fops, *new_fops = NULL; lock_kernel(); mutex_lock(&misc_mtx); /*找到次裝備號(hào)對(duì)應(yīng)的操作函數(shù)集合,讓new_fops指向這個(gè)具體裝備的操作函數(shù)集合*/ list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { new_fops = fops_get(c->fops); break; } } if(!new_fops) { mutex_unlock(&misc_mtx); /*如果沒(méi)有找到,則要求加載這個(gè)次裝備號(hào)對(duì)應(yīng)的模塊*/ request_module("char-major-%d-%d", MISC_MAJOR, minor); mutex_lock(&misc_mtx); /*重新遍歷misc_list鏈表,如果沒(méi)有找到就退出,否則讓new_fops指向這個(gè)具體裝備的操作函數(shù)集合*/ 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; /*保存舊打開函數(shù)的地址*/ old_fops = file->f_op; /*讓主裝備號(hào)的操作函數(shù)集合指針指向具體裝備的操作函數(shù)集合*/ file->f_op = new_fops; if(file->f_op->open) { /*使用具體裝備的打開函數(shù)打開裝備*/ err=file->f_op->open(inode,file); 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; }


再來(lái)看看misc子系統(tǒng)對(duì)外提供的兩個(gè)重要的API,misc_register,misc_deregister:

         misc_register()函數(shù)在misc.c中,最主要的功能是基于misc_class構(gòu)造1個(gè)裝備,將miscdevice結(jié)構(gòu)掛載到misc_list列表上,并初始化與linux裝備模型相干的結(jié)構(gòu),它的參數(shù)是miscdevice結(jié)構(gòu)體。

int misc_register(struct miscdevice *misc) { struct miscdevice *c; dev_t dev; interr = 0; INIT_LIST_HEAD(&misc->list); //鏈表項(xiàng)使用時(shí)必須初始化 mutex_lock(&misc_mtx); /*遍歷misc_list鏈表,看這個(gè)次裝備號(hào)之前有無(wú)被用過(guò),如果次裝備號(hào)已被占有則退出*/ list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { mutex_unlock(&misc_mtx); return -EBUSY; } } /*看是不是是需要?jiǎng)討B(tài)分配次裝備號(hào)*/ if(misc->minor == MISC_DYNAMIC_MINOR) { /* *#define DYNAMIC_MINORS 64 /* like dynamic majors */ *static unsigned char misc_minors[DYNAMIC_MINORS / 8]; *這里存在1個(gè)次裝備號(hào)的位圖,1共64位。下邊是遍歷每位, *如果這位為0,表示沒(méi)有被占有,可使用,為1表示被占用。 */ 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; } /*得到這個(gè)次裝備號(hào)*/ misc->minor = i; } /*設(shè)置位圖中相應(yīng)位為1*/ if(misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor& 7); /*計(jì)算出裝備號(hào)*/ dev= MKDEV(MISC_MAJOR, misc->minor); /*在/dev下創(chuàng)建裝備節(jié)點(diǎn),這就是有些驅(qū)動(dòng)程序沒(méi)有顯式調(diào)用device_create,卻出現(xiàn)了裝備節(jié)點(diǎn)的緣由*/ 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; } /* *Add it to the front, so that later devices can "override" *earlier defaults */ /*將這個(gè)miscdevice添加到misc_list鏈表中*/ list_add(&misc->list, &misc_list); out: mutex_unlock(&misc_mtx); return err; }


可以看出,這個(gè)函數(shù)首先遍歷misc_list鏈表,查找所用的次裝備號(hào)是不是已被注冊(cè),避免沖突。如果是動(dòng)態(tài)次裝備號(hào)則分配1個(gè),然后調(diào)用MKDEV生成裝備號(hào),從這里可以看出所有的misc裝備同享1個(gè)主裝備號(hào)MISC_MAJOR,然后調(diào)用device_create,生成裝備文件。最后加入到misc_list鏈表中。

    關(guān)于device_create,class_create 作用: class_create函數(shù)在misc.c中的模塊初始化中被調(diào)用,現(xiàn)在1起說(shuō)1下。這兩個(gè)函數(shù)看起來(lái)很陌生,沒(méi)有在ldd3中發(fā)現(xiàn)過(guò),看源代碼的時(shí)候發(fā)現(xiàn)class_create會(huì)調(diào)用底層組件__class_regsiter()是說(shuō)明它是注冊(cè)1個(gè)類。而device_create是創(chuàng)建1個(gè)裝備,他是創(chuàng)建裝備的便捷實(shí)現(xiàn)調(diào)用了device_register函數(shù)。他們都提供給linux裝備模型使用,從linux內(nèi)核2.6的某個(gè)版本以后,devfs不復(fù)存在,udev成為devfs的替換。相比devfs,udev有很多優(yōu)勢(shì)。

struct class *myclass =class_create(THIS_MODULE, “my_device_driver”); 

class_device_create(myclass, NULL,MKDEV(major_num, 0), NULL, “my_device”); 

   這樣就創(chuàng)建了1個(gè)類和裝備,模塊被加載時(shí),udev daemon就會(huì)自動(dòng)在/dev下創(chuàng)建my_device裝備文件節(jié)點(diǎn)。這樣就省去了自己創(chuàng)建裝備文件的麻煩。這樣也有助于動(dòng)態(tài)裝備的管理.

這個(gè)是miscdevice的卸載函數(shù):

int misc_deregister(struct miscdevice*misc) { inti = misc->minor; if(list_empty(&misc->list)) return -EINVAL; mutex_lock(&misc_mtx); /*在misc_list鏈表中刪除miscdevice裝備*/ list_del(&misc->list); /*刪除裝備節(jié)點(diǎn)*/ device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if(i < DYNAMIC_MINORS && i>0) { /*釋放位圖相應(yīng)位*/ misc_minors[i>>3] &= ~(1 << (misc->minor &7)); } mutex_unlock(&misc_mtx); return 0; }

總結(jié)1下miscdevice驅(qū)動(dòng)的注冊(cè)和卸載流程:

misc_register:匹配次裝備號(hào)->找到1個(gè)沒(méi)有占用的次裝備號(hào)(如果需要?jiǎng)討B(tài)分配的話)->計(jì)算裝備號(hào)->創(chuàng)建裝備文件->miscdevice結(jié)構(gòu)體添加到misc_list鏈表中。

misc_deregister:從mist_list中刪除miscdevice->刪除裝備文件->位圖位清零。

 

總結(jié):

雜項(xiàng)裝備作為字符裝備的封裝,為字符裝備提供的簡(jiǎn)單的編程接口,如果編寫新的字符驅(qū)動(dòng),可以斟酌使用雜項(xiàng)裝備接口,方便簡(jiǎn)單,只需要初始化1個(gè)miscdevice的結(jié)構(gòu),調(diào)用misc_register就能夠了。系統(tǒng)最多有255個(gè)雜項(xiàng)裝備,由于雜項(xiàng)裝備模塊自己占用了1個(gè)次裝備號(hào)

生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲精品毛片久久久久久久 | 国产综合久久久久 | 国产未成女年一区二区 | 国产成人黄网址在线视频 | 欧美一级特黄特黄毛片 | 成人在线观看免费爱爱 | 国内自拍亚洲 | 午夜写真福利视频在线观看 | 成人三级精品视频在线观看 | 在线观看麻豆 | 国产性夜夜春夜夜爽30 | 亚洲性69影院在线观看 | 中文字幕乱码中文乱码51精品 | 黑人又大又粗好爽好猛视频 | 欧美一级毛片100部 欧美一级毛片不卡免费观看 | 国产一区二区在线视频播放 | 色人阁色五月 | 一本大道香蕉大无线视频 | 国产成人短视频在线观看免费 | 黄大片日本一级在线a | 一级爱爱片 | 欧美13一14周岁a在线播放 | 亚洲精品第一区二区在线 | 欧美国产成人免费观看永久视频 | yellow中文字幕视频在线 | 国产亚洲一区二区三区在线 | 一级一级特黄女人精品毛片视频 | 欧美日韩国产一区二区三区不卡 | 肉体肉体xxxx肉体d | 国产精品美乳免费看 | 欧美亚洲欧美日韩中文二区 | 香蕉视频在线网站 | 九九热在线免费视频 | jizz亚洲 | 国产在线不卡 | 在线中文字幕亚洲 | 国产大毛片 | 成人精品视频网站 | 亚洲精彩视频在线观看 | 一级做α爱过程免费视频 | 国产成人久久精品一区二区三区 |