Linux設備管理(四):總線、設備、驅動三者之間的聯繫

/************************************************************************************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

************************************************************************************/函數

1. 總線

在物理層面上,總線表明着同類設備須要共同遵照的工做時序,不一樣的總線對於物理電平的要求是不同的,對於每一個比特的電平維持寬度也是不同,而總線上傳遞的命令也會有本身的格式約束。如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;
};
struct bus_type

2. 設備

設備表明真實的、具體的物理器件。在軟件層面上,用器件的獨特的參數屬性來表明該器件。如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; };
struct device

3. 驅動

驅動表明着操做設備的方式和流程。驅動主要包括兩部分,第一是經過對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;
};
struct device_driver

4. 總線、設備、驅動三者之間的聯繫

上圖爲平臺總線設備驅動模型的總體框架。

上圖爲平臺總線設備驅動模型的總體框架。

在總線設備驅動模型中,需關心總線、設備和驅動這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設備文件的建立

相關文章
相關標籤/搜索