归结为下一个:
- 重用现有的 kobject
struct device
(从你的struct platform_device
) for sysfs_create_group()
(而不是创建自己的kobject
)
- use
DEVICE_ATTR()
声明struct device_attribute
而不是常规的__ATTR()
,这会创建struct kobj_attribute
.
以下是我为平台驱动程序创建 sysfs 属性的方法。
-
创建您将用作私有数据的结构show()
/ store()
sysfs 属性(文件)的操作。例如:
struct mydrv {
struct device *dev;
long myparam;
};
-
在您的驱动程序中分配此结构probe()
:
static int mydrv_probe(struct platform_device *pdev)
{
struct mydrv *mydrv;
mydrv = devm_kzalloc(&pdev->dev, sizeof(*mydrv), GFP_KERNEL);
mydrv->dev = &pdev->dev;
platform_set_drvdata(pdev, mydrv);
...
}
-
Create show()
/ store()
功能:
static ssize_t mydrv_myparam_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mydrv *mydrv = dev_get_drvdata(dev);
int len;
len = sprintf(buf, "%d\n", mydrv->myparam);
if (len <= 0)
dev_err(dev, "mydrv: Invalid sprintf len: %d\n", len);
return len;
}
static ssize_t mydrv_myparam_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mydrv *mydrv = dev_get_drvdata(dev);
kstrtol(buf, 10, &mydrv->myparam);
return count;
}
-
为这些函数创建设备属性(就在这些函数之后):
static DEVICE_ATTR(myparam, S_IRUGO | S_IWUSR, mydrv_myparam_show,
mydrv_myparam_store);
-
声明属性表(实际上列出系统文件系统文件给你的司机):
static struct attribute *mydrv_attrs[] = {
&dev_attr_myparam.attr,
NULL
};
-
声明属性组(实际上指定sysfs目录为您的司机):
static struct attribute_group mydrv_group = {
.name = "mydrv",
.attrs = mydrv_attrs,
};
static struct attribute_group *mydrv_groups[] = {
&mydrv_group,
NULL
}
实际上可以用一行替换:
ATTRIBUTE_GROUPS(mydrv);
-
在驱动程序中创建 sysfs 目录和文件probe()
功能:
static int mydrv_probe(struct platform_device *pdev)
{
int ret;
...
ret = sysfs_create_group(&pdev->dev.kobj, &mydrv_group);
if (ret) {
dev_err(&pdev->dev, "sysfs creation failed\n");
return ret;
}
...
}
-
删除驱动程序中的 sysfs 文件remove()
功能:
static int mydrv_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &mydrv_group);
...
}
竞赛条件注释
正如@FranzForstmayr 正确指出的那样,可能有竞争条件添加 sysfs 文件时sysfs_create_group()
in mydrv_probe()
。这是因为用户空间已经可以被通知这些文件之前存在mydrv_probe()
调用(这些文件实际上是由sysfs_create_group()
功能)。这个问题在《如何正确创建 sysfs 文件》格雷格·克罗哈特曼的文章。
所以在我们的例子中platform_device
,而不是调用sysfs_create_group()
(及其对应的sysfs_remove_group()
), 您可以使用默认属性组。为此,您需要分配相应的.groups
你的领域struct device
到您的属性组变量:
static int mydrv_probe(struct platform_device *pdev)
{
...
pdev->dev.groups = mydrv_groups;
...
}
免责声明:我没有测试这段代码,尽管它应该可以工作,因为this code.
有关上述竞争条件的更多见解,请参阅 [1,2,3] 链接。
有关更多示例,请在内核源目录中运行下一个命令:
$ git grep -l --all-match -e platform_device -e attribute -e '\.groups =' -- drivers/
您还可以在提交消息中按“默认属性”进行搜索:
$ git log --no-merges --oneline --grep="default attribute" -- drivers/
我发现的一些提交是这样的:[4,5,6,7]。
参考
[1] 我的属性太活泼了,我该怎么办?
[2] 补丁:sysfs:添加 devm_sysfs_create_group() 和朋友
[3] [GIT PATCH] 3.11-rc2的驱动核心补丁
[4] commit 1
[5] commit 2
[6] commit 3
[7] commit 4