Hi,

here's the version which should be correct and incorporates Greg's
suggestions. Now, does anybody on this list actually have a device with 
multiple configurations ?

        Regards
                Oliver

--- usb-2.5/drivers/usb/core/hub.c      2002-10-12 14:49:17.000000000 +0200
+++ con25/drivers/usb/core/hub.c        2002-10-11 15:37:49.000000000 +0200
@@ -1237,7 +1236,7 @@
                return 1;
        }
 
-       ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
+       ret = usb_physical_set_conf(dev, dev->actconfig->bConfigurationValue);
        if (ret < 0) {
                err("failed to set dev %s active configuration (error=%d)",
                        dev->devpath, ret);
--- usb-2.5/drivers/usb/core/message.c  2002-10-08 21:30:09.000000000 +0200
+++ con25/drivers/usb/core/message.c    2002-10-12 21:31:02.000000000 +0200
@@ -838,6 +838,54 @@
 }
 
 /**
+ * usb_physical_set_conf - send the actual message changing configuration
+ * @dev: the device whose configuration is being updated
+ * @configuration: the configuration being chosen.
+ * Context: !in_interrupt ()
+ *
+ * Caller must make sure that disconnect processing waits for this to 
complete
+ */
+static inline struct usb_config_descriptor *find_valid_config(struct 
usb_device *dev, int configuration)
+{
+       int i;
+
+       for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+               if (dev->config[i].bConfigurationValue == configuration) {
+                       return &dev->config[i];
+
+               }
+       }
+       
+       return NULL;
+}
+
+int usb_physical_set_conf(struct usb_device *dev, int configuration)
+{
+       int r;
+       struct usb_config_descriptor *cp;
+       
+       r = -EINVAL;
+       cp = find_valid_config(dev, configuration);
+       if (!cp)
+               goto err;
+
+       r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                               USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+                               NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+       if (r)
+               goto err;
+
+       dev->actconfig = cp;
+       dev->toggle[0] = 0;
+       dev->toggle[1] = 0;
+       usb_set_maxpacket(dev);
+
+err:
+       return r;
+
+}
+
+/**
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
  * @configuration: the configuration being chosen.
@@ -871,7 +919,7 @@
 {
        int i, ret;
        struct usb_config_descriptor *cp = NULL;
-       
+
        for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
                if (dev->config[i].bConfigurationValue == configuration) {
                        cp = &dev->config[i];
@@ -883,17 +931,28 @@
                return -EINVAL;
        }
 
-       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                       USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
-                       NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
-               return ret;
+       down(&dev->serialize);
 
-       dev->actconfig = cp;
-       dev->toggle[0] = 0;
-       dev->toggle[1] = 0;
-       usb_set_maxpacket(dev);
+       for (i = 0; i < USB_MAXCHILDREN; i++) {
+               struct usb_device **child = dev->children + i;
+               if (*child) {
+                       ret = -EBUSY;
+                       goto err; /* refuse if children were harmed */
+               }
+       }
+
+       usb_reap_interfaces(dev); /* get rid of all interfaces */
+
+       if ((ret = usb_physical_set_conf(dev, configuration)))
+               goto err;
+
+       dev->desired_conf = configuration; /* for pm */
+
+       ret = usb_register_interfaces(dev); /* reevaluate device */
 
-       return 0;
+err:
+       up(&dev->serialize);
+       return ret;
 }
 
 
--- usb-2.5/drivers/usb/core/usb.c      2002-10-12 14:49:17.000000000 +0200
+++ con25/drivers/usb/core/usb.c        2002-10-12 21:28:47.000000000 +0200
@@ -78,6 +75,7 @@
 {
        struct usb_interface * intf = to_usb_interface(dev);
        struct usb_driver * driver = to_usb_driver(dev->driver);
+       struct usb_device * udev =  interface_to_usbdev(intf);
        const struct usb_device_id *id;
        int error = -ENODEV;
        int m;
@@ -97,7 +95,9 @@
        if (id) {
                dbg ("%s - got id", __FUNCTION__);
                down (&driver->serialize);
+               down (&udev->serialize);
                error = driver->probe (intf, id);
+               up (&udev->serialize);
                up (&driver->serialize);
        }
        if (!error)
@@ -113,10 +113,12 @@
 {
        struct usb_interface *intf;
        struct usb_driver *driver;
+       struct usb_device *udev;
        int m;
 
        intf = list_entry(dev,struct usb_interface,dev);
        driver = to_usb_driver(dev->driver);
+       udev = interface_to_usbdev(intf);
 
        if (!driver) {
                err("%s does not have a valid driver to work with!",
@@ -135,10 +137,10 @@
        }
 
        /* if we sleep here on an umanaged driver 
-        * the holder of the lock guards against 
+        * the holder of the lock guards against
         * module unload */
        down(&driver->serialize);
-
+       down(&udev->serialize);
        if (intf->driver && intf->driver->disconnect)
                intf->driver->disconnect(intf);
 
@@ -146,6 +148,7 @@
        if (intf->driver)
                usb_driver_release_interface(driver, intf);
 
+       up(&udev->serialize);
        up(&driver->serialize);
        if (driver->owner)
                __MOD_DEC_USE_COUNT(driver->owner);
@@ -759,6 +767,26 @@
        return -1;
 }
 
+/** usb_reap_interfaces - disconnect all interfaces of a usb device
+ *  @dev: pointer to the device whose interfaces shall be disconnected
+ *  Context: !in_interrupt ()
+ *
+ *  Getting rid of interfaces associated with drivers.
+ *  This is for physical disconnection and configuration changes
+ */
+void usb_reap_interfaces(struct usb_device *dev)
+{
+       int i;
+
+       if (dev->actconfig) {
+               for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+                       struct usb_interface *interface = 
+&dev->actconfig->interface[i];
+
+                       /* remove this interface */
+                       device_unregister(&interface->dev);
+               }
+       }
+}
 /**
  * usb_disconnect - disconnect a device (usbcore-internal)
  * @pdev: pointer to device being disconnected
@@ -790,20 +818,13 @@
                        usb_disconnect(child);
        }
 
-       if (dev->actconfig) {
-               for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
-                       struct usb_interface *interface = 
&dev->actconfig->interface[i];
-
-                       /* remove this interface */
-                       device_unregister(&interface->dev);
-               }
-       }
+       usb_reap_interfaces(dev);
 
        /* Free the device number and remove the /proc/bus/usb entry */
        if (dev->devnum > 0) {
                clear_bit(dev->devnum, dev->bus->devmap.devicemap);
                usbfs_remove_device(dev);
@@ -921,6 +942,50 @@
 }
 
 /*
+ * This registers a device's interfaces with the generic device layer
+ *
+ * for new devices or configuration changes
+ */
+int usb_register_interfaces(struct usb_device *dev)
+{
+       int i;
+       
+       /* Register all of the interfaces for this device with the driver core.
+        * Remember, interfaces get bound to drivers, not devices. */
+       for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+               struct usb_interface *interface = &dev->actconfig->interface[i];
+               struct usb_interface_descriptor *desc = interface->altsetting;
+
+               interface->dev.parent = &dev->dev;
+               interface->dev.driver = NULL;
+               interface->dev.bus = &usb_bus_type;
+               sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
+                        dev->bus->busnum, dev->devpath,
+                        interface->altsetting->bInterfaceNumber);
+               if (!desc->iInterface
+                               || usb_string (dev, desc->iInterface,
+                                       interface->dev.name,
+                                       sizeof interface->dev.name) <= 0) {
+                       /* typically devices won't bother with interface
+                        * descriptions; this is the normal case.  an
+                        * interface's driver might describe it better.
+                        * (also: iInterface is per-altsetting ...)
+                        */
+                       sprintf (&interface->dev.name[0],
+                               "usb-%s-%s interface %d",
+                               dev->bus->bus_name, dev->devpath,
+                               interface->altsetting->bInterfaceNumber);
+               }
+               dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
+               device_register (&interface->dev);
+               usb_create_driverfs_intf_files (interface);
+       }
+       
+       return 0;
+}
+
+
+/*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
  * get the ball rolling..
@@ -1006,7 +1071,7 @@
        }
 
        /* we set the default configuration here */
-       err = usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+       err = usb_physical_set_conf(dev, dev->config[0].bConfigurationValue);
        if (err) {
                err("failed to set device %d default configuration (error=%d)",
                        dev->devnum, err);
@@ -1042,37 +1107,11 @@
 
        /* add the USB device specific driverfs files */
        usb_create_driverfs_dev_files (dev);
-
-       /* Register all of the interfaces for this device with the driver core.
-        * Remember, interfaces get bound to drivers, not devices. */
-       for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
-               struct usb_interface *interface = &dev->actconfig->interface[i];
-               struct usb_interface_descriptor *desc = interface->altsetting;
-
-               interface->dev.parent = &dev->dev;
-               interface->dev.driver = NULL;
-               interface->dev.bus = &usb_bus_type;
-               sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
-                        dev->bus->busnum, dev->devpath,
-                        interface->altsetting->bInterfaceNumber);
-               if (!desc->iInterface
-                               || usb_string (dev, desc->iInterface,
-                                       interface->dev.name,
-                                       sizeof interface->dev.name) <= 0) {
-                       /* typically devices won't bother with interface
-                        * descriptions; this is the normal case.  an
-                        * interface's driver might describe it better.
-                        * (also: iInterface is per-altsetting ...)
-                        */
-                       sprintf (&interface->dev.name[0],
-                               "usb-%s-%s interface %d",
-                               dev->bus->bus_name, dev->devpath,
-                               interface->altsetting->bInterfaceNumber);
-               }
-               dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
-               device_register (&interface->dev);
-               usb_create_driverfs_intf_files (interface);
-       }
+       
+       err = usb_register_interfaces(dev);
+       
+       if (err)
+               return err;
 
        /* add a /proc/bus/usb entry */
        usbfs_add_device(dev);
--- usb-2.5/include/linux/usb.h 2002-10-12 14:49:19.000000000 +0200
+++ con25/include/linux/usb.h   2002-10-12 21:32:23.000000000 +0200
@@ -375,6 +375,7 @@
 
        int have_langid;                /* whether string_langid is valid yet */
        int string_langid;              /* language ID for strings */
+       int desired_conf;               /* configuration to restore on resume */
 
        void *hcpriv;                   /* Host Controller private data */
        
@@ -1033,6 +1033,9 @@
                struct scatterlist *sg, int n_hw_ents);
 void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
                struct scatterlist *sg, int n_hw_ents);
+void usb_reap_interfaces(struct usb_device *dev);
+int usb_physical_set_conf(struct usb_device *dev, int configuration);
+int usb_register_interfaces(struct usb_device *dev);
 
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to