一,在前面几节里简单地分析了一下设备驱动模型的总线,设备和驱动三个基本元素,今天我们再往底层一点来看看sysfs的核心kobject,继续给出一个实例作先锋。(基于TCC8900 + linux-2.6.28)
二,kobject的实例驱动如下:
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> struct attribute test_attr = { .name = "kobject_attr", .mode = S_IRWXUGO, }; static struct attribute *ktype_attrs[] = { &test_attr, NULL };
ssize_t kobject_test_show(struct kobject *kobject, struct attribute *attr,char *buf) { return snprintf(buf, strlen(attr->name)+2, "%s\n", attr->name); } ssize_t kobject_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count) { printk("data from user: %s\n",buf); return count; } struct sysfs_ops kobject_test_sysops = { .show = kobject_test_show, .store = kobject_test_store, };
void kobject_test_release(struct kobject *kobject) { printk(KERN_INFO "kobject_test: release .\n"); }
struct kobj_type ktype_test = { .release = kobject_test_release, .sysfs_ops=&kobject_test_sysops, .default_attrs=ktype_attrs, }; struct kobject kobj;
static __init int kobject_test_init(void) { kobject_init_and_add(&kobj,&ktype_test,NULL,"kobject_test"); return 0; } static __exit void kobject_test_exit(void) { kobject_del(&kobj); } module_init(kobject_test_init); module_exit(kobject_test_exit); MODULE_AUTHOR("J.H.Luo"); MODULE_LICENSE("Dual BSD/GPL");
|
1,首先,我们要有一个感性认识:每一个kobject都对应着sysfs中的每一个目录项。在这个例子里,我们注册了一个kobject,由于没有指定其parent,它就会在/sys下面产生一个名为kobject_test的目录项。
2,下面来跟踪一下kobject的建立过程:
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...) { va_list args; int retval;
kobject_init(kobj, ktype);
va_start(args, fmt); retval = kobject_add_varg(kobj, parent, fmt, args); va_end(args);
return retval; }
|
kobject_init()——> kobject_init_internal()初始化kobject各个成员,并指定特定的ktype。Kobj_type结构表示kobject的类型。
struct kobj_type { void (*release)(struct kobject *kobj); /*属性操作集*/ struct sysfs_ops *sysfs_ops; /*指向这一类对象共有的一些属性,在sysfs中每一个属性呈现为一个文件*/ struct attribute **default_attrs; }; struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *,char *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); };
|
sysfs_ops用于实现对属性的读写。当从用户空间读取属性时(如执行cat命令),show()函数会被调用;当从用户空间写入数据时(如echo命令),store()函数会被调用。一般用于改变属性值。
Kobject初始化完成后,将调用kobject_add_varg()建立kobject:
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs) { int retval; /*设置kobject为给定的名字,没什么好说的*/ retval = kobject_set_name_vargs(kobj, fmt, vargs); if (retval) { printk(KERN_ERR "kobject: can not set name properly!\n"); return retval; } /*设置kobject的parent,在这个例子里,parent为NULL*/ kobj->parent = parent; /*添加这个kobject到sysfs*/ return kobject_add_internal(kobj); } static int kobject_add_internal(struct kobject *kobj) { int error = 0; struct kobject *parent;
if (!kobj) return -ENOENT;
if (!kobj->name || !kobj->name[0]) { WARN(1, "kobject: (%p): attempted to be registered with empty " "name!\n", kobj); return -EINVAL; } //取得kobject的父结点
parent = kobject_get(kobj->parent); /*如果kobject的父结点没有指定,就用kset->kobject做为它的父结点*/ /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { if (!parent) parent = kobject_get(&kobj->kset->kobj); /*将kobject加入kset的链表里*/ kobj_kset_join(kobj); kobj->parent = parent; }
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", kobject_name(kobj), kobj, __func__, parent ? kobject_name(parent) : "", kobj->kset ? kobject_name(&kobj->kset->kobj) : ""); /*在sysfs里创建一个目录项*/ error = create_dir(kobj); if (error) { /*如果创建失败,则要把kobject从kset链表中移出, 并减小parent的引用计数*/ kobj_kset_leave(kobj); kobject_put(parent); kobj->parent = NULL;
/* be noisy on error issues */ if (error == -EEXIST) printk(KERN_ERR "%s failed for %s with " "-EEXIST, don't try to register things with " "the same name in the same directory.\n", __func__, kobject_name(kobj)); else printk(KERN_ERR "%s failed for %s (%d)\n", __func__, kobject_name(kobj), error); dump_stack(); } else /*如果目录创建成功,就设置状态标志*/ kobj->state_in_sysfs = 1;
return error; }
static int create_dir(struct kobject *kobj) { int error = 0; if (kobject_name(kobj)) { error = sysfs_create_dir(kobj); if (!error) {
/*如果没有错误,创建属性*/ error = populate_dir(kobj); if (error) sysfs_remove_dir(kobj); } } return error; }
|
从这里可以看到,为sysfs创建目录,最终还是回到fs/sysfs/dir.c里的sysfs_create_dir()函数来实现的。在此不再深入去分析了。
目录创建完成之后,通过populate_dir()在该目录下创建属性:
static int populate_dir(struct kobject *kobj) { struct kobj_type *t = get_ktype(kobj); struct attribute *attr; int error = 0; int i; if (t && t->default_attrs) { for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { error = sysfs_create_file(kobj, attr); if (error) break; } } return error; }
|
这个函数遍历kobj_type的default_attrs的每一项,通过sysfs_create_file()创建属性文件,在我们这个例子里,default_attrs只有一个属性项,也就是说只有一个属性文件。
三,最后对此object实例测试一下:
/nand2 # insmod kobject_test.ko /nand2 # cd /sys/kobject_test/ /sys/kobject_test # ls -l -rwxrwxrwx 1 0 0 4096 Jan 1 00:00 kobject_attr /sys/kobject_test # cat kobject_attr kobject_attr /sys/kobject_test # echo anything > kobject_attr data from user: anything
|
------------------------------------------
本文乃原创!
转载请注明出处:http://sparklecliz.cublog.cn/
------------------------------------------
阅读(1326) | 评论(0) | 转发(0) |