linux设备模型中ktype的用法
时间:2016-12-09作者:华清远见
在上篇《利用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 { 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、
int class_device_register(struct class_device *class_dev) 3、
void class_device_initialize(struct class_device *class_dev) 4、
#define kobj_set_kset_s(obj,subsys) \ 5、
看看class_obj_subsys的定义
#define decl_subsys(_name,_type,_uevent_ops) \ 所以kset对应的ktype为ktype_class_device 6、
static struct kobj_type ktype_class_device = { 7、
static struct sysfs_ops class_dev_sysfs_ops = { 在操作上文中的“dev”或“uevent”时都是操作这个class_dev_sysfs_ops 8、
class_device_attr_show(struct kobject * kobj, struct attribute * attr,
class_device_attr_store(struct kobject * kobj, struct attribute * attr, 可以看出操作函数会根据to_class_dev_attr(attr);找出对应attr的class_dev_attr并调用其对应的show或store 9、 再跟踪一下上文中的dev及uvent属性的定义及其对应的操作函数
attr->attr.name = "dev";
static ssize_t show_dev(struct class_device *class_dev, char *buf)
class_dev->uevent_attr.attr.name = "uevent";
static ssize_t store_uevent(struct class_device *class_dev, 可以看出无论写入什么值都会触发KOBJ_ADD事件,内核调用kobject_uevent函数发送netlink message给用户空间用户层,用户空间可以用udev通过取到此事件,从而处理热插拔事件。 好了,写完了,希望对大家有点参考价值。
相关资讯
发表评论
|