usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动。两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备。libusb中须要先detach内核驱动后,才能claim interface,否则claim会返回的vice busy的错误。如果你不dettach,也不claim interface,也能使用libusb对设备进行访问,但是,容易导致内核usbfs瘫痪,这是不允许的。
如果不能dettach内核驱动,那么你不能通过usbfs访问设备,也就是不能使用libusb。若确实需要usbfs才能完成的操作,如控制传输,中断传输等,可以在内核驱动里给ioctl添加对应的功能,即可通过内核驱动完成usb设备的所有原始通信。
使用libusb读写ft232的eeprom,不允许把内核驱动dettach的情况下,经常导致usbfs瘫痪,所有usb都处于disk sleep状态。这里我之用得到control传输,经过一番思考,我在内核驱动里面的ioctl里添加了USBDEVFS_CONTROL选项,通过内核驱动完成usb control msg,测试了好几天,没发现任何问题。好,基本完成任务。
以下是我的操作:
在设备驱动文件ftdi_sio.c的ioctl函数里面添加:
- static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
- {
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- int ret, mask;
- dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
- /* Based on code from acm.c and others */
- switch (cmd) {
- /* To support usb_control_msg to ttyUSB */
- case USBDEVFS_CONTROL:
- dev_printk(KERN_DEBUG, &port->serial->dev->dev, "%s: CONTROL\n", __FUNCTION__);
- return tty_control(port, (void __user *)arg);
- break;
- case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
- 。。。。。。
以下是从usbfs的proc_control()移植过来的控制传输函数:
- static int tty_control(struct usb_serial_port *port, void __user *arg)
- {
- struct usb_device *dev = port->serial->dev;
- struct usbdevfs_ctrltransfer ctrl;
- unsigned int tmo;
- unsigned char *tbuf;
- int i, j, ret;
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
- //if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
- //return ret;
- if (ctrl.wLength > PAGE_SIZE)
- return -EINVAL;
- if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- tmo = (ctrl.timeout * HZ + 999) / 1000;
- if (ctrl.bRequestType & 0x80) {
- if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
- free_page((unsigned long)tbuf);
- return -EINVAL;
- }
- dev_printk(KERN_DEBUG, &dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
- ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
- if ((i > 0) && ctrl.wLength) {
- if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {
- free_page((unsigned long)tbuf);
- return -EFAULT;
- }
- }
- } else {
- if (ctrl.wLength) {
- if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
- free_page((unsigned long)tbuf);
- return -EFAULT;
- }
- }
- dev_printk(KERN_DEBUG, &dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
- i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
- ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
- }
- free_page((unsigned long)tbuf);
- if (i<0) {
- dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
- "failed cmd %s rqt %u rq %u len %u ret %d\n",
- current->comm, ctrl.bRequestType, ctrl.bRequest,
- ctrl.wLength, i);
- }
- return i;
- }
好了,编译加载后,设备文件就支持usb_control_msg了。以下是用户程序的usb_control_msg
- #define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer)
- struct usb_ctrltransfer {
- /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */
- u_int8_t bRequestType;
- u_int8_t bRequest;
- u_int16_t wValue;
- u_int16_t wIndex;
- u_int16_t wLength;
- u_int32_t timeout; /* in milliseconds */
- /* pointer to data */
- void *data;
- };
- static int usb_control_msg(int fd, int requesttype, int request,
- int value, int index, char *bytes, int size, int timeout)
- {
- struct usb_ctrltransfer ctrl;
- int ret;
- ctrl.bRequestType = requesttype;
- ctrl.bRequest = request;
- ctrl.wValue = value;
- ctrl.wIndex = index;
- ctrl.wLength = size;
- ctrl.data = bytes;
- ctrl.timeout = timeout;
- ret = ioctl(fd, IOCTL_USB_CONTROL, &ctrl);
- if (ret < 0)
- printf("usb_control_msg: %s\n", strerror(errno));
- return ret;
- }
其实,上面的usb_ctrltransfer和usbdevice_fs.h 里的struct usbdevfs_ctrltransfer是一样的,只是为了方便查阅,才定义了另外一个在源文件里。
linux-2.6.8.1/include/linux/usbdevice_fs.h
- /* usbdevfs ioctl codes */
- struct usbdevfs_ctrltransfer {
- __u8 bRequestType;
- __u8 bRequest;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
- __u32 timeout; /* in milliseconds */
- void __user *data;
- };
- #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer)