You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Linux驱动ioctl()中通过file对象获取pci_dev及驱动数据?

嘿,这个问题我熟!在Linux内核里要从ioctl的struct file*指针拿到之前存在pci_dev里的drvdata,核心是把filepci_dev提前关联起来,最常用也最清晰的方式是通过驱动的open函数把关联信息存在file->private_data里,下面给你一步步拆解:

第一步:先定义自定义设备结构体(常规操作,让代码更清晰)

如果还没定义,先搞一个封装PCI设备和字符设备的结构体,把相关资源都整合在一起:

struct my_pcie_device {
    struct pci_dev *pdev;       // 指向对应的PCI设备对象
    struct cdev cdev;           // 字符设备对象
    // 这里可以加你的其他业务数据字段,也可以直接把这个结构体作为pci_set_drvdata的存储内容
};

第二步:在PCI驱动的probe函数里完成关联初始化

在probe函数中,除了调用pci_set_drvdata,还要完成字符设备的注册,并把自定义结构体和PCI设备绑定:

static int my_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct my_pcie_device *dev;
    dev_t dev_num;

    // 分配自定义结构体内存
    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    // 关联PCI设备指针
    dev->pdev = pdev;
    // 把自定义结构体存在pci_dev的drvdata里(如果你要存的是其他数据块,直接替换成你的数据即可)
    pci_set_drvdata(pdev, dev);

    // 动态分配字符设备号(也可以静态提前申请)
    if (alloc_chrdev_region(&dev_num, 0, 1, "my_pcie_drv") < 0) {
        kfree(dev);
        return -ENODEV;
    }

    // 初始化并注册字符设备
    cdev_init(&dev->cdev, &my_pcie_fops);
    dev->cdev.owner = THIS_MODULE;
    if (cdev_add(&dev->cdev, dev_num, 1) < 0) {
        unregister_chrdev_region(dev_num, 1);
        kfree(dev);
        return -ENODEV;
    }

    // 创建设备节点,把自定义结构体作为drvdata传入,方便后续关联
    device_create(my_pcie_class, &pdev->dev, dev_num, dev, "my_pcie_%d", MINOR(dev_num));

    // 其他PCI设备初始化(比如启用设备、映射BAR等)
    // ...

    return 0;
}

第三步:在open函数里绑定file和自定义结构体

当用户空间打开设备节点时,我们把自定义结构体指针存到file->private_data里,为ioctl做准备:

static int my_pcie_open(struct inode *inode, struct file *file)
{
    // 通过inode里的cdev反向找到我们的自定义设备结构体
    struct my_pcie_device *dev = container_of(inode->i_cdev, struct my_pcie_device, cdev);
    
    // 把结构体指针存到file的private_data,ioctl里就能直接取
    file->private_data = dev;

    return 0;
}

第四步:在ioctl里直接获取目标数据

现在在ioctl例程里,就能轻松拿到你之前存在pci_dev里的数据了:

static long my_pcie_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    // 从file里取出自定义结构体
    struct my_pcie_device *dev = file->private_data;
    // 拿到之前通过pci_set_drvdata存储的数据(如果当初存的是其他类型,这里替换成对应类型即可)
    void *your_stored_data = pci_get_drvdata(dev->pdev);

    // 接下来就可以根据ioctl命令处理业务,比如用your_stored_data操作硬件
    // ...

    return 0;
}

额外注意点

  • 确保你的file_operations结构体正确指定了函数指针(4.13内核推荐用unlocked_ioctl而非旧的ioctl):
static const struct file_operations my_pcie_fops = {
    .owner = THIS_MODULE,
    .open = my_pcie_open,
    .unlocked_ioctl = my_pcie_ioctl,
    .release = my_pcie_release, // 记得实现release函数清理资源,避免内存泄漏
};
  • 如果当初你用pci_set_drvdata存的不是自定义结构体,而是直接一块业务数据,那自定义结构体可以简化,只要能关联到pci_dev就行。

内容的提问来源于stack exchange,提问作者Ryan Yuan Hu

火山引擎 最新活动