我为我们开发的外围设备编写了一个平台驱动程序,并希望向sysfs公开一些配置选项。我已经设法使用探测器函数中的属性结构(见下文)和sysfs_create_file
创建了相应的文件,但我无法弄清楚如何将show / store函数附加到平台驱动程序中的结构。 / p>
我在网上找到的大多数资源使用device_attribute
结构或类似的东西来创建文件,这在哪里也适用?还有另一种方法可以为平台驱动程序执行此操作吗?
我的属性struct看起来像这样:
struct attribute subkey_attr = {
.name = "subkeys",
.mode = S_IWUGO | S_IRUGO,
};
我使用此调用注册该文件:
riddler_kobject = &pdev->dev.kobj;
ret_val = sysfs_create_file(riddler_kobject, &subkey_attr);
答案 0 :(得分:18)
归结为下一个:
struct device
(来自struct platform_device
){/ 1}}的现有kobject(而不是创建自己的sysfs_create_group()
)kobject
来声明DEVICE_ATTR()
而非常规struct device_attribute
,这会创建__ATTR()
。以下是我为平台驱动程序创建sysfs属性的方法。
在sysfs属性(文件)的struct kobj_attribute
/ show()
操作中创建您将用作私有数据的结构。例如:
store()
在您的驱动程序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\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;
}
为您的驱动程序声明属性表(实际列出 sysfs文件):
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
};
实际上可以替换为一行:
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()
正如@FranzForstmayr正确指出的那样,在static int mydrv_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &mydrv_group);
...
}
中添加sysfs_create_group()
的sysfs文件时,可能会有竞争条件。这是因为在调用mydrv_probe()
之前可以通知用户空间这些文件存在(这些文件实际上是由mydrv_probe()
函数创建的)。这个问题在Greg Kroah-Hartman撰写的"How to Create a sysfs File Correctly"文章中有详细介绍。
因此,在sysfs_create_group()
的情况下,您可以使用默认属性组,而不是调用platform_device
(及其对应的sysfs_create_group()
)。为此,您需要将sysfs_remove_group()
的相应.groups
字段分配给您的属性组变量:
struct device
免责声明:由于代码this,我没有测试此代码,但它应该可以使用。
有关上述竞争条件的更多见解,请参阅[1,2,3]链接。
有关更多示例,请在内核源目录中运行next命令:
static int mydrv_probe(struct platform_device *pdev)
{
...
pdev->dev.groups = mydrv_groups;
...
}
您也可以在提交消息中使用“default attribute”进行搜索:
$ git grep -l --all-match -e platform_device -e attribute -e '\.groups =' -- drivers/
我发现了一些提交:[4,5,6,7]。
[1] My attributes are way too racy, what should I do?
[2] PATCH: sysfs: add devm_sysfs_create_group() and friends
[3] [GIT PATCH] Driver core patches for 3.11-rc2
[4] commit 1
[5] commit 2
[6] commit 3
[7] commit 4
答案 1 :(得分:0)
没有足够的声誉来发表评论,但我只想评论已接受答案中的默认属性组笔记。 我的理解是,不应如示例中所示在探测函数中添加它,而应在通常在您的末尾定义的设备结构(或device_driver,类或总线,取决于驱动程序)中进行设置文件。 例如:
static struct device iio_evgen_dev = {
.bus = &iio_bus_type,
.groups = iio_evgen_groups,
.release = &iio_evgen_release,
};
来自this示例
奇怪的是,根据this,当使用DEVICE_INT_ATTR
创建属性时,它无法正常工作,因此不确定所有内容。
我也不是100%肯定,但是我认为this是在加载驱动程序时调用的,而不是在探测设备时调用的。
答案 2 :(得分:0)
这是对 Sam Protsenko 和 Anthony 回答的补充
如果您通过 DEVICE_ATTR
宏创建设备属性,那么您必须在 mydrv_groups
而不是 {{ 1}} 字段。
.dev_groups
然后属性会自动正确注册,无需在探测/删除函数中设置任何内容,如 Greg Kroah-Hartman 的文章中所述。
假设模块已经加载到内核中并且驱动程序在
中注册.groups
每个设备实例都将是驱动程序文件夹的子目录,例如
static struct device iio_evgen_dev = {
.bus = &iio_bus_type,
.dev_groups = iio_evgen_groups, // .dev_groups for DEVICE_ATTR
.groups = another_attr_group, // .groups for DRIVER_ATTR
.release = &iio_evgen_release,
};
在 /sys/bus/platform/drivers/mydrv
字段中注册属性会在 driver 文件夹中创建属性。
在 /sys/bus/platform/drivers/mydrv/mydrv1
/sys/bus/platform/drivers/mydrv/mydrv2
字段中注册属性会在 device 的实例文件夹中创建属性。
.groups
.dev_groups
字段中属性的显示/存储功能无法通过 mydrv
├── driver_attr1
├── driver_attr2
└── mydrv1
├── device_attr1
└── device_attr2
访问驱动程序数据集。
至少不是通过 .groups
访问它。
通过 platform_set_drvdata(pdev, mydrv)
访问驱动程序数据返回 dev_get_drvdata(dev)
并取消引用它会导致内核 oops。
反过来,他在 dev_get_drvdata(dev)
字段中显示/存储属性的函数可以通过
NULL