《驱动学习 —— 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 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 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, led_sysfs_attr_group);//驱动退出时释放结点 kobject_put(led_kobj); }

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

 

 

 

 

 

  

posted @ 2022-03-19 17:40  一个不知道干嘛的小萌新  阅读(627)  评论(0编辑  收藏  举报