• 《驱动学习 —— sysfs文件系统的编写》


    1.sysfs文件系统

      sysfs文件系统可以把内核空间的数据、属性、链接等输出到用户空间。反过来,用户也可以通过sysfs文件系统,往对应的内核空间传递数据。

      例如:echo 1 > /sys/class/gpio/gpio64/value,就是改变gpio64的值。

         cat > /sys/class/gpio/gpio64/value,就是读取gpio64的值。

      那么怎么在驱动中增加这个接口呢?

    2.新增/sys接口

    2.1 attribute属性

    struct attribute {
        char         *name;     //sys下接口的名字
        umode_t    mode;     //使用权限
    };

      mode为文件的权限,定义在kernel/include/uapi/linux/stat.h

    #define S_IRWXU 00700 //用户可读写和执行
    #define S_IRUSR 00400//用户可读
    #define S_IWUSR 00200//用户可写
    #define S_IXUSR 00100//用户可执行
     
    #define S_IRWXG 00070//用户组可读写和执行
    #define S_IRGRP 00040//用户组可读
    #define S_IWGRP 00020//用户组可写
    #define S_IXGRP 00010//用户组可执行
     
    #define S_IRWXO 00007//其他可读写和执行
    #define S_IROTH 00004//其他可读
    #define S_IWOTH 00002//其他可写
    #define S_IXOTH 00001//其他可执行

    2.2 device_attribute

      这个就是面对对象封装了一层

     /* interface for exporting device attributes */
     struct device_attribute {
         struct attribute    attr;
         ssize_t (*show)(struct device *dev, struct device_attribute *attr,
                 char *buf);
         ssize_t (*store)(struct device *dev, struct device_attribute *attr,
                  const char *buf, size_t count);
     };

      再用宏简化了device_attribute结构对象的定义和初始化

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

      其中_show和_store,分别代表在用户空间执行cat和echo所调用的函数,可以理解为read和write。

    2.3 创建文件

    int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
    void sysfs_remove_file(struct kobject *kobj, struct attribute *attr);

    2.4 kobject_create_and_add()函数

    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)

      功能:动态注册kobject并生成sysfs

    3. 实例编程

    3.1 使用sysfs_create_files函数

    
    
    #include <linux/sysfs.h>
    #include <linux/kobject.h>

    static
    ssize_t led_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t len) { printk("led_store()\n"); return len;//必须返回传入的长度 } //下面的show和store只是简单举例 static ssize_t led_show(struct device *dev, struct device_attribute*attr, char *buf) { printk("led_show()\n"); returnpr_info("store\n"); } //用DEVICE_ATTR宏创建属性led_sysfs文件,如果show()或是store()没有功能,就以NULL代替 static DEVICE_ATTR(led_sysfs, S_IWUSR, led_show,led_store); //最后一项必须以NUll结尾 static const struct attribute *atk_imx6ul_led_sysfs_attrs[] = { &dev_attr_led_sysfs.attr, NULL, }; //驱动中的初始化函数 static int __init xxxxx_mod_init(void) { led_kobj = kobject_create_and_add("led_test", NULL); sysfs_create_files(led_kobj,atk_imx6ul_led_sysfs_attrs); } //驱动中的退出函数 static void __exit xxxxx_mod_exit(void) { sysfs_remove_file(led_kobj, atk_imx6ul_led_sysfs_attrs);//驱动退出时释放结点 kobject_put(led_kobj);
    }

      编译insmod后就可以看到/sys/led_test/led_sysfs。

      cat sys/led_test/led_sysfs就相当于调用led_show()函数。

      echo 1 > /sys/led_test/led_sysfs就相当于调用led_store()函数。

    注意:

      其中结构体变量dev_attr_led_sysfs是不是没看到在哪里有定义。

    static DEVICE_ATTR(led_sysfs, S_IWUSR, led_show,led_store);

      当调用该宏定义的时候已经定义了

    #define DEVICE_ATTR(_name, _mode, _show, _store) \
       struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

    3.2 使用sysfs_create_group函数

      通常情况下,我们更多的将上述的struct attribute进行进一步的封装,并使用sysfs_create_group()来创建一个名为attribute_group.name的、包含struct attribute中的属性目录,这种方式更加的灵活,因为如果我们不指定目录的名字,那么效果个sysfs_create_file()是一样的。

    #include <linux/sysfs.h>
    #include <linux/kobject.h>

    static
    struct kobject *led_kobj = NULL; static ssize_t led_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t len) { printk("led_store()\n"); return len;//必须返回传入的长度 } //下面的show和store只是简单举例 static ssize_t led_show(struct device *dev, struct device_attribute*attr, char *buf) { printk("led_show()\n"); returnpr_info("store\n"); } //用DEVICE_ATTR宏创建属性led_sysfs文件,如果show()或是store()没有功能,就以NULL代替 static DEVICE_ATTR(led_sysfs, S_IWUSR, led_show,led_store); //最后一项必须以NUll结尾 static const struct attribute *atk_imx6ul_led_sysfs_attrs[] = { &dev_attr_led_sysfs.attr, NULL, }; static struct attribute_group led_sysfs_attr_group = { .name = "my_sysfs", .attrs = atk_imx6ul_led_sysfs_attrs }; //驱动中的初始化函数 static int __init xxxxx_mod_init(void) { led_kobj = kobject_create_and_add("led_test", NULL); sysfs_create_group(led_kobj,atk_imx6ul_led_sysfs_attrs); } //驱动中的退出函数 static void __exit xxxxx_mod_exit(void) { sysfs_remove_group(led_kobj, atk_imx6ul_led_sysfs_attrs);//驱动退出时释放结点 kobject_put(led_kobj); }

      这样会生成/sys/led_test/my_sysfs/led_sysfs

      

  • 相关阅读:
    Netty ChannelHandler组件作用
    Netty Channel组件作用
    Netty NioEventLoop自定义任务处理
    NIO与BIO
    JDK ByteBuffer与Netty ByteBuf
    linux-源码软件管理-yum配置
    typora使用快捷键
    远程连接mysql库问题
    MVC 后台处理 json格式的日期
    使用 SqlClient 创建数据库连接并获取数据
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/16027252.html
Copyright © 2020-2023  润新知