如何将文件操作附加到平台驱动程序中的 sysfs 属性? [英] How to attach file operations to sysfs attribute in platform driver?
问题描述
我为我们开发的外围设备编写了一个平台驱动程序,并希望向 sysfs 公开一些配置选项.我已经设法在探测函数中使用属性结构(见下文)和 sysfs_create_file
创建了适当的文件,但我不知道如何将显示/存储函数附加到平台中的结构司机.
I wrote a platform driver for a peripheral we developed and would like to expose some configuration options to the sysfs. I have managed to create the appropriate files using attribute structs (see below) and sysfs_create_file
in the probe function, but I can't figure out how to attach the show/store functions to the structs in a platform driver.
我在网上找到的大多数资源都使用 device_attribute
结构或类似的东西来创建它们的文件,这在这里也合适吗?对于平台驱动程序,还有其他方法可以做到这一点吗?
Most resources I found online used a device_attribute
struct or something similar to create their files, is that also appropriate here? Is there another way to do this for a platform driver?
我的属性结构如下所示:
My attribute struct looks like this:
struct attribute subkey_attr = {
.name = "subkeys",
.mode = S_IWUGO | S_IRUGO,
};
我使用这个调用注册文件:
And I register the file using this call:
riddler_kobject = &pdev->dev.kobj;
ret_val = sysfs_create_file(riddler_kobject, &subkey_attr);
推荐答案
归结为下一个:
- 将
struct device
(来自您的struct platform_device
)中的现有 kobject 重用于sysfs_create_group()
(而不是创建您自己的kobject
) - 使用
DEVICE_ATTR()
来声明struct device_attribute
而不是常规的__ATTR()
,这会创建struct kobj_attribute
.
- reuse existing kobject from
struct device
(from yourstruct platform_device
) forsysfs_create_group()
(instead of creating your ownkobject
) - use
DEVICE_ATTR()
to declarestruct device_attribute
instead of regular__ATTR()
, which createsstruct kobj_attribute
.
这是我为我的平台驱动程序创建 sysfs 属性的方法.
Here is how I created sysfs attributes for my platform driver.
创建您将在
show()
/store()
操作中用作 sysfs 属性(文件)的私有数据的结构.例如:
Create structure you'll be using as private data in
show()
/store()
operations for your sysfs attribute (file). For example:
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);
...
}
创建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
", mydrv->myparam);
if (len <= 0)
dev_err(dev, "mydrv: Invalid sprintf len: %d
", 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;
}
为这些函数创建设备属性(在这些函数之后):
Create device attribute for those functions (right after those functions):
static DEVICE_ATTR(myparam, S_IRUGO | S_IWUSR, mydrv_myparam_show,
mydrv_myparam_store);
声明属性表(实际上为您的驱动程序列出sysfs 文件):
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
}
实际上可以用一行替换:
which can be actually replaced with one line:
ATTRIBUTE_GROUPS(mydrv);
在驱动程序的 probe()
函数中创建 sysfs 目录和文件:
Create sysfs directory and files in your driver's probe()
function:
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
");
return ret;
}
...
}
在驱动程序的 remove()
函数中删除 sysfs 文件:
Remove your sysfs files in your driver's remove()
function:
static int mydrv_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &mydrv_group);
...
}
比赛条件说明
正如@FranzForstmayr 正确指出的那样,在mydrv_probe()
中使用sysfs_create_group()
添加sysfs 文件时可能会出现竞争条件.这是因为用户空间可以在 mydrv_probe()
调用之前已经通知这些文件存在(这些文件实际上是由 sysfs_create_group()
函数创建的).中详细介绍了此问题如何正确创建 sysfs 文件" Greg Kroah-Hartman 的文章.
Race condition note
As @FranzForstmayr correctly pointed out, there may be race condition when adding sysfs files with sysfs_create_group()
in mydrv_probe()
. That's because user-space can be already notified that those files exist before mydrv_probe()
called (where those files are actually being created by sysfs_create_group()
function). This issue covered in details in "How to Create a sysfs File Correctly" article by Greg Kroah-Hartman.
因此,在我们的 platform_device
示例中,您可以使用 sysfs_create_group()
(及其对应的 sysfs_remove_group()
),而不是调用 强>默认属性组.为此,您需要将
struct device
的相应 .groups
字段分配给您的属性组变量:
So in our case of platform_device
, instead of calling sysfs_create_group()
(and its counterpart sysfs_remove_group()
), you can use default attribute group. To do so, you need to assign corresponding .groups
field of your struct device
to your attribute groups variable:
static int mydrv_probe(struct platform_device *pdev)
{
...
pdev->dev.groups = mydrv_groups;
...
}
免责声明:我没有测试这段代码,虽然它应该可以工作,因为 这个代码.
DISCLAIMER: I didn't test this code, though it should work, because of this code.
请参阅 [1,2,3] 链接以获取有关上述竞争条件的更多见解.
See [1,2,3] links for more insights on mentioned race condition.
更多示例,请在内核源目录中运行下一个命令:
For more examples, run next command in kernel source directory:
$ git grep -l --all-match -e platform_device -e attribute -e '.groups =' -- drivers/
您也可以在提交消息中通过默认属性"进行搜索:
Also you can search by "default attribute" in commit messages:
$ git log --no-merges --oneline --grep="default attribute" -- drivers/
我通过这种方式发现的一些提交:[4,5,6,7].
Some commits I found this way: [4,5,6,7].
[1] 我的属性太活泼了,我该怎么办?
[2] PATCH:sysfs:添加 devm_sysfs_create_group() 和朋友
[3] [GIT PATCH] 3.11-rc2 驱动核心补丁
[4] 提交 1
[5] 提交 2
[6] 提交 3
[7] 提交 4
这篇关于如何将文件操作附加到平台驱动程序中的 sysfs 属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!