使用usbfs与内核驱动之间的冲突


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)





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值