微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 手机设计讨论 > MTK手机平台交流 > Linux设备模型分析之kobject--转

Linux设备模型分析之kobject--转

时间:10-02 整理:3721RD 点击:
Linux设备模型分析之kobject --转

一、kobject应用举例linux设备模型最基本的组成元素是kobject,我们先来看一个kobject的应用例子,该程序在Ubuntu 10.10, 2.6.32-38-generic-pae内核上调试通过。[cpp] view plaincopyprint?

    #include <linux/device.h>   
  • #include <linux/module.h>   
    #include <linux/kernel.h>   
  • #include <linux/init.h>   
    #include <linux/string.h>   
  • #include <linux/sysfs.h>   
    #include <linux/stat.h>   
  •   
    MODULE_AUTHOR("haoyu");  
  • MODULE_LICENSE("Dual BSD/GPL");  
      
  • struct my_kobject  
    {  
  •     int value;  
        struct kobject kobj;  
  • };  
          
  • struct my_kobject my_kobj;  
      
  • void kobject_release(struct kobject *kobject);  
    ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf);  
  • ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);  
      
  • struct attribute kobject_attr1 = {  
        .name = "name",  
  •     .mode = S_IRWXUGO,  
    };  
  •   
    struct attribute kobject_attr2 = {  
  •     .name = "value",  
        .mode = S_IRWXUGO,  
  • };  
      
  • static struct attribute *kobject_def_attrs[] = {  
        &kobject_attr1,  
  •     &kobject_attr2,  
        NULL,  
  • };  
      
  • struct sysfs_ops kobject_sysfs_ops =  
    {  
  •     .show = kobject_attr_show,  
        .store = kobject_attr_store,  
  • };  
      
  • struct kobj_type ktype =  
    {  
  •     .release = kobject_release,  
        .sysfs_ops = &kobject_sysfs_ops,  
  •     .default_attrs = kobject_def_attrs,  
    };  
  •   
    void kobject_release(struct kobject *kobject)  
  • {  
        printk("kobject release.\n");  
  • }  
      
  • ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf)  
    {  
  •     int count = 0;  
        struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);  
  •     printk("kobject attribute show.\n");  
        if(strcmp(attr->name, "name") == 0)  
  •         count = sprintf(buf, "%s\n", kobject->name);  
        else if(strcmp(attr->name, "value") == 0)  
  •         count = sprintf(buf, "%d\n", my_kobj->value);  
        else  
  •         printk("no this attribute.\n");  
          
  •     return count;  
    }  
  •   
    ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)  
  • {  
        int val;  
  •     struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);  
        printk("kobject attribute store.\n");  
  •     if(strcmp(attr->name, "name") == 0)  
            printk("Can not change name.\n");  
  •     else if(strcmp(attr->name, "value") == 0)  
        {  
  •         val = buf[0] - '0';  
            if(val == 0 || val == 1)  
  •             my_kobj->value = val;  
            else  
  •             printk("value is '0' or '1'\n");  
        }  
  •     else  
            printk("no this attribute.\n");  
  •          
        return count;  
  • }  
      
  • static int kobject_test_init(void)  
    {  
  •     printk("kboject test init.\n");  
        kobject_init_and_add(&my_kobj.kobj,&ktype,NULL,"kobject_test");  
  •     return 0;  
    }  
  •   
    static void kobject_test_exit(void)  
  • {  
        printk("kobject test exit.\n");  
  •     kobject_del(&my_kobj.kobj);  
    }  
  •   
    module_init(kobject_test_init);  
  • module_exit(kobject_test_exit);  

#include <linux/device.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/sysfs.h>#include <linux/stat.h>MODULE_AUTHOR("haoyu");MODULE_LICENSE("Dual BSD/GPL");struct my_kobject{    int value;    struct kobject kobj;};    struct my_kobject my_kobj;void kobject_release(struct kobject *kobject);ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf);ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);struct attribute kobject_attr1 = {    .name = "name",    .mode = S_IRWXUGO,};struct attribute kobject_attr2 = {    .name = "value",    .mode = S_IRWXUGO,};static struct attribute *kobject_def_attrs[] = {    &kobject_attr1,    &kobject_attr2,    NULL,};struct sysfs_ops kobject_sysfs_ops ={    .show = kobject_attr_show,    .store = kobject_attr_store,};struct kobj_type ktype ={    .release = kobject_release,    .sysfs_ops = &kobject_sysfs_ops,    .default_attrs = kobject_def_attrs,};void kobject_release(struct kobject *kobject){    printk("kobject release.\n");}ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf){    int count = 0;    struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);    printk("kobject attribute show.\n");    if(strcmp(attr->name, "name") == 0)        count = sprintf(buf, "%s\n", kobject->name);    else if(strcmp(attr->name, "value") == 0)        count = sprintf(buf, "%d\n", my_kobj->value);    else        printk("no this attribute.\n");        return count;}ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count){    int val;    struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);    printk("kobject attribute store.\n");    if(strcmp(attr->name, "name") == 0)        printk("Can not change name.\n");    else if(strcmp(attr->name, "value") == 0)    {        val = buf[0] - '0';        if(val == 0 || val == 1)            my_kobj->value = val;        else            printk("value is '0' or '1'\n");    }    else        printk("no this attribute.\n");            return count;}static int kobject_test_init(void){    printk("kboject test init.\n");    kobject_init_and_add(&my_kobj.kobj,&ktype,NULL,"kobject_test");    return 0;}static void kobject_test_exit(void){    printk("kobject test exit.\n");    kobject_del(&my_kobj.kobj);}module_init(kobject_test_init);module_exit(kobject_test_exit);
该模块执行过程如下图所示:
二、相关数据结构:kobject是Linux设备模型中最基本的数据结构,代表设备模式的一个基本对象。kobj_type是kobject的类型,包括kobject的属性以及属性的操作接口,不同的kobject可以具有相同的kobj_type。kset是几个kobject的集合,这些kobject可以具有相同的kobj_type,也可以具有不同的kobj_type。[cpp] view plaincopyprint?

    struct kobject {  
  •         const char             *name;  
            struct list_head       entry;  
  •         struct kobject         *parent;  
            struct kset            *kset;  
  •         struct kobj_type       *ktype;  
            struct sysfs_dirent    *sd;  
  •         struct kref            kref;  
            unsigned int state_initialized:1;  
  •         unsigned int state_in_sysfs:1;  
            unsigned int state_add_uevent_sent:1;  
  •         unsigned int state_remove_uevent_sent:1;  
            unsigned int uevent_suppress:1;  
  • };  
       
  • /**
    * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  • *
    * A kset defines a group of kobjects.  They can be individually
  • * different "types" but overall these kobjects all want to be grouped
    * together and operated on in the same manner.  ksets are used to
  • * define the attribute callbacks and other common events that happen to
    * a kobject.
  • *
    * @list: the list of all kobjects for this kset
  • * @list_lock: a lock for iterating over the kobjects
    * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
  • * @uevent_ops: the set of uevent operations for this kset.  These are
    * called whenever a kobject has something happen to it so that the kset
  • * can add new environment variables, or fiLTEr out the uevents if so
    * desired.
  • */  
    struct kset {  
  •         struct list_head list;  
            SPInlock_t list_lock;  
  •         struct kobject kobj;  
            const struct kset_uevent_ops *uevent_ops;  
  • };  
       
  • struct kset_uevent_ops {  
            int (* const filter)(struct kset *kset, struct kobject *kobj);  
  •         const char *(* const name)(struct kset *kset, struct kobject *kobj);  
            int (* const uevent)(struct kset *kset, struct kobject *kobj,  
  •                      struct kobj_uevent_env *env);  
    };  
  •    
    struct kobj_type {  
  •         void (*release)(struct kobject *kobj);  
            const struct sysfs_ops *sysfs_ops;  
  •         struct attribute **default_attrs;  
            const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);  
  •         const void *(*namespace)(struct kobject *kobj);  
    };  
  •    
    struct sysfs_ops {  
  •         ssize_t (*show)(struct kobject *, struct attribute *,char *);  
            ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);  
  • };  
       
  • struct attribute {  
            const char             *name;  
  •         mode_t                 mode;  
    #ifdef CONFIG_DEBUG_LOCK_ALLOC   
  •         struct lock_class_key  *key;  
            struct lock_class_key  skey;  
  • #endif   
    };  
  •    
    /*
  • * Callbacks so sysfs can determine namespaces
    *   @current_ns: return calling task's namespace
  • *   @netlink_ns: return namespace to which a sock belongs (right?)
    *   @initial_ns: return the initial namespace (i.e. init_net_ns)
  • */  
    struct kobj_ns_type_operations {  
  •         enum kobj_ns_type type;  
            const void *(*current_ns)(void);  
  •         const void *(*netlink_ns)(struct sock *sk);  
            const void *(*initial_ns)(void);  
  • };  
       
  • struct kref {  
            atoMIC_t refcount;  
  • };  

struct kobject {        const char             *name;        struct list_head       entry;        struct kobject         *parent;        struct kset            *kset;        struct kobj_type       *ktype;        struct sysfs_dirent    *sd;        struct kref            kref;        unsigned int state_initialized:1;        unsigned int state_in_sysfs:1;        unsigned int state_add_uevent_sent:1;        unsigned int state_remove_uevent_sent:1;        unsigned int uevent_suppress:1;}; /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * * A kset defines a group of kobjects.  They can be individually * different "types" but overall these kobjects all want to be grouped * together and operated on in the same manner.  ksets are used to * define the attribute callbacks and other common events that happen to * a kobject. * * @list: the list of all kobjects for this kset * @list_lock: a lock for iterating over the kobjects * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) * @uevent_ops: the set of uevent operations for this kset.  These are * called whenever a kobject has something happen to it so that the kset * can add new environment variables, or filter out the uevents if so * desired. */struct kset {        struct list_head list;        spinlock_t list_lock;        struct kobject kobj;        const struct kset_uevent_ops *uevent_ops;}; struct kset_uevent_ops {        int (* const filter)(struct kset *kset, struct kobject *kobj);        const char *(* const name)(struct kset *kset, struct kobject *kobj);        int (* const uevent)(struct kset *kset, struct kobject *kobj,                     struct kobj_uevent_env *env);}; struct kobj_type {        void (*release)(struct kobject *kobj);        const struct sysfs_ops *sysfs_ops;        struct attribute **default_attrs;        const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);        const void *(*namespace)(struct kobject *kobj);}; struct sysfs_ops {        ssize_t (*show)(struct kobject *, struct attribute *,char *);        ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);}; struct attribute {        const char             *name;        mode_t                 mode;#ifdef CONFIG_DEBUG_LOCK_ALLOC        struct lock_class_key  *key;        struct lock_class_key  skey;#endif}; /* * Callbacks so sysfs can determine namespaces *   @current_ns: return calling task's namespace *   @netlink_ns: return namespace to which a sock belongs (right?) *   @initial_ns: return the initial namespace (i.e. init_net_ns) */struct kobj_ns_type_operations {        enum kobj_ns_type type;        const void *(*current_ns)(void);        const void *(*netlink_ns)(struct sock *sk);        const void *(*initial_ns)(void);}; struct kref {        atomic_t refcount;};
三、kobject注册和注销过程分析kobject的注册是通过调用kobject_init_and_add函数,该函数定义如下:[cpp] view plaincopyprint?

    /**
  • * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
    * @kobj: pointer to the kobject to initialize
  • * @ktype: pointer to the ktype for this kobject.
    * @parent: pointer to the parent of this kobject.
  • * @fmt: the name of the kobject.
    *
  • * This function combines the call to kobject_init() and
    * kobject_add().  The same type of error handling after a call to
  • * kobject_add() and kobject lifetime rules are the same here.
    */  
  • 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_and_add - initialize a kobject structure and add it to the kobject hierarchy * @kobj: pointer to the kobject to initialize * @ktype: pointer to the ktype for this kobject. * @parent: pointer to the parent of this kobject. * @fmt: the name of the kobject. * * This function combines the call to kobject_init() and * kobject_add().  The same type of error handling after a call to * kobject_add() and kobject lifetime rules are the same here. */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对象进行基本的初始化。然后,调用kobject_add_varg函数将kobject注册到系统中。va_start和va_end是处理可变参数的固定语法。先来看kobject_init,该函数定义如下:[cpp] view plaincopyprint?

    /**
  • * kobject_init - initialize a kobject structure
    * @kobj: pointer to the kobject to initialize
  • * @ktype: pointer to the ktype for this kobject.
    *
  • * This function will properly initialize a kobject such that it can then
    * be passed to the kobject_add() call.
  • *
    * After this function is called, the kobject MUST be cleaned up by a call
  • * to kobject_put(), not by a call to kfree directly to ensure that all of
    * the memory is cleaned up properly.
  • */  
    void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  
  • {  
            char *err_str;  
  •    
            if (!kobj) {  
  •                err_str = "invalid kobject pointer!";  
                   goto error;  
  •         }  
            if (!ktype) {  
  •                err_str = "must have a ktype to be initialized properly!\n";  
                   goto error;  
  •         }  
            if (kobj->state_initialized) {  
  •                /* do not error out as sometimes we can recover */  
                   printk(KERN_ERR "kobject (%p): tried to init an initialized "  
  •                       "object, something is seriously wrong.\n", kobj);  
                    dump_stack();  
  •         }  
       
  •         kobject_init_internal(kobj);  
            kobj->ktype = ktype;  
  •         return;  
       
  • error:  
            printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);  
  •         dump_stack();  
  • }  

/** * kobject_init - initialize a kobject structure * @kobj: pointer to the kobject to initialize * @ktype: pointer to the ktype for this kobject. * * This function will properly initialize a kobject such that it can then * be passed to the kobject_add() call. * * After this function is called, the kobject MUST be cleaned up by a call * to kobject_put(), not by a call to kfree directly to ensure that all of * the memory is cleaned up properly. */void kobject_init(struct kobject *kobj, struct kobj_type *ktype){        char *err_str;         if (!kobj) {               err_str = "invalid kobject pointer!";               goto error;        }        if (!ktype) {               err_str = "must have a ktype to be initialized properly!\n";               goto error;        }        if (kobj->state_initialized) {               /* do not error out as sometimes we can recover */               printk(KERN_ERR "kobject (%p): tried to init an initialized "                      "object, something is seriously wrong.\n", kobj);                dump_stack();        }         kobject_init_internal(kobj);        kobj->ktype = ktype;        return; error:        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);        dump_stack();}
该函数首先确保kobj和ktype都存在,否则直接退出。如果该kobj进行过初始化,则打印警告信息。然后调用kobject_init_internal真正开始初始化kobj,最后把kobj->ktype设置为ktype。kobject_init_internal函数定义如下:[cpp] view plaincopyprint?

    static void kobject_init_internal(struct kobject *kobj)  
  • {  
            if (!kobj)  
  •                return;  
            kref_init(&kobj->kref);  
  •         INIT_LIST_HEAD(&kobj->entry);  
            kobj->state_in_sysfs = 0;  
  •         kobj->state_add_uevent_sent = 0;  
            kobj->state_remove_uevent_sent = 0;  
  •         kobj->state_initialized = 1;  
  • }  

static void kobject_init_internal(struct kobject *kobj){        if (!kobj)               return;        kref_init(&kobj->kref);        INIT_LIST_HEAD(&kobj->entry);        kobj->state_in_sysfs = 0;        kobj->state_add_uevent_sent = 0;        kobj->state_remove_uevent_sent = 0;        kobj->state_initialized = 1;}
首先初始化kobj->kref,实际上kobj->kref就是一个原子变量(atomic_t)。接着初始化链表项kobj->entry,并设置其他kobject成员。至此,kobject_init函数就分析完了,我们返回到kobject_init_and_add函数,下面该分析kobject_add_varg函数了:[cpp] view plaincopyprint?

    static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,  
  •                            const char *fmt, va_list vargs)  
    {  
  •         int retval;  
       
  •         retval = kobject_set_name_vargs(kobj, fmt, vargs);  
            if (retval) {  
  •                printk(KERN_ERR "kobject: can not set name properly!\n");  
                   return retval;  
  •         }  
            kobj->parent = parent;  
  •         return kobject_add_internal(kobj);  
  • }  

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,                           const char *fmt, va_list vargs){        int retval;         retval = kobject_set_name_vargs(kobj, fmt, vargs);        if (retval) {               printk(KERN_ERR "kobject: can not set name properly!\n");               return retval;        }        kobj->parent = parent;        return kobject_add_internal(kobj);}
首先调用kobject_set_name_vargs设置kob->name。然后初始化kobj->parent为parent参数指定的kobject。最后,调用kobject_add_internal将kobject注册到系统中,该函数定义如下:[cpp] view plaincopyprint?

    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;  
            }  
  •    
            parent = kobject_get(kobj->parent);  
  •    
            /* 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);  
                   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) : "<NULL>",  
  •                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");  
       
  •         error = create_dir(kobj);  
            if (error) {  
  •                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 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;        }         parent = kobject_get(kobj->parent);         /* 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);               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) : "<NULL>",                kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");         error = create_dir(kobj);        if (error) {               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;}
首先确保kobj->name已经被赋值,即kobject必须有名字。如果指定了kobj->kset,则调用kobj_kset_join将kobj加入到kobj->kset中。同时,如果kobj->parent仍为NULL,则将kobj->parent设置为kobj->kset->kobj。然后,调用create_dir(kobj)在/sys目录下建立kobject相关目录结构。kobj_kset_join函数定义如下:[cpp] view plaincopyprint?

    /* add the kobject to its kset's list */  
  • static void kobj_kset_join(struct kobject *kobj)  
    {  
  •         if (!kobj->kset)  
                   return;  
  •    
            kset_get(kobj->kset);  
  •         spin_lock(&kobj->kset->list_lock);  
            list_add_tail(&kobj->entry, &kobj->kset->list);  
  •         spin_unlock(&kobj->kset->list_lock);  
  • }  

/* add the kobject to its kset's list */static void kobj_kset_join(struct kobject *kobj){        if (!kobj->kset)               return;         kset_get(kobj->kset);        spin_lock(&kobj->kset->list_lock);        list_add_tail(&kobj->entry, &kobj->kset->list);        spin_unlock(&kobj->kset->list_lock);}
create_dir函数定义如下:[cpp] view plaincopyprint?

    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;  
  • }  

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_create_dir在/sys下建立目录,然后再调用populate_dir在新建目录下生成属性文件。sysfs_create_dir函数定义如下:[cpp] view plaincopyprint?

    /**
  • *      sysfs_create_dir - create a directory for an object.
    *      @kobj:         object we're creating directory for.  
  • */  
    int sysfs_create_dir(struct kobject * kobj)  
  • {  
            enum kobj_ns_type type;  
  •         struct sysfs_dirent *parent_sd, *sd;  
            const void *ns = NULL;  
  •         int error = 0;  
       
  •         BUG_ON(!kobj);  
       
  •         if (kobj->parent)  
                   parent_sd = kobj->parent->sd;  
  •         else  
                   parent_sd = &sysfs_root;  
  •    
            if (sysfs_ns_type(parent_sd))  
  •                ns = kobj->ktype->namespace(kobj);  
            type = sysfs_read_ns_type(kobj);  
  •    
            error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);  
  •         if (!error)  
                   kobj->sd = sd;  
  •         return error;  
  • }  

/** *      sysfs_create_dir - create a directory for an object. *      @kobj:         object we're creating directory for.  */int sysfs_create_dir(struct kobject * kobj){        enum kobj_ns_type type;        struct sysfs_dirent *parent_sd, *sd;        const void *ns = NULL;        int error = 0;         BUG_ON(!kobj);         if (kobj->parent)               parent_sd = kobj->parent->sd;        else               parent_sd = &sysfs_root;         if (sysfs_ns_type(parent_sd))               ns = kobj->ktype->namespace(kobj);        type = sysfs_read_ns_type(kobj);         error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);        if (!error)               kobj->sd = sd;        return error;}
这里主要是通过调用create_dir函数建立kobject对应的目录。这个函数我们就不继续向下跟踪了。下面来看populate_dir函数,其定义如下:[cpp] view plaincopyprint?

    /*
  • * populate_dir - populate directory with attributes.
    * @kobj: object we're working on.
  • *
    * Most subsystEMS have a set of default attributes that are associated
  • * with an object that registers with them.  This is a helper called during
    * object registration that loops through the default attributes of the
  • * subsystem and creates attributes files for them in sysfs.
    */  
  • 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) != NULL; i++) {  
                           error = sysfs_create_file(kobj, attr);  
  •                        if (error)  
                                   break;  
  •                }  
            }  
  •         return error;  
  • }  

/* * populate_dir - populate directory with attributes. * @kobj: object we're working on. * * Most subsystems have a set of default attributes that are associated * with an object that registers with them.  This is a helper called during * object registration that loops through the default attributes of the * subsystem and creates attributes files for them in sysfs. */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) != NULL; i++) {                       error = sysfs_create_file(kobj, attr);                       if (error)                               break;               }        }        return error;}
该函数循环遍历kobject的所有属性,并调用sysfs_create_file函数在/sys系统对应目录下建立属性文件。至此,kobject的注册过程我们就分析完了。kobject的注销过程是调用kobject_del函数,该函数定义如下:[cpp] view plaincopyprint?

    /**
  • * kobject_del - unlink kobject fROM hierarchy.
    * @kobj: object.
  • */  
    void kobject_del(struct kobject *kobj)  
  • {  
            if (!kobj)  
  •                return;  
       
  •         sysfs_remove_dir(kobj);  
            kobj->state_in_sysfs = 0;  
  •         kobj_kset_leave(kobj);  
            kobject_put(kobj->parent);  
  •         kobj->parent = NULL;  
  • }  

/** * kobject_del - unlink kobject from hierarchy. * @kobj: object. */void kobject_del(struct kobject *kobj){        if (!kobj)               return;         sysfs_remove_dir(kobj);        kobj->state_in_sysfs = 0;        kobj_kset_leave(kobj);        kobject_put(kobj->parent);        kobj->parent = NULL;}
这里需要注意的是,只要把目录删除,目录下的属性文件自动就删除了。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top