This takes all of the feedback I got back about the first patch. Changes
since the first patch:

- updated to 2.4.0-test1-ac18. only significant change was the ioctl number
  has changed
- Simulate disconnect() and probe() on all interfaces not claimed by the
  calling process in ioctl()
- Only set_configuration() and set_interface() if the device descriptor
  hasn't changed. Otherwise, it dumps the configs and rereads them
- More comments

Any other changes someone can think of?

JE

diff -ur linux-2.4.0-test1-ac18.orig/drivers/usb/devio.c 
linux-2.4.0-test1-ac18/drivers/usb/devio.c
--- linux-2.4.0-test1-ac18.orig/drivers/usb/devio.c     Wed Jun 14 19:23:42 2000
+++ linux-2.4.0-test1-ac18/drivers/usb/devio.c  Wed Jun 14 19:25:09 2000
@@ -744,6 +744,32 @@
        return 0;
 }
 
+static int proc_resetdevice(struct dev_state *ps)
+{
+       int i, ret;
+
+       ret = usb_reset_device(ps->dev);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ps->dev->actconfig->bNumInterfaces; i++) {
+               struct usb_interface *intf = &ps->dev->actconfig->interface[i];
+
+               /* Don't simulate interfaces we've claimed */
+               if (test_bit(i, &ps->ifclaimed))
+                       continue;
+
+               if (intf->driver) {
+                       down(&intf->driver->serialize);
+                       intf->driver->disconnect(ps->dev, intf->private_data);
+                       intf->driver->probe(ps->dev, i);
+                       up(&intf->driver->serialize);
+               }
+       }
+
+       return 0;
+}
+
 static int proc_setintf(struct dev_state *ps, void *arg)
 {
        struct usbdevfs_setinterface setintf;
@@ -1089,6 +1115,10 @@
                ret = proc_resetep(ps, (void *)arg);
                if (ret >= 0)
                        inode->i_mtime = CURRENT_TIME;
+               break;
+
+       case USBDEVFS_RESET:
+               ret = proc_resetdevice(ps);
                break;
 
        case USBDEVFS_GETDRIVER:
--- linux-2.4.0-test1-ac18.orig/include/linux/usbdevice_fs.h    Wed Jun 14 19:23:49 
2000
+++ linux-2.4.0-test1-ac18/include/linux/usbdevice_fs.h Wed Jun 14 19:39:11 2000
@@ -108,6 +108,7 @@
        struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
+/* ioctls for talking to drivers in the usbcore module: */
 struct usbdevfs_ioctl {
        int     ifno;           /* interface 0..N ; negative numbers reserved */
        int     ioctl_code;     /* MUST encode size + direction of data so the
@@ -115,6 +116,13 @@
        void    *data;          /* param buffer (in, or out) */
 };
 
+/* You can do most things with hubs just through control messages,
+ * except find out what device connects to what port. */
+struct usbdevfs_hub_portinfo {
+       char nports;            /* number of downstream ports in this hub */
+       char port [127];        /* e.g. port 3 connects to device 27 */
+};
+
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
@@ -130,19 +138,8 @@
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
 #define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
 #define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
-
-/* --------------------------------------------------------------------- */
-
-/* ioctls for talking to drivers in the usbcore module: */
-
-/* You can do most things with hubs just through control messages,
- * except find out what device connects to what port. */
-struct usbdevfs_hub_portinfo {
-       char nports;            /* number of downstream ports in this hub */
-       char port [127];        /* e.g. port 3 connects to device 27 */
-};
-#define USBDEVFS_HUB_PORTINFO     _IOR('U', 19, struct usbdevfs_hub_portinfo)
-
+#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
+#define USBDEVFS_RESET             _IO('U', 20)
 
 /* --------------------------------------------------------------------- */
 
--- linux-2.4.0-test1-ac18.orig/drivers/usb/hub.c       Wed Jun 14 19:23:42 2000
+++ linux-2.4.0-test1-ac18/drivers/usb/hub.c    Wed Jun 14 19:49:31 2000
@@ -20,6 +20,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 
+#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -27,6 +28,7 @@
 
 /* Wakes up khubd */
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(usb_address0_sem);
 
 static LIST_HEAD(hub_event_list);      /* List of hubs needing servicing */
 static LIST_HEAD(hub_list);            /* List containing all of the hubs (for 
cleanup) */
@@ -398,19 +400,20 @@
                if (!(portstatus & USB_PORT_STAT_CONNECTION))
                        return;
        }
-       wait_ms(400);   
+       wait_ms(400);
 
-#define MAX_TRIES 5
+       down(&usb_address0_sem);
 
+#define MAX_TRIES 5
        /* Reset the port */
        for (tries = 0; tries < MAX_TRIES ; tries++) {
                usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
-               wait_ms(200);   
+               wait_ms(200);
 
                ret = usb_get_port_status(hub, port + 1, &portsts);
                if (ret < 0) {
                        err("get_port_status(%d) failed (err = %d)", port + 1, ret);
-                       return;
+                       goto out;
                }
 
                portstatus = le16_to_cpu(portsts.wPortStatus);
@@ -420,7 +423,7 @@
 
                if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
                    !(portstatus & USB_PORT_STAT_CONNECTION))
-                       return;
+                       goto out;
 
                if (portstatus & USB_PORT_STAT_ENABLE)
                        break;
@@ -431,7 +434,7 @@
        if (tries >= MAX_TRIES) {
                err("Cannot enable port %i after %i retries, disabling port.", port+1, 
MAX_TRIES);
                err("Maybe the USB cable is bad?");
-               return;
+               goto out;
        }
 
        usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
@@ -440,7 +443,7 @@
        usb = usb_alloc_dev(hub, hub->bus);
        if (!usb) {
                err("couldn't allocate usb_device");
-               return;
+               goto out;
        }
 
        usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
@@ -467,6 +470,9 @@
                                USB_PORT_FEAT_ENABLE);
                }
        }
+
+out:
+       up(&usb_address0_sem);
 }
 
 static void usb_hub_events(void)
@@ -577,10 +583,6 @@
 
 static int usb_hub_thread(void *__hub)
 {
-/*
-       MOD_INC_USE_COUNT;
-*/
-       
        khubd_running = 1;
 
        lock_kernel();
@@ -601,10 +603,6 @@
                interruptible_sleep_on(&khubd_wait);
        } while (!signal_pending(current));
 
-/*
-       MOD_DEC_USE_COUNT;
-*/
-
        dbg("usb_hub_thread exiting");
        khubd_running = 0;
 
@@ -673,28 +671,130 @@
        usb_deregister(&hub_driver);
 } /* usb_hub_cleanup() */
 
+/*
+ * WARNING - If a driver calls usb_reset_device, you should simulate a
+ * disconnect() and probe() for other interfaces you doesn't claim. This
+ * is left up to the driver writer right now. This insures other drivers
+ * have a chance to re-setup their interface.
+ *
+ * Take a look at proc_resetdevice in devio.c for some sample code to
+ * do this.
+ */
 int usb_reset_device(struct usb_device *dev)
 {
        struct usb_device *parent = dev->parent;
-       int i;
+       struct usb_device_descriptor descriptor;
+       int i, ret, port = -1;
 
        if (!parent) {
                err("attempting to reset root hub!");
                return -EINVAL;
        }
 
-       for (i = 0; i < parent->maxchild; i++) {
+       for (i = 0; i < parent->maxchild; i++)
                if (parent->children[i] == dev) {
-                       usb_set_port_feature(parent, i + 1,
-                               USB_PORT_FEAT_RESET);
+                       port = i;
+                       break;
+               }
+
+       if (port < 0)
+               return -ENOENT;
+
+       down(&usb_address0_sem);
+
+       /* Send a reset to the device */
+       usb_set_port_feature(parent, port + 1, USB_PORT_FEAT_RESET);
+
+       wait_ms(200);
 
-                       usb_disconnect(&dev);
-                       usb_hub_port_connect_change(parent, i);
+       usb_clear_port_feature(parent, port + 1, USB_PORT_FEAT_C_RESET);
 
-                       return 0;
+       /* Reprogram the Address */
+       ret = usb_set_address(dev);
+       if (ret < 0) {
+               err("USB device not accepting new address (error=%d)", ret);
+               clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               up(&usb_address0_sem);
+               return ret;
+       }
+
+       wait_ms(10);    /* Let the SET_ADDRESS settle */
+
+       up(&usb_address0_sem);
+
+       /*
+        * Now we fetch the configuration descriptors for the device and
+        * see if anything has changed. If it has, we dump the current
+        * parsed descriptors and reparse from scratch. Then we leave
+        * the device alone for the caller to finish setting up.
+        *
+        * If nothing changed, we reprogram the configuration and then
+        * the alternate settings.
+        */
+       ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
+                       sizeof(descriptor));
+       if (ret < 0)
+               return ret;
+
+       le16_to_cpus(&descriptor.bcdUSB);
+       le16_to_cpus(&descriptor.idVendor);
+       le16_to_cpus(&descriptor.idProduct);
+       le16_to_cpus(&descriptor.bcdDevice);
+
+       if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+               usb_destroy_configuration(dev);
+
+               ret = usb_get_device_descriptor(dev);
+               if (ret < sizeof(dev->descriptor)) {
+                       if (ret < 0)
+                               err("unable to get device descriptor (error=%d)", ret);
+                       else
+                               err("USB device descriptor short read (expected %i, 
+got %i)", sizeof(dev->descriptor), ret);
+        
+                       clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+                       dev->devnum = -1;
+                       return -EIO;
+               }
+
+               ret = usb_get_configuration(dev);
+               if (ret < 0) {
+                       err("unable to get configuration (error=%d)", ret);
+                       clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+                       dev->devnum = -1;
+                       return 1;
                }
+
+               dev->actconfig = dev->config;
+               usb_set_maxpacket(dev);
+
+               return 1;
+       } else {
+               ret = usb_set_configuration(dev,
+                       dev->actconfig->bConfigurationValue);
+               if (ret < 0) {
+                       err("failed to set active configuration (error=%d)",
+                               ret);
+                       return ret;
+               }
+
+               for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+                       struct usb_interface *intf =
+                               &dev->actconfig->interface[i];
+                       struct usb_interface_descriptor *as =
+                               &intf->altsetting[intf->act_altsetting];
+
+                       ret = usb_set_interface(dev, as->bInterfaceNumber,
+                               as->bAlternateSetting);
+                       if (ret < 0) {
+                               err("failed to set active alternate setting for 
+interface %d (error=%d)", i, ret);
+                               return ret;
+                       }
+               }
+
+               return 0;
        }
 
-       return -ENOENT;
+       return 0;
 }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to