武漢電腦培訓資訊:Linux中總線、設備、驅動是如何關聯(lián)的?

武漢
當前位置:求學問校網(wǎng)首頁>武漢資訊>武漢電腦培訓資訊

Linux中總線、設備、驅動是如何關聯(lián)的?

來源:求學問校網(wǎng)     發(fā)表時間:2011-08-31     瀏覽 102

作者:武漢華嵌技術部

 

對于Linux驅動開發(fā)來說,設備模型的理解是根本,顧名思義設備模型是關于設備的模型,設備的概念就是總線和與其相連的各種設備了。

電腦城的IT 工作者都會知道設備是通過總線連到計算機上的,而且還需要對應的驅動才能用,可是總線是如何發(fā)現(xiàn)設備的,設備又是如何和驅動對應起來的?

總線、設備、驅動,也就是bus、device、driver,在內核里都會有它們自己專屬的結構,在include/linux/device.h 里定義。

首先是總線,bus_type.
struct bus_type {
const char  * name;
struct subsystem subsys;//代表自身
struct kset  drivers;   //當前總線的設備驅動集合
struct kset  devices; //所有設備集合
struct klist  klist_devices;
struct klist  klist_drivers;
struct bus_attribute * bus_attrs;//總線屬性
struct device_attribute * dev_attrs;//設備屬性
struct driver_attribute * drv_attrs;
int  (*match)(struct device * dev, struct device_driver * drv);//設備驅動匹配函數(shù)
int  (*uevent)(struct device *dev, char **envp,   
      int num_envp, char *buffer, int buffer_size);//熱拔插事件
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);
};

下面是設備device的定義:

struct device {
struct device  * parent; //父設備,一般一個bus也對應一個設備。
struct kobject kobj;//代表自身
char bus_id[BUS_ID_SIZE]; 
struct bus_type * bus;  /* 所屬的總線 */
struct device_driver *driver; /* 匹配的驅動*/
void  *driver_data; /* data private to the driver 指向驅動 */
void  *platform_data; /* Platform specific data,由驅動定義并使用*/
///更多字段忽略了
};
下面是設備驅動定義:
struct device_driver {
const char  * name;
struct bus_type  * bus;//所屬總線
struct completion unloaded;
struct kobject  kobj;//代表自身
struct klist  klist_devices;//設備列表
struct klist_node knode_bus;
struct module  * owner;
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);
};

 

我們會發(fā)現(xiàn),structbus_type中有成員structksetdrivers 和structksetdevices,同時structdevice中有兩個成員struct bus_type * bus和struct device_driver *driver , structdevice_driver中有兩個成員structbus_type*bus和structklistklist_devices。structdevice中的bus表示這個設備連到哪個總線上,driver表示這個設備的驅動是什么,structdevice_driver中的bus表示這個驅動屬于哪個總線,klist_devices表示這個驅動都支持哪些設備,因為這里device是復數(shù),又是list,更因為一個驅動可以支持多個設備,而一個設備只能綁定一個驅動。當然,structbus_type中的drivers和devices分別表示了這個總線擁有哪些設備和哪些驅動。

還有上面device 和driver結構里出現(xiàn)的kobject 結構是什么?kobject 和kset 都是Linux 設備模型中最基本的元素。一般來說應該這么理解,整個Linux 的設備模型是一個OO 的體系結構,總線、設備和驅動都是其中鮮活存在的對象,kobject 是它們的基類,所實現(xiàn)的只是一些公共的接口,kset 是同種類型kobject 對象的集合,也可以說是對象的容器。

那么總線、設備和驅動之間是如何關聯(lián)的呢?

先說說總線中的那兩條鏈表是怎么形成的。內核要求每次出現(xiàn)一個設備就要向總線匯報,或者說注冊,每次出現(xiàn)一個驅動,也要向總線匯報,或者說注冊。比如系統(tǒng)初始化的時候,會掃描連接了哪些設備,并為每一個設備建立起一個structdevice 的變量,每一次有一個驅動程序,就要準備一個tructdevice_driver 結構的變量。把這些變量統(tǒng)統(tǒng)加入相應的鏈表,device 插入devices 鏈表,driver 插入drivers 鏈表。這樣通過總線就能找到每一個設備,每一個驅動。

設備和驅動又是如何聯(lián)系?

原來是把每一個要用的設備在計算機啟動之前就已經(jīng)插好了,插放在它應該在的位置上,然后計算機啟動,然后操作系統(tǒng)開始初始化,總線開始掃描設備,每找到一個設備,就為其申請一個structdevice 結構,并且掛入總線中的devices 鏈表中來,然后每一個驅動程序開始初始化,開始注冊其struct device_driver 結構,然后它去總線的devices 鏈表中去尋找(遍歷),去尋找每一個還沒有綁定驅動的設備,structdevice 中的structdevice_driver 指針仍為空的設備,然后它會去觀察這種設備的特征,看是否是他所支持的設備,如果是,那么調用一個叫做device_bind_driver 的函數(shù),然后他們就結為了秦晉之好。換句話說,把structdevice 中的structdevice_driverdriver 指向這個驅動,而struct device_driver driver 把struct device 加入他的那structklist klist_devices鏈表中來。就這樣,bus、device 和driver,這三者之間或者說他們中的兩兩之間,就給聯(lián)系上了。知道其中之一,就能找到另外兩個。

但現(xiàn)在情況變了,出現(xiàn)了一種新的名詞,叫熱插拔。設備可以在計算機啟動以后在插入或者拔出計算機了。設備可以在任何時刻出現(xiàn),而驅動也可以在任何時刻被加載,所以,出現(xiàn)的情況就是,每當一個structdevice 誕生,它就會去bus 的drivers鏈表中尋找自己的另一半,反之,每當一個struct device_driver 誕生,它就去bus的devices 鏈表中尋找它的那些設備。如果找到了合適的,那么OK,和之前那種情況一下,調device_bind_driver 綁定好。如果找不到,沒有關系,等待吧!