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)