linux驅(qū)動(dòng)篇之 driver_register 過(guò)程分析(二)
個(gè)人筆記,歡迎轉(zhuǎn)載,請(qǐng)注明出處,共同分享 共同進(jìn)步?
http://blog.csdn.net/richard_liujh/article/details/48245715
kernel版本3.10.14
1.概述
本篇主要圍繞driver_register中的第二步bus_add_driver展開(kāi)分析。在上一篇博文中主要分析了driver_find的過(guò)程,在driver_register中調(diào)用driver_find主要是為了檢驗(yàn)驅(qū)動(dòng)是否已經(jīng)注冊(cè)到kernel中,如果沒(méi)有注冊(cè),那么接下來(lái)的幾個(gè)步驟才是driver_register的核心作用。
driver_register簡(jiǎn)化過(guò)程如下:
[cpp] ?view plaincopy print?
int ?driver_register( struct ?device_driver?*drv)?? ????|?? ????|-->?driver_find??? ????|-->?bus_add_driver?? ????|-->?driver_add_groups?? ????|-->?kobject_uevent??
2.bus_add_driver分析
2.1?bus_add_driver源碼
bus_add_driver源碼在./drivers/base/bus.c 文件中
[cpp] ?view plaincopy print?
? ? ? ?? int ?bus_add_driver( struct ?device_driver?*drv)?? {?? ????struct ?bus_type?*bus;?? ????struct ?driver_private?*priv;?? ????int ?error?=?0;?? ?? ????bus?=?bus_get(drv->bus);?? ????if ?(!bus)?? ????????return ?-EINVAL;?? ?? ????pr_debug("bus:?'%s':?add?driver?%s\n" ,?bus->name,?drv->name);?? ?? ????priv?=?kzalloc(sizeof (*priv),?GFP_KERNEL);?? ????if ?(!priv)?{?? ????????error?=?-ENOMEM;?? ????????goto ?out_put_bus;?? ????}?? ????klist_init(&priv->klist_devices,?NULL,?NULL);?? ????priv->driver?=?drv;?? ????drv->p?=?priv;?? ????priv->kobj.kset?=?bus->p->drivers_kset;?? ????error?=?kobject_init_and_add(&priv->kobj,?&driver_ktype,?NULL,?? ?????????????????????"%s" ,?drv->name);?? ????if ?(error)?? ????????goto ?out_unregister;?? ?? ????klist_add_tail(&priv->knode_bus,?&bus->p->klist_drivers);?? ????if ?(drv->bus->p->drivers_autoprobe)?{?? ????????error?=?driver_attach(drv);?? ????????if ?(error)?? ????????????goto ?out_unregister;?? ????}?? ????module_add_driver(drv->owner,?drv);?? ?? ????error?=?driver_create_file(drv,?&driver_attr_uevent);?? ????if ?(error)?{?? ????????printk(KERN_ERR?"%s:?uevent?attr?(%s)?failed\n" ,?? ????????????__func__,?drv->name);?? ????}?? ????error?=?driver_add_attrs(bus,?drv);?? ????if ?(error)?{?? ?????????? ????????printk(KERN_ERR?"%s:?driver_add_attrs(%s)?failed\n" ,?? ????????????__func__,?drv->name);?? ????}?? ?? ????if ?(!drv->suppress_bind_attrs)?{?? ????????error?=?add_bind_files(drv);?? ????????if ?(error)?{?? ?????????????? ????????????printk(KERN_ERR?"%s:?add_bind_files(%s)?failed\n" ,?? ????????????????__func__,?drv->name);?? ????????}?? ????}?? ?? ????return ?0;?? ?? out_unregister:?? ????kobject_put(&priv->kobj);?? ????kfree(drv->p);?? ????drv->p?=?NULL;?? out_put_bus:?? ????bus_put(bus);?? ????return ?error;?? }??
代碼稍微有點(diǎn)長(zhǎng),但是為了保留kernel源碼的美感,所以上面代碼沒(méi)有做任何改動(dòng)。
2.1 ?bus_add_driver簡(jiǎn)化過(guò)程
為了使分析bus_add_driver不顯得太雜亂,這里我將bus_add_driver分為以下幾個(gè)部分:
[cpp] ?view plaincopy print?
int ?bus_add_driver( struct ?device_driver?*drv)?? ????|?? ????|--->?bus_get?? ????|????? ????|--->?klist_init?? ????|--->?kobject_init_and_add?? ????|--->?klist_add_tail?? ????|?? ????|--->?module_add_driver?? ????|--->?driver_create_file?? ????|--->?driver_add_attrs??
在bus_add_driver函數(shù)里,只傳過(guò)來(lái)一個(gè)參數(shù)就是device_driver?*drv 。為什么bus_add_driver只需要device_driver的指針這一個(gè)參數(shù)? device_driver是不是很熟悉?我們?cè)趯戲?qū)動(dòng)時(shí),device_driver是一個(gè)非常重要的結(jié)構(gòu)體。在文件./include/linux/device.h 中有device_driver的定義。
[cpp] ?view plaincopy print?
struct ?device_driver?{?? ????const ? char ??????*name;?? ????struct ?bus_type?????*bus;?? ?? ????struct ?module???????*owner;?? ????const ? char ??????*mod_name;?? ?? ?? ????bool ?suppress_bind_attrs;??? ?? ?? ????const ? struct ?of_device_id???*of_match_table;?? ????const ? struct ?acpi_device_id?*acpi_match_table;?? ?? ????int ?(*probe)?( struct ?device?*dev);?? ????int ?(*remove)?( struct ?device?*dev);?? ????void ?(*shutdown)?( struct ?device?*dev);?? ????int ?(*suspend)?( struct ?device?*dev,?pm_message_t?state);?? ????int ?(*resume)?( struct ?device?*dev);?? ????const ? struct ?attribute_group?**groups;?? ?? ????const ? struct ?dev_pm_ops?*pm;?? ?? ????struct ?driver_private?*p;?? };??
從上面的device_driver結(jié)構(gòu)內(nèi)容可以看出,里面包含了driver的名字(name),總線的類型(bus),所屬的模塊(owner)。和一些非常重要的函數(shù)指針,例如嗅探函數(shù)指針probe,驅(qū)動(dòng)刪除函數(shù)指針remove,關(guān)機(jī)時(shí)調(diào)用的函數(shù)指針shutdown,睡眠時(shí)調(diào)用的函數(shù)指針suspend,睡眠喚醒時(shí)恢復(fù)驅(qū)動(dòng)的函數(shù)指針resume等等....
對(duì)于一個(gè)初級(jí)的驅(qū)動(dòng),是不是最先了解的是name、bus、module、probe這個(gè)成員變量?通過(guò)后面的分析,我們可以深入理解這些變量的作用。
2.2 簡(jiǎn)化過(guò)程分析
在kernel中的函數(shù)名一般都很通俗易懂,例如我們要分析的bus_add_driver,就有簡(jiǎn)單bus、add和driver等單詞組合。所以憑借男人的第六感,能夠大概猜出是在某個(gè)bus上添加驅(qū)動(dòng)了。所以在剛才簡(jiǎn)化bus_add_driver的第一個(gè)過(guò)程就是bus_get。bus_get的名字言簡(jiǎn)意賅,獲得bus。因?yàn)槲覀円谀硞€(gè)bus上添加driver。
2.2.1 bus_get源碼:
bus_get 源碼
./drivers/base/bus.c
[cpp] ?view plaincopy print?
bus?=?bus_get(drv->bus);?? ?? static ? struct ?bus_type?*bus_get( struct ?bus_type?*bus)?? {?? ????if ?(bus)?{ ?? ????????kset_get(&bus->p->subsys);?? ????????return ?bus; ?? ????}?? ????return ?NULL; ?? }??
bus_get相對(duì)比較簡(jiǎn)單,上一篇博文是以platform_driver_register開(kāi)始講解的,所以bus_type為platform_bus_type。
2.2.2 klist_init,?kobject_init_and_add,?klist_add_tail分析
klist_init,kobject_init_and_add 和klist_add_tail我把他們歸納在一起,主要完成了Kobject的初始化和將初始化的kobjec尾插到kset鏈表中。還記得在上篇博文講解中driver_find的過(guò)程,就涉及到一個(gè)鏈表的遍歷過(guò)程吧,如果鏈表里面有對(duì)應(yīng)驅(qū)動(dòng)的name說(shuō)明驅(qū)動(dòng)已經(jīng)注冊(cè)了。如果第一次注冊(cè),驅(qū)動(dòng)的name當(dāng)然是在鏈表中不存在的(除非沖突了),所以這里的操作就是將驅(qū)動(dòng)相關(guān)的基類Kobject添加到對(duì)應(yīng)kset的循環(huán)鏈表中。
klist_init
在bus_add_driver調(diào)用時(shí)如下:
[cpp] ?view plaincopy print?
klist_init(&priv->klist_devices,?NULL,?NULL);??
所以我們觀察一下參數(shù),后面兩個(gè)是NULL,前面是&priv->klist_devices。注意有一個(gè)“&”符號(hào),也就是將priv的成員
klist_devices地址
傳送過(guò)去。
補(bǔ):像用C編寫的代碼,尤其是linux 源碼,內(nèi)核中會(huì)經(jīng)常傳送指針。一般傳送一級(jí)指針要留意,傳送二級(jí)指針要多留意,傳送結(jié)構(gòu)體指針要更加留意。 這個(gè)函數(shù)很明顯是將klist_devices的地址傳送過(guò)去進(jìn)行初始化了。那么如何初始化?初始化了哪些內(nèi)容呢?為了解決這個(gè)問(wèn)題,我們得先知道要被初始化的變量是什么類型的!
首先來(lái)了解bus_add_driver中的struct driver_private *priv; 這個(gè)priv 是指向driver_private結(jié)構(gòu)體的指針 。其成員如下
[cpp] ?view plaincopy print?
struct ?driver_private?{?? ????struct ?kobject?kobj;?? ????struct ?klist?klist_devices;?? ????struct ?klist_node?knode_bus;?? ????struct ?module_kobject?*mkobj;?? ????struct ?device_driver?*driver;?? };??
private是私有的意思,很多面向?qū)ο蟮恼Z(yǔ)言都有private關(guān)鍵字,表示資源是私有的,其他人不能隨意使用。這里driver_private的意思是driver所擁有的資源,相當(dāng)于將driver相關(guān)
的資源封裝了一個(gè)結(jié)構(gòu)體中,使得代碼的層次感更強(qiáng),面向?qū)ο蟮拿栏懈谩?duì)于priv? ,bus_add_driver 有如下幾個(gè)操作:
[cpp] ?view plaincopy print?
struct ?driver_private?*priv; ?? priv?=?kzalloc(sizeof (*priv),?GFP_KERNEL); ??
好了,這個(gè)清楚了后我們就該繼續(xù)看klist_init 初始化的
&priv->klist_devices
,klist_devices在d
river_private定義如下:
[cpp] ?view plaincopy print?
struct ?klist?klist_devices;??
klist結(jié)構(gòu)體在文件
./include/linux/klist.h
中定義
[cpp] ?view plaincopy print?
struct ?klist?{?? ????spinlock_t??????k_lock;?? ????struct ?list_head????k_list;?? ????void ????????????(*get)( struct ?klist_node?*);?? ????void ????????????(*put)( struct ?klist_node?*);?? }??
這里就很簡(jiǎn)單了,既然是要對(duì)klist_devices初始化,通過(guò)上面的定義可以看到有4個(gè)成員變量:自旋鎖k_lock,鏈表節(jié)點(diǎn)k_list和兩個(gè)函數(shù)指針get,put。
klist_ini的t源碼在文件./lib/klist.c
[cpp] ?view plaincopy print?
void ?klist_init( struct ?klist?*k,? void ?(*get)( struct ?klist_node?*),?? ????????void ?(*put)( struct ?klist_node?*))?? {?? ????INIT_LIST_HEAD(&k->k_list);?? ????spin_lock_init(&k->k_lock);?? ????k->get?=?get;?? ????k->put?=?put;?? }??
知道了klist_devices的成員,上面的代碼就很簡(jiǎn)單了,就是對(duì)klist_devices的四個(gè)成員變量進(jìn)行初始化。代碼比較簡(jiǎn)單,就不細(xì)說(shuō)了。只簡(jiǎn)單提一下
INIT_LIST_HEAD
,因?yàn)樵趦?nèi)核中經(jīng)常可以看到這個(gè)函數(shù)。
在文件./include/linux/list.h中有INIT_LIST_HEAD 定義
[cpp] ?view plaincopy print?
static ? inline ? void ?INIT_LIST_HEAD( struct ?list_head?*list)?? {?? ????list->next?=?list;?? ????list->prev?=?list;?? }??
很明顯,這是一個(gè) 內(nèi)聯(lián)函數(shù)(有inline)。實(shí)現(xiàn)的功能也很簡(jiǎn)單,list是鏈表,我們?cè)趯?shí)現(xiàn)循環(huán)鏈表時(shí)總會(huì)定義兩個(gè)指針
next
和
prev
。next指向下一個(gè)節(jié)點(diǎn)的地址,prev指向上一個(gè)節(jié)點(diǎn)的地址。所以INIT_LIST_HEAD其實(shí)就是使next和prev都指向自己的地址,我們判斷鏈表是否為空的時(shí)候不就是看看next和prev指向的地址是否相同嗎,相同表示為空。
下面是INIT_LIST_HEAD的一個(gè)簡(jiǎn)單示意圖
kobject_init_and_add
kobject_init_and_add 源碼在文件./lib/kobject.c ??
[cpp] ?view plaincopy print?
? ? ? ? ? ? ? ? ? ? ?? int ?kobject_init_and_add( struct ?kobject?*kobj,? struct ?kobj_type?*ktype,?? ?????????????struct ?kobject?*parent,? const ? char ?*fmt,?...)?? {?? ????va_list ?args;?? ????int ?retval;?? ?? ????kobject_init(kobj,?ktype);?? ?? ????va_start(args,?fmt);?? ????retval?=?kobject_add_varg(kobj,?parent,?fmt,?args);?? ????va_end(args);?? ?? ????return ?retval;?? }?? EXPORT_SYMBOL_GPL(kobject_init_and_add);??
過(guò)注釋可以很清楚的知道
kobject_init_and_add
的作用,初始化
kobject
結(jié)構(gòu)體并添加到
kobject
的層次中。
kobject_init_and_add 通過(guò)kobject_init 初始化kobject,通過(guò)kobject_add_varg 完成添加操作。
kobject_init_and_add
|------?kobject_init
kobject_init源碼也在文件./lib/kobject.c ??中
[cpp] ?view plaincopy print?
? ? ? ? ? ? ? ? ? ? ? ?? void ?kobject_init( struct ?kobject?*kobj,? struct ?kobj_type?*ktype)?? {?? ????char ?*err_str;?? ?? ????if ?(!kobj)?{ ?? ????????err_str?=?"invalid?kobject?pointer!" ;?? ????????goto ?error;?? ????}?? ????if ?(!ktype)?{ ?? ????????err_str?=?"must?have?a?ktype?to?be?initialized?properly!\n" ;?? ????????goto ?error;?? ????}?? ????if ?(kobj->state_initialized)?{ ?? ?????????? ????????printk(KERN_ERR?"kobject?(%p):?tried?to?init?an?initialized?" ?? ???????????????"object,?something?is?seriously?wrong.\n" ,?kobj);?? ????????dump_stack();?? ????}?? ?? ????kobject_init_internal(kobj);?? ????kobj->ktype?=?ktype;?? ????return ;?? ?? error:?? ????printk(KERN_ERR?"kobject?(%p):?%s\n" ,?kobj,?err_str);?? ????dump_stack();?? }?? EXPORT_SYMBOL(kobject_init);??
這個(gè)函數(shù)注釋也寫的很清楚了This function will properly initialize a kobject such that it can then?be passed to the kobject_add() call. ?功能雖簡(jiǎn)單,但是內(nèi)核做事還是比較嚴(yán)謹(jǐn),從代碼中對(duì)kobj 、ktype 和kobj->state_initialized 依次進(jìn)行了檢查。檢查無(wú)誤開(kāi)始調(diào)用kobject_init_internal
kobject_init_internal源碼如下:[?./lib/kobject.c? ]
[cpp] ?view plaincopy print?
static ? void ?kobject_init_internal( struct ?kobject?*kobj)?? {?? ????if ?(!kobj)?? ????????return ;?? ????kref_init(&kobj->kref);?? ????INIT_LIST_HEAD(&kobj->entry);?? ????kobj->state_in_sysfs?=?0;?? ????kobj->state_add_uevent_sent?=?0;?? ????kobj->state_remove_uevent_sent?=?0;?? ????kobj->state_initialized?=?1;?? }??
上面是對(duì)kobject真正的初始化。因?yàn)閗object是linux設(shè)備驅(qū)動(dòng)的核心結(jié)構(gòu)體之一,所涉及到的內(nèi)容比較多也比較復(fù)雜,所以這里就不再深究具體初始化的含義。希望在以后的設(shè)備驅(qū)動(dòng)相關(guān)博文中詳解。
kobject_init_and_add
|------?kobject_add_varg
上面初始化好kobject后,開(kāi)始通過(guò)kobject_add_varg添加kobject
kobject_init_and_add源碼如下,在文件./lib/kobject.c 中
[cpp] ?view plaincopy print?
static ? int ?kobject_add_varg( struct ?kobject?*kobj,? struct ?kobject?*parent,?? ????????????????const ? char ?*fmt,? va_list ?vargs)?? {?? ????int ?retval;?? ?? ????retval?=?kobject_set_name_vargs(kobj,?fmt,?vargs);?? ????if ?(retval)?{?? ????????printk(KERN_ERR?"kobject:?can?not?set?name?properly!\n" );?? ????????return ?retval;?? ????}?? ????kobj->parent?=?parent;?? ????return ?kobject_add_internal(kobj);?? }??
在分析這個(gè)函數(shù)時(shí),有必要看看kobject_init_and_add的函數(shù)接口定義:
[cpp] ?view plaincopy print?
int ?kobject_init_and_add( struct ?kobject?*kobj,? struct ?kobj_type?*ktype,? struct ?kobject?*parent,? const ? char ?*fmt,?...)??
最后的參數(shù)
const char *fmt, ...
是可變參數(shù),那么fmt的值是什么呢?再來(lái)看看調(diào)用kobject_init_and_add時(shí)的傳參:
[cpp] ?view plaincopy print?
error?=?kobject_init_and_add(&priv->kobj,?&driver_ktype,?NULL,? "%s" ,?drv->name);??
所以可變參數(shù)
const char *fmt, ...
的內(nèi)容是
"%s", drv->name
也就是驅(qū)動(dòng)的名字。在kobject_init_and_add中的kobject_set_name_vargs函數(shù)通過(guò)處理可變參數(shù),最終將drv->name的內(nèi)容給kobj->name。
最后的重點(diǎn)就是
[cpp] ?view plaincopy print?
return ?kobject_add_internal(kobj);??
kobject_add_internal的作用還是非常多的。通過(guò)kobject_add_internal將準(zhǔn)備好的kobject添加到kset的循環(huán)列表中,并且在sys/目錄下創(chuàng)建kobject的目錄。
kobject_init_and_add
|------?kobject_add_varg
|-------kobject_add_internal
kobject_add_internal源碼在在文件./lib/kobject.c 中
[cpp] ?view plaincopy print?
static ? int ?kobject_add_internal( struct ?kobject?*kobj)?? {?? ????int ?error?=?0;?? ????struct ?kobject?*parent;?? ?? ????if ?(!kobj)?? ????????return ?-ENOENT;?? ?? ????if ?(!kobj->name?||?!kobj->name[0])?{?? ????????WARN(1,?"kobject:?(%p):?attempted?to?be?registered?with?empty?" ?? ?????????????"name!\n" ,?kobj);?? ????????return ?-EINVAL;?? ????}?? ?? ????parent?=?kobject_get(kobj->parent);?? ?? ?????? ????if ?(kobj->kset)?{?? ????????if ?(!parent)?? ????????????parent?=?kobject_get(&kobj->kset->kobj);?? ????????kobj_kset_join(kobj);?? ????????kobj->parent?=?parent;?? ????}?? ?? ????pr_debug("kobject:?'%s'?(%p):?%s:?parent:?'%s',?set:?'%s'\n" ,?? ?????????kobject_name(kobj),?kobj,?__func__,?? ?????????parent???kobject_name(parent)?:?"<NULL>" ,?? ?????????kobj->kset???kobject_name(&kobj->kset->kobj)?:?"<NULL>" );?? ?? ????error?=?create_dir(kobj);?? ????if ?(error)?{?? ????????kobj_kset_leave(kobj);?? ????????kobject_put(parent);?? ????????kobj->parent?=?NULL;?? ?? ?????????? ????????if ?(error?==?-EEXIST)?? ????????????WARN(1,?"%s?failed?for?%s?with?" ?? ?????????????????"-EEXIST,?don't?try?to?register?things?with?" ?? ?????????????????"the?same?name?in?the?same?directory.\n" ,?? ?????????????????__func__,?kobject_name(kobj));?? ????????else ?? ????????????WARN(1,?"%s?failed?for?%s?(error:?%d?parent:?%s)\n" ,?? ?????????????????__func__,?kobject_name(kobj),?error,?? ?????????????????parent???kobject_name(parent)?:?"'none'" );?? ????}?else ?? ????????kobj->state_in_sysfs?=?1;?? ?? ????return ?error;?? }??
上面的的代碼說(shuō)多不多,說(shuō)少也不簡(jiǎn)單....
還是為了簡(jiǎn)化,我把kobject_add_internal的功能簡(jiǎn)化如下(一些簡(jiǎn)單的if 判斷就不細(xì)講了):
[cpp] ?view plaincopy print?
static ? int ?kobject_add_internal( struct ?kobject?*kobj)?? {?? ????parent?=?kobject_get(kobj->parent);?? <span?style="white-space:pre" >????</span>……?? ?????? ????if ?(kobj->kset)?{ ?? ????????if ?(!parent)?? ????????????parent?=?kobject_get(&kobj->kset->kobj);?? ????????kobj_kset_join(kobj);?? ????????kobj->parent?=?parent;?? ????}?? <span?style="white-space:pre" >????</span>……?? ????error?=?create_dir(kobj);?? <span?style="white-space:pre" >????</span>……?? ????????kobj->state_in_sysfs?=?1;?? ?? ????return ?error;?? }??
代碼里面if (kobj->kset)對(duì)kobject的kset進(jìn)行的檢查,那么我們這里的kset什么值呢?這就要回到bus_add_driver函數(shù),其中有這么一句話priv->kobj.kset = bus->p->drivers_kset; 所以此時(shí)的kobject->kset不為空。
if (!parent)的作用是判斷kobject是否有父類,對(duì)于kset、kobject、parent和list,在權(quán)威書(shū)籍LDD3-chapter14(linux設(shè)備驅(qū)動(dòng))中有一個(gè)很經(jīng)典的圖,所以我就借花獻(xiàn)佛了。
上圖~
解釋:
在鏈表中每一個(gè)kobject都有一個(gè)指向kset的指針。 在鏈表中每一個(gè)kobject都有指向父類kobject(內(nèi)嵌在kset中)的指針 在鏈表中每一個(gè)kobject 都有鏈表指針(next、prev)指向相鄰的節(jié)點(diǎn)
這張圖很簡(jiǎn)潔的解釋了kset和kobject的基本關(guān)系。感興趣的請(qǐng)直接閱讀葵花寶典《LDD3》。點(diǎn)擊下載LDD3
他們之間的關(guān)系清楚了后,我們開(kāi)始分析kobject是如何添加到kset的鏈表中的。這個(gè)功能是由kobj_kset_join 完成的
kobj_kset_join源碼在./lib/kobject.c 中
[cpp] ?view plaincopy print?
?? static ? void ?kobj_kset_join( struct ?kobject?*kobj)?? {?? ????if ?(!kobj->kset)?? ????????return ;?? ?? ????kset_get(kobj->kset);?? ????spin_lock(&kobj->kset->list_lock);<span?style="font-family:?Arial,?Helvetica,?sans-serif;" > ?? ????list_add_tail(&kobj->entry,?&kobj->kset->list);?? ????spin_unlock(&kobj->kset->list_lock);解鎖?? }??
其中spin_lock和spin_unlock都是對(duì)自旋鎖的操作,這里不多講了。比較重要的就是
list_add_tail。 list_add_tail
通過(guò)名字,我們能猜到這個(gè)函數(shù)就是在鏈表中添加節(jié)點(diǎn),其中tail應(yīng)該就是從尾部添加也就是尾插法了。
kobject_init_and_add
|------?kobject_add_varg
|-------kobject_add_internal
|------list_add_tail
list_add_tail源碼在頭文件./include/linux/list.h ?中
[cpp] ?view plaincopy print?
? ? ? ? ? ? ? ?? static ? inline ? void ?list_add_tail( struct ?list_head?* new ,? struct ?list_head?*head)?? {?? ????__list_add(new ,?head->prev,?head);?? }??
而__list_add的源碼如下:
[cpp] ?view plaincopy print?
static ? inline ? void ?__list_add( struct ?list_head?* new ,?? ??????????????????struct ?list_head?*prev,?? ??????????????????struct ?list_head?*next)?? {?? ????next->prev?=?new ;?? ????new ->next?=?next;?? ????new ->prev?=?prev;?? ????prev->next?=?new ;?? }??
很明顯,上面的代碼就是鏈表插入節(jié)點(diǎn)的操作。只是稍微注意一下傳參過(guò)程,因?yàn)閰?shù)的名稱并不一致,但是都是指針,細(xì)心一點(diǎn)就沒(méi)有問(wèn)題的。
總結(jié)上述過(guò)程,通下圖表示:
上圖~
當(dāng)kobject成功添加到kset的鏈表中后,開(kāi)始在sysfs中創(chuàng)建kobject的相關(guān)目錄,這個(gè)過(guò)程由error = create_dir(kobj);完成。
一下是sysfs穿件目錄的核心代碼:在文件?./fs/sysfs/dir.c 中
[cpp] ?view plaincopy print?
? ? ? ?? int ?sysfs_create_dir( struct ?kobject?*?kobj)?? {?? ????enum ?kobj_ns_type?type;?? ????struct ?sysfs_dirent?*parent_sd,?*sd;?? ????const ? void ?*ns?=?NULL;?? ????int ?error?=?0;?? ?? ????BUG_ON(!kobj);?? ?? ????if ?(kobj->parent)?? ????????parent_sd?=?kobj->parent->sd;?? ????else ?? ????????parent_sd?=?&sysfs_root;?? ?? ????if ?(!parent_sd)?? ????????return ?-ENOENT;?? ?? ????if ?(sysfs_ns_type(parent_sd))?? ????????ns?=?kobj->ktype->namespace (kobj);?? ????type?=?sysfs_read_ns_type(kobj);?? ?? ????error?=?create_dir(kobj,?parent_sd,?type,?ns,?kobject_name(kobj),?&sd);?? ????if ?(!error)?? ????????kobj->sd?=?sd;?? ????return ?error;?? }??
sysfs穿件目錄的代碼就不詳細(xì)說(shuō)明了,記得在前面分析
kobject_init_and_add
時(shí),有這樣的一句注釋
initialize a kobject structure and add it to the kobject hierarchy
單詞hierarchy是 層級(jí),等級(jí)的意思。注釋的大致意思是將kobject添加到kobject等級(jí)中。這里的“等級(jí) ”體現(xiàn)最明顯的就是目錄結(jié)構(gòu)。
說(shuō)到目錄,我們會(huì)很快聯(lián)想到子目錄 或者上一級(jí) 目錄。要在sysfs里面創(chuàng)建kobject相關(guān)的目錄,也需要遵守目錄的等級(jí)制度啦。按照kobject的parent (也是kobject類)就是上一級(jí)目錄的規(guī)則去創(chuàng)建,目錄名 是kobject->name 。為了能讓讀者更加清楚創(chuàng)建的規(guī)則,我就以目前手中的平臺(tái)為例:
文章開(kāi)頭,我們是以platform_driver_register為例子講解,目前我手上剛好有一個(gè)國(guó)產(chǎn)君正M200平臺(tái)的開(kāi)發(fā)板。處理器是mips架構(gòu)。
假設(shè),我們要注冊(cè)的驅(qū)動(dòng)是framebuffer。在君正平臺(tái)代碼中,有如下定義:
[cpp] ?view plaincopy print?
static ? struct ?platform_driver?jzfb_driver?=?{?? ????.probe?=?jzfb_probe,?? ????.remove?=?jzfb_remove,?? ????.shutdown?=?jzfb_shutdown,?? ????.driver?=?{?? ???????????.name?=?"jz-fb" ,?? #ifdef?CONFIG_PM ?? ???????????.pm?=?&jzfb_pm_ops,?? #endif ?? ?? ???????????},?? };??
可以看到driver->name 是“jz-fb”。通過(guò)platform_driver_register(&jzfb_driver);注冊(cè)platform架構(gòu)驅(qū)動(dòng)。當(dāng)代碼執(zhí)行到上述過(guò)程,肯定會(huì)在sysfs下創(chuàng)建相關(guān)的目錄,并且以
kobject->name
命名。
我通過(guò)終端,訪問(wèn)sys目錄,結(jié)果如下:
上圖~
所以可以觀察到/sys/bus/platform/drivers/jz-fb ?的目錄結(jié)構(gòu)剛好符合了我們分析代碼的順序。
總結(jié)?
上面主要分析了driver在注冊(cè)過(guò)程中,初始化driver的kobject和將kobject添加到對(duì)應(yīng)的層級(jí)結(jié)構(gòu)中。
總結(jié)
以上是生活随笔 為你收集整理的linux驱动篇之 driver_register 过程分析(二)bus_add_driver 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。