如何将文件操作附加到平台驱动程序中的 sysfs 属性? [英] How to attach file operations to sysfs attribute in platform driver?

查看:18
本文介绍了如何将文件操作附加到平台驱动程序中的 sysfs 属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为我们开发的外围设备编写了一个平台驱动程序,并希望向 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 your struct platform_device) for sysfs_create_group() (instead of creating your own kobject)
  • use DEVICE_ATTR() to declare struct device_attribute instead of regular __ATTR(), which creates struct kobj_attribute.

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

Here is how I created sysfs attributes for my platform driver.

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

  1. 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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆