加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux-kernel – 具有平台驱动程序和字符设备接口的设备特定数据

发布时间:2020-12-14 00:43:28 所属栏目:Linux 来源:网络整理
导读:我正在努力理解平台设备驱动程序与字符设备接口之间的链接以及将数据存储在特定于设备的数据结构中. 我创建了一个结构来跟踪与我的设备相关的数据,然后将它添加到probe函数的devices结构中: dev_set_drvdata(dev,data_struct); 我还保留了data_struct的全局
我正在努力理解平台设备驱动程序与字符设备接口之间的链接以及将数据存储在特定于设备的数据结构中.

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

dev_set_drvdata(dev,data_struct);

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

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

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

解决方法

当你的miscdevice第一次打开时,miscdevice框架会将file-> private_data设置为你的struct miscdevice(参见 misc_open()函数和 comment to misc_register()函数).您可以依赖于此并使用文件操作中的file-> private_data来使用container_of()宏来获取自定义结构.当然,您的自定义结构必须包含您的struct miscdevice.这种简洁而常用的方法是创建一个名为_ *()的辅助函数,它将通过提供的文件指针找出并返回自定义结构.因此,如果调用自定义结构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 miscdevn");
        return ret;
    }

    dev_info(&pdev->dev,"Registeredn");

    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,"Unregisteredn");

    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/

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读