On Wed, 20 Mar 2002, Greg KH wrote:
>> Folk would benefit from being able to bind/unbind drivers from >> interfaces (viz that recent VMWare note, and there are other cases >> too). > >Agreed. The pencam userspace program has this problem right now with >the video kernel driver being bound to the device. I'd love a solution >for that right now, so much that I'd be willing to add a new ioctl :) See patch below. This was originally created by David many months ago and posted to the list, but not put into the kernel. I modified the original patch to: -patch against the 2.5.7 kernel -use the 'real' interface number, not position (to do this I added 2 methods in usb.c) I would really be happy if this got into the kernel. David, if you have anything to add here or want to do this different, well it's your patch. I will send a second email containing a simple program to exercise this. diff -urN 2.5.7-clean/drivers/usb/devio.c linux/drivers/usb/devio.c --- 2.5.7-clean/drivers/usb/devio.c Mon Mar 18 15:37:15 2002 +++ linux/drivers/usb/devio.c Fri Mar 22 13:20:46 2002 @@ -1059,6 +1059,8 @@ int size; void *buf = 0; int retval = 0; + struct usb_interface *ifp = 0; + struct usb_driver *driver = 0; /* get input parameters and alloc buffer */ if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) @@ -1076,33 +1078,41 @@ } } - /* ioctl to device */ - if (ctrl.ifno < 0) { - switch (ctrl.ioctl_code) { - /* access/release token for issuing control messages - * ask a particular driver to bind/unbind, ... etc - */ - } - retval = -ENOSYS; + if (!ps->dev) + retval = -ENODEV; + else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + retval = -EINVAL; + else switch (ctrl.ioctl_code) { - /* ioctl to the driver which has claimed a given interface */ - } else { - struct usb_interface *ifp = 0; - if (!ps->dev) - retval = -ENODEV; - else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces) + /* disconnect kernel driver from interface, leaving it unbound. */ + case USBDEVFS_DISCONNECT: + driver = ifp->driver; + if (driver) { + down (&driver->serialize); + dbg ("disconnect '%s' from dev %d interface %d", + driver->name, ps->dev->devnum, ctrl.ifno); + driver->disconnect (ps->dev, ifp->private_data); + usb_driver_release_interface (driver, ifp); + up (&driver->serialize); + } else retval = -EINVAL; + break; + + /* let kernel drivers try to (re)bind to the interface */ + case USBDEVFS_CONNECT: + usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno); + break; + + /* talk directly to the interface's driver */ + default: + driver = ifp->driver; + if (driver == 0 || driver->ioctl == 0) + retval = -ENOSYS; else { - if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) - retval = -EINVAL; - else if (ifp->driver == 0 || ifp->driver->ioctl == 0) - retval = -ENOSYS; - } - if (retval == 0) { if (ifp->driver->owner) __MOD_INC_USE_COUNT(ifp->driver->owner); /* ifno might usefully be passed ... */ - retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf); + retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf); /* size = min_t(int, size, retval)? */ if (ifp->driver->owner) __MOD_DEC_USE_COUNT(ifp->driver->owner); diff -urN 2.5.7-clean/drivers/usb/usb.c linux/drivers/usb/usb.c --- 2.5.7-clean/drivers/usb/usb.c Mon Mar 18 15:37:16 2002 +++ linux/drivers/usb/usb.c Fri Mar 22 13:20:46 2002 @@ -196,6 +196,26 @@ usbfs_update_special(); } +/* + * usb_ifnum_to_ifpos - convert the interface _number_ (as in +interface.bInterfaceNumber) + * to the interface _position_ (as in dev->actconfig->interface + position) + * @dev: the device to use + * @ifnum: the interface number (bInterfaceNumber); not interface position + * + * Note that the number is the same as the position for all interfaces _except_ + * devices with interfaces not sequentially numbered (e.g., 0, 2, 3, etc). + */ +int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum) +{ + int i; + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) + if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == +ifnum) + return i; + + return -EINVAL; +} + /** * usb_ifnum_to_if - get the interface object with a given interface number * @dev: the device whose current configuration is considered @@ -570,6 +590,23 @@ return -1; } +/* + * usb_find_interface_driver_for_ifnum - convert ifnum to ifpos via + * usb_ifnum_to_ifpos and call usb_find_interface_driver(). + * @dev: the device to use + * @ifnum: the interface number (bInterfaceNumber); not interface position! + * + * Note usb_find_interface_driver's ifnum parameter is actually interface position. + */ +int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum) +{ + int ifpos = usb_ifnum_to_ifpos(dev, ifnum); + + if (0 > ifpos) + return -EINVAL; + + return usb_find_interface_driver(dev, ifpos); +} #ifdef CONFIG_HOTPLUG @@ -2623,6 +2660,7 @@ * into the kernel, and other device drivers are built as modules, * then these symbols need to be exported for the modules to use. */ +EXPORT_SYMBOL(usb_ifnum_to_ifpos); EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_epnum_to_ep_desc); @@ -2634,6 +2672,7 @@ EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_inc_dev_use); +EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum); EXPORT_SYMBOL(usb_driver_claim_interface); EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_driver_release_interface); diff -urN 2.5.7-clean/include/linux/usb.h linux/include/linux/usb.h --- 2.5.7-clean/include/linux/usb.h Mon Mar 18 15:37:13 2002 +++ linux/include/linux/usb.h Fri Mar 22 13:20:46 2002 @@ -305,6 +305,7 @@ } __attribute__ ((packed)); /* helpers for driver access to descriptors */ +extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum); extern struct usb_interface * usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); extern struct usb_endpoint_descriptor * @@ -1047,6 +1048,7 @@ #define usb_dec_dev_use usb_free_dev /* used these for multi-interface device registration */ +extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int +ifnum); extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv); extern int usb_interface_claimed(struct usb_interface *iface); diff -urN 2.5.7-clean/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- 2.5.7-clean/include/linux/usbdevice_fs.h Mon Mar 18 15:37:08 2002 +++ linux/include/linux/usbdevice_fs.h Fri Mar 22 13:20:46 2002 @@ -142,6 +142,8 @@ #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) #define USBDEVFS_RESET _IO('U', 20) #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) +#define USBDEVFS_DISCONNECT _IO('U', 22) +#define USBDEVFS_CONNECT _IO('U', 23) /* --------------------------------------------------------------------- */ _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel