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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

linux设备驱动——andriod平台wlan驱动

發布時間:2025/3/21 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux设备驱动——andriod平台wlan驱动 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自 :http://blog.chinaunix.net/space.php?uid=22278460&do=blog&cuid=2186191


linux設備驅動——andriod平臺wlan驅動

關于這一部分的blog,所有的內容均摘自自己的工作總結筆記,在很多網站都發現了自己寫的技術總結的轉載感到很高興,雖然我還是個菜鳥,但是我會繼續努力。另外關于wlan驅動這方面的資料真的很少,我基本上是靠自己讀代碼來理解那些繁瑣的寄存器讀寫、802.11/e/h/d等標準的,真的比較辛苦。不過好在算是慢慢的搞清楚了這個流程,在此之前我們仍然要補習一下關于在2.6版本內核中寫驅動的知識。

??? 有關linux設備模型這一塊比較復雜,我不敢斷定自己理解的肯定正確,但是我會在做這個驅動的過程中回過頭來修改自己的筆記并且糾正自己在blog上貼的并不正確的地方。另外,我的無線網卡是掛接在SDIO總線上的,所以呢,我們之前會先介紹一點SDIO的驅動,當然并不在這篇blog上,這篇blog會是總領性的關于基礎知識的介紹。下面是筆記

?

在進入正式的驅動代碼之前,我們不得不補充一點基礎知識,也就是在2.6版本內核的現在,內核是如何管理總線,驅動,設備之間的關系的,關于bus_type、device_driver、device這三個內核結構在內核代碼中可以找到。由于這三個結構的重要性,我們在這里先將它們貼出來,我會用紅色的注釋標注。我在筆記中將會提到的一些結構成員以其代表的意義,這樣便于對照。(我不得不承認,這三個結構的代碼枯燥復雜,但我可以保證,在看完我總結的筆記之后,你會對這三個結構中重要的數據成員有個非常不錯的了解,當然你得對內核和驅動有基本的了解。如果我誤導了你,請指正我,所以我的建議是不妨先看完了筆記再來看這些結構)

?

1、設備結構的定義:

struct device {
?struct klist??klist_children;????????
?struct klist_node?knode_parent;??/* node in sibling list */
?struct klist_node?knode_driver;
?struct klist_node?knode_bus;
?struct device??*parent;

struct kobject kobj;???? //kobject結構,關于這個結構與kset結構以及subsystem結構,筆記中會有描述。
?char?bus_id[BUS_ID_SIZE];?/* position on parent bus */
?struct device_type?*type;
?unsigned??is_registered:1;
?unsigned??uevent_suppress:1;

struct semaphore?sem;?/* semaphore to synchronize calls to

* its driver.
????? */

struct bus_type?* bus;??/* type of bus device is on */??//這個設備掛接的總線的類型
?struct device_driver *driver;?/* which driver has allocated this device */??//這個設備掛接的驅動
?void??*driver_data;?/* data private to the driver */

void??*platform_data;?/* Platform specific data, device core doesn't touch it */
?struct dev_pm_info?power;

#ifdef CONFIG_NUMA
?int??numa_node;?/* NUMA node this device is close to */
#endif

u64??*dma_mask;?/* dma mask (if dma'able device) */
?u64??coherent_dma_mask;/* Like dma_mask, but for
????????? alloc_coherent mappings as
????????? not all hardware supports
????????? 64 bit addresses for consistent
????????? allocations such descriptors. */

struct list_head?dma_pools;?/* dma pools (if dma'ble) */

struct dma_coherent_mem?*dma_mem; /* internal for coherent mem override */
?/* arch specific additions */
?struct dev_archdata?archdata;

spinlock_t??devres_lock;
?struct list_head?devres_head;

/* class_device migration path */
?struct list_head?node;
?struct class??*class;
?dev_t???devt;??/* dev_t, creates the sysfs "dev" */
?struct attribute_group?**groups;?/* optional groups */

void?(*release)(struct device * dev);
};

2、設備驅動的結構:

struct device_driver {
?const char??* name;???????????????????????????????? //設備驅動的名字
?struct bus_type??* bus;?????????????????????????????//設備驅動掛接的總線的類型

struct kobject??kobj;???????????????????????????????? //kobject結構

struct klist??klist_devices;???????????????????????????//這個驅動對應的設備的鏈表
?struct klist_node?knode_bus;

struct module??* owner;
?const char ??* mod_name;?/* used for built-in modules */

struct module_kobject?* mkobj;

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);
};

?

3、總線結構:

struct bus_type {
?const char??* name;?????????????????????????????????//總線的名字
?struct module??* owner;

struct kset??subsys;??????????????????????????????? //與該總線相關的subsystem

struct kset??drivers;???????????????????????????????//掛接在該總線上的驅動的集合
?struct kset??devices;?????????????????????????????? //掛接在該總線上的設備的集合
?struct klist??klist_devices;????????????????????????
?struct klist??klist_drivers;

struct blocking_notifier_head bus_notifier;

struct bus_attribute?* bus_attrs;????????????????? //總線屬性
?struct device_attribute?* dev_attrs;???????????????//設備屬性
?struct driver_attribute?* drv_attrs;?????????????? //驅動屬性

int??(*match)(struct device * dev, struct device_driver * drv);

int??(*uevent)(struct device *dev, struct kobj_uevent_env *env);
?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 (*suspend_late)(struct device * dev, pm_message_t state);
?int (*resume_early)(struct device * dev);
?int (*resume)(struct device * dev);

unsigned int drivers_autoprobe:1;
};

?

我們注意到只有在bus_type結構中有kset結構,其他兩個結構中則沒有,我們知道kset結構是用于存放相同類型的kobject的,這究竟是個什么意思呢?kset又是為什么而存在的呢?為什么不能就是kobject呢?(關于kobject結構,我們很難抽象的形容,盡管它就是一個抽象的概念,我們將留待看代碼的時候介紹,這里可以將kobject看成一個基類,kset就是容器了),下面我會按照自己的理解來回答這個問題(建議通讀一下《linux設備驅動第三版》的linux 設備模型章節)

?? 首先不管是設備還是驅動,都是掛接在某條總線上的,也就是說我們根據總線類型的不同來區分各種設備和驅動。(但是我們也要注意到,一個設備和驅動是可以掛接在不同的總線上的,比如網卡可以掛接在pci和sdio總線上,但這并不是說在linux設備模型中就可以同時掛接在兩個總線上,我們只能選擇其中的一種掛接)。

?? 在內核代碼中我們找到了bus_type結構,我們發現了它使用了三個kset結構,分別是:?????? struct kset? subsys? 、struct kset? drivers 、struct kset devices。我們先拋開subsys因為它是用來向上掛接的。這里我們先看drivers與devices兩個kset結構的意義。我們從發現一個設備或者驅動說起吧,一個設備或者驅動向內核注冊的時候(對于設備來說就是被插入了;對于驅動來說就是.ko模塊被加載了),對于每一次設備注冊或者驅動注冊,我們都得分配一個device結構或者device_drive結構,每一次我們都需要將device結構掛入drivers或devices(kset結構)鏈表中,這樣我們能通過總線找到掛接在這個總線上的所有設備和驅動。但是這里我們注意到僅僅將設備們和驅動們掛接在總線上并不能表明設備和驅動之間的關系,這樣的處理僅僅表明了驅動、設備與總線的關系,它們申明了我現在掛接在這條總線下,以后操作我就請通過這條總線。

那么設備如何認出驅動,或者驅動如何認出設備呢?是的,我們是使用的probe函數。那么需要完成哪些過程了?在這些結構總是如何關聯的?這才是我們關心的問題。所以這里我們將不得不在說明一下klist結構的作用。在內核代碼中我們再次找到了device結構和device_drive結構。我們注意到在device結構中存在一個struct device_driver *driver這樣的聲明,而在device_drive中卻并沒有同樣的包含device結構。我們這樣想就明白了:對于一個設備來說,我們只能綁定一個驅動;而對于一個驅動來說,我們是可以對應于多個設備的。也就是說這里device中的driver指針將會指向其綁定的驅動。那么回到probe探測函數,在我們對一個設備驅動進行注冊的過程中,我們會在其相應的總線(也就是其掛接的總線)上發出一個探測,這個探測會搜尋所有掛接在這個總線上的尚未被綁定的設備(也就是driver指針為NULL),然后將driver指針指向這個驅動的結構,同時將這個設備的device結構掛接在device_driver結構中的klist鏈表中。 另外要提及一點就是我居然發現在device結構中也發現了一個這樣的結構struct klist_node??? knode_driver,它看起來跟klist有關,但是我得說我確實不認為device需要一個klist來掛上它能使用的driver。同樣,當一個設備被注冊時,它也會去尋找掛接在同一條總線上的驅動,并將自己與這個驅動聯系起來。

?

?? 關于基礎知識大致就這么些,如果需要知道的更細,可以查看《linux設備驅動第三版》,后面的我們會結合代碼敘述注冊設備,發現設備(對于驅動來說這里的工作其實很少,如果想知道內核做了些什么,就請跟著我一起看看內核的奧秘),以及數據傳輸的驅動代碼。

?

sdio_register_driver(&sdio) 函數被調用從而注冊sdio驅動.這里已經進入內核部分代碼,他存在于內核的drivers/mmc/core/sdio_bus.c文件中,噢,忘了說了,我看的內核代碼版本是2.6.30.1.

貼一下sdio_register_driver函數:???

int sdio_register_driver(struct sdio_driver *drv)
{
??????? drv->drv.name = drv->name;?? //首先忽略下面兩行,直接進入driver_register函數.
??????? drv->drv.bus = &sdio_bus_type;???//實際上這行代碼是關鍵,而下面的函數中我們要找的僅僅是調用probe函數的地方而已,稍后分析

?????? return driver_register(&drv->drv);
}

?

來看driver_register函數的內容,由于其中涉及較多有關klist、kobject結構的內容,如果有不明白的地方,請查看同為《linux設備驅動——andriod平臺wlan驅動》系列的介紹klist、kobject內容的章節,這里希望有的放矢.它的代碼在drivers/base/driver.c中.
int driver_register(struct device_driver *drv)

{
??????? int ret;
??????? struct device_driver *other;

??????? if ((drv->bus->probe && drv->probe) ||
??????????? (drv->bus->remove && drv->remove) ||
??????????? (drv->bus->shutdown && drv->shutdown))

??????????????? printk(KERN_WARNING "Driver '%s' needs updating - please use "
??????????????????????? "bus_type methods\n", drv->name);

??????? other = driver_find(drv->name, drv->bus);??????? //在kobject結構組成的鏈表中查找是否已經存在這個驅動,以前的blog講過,驅動必然掛接在某個總線上.請復習,返回值是device_driver結構的指針

??????? if (other) {
??????????????? put_driver(other);??????????????? //由于之前增加了引用計數,這里在減1 ??????????????????????
??????????????? printk(KERN_ERR "Error: Driver '%s' is already registered, "
??????????????????????? "aborting...\n", drv->name);
??????????????? return -EEXIST;
??????? }

?????? ret = bus_add_driver(drv);???????????? //此函數是重點!
??????? if (ret)
??????????????? return ret;
??????? ret = driver_add_groups(drv, drv->groups);?????????????? //這兩個函數不用介紹也猜的出來
??????? if (ret)
??????????????? bus_remove_driver(drv);
??????? return ret;
}

?

那么我們接著看bus_add_driver函數,這個函數的作用是:如果驅動還未掛接在總線上,掛接它并且調用probe函數進行探測.它的代碼在drivers/base/bus.c中.
int bus_add_driver(struct device_driver *drv)???????????? //這個函數我不記得我的blog中是否有講過(我記得我寫過注釋,如果沒寫過,就請自己看吧? 呵呵 )
{

?????? .......................................
??????? if (drv->bus->p->drivers_autoprobe) {
??????????????? error = driver_attach(drv);?????????????????????????? //這個函數是重點.

??????????????? if (error)
??????????????????????? goto out_unregister;
??????? }
? ? ? ? ...................................... ?????
?}

driver_attach函數在drivers/base/dd.c中,很簡單的一句話:
?int driver_attach(struct device_driver *drv)
{
??????? return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

這個函數會調用__driver_attach函數,我們已經接近目標了.
static int __driver_attach(struct device *dev, void *data)
{
??????? struct device_driver *drv = data;

??????? /*

??????? * Lock device and try to bind to it. We drop the error
???????? * here and always return 0, because we need to keep trying
???????? * to bind to devices and some drivers will return an error
???????? * simply if it didn't support the device.
???????? *

???????? * driver_probe_device() will spit a warning if there
???????? * is an error.
???????? */

??????? if (dev->parent)??????? /* Needed for USB */

??????????????? down(&dev->parent->sem);
??????? down(&dev->sem);
??????? if (!dev->driver)
??????????????? driver_probe_device(drv, dev);????????????????????? //此函數就是我們要找的函數了.

?????? up(&dev->sem);
??????? if (dev->parent)
??????????????? up(&dev->parent->sem);

??????? return 0;
}

?

driver_probe_device函數中有一個really_probe函數,這是我們的最終目的地:
static int really_probe(struct device *dev, struct device_driver *drv)
{
??????? ...................................................

?????????? if (dev->bus->probe) {???????????????????????????????????????? //我們看到了這里會調用probe函數,同樣這里也會決定你的probe函數是使用一個參數還是兩個參數,
??????????????? ret = dev->bus->probe(dev);????????????????????????? 因為這取決于你是如何注冊的.也就是是否調用了(僅僅針對于網友的提問)platform_device_register

?????????????? if (ret)??????????????????????????????????????????????????????????????? 函數來注冊設備.具體看下面的總結.
??????????????????????? goto probe_failed;
??????? } else if (drv->probe) {

?????????????? ret = drv->probe(dev);
??????????????? if (ret)
??????????????????????? goto probe_failed;
??????? }
???????? ....................................................
}

好了,這里來總結一下得失,同時根據以上列的代碼回答網友的提問: if (dev->bus->probe)這個表示是否注冊了device結構,如果注冊了并且給device結構掛接上了驅動和總線,那么調用掛接在device結構中的總線的probe函數.這里的device結構從哪里冒出來的?它在 bus_for_each_dev函數中:

int bus_for_each_dev(struct bus_type *bus, struct device *start,
???????????????????? void *data, int (*fn)(struct device *, void *))
{
??????? struct klist_iter i;
??????? struct device *dev;

?????? int error = 0;

??????? if (!bus)
??????????????? return -EINVAL;

??????? klist_iter_init_node(&bus->p->klist_devices, &i,????????

???????????????????????????? (start ? &start->knode_bus : NULL));
??????? while ((dev = next_device(&i)) && !error)????????????????????????????????????? //查找每個掛接在sdio總線上的設備,看他們是否有注冊,并調用相應的probe函數也就是

?????????????? error = fn(dev, data);??????????????????????????????????????????????????????????????? __driver_attach函數.實際上就是查找device結構.
??????? klist_iter_exit(&i);
??????? return error;
}

關于platform_device結構與device結構的關系,就不用我在解釋了吧!probe函數的調用,就取決于你在你注冊的device結構中掛接的總線的類型了.因為調用 dev->bus->probe(dev); 所以清查看一下你注冊是掛接的總線的probe函數的參數即可. 一般來說,參數會是兩個,因為一類總線上總是可以掛接多個設備,所以我們還需要一個device_id. 如果行到else部分: else if (drv->probe) .這里調用驅動的probe函數,由于我們注冊的是sdio_driver結構.看一看sdio_driver結構的申明,在include/linux/mmc/sdio_func.h中:
struct sdio_driver {
??????? char *name;
??????? const struct sdio_device_id *id_table;

??????? int (*probe)(struct sdio_func *, const struct sdio_device_id *);???????????????????? //很顯然probe就是兩個參數,而不是一個.
??????? void (*remove)(struct sdio_func *);

??????? struct device_driver drv;
};

?

至于為什么你的probe是一個參數,我希望你能給出完整的注冊流程才能分析,但是我認為根據我剛才分析的流程應該可以自己找出相應的代碼了.

首先我要做的是總領一下kobject、kset、subsystem這三個結構之間的關系。同樣以下內容摘自我的工作筆記,但順序顛倒了,這里先行介紹可能對我們之后的代碼介紹要有些許幫助。

??? 關于kobject結構,首先每個目錄代表一個kobject對象,每個文件代表kobject的屬性(這里我實在不敢肯定!)。kobject是組成設備模型的基本結構,它只是一個類似c++中基類的東西。

?? 我想給出這樣一個比喻(我不知道這個比喻是否恰當):對于每一個目錄,它們都有一些共同的特點,比如都有名字,都有父子目錄。而對于“方法”來說,它們都有用來實現引用計數的方法。我們將這些共同點封裝起來形成了基類。但是這個基類并不能真正的代表一個目錄,加上了其它的特征之后才能成為一個真正的目錄,所以我們需要將kobject這個結構嵌入所有的sysfs下的目錄中以獲得kobject提供的一些特征,在加上每個目錄自己所獨有特征從而形成一個sysfs中的目錄。這也就是我理解的kobject結構的意義。那么kobject結構是否真的就對應于一個目錄呢?回答是肯定的,因為我在代碼中找到了這樣的答案,每一次調用kobject_add函數,都會在這個函數中調用create_dir來創建一個目錄。

那么kset又是什么呢?為什么需要kset?還有subsystem呢?kobject、kset、subsystem這三個結構到底在設備樹中各自承擔什么樣的角色?kset是是嵌入相同類型結構的kobject的集合,對于c++來說意味著將繼承自所有基類的子類放在一起,這有什么意義呢?這樣想是否就會覺得很合理了,kset是用來將所有有著共同特點的目錄聯系在一起的東西。可能你還是要在內心不停的問,這太抽象了太抽象了,能舉個例子嗎?是的,比如我們的設備樹下的pci總線目錄/sys/bus/pci下掛接著很多的設備和驅動(當然有很多的設備和驅動可以掛著在pci總線下),那么我們如何將它們聯系在一起呢?是的,是通過kset結構,那么kset結構是個什么樣的地位呢?噢,我想之前我理解錯了,它不是/sys/bus/pci目錄,也不是/sys/bus/pci/drivers目錄中的某個具體驅動,它剛好就是/sys/bus/pci/drivers目錄。不相信? 那么打開你們的linux操作系統,看一看是否每一條總線都有著drives和devices兩個目錄?它們兩個都是嵌入了kset結構;那么/sys/bus/pci/drivers目錄中的某個具體驅動呢?它就是嵌入了kobject結構的目錄;/sys/bus/pci目錄呢?猜對了,它就是subsystem結構的嵌入。 還有要補充的嗎?是呢,現在subsystem貌似被取消了,取代它的就是kset結構。這樣也就是說一系列的kset就組成了subsystem。

??? 我似乎忘記了自己問了三個問題,對的,我還需要問答自己看《linux設備驅動第三版》提出來的第三個問題:為什么需要kset?提出這個問題的想法很幼稚,難道我們不能夠只用kobject結構將掛接在一條總線上的驅動或者設備都鏈接在一起嗎?只要我們有list_head!linux內核的作者回答了我這個問題,你需要一個容器來管理它們,就像c++中的容器一樣。但這至少說明了kset并不是必要的存在。那么kset是如何扮演容器的角色的呢?這個問題,我們需要看后面的圖解來回答。

????以上是摘自我穿插在工作筆記中的關于kobject、ket、subsystem三個結構的描述,可能大家讀完這段解釋仍然無法形成具體的概念,仍然覺得很抽象。沒關系,因為我在代碼分析之后還會有總結性的舉例。那時還不明白我就沒轍了!!!

??? 好了,現在我們得費勁心思的捋一遍我們的驅動注冊代碼,以便找到設備樹添加的關鍵部分。我想我又得強調一下,我的介紹是SDIO驅動,所以請大家看著linux內核代碼drivers/mmc中關于sdio的驅動來理解我下面的筆記中的內容(想不看內核代碼就理解設備樹,我想太難太難)

?? 有關sbi_register函數(這是在我的wlan驅動代碼中的函數,并不需要你太多的關注)中sdio_register_driver函數(從現在開始就都是內核函數了)注冊驅動的介紹,在sdio_register_driver中將會指明驅動的名稱(這里是”wlan_sdio”),此函數的參數為sdio_driver結構。驅動所掛接的總線sdio_bus_type,其結構類型為:

? static struct bus_type sdio_bus_type =?{

???????????? .name???????????? = "sdio",???????????????? //總線類型

???????????? .dev_attrs?????? = sdio_dev_attrs,????????????? //屬性

???????????? .match?????????? = sdio_bus_match,???????? //ops

??????????? .uevent?????????? = sdio_bus_uevent,

???????????? .probe??????????? = sdio_bus_probe,?

???????????? .remove????????? = sdio_bus_remove,

};

??? 這個結構將在sdio_register_driver函數中被賦值以產生device_driver結構。也就是說device_driver被包含在sdio_driver中。隨后調用函數driver_register,其參數為device_driver(此結構中定義了bus_type,也就是驅動掛接的總線類型)。至此將轉入所有驅動(不止是sdio卡驅動)的注冊代碼中。此時的驅動結構已經變為device_drive(內核定義的驅動結構)。

??? driver_register將會完成掛接驅動至總線及生成設備樹的過程,其完成的任務大致包括:

??? 1、設置設備驅動中kobject的名字

????2、將kobject添加至sysfs中,也就是在sysfs樹中創建一個目錄(kobject中有一個函數create_dir用于創建目錄。)

????? 3、調用driver_attach函數完成probe?

????? 4、driver_create_file創建文件屬性,會生成一個屬性為driver_attr_uevent的屬性文件。

????? 5、add_bind_files生成屬性為driver_attr_unbind和driver_attr_bind的屬性文件,關于文件的屬性,它定義了文件的讀寫方式。

如此抽象的描述及流水賬般的記述我發現還是很沒有說服力,因此我決定給出一個具體的例子,并給出代碼的實現。先看例子——讓我們看一下/sys/bus/下的目錄,然后來個具體的描述:已知我們的總線的目錄名字為”sdio”。也就是說在/sys/bus目錄下有一個目錄叫sdio,即/sys/bus/sdio。它是怎么形成的?內核中有”sdio”總線的驅動,找到這個函數bus_register(&sdio_bus_type);就是用來注冊總線的。我們在前面不也看到了driver_register函數嗎,是的,你猜對了,還有一個函數叫device_register。在這個函數調用完成后,就會得到/sys/bus/目錄下的sdio目錄了。那么驅動的名字”wlan_sdio”又是如何插入到/sys/bus/drivers/wlan_sdio目錄下的呢。在driver_register->driver_register->bus_add_driver函數中有個重要的語句drv->kobj.kset = &bus->drivers;想象一下我們折騰了那么長時間的kobject與kset的意義,是的,這里就是將driver的kobj所屬的kset掛接上總線的kset。我們這里顯得很繞對嗎?幸運的是我在網上找到了一個非常棒的示意圖:

?

? 我該怎么樣來形容這個圖呢? 它把依賴關系說的已經足夠清楚了!!我這里唯一要解釋的僅僅是在驅動文件夾被正確后所謂的文件屬性有在那里。同樣我們順著目錄/sys/bus/sdio/driver/wlan_sdio/下我們發現了bind、unbind和new_id三個文件。

?? 好了,別忘了我們在前面提過的問題,kset是如何扮演容器的角色的呢?圖中很清楚吧,看看粉紅色的箭頭,kset children list用來將將同類型的kobject連接起來以達到容器的效果。

?但是我們的驅動還沒有結束,關于這個圖的建立,我們勢必要用代碼才能說得明白。

我們還是花費一點時間來看一下內核中的代碼,關于sdio總線注冊的代碼部分,其它的部分,大家類舉就可以了。懂了這段自然就懂了全部:

int bus_register(struct bus_type * bus)

{

?????? int retval;

?

?????? BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);

????? retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);?? ?//總線的名字”sdio”,我們說過了一個kobject對應一個目錄,這時會為這個目錄賦值名字。

?????? if (retval)

????????????? goto out;

?????? bus->subsys.kobj.kset = &bus_subsys;????????????????????? ??//將其kset指向bus_subsys.,如何理解? 看看ldd_bus_type指向bus_subsys的那條藍線

?????? retval = subsystem_register(&bus->subsys);???????????? ?//bus->subsys的注冊,實際上是用kset指針將其鏈接在一起。好吧 我得承認實際上這里取消了subsysem結構的概念,用kset代替了。這里會創建一個目錄。它是一個kset也是一個kobject,因為kset包含了kobject。

?????? if (retval)

????????????? goto out;

?????? retval = bus_create_file(bus, &bus_attr_uevent);?????????? ?//創建屬性文件

?????? if (retval)

????????????? goto bus_uevent_fail;

?????? kobject_set_name(&bus->devices.kobj, "devices");??????? ?//設置devices kset的名字為devices

?????? bus->devices.kobj.parent = &bus->subsys.kobj;??????????? //參見ldd_bus_type->devices指向ldd_bus_type->sub_sys的紅色箭頭(注意這里也不是subsystem,而是kset)

?????? retval = kset_register(&bus->devices);???????????????? //創建devices命名的目錄

?????? if (retval)

????????????? goto bus_devices_fail;

?????? kobject_set_name(&bus->drivers.kobj, "drivers");?????? //設置devices kset的名字為drivers

?????? bus->drivers.kobj.parent = &bus->subsys.kobj;???????? //同樣參見ldd_bus_type->drivers指向ldd_bus_type->sub_sys的紅色箭頭(注意這里也不是subsystem,而是kset)。

????? bus->drivers.ktype = &driver_ktype;?????????? ????????//對kobject默認屬性的賦值

?????? retval = kset_register(&bus->drivers);??????????????? ?//創建drivers命名的目錄

?????? if (retval)

????????????? goto bus_drivers_fail;

????? klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);?? ?//klist結構的初始化,關于klist鏈接的作用我們已經說得很清楚了

?????? klist_init(&bus->klist_drivers, NULL, NULL);

????? bus->drivers_autoprobe = 1;

?????? retval = add_probe_files(bus);???????????????????? ?//添加探測屬性

?????? if (retval)

????????????? goto bus_probe_files_fail;

????? retval = bus_add_attrs(bus);????????????????????? ?//添加其他屬性

?????? if (retval)

????????????? goto bus_attrs_fail;

?

?????? pr_debug("bus type '%s' registered\n", bus->name);

?????? return 0;

bus_attrs_fail:

?????? remove_probe_files(bus);

bus_probe_files_fail:

?????? kset_unregister(&bus->drivers);

bus_drivers_fail:

????? kset_unregister(&bus->devices);

bus_devices_fail:

?????? bus_remove_file(bus, &bus_attr_uevent);

bus_uevent_fail:

?????? subsystem_unregister(&bus->subsys);

out:

?????? return retval;

}

至此 我們終于理順了整個過程。

?


總結

以上是生活随笔為你收集整理的linux设备驱动——andriod平台wlan驱动的全部內容,希望文章能夠幫你解決所遇到的問題。

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