Linux那些事儿 之 戏说USB(10)模型,又见模型
顧名而思義就知道設備模型是關于設備的模型,對咱們寫驅動的和不寫驅動的人來說,設備的概念就是總線和與其相連的各種設備了。電腦城的IT工作者都會知道設備是通過總線連到計算機上的,而且還需要對應的驅動才能用,可是總線是如何發現設備的,設備又是如何和驅動對應起來的,它們經過怎樣的艱辛才找到命里注定的那個他,它們的關系如何,白頭偕老型的還是朝三暮四型的,這些問題就不是他們關心的了,是咱們需要關心的。經歷過高考千錘百煉的咱們還能夠驚喜的發現,這些疑問的中心思想中心詞匯就是總線、設備和驅動,沒錯,它們都是咱們這里要聊的linux設備模型的名角。
總線、設備、驅動,也就是bus、device、driver,既然是名角,在內核里都會有它們自己專屬的結構,在include/linux/device.h里定義。
struct bus_type {const char *name;const char *dev_name;struct device *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;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 (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};
struct device {struct device *parent;struct device_private *p;struct kobject kobj;const char *init_name; /* initial name of the device */const struct device_type *type;struct mutex mutex; /* mutex to synchronize calls to* its driver.*/struct bus_type *bus; /* type of bus device is on */struct device_driver *driver; /* which driver has allocated thisdevice */void *platform_data; /* Platform specific data, devicecore doesn't touch it */void *driver_data; /* Driver data, set and get withdev_set/get_drvdata */struct dev_pm_info power;struct dev_pm_domain *pm_domain;#ifdef CONFIG_PINCTRLstruct dev_pin_info *pins;
#endif#ifdef CONFIG_NUMAint numa_node; /* NUMA node this device is close to */
#endifu64 *dma_mask; /* dma mask (if dma'able device) */u64 coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations such descriptors. */unsigned long dma_pfn_offset;struct device_dma_parameters *dma_parms;struct list_head dma_pools; /* dma pools (if dma'ble) */struct dma_coherent_mem *dma_mem; /* internal for coherent memoverride */
#ifdef CONFIG_DMA_CMAstruct cma *cma_area; /* contiguous memory area for dmaallocations */
#endif/* arch specific additions */struct dev_archdata archdata;struct device_node *of_node; /* associated device tree node */struct acpi_dev_node acpi_node; /* associated ACPI device node */dev_t devt; /* dev_t, creates the sysfs "dev" */u32 id; /* device instance */spinlock_t devres_lock;struct list_head devres_head;struct klist_node knode_class;struct class *class;const struct attribute_group **groups; /* optional groups */void (*release)(struct device *dev);struct iommu_group *iommu_group;bool offline_disabled:1;bool offline:1;
};
struct device_driver {const char *name;struct bus_type *bus;struct module *owner;const char *mod_name; /* used for built-in modules */bool suppress_bind_attrs; /* disables bind/unbind via sysfs */const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;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);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};
沒有人會監督我節省紙張,所以就都貼出來了,有沒有發現它們的共性是什么?對,都很復雜很長,那是因為還沒有見到更復雜更長的。不妨把它們看成藝術品,linux整個內核都是藝術品,既然是藝術,當然不會讓你那么容易的就看懂了,不然怎么稱大師稱名家。這么想想咱們就會比較的寬慰了,阿Q是魯迅對咱們80后最大的貢獻。
我知道進入了21世紀,最缺的就是耐性,房價股價都讓咱們沒有耐性,內核的代碼也讓人沒有耐性。不過做為最沒有耐性的一代人,因為都被壓扁了,還是要平心凈氣的掃一下上面的結構,我們會發現struct device結構中有兩個成員struct bus_type和struct device_driver,struct device_driver結構中有成員struct bus_type。
憑一個男人的直覺,我們可以知道,struct device中的bus表示這個設備連到哪個總線上,driver表示這個設備的驅動是什么,struct device_driver中的bus表示這個驅動屬于哪個總線。
kobject和kset都是linux設備模型中最基本的元素,總線、設備、驅動是西瓜,kobjcet、klist是種瓜的人。kobject和kset不會在意自己自己的得失,它們存在的意義在于把總線、設備和驅動這樣的對象連接到設備模型上。
一般來說應該這么理解,整個linux的設備模型是一個OO的體系結構,總線、設備和驅動都是其中鮮活存在的對象,kobject是它們的基類,所實現的只是一些公共的接口,kset是同種類型kobject對象的集合,也可以說是對象的容器。只是因為C里不可能會有C++里類的class繼承、組合等的概念,只有通過kobject嵌入到對象結構里來實現。這樣,內核使用kobject將各個對象連接起來組成了一個分層的結構體系,就好像通過馬列主義將我們13億人也連接成了一個分層的社會體系一樣。kobject結構里包含了parent成員,指向了另一個kobject結構,也就是這個分層結構的上一層結點。而kset是通過鏈表來實現的。
那么klist那?其實它就包含了一個鏈表和一個自旋鎖,我們暫且把它看成鏈表也無妨,本來在2.6.11版本里,struct device_driver結構的devices成員就是一個鏈表類型。
還是先說說總線中的那兩條鏈表是怎么形成的吧。復旦人甲說這要求每次出現一個設備就要向總線匯報,或者說注冊,每次出現一個驅動,也要向總線匯報,或者說注冊。比如系統初始化的時候,會掃描連接了哪些設備,并為每一個設備建立起一個struct device的變量,每一次有一個驅動程序,就要準備一個struct device_driver結構的變量。把這些變量統統加入相應的鏈表,device 插入devices 鏈表,driver插入drivers鏈表。這樣通過總線就能找到每一個設備,每一個驅動。然而,假如計算機里只有設備卻沒有對應的驅動,那么設備無法工作。反過來,倘若只有驅動卻沒有設備,驅動也起不了任何作用。
現在,總線上的兩條鏈表已經有了,這個三角關系三個邊已經有了兩個,剩下的那個那?鏈表里的device和driver又是如何聯系那?先有device還是先有driver?偷懶一下,仍然摘引復旦人甲的話吧。很久很久以前,在那激情燃燒的歲月里,先有的是device,每一個要用的device在計算機啟動之前就已經插好了,插放在它應該在的位置上,然后計算機啟動,然后操作系統開始初始化,總線開始掃描設備,每找到一個設備,就為其申請一個struct device結構,并且掛入總線中的devices鏈表中來,然后每一個驅動程序開始初始化,開始注冊其struct device_driver結構,然后它去總線的devices鏈表中去尋找(遍歷),去尋找每一個還沒有綁定driver的設備,即struct device中的struct device_driver指針仍為空的設備,然后它會去觀察這種設備的特征,看是否是他所支持的設備,如果是,那么調用一個叫做device_bind_driver的函數,然后他們就結為了秦晉之好。換句話說,把struct device中的struct device_driver driver指向這個driver,而struct device_driver driver把struct device加入他的那張struct klist klist_devices鏈表中來。就這樣,bus、device和driver,這三者之間或者說他們中的兩兩之間,就給聯系上了。
但現在情況變了,在這紅蓮綻放的日子里,在這櫻花傷逝的日子里,出現了一種新的名詞,叫熱插拔。device可以在計算機啟動以后在插入或者拔出計算機了。因此,很難再說是先有device還是先有driver了。因為都有可能。device可以在任何時刻出現,而driver 也可以在任何時刻被加載,所以,出現的情況就是,每當一個struct device誕生,它就會去bus的drivers鏈表中尋找自己的另一半,反之,每當一個一個struct device_driver誕生,它就去bus的devices鏈表中尋找它的那些設備。如果找到了合適的,那么ok,和之前那種情況一下,調用device_bind_driver綁定好.如果找不到,沒有關系,等待吧,等到曇花再開,等到風景看透,心中相信,這世界上總有一個人是你所等的,只是還沒有遇到而已。總結
以上是生活随笔為你收集整理的Linux那些事儿 之 戏说USB(10)模型,又见模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux那些事儿 之 戏说USB(9)
- 下一篇: Linux那些事儿 之 戏说USB(11