1. 程式人生 > >Linux內核(7) - 設備模型(上)

Linux內核(7) - 設備模型(上)

結點 沒有 call 會有 可能 特征 ike 股票 插入

對於驅動開發來說,設備模型的理解是根本,毫不誇張得說,理解了設備模型,再去看那些五花八門的驅動程序,你會發現自己站在了另一個高度,從而有了一種俯視的感覺,就像鳳姐俯視知音和故事會,韓峰同誌俯視女下屬。

顧名而思義就知道設備模型是關於設備的模型,既不是任小強們的房模,也不是張導的炮模。對咱們寫驅動的和不寫驅動的人來說,設備的概念就是總線和與其相連的各種設備了。電腦城的IT工作者都會知道設備是通過總線連到計算機上的,而且還需要對應的驅動才能用,可是總線是如何發現設備的,設備又是如何和驅動對應起來的,它們經過怎樣的艱辛才找到命裏註定的那個他,它們的關系如何,白頭偕老型的還是朝三暮四型的,這些問題就不是他們關心的了,而是咱們需要關心的。在房市股市千錘百煉的咱們還能夠驚喜的發現,這些疑問的中心思想中心詞匯就是總線、設備和驅動,沒錯,它們就是咱們這裏要聊的Linux設備模型的名角。

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

52 struct bus_type {
53 const char * name;
54 struct module * owner;
55
56 struct kset subsys;
57 struct kset drivers;
58 struct kset devices;
59 struct klist klist_devices;
60 struct klist klist_drivers;
61
62 struct blocking_notifier_head bus_notifier;
63
64 struct bus_attribute * bus_attrs;
65 struct device_attribute * dev_attrs;
66 struct driver_attribute * drv_attrs;
67 struct bus_attribute drivers_autoprobe_attr;
68 struct bus_attribute drivers_probe_attr;
69
70 int (*match)(struct device * dev, struct device_driver * drv);
71 int (*uevent)(struct device *dev, char **envp,
72 int num_envp, char *buffer, int buffer_size);
73 int (*probe)(struct device * dev);
74 int (*remove)(struct device * dev);
75 void (*shutdown)(struct device * dev);
76
77 int (*suspend)(struct device * dev, pm_message_t state);
78 int (*suspend_late)(struct device * dev, pm_message_t state);
79 int (*resume_early)(struct device * dev);
80 int (*resume)(struct device * dev);
81
82 unsigned int drivers_autoprobe:1;
83 };

124 struct device_driver {
125 const char * name;
126 struct bus_type * bus;
127
128 struct kobject kobj;
129 struct klist klist_devices;
130 struct klist_node knode_bus;
131
132 struct module * owner;
133 const char * mod_name; /* used for built-in modules */
134 struct module_kobject * mkobj;
135
136 int (*probe) (struct device * dev);
137 int (*remove) (struct device * dev);
138 void (*shutdown) (struct device * dev);
139 int (*suspend) (struct device * dev, pm_message_t state);
140 int (*resume) (struct device * dev);
141 };

407 struct device {
408 struct klist klist_children;
409 struct klist_node knode_parent; /* node in sibling list */
410 struct klist_node knode_driver;
411 struct klist_node knode_bus;
412 struct device *parent;
413
414 struct kobject kobj;
415 char bus_id[BUS_ID_SIZE]; /* position on parent bus */
416 struct device_type *type;
417 unsigned is_registered:1;
418 unsigned uevent_suppress:1;
419
420 struct semaphore sem; /* semaphore to synchronize calls to
421 * its driver.
422 */
423
424 struct bus_type * bus; /* type of bus device is on */
425 struct device_driver *driver; /* which driver has allocated this
426 device */
427 void *driver_data; /* data private to the driver */
428 void *platform_data; /* Platform specific data, device
429 core doesn‘t touch it */
430 struct dev_pm_info power;
431
432 #ifdef CONFIG_NUMA
433 int numa_node; /* NUMA node this device is close to */
434 #endif
435 u64 *dma_mask; /* dma mask (if dma‘able device) */
436 u64 coherent_dma_mask;/* Like dma_mask, but for
437 alloc_coherent mappings as
438 not all hardware supports
439 64 bit addresses for consistent
440 allocations such descriptors. */
441
442 struct list_head dma_pools; /* dma pools (if dma‘ble) */
443
444 struct dma_coherent_mem *dma_mem; /* internal for coherent mem
445 override */
446 /* arch specific additions */
447 struct dev_archdata archdata;
448
449 spinlock_t devres_lock;
450 struct list_head devres_head;
451
452 /* class_device migration path */
453 struct list_head node;
454 struct class *class;
455 dev_t devt; /* dev_t, creates the sysfs "dev" */
456 struct attribute_group **groups; /* optional groups */
457
458 void (*release)(struct device * dev);
459 };

有沒有發現它們的共性是什麽?對,不是很傻很天真,而是很長很復雜。不過不妨把它們看成藝術品,既然是藝術,當然不會讓你那麽容易的就看懂了,不然怎麽稱大師稱名家。這麽想想咱們就會比較的寬慰了,阿Q是魯迅對咱們80後最大的貢獻。

我知道進入了21世紀,最缺的就是耐性,房價股價都讓咱們沒有耐性,內核的代碼也讓人沒有耐性。不過做為最沒有耐性的一代人,還是要平心靜氣的掃一下上面的結構,我們會發現,struct bus_type中有成員struct kset drivers 和struct kset devices,同時struct device中有兩個成員struct bus_type * bus和struct device_driver *driver,struct device_driver中有兩個成員struct bus_type * bus和struct klist klist_devices。先不說什麽是klist、kset,光從成員的名字看,它們就是一個完美的三角關系。我們每個人心中是不是都有兩個她?一個夢中的她,一個現實中的她。

憑一個男人的直覺,我們可以知道,struct device中的bus表示這個設備連到哪個總線上,driver表示這個設備的驅動是什麽,struct device_driver中的bus表示這個驅動屬於哪個總線,klist_devices表示這個驅動都支持哪些設備,因為這裏device是復數,又是list,更因為一個驅動可以支持多個設備,而一個設備只能綁定一個驅動。當然,struct bus_type中的drivers和devices分別表示了這個總線擁有哪些設備和哪些驅動。

單憑直覺,張鈺紅不了。我們還需要看看什麽是klist、kset。還有上面device和driver結構裏出現的kobject結構是什麽?作為一個五星紅旗下長大的孩子,我可以肯定的告訴你,kobject和kset都是Linux設備模型中最基本的元素,總線、設備、驅動是西瓜,kobjcet、klist是種瓜的人,沒有幕後種瓜人的汗水不會有清爽解渴的西瓜,我們不能光知道西瓜的的甜,還要知道種瓜人的辛苦。kobject和kset不會在意自己的得失,它們存在的意義在於把總線、設備和驅動這樣的對象連接到設備模型上。種瓜的人也不會在意自己的汗水,在意的只是能不能送出甜蜜的西瓜。

一般來說應該這麽理解,整個Linux的設備模型是一個OO的體系結構,總線、設備和驅動都是其中鮮活存在的對象,kobject是它們的基類,所實現的只是一些公共的接口,kset是同種類型kobject對象的集合,也可以說是對象的容器。只是因為C裏不可能會有C++裏類的class繼承、組合等的概念,只有通過kobject嵌入到對象結構裏來實現。這樣,內核使用kobject將各個對象連接起來組成了一個分層的結構體系,就好像馬列主義將我們13億人也連接成了一個分層的社會體系一樣。kobject結構裏包含了parent成員,指向了另一個kobject結構,也就是這個分層結構的上一層結點。而kset是通過鏈表來實現的,這樣就可以明白,struct bus_type結構中的成員drivers和devices表示了一條總線擁有兩條鏈表,一條是設備鏈表,一條是驅動鏈表。我們知道了總線對應的數據結構,就可以找到這條總線關聯了多少設備,又有哪些驅動來支持這類設備。

那麽klist呢?其實它就包含了一個鏈表和一個自旋鎖,我們暫且把它看成鏈表也無妨,本來在2.6.11內核裏,struct device_driver結構的devices成員就是一個鏈表類型。這麽一說,咱們上面的直覺都是正確的,如果買股票,摸彩票時直覺都這麽管用,就不會有咱們這被壓扁的一代了。

現在的人都知道,三角關系很難處。那麽總線、設備和驅動之間是如何和諧共處那?先說說總線中的那兩條鏈表是怎麽形成的。內核要求每次出現一個設備就要向總線匯報,或者說註冊,每次出現一個驅動,也要向總線匯報,或者說註冊。比如系統初始化的時候,會掃描連接了哪些設備,並為每一個設備建立起一個struct device的變量,每一次有一個驅動程序,就要準備一個struct device_driver結構的變量。把這些變量統統加入相應的鏈表,device 插入devices 鏈表,driver插入drivers鏈表。這樣通過總線就能找到每一個設備,每一個驅動。然而,假如計算機裏只有設備卻沒有對應的驅動,那麽設備無法工作。反過來,倘若只有驅動卻沒有設備,驅動也起不了任何作用。在他們遇見彼此之前,雙方都如同路埂的野草,一個飄啊飄,一個搖啊搖,誰也不知道未來在哪裏,只能在生命的風裏飄搖。於是總線上的兩張表裏就慢慢的就掛上了那許多孤單的靈魂。devices開始多了,drivers開始多了,他們像是來自兩個世界,devices們彼此取暖,drivers們一起狂歡,但他們有一點是相同的,都只是在等待屬於自己的那個另一半。

現在,總線上的兩條鏈表已經有了,這個三角關系三個邊已經有了兩個,剩下的那個那?鏈表裏的設備和驅動又是如何聯系那?先有設備還是先有驅動?很久很久以前,在那激情燃燒的歲月裏,先有的是設備,每一個要用的設備在計算機啟動之前就已經插好了,插放在它應該在的位置上,然後計算機啟動,然後操作系統開始初始化,總線開始掃描設備,每找到一個設備,就為其申請一個struct device結構,並且掛入總線中的devices鏈表中來,然後每一個驅動程序開始初始化,開始註冊其struct device_driver結構,然後它去總線的devices鏈表中去尋找(遍歷),去尋找每一個還沒有綁定驅動的設備,即struct device中的struct device_driver指針仍為空的設備,然後它會去觀察這種設備的特征,看是否是他所支持的設備,如果是,那麽調用一個叫做device_bind_driver的函數,然後他們就結為了秦晉之好。換句話說,把struct device中的struct device_driver driver指向這個驅動,而struct device_driver driver把struct device加入他的那張struct klist klist_devices鏈表中來。就這樣,bus、device和driver,這三者之間或者說他們中的兩兩之間,就給聯系上了。知道其中之一,就能找到另外兩個。一榮俱榮,一損俱損。

但現在情況變了,在這紅蓮綻放的日子裏,在這櫻花傷逝的日子裏,出現了一種新的名詞,叫熱插拔。設備可以在計算機啟動以後在插入或者拔出計算機了。因此,很難再說是先有設備還是先有驅動了。因為都有可能。設備可以在任何時刻出現,而驅動也可以在任何時刻被加載,所以,出現的情況就是,每當一個struct device誕生,它就會去bus的drivers鏈表中尋找自己的另一半,反之,每當一個一個struct device_driver誕生,它就去bus的devices鏈表中尋找它的那些設備。如果找到了合適的,那麽OK,和之前那種情況一下,調用device_bind_driver綁定好。如果找不到,沒有關系,等待吧,等到曇花再開,等到風景看透,心中相信,這世界上總有一個人是你所等的,只是還沒有遇到而已。

Linux內核(7) - 設備模型(上)