Linux內核--usb子係統的分析
drivers/usb/core/usb.c
subsys_init(usb_init);module_exit(usb_exit);
我們 看到一個subsys_initcall,它也是一個宏,我們可以把它理解為module_init,隻不過這部分代碼比較核心,開發者們把它看做一個子係統,而不僅僅是一個模塊。usbcore這個模塊它代表的不是某一個設備,而是所有usb設備賴以生存的模塊,Linux中,像這樣一個類別的設備驅動被鬼節為一個子係統。比如PCI子係統、SCSI子係統,基本上,drivers/目錄西麵的每一個目錄就算為一個子係統,因為他們代表了一類設備。
subsys_initcall(usb_init)的意思就是告訴我們usb_init是usb子係統真正的初始化函數,而usb_exit()將是整個usb子係統的結束時的清理函數。
我們需要從usb_init函數開始分析:
static int __init usb_init(void)
__init標記:它對於內核來說就是一種暗示,表明這個函數僅僅在初始化期間使用,在模塊被裝載之後,它占用的資源就會釋放掉,用作別用。__init的定義在include/linux/init.h中
#define __init__section(.init.text) __cold notrace
__attribute__、__section__等等都是GNUC的擴展,GNUC作為能夠編譯內核的唯一編譯器。通常編譯器將函數放在.text段,變量放在.data或.bss段,使用section屬性,可以讓編譯器將函數或變量放在指定的段中。__init的定義便表示將它修飾的代碼放在.init.text段中。連接器可以把相同段的代碼或數據安排在一起,比如__init修飾的所有代碼都被放在.init.text段中,初始化結束後就可以釋放這部分內存。
設備模型:
總線、設備、驅動:(bus、device、driver)定義在include/linux/device.h
struct bus_type {
const char *name;
struct bus_attribute *bus_attrs;
struct device_attribute *dev_attrs;
struct driver_attribute *drv_attrs;
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 (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
struct dev_pm_ops *pm;
struct bus_type_private *p;
};
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
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);
struct attribute_group **groups;
struct dev_pm_ops *pm;
struct driver_private *p;
};
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct device_type *type;
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
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 mem
override */
/* arch specific additions */
struct dev_archdata archdata;
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
struct device中的bus表示這個設備連到那個總線上,driver表示這個設備的驅動是什麼,struct device_driver中的bus表示這個驅動屬於那個總線,klist_devices表示這個驅動都支持哪些設備,因為這裏device是複數,又是list,更因為一個驅動可以支持多個設備,而一個設備隻能綁定一個驅動。當然struct bus_type中的drivers和devices分別表示了這個總線擁有哪些設備和哪些驅動。
kobjece和kset是Linux設備模型中最基本的元素,存在的意義是把總線、設備和驅動這樣的對象連接到設備模型上。
整個linux的設備模型是一個OO的體係結構,總線、設備和驅動都是其對象,kobject是它們的基類,所實現的知識一些公共的接口,kset是同種類型kobject對象的集合,也可以說是對象的容器。因為在c裏不可能有c++裏的class繼承、組合等概念,隻有通過kobject嵌入到對象結構裏來實現。這樣,內核使用kobject將各個對象連接起來組成一個分層的結構體係。kobject結構裏包含了parent成員,指向了另外一個kobject結構,也就是這個分層結構的上一層結點。而kset是通過鏈表來實現的,struct
bus_type結構中的成員drivers和devices表示了一條總線擁有兩條鏈表,一條是設備鏈表,一條是驅動鏈表。我們知道了總線對應的數據結構,就可以找到這條總線關聯了多少設備,又有哪些驅動來支持這類設備。
最後更新:2017-04-03 14:53:53