Chinaunix首页 | 论坛 | 博客
  • 博客访问: 152275
  • 博文数量: 101
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 9
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-17 08:11
文章分类
文章存档

2017年(91)

2016年(10)

我的朋友

分类: 嵌入式

2017-03-21 09:37:42

测试代码:

点击(此处)折叠或打开

  1. #include<linux/device.h>
  2. #include<linux/module.h>
  3. #include<linux/kernel.h>
  4. #include<linux/stat.h>
  5. #include<linux/init.h>
  6. #include<linux/string.h>
  7. #include<linux/sysfs.h>
  8. #include<linux/kobject.h>

  9. MODULE_LICENSE("Dual BSD/GPL");
  10. MODULE_AUTHOR("SM");

  11. #define    BUFFER_SIZE    20
  12. #define    NAME_MAX    20
  13. #define    PHONE_MAX    20
  14. struct    my_kobject
  15. {
  16.     char    name[NAME_MAX];
  17.     char    phone[PHONE_MAX];
  18.     int        age;
  19.     struct    kobject kobj;
  20. };

  21. struct     my_kobject    test;

  22. struct    attribute    attr1     =
  23. {
  24.     .name        = "name",
  25.     .mode        = S_IRWXUGO,
  26. };

  27. struct    attribute    attr2    =
  28. {
  29.     .name        = "phone",
  30.     .mode        = S_IRWXUGO,
  31. };

  32. struct    attribute    attr3    =
  33. {
  34.     .name        = "age",
  35.     .mode        = S_IRWXUGO,
  36. };

  37. static    struct    attribute * attribute_test[] =
  38. {
  39.     &attr1,
  40.     &attr2,
  41.     &attr3,
  42.     NULL,
  43. };


  44. ssize_t        test_show(struct kobject *obj,struct attribute *attr,char *buf)
  45. {
  46.     struct    my_kobject    *my_kobj    = container_of(obj,struct my_kobject,kobj);
  47.     int        count    = 0;

  48.     printk("test_show \n");

  49.     if(strcmp(attr->name, "name") == 0)
  50.     {
  51.         count = sprintf(buf, "name : %s\n", my_kobj->name);
  52.     }
  53.     else if(strcmp(attr->name, "phone") == 0)
  54.     {
  55.         count = sprintf(buf, "phone : %s\n", my_kobj->phone);
  56.     }
  57.     else if(strcmp(attr->name, "age") == 0)
  58.     {
  59.         count = sprintf(buf, "age : %d\n", my_kobj->age);
  60.     }
  61.     else
  62.     {
  63.         count = sprintf(buf, "show error\n");
  64.     }

  65.     return count;
  66. }

  67. ssize_t        test_store(struct kobject *kobj,struct attribute *attr,const char *buf,
  68.                         size_t    count)
  69. {
  70.     struct    my_kobject    *my_kobj    = container_of(kobj,struct my_kobject,kobj);
  71.     printk("test_store \n");

  72.     if(strcmp(attr->name, "name") == 0)
  73.     {
  74.         strcpy(my_kobj->name,buf);
  75.     }
  76.     else if(strcmp(attr->name, "phone") == 0)
  77.     {
  78.         strcpy(my_kobj->phone,buf);
  79.     }
  80.     else if(strcmp(attr->name, "age") == 0)
  81.     {
  82.         my_kobj->age    = simple_strtol(buf,NULL,10);
  83.     }
  84.     else
  85.     {
  86.         printk(KERN_NOTICE"store error\n");
  87.     }

  88.     return count;
  89. }

  90. struct     sysfs_ops    test_ops =
  91. {
  92.     .show        = test_show,
  93.     .store        = test_store,
  94. };



  95. void    test_release(struct kobject *obj)
  96. {
  97.     printk("release test \n");
  98. }


  99. #if 1
  100. struct     kobj_type        ktype =
  101. {
  102.     .release        = test_release,
  103.     .sysfs_ops        = &test_ops,
  104.     .default_attrs    = attribute_test,
  105. };
  106. #endif

  107. int        __init    sysfs_init(void)
  108. {
  109.     if(kobject_init_and_add(&test.kobj,&ktype,NULL,"test"))
  110.         printk("test fail\n");

  111.     printk("register success\n");

  112.     return 0;
  113. }



  114. void    __exit    sysfs_exit(void)
  115. {
  116.     kobject_del(&test.kobj);
  117.     printk("unregister success\n");
  118. }

  119. module_init(sysfs_init);
  120. module_exit(sysfs_exit);

/sys/test
├── age
├── name
├── phone

mode的值

点击(此处)折叠或打开   

  1. #define S_IRWXU 00700
  2. #define S_IRUSR 00400
  3. #define S_IWUSR 00200
  4. #define S_IXUSR 00100

  5. #define S_IRWXG 00070
  6. #define S_IRGRP 00040
  7. #define S_IWGRP 00020
  8. #define S_IXGRP 00010

  9. #define S_IRWXO 00007
  10. #define S_IROTH 00004
  11. #define S_IWOTH 00002
  12. #define S_IXOTH 00001

  13. #endif

  14. #ifdef __KERNEL__
  15. #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
  16. #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
  17. #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
  18. #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
  19. #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)

1,设备模型 kobject 的操作流程以及重点难点

      1)初始化,添加
kobject_init_and_add():           

点击(此处)折叠或打开

  1. /**
  2.  * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
  3.  * @kobj: pointer to the kobject to initialize
  4.  * @ktype: pointer to the ktype for this kobject.
  5.  * @parent: pointer to the parent of this kobject.
  6.  * @fmt: the name of the kobject.
  7.  *
  8.  * This function combines the call to kobject_init() and
  9.  * kobject_add(). The same type of error handling after a call to
  10.  * kobject_add() and kobject lifetime rules are the same here.
  11.  */
  12. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
  13.              struct kobject *parent, const char *fmt, ...)
  14. {
  15.     va_list args;
  16.     int retval;

  17.     kobject_init(kobj, ktype);

  18.     va_start(args, fmt);
  19.     retval = kobject_add_varg(kobj, parent, fmt, args);
  20.     va_end(args);

  21.     return retval;
  22. }
  23. EXPORT_SYMBOL_GPL(kobject_init_and_add);
 当前函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test") 
          kobj        : test.kobj
          ktype       : ktype
          parent      : NULL
          fmt         : "test"

    
              @a1@ kobject_init : 初始化一个内核对象的各个参数

点击(此处)折叠或打开   

  1. /**
  2.  * kobject_init - initialize a kobject structure
  3.  * @kobj: pointer to the kobject to initialize
  4.  * @ktype: pointer to the ktype for this kobject.
  5.  *
  6.  * This function will properly initialize a kobject such that it can then
  7.  * be passed to the kobject_add() call.
  8.  *
  9.  * After this function is called, the kobject MUST be cleaned up by a call
  10.  * to kobject_put(), not by a call to kfree directly to ensure that all of
  11.  * the memory is cleaned up properly.
  12.  */
  13. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
  14. {
  15.     char *err_str;

  16.     if (!kobj) {
  17.         err_str = "invalid kobject pointer!";
  18.         goto error;
  19.     }
  20.     if (!ktype) {
  21.         err_str = "must have a ktype to be initialized properly!\n";
  22.         goto error;
  23.     }
  24.     if (kobj->state_initialized) {
  25.         /* do not error out as sometimes we can recover */
  26.         printk(KERN_ERR "kobject (%p): tried to init an initialized "
  27.          "object, something is seriously wrong.\n", kobj);
  28.         dump_stack();
  29.     }

  30.     kobject_init_internal(kobj);
  31.     kobj->ktype = ktype;
  32.     return;

  33. error:
  34.     printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
  35.     dump_stack();
  36. }
  37. EXPORT_SYMBOL(kobject_init);
 kobject_init(kobj, ktype); 
          kobj        : test.kobj
          ktype       : ktype
 
                    @b1@ 首先要确定对象的存在,以及对象类型的存在,否则无法释放对象,
                        无法对这个对象的各个属性进行读写

                    @b2@ 初始化该对象

点击(此处)折叠或打开  

  1. static void kobject_init_internal(struct kobject *kobj)
  2. {
  3.     if (!kobj)
  4.         return;
  5.     kref_init(&kobj->kref);
  6.     INIT_LIST_HEAD(&kobj->entry);
  7.     kobj->state_in_sysfs = 0;
  8.     kobj->state_add_uevent_sent = 0;
  9.     kobj->state_remove_uevent_sent = 0;
  10.     kobj->state_initialized = 1;
  11. }
   kobject_init_internal(kobj);
          kobj        : test.kobj
  首先初始化 kobj->kref,实际上kobj->kref就是一个原子变量(atomic_t),表示对象引用计数;
  然后初始化 kobj->entry,即对象的链表(清空链表)(用于连接到所在的 kset 中去的单元 );
  最后设置对象的其他成员。

                    @b DONE@                        
               @a2@ va_start和va_end是处理可变参数的固定语法

               @a3@ kobject_add_varg :通过环境变量把该对象添加到合适的位置上去

点击(此处)折叠或打开        

  1. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
  2.              const char *fmt, va_list vargs)
  3. {
  4.     int retval;

  5.     retval = kobject_set_name_vargs(kobj, fmt, vargs);
  6.     if (retval) {
  7.         printk(KERN_ERR "kobject: can not set name properly!\n");
  8.         return retval;
  9.     }
  10.     kobj->parent = parent;
  11.     return kobject_add_internal(kobj);
  12. }
kobject_add_varg(kobj, parent, fmt, args);
          kobj        : test.kobj
          parent      : NULL
          fmt         : "test"

 
                    @b1@ 设置该对象的名字

点击(此处)折叠或打开       

  1. /**
  2.  * kobject_set_name_vargs - Set the name of an kobject
  3.  * @kobj: struct kobject to set the name of
  4.  * @fmt: format string used to build the name
  5.  * @vargs: vargs to format the string.
  6.  */
  7. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
  8.                  va_list vargs)
  9. {
  10.     const char *old_name = kobj->name;
  11.     char *s;

  12.     if (kobj->name && !fmt)
  13.         return 0;

  14.     kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
  15.     if (!kobj->name)
  16.         return -ENOMEM;

  17.     /* ewww... some of these buggers have '/' in the name ... */
  18.     while ((s = strchr(kobj->name, '/')))
  19.         s[0] = '!';

  20.     kfree(old_name);
  21.     return 0;
  22. }
kobject_set_name_vargs(kobj, fmt, vargs);
          kobj        : test.kobj
          fmt         : "test"


                           @c1@ 如果对象名已被赋值,且 fmt 为 NULL,则退出。
!!!因此,如果对象名没有被赋值,且 fmt 为 NULL,则会产生段错误!!!
即kobject_init_and_add(&test.kobj,&ktype,NULL,NULL);
                       
                           @c2@ 通过 fmt 参数给 对象名 赋值

点击(此处)折叠或打开

  1. /* Simplified asprintf. */
  2. char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
  3. {
  4.     unsigned int len;
  5.     char *p;
  6.     va_list aq;

  7.     va_copy(aq, ap);
  8.     len = vsnprintf(NULL, 0, fmt, aq);
  9.     va_end(aq);

  10.     p = kmalloc(len+1, gfp);
  11.     if (!p)
  12.         return NULL;

  13.     vsnprintf(p, len+1, fmt, ap);

  14.     return p;
  15. }
  16. EXPORT_SYMBOL(kvasprintf);
                                 @d1@ 首先测量这个字符串的长度;如 fun("test%d%s",3,"hello"),
                                   则这个字符串的长度为:strlen("test3hello") = 10 个字节;
                                 
                                 @d2@ 创建内存空间;
                    
                                 @d3@ 把字符串保存到刚创建的内存空间中  
  
                                 @d DONE@
                           @c3@ 释放 旧的对象名 所占的内存空间  
    
                           @c DONE@

                    @b2@ 把对象加载到合适的位置

点击(此处)折叠或打开

  1. static int kobject_add_internal(struct kobject *kobj)
  2. {
  3.     int error = 0;
  4.     struct kobject *parent;

  5.     if (!kobj)
  6.         return -ENOENT;

  7.     if (!kobj->name || !kobj->name[0]) {
  8.         WARN(1, "kobject: (%p): attempted to be registered with empty "
  9.              "name!\n", kobj);
  10.         return -EINVAL;
  11.     }

  12.     parent = kobject_get(kobj->parent);

  13.     /* join kset if set, use it as parent if we do not already have one */
  14.     if (kobj->kset) {
  15.         if (!parent)
  16.             parent = kobject_get(&kobj->kset->kobj);
  17.         kobj_kset_join(kobj);
  18.         kobj->parent = parent;
  19.     }

  20.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
  21.          kobject_name(kobj), kobj, __func__,
  22.          parent ? kobject_name(parent) : "",
  23.          kobj->kset ? kobject_name(&kobj->kset->kobj) : "");

  24.     error = create_dir(kobj);
  25.     if (error) {
  26.         kobj_kset_leave(kobj);
  27.         kobject_put(parent);
  28.         kobj->parent = NULL;

  29.         /* be noisy on error issues */
  30.         if (error == -EEXIST)
  31.             printk(KERN_ERR "%s failed for %s with "
  32.              "-EEXIST, don't try to register things with "
  33.              "the same name in the same directory.\n",
  34.              __func__, kobject_name(kobj));
  35.         else
  36.             printk(KERN_ERR "%s failed for %s (%d)\n",
  37.              __func__, kobject_name(kobj), error);
  38.         dump_stack();
  39.     } else
  40.         kobj->state_in_sysfs = 1;

  41.     return error;
  42. }
                        @c1@ 首先要确定这个对象是存在的(即其是一个分配了内存的变量,
                             不是一个指针变量),在本例子中如下:

点击(此处)折叠或打开

  1. struct my_kobject
  2. {
  3.     char name[NAME_MAX];
  4.     char phone[PHONE_MAX];
  5.     int age;
  6.     struct kobject kobj;
  7. };
  8. struct my_kobject test;
    函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test") 
          kobj        : test.kobj
          ktype       : ktype
          parent      : NULL
          fmt         : "test"

                           定义了一个名为 test 的变量,系统会为这个变量分配内存空间,
                            而这个变量中的成员 kobj 也就被分配了内存空间了。
  
                        @c2@ “!kobj->name”这个对象保存名字的空间是需要被创建了的
                              “!kobj->name[0]”这个对象名需要已经被赋值了的,不可为空

                        @c3@ 当前对象的父对象的引用加 1;
                             在本例子中 parent      : NULL

                        @c4@ 如果对象设置了所归属的集合,
                                a> 则这个集合的引用加 1;
                                b> 再把这个对象添加到这个集合的链表尾部

                        @c5@ 为这个对象创建目录

点击(此处)折叠或打开

  1. static int create_dir(struct kobject *kobj)
  2. {
  3.     int error = 0;
  4.     if (kobject_name(kobj)) {
  5.         error = sysfs_create_dir(kobj);
  6.         if (!error) {
  7.             error = populate_dir(kobj);
  8.             if (error)
  9.                 sysfs_remove_dir(kobj);
  10.         }
  11.     }
  12.     return error;
  13. }
                             @d1@ 获得对象的名字

点击(此处)折叠或打开   

  1. static inline const char *kobject_name(const struct kobject *kobj)
  2. {
  3.     return kobj->name;
  4. }

                             @d2@ 在 sysfs 文件系统中创建目录

点击(此处)折叠或打开

  1. /**
  2.  *    sysfs_create_dir - create a directory for an object.
  3.  *    @kobj:        object we're creating directory for.
  4.  */
  5. int sysfs_create_dir(struct kobject * kobj)
  6. {
  7.     enum kobj_ns_type type;
  8.     struct sysfs_dirent *parent_sd, *sd;
  9.     const void *ns = NULL;
  10.     int error = 0;

  11.     BUG_ON(!kobj);

  12.     if (kobj->parent)
  13.         parent_sd = kobj->parent->sd;
  14.     else
  15.         parent_sd = &sysfs_root;

  16.     if (sysfs_ns_type(parent_sd))
  17.         ns = kobj->ktype->namespace(kobj);
  18.     type = sysfs_read_ns_type(kobj);

  19.     error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
  20.     if (!error)
  21.         kobj->sd = sd;
  22.     return error;
  23. }
      函数 kobject_init_and_add(&test.kobj,&ktype,NULL,"test") 
          kobj        : test.kobj
          ktype       : ktype
          parent      : NULL
          fmt         : "test"

                               @e1@ 确定对象已被分配内存空间

                                @e2@ 获得对象的父对象的目录入口地址。
                                     在本例子中 parent      : NULL
                             因此
对象的父对象的目录入口地址为文件系统的根目录

点击(此处)折叠或打开

  1. struct sysfs_dirent sysfs_root = {
  2.     .s_name        = "",
  3.     .s_count    = ATOMIC_INIT(1),
  4.     .s_flags    = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
  5.     .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
  6.     .s_ino        = 1,
  7. };
                               
                                @e3@ 获得对象的父对象的目录入口地址的命名空间
                                       从而读取对象的命名空间,有3中命名空间

点击(此处)折叠或打开

  1. /*
  2.  * Namespace types which are used to tag kobjects and sysfs entries.
  3.  * Network namespace will likely be the first.
  4.  */
  5. enum kobj_ns_type {
  6.     KOBJ_NS_TYPE_NONE = 0,
  7.     KOBJ_NS_TYPE_NET,
  8.     KOBJ_NS_TYPES
  9. };
                                @e4@创建目录

点击(此处)折叠或打开

  1. static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
  2.     enum kobj_ns_type type, const void *ns, const char *name,
  3.     struct sysfs_dirent **p_sd)
  4. {
  5.     umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
  6.     struct sysfs_addrm_cxt acxt;
  7.     struct sysfs_dirent *sd;
  8.     int rc;

  9.     /* allocate */
  10.     sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
  11.     if (!sd)
  12.         return -ENOMEM;

  13.     sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
  14.     sd->s_ns = ns;
  15.     sd->s_dir.kobj = kobj;

  16.     /* link in */
  17.     sysfs_addrm_start(&acxt, parent_sd);
  18.     rc = sysfs_add_one(&acxt, sd);
  19.     sysfs_addrm_finish(&acxt);

  20.     if (rc == 0)
  21.         *p_sd = sd;
  22.     else
  23.         sysfs_put(sd);

  24.     return rc;
  25. }


问题:目录是怎么被创建的?

                                    @f1@ sysfs_new_dirent(name, mode,SYSFS_DIR);
                                        
从cache中获取一个slab对象

                                    @f2@

                                    @f3@

                                    @f DONE@
                                @e DONE@
                             @d3@ 创建目录成功,添加对象的属性到对象的目录中


问题:属性文件是怎么添加到目录中的?

                             @d DONE@
                        @c DONE@
                    @b DONE@
               @a DONE@

        
      2)卸载





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