試著總結(jié)一下,學(xué)習(xí)一下,至少現(xiàn)在的我對(duì)于設(shè)備模型這個(gè)概念,幾乎完全不懂。
Linux設(shè)備模型中三個(gè)很重要的概念就是總線、設(shè)備和驅(qū)動(dòng),即bus、device、driver,而實(shí)際上內(nèi)核中也定義了這么一些數(shù)據(jù)結(jié)構(gòu),分別為struct bus_type,struct device,struct device_driver,
原型定義均在include/linux/device.h中。而struct bus_type結(jié)構(gòu)中兩個(gè)非常重要的成員就是kset和kobject這兩個(gè)結(jié)構(gòu)體。
于是乎,Linux設(shè)備模型概念中重要的5個(gè)概念都引出來了,即設(shè)備模型
在具體實(shí)現(xiàn)方面分兩個(gè)層次:
一是底層數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)基本對(duì)象及其層次關(guān)系:kobjects和ksets。
二是基于這兩個(gè)底層數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)的設(shè)備模型:總線,設(shè)備,驅(qū)動(dòng)。
一、底層數(shù)據(jù)結(jié)構(gòu):kobject,kset
kobject
結(jié)合面向?qū)ο蟮乃季S。這個(gè)kobject屬于最基礎(chǔ)的結(jié)構(gòu),也就是最高抽象層(有點(diǎn)像java中的Cobject類)。任何一個(gè)設(shè)備模型如總線,設(shè)備,驅(qū)動(dòng)都屬于一個(gè)kobject 。在實(shí)現(xiàn)上這種派生關(guān)系就是在結(jié)構(gòu)體中包含一個(gè)kobject的變量。
這個(gè)在層次上處理最頂層的kobject結(jié)構(gòu)提供了所有模型需要的最基本的功能:
1 引用計(jì)數(shù) 用于內(nèi)核維護(hù)其存在與消亡
2 sys水利模型fs表示 每個(gè)sys/下的對(duì)象對(duì)應(yīng)著一個(gè)kobject。
3 熱拔插事件處理 處理設(shè)備的熱拔插事件。
Kobjects 在內(nèi)核中對(duì)應(yīng)有一套申請(qǐng),初始化,添加,注冊(cè),計(jì)數(shù)操縱,開釋等函數(shù) //2.6.10 struct kobject { char * k_name; //名稱 char name[KOBJ_NAME_LEN]; struct kref kref; //計(jì)數(shù) struct list_head entry;//用于連接到同類kobjects的鏈表 struct kobjectn * parent;//用于實(shí)現(xiàn)層次,指向其父對(duì)象 struct kset * kset; //用于實(shí)現(xiàn)層次,所屬的集合 struct kobj_typen * ktype;//指向?qū)ο蟮念愋?struct dentry * dentry; //指示在sysfs中的目錄項(xiàng) }; Kset和kobj_type
Kset在概念上是一個(gè)集合或者叫容器。實(shí)現(xiàn)了對(duì)象的層鍋爐模型次鍋爐模型。所有屬于一個(gè)ksets的對(duì)象(kobject)的parent都指向該ksets的kobj.同時(shí)這個(gè)對(duì)象都連接到kset 的list表上。同時(shí)位于ksets層次之上的是subsys,在最新的內(nèi)核中已經(jīng)取消subsys,由于它本質(zhì)上也就是一個(gè)ksets。Kset有一套類似kobject的操縱,實(shí)現(xiàn)上只是進(jìn)一步調(diào)用其自身kobj的相應(yīng)操縱,究竟ksets本質(zhì)上也是一個(gè)kobject。 //2.6.10 struct kset { struct subsystem * subsys; //在新內(nèi)核中已經(jīng)沒有subsys概念了,同一用kests struct kobj_type * ktype; //類型 struct list_head list; //同一kset的鏈表 struct kobject kobj; //自身的kobjects struct kset_hotplug_ops * hotplu鍋爐模型g_ops; }; 最后 屬于同一個(gè)集合的對(duì)象可以擁有共同的屬性:ktype 。
struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops; struct attribute ** default_attrs; }; 所謂的屬性更具體一點(diǎn)說就是一些鍵值對(duì)。并且在sysfs_ops中的show函數(shù)被文件系統(tǒng)調(diào)用來顯示sys/下面對(duì)應(yīng)進(jìn)口各屬性的值。
如此 ,kobjects與ksets實(shí)現(xiàn)層次樹的底層骨架。
進(jìn)一步地,通過封裝這些底層結(jié)構(gòu)來實(shí)現(xiàn)上層的設(shè)備驅(qū)動(dòng)模型。
二、總線 設(shè)備 驅(qū)動(dòng)
關(guān)于bus,關(guān)于device,關(guān)于driver,他們是如何建立聯(lián)系的呢?
基本關(guān)系扼要的概括如下:
驅(qū)動(dòng)核心可以注冊(cè)多種類型的總線。
每種總線下面可以掛載很多設(shè)備。(通過kset devices)
每種總線下可以用很多設(shè)備驅(qū)動(dòng)。(通過包含一個(gè)kset drivers)}
每個(gè)驅(qū)動(dòng)可以處理一組設(shè)備。
這種基本關(guān)系的建立源于實(shí)際系統(tǒng)中各種總線,設(shè)備,驅(qū)動(dòng)結(jié)構(gòu)的抽象。
具體到usb設(shè)備就是usb core的代碼會(huì)進(jìn)行整個(gè)usb系統(tǒng)的初始化,比如申請(qǐng)struct bus_type usb_bus_type,然后掃描usb總線,看線上連接了哪些usb設(shè)備,或者說root hub上連了哪些usb設(shè)備
,比如說連了一個(gè)usb鍵盤,那么就為它預(yù)備一個(gè)struct device,根據(jù)它的實(shí)際情況,為這個(gè)struct device賦值,并插進(jìn)devices鏈表中來。又比沙盤模型如root hub上連了一個(gè)普通的hub,那么除了要為這個(gè)hub本身預(yù)備一個(gè)struct device以外,還得繼續(xù)掃描這個(gè)hub上是否又連了別的設(shè)備,有的話繼續(xù)重復(fù)之前的事情,這樣一直進(jìn)行下往,直到完成整個(gè)掃描,終極就把usb_bus_type中的devices鏈表給建立了起來。
那么drivers鏈表呢?這個(gè)就不用bus方面主動(dòng)了,而該由每一個(gè)driver本身往bus上面登記,或者說掛牌。具體到usb系統(tǒng),每一個(gè)usb設(shè)備的驅(qū)動(dòng)程序都會(huì)有一個(gè)struct usb_driver結(jié)構(gòu)體,其代
碼如下,來自include/linux/usb.h //2.6.10 struct usb_driver { struct module *owner; const char *name; int (*probe) (struct usb_inte***ce *intf, const struct usb_device_id *id); void (*disconnect) (struct usb_inte***ce *intf); int (*ioctl) (struct usb_inte***ce *intf, unsigned int code, void *buf); int (*suspend) (struct usb_inte***ce *intf, u32 state); int (*resume) (struct usb_inte***ce *intf); const str沙盤模型//" title="沙盤模型" target="_blank ">沙盤模型uct usb_device_id *id_table; struct device_driver driver; }; bus和device之間是如何建立聯(lián)系的?
看似很長(zhǎng)一段,實(shí)際上也就是注釋為主.而此刻我們只需留意到其中的struct device_driver driver這個(gè)成員,usb core為每一個(gè)設(shè)備驅(qū)動(dòng)預(yù)備了一個(gè)函數(shù),讓它把自己的這個(gè)
struct device_driver driver插進(jìn)到usb_bus_type中的drivers鏈表中往.而這個(gè)函數(shù)正是我們此前看到的usb_register.而與之對(duì)應(yīng)的 usb_deregister所從事的正是與之相反的工作,把這個(gè)結(jié)構(gòu)
體從drivers鏈表中刪除.可以說,usb core的確是專心良苦,為每一個(gè)usb設(shè)備驅(qū)動(dòng)做足了作業(yè),正由于如此,作為一個(gè)實(shí)際的usb設(shè)備驅(qū)動(dòng),它在初始化階段所要做的事情就很少,很簡(jiǎn)單了, 直接調(diào)用
usb_register即可.事實(shí)上,沒有人是理所當(dāng)然應(yīng)該為你做什么的,但usb core這么做了.所以每一個(gè)寫usb設(shè)備驅(qū)動(dòng)的人應(yīng)該銘記,usb device driver盡不是一個(gè)人在工作,在他身后,是usb core所提
供的默默無(wú)聞?dòng)植豢苫蛉钡闹С帧?
device和driver之間是如何建立聯(lián)系的呢?
由于有了熱插拔,device可以在計(jì)算機(jī)啟動(dòng)以后在插進(jìn)或者拔出計(jì)算機(jī)了.因此,很難再說是先有device還是先有driver了.由于都有可能.device可以在任何時(shí)刻出現(xiàn),而driver也可以在任何時(shí)刻被加載,所以,出現(xiàn)的情況就是,每當(dāng)一個(gè)struct device誕生,它就會(huì)往bus的drivers鏈表中尋找自己的另一半,反之,每當(dāng)一個(gè)一個(gè)struct device_driver誕生,它就往bus的devices鏈表中尋找它的那些設(shè)備.假如找到了合適的,那么ok,調(diào)用 device_bind_driver綁定好.假如找不到,沒有關(guān)系,等待吧。
還記得初始化的那幾行代碼嗎?回到usb_register中來,看一下傳給他的參數(shù)是什么?
我們留意到,那句調(diào)用是這樣子的, /* register the driver, return usb_register return code if error */ retval = usb_register(&usb_storage_driver); 是的,傳遞了一個(gè)叫做usb_storage_driver的家伙,這是什么?同一文件中,drivers/usb/storage/usb.c:
struct usb_driver usb_storage_driver = { .owner = THIS_MODULE, .name = "usb-storage", .probe = storage_probe, .disconnect = storage_disconnect, .id_table = storage_usb_ids, }; 可以看到這里定義了一個(gè)struct usb_driver的結(jié)構(gòu)體變量,usb_storage_driver,關(guān)于usb_driver我們上節(jié)已經(jīng)說過了,當(dāng)時(shí)主要說的是其中的成員driver,而眼下要講的則是另外幾個(gè)成員.首先,.owner
和.name這兩個(gè)沒啥好多說的,owner這玩藝是用來給模塊計(jì)數(shù)的,每個(gè)模塊都這么用,賦值總是THIS_MODULE,而name就是這個(gè)模塊的名字,usb core會(huì)處理它,所以假如這個(gè)模塊正常被加載了的話,使用lsmod命令能看到一個(gè)叫做usb-storage的模塊名。
|