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



我正在为一个USB设备编写一个驱动程序,该设备有三种不同的读/写操作(闪存、EEPROM和I2C(,每种操作都有不同的实现方式。我一直在为这件事挠头,因为我是linux内核开发领域的新手。我读到我应该不惜一切代价避免ioctl,但我不知道如何实现它。既然linux中的所有东西都是一个文件,我可以为每个位置创建多个要写入的端点吗?我该怎么做呢?我会定义多个usb_class_driver结构吗?

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

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

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

在漂流时

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,
};

在漂流途中

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 memoryn");
        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 attachedn");
    return 0;
error:
    if (gdev)
        kref_put(&gdev->kref, adriver_delete);
    return retval;
}

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

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

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

[iotl]调用被用作不完全适合UNIX流I/O模型的操作的catch-all。

跳出框框思考:

假设这在您的设备上是可行的,您可以考虑使用libusb(旧链接((SourceForge(或另一个用户空间USB库编写用户空间驱动程序。然后,您可以更容易地调试、开发和测试,并获得潜在的跨平台兼容性的额外优势,而无需编写内核驱动程序。

最新更新