在Linux驱动调试时,常常需要添加属性文件,sysfs属性节点可以实现用户空间与硬件或者驱动交互。
DEVICE_ATTR介绍
/* 路径:linux/device.h */
#define DEVICE_ATTR(_name, _mode, _show, _store) \struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)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);
};/* 路径:include/linux/sysfs.h */
#define __ATTR(_name, _mode, _show, _store) { \.attr = {.name = __stringify(_name), \.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \.show = _show, \.store = _store, \
}
DEVICE_ATTR 宏用来定义一个 struct device_attribute 结构体,并对各成员初始化。注意变量名称为dev_attr##_name
。
DEVICE_ATTR(_name, _mode, _show, _store)
- _name:名称,也就是将在sysfs中生成的文件名称;
- _mode:属性文件的权限mode,与普通文件相同,UGO的格式。只读0444,只写0222,或者读写都行的0666;
- _show:显示函数,cat该文件时,此函数被调用;
- _store:写函数,echo内容到该文件时,此函数被调用;
示例
ssize_t param_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "hello i am param_show\n");
}ssize_t param_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{printk("%s:%s\n", __func__,buf);return count;
}static DEVICE_ATTR(param, 0664, param_show, param_store);static int haptic_drv_probe(struct platform_device *pdev)
{int ret = 0;int* status=NULL;struct resource* res0=NULL;struct resource* res1=NULL;haptic_miscdev_t *hap_miscdev=NULL;struct file_operations *haptics_fops=NULL;res0 = platform_get_resource(pdev,IORESOURCE_MEM,0);res1 = platform_get_resource(pdev,IORESOURCE_MEM,1);printk("res0 start=%d size=%d\n",(int)res0->start,(int)(res0->end-res0->start+1));printk("res1 start=%d size=%d\n",(int)res1->start,(int)(res1->end-res1->start+1));status = dev_get_platdata(&pdev->dev);printk("status=%d\n",*status);haptics_fops = devm_kzalloc(&pdev->dev,sizeof(struct file_operations), GFP_KERNEL);haptics_fops->open = haptics_open;haptics_fops->release = haptics_release;haptics_fops->unlocked_ioctl = haptics_ioctl;hap_miscdev = devm_kzalloc(&pdev->dev,sizeof(haptic_miscdev_t), GFP_KERNEL);hap_miscdev->res = res0;hap_miscdev->status = *status;hap_miscdev->miscdev.name = pdev->name;hap_miscdev->miscdev.fops = haptics_fops;hap_miscdev->miscdev.minor = MISC_DYNAMIC_MINOR,ret = misc_register(&hap_miscdev->miscdev);/* save as drvdata *///platform_set_drvdata函数,将设备数据信息存入在平台驱动结构体中pdev->dev->driver_data中platform_set_drvdata(pdev, hap_miscdev);device_create_file(&pdev->dev,&dev_attr_param);return ret;
}static int haptic_drv_remove(struct platform_device *pdev)
{int ret = 0;haptic_miscdev_t *hap_miscdev = platform_get_drvdata(pdev);device_remove_file(&pdev->dev,&dev_attr_param);misc_deregister(&hap_miscdev->miscdev);return ret;
}
我们可以看到设备文件夹下有我们创建的属性文件。
cat命令
可以获取show函数
中的buf
echo命令
可以将参数传给store函数
中的buf
创建多个sysfs属性文件
对于多个属性文件的添加,我们可以定义属性组,然后将这个属性组使用 sysfs_create_group() 添加进sysfs文件系统中。
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
示例
ssize_t param0_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "hello i am param0_show\n");
}ssize_t param0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{printk("%s:%s\n", __func__,buf);return count;
}ssize_t param1_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "hello i am param1_show\n");
}ssize_t param1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{printk("%s:%s\n", __func__,buf);return count;
}static DEVICE_ATTR(param0, 0664, param0_show, param0_store);
static DEVICE_ATTR(param1, 0664, param1_show, param1_store);static struct attribute* haptic_params_attributes[] =
{&dev_attr_param0.attr,&dev_attr_param1.attr,NULL,
};static struct attribute_group haptic_param_attr_group =
{.attrs = haptic_params_attributes,
};ret = sysfs_create_group(&pdev->dev.kobj,&haptic_param_attr_group);
总结
我们在前面也介绍了设备节点,就是在/dev/xxx
目录下的,那么今天介绍的设备属性节点又有啥不一样呢。其他大差不差,都是给应用层提供操作接口。但是属性节点可以直接使用cat
或者echo
命令来操作,也可以在应用程序中进行操作,操作的方式与设备节点的方式一致,这里就不做示例了。
关于设备属性节点的位置,我看很多介绍说是在/sys/class
目录下,但是我们前面的实例是注册的杂项设备,在该目录下没有找到属性节点,只在/sys/devices
目录下找到了。
接口。但是属性节点可以直接使用cat
或者echo
命令来操作,也可以在应用程序中进行操作,操作的方式与设备节点的方式一致,这里就不做示例了。
关于设备属性节点的位置,我看很多介绍说是在/sys/class
目录下,但是我们前面的实例是注册的杂项设备,在该目录下没有找到属性节点,只在/sys/devices
目录下找到了。