linux裝置模型中ktype的用法

2021-08-23 15:13:59 字數 4520 閱讀 8743

在上篇《利用udev、sys動態建立裝置結點》的記錄中,裝置驅動中主要依靠下面兩個功能完成的:

1、在/sys/class下建立farsight_class類

my_class =class_create(this_module, "farsight_class");

2、在farsight_class中建立新的class裝置

class_device_create(my_class,null, devno, null,"farsight_dev");

然後會在/sys中出現如圖的檔案結構:

其中」dev」和uevent都是「屬性」,可以讀取dev獲取裝置的主次裝置號;也可以對uevent操作;讓核心發出「add」事件用於熱插拔。如:

注:這裡寫入任何值都會導致「add」事件的產生,udevmonitor檢測時現象如下:

uevent[1220019773.507374] add????? /class/farsight_class/farsight_dev (farsight_class)

那麼上述功能實現的原理是什麼呢?現在就要過度到本文的主題ktype的使用了。先認識下這個結構

kype的結構定義為:

struct kobj_type ;

其中 attribute定義為:

struct attribute ; /*default_attrs 列表中的最後乙個元素必須用 0 填充*/

sysfs 系統中的屬性讀寫是由 kobj_type->sysfs_ops 成員中的函式完成的:

struct sysfs_ops ;

當使用者空間讀取乙個屬性時(如:#cat dev),核心會使用指向 kobject 的指標(kobj)和正確的屬性結構(*attr)來呼叫show 方法,該方法將給定屬性值編碼進緩衝(buffer)(注意不要越界( page_size 位元組)), 並返回實際資料長度。

也可對所有 kobject (通常指在乙個kset關聯的範圍內)關聯的屬性使用同乙個 show 方法,用傳遞到函式的 attr 指標來判斷所請求的屬性。有的 show 方法包含對屬性名字的檢查。有的show 方法會將屬性結構嵌入另乙個結構(本文舉的例子就是用的這種方法), 這個結構包含需要返回屬性值的資訊,這時可用container_of 獲得上層結構的指標以返回屬性值的資訊。

當使用者空間寫入乙個屬性時(如echo 「hello」 > event)核心會使用指向 kobject 的指標(kobj)和正確的屬性結構(*attr)來呼叫store 方法。

store 方法將存在緩衝(buffer)的資料( size為資料的長度,不能超過 page_size )解碼並儲存新值到屬性(*attr), 返回實際解碼的位元組數。store 方法只在擁有屬性的寫許可權時才能被呼叫。此時注意:接收來自使用者空間的資料一定要驗證其合法性。如果到資料不匹配, 返回乙個負的錯誤值。

每乙個 kobject 需要有乙個關聯的 kobj_type 結構,指向這個結構的指標能在 2 個不同的地方找到:

(1)kobject 結構自身包含乙個成員(ktype)指向kobj_type ;

struct kobject

(2)如果這個 kobject 是乙個 kset 的成員, kset 會提供kobj_type 指標。

struct kset

訪問屬性的時候到底是用的哪個kobj_type呢?

下面這個函式用以查詢指定kobject的kobj_type 指標:

static inline struct kobj_type * get_ktype(struct kobject * k)

上面可以看出,kset中的ktype這個型別優先於 kobject自身中的 ktype。因此在典型的應用中, 在 struct kobject 中的 ktype 成員被設為 null, 而 kset 中的ktype是實際被使用的。

下面通過跟蹤class_device_create(my_class,null, devno, null,"farsight_dev");來確定ktype的使用。

1、struct class_device *class_device_create(……)

2、 intclass_device_register(struct class_device *class_dev)

3、 voidclass_device_initialize(struct class_device *class_dev)

4、 #definekobj_set_kset_s(obj,subsys) \

(obj)->kobj.kset = &(subsys).kset

從中可以看出名為「farsight_dev」的kobject對應的kset是class_obj_subsys.kset

5、 看看class_obj_subsys的定義

static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);

#define decl_subsys(_name,_type,_uevent_ops) \

struct subsystem _name##_subsys = , \

.ktype = _type, \

.uevent_ops =_uevent_ops, \

} \}

所以kset對應的ktype為ktype_class_device

6、 static struct kobj_typektype_class_device= ;

7、 static struct sysfs_opsclass_dev_sysfs_ops= ;

在操作上文中的「dev」或「uevent」時都是操作這個class_dev_sysfs_ops8、

class_device_attr_show(struct kobject * kobj, struct attribute * attr,

char * buf)

class_device_attr_store(struct kobject * kobj, struct attribute * attr,

const char * buf, size_t count)

可以看出操作函式會根據to_class_dev_attr(attr);找出對應attr的class_dev_attr並呼叫其對應的show或store

9、 再跟蹤一下上文中的dev及uvent屬性的定義及其對應的操作函式

attr->attr.name = "dev";

attr->attr.mode = s_irugo;

attr->attr.owner = parent_class->owner;

attr->show = show_dev;

error = class_device_create_file(class_dev, attr);

static ssize_t show_dev(struct class_device *class_dev, char *buf)

class_dev->uevent_attr.attr.name = "uevent";

class_dev->uevent_attr.attr.mode = s_iwusr;

class_dev->uevent_attr.attr.owner = parent_class->owner;

class_dev->uevent_attr.store = store_uevent;

error = class_device_create_file(class_dev, &class_dev->uevent_attr);

static ssize_tstore_uevent(struct class_device *class_dev,

const char *buf, size_t count)

可以看出無論寫入什麼值都會觸發kobj_add事件,核心呼叫kobject_uevent函式傳送netlink message給使用者空間使用者層,使用者空間可以用udev通過取到此事件,從而處理熱插拔事件。

linux裝置模型中ktype的用法

在上篇 利用udev sys動態建立裝置結點 的記錄中,裝置驅動中主要依靠下面兩個功能完成的 1 在 sys class下建立farsight class類 my class class create this module,farsight class 2 在farsight class中建立新的...

linux裝置模型中ktype的用法

金牌講師 在上篇 利用udev sys動態建立裝置結點 的記錄中,裝置驅動中主要依靠下面兩個功能完成的 1 在 sys class下建立farsight class類 my class class create this module,farsight class 2 在farsight class...

Linux裝置模型

linux裝置驅動模型 我們在寫最簡單的裝置驅動程式的時候,我們將所有的硬體資訊都儲存在了驅動 中,這樣有乙個非常明顯的不足 會導致驅動程式的通用性極差,一旦硬體平台或硬體連線有鎖改變,就一定要修改驅動 為了解決這個問題,linux在2.6版本之後,新增了 匯流排 裝置 驅動 的linux裝置模型,...