sysfs在设备文件创建中的作用
内核注册设备驱动时采用的是cdev_add接口,但是对于应用层来说,想要访问设备文件,必须先要创建一个对应设备号的设备文件才可以,比如:
sudo mknod dev/null c 1 3
上面是一种古老的方式,所有的设备驱动都要手动创建设备文件去访问,当前最流行的方法是利用上层的udev/mdev工具来帮助我们实现这个功能。mdev命令常用在嵌入式系统中,通过编译busybox之后即可拥有该工具。使用如下命令可以启动mdev自动检测设备驱动并创建设备文件:
cdev -s
那么既然介绍到这里,那么这个工具是利用什么原理来实现这个功能的呢?设备驱动代码需要生成相关的sysfs设备节点,只有添加了sysfs设备节点的驱动才能够被上层工具检测到并自动生成设备文件。举个驱动代码为例,首先会申请设备号并且在内核层创建设备:
rc = alloc_chrdev_region(&synx_dev->dev, 0, 1, SYNX_DEVICE_NAME);
if (rc < 0) {
pr_err("region allocation failed\n");
goto alloc_fail;
}
cdev_init(&synx_dev->cdev, &synx_fops);
synx_dev->cdev.owner = THIS_MODULE;
rc = cdev_add(&synx_dev->cdev, synx_dev->dev, 1);
if (rc < 0) {
pr_err("device registation failed\n");
goto reg_fail;
}
创建完设备后,并不会自动生成设备文件,需要生成sysfs设备文件:
synx_dev->class = class_create(THIS_MODULE, SYNX_DEVICE_NAME);
device_create(synx_dev->class, NULL, synx_dev->dev,
NULL, SYNX_DEVICE_NAME);
device_create
会在sysfs中创建对应的文件节点,从而可以被上层的udev和mdev检测到并创建对应的设备文件。
device_create --> device_create_vargs --> device_create_groups_vargs --> device_add --> kobject_add
-->kobject_add_varg --> kobject_add_internal --> create_dir --> sysfs_create_dir_ns --> kernfs_create_dir_ns
创建完成后可以在sysfs节点中查看对应的设备节点目录,并且在/dev目录下生成设备文件:
/sys/class/[CLASS_NAME]/[DEVICE_NAME]
/dev/[DEVICE_NAME]
创建device attribute文件的两种方法
sysfs除了用于生成设备节点,还可以用来传递驱动信息到用户空间。有两种方法来完成这个功能:
第一种方式是使用如下接口来创建,这个接口每次只能创建一个文件节点:
int device_create_file(struct device *dev,
const struct device_attribute *attr);
第二种方式是使用sysfs相关的接口来创建,可以用于批量创建attribute文件节点:
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);
举个实例:
static ssize_t show_debug(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "debug value:%d\n", debug_value);
}
static ssize_t store_debug(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
sscanf(buf, "%d", &debug_value);
return size;
}
static DEVICE_ATTR(debug, 0660, show_debug, store_debug);
static struct attribute *ramchar_attributes[] = {
&dev_attr_debug.attr,
NULL
};
static const struct attribute_group ramchar_attr_group = {
.attrs = ramchar_attributes,
};
static int __init ramdev_init(void)
{
......
rc = sysfs_create_group(&ramdev->device->kobj, &ramchar_attr_group);
if (rc < 0) {
ramdev_err("Failed to create attribute sysfs\n");
goto cdev_fail;
}
......
}