如何在Linux驱动ioctl()中通过file对象获取pci_dev及驱动数据?
嘿,这个问题我熟!在Linux内核里要从ioctl的struct file*指针拿到之前存在pci_dev里的drvdata,核心是把file和pci_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




