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