繁体   English   中英

具有平台驱动程序和字符设备接口的设备特定数据结构

[英]Device Specific Data Structure with Platform Driver and Character Device Interface

我正在努力理解具有字符设备接口的平台设备驱动程序与将数据存储在设备特定的数据结构中之间的联系。

我创建了一个结构体来跟踪与我的设备相关的数据,然后将它添加到探针函数中的设备结构体中:

dev_set_drvdata(dev, data_struct);

我还保留了data_struct的全局副本。

我注册了一个 misc 设备,以便我可以mmap()并通过ioctl()命令访问该设备。 如果我想访问这个设备的data_struct ,目前我是通过全局副本访问它的。 是否有另一种方式通过inodefile指针访问我存储在设备结构中的数据?

我目前只允许设备的一个实例,但我想确保我正确地实现了这一点,以便将来可能有多个设备使用相同的驱动程序。

当您的 miscdevice 第一次打开时, miscdevice 框架会将file->private_data设置为您的struct miscdevice (请参阅misc_open()函数以及对 misc_register()函数的注释)。 您可以依靠它并在您的文件操作中使用file->private_data来获取您的自定义结构,使用container_of()宏。 当然,您的自定义结构必须struct miscdevice包含您的struct miscdevice 这样做的简洁且常用的方法是创建名为to_*()辅助函数,它将通过提供的file指针找出并返回您的自定义结构。 因此,如果您调用自定义结构my_struct ,则应将该辅助函数称为to_my_struct()

此外,如果您正在编写平台驱动程序,您可以使用platform_set_drvdata()而不是dev_set_drvdata() 这是必需的,以便您可以在平台驱动程序的remove()函数中获取自定义结构。

这是上面解释的所有内容的示例:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

struct my_struct {
    struct platform_device *pdev;
    struct miscdevice mdev;
};

static inline struct my_struct *to_my_struct(struct file *file)
{
    struct miscdevice *miscdev = file->private_data;

    return container_of(miscdev, struct my_struct, mdev);
}

static ssize_t my_read(struct file *file, char __user *buf, size_t count,
                       loff_t *pos)
{
    struct my_struct *my = to_my_struct(file); /* just for example */

    (void)my; /* unused */
    return simple_read_from_buffer(buf, count, pos, "my text", 7);
}

static const struct file_operations my_fops = {
    .owner  = THIS_MODULE,
    .read   = my_read,
};

static int my_probe(struct platform_device *pdev)
{
    struct my_struct *my;
    int ret;

    my = kmalloc(sizeof(*my), GFP_KERNEL);
    if (!my)
        return -ENOMEM;

    platform_set_drvdata(pdev, my);
    my->pdev = pdev;

    my->mdev.minor  = MISC_DYNAMIC_MINOR;
    my->mdev.name   = "my";
    my->mdev.fops   = &my_fops;
    my->mdev.parent = NULL;

    ret = misc_register(&my->mdev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to register miscdev\n");
        return ret;
    }

    dev_info(&pdev->dev, "Registered\n");

    return 0;
}

static int my_remove(struct platform_device *pdev)
{
    struct my_struct *my = platform_get_drvdata(pdev);

    misc_deregister(&my->mdev);
    kfree(my);
    dev_info(&pdev->dev, "Unregistered\n");

    return 0;
}

static struct platform_driver my_driver = {
    .probe      = my_probe,
    .remove     = my_remove,
    .driver = {
        .name = "my",
    },
};

module_platform_driver(my_driver);

MODULE_AUTHOR("Sam Protsenko");
MODULE_DESCRIPTION("Platform device driver using char device example");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:my");

顺便说一句,您可以在内核代码中查找示例,只需使用关键字,如下所示:

$ git grep -l --all-match -e 'misc_register(' -e 'platform_device' -e 'file->private_data' -- drivers/

感谢使用 misc device 来解决这个问题!

对于将来引用此内容的任何人,我在将其插入内核时遇到了分段错误。 如果有帮助:

而不是: my = kmalloc(sizeof(*my), GFP_KERNEL);

我用过: my = (struct my_struct *) kmalloc(sizeof(struct my_struct), GFP_KERNEL);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM