/************************************************************************************html
*本文爲我的學習記錄,若有錯誤,歡迎指正。node
* https://www.cnblogs.com/andtt/articles/2178905.html數據結構
* https://blog.csdn.net/yueqian_scut/article/details/46694417框架
* http://www.javashuo.com/article/p-tvrsspnx-m.htmlide
************************************************************************************/函數
在物理層面上,總線表明着同類設備須要共同遵照的工做時序,不一樣的總線對於物理電平的要求是不同的,對於每一個比特的電平維持寬度也是不同,而總線上傳遞的命令也會有本身的格式約束。如I2C總線、USB總線、PCI總線等等。以I2C總線爲例,在同一組I2C總線上鏈接着不一樣的I2C設備。學習
在軟件層面上,總線的主要做用是管理設備與驅動。ui
Linux內核中使用struct bus_type描述一個總線,其中包含了該總線的全部信息。this
//所在文件/kernel/drivers/base/base.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); const struct dev_pm_ops *pm; struct bus_type_private *p; }; struct bus_type_private { struct kset subsys; struct kset *drivers_kset; struct kset *devices_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; };
設備表明真實的、具體的物理器件。在軟件層面上,用器件的獨特的參數屬性來表明該器件。如I2C總線上鏈接的I2C從設備都有一個標識本身的設備地址,由這個設備地址來肯定主設備發過來的命令是否該由它來響應。
struct device是一個基類,被設備相關的數據結構包含,其中包含了該設備的信息。
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 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 this device */ 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; 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 */ struct dev_archdata archdata; #ifdef CONFIG_OF struct device_node *of_node; #endif 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; const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev); }; struct device_private { struct klist klist_children; struct klist_node knode_parent; struct klist_node knode_driver; struct klist_node knode_bus; void *driver_data; struct device *device; };
驅動表明着操做設備的方式和流程。驅動主要包括兩部分,第一是經過對SoC的控制寄存器進行編程,按總線要求輸出時序和命令,成功地與外圍設備進行交互;第二是對第一步中獲得的數據進行處理,並嚮應用層提供特定格式的數據。
struct driver是一個基類,被驅動相關的數據結構包含,其中包含了該驅動的信息。
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 */ #if defined(CONFIG_OF) const struct of_device_id *of_match_table; #endif 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; }; struct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; };
上圖爲平臺總線設備驅動模型的總體框架。
在總線設備驅動模型中,需關心總線、設備和驅動這3個實體,總線將設備和驅動綁定。
當系統向內核註冊每個驅動程序時,都要經過調用驅動註冊函數(xxx_driver_register)將驅動程序註冊到總線,並將其放入所屬總線的drv鏈表中,註冊驅動的時候會調用所屬總線的match函數尋找該總線上與之匹配的每個設備,若是找到與之匹配的設備則會調用相應的probe函數將相應的設備和驅動進行綁定;一樣的當系統向內核註冊每個設備時,都要經過調用設備註冊函數(xxx_device_register)將設備註冊到總線,並將其放入所屬總線的dev鏈表中,註冊設備的時候一樣也會調用所屬總線的match函數尋找該總線上與之匹配的每個驅動程序,若是找到與之匹配的驅動程序時會調用相應的probe函數將相應的設備和驅動進行綁定;而這一匹配的過程是由總線自動完成的。
總線在匹配設備和驅動以後驅動要考慮一個這樣的問題,設備對應的軟件數據結構表明着靜態的信息,真實的物理設備此時是否正常還不必定,所以驅動須要探測這個設備是否正常。總線的管理代碼中會有這樣的邏輯:
if(match(device, driver) == OK) driver->probe();
總線匹配設備和驅動以後,驅動探測到設備正常,開始建立設備文件。調用class_create()、device_create()函數在/dev目錄下建立相應的設備文件,其內部原理是經過sysfs文件系統、uevent事件通知機制和後臺應用服務mdev程序配合可以成功地在/dev目錄建立對應的設備文件。詳見Linux設備文件的建立。