1. 程式人生 > >linux裝置驅動模型之Kobject、kobj_type、kset

linux裝置驅動模型之Kobject、kobj_type、kset

一、sysfs檔案系統簡介:

1、sysfs概述

sysfs檔案系統是核心物件(kobject)、屬性(kobj_type)、及它們相互關係的一種表現。
sysfs非常重要的特徵:使用者可以從sysfs中讀出核心資料,也可以將使用者資料寫入核心。

2、核心結構與sysfs對應關係:

kobject    -->目錄
kobj_type-->屬性檔案

3、特點

sysfs檔案系統只存在於記憶體中,動態的表示核心資料結構。裝置啟動時,裝置驅動模型會註冊kobject物件,並在sysfs檔案系統中產生sys下目錄檔案。

sys/bus:下列出了註冊到系統中的匯流排,如USB匯流排、platform匯流排。
sys/class:註冊到核心中的裝置類,如聲音類(sound)、輸入類(input)。

二、核心資料結構

在Linux的驅動表示中,主要有三個基本的結構,分別是kobject、kset、ktype.這三個結構是裝置模型中的下層架構。
模型中的每一個元素都對應一個kobject.
kset和ktype可以看成是kobject在層次結構與屬性結構方面的擴充。將三者之間的關係用圖的方示描述如下:
參考:http://blog.csdn.net/lizuobin2/article/details/51511336

如上圖所示,sysfs中每一個目錄都對應一個kobject.
這些kobject都有自己的parent。在沒有指定parent的情況下,都會指向它所屬的kset->object。
其次,kset也內嵌了kobject.這個kobject又可以指它上一級的parent。就這樣。構成了一個空間上面的層次關係。
其實,每個物件都有屬性。例如,電源管理,執插撥事性管理等等。
因為大部份的同類裝置都有相同的屬性,因此將這個屬性隔離開來,存放在ktype中。
這樣就可以靈活的管理了.記得在分析sysfs的時候。
對於sysfs中的普通檔案讀寫操作都是由kobject->ktype->sysfs_ops來完成的.
1、kobject結構體

kobject組成裝置驅動模型的基本結構。
sysfs中,裝置用樹形結構來表示,樹形結構每一個目錄對應一個kobject物件(目錄組織結構和名字等資訊)

struct kobject {
    const char        *name;                 kobject的名稱,顯示在sysfs檔案系統中,作為一個目錄的名字。
    struct list_head    entry;                   連結下一個kobject結構
    struct kobject        *parent;               指向父kobject結構體
    struct kset        *kset;                   指向所屬的kest集合
    struct kobj_type    *ktype;                 指向kobject的屬性檔案,每個物件都有屬性
                                    將屬性單獨組織成資料結構kobj_type存放在ktype中
                                    對於sysfs中的普通檔案讀寫操作都是由kobject->ktype->sysfs_ops來完成的
    struct sysfs_dirent    *sd;                      對應sysfs的檔案目錄
    struct kref        kref;                             kobject的引用計數
    unsigned int state_initialized:1;           初始化狀態
    unsigned int state_in_sysfs:1;            是否已經加入到sysfs中
    unsigned int state_add_uevent_sent:1;
    unsigned int state_remove_uevent_sent:1;
    unsigned int uevent_suppress:1;
};

在核心中,沒有用kobject直接定義的變數,kobject只是作為一個抽象的基類而存在。一般都是將kobject嵌入到另一個結構,這個結構就可以看做是kobject的一個子類。而kobject的子類會比較關心kobject的屬性和方法。

核心裡的裝置之間是以樹狀形式組織的,在這種組織架構裡比較靠上層的節點可以看作是下層節點的父節點,
反映到sysfs裡就是上級目錄和下級目錄之間的關係,在核心裡,正是kobject幫助我們實現這種父子關係。
kobject的成員:

name表示的是kobject在sysfs中的名字;

指標parent用來指向kobject的父物件;

Kref大家應該比較熟悉了,kobject通過它來實現引用計數;

Kset指標用來指向這個kobject所屬的kset;

對於ktype用來描述kobject的型別資訊。

kobject的作用:

(1)kobject始終代表sysfs檔案系統中的一個目錄,name成員指定了目錄名,不是檔案。

(2)parent成員指定了kobject在sysfs中的目錄,從而形成一個樹形結構。

(3)ktype是kobject的屬性,屬性用檔案來表示,放在kobject對應目錄下。

2、裝置屬性kobj_type

每個kobject物件都有一些屬性,這些屬性由kobj_type表示,kobject中有指向kobj_type的指標,屬性用檔案來表示。
struct kobj_type {
    void (*release)(struct kobject *kobj); 釋放kobject和其佔用資源的函式
    const struct sysfs_ops *sysfs_ops;      操作下一個屬性陣列的方法
    struct attribute **default_attrs;        屬性陣列
    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
    const void *(*namespace)(struct kobject *kobj);
};
kobj_type的default_attrs成員儲存了屬性陣列,每個kobject物件可以一個或多個屬性,屬性的定義如下:
struct attribute {
    const char        *name;      屬性的名稱,對應目錄下一個檔案的名字
    umode_t            mode;         屬性的讀寫許可權
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};
kobj_type的default_attrs陣列表明了kobject有哪些屬性,但是沒有說明如何操作這些屬性,這個任務由kobj_type的
sysfs_ops->sysfs_ops來完成
struct sysfs_ops {
    ssize_t    (*show)(struct kobject *, struct attribute *,char *);                      讀屬性操作函式
    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);         寫屬性操作函式
    const void *(*namespace)(struct kobject *, const struct attribute *);
};
kobject:要讀寫的kobject指標,attribute:要讀寫的屬性。
3.kset結構體

之前說kobject對應檔案系統/sys裡的一個目錄,kset中包含kobject結構體,所以kset也對應於/sys裡的一個目錄。
簡單來說,kset 與 kobj 都是目錄,既然是目錄,那麼在就是一個樹狀結構,每一個目錄都將有一個父節點,
在kset中使用kset.kobj->parent 指定 
在kboject中使用  kobj->parent 指定
顯然,整個樹狀目錄結構,都是通過kobj來構建的,只不過有些kobj嵌在Kset裡,分析目錄結構時把kset當成一個普通的kobj會好理解很多。
kobject通過kset組織成層次化的結構,kset是具有相同型別的kobject集合。像驅動程式放在/sys/drivers目錄下一樣,目錄drivers是一個kset物件,包含系統中驅動程式對應的目錄,驅動程式的目錄有kboject表示。核心將相似的kboject結構連線在kset集合中。
struct kset {
    struct list_head list;
    spinlock_t list_lock;
    struct kobject kobj;
    const struct kset_uevent_ops *uevent_ops;
};

 

struct kset_uevent_ops { int (* const filter)(struct kset *kset, struct kobject *kobj);

//當任何kobject需要上報uevent時,它所屬的kset可以通過filter藉口過濾,阻止不希望上報的uevent。

const char *(* const name)(struct kset *kset, struct kobject *kobj);

//該介面可以返回kset的名稱。如果一個kset沒有合法的名稱,則其下的所有kobject將不允許上報uevent

int (* const uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);

//當任何kobject需要上報uevent時,它所屬的kset可以通過該介面統一為這些event新增環境變數。

//因為很多時候上報uevent時的環境變數都是相同的,因此可以由kset統一處理,就不需要讓每個Kobject獨自添加了。 };

linux裝置驅動模型中,熱拔插使用到的函式為看kobject_uevent函式來實現,通過傳送一個uenvet訊息和呼叫call_usermodehelper來與使用者空間進行溝通。可以看出kobject_uevent能實現熱拔插,依賴於udev和sbin/hotplug。

所以kobject需要使用到熱拔插功能,就必須隸屬於一個kset。

注:系統中的熱拔插有兩種實現機制,一個是udev,另一個是、sbin/hotplug

    udev:實現基於核心中的網路機制,它通過建立標準的socket介面來監聽來自核心的網路廣播包,並對接收的包進行分析。

    sbin/hotplug: 它的幕後推手call_usermodehelper函式,能夠從核心空間啟動一個使用者空間的應用程式。

kobject與kset對應關係:

目前的簡單理解:

linux存在一個虛擬檔案系統/sysfs,核心啟動掛接檔案系統後會將sysfs檔案系統掛接到/sys下。核心啟動時會初始化並註冊一些匯流排、裝置,這些匯流排、裝置等會在sys下建立目錄,來儲存,如/sys/bus/platform 下儲存了平臺裝置資訊。如何組織管理裝置,並建立目錄呢,通過裝置驅動模型的幾個重要結構體:Kobject、kobj_type、kset來組織和管理目錄及檔案結構。
---------------------