Chinaunix首页 | 论坛 | 博客
  • 博客访问: 110285
  • 博文数量: 24
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 270
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-30 18:17
文章分类

全部博文(24)

文章存档

2010年(21)

2009年(3)

我的朋友

分类: LINUX

2010-03-16 10:15:49

一,在前面几节里简单地分析了一下设备驱动模型的总线,设备和驱动三个基本元素,今天我们再往底层一点来看看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各个成员,并指定特定的ktypeKobj_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_typedefault_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/

------------------------------------------


阅读(2446) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~