我正在为USB设备编写驱动程序,该驱动程序具有三种不同的读/写操作(闪存,EEPROM和I2C),每种操作都有不同的实现。我一直在摸不着头脑,因为我对这个整个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;
}
答案 0 :(得分: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模型的操作的全能。
答案 1 :(得分:0)
在框外思考:
假设您的设备可行,您可以考虑使用libusb (old link) (SourceForge)或其他用户空间USB库编写用户空间驱动程序。然后,您可以更轻松地调试,开发和测试,并获得潜在的跨平台兼容性的额外优势,而无需编写内核驱动程序。