試著總結一下,學習一下,至少現在的我對於裝置模型這個概念,幾乎完全不懂。
Linux裝置模型中三個很重要的概念就是匯流排、裝置和驅動,即bus、device、driver,而實際上核心中也定義了這麼一些資料結構,分別為struct bus_type,struct device,struct device_driver,
原型定義均在include/linux/device.h中。而struct bus_type結構中兩個非常重要的成員就是kset和kobject這兩個結構體。
於是乎,Linux裝置模型概念中重要的5個概念都引出來了,即裝置模型
在具體實現方面分兩個層次:
一是底層資料結構來實現基本對象及其層次關係:kobjects和ksets。
二是基於這兩個底層資料結構上實現的裝置模型:匯流排,裝置,驅動。
一、底層資料結構:kobject,kset
kobject
結合物件導向的思維。這個kobject屬於最基礎的結構,也就是最高抽象層(有點像java中的Cobject類)。任何一個裝置模型如匯流排,裝置,驅動都屬於一個kobject 。在實現上這種派生關係就是在結構體中包含一個kobject的變數。
這個在層次上處理最頂層的kobject結構提供了所有模型需要的最基本的功能:
1 引用計數 用於核心維護其存在與消亡
2 sysfs表示 每個sys/下的對象對應著一個kobject。
3 熱拔插事件處理 處理裝置的熱拔插事件。
Kobjects 在核心中對應有一套申請,初始化,添加,註冊,計數操作,釋放等函數
//2.6.10
struct kobject {
char * k_name; //名稱
char name[KOBJ_NAME_LEN];
struct kref kref; //計數
struct list_head entry;//用於串連到同類kobjects的鏈表
struct kobjectn * parent;//用於實現層次,指向其父物件
struct kset * kset; //用於實現層次,所屬的集合
struct kobj_typen * ktype;//指向對象的類型
struct dentry * dentry; //指示在sysfs中的目錄項
};
Kset和kobj_type
Kset在概念上是一個集合或者叫容器。實現了對象的層次。所有屬於一個ksets的對象(kobject)的parent都指向該ksets的kobj.同時這個對象都串連到kset 的list表上。同時位於ksets層次之上的是subsys,在最新的核心中已經取消subsys,因為它本質上也就是一個ksets。Kset有一套類似kobject的操作,實現上只是進一步調用其自身kobj的相應操作,畢竟ksets本質上也是一個kobject。
//2.6.10
struct kset {
struct subsystem * subsys; //在新核心中已經沒有subsys概念了,統一用kests
struct kobj_type * ktype; //類型
struct list_head list; //同一kset的鏈表
struct kobject kobj; //自身的kobjects
struct kset_hotplug_ops * hotplug_ops;
};
最後 屬於同一個集合的對象可以擁有共同的屬性:ktype 。
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
所謂的屬性更具體一點說就是一些索引值對。並且在sysfs_ops中的show函數被檔案系統調用來顯示sys/下面對應入口各屬性的值。
如此 ,kobjects與ksets實現層次樹的底層骨架。
進一步地,通過封裝這些底層結構來實現上層的裝置驅動模型。
二、匯流排 裝置 驅動
關於bus,關於device,關於driver,他們是如何建立聯絡的呢?
基本關係簡要的概括如下:
驅動核心可以註冊多種類型的匯流排。
每種匯流排下面可以掛載許多裝置。(通過kset devices)
每種匯流排下可以用很多裝置驅動。(通過包含一個kset drivers)}
每個驅動可以處理一組裝置。
這種基本關係的建立源於實際系統中各種匯流排,裝置,驅動結構的抽象。
具體到usb裝置就是usb core的代碼會進行整個usb系統的初始化,比如申請struct bus_type usb_bus_type,然後掃描usb匯流排,看線上串連了哪些usb裝置,或者說root hub上連了哪些usb裝置
,比如說連了一個usb鍵盤,那麼就為它準備一個struct device,根據它的實際情況,為這個struct device賦值,並插入devices鏈表中來。又比如root hub上連了一個普通的hub,那麼除了要為這個hub本身準備一個struct device以外,還得繼續掃描這個hub上是否又連了別的裝置,有的話繼續重複之前的事情,這樣一直進行下去,直到完成整個掃描,最終就把usb_bus_type中的devices鏈表給建立了起來。
那麼drivers鏈表呢?這個就不用bus方面主動了,而該由每一個driver本身去bus上面登記,或者說掛牌。具體到usb系統,每一個usb裝置的驅動程式都會有一個struct usb_driver結構體,其代
碼如下,來自include/linux/usb.h
//2.6.10
struct usb_driver {
struct module *owner;
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
int (*suspend) (struct usb_interface *intf, u32 state);
int (*resume) (struct usb_interface *intf);
const struct usb_device_id *id_table;
struct device_driver driver;
};
bus和device之間是如何建立聯絡的?
看似很長一段,實際上也就是注釋為主.而此刻我們只需注意到其中的struct device_driver driver這個成員,usb core為每一個裝置驅動準備了一個函數,讓它把自己的這個
struct device_driver driver插入到usb_bus_type中的drivers鏈表中去.而這個函數正是我們此前看到的usb_register.而與之對應的 usb_deregister所從事的正是與之相反的工作,把這個結構
體從drivers鏈表中刪除.可以說,usb core的確是用心良苦,為每一個usb裝置驅動做足了功課,正因為如此,作為一個實際的usb裝置驅動,它在初始化階段所要做的事情就很少,很簡單了, 直接調用
usb_register即可.事實上,沒有人是理所當然應該為你做什麼的,但usb core這麼做了.所以每一個寫usb裝置驅動的人應該銘記,usb device driver絕不是一個人在工作,在他身後,是usb core所提
供的默默無聞又不可或缺的支援。
device和driver之間是如何建立聯絡的呢?
因為有了熱插拔,device可以在電腦啟動以後在插入或者拔出電腦了.因此,很難再說是先有device還是先有driver了.因為都有可能.device可以在任何時刻出現,而driver也可以在任何時刻被載入,所以,出現的情況就是,每當一個struct device誕生,它就會去bus的drivers鏈表中尋找自己的另一半,反之,每當一個一個struct device_driver誕生,它就去bus的devices鏈表中尋找它的那些裝置.如果找到了合適的,那麼ok,調用 device_bind_driver綁定好.如果找不到,沒有關係,等待吧。
還記得初始化的那幾行代碼嗎?回到usb_register中來,看一下傳給他的參數是什嗎?
我們注意到,那句調用是這樣子的,
/* register the driver, return usb_register return code if error */
retval = usb_register(&usb_storage_driver);
是的,傳遞了一個叫做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,
};
可以看到這裡定義了一個struct usb_driver的結構體變數,usb_storage_driver,關於usb_driver我們上節已經說過了,當時主要說的是其中的成員driver,而眼下要講的則是另外幾個成員.首先,.owner
和.name這兩個沒啥好多說的,owner這玩藝是用來給模組計數的,每個模組都這麼用,賦值總是THIS_MODULE,而name就是這個模組的名字,usb core會處理它,所以如果這個模組正常被載入了的話,使用lsmod命令能看到一個叫做usb-storage的模組名。
------------------------------------------------------------------------------------------------------------------
作者:龐輝
出處:http://www.cnblogs.com/pang123hui/
本文基於署名 2.5 中國大陸許可協議發布,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名龐輝(包含連結).