如何将文件操作附加到平台驱动程序中的sysfs属性?

The*_*ble 7 linux-device-driver linux-kernel embedded-linux sysfs

我为我们开发的外围设备编写了一个平台驱动程序,并希望向sysfs公开一些配置选项.我已设法使用属性结构(见下文)和sysfs_create_file探测函数创建适当的文件,但我无法弄清楚如何将show/store函数附加到平台驱动程序中的结构.

我在网上找到的大多数资源使用了一个device_attribute结构或类似的东西来创建他们的文件,这也适合吗?还有另一种方法可以为平台驱动程序执行此操作吗?

我的属性struct看起来像这样:

struct attribute subkey_attr = {
    .name = "subkeys",
    .mode = S_IWUGO | S_IRUGO,
};
Run Code Online (Sandbox Code Playgroud)

我使用此调用注册该文件:

riddler_kobject = &pdev->dev.kobj;
ret_val = sysfs_create_file(riddler_kobject, &subkey_attr);
Run Code Online (Sandbox Code Playgroud)

Sam*_*nko 20

归结为下一个:

  • struct device(从你的struct platform_device)重用现有的kobject sysfs_create_group()(而不是创建你自己的kobject)
  • 使用DEVICE_ATTR()声明struct device_attribute代替普通__ATTR(),它创建struct kobj_attribute.

以下是我为平台驱动程序创建sysfs属性的方法.

  1. 创建您将用作sysfs属性(文件)的show()/ store()operations中的私有数据的结构.例如:

    struct mydrv {
        struct device *dev;
        long myparam;
    };
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在你的驱动程序中分配这个结构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);
    
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 创建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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 为这些函数创建设备属性(在这些函数之后):

    static DEVICE_ATTR(myparam, S_IRUGO | S_IWUSR, mydrv_myparam_show,
                       mydrv_myparam_store);
    
    Run Code Online (Sandbox Code Playgroud)
  5. 声明属性表(实际上列出了驱动程序的sysfs文件):

    static struct attribute *mydrv_attrs[] = {
        &dev_attr_myparam.attr,
        NULL
    };
    
    Run Code Online (Sandbox Code Playgroud)
  6. 声明属性组(实际上为驱动程序指定sysfs目录):

    static struct attribute_group mydrv_group = {
        .name = "mydrv",
        .attrs = mydrv_attrs,
    };
    
    static struct attribute_group *mydrv_groups[] = {
        &mydrv_group,
        NULL
    }
    
    Run Code Online (Sandbox Code Playgroud)

    实际上可以用一行代替:

    ATTRIBUTE_GROUPS(mydrv);
    
    Run Code Online (Sandbox Code Playgroud)
  7. 在驱动程序的probe()函数中创建sysfs目录和文件:

    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;
        }
    
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  8. 删除驱动程序remove()函数中的sysfs文件:

    static int mydrv_remove(struct platform_device *pdev)
    {
        sysfs_remove_group(&pdev->dev.kobj, &mydrv_group);
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

比赛条件说明

正如@FranzForstmayr正确指出的那样,在使用in 添加sysfs文件时可能存在竞争条件.这是因为在调用之前已经通知用户空间这些文件存在(这些文件实际上是由函数创建的).这个问题在Greg Kroah-Hartman的"如何正确创建sysfs文件"一文中有详细介绍.sysfs_create_group()mydrv_probe()mydrv_probe()sysfs_create_group()

因此,在我们的情况下,您可以使用默认属性组platform_device,而不是调用sysfs_create_group()(及其对应方sysfs_remove_group()).为此,您需要将相应的字段分配给属性组变量:.groupsstruct device

static int mydrv_probe(struct platform_device *pdev)
{
    ...

    pdev->dev.groups = mydrv_groups;

    ...
}
Run Code Online (Sandbox Code Playgroud)

免责声明:我没有测试此代码,但它应该工作,因为这个代码.

有关上述竞争条件的更多见解,请参阅[1,2,3]链接.

有关更多示例,请在内核源目录中运行next命令:

$ git grep -l --all-match -e platform_device -e attribute -e '\.groups =' -- drivers/
Run Code Online (Sandbox Code Playgroud)

您也可以在提交消息中通过"default attribute"进行搜索:

$ git log --no-merges --oneline --grep="default attribute" -- drivers/
Run Code Online (Sandbox Code Playgroud)

我发现了一些提交:[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

  • 您能否根据 Greg KH 的帖子解释如何调整此解决方案?http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/ (2认同)

Ant*_*ony 6

没有足够的声誉来发表评论,但我只想对已接受答案中的默认属性组注释进行评论。我的理解是,不应将其添加到探针函数中,如示例中所示,而应在设备结构中设置(或 device_driver、类或总线,具体取决于您的驱动程序),通常在您的设备末尾定义文件。例如:

static struct device iio_evgen_dev = {
    .bus = &iio_bus_type,
    .groups = iio_evgen_groups,
    .release = &iio_evgen_release,
};
Run Code Online (Sandbox Code Playgroud)

这个例子

奇怪的是,据此,DEVICE_INT_ATTR在用于创建属性时无法正常工作,因此不确定这是什么意思。

另外,我不是 100% 确定,但我认为是在加载驱动程序时调用的,而不是在探测设备时调用的。