Linux设备管理(四)(4)

有了这个宏,我们就可以直接通过这个接口创建我们自己的对象

static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);

我们可以追一下源码,可以发现,我们使用的自动创建设备文件device_create()就会调用device_create_file()并最终调用sysfs_create_file()

"drivers/base/core.c"
device_create()
  └── device_create_vargs()
        └── device_create_groups_vargs()
                └── device_add()
                        └── device_create_file()
                                  ├── "include/linux/sysfs.h"
                                 └── sysfs_create_file()

eg_0: #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct device_attribute *dev_attr = to_dev_attr(attr); struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { print_symbol("dev_attr_show: %s returned bad count\n", (unsigned long)dev_attr->show); } return ret; } 读写attribute

当一个子系统定义了一个新的属性,它必须执行一组针对的sysfs操作以便对实现对属性的读写,这些读写操作通过回调ktype.sysfs_ops.show()和store()

//include/linux/sysfs.h 184 struct sysfs_ops { 185 ssize_t (*show)(struct kobject *, struct attribute *, char *); 186 ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); 187 };

当进行读写的时候,sysfs会分配一个PAGE_SIZE大小的buf并把它作为参数传入这两个函数,同时,对于每一次对属性的读写操作,sysfs都会调用这两个函数,所以,调用read系统调用的时候,show()方法应该填满整个buf,注���一个属性应该是一个或一组相似的值,所以这种机制并不会浪费很多系统资源。这种机制允许用户读取一部分内容并且可以任意的移动文件位置指针,如果用户空间将文件指针置为0或以0为偏移量调用了pread()show()会被重新调用并且再填满一个buf。类似地,调用write()系统调用的时候,sysfs希望第一次传入的buf是被填满的,sysfs会在传入的数据最后自动加NUL,这可以让诸如sysfs_strqe()一类的函数用起来更安全。当对sysfs执行写操作时,用户空间应该首先读取整个文件的内容,按自己的需求改变其中的一部分并回写,属性读写操作应该使用同一个buf

tips:

通过read()/write()传递数据不同,这里的show()/store()里的buf已经是内核空间的了,不需要进行copy_to_user() etc

写操作会导致show方法重新执行而忽视当前文件位置指针的位置

buf是PAGE_SIZE大小

show()方法返回打印到buf的实际byte数,这个就是scnprintf()的返回值

在进行格式化打印到用户空间的时候,show必须用scnprintf()除非你能保证栈不会溢出

stor应该返回buf中使用的数据的byte数目

show或store应该设置合适的返回值确保安全

eg_1 static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name); } static ssize_t store_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { snprintf(dev->name, sizeof(dev->name), "%.*s", (int)min(count, sizeof(dev->name) - 1), buf); return count; } static DEVICE_ATTR(name, S_IRUGO, show_name, store_name); 内核已实现接口

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4660794135ab141263397c309971b569.html