linux内核中提供了sysfs接口给用户使用,用户可以通过echo cat等命令来查看驱动中某些变量的值。
//灯灭
echo 0 >/sys/class/leds/firefly:blue:power/brightness
//灯亮
echo 1 >/sys/class/leds/firefly:blue:power/brightness
接口创建
声明节点,创建读写函数
使用DEVICE_ATTR可以声明一个sysfs节点,原型为DEVICE_ATTR(_name, _mode, _show, _store),其定义位于include/linux/device.h中,定义如下所示:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
其中_mode定义如下:
400 拥有者能够读,其他任何人不能进行任何操作;
644 拥有者都能够读,但只有拥有者可以编辑;
660 拥有者和组用户都可读和写,其他人不能进行任何操作;
664 所有人都可读,但只有拥有者和组用户可编辑;
700 拥有者能够读、写和执行,其他用户不能任何操作;
744 所有人都能读,但只有拥有者才能编辑和执行;
755 所有人都能读和执行,但只有拥有者才能编辑;
777 所有人都能读、写和执行(该设置通常不是好想法)
使用方法为:
static ssize_t show_my_device(struct device *dev,
struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数
{
return buf;
}
static ssize_t set_my_device(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len) //echo命令时,将会调用该函数.
{
return len;
}
static DEVICE_ATTR(xx_dev, S_IWUSR|S_IRUSR, show_my_device, set_my_device); //定义一个名字为my_device_test的设备属性文件
其中,函数show_my_device和set_my_device即是cat和echo命令对应的执行函数。
定义struct attribute和struct attribute_group数组
static struct attribute *xx_attributes[]={
/*上述使用了DEVICE_ATTR声明节点名字为xx_dev,
* 则struct attribute名字应为:
* dev_attr_ + (节点名) + .attr
* 所以名字为dev_attr_xx_dev.attr
*/
&dev_attr_xx_dev.attr,
NULL,
};
static const struct attribute_group xx_attrs={
.attrs = xx_attributes,//引用上述struct attribute数组
};
注册接口
在驱动函数中调用sysfs_create_group()和sysfs_remove_group()即可注册或删除节点
int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
int sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
驱动程序示例
static unsigned int xxx = 0;
static ssize_t show_my_device(struct device *dev, struct device_attribute *attr, char *buf)
{
//打印相关信息
return sprintf(buf, "%s:%d.\n", "xxx", xxx);
}
static ssize_t set_my_device(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//从用户态读取相关信息
sscanf(buf, "%d", &xxx);
return count;
}
static DEVICE_ATTR(xxx_dev, 0600, show_my_device, set_my_device);
static struct attribute *xxx_attributes[]={
&dev_attr_xxx_status.attr,
NULL,
};
static const struct attribute_group xxx_attrs={
.attrs = xxx_attributes,
};
static int xxx_probe(struct platform_device *pdev)
{
sysfs_create_group(&pdev->dev.kobj, &xxx_attrs);
return 0;
}
static int xxx_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &xxx_attrs);
return 0;
}
static const struct of_device_id xxx_of_match[] = {
{.compatible = "xx,xxx"},
};
static struct platform_driver xxx_driver = {
.probe = xxx_probe,
.remove = xxx_remove,
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
.of_match_table = xxx_of_match,
},
};
static int __init xxx_init(void)
{
return platform_driver_register(&xxx_driver );
}
static void __exit xxx_exit(void)
{
platform_driver_unregister(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);