天天看點

Linux裝置模型(中)之上層容器

基本概念 總線 

Linux裝置模型是由總線(bus_type),裝置(device),驅動(device_driver)這三個資料結構來描述的。

總線是處理器和一個或多個裝置之間的通道。

在裝置模型中, 所有的裝置都通過總線相連, 甚至是内部的虛拟“platform”總線(下一篇介紹),注意,這裡裝置模型中隻是為個更好友善管理,是以有些總線是pic,i2c,usb等,但都隻是一個分類的名字而已,但有些比如s3c2440上內建的控制器(lcd,watchdog,rtc等),platform所描述的資源有一個共同點,就是在cpu的總線上直接取址,是以Linux定義了一個給别的找不到很明顯屬于哪個總線的裝置所屬的平台總線(platform),來維持總線,驅動,裝置的關系。

總線可以互相插入。裝置模型展示了總線和它們所控制的裝置之間的實際連接配接。

 bus_type (總線)

 Linux 裝置模型中, 總線由 bus_type 結構表示

 每個bus_type對象都對應/sys/bus目錄下的一個子目錄,如PCI總線類型對應于/sys/bus/pci。

 在每個這樣的目錄下都存在兩個子目錄:devices和drivers(分别對應于bustype結構中的devices和drivers域)。

 devices子目錄描述連接配接在該總線上的所有裝置

 Drivers子目錄描述與該總線關聯的所有驅動程式。

 bus_type結構還包含幾個函數(match、hotplug等)處理相應的熱插拔、即插即拔和電源管理事件。

01.struct bus_type {  
02.    const char      *name;       //總線類型的名稱   
03.    struct bus_attribute    *bus_attrs;  //總線屬性   
04.    struct device_attribute *dev_attrs;  //裝置屬性   
05.    struct driver_attribute *drv_attrs;  //驅動屬性   
06.    int (*match)(struct device *dev, struct device_driver *drv);  
07.    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  
08.    int (*probe)(struct device *dev);  
09.    int (*remove)(struct device *dev);  
10.    void (*shutdown)(struct device *dev);  
11.    int (*suspend)(struct device *dev, pm_message_t state);  
12.    int (*suspend_late)(struct device *dev, pm_message_t state);  
13.    int (*resume_early)(struct device *dev);  
14.    int (*resume)(struct device *dev);  
15.    struct dev_pm_ops *pm;  
16.    struct bus_type_private *p;  
17.};  
           

int (*match)(struct device *device, struct device_driver *driver);

無論何時一個新裝置或者驅動被添加給這個總線.如果給定的裝置可被給

定的驅動處理,這個方法應當傳回一個非零值 . 這個函數必須在總線級别

處理, 因為那是合适的邏輯存在的地方; 核心核心不能知道如何比對每個

可能總線類型的裝置和驅動.

這個函數隻是簡單對比驅動和裝置的名字是不是相同而已,來比對驅動和裝置。 是以某個驅動和某個裝置一定要同名才能讓它們比對起來。

int (*uevent)(struct device *dev, char **envp, int num_envp,

char *buffer, int buffer_size)

在為使用者空間産生熱插拔事件之前,這個方法允許總線添加環境變量。

總線屬性由bus_attribute  結構描述,定義如下:

struct bus_attribute {
struct attribute
attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char *
buf, size_t count);
}
           

需要注意的是,總線也是裝置,也必須按裝置注冊

總線的注冊使用:

bus_register(struct bus_type * bus)

若成功,新的總線将被添加進系統,并可在sysfs 的 /sys/bus 下看到。

總線的删除使用:

void bus_unregister(struct bus_type *bus)

  device(裝置)

Linux 系統中的每個裝置由一個 device對象描述

g_list 将該device對象挂接到全局裝置連結清單中,所有的 device對象都包含在devices subsys中,并組織成層次結構。

 Node域将該對象挂接到其兄弟對象的連結清單中

 bus list則用于将連接配接到相同總線上的裝置組織成連結清單

 driver list則将同一驅動程式管理的所有裝置組織為連結清單。

Device對象内嵌一個kobject對象,用于引用計數管理并通過它實作裝置層次結構。

 Driver域指向管理該裝置的驅動程式對象,而 driver data則是提供給驅動程式的資料。

 Bus域描述裝置所連接配接的總線類型。

核心提供了相應的函數用于操作device對象。

device_register()函數将一個新的device對象插入裝置模型,并自

動在/sys/devices下建立一個對應的目錄。

device_unregister()完成相反的操作,登出裝置對象。 get_device()和put_device()分别增加與減少裝置對象的引用計數。

 通常device結構不單獨使用,而是包含在更大的結構中作為一個子結構使用,比如描述PCI裝置的struct pci_dev

driver(驅動)

系統中的每個驅動程式由一個device_driver對象描述

struct device_driver {
char *name; 裝置驅動程式的名稱
struct bus_type *bus; 該驅動所管理的裝置挂接的總線類型
struct kobject kobj; 内嵌kobject對象
struct list_head devices; 該驅動所管理的裝置連結清單頭
int (*probe)(struct device *dev); 指向裝置探測函數,用于探測裝置
是否可以被該驅動程式管理
int (*remove)(struct device *dev); 用于删除裝置的函數
};

           

device_driver對象依靠内嵌的kobject對象實作引用計數管理和層次結構組織。

 對大多數驅動程式核心結構, device_driver 結構通常被嵌入到一個更高層的、總線相關的結構中。

注冊與登出函數是:

 int driver_register(struct device_driver *drv);

 void driver_unregister(struct device_driver *drv);

繼續閱讀