金牌講師
在上篇《利用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裝置模型,...