前面我们了解了设备驱动模型的三个基本结构,以及它们的相关操作函数,这里我们以实例来看一下它们的用法。
首先定义一个内嵌的kobject结构:
struct test_container { int member; struct kobject kobj; };
定义了一个kobject和一个member成员,主要就是嵌套了kobject结构。
struct test_container *con1, *con2, *con3; struct kset *test_kset; struct kobj_type test_type;
struct attribute name_attr = { .name = "name", .mode = 0666, }; struct attribute val_attr = { .name = "member", .mode = 0666, }; struct attribute *test_attrs[] = { &name_attr, &val_attr, NULL, };
ssize_t test_show(struct kobject *kobj, struct attribute *attr, char *buffer) { struct test_container *obj = container_of(kobj, struct test_container, kobj); ssize_t count = 0; if (strcmp(attr->name, "name") == 0) { count = sprintf(buffer, "%s\n", kobject_name(kobj)); } else if (strcmp(attr->name, "member") == 0) { count = sprintf(buffer, "%d\n", obj->member); } return count; } ssize_t test_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size) { struct test_container *obj = container_of(kobj, struct test_container, kobj); if (strcmp(attr->name, "member") == 0) { sscanf(buffer, "%d", &obj->member); } return size; } struct sysfs_ops test_sysfsops = { .show = test_show, .store = test_store, };
void obj_release(struct kobject *kobj) { struct test_container *obj = container_of(kobj, struct test_container, kobj); printk(KERN_INFO "obj_release,name is: %s\n", kobject_name(&obj->kobj)); kfree(obj); }当konject释放的时候调用。
static int __init testkset_init(void) { printk(KERN_WARNING "test_init\n"); test_kset = kset_create_and_add("test_kset", NULL, NULL); if (!test_kset) { return -ENOMEM; } con1 = kzalloc(sizeof(struct test_container), GFP_KERNEL); if (!con1) { kset_unregister(test_kset); return -ENOMEM; } con1->member = 1; con2 = kzalloc(sizeof(struct test_container), GFP_KERNEL); if (!con2) { kset_unregister(test_kset); kfree(con1); return -ENOMEM; } con2->member = 2; con3 = kzalloc(sizeof(struct test_container), GFP_KERNEL); if (!con3) { kset_unregister(test_kset); kfree(con1); kfree(con2); return -ENOMEM; } con3->member = 3; con1->kobj.kset = test_kset; con2->kobj.kset = test_kset; con3->kobj.kset = test_kset; test_type.release = obj_release; test_type.default_attrs = test_attrs; test_type.sysfs_ops = &test_sysfsops; kobject_init_and_add(&con1->kobj, &test_type, NULL, "con1"); kobject_init_and_add(&con2->kobj, &test_type, &con1->kobj, "con2"); kobject_init_and_add(&con3->kobj, &test_type, NULL, "con3"); return 0; }
static void __exit testkset_exit(void) { printk(KERN_INFO "test_kset_exit\n"); kobject_del(&con1->kobj); kobject_put(&con1->kobj); kobject_del(&con2->kobj); kobject_put(&con2->kobj); kobject_del(&con3->kobj); kobject_put(&con3->kobj); kset_unregister(test_kset); return; }kobject_del的作用是把kobject从设备模型的那棵树里摘掉,同时sysfs里相应的目录也会删除。这里需要指出的是,释放的顺序应该是先子对象,后父对象。因为kobject_init_and_add和kobject_add这两个函数会调用kobject_get来增加父对象的引用计数,所以kobject_del需要调用kobject_put来减少父对象的引用计数。在本例中,如果先通过kobject_put来释放obj1,那kobject_del(&obj2->kobj)就会出现内存错误。
这个示例构建了一个如下的架构:
相关的/sys目录结构及属性操作:
root@leaves-desktop:/home/leaves/Test/ldm/ldm2# insmod ldm2.ko root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys total 4 drwxr-xr-x 13 root root 0 May 15 14:39 ./ drwxr-xr-x 26 root root 4096 Mar 14 14:28 ../ drwxr-xr-x 2 root root 0 May 15 14:39 block/ drwxr-xr-x 22 root root 0 May 15 14:39 bus/ drwxr-xr-x 45 root root 0 May 15 14:39 class/ drwxr-xr-x 4 root root 0 May 15 14:39 dev/ drwxr-xr-x 14 root root 0 May 15 14:39 devices/ drwxr-xr-x 4 root root 0 May 15 14:39 firmware/ drwxr-xr-x 6 root root 0 May 15 14:39 fs/ drwxr-xr-x 7 root root 0 May 15 14:39 kernel/ drwxr-xr-x 105 root root 0 May 15 14:39 module/ drwxr-xr-x 2 root root 0 May 15 14:39 power/ drwxr-xr-x 4 root root 0 May 15 14:43 test_kset/ root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys/test_kset/ total 0 drwxr-xr-x 4 root root 0 May 15 14:43 ./ drwxr-xr-x 13 root root 0 May 15 14:39 ../ drwxr-xr-x 3 root root 0 May 15 14:43 con1/ drwxr-xr-x 2 root root 0 May 15 14:43 con3/ root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys/test_kset/con con1/ con3/ root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys/test_kset/con con1/ con3/ root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys/test_kset/con1/ total 0 drwxr-xr-x 3 root root 0 May 15 14:43 ./ drwxr-xr-x 4 root root 0 May 15 14:43 ../ drwxr-xr-x 2 root root 0 May 15 14:43 con2/ -rw-rw-rw- 1 root root 4096 May 15 14:43 member -rw-rw-rw- 1 root root 4096 May 15 14:43 name root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con1/member 1 root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con1/name con1 root@leaves-desktop:/home/leaves/Test/ldm/ldm2# ll /sys/test_kset/con1/con2/ total 0 drwxr-xr-x 2 root root 0 May 15 14:43 ./ drwxr-xr-x 3 root root 0 May 15 14:43 ../ -rw-rw-rw- 1 root root 4096 May 15 14:44 member -rw-rw-rw- 1 root root 4096 May 15 14:44 name root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con con1/ con3/ root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con1/con2/member 2 root@leaves-desktop:/home/leaves/Test/ldm/ldm2# echo 4 /sys/test_kset/con1/member 4 /sys/test_kset/con1/member root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con1/member 1 root@leaves-desktop:/home/leaves/Test/ldm/ldm2# echo 4 > /sys/test_kset/con1/member root@leaves-desktop:/home/leaves/Test/ldm/ldm2# cat /sys/test_kset/con1/member 4 root@leaves-desktop:/home/leaves/Test/ldm/ldm2# rmmod ldm2.ko root@leaves-desktop:/home/leaves/Test/ldm/ldm2#
上面的case中,我们介绍到如何使用default attribute。Default attribute使用很方便,但不够灵活。比如上面的那个例子,name和val这两个attribute使用同一个show/store函数来访问,如果attribute非常多,show/store函数里的分支就会很凌乱。
为了解决这个问题,我们可以参考内核提供的kobj_attribute。在内核里,kobj_attibute是这样定义的:
static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct kobj_attribute *kattr; ssize_t ret = -EIO; kattr = container_of(attr, struct kobj_attribute, attr); if (kattr->show) ret = kattr->show(kobj, kattr, buf); return ret; } static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct kobj_attribute *kattr; ssize_t ret = -EIO; kattr = container_of(attr, struct kobj_attribute, attr); if (kattr->store) ret = kattr->store(kobj, kattr, buf, count); return ret; } const struct sysfs_ops kobj_sysfs_ops = { .show = kobj_attr_show, .store = kobj_attr_store, }; static void dynamic_kobj_release(struct kobject *kobj) { pr_debug("kobject: (%p): %s\n", kobj, __func__); kfree(kobj); } static struct kobj_type dynamic_kobj_ktype = { .release = dynamic_kobj_release, .sysfs_ops = &kobj_sysfs_ops, };
struct my_attribute { struct attribute attr; ssize_t (*show)(struct my_kobj *obj, struct my_attribute *attr, char *buf); ssize_t (*store)(struct my_kobj *obj, struct my_attribute *attr, const char *buf, size_t count); };
static ssize_t my_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct my_attribute *my_attr; ssize_t ret = -EIO; my_attr = container_of(attr, struct my_attribute, attr); if (my_attr->show) ret = my_attr->show(container_of(kobj, struct my_kobj, kobj), my_attr, buf); return ret; } static ssize_t my_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct my_attribute *my_attr; ssize_t ret = -EIO; my_attr = container_of(attr, struct my_attribute, attr); if (my_attr->store) ret = my_attr->store(container_of(kobj, struct my_kobj, kobj), my_attr, buf, count); return ret; }
ssize_t name_show(struct my_kobj *obj, struct my_attribute *attr, char *buffer) { return sprintf(buffer, "%s\n", kobject_name(&obj->kobj)); } ssize_t val_show(struct my_kobj *obj, struct my_attribute *attr, char *buffer) { return sprintf(buffer, "%d\n", obj->val); } ssize_t val_store(struct my_kobj *obj, struct my_attribute *attr, const char *buffer, size_t size) { sscanf(buffer, "%d", &obj->val); return size; }
struct my_attribute name_attribute = __ATTR(name, 0444, name_show, NULL); struct my_attribute val_attribute = __ATTR(val, 0666, val_show, val_store); struct attribute *my_attrs[] = { &name_attribute.attr, &val_attribute.attr, NULL, };
#define __ATTR(_name,_mode,_show,_store) { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }在module_init里,我们调用sysfs_create_files来把attribute增加到sysfs中。
retval = sysfs_create_files(&obj->kobj, (const struct attribute **)my_attrs); if (retval) { // ... }在kobject对应的目录里,还可以创建子目录,Linux内核里是用attribute_group来实现。在本例中,我们可以这么做:
struct attribute_group my_group = { .name = "mygroup", .attrs = my_attrs, };然后在module_init里调用sysfs_create_group来添加。
retval = sysfs_create_group(&obj->kobj, &my_group); if (retval) { // ... }
本例创建的attribute_group中包含的attribute也是my_attrs,所以在子目录mygroup下的文件和mykobj目录下的文件完全一致。 最后我们得到的目录结构是这样的。
mykobj/ |-- mygroup | |-- name | `-- val |-- name `-- val
总结:
kobj、kset对应着sys目录下面的一个个文件夹,而ktype反映的是sys目录下面的文件及操作其show 和store的方法
http://download.csdn.net/detail/new_abc/4312872