知方号

知方号

linux中sysfs创建设备节点的方法和DEVICE

linux中sysfs创建设备节点的方法和DEVICE

使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,使用函数sysfs_create_group或sysfs_create_file便可以在设备目录下创建具有show和store方法的节点。能方便的进行调试。

一、使用DEVICE_ATTR构建device attribute

下面将顺着我们直接使用的DEVICE_ATTR来分析一下,这个宏究竟都做了哪些事情。

 DEVICE_ATTR的定义:

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

 

 而__ATTR宏的定义在include/linux/sysfs.h文件中,如下:

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

 那么struct device_attribute的定义又是怎么样的呢?该结构体的定义在include /linux/device.h,其定义如下:

/* 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);};

 而其中的struct attribute的定义在include/linux/device.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};

 总结一下:

DEVICE_ATTR(_name, _mode, _show, _store)等价于:struct device_attribute dev_attr_##_name = { .attr = {.name = __stringify(_name), .mode = VERIFY_OCTAL_PERMISSIONS(_mode)}, .show = _show, .store = _store,}

 其中:.show和.store的类型定义如下:

 show函数的详细描述:

ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); 入参buf是需要我们填充的string即我们cat属性节点时要显示的内容;函数的返回值是我们填充buf的长度,且长度应当小于一个页面的大小(4096字节);其他参数一般不用关心。

例如:

static ssize_t show_my_device(struct device *dev, struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数{ return sprintf(buf, "%s ", mybuf);}

store函数的详细描述:

ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); 入参buf是用户传入的字符串,即echo到属性节点的内容;入参count是buf中字符串的长度。函数的返回值通常返回count即可。其他参数一般不用关心。

例如:

static ssize_t store_my_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) //echo命令时,将会调用该函数{ sprintf(mybuf, "%s", buf); return count;}

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//其他可执行

  至此,我们已经定义好了.show和.store函数,那么就可以使用DEVICE_ATTR了。

static DEVICE_ATTR(my_device_test, S_IWUSR | S_IRUSR, show_my_device, store_my_device);

 

二、将device attribute添加到sysfs中

上面我们已经创建好了所需要的device attribute,下面就要将这些attribute添加到sysfs中了,此处可用的函数由sysfs_create_file和sysfs_create_group。

1、只有一个节点的创建sysfs_create_file

此处在驱动的probe或module_init函数调用sysfs_create_file即可,在module_exit或remove函数中调用sysfs_remove_file来移除节点。

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

以下是全部的代码:

#include #include #include #include #include static char sysfs_buff[100] = "my_sysfs_test_string";static ssize_t show_sys_device(struct device *dev, struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数{ return sprintf(buf, "%s ", sysfs_buff);}static ssize_t store_sys_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) //echo命令时,将会调用该函数{ sprintf(sysfs_buff, "%s", buf); return count;}static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);//定义一个名字为sys_device_file的设备属性文件struct file_operations mytest_ops = { .owner = THIS_MODULE,};static int major;static struct class *cls;struct device *mydev;static int mytest_init(void){ major = register_chrdev(0, "mytest", &mytest_ops); cls = class_create(THIS_MODULE, "mytest_class"); mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //创建mytest_device设备 if (sysfs_create_file(&(mydev->kobj), &dev_attr_sys_device_file.attr)) { //在mytest_device设备目录下创建一个sys_device_file属性文件 return -1; } return 0;}static void mytest_exit(void){ device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); unregister_chrdev(major, "mytest"); sysfs_remove_file(&(mydev->kobj), &dev_attr_sys_device_file.attr);}module_init(mytest_init);module_exit(mytest_exit);MODULE_LICENSE("GPL");

 

2、多个节点的创建sysfs_create_group

 定义attribute属性结构体数组到属性组中:

static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file0, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file1, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file2, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static struct attribute *sys_device_attributes[] = { &dev_attr_sys_device_file.attr, &dev_attr_sys_device_file0.attr, &dev_attr_sys_device_file1.attr, &dev_attr_sys_device_file2.attr, NULL////属性结构体数组最后一项必须以NULL结尾。};static const struct attribute_group sys_device_attr_group = { .attrs = sys_device_attributes,};

 下面就可以利用sysfs_create_group和sysfs_create_group来添加、移除属性节点组了。

定义如下:

 

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)

 

全部代码如下:

#include #include #include #include #include static char sysfs_buff[100] = "my_sysfs_test_string";static ssize_t show_sys_device(struct device *dev, struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数{ return sprintf(buf, "%s ", sysfs_buff);}static ssize_t store_sys_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) //echo命令时,将会调用该函数{ sprintf(sysfs_buff, "%s", buf); return count;}//定义多个sys_device_file的设备属性文件static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file0, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file1, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static DEVICE_ATTR(sys_device_file2, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);static struct attribute *sys_device_attributes[] = { &dev_attr_sys_device_file.attr, &dev_attr_sys_device_file0.attr, &dev_attr_sys_device_file1.attr, &dev_attr_sys_device_file2.attr, NULL////属性结构体数组最后一项必须以NULL结尾。};static const struct attribute_group sys_device_attr_group = { .attrs = sys_device_attributes,};struct file_operations mytest_ops = { .owner = THIS_MODULE,};static int major;static struct class *cls;struct device *mydev;static int mytest_init(void){ major = register_chrdev(0, "mytest", &mytest_ops); cls = class_create(THIS_MODULE, "mytest_class"); mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //创建mytest_device设备 if (sysfs_create_group(&(mydev->kobj), &sys_device_attr_group)) { //在mytest_device设备目录下创建多个sys_device_file属性文件 return -1; } return 0;}static void mytest_exit(void){ device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); unregister_chrdev(major, "mytest"); sysfs_remove_group(&(mydev->kobj), &sys_device_attr_group);}module_init(mytest_init);module_exit(mytest_exit);MODULE_LICENSE("GPL");

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。