linux中sysfs创建设备节点的⽅法和DEVICE_ATTR
使⽤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\n", 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 <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
理学是什么专业#include <linux/delay.h>
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\n", 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 <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>
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\n", 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");