暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一起撸linux内核28-初探kobject

囧囧妹 2022-05-16
104

点击上方蓝字【囧囧妹】一起学习,一起成长!

一、开篇

接上一节一起撸linux内核27-初探kobject上一节我们了解了kobject,创建一个kobject在用户层的体现就是/sys/目录下增加了创建文件。这一节来了解下attribute。

二、attribute

attribute就是上一节我们创建的kobject对象的属性,之前我们也说了kobject借鉴了oop思想,attribute在用户层面的体现就是kobject目录下的文件。

attribute通过结构体struct attribute来描述,在内核源码/include/linux/sysfs.h

    struct attribute {
    const char *name;//文件名字
    umode_t mode;//文件权限
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    bool ignore_lockdep:1;
    struct lock_class_key *key;
    struct lock_class_key skey;
    #endif
    };

    但是一般情况下不会直接使用struct attribute,我们会通过kobj_attribute来使用,其在内核源码/include/linux/kobject.h定义

      struct kobj_attribute {
      struct attribute attr;//属性
          //对属性进行读写时就会回调到下面两个函数
      ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
      ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
      };

      kobj_attribute包含了attribute结构体,同时下面还有两个函数指针,这两个函数指针就是当用户在用户空间对kobject下的属性文件进行读写操作时就会回调到内核态对应的属性下的两个函数指针指向的函数。

      初始化kobj_attribute有两种方式:

        • 过直接赋值


        static struct kobj_attribute value_attr = {
            .attr = {
                .name = "value",
                .mode = 0664,
            },
            .show = show_value,
            .store = store_value,
        };
          • 通过调用__ATTR宏定义

          #define __ATTR(_name, _mode, _show, _store) { \
          .attr = {.name = __stringify(_name), \
          .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
          .show = _show, \
          .store = _store, \
          }


          我们通过一个示例来展示一下属性:



            /**
            * @file kobject.c
            * @brief
            * @author zshare
            * @version v1.0
            * @date 2022-05-16
            * @history
            */


            #include <linux/module.h>//对应内核源码中include/linux/module.h
            #include <linux/moduleparam.h>
            #include <linux/kernel.h>
            #include <linux/init.h> 包含了module_init和module_exit的声明
            #include <linux/cdev.h> 包含字符设备操作函数
            #include <linux/fs.h> 包含文件接口操作函数
            #include <linux/uaccess.h>
            #include <asm/atomic.h>
            #include <linux/slab.h>


            #define _log_
            #ifdef _log_
            #define kernel_print(format, arg...) printk(format,## arg)
            #else
            #define kernel_print(format, arg...) do{}while(0)
            #endif
            #define VERSION "V1.0"
            typedef unsigned char u8;
            typedef unsigned short u16;
            typedef unsigned int u32;
            #define nil NULL
            #define CMD_GET_VERSION 0x01


            static struct kobject *kobj_test;
            unsigned int value;


            ssize_t show_value(struct kobject *kobj, struct kobj_attribute *attr, char *buf){
            return sprintf(buf, "%d\n", value);
            }


            ssize_t store_value(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count){
            unsigned char tbuf[4] = {0};
            if(count > 4){
            printk("size is too long.\n");
            return -1;
            }
            strncpy(tbuf, buf, count);


            value = simple_strtoul(tbuf, NULL, 0);
            return count;
            }




            static struct kobj_attribute value_attr = {
            .attr = {
            .name = "value",
            .mode = 0664,
            },
            .show = show_value,
            .store = store_value,
            };
            //static struct kobj_attribute value_attr =
            // __ATTR(value, 0664, show_value, store_value);
            static int __init kobject_test_init(void){
            int ret = 0;
            kobj_test = kobject_create_and_add("hello", kernel_kobj);
            if(!kobj_test){
            printk("kobject create failed!\n");
            return -ENOMEM;
            }

            ret = sysfs_create_file(kobj_test, &value_attr.attr);
            if(ret){
            kobject_put(kobj_test);
            printk("sysfs create file failed!\n");
            return -1;
            }
            return 0;
            }


            static void __exit kobject_test_exit(void){
            kobject_put(kobj_test);
            }


            module_init(kobject_test_init);
            module_exit(kobject_test_exit);


            MODULE_LICENSE("GPL");//软件代码接受的许可协议General Public License
            MODULE_AUTHOR("Share");//声明作者
            MODULE_DESCRIPTION("kobject test module");//模块简单的描述
            MODULE_VERSION(VERSION);//模块版本
            MODULE_ALIAS("route");//模块在用户空间的别名


            我们make编译一下,并查看一下/sys/kernel/下的文件:

            插入ko文件再来看/sys/kernel/hello

            我们通过cat来查看value的值为0,这个动作就对应内核态的show_value函数,我们通过echo来设置value文件的值,这个动作就对应内核态的store_value函数。我们深入一些,如果我们有个gpio驱动来通过kobject实现,就可以通过kobject和attribute在sysfs目录下建立交互文件,通过uevent等文件来在用户态操作内核态的gpio驱动。


            觉得不错,点击“分享”,“赞”,“在看”传播给更多热爱嵌入式的小伙伴吧!

            文章转载自囧囧妹,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论