问题描述
我为我们开发的外围设备编写了平台驱动程序,并希望向sysfs公开一些配置选项.我已经设法在Probe函数中使用属性struct(请参见下文)和sysfs_create_file
创建适当的文件,但是我不知道如何将show/store函数附加到平台驱动程序中的结构上.
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?
我的属性结构如下:
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.
-
为您的sysfs属性(文件)创建要在
show()
/store()
操作中用作私有数据的结构.例如:
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()
中分配此结构:
Allocate this structure in your driver's 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()
函数:
Create show()
/ store()
functions:
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;
}
为这些功能创建设备属性(在这些功能之后):
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\n");
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()
函数创建的). Greg Kroah-Hartman的如何正确创建sysfs文件" 文章.
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;
...
}
免责声明:由于此代码.
请参阅[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属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!