【问题标题】:Device Specific Data Structure with Platform Driver and Character Device Interface具有平台驱动程序和字符设备接口的设备特定数据结构
【发布时间】:2017-01-20 16:49:11
【问题描述】:

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

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

dev_set_drvdata(dev, data_struct);

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

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

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

【问题讨论】:

    标签: linux-kernel driver linux-device-driver embedded-linux kernel-module


    【解决方案1】:

    当您的 miscdevice 首次打开时,miscdevice 框架会将file->private_data 设置为您的struct miscdevice(参见misc_open() 函数和comment to misc_register() 函数)。您可以依靠它并在文件操作中使用file->private_data 来获取您的自定义结构,使用container_of() 宏。当然,您的自定义结构必须包含您的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/
    

    【讨论】:

      【解决方案2】:

      感谢这个 misc device 的实现来解决这个问题!

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-14
        • 1970-01-01
        相关资源
        最近更新 更多