具有多个读取操作、ioctl 或 fops 的 Linux USB 驱动程序?

Posted

技术标签:

【中文标题】具有多个读取操作、ioctl 或 fops 的 Linux USB 驱动程序?【英文标题】:Linux USB driver with multiple read operations, ioctl or fops? 【发布时间】:2014-03-12 23:26:07 【问题描述】:

我正在为具有三种不同读/写操作(闪存、EEPROM 和 I2C)的 USB 设备编写驱动程序,每种操作都有不同的实现。我一直在为此摸不着头脑,因为我是整个 linux 内核开发世界的新手。我读过我应该不惜一切代价避免 ioctl,但我不知道如何实现这一点。由于 linux 中的所有内容都是一个文件,我可以为每个位置创建多个端点来写入吗?我该怎么做呢?我会定义多个usb_class_driver 结构吗?

另一方面,我是否应该在一个端点中包含所有功能并使用 ioctl?将工作从同一个驱动程序中拆分出来更好还是将所有功能整合到一个地方更好?

我不能使用 libusb,因为它对同步传输的限制以及缺乏对 dma 传输的直接控制(两者都需要产品最终产品)。

更新: 在尝试对每个端点使用多个通用文件操作并获得 -98 的响应代码(已注册)之后,我想我将不得不将单个端点与 ioctl 一起使用。无效的代码如下:

在 adriver.h 中

static struct usb_class_driver adriver_eeprom_class = 
    .name = "usb/adriver_eeprom%d",
    .fops = &adriver_eeprom_fops,
    .minor_base = USB_SKEL_MINOR_BASE,
;
static struct usb_class_driver adriver_flash_class = 
    .name = "usb/adriver_flash%d",
    .fops = &adriver_flash_fops,
    .minor_base = USB_SKEL_MINOR_BASE,
;
static struct usb_class_driver adriver_i2c_class = 
    .name = "usb/adriver_i2c%d",
    .fops = &adriver_i2c_fops,
    .minor_base = USB_SKEL_MINOR_BASE,
;
static struct usb_class_driver driver_fifo_class = 
    .name = "usb/driver_fifo%d",
    .fops = &driver_fifo_fops,
    .minor_base = USB_SKEL_MINOR_BASE,
;
static struct usb_class_driver adriver_class = 
    .name = "usb/adriver%d",
    .fops = &adriver_fops,
    .minor_base = USB_SKEL_MINOR_BASE,
;

在 adriver.c 中

static int adriver_probe(struct usb_interface *interface, const struct usb_device_id *id) 
    struct usb_device *udev = interface_to_usbdev(interface);
    struct usb_adriver *gdev;
    int retval = -ENOMEM;
    gdev = kmalloc(sizeof(struct usb_adriver), GFP_KERNEL);
    if(gdev == NULL)
    
        dev_err(&interface->dev, "Out of memory\n");
        goto error;
    
    memset(gdev, 0x00, sizeof(*gdev));

    kref_init(&gdev->kref);

    gdev->udev = usb_get_dev(udev);

    usb_set_intfdata(interface,gdev);

    retval = usb_register_dev(interface, &adriver_eeprom_class);
    if (retval) 
        /* something prevented us from registering this driver */
        pr_err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    
    retval = usb_register_dev(interface, &adriver_flash_class);
    if (retval) 
        /* something prevented us from registering this driver */
        pr_err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    
    retval = usb_register_dev(interface, &adriver_i2c_class);
    if (retval) 
        /* something prevented us from registering this driver */
        pr_err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    
    retval = usb_register_dev(interface, &adriver_fifo_class);
    if (retval) 
        /* something prevented us from registering this driver */
        pr_err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    
    retval = usb_register_dev(interface, &adriver_class);
    if (retval) 
        /* something prevented us from registering this driver */
        pr_err("Not able to get a minor for this device.");
        usb_set_intfdata(interface, NULL);
        goto error;
    

    dev_info(&interface->dev, "USB adriver device now attached\n");
    return 0;

error:
    if (gdev)
        kref_put(&gdev->kref, adriver_delete);
    return retval;

【问题讨论】:

【参考方案1】:

设备驱动程序可以按照您最初的建议创建 3 个设备。如果设备上只有一个 IRQ,这个模型就更合适了。

如果有一点运气和技巧(可能更多的是后者),驱动程序的读写例程只需实现为一个用于读取的函数和一个用于写入的函数,并传递一个额外的参数,或者读/写例程推断通过检查其struct file * 参数(如果命名为f,则为MINOR(f -> f_dentry -> d_inode -> i_rdev),它是哪个设备给出了设备的次要设备ID。由于您在 probe() 函数中使用 device_create() 控制次要设备分配,因此您可以利用它来关联有用的类型信息。

通过这种方式,很容易避免ioctl,对于简单的读写操作确实应该避免。这使得从 bash 脚本、命令行等中使用设备变得很容易。如果涉及到 ioctl,则意味着需要编程语言才能使用它。ioctl() 的手册页说

[ioctl] 调用用作不完全适合 UNIX 流 I/O 模型的操作的包罗万象。

【讨论】:

【参考方案2】:

跳出框框思考:

假设它适用于您的设备,您可以考虑使用libusb(old link)(SourceForge) 或其他用户空间 USB 库编写用户空间驱动程序。然后,您可以更轻松地调试、开发和测试,并获得潜在跨平台兼容性的额外优势,而无需编写内核驱动程序。

【讨论】:

很遗憾,由于需要同步 urb 传输和对 DMA 的控制,我无法使用 libusb(x)。

以上是关于具有多个读取操作、ioctl 或 fops 的 Linux USB 驱动程序?的主要内容,如果未能解决你的问题,请参考以下文章

camera驱动

为啥 ioctl 调用没有传递给 sys_ioctl?

:高级字符驱动程序操作

是否可以以相同或不同的顺序将具有相同标题或标题子集的多个 csv 文件读取到 spark 数据帧中?

具有多个进程的文件操作

在另一个进程上下文中调用释放函数