sysfs是什么?说白了其实是一个桥梁,用来连接linux内核空间以及用户空间,可以让用户级进程直接通过sysfs节点去操作内核空间,我们可以利用这个特性去创建节点以此来调试底层驱动或者可以通过此节点来进行工厂测试,最终在产品量产后达到对具体硬件外设的管控。
下面是如何创建具体节点的过程:
一、首先需要先认识一些函数:
以下两个函数都是用于创建具体的节点:
1、此函数在此处定义:drivers/base/core.c
关于函数具体在哪里,可以在这里找很方便,可以找到所有版本的linux内核源码:Linux source code (v6.5.2) - Bootlin 后面就不贴函数的位置了。
int device_create_file(struct device *dev,
const struct device_attribute *attr)
{
int error = 0;
if (dev) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
}
return error;
}
参数1:struct device *dev
传递的是设备的描述结构体,就是平台驱动创建所需的,这里就不过多介绍
参数2:const struct device_attribute *attr
函数原型如下:
struct device_attribute {
struct attribute attr; // 内置的attribute 结构体
ssize_t (*show)(struct device *dev, struct device_attribute *attr, //属性文件的show方法(也就是读)
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr, //属性文件的store方法(也就是写)
const char *buf, size_t count);
};
需要如下方式进行赋值:
static struct device_attribute dev_attr_demo = {
.attr = {
.name = "demo",
.mode = (S_IRUGO | S_IWUSR)
},
.show = demo_show,
.store = demo_store,
};
此函数用于初始化此结构体struct device_attribute:
DEVICE_ATTR(_name, _mode, _show, _store)
_name:名称,也就是将在节点下生成的文件名称。
_mode:上述文件的访问权限,与普通文件相同,UGO的格式。只读0444,只写0222,或者读写都行的0666。
_show:显示函数,cat该文件时,此函数被调用。
_store:写函数,echo内容到该文件时,此函数被调用
2、此函数与device_create_file的区别就是可以一次创建多个节点
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)
{
return internal_create_group(kobj, 0, grp);
}
方法与device_create_file一样,我们这里直接以此函数为例。
二、示例
static ssize_t demo_show(struct device *dev, struct device_attribute *attr, char *buf)
{
//此函数一般用于打印数据
sprintf(buf,"read,demo temp is %d\n",temp); //将要打印的数据存到buf,最后打印的就是buf的内容
return 0;
}
static ssize_t demo_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t size)
{
//具体要执行的操作,往绑定好的节点echo 1就会执行此函数
return size;
}
static DEVICE_ATTR(show, 0666,demo_show); //0666为可读可写权限
static DEVICE_ATTR(set, 0666,demo_store);
static struct attribute *demo_attrs[] = {
&dev_attr_show.attr, //dev_attr_节点名
&dev_attr_set.attr,
NULL, //这里必须要以NULL结尾
};
static const struct attribute_group demo_attr_grp = {//将定义好的attribute传递到attribute_group
.attrs = demo_attrs,
}
static int __devinit demo_probe(struct platform_device *pdev)
{
int ret = 0;
ret = sysfs_create_group(&pdev->dev.kobj,&demo_attr_grp); //通过具体的dev对象以及定义的attribute_group 创建节点
if (ret < 0)
{
printk("error creating sysfs attr files\n");
goto err_sysfs;
}
err_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &aw9610x_sar_attribute_group); //创建有问题就删除掉节点
return 0;
}
static int __devinit demo_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &aw9610x_sar_attribute_group);
return 0
}
创建完成后可以在/sys/xxx/xxx/目录下(具体是在哪个目录由此参数&pdev->dev.kobj决定)找到show和set节点,cat show即可打印保存在buf的内容,echo 1 > set即可执行demo_store(也就是与set节点绑定的函数)。