Hi all,

here is a backport of the usbfs 'disconnect' functionality.  The only 
difference I know of from the 2.5 code is this doesn't use the kernel 
lock.  I'm not sure if that is really needed?  Anyway it would be great to 
finally get this into 2.4...


diff -urN linux-2.4.18-3/drivers/usb/devio.c linux/drivers/usb/devio.c
--- linux-2.4.18-3/drivers/usb/devio.c  2001-11-02 20:18:58.000000000 -0500
+++ linux/drivers/usb/devio.c   2002-08-19 12:49:38.000000000 -0400
@@ -1048,6 +1052,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)))
@@ -1065,32 +1071,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;
-
-       /* 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)
-                       retval = -EINVAL;
+       if (!ps->dev)
+               retval = -ENODEV;
+       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+               retval = -EINVAL;
+       else switch (ctrl.ioctl_code) {
+
+       /* 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
+                       return -ENODATA;
+               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)
                        /* 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)? */
+               }
        }
 
        /* cleanup and return */
diff -urN linux-2.4.18-3/drivers/usb/usb.c linux/drivers/usb/usb.c
--- linux-2.4.18-3/drivers/usb/usb.c    2002-02-25 14:38:07.000000000 -0500
+++ linux/drivers/usb/usb.c     2002-08-19 12:49:38.000000000 -0400
@@ -193,6 +193,17 @@
        up (&usb_bus_list_lock);
 }
 
+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;
+}
+
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
 {
        int i;
@@ -749,6 +760,23 @@
        return -1;
 }
 
+/*
+ * This simply converts the interface _number_ (as in interface.bInterfaceNumber) and
+ * converts it to the interface _position_ (as in dev->actconfig->interface + 
position)
+ * and calls usb_find_interface_driver().
+ *
+ * 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_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
 
@@ -2367,6 +2395,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);
 
@@ -2381,6 +2410,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 linux-2.4.18-3/include/linux/usb.h linux/include/linux/usb.h
--- linux-2.4.18-3/include/linux/usb.h  2002-04-18 07:33:38.000000000 -0400
+++ linux/include/linux/usb.h   2002-08-21 14:20:19.000000000 -0400
@@ -808,6 +808,7 @@
        struct usb_device *children[USB_MAXCHILDREN];
 };
 
+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 *usb_epnum_to_ep_desc(struct usb_device *dev, 
unsigned epnum);
 
@@ -816,6 +817,7 @@
 extern void usb_scan_devices(void);
 
 /* 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);
 extern void usb_driver_release_interface(struct usb_driver *driver, struct 
usb_interface *iface);
diff -urN linux-2.4.18-3/include/linux/usbdevice_fs.h 
linux/include/linux/usbdevice_fs.h
--- linux-2.4.18-3/include/linux/usbdevice_fs.h 2002-04-18 07:38:09.000000000 -0400
+++ linux/include/linux/usbdevice_fs.h  2002-08-21 14:47:32.000000000 -0400
@@ -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)
 
 /* --------------------------------------------------------------------- */
 


-------------------------------------------------------
This SF.net email is sponsored by: VM Ware
With VMware you can run multiple operating systems on a single machine.
WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines
at the same time. Free trial click here:http://www.vmware.com/wl/offer/358/0
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to