On Mon, 22 Oct 2001, David Brownell wrote:

>> Someone proposed an ioctl() some time ago to force a kernel-module to
>> release an interface, but I never saw it implemented.
>
>It was implemented, and I hope to dust off the patch this week.  Check
>list archives for January.

The original posting is here:

http://marc.theaimsgroup.com/?l=linux-usb-devel&m=98002097701710&w=2

and below is the patch updated to 2.4.12, with additions.  Dave, since
this is your patch, you may want to update it differently or at least
check the patch below, however see below...

One important change/addition is the fact that the user-supplied
ifnum needs to be the actual interface number, not the interface
position, which is only the same as the number for devices
with sequentially numbered interfaces.

So, I changed devio.proc_ioctl() to use the interface number (not
position); left usb_find_interface_driver() unchanged; and
added a (exported) function usb_find_interface_driver_for_ifnum(),
which just converts and calls the static function.

Patch below.


diff -urN 2.4.12-clean/drivers/usb/devio.c linux/drivers/usb/devio.c
--- 2.4.12-clean/drivers/usb/devio.c    Mon Sep 10 11:06:32 2001
+++ linux/drivers/usb/devio.c   Mon Oct 22 18:43:58 2001
@@ -1040,6 +1040,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)))
@@ -1057,32 +1059,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)
                        /* 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 2.4.12-clean/drivers/usb/usb.c linux/drivers/usb/usb.c
--- 2.4.12-clean/drivers/usb/usb.c      Tue Oct  9 18:15:02 2001
+++ linux/drivers/usb/usb.c     Mon Oct 22 19:24:09 2001
@@ -193,6 +193,17 @@
        read_unlock_irq (&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;
@@ -682,9 +693,12 @@
  * the drivers don't have to dig around in our structures to set the
  * private pointer if they only need one interface.
  *
+ * Note that the parameter ifpos is the position, not number, of the interface.
+ * See usb_find_interface_driver_for_ifnum() for details.
+ *
  * Returns: 0 if a driver accepted the interface, -1 otherwise
  */
-static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
+static int usb_find_interface_driver(struct usb_device *dev, unsigned ifpos)
 {
        struct list_head *tmp;
        struct usb_interface *interface;
@@ -693,14 +707,14 @@
        struct usb_driver *driver;
        int i;

-       if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
+       if ((!dev) || (ifpos >= dev->actconfig->bNumInterfaces)) {
                err("bad find_interface_driver params");
                return -1;
        }

        down(&dev->serialize);

-       interface = dev->actconfig->interface + ifnum;
+       interface = dev->actconfig->interface + ifpos;

        if (usb_interface_claimed(interface))
                goto out_err;
@@ -718,7 +732,7 @@
                                id = usb_match_id(dev, interface, id);
                                if (id) {
                                        down(&driver->serialize);
-                                       private = driver->probe(dev,ifnum,id);
+                                       private = driver->probe(dev,ifpos,id);
                                        up(&driver->serialize);
                                        if (private != NULL)
                                                break;
@@ -730,12 +744,12 @@
                                interface->act_altsetting = 0;
                } else { /* "old style" driver */
                        down(&driver->serialize);
-                       private = driver->probe(dev, ifnum, NULL);
+                       private = driver->probe(dev, ifpos, NULL);
                        up(&driver->serialize);
                }

                /* probe() may have changed the config on us */
-               interface = dev->actconfig->interface + ifnum;
+               interface = dev->actconfig->interface + ifpos;

                if (private) {
                        usb_driver_claim_interface(driver, interface, private);
@@ -749,6 +763,23 @@
        return -1;
 }

+/*
+ * This simply converts the interface _number_ (as in interface.bInterfaceNumber)
+ * 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

@@ -2358,6 +2389,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);

@@ -2372,6 +2404,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.4.12-clean/include/linux/usb.h linux/include/linux/usb.h
--- 2.4.12-clean/include/linux/usb.h    Thu Oct 11 02:47:25 2001
+++ linux/include/linux/usb.h   Mon Oct 22 18:46:02 2001
@@ -645,6 +645,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);

@@ -653,6 +654,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 2.4.12-clean/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h
--- 2.4.12-clean/include/linux/usbdevice_fs.h   Thu Oct 11 02:47:51 2001
+++ linux/include/linux/usbdevice_fs.h  Mon Oct 22 13:59:53 2001
@@ -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

Reply via email to