Greg:

This patch (as714) makes the USB device (as opposed to interface) driver
usb_generic be treated just like all other drivers, subject to matching,
probing, and unbinding.  For instance, some of the normal boilerplate
stuff that goes along with discovery of a new USB device (registration in
usbfs, creation of the sysfs attribute files, and selection of an initial
configuration) is moved into the probe routine, where any normal driver 
would put it.

This change isn't particularly important for now -- other than in an
organizational sense -- but it opens the door to having alternate USB
device drivers.  The examples that spring to mind are when a host exports
a USB device over the network or to a virtual guest operating system.  In
each case, the device shouldn't show up as a normal USB device on the host
but rather on the client/guest.  This could be accomplished by binding the
host's device to a different driver.  If this was done for a root hub, an
entire USB device tree could automatically be exported!

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

---

Index: usb-2.6/drivers/usb/core/driver.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/driver.c
+++ usb-2.6/drivers/usb/core/driver.c
@@ -15,10 +15,6 @@
  *             (usb_device_id matching changes by Adam J. Richter)
  *     (C) Copyright Greg Kroah-Hartman 2002-2003
  *
- * NOTE! This is not actually a driver at all, rather this is
- * just a collection of helper routines that implement the
- * generic USB things that the real drivers can use..
- *
  */
 
 #include <linux/config.h>
@@ -27,37 +23,223 @@
 #include "hcd.h"
 #include "usb.h"
 
-static int generic_probe(struct device *dev)
+static inline const char *plural(int n)
 {
+       return (n == 1 ? "" : "s");
+}
+
+static int choose_configuration(struct usb_device *udev)
+{
+       int i;
+       int num_configs;
+       int insufficient_power = 0;
+       struct usb_host_config *c, *best;
+
+       best = NULL;
+       c = udev->config;
+       num_configs = udev->descriptor.bNumConfigurations;
+       for (i = 0; i < num_configs; (i++, c++)) {
+               struct usb_interface_descriptor *desc = NULL;
+
+               /* It's possible that a config has no interfaces! */
+               if (c->desc.bNumInterfaces > 0)
+                       desc = &c->intf_cache[0]->altsetting->desc;
+
+               /*
+                * HP's USB bus-powered keyboard has only one configuration
+                * and it claims to be self-powered; other devices may have
+                * similar errors in their descriptors.  If the next test
+                * were allowed to execute, such configurations would always
+                * be rejected and the devices would not work as expected.
+                * In the meantime, we run the risk of selecting a config
+                * that requires external power at a time when that power
+                * isn't available.  It seems to be the lesser of two evils.
+                *
+                * Bugzilla #6448 reports a device that appears to crash
+                * when it receives a GET_DEVICE_STATUS request!  We don't
+                * have any other way to tell whether a device is self-powered,
+                * but since we don't use that information anywhere but here,
+                * the call has been removed.
+                *
+                * Maybe the GET_DEVICE_STATUS call and the test below can
+                * be reinstated when device firmwares become more reliable.
+                * Don't hold your breath.
+                */
+#if 0
+               /* Rule out self-powered configs for a bus-powered device */
+               if (bus_powered && (c->desc.bmAttributes &
+                                       USB_CONFIG_ATT_SELFPOWER))
+                       continue;
+#endif
+
+               /*
+                * The next test may not be as effective as it should be.
+                * Some hubs have errors in their descriptor, claiming
+                * to be self-powered when they are really bus-powered.
+                * We will overestimate the amount of current such hubs
+                * make available for each port.
+                *
+                * This is a fairly benign sort of failure.  It won't
+                * cause us to reject configurations that we should have
+                * accepted.
+                */
+
+               /* Rule out configs that draw too much bus current */
+               if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+                       insufficient_power++;
+                       continue;
+               }
+
+               /* If the first config's first interface is COMM/2/0xff
+                * (MSFT RNDIS), rule it out unless Linux has host-side
+                * RNDIS support. */
+               if (i == 0 && desc
+                               && desc->bInterfaceClass == USB_CLASS_COMM
+                               && desc->bInterfaceSubClass == 2
+                               && desc->bInterfaceProtocol == 0xff) {
+#ifndef CONFIG_USB_NET_RNDIS_HOST
+                       continue;
+#else
+                       best = c;
+#endif
+               }
+
+               /* From the remaining configs, choose the first one whose
+                * first interface is for a non-vendor-specific class.
+                * Reason: Linux is more likely to have a class driver
+                * than a vendor-specific driver. */
+               else if (udev->descriptor.bDeviceClass !=
+                                               USB_CLASS_VENDOR_SPEC &&
+                               (!desc || desc->bInterfaceClass !=
+                                               USB_CLASS_VENDOR_SPEC)) {
+                       best = c;
+                       break;
+               }
+
+               /* If all the remaining configs are vendor-specific,
+                * choose the first one. */
+               else if (!best)
+                       best = c;
+       }
+
+       if (insufficient_power > 0)
+               dev_info(&udev->dev, "rejected %d configuration%s "
+                       "due to insufficient available bus power\n",
+                       insufficient_power, plural(insufficient_power));
+
+       if (best) {
+               i = best->desc.bConfigurationValue;
+               dev_info(&udev->dev,
+                       "configuration #%d chosen from %d choice%s\n",
+                       i, num_configs, plural(num_configs));
+       } else {
+               i = -1;
+               dev_warn(&udev->dev,
+                       "no configuration chosen from %d choice%s\n",
+                       num_configs, plural(num_configs));
+       }
+       return i;
+}
+
+static int generic_probe(struct usb_interface *_udev,
+               const struct usb_device_id *unused)
+{
+       struct usb_device *udev = (struct usb_device *) _udev;
+       int err, c;
+
+       /* put device-specific files into sysfs */
+       usb_create_sysfs_dev_files(udev);
+
+       /* Choose and set the configuration.  This registers the interfaces
+        * with the driver core and lets interface drivers bind to them.
+        */
+       c = choose_configuration(udev);
+       if (c >= 0) {
+               err = usb_set_configuration(udev, c);
+               if (err) {
+                       dev_err(&udev->dev, "can't set config #%d, error %d\n",
+                                       c, err);
+                       /* This need not be fatal.  The user can try to
+                        * set other configurations. */
+               }
+       }
+
+       /* USB device state == configured ... usable */
+       usb_notify_add_device(udev);
+
        return 0;
 }
-static int generic_remove(struct device *dev)
+
+static void generic_disconnect(struct usb_interface *_udev)
 {
-       struct usb_device *udev = to_usb_device(dev);
+       struct usb_device *udev = (struct usb_device *) _udev;
+
+       usb_notify_remove_device(udev);
 
        /* if this is only an unbind, not a physical disconnect, then
         * unconfigure the device */
        if (udev->state == USB_STATE_CONFIGURED)
                usb_set_configuration(udev, 0);
 
+       usb_remove_sysfs_dev_files(udev);
+
        /* in case the call failed or the device was suspended */
        if (udev->state >= USB_STATE_CONFIGURED)
                usb_disable_device(udev, 0);
-       return 0;
 }
 
-struct device_driver usb_generic_driver = {
-       .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+
+static int verify_suspended(struct device *dev, void *unused)
+{
+       return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
+}
+
+static int generic_suspend(struct usb_interface *_udev, pm_message_t msg)
+{
+       struct usb_device *udev = (struct usb_device *) _udev;
+       int status;
+
+       /* rule out bogus requests through sysfs */
+       status = device_for_each_child(&udev->dev, NULL, verify_suspended);
+       if (status)
+               return status;
+
+       /* USB devices enter SUSPEND state through their hubs, but can be
+        * marked for FREEZE as soon as their children are already idled.
+        * But those semantics are useless, so we equate the two (sigh).
+        */
+       return usb_suspend_device(udev);
+}
+
+static int generic_resume(struct usb_interface *_udev)
+{
+       struct usb_device *udev = (struct usb_device *) _udev;
+
+       if (udev->state == USB_STATE_NOTATTACHED)
+               return 0;
+
+       return usb_resume_device(udev);
+}
+
+#endif /* CONFIG_PM */
+
+static struct usb_device_id generic_ids [] = {
+       { }
+};
+
+struct usb_driver usb_generic_driver = {
        .name = "usb",
-       .bus = &usb_bus_type,
        .probe = generic_probe,
-       .remove = generic_remove,
+       .disconnect = generic_disconnect,
+#ifdef CONFIG_PM
+       .suspend = generic_suspend,
+       .resume = generic_resume,
+#endif
+       .id_table = generic_ids,
+       .for_devices = 1,
 };
 
-/* Fun hack to determine if the struct device is a
- * usb device or a usb interface. */
-int usb_generic_driver_data;
-
 #ifdef CONFIG_HOTPLUG
 
 /*
@@ -176,11 +358,50 @@ static const struct usb_device_id *usb_m
 }
 
 
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
+static int usb_probe_device(struct device *dev)
+{
+       struct usb_driver *driver = to_usb_driver(dev->driver);
+       struct usb_device *udev;
+       int error = -ENODEV;
+
+       dev_dbg(dev, "%s\n", __FUNCTION__);
+
+       if (!driver->probe)
+               return error;
+       if (!is_usb_device(dev))        /* Sanity check */
+               return error;
+
+       udev = to_usb_device(dev);
+
+       /* FIXME: resume a suspended device */
+       if (udev->state == USB_STATE_SUSPENDED)
+               return -EHOSTUNREACH;
+
+       /* TODO: Add real matching code */
+
+       /* the typecast is unavoidable :-( */
+       error = driver->probe((struct usb_interface *) udev, NULL);
+       return error;
+}
+
+/* called from driver core with dev locked */
+static int usb_unbind_device(struct device *dev)
+{
+       struct usb_driver *driver = to_usb_driver(dev->driver);
+
+       if (driver->disconnect)
+               driver->disconnect((struct usb_interface *)
+                               to_usb_device(dev));
+       return 0;
+}
+
+
+/* called from driver core with dev locked */
 static int usb_probe_interface(struct device *dev)
 {
-       struct usb_interface * intf = to_usb_interface(dev);
-       struct usb_driver * driver = to_usb_driver(dev->driver);
+       struct usb_driver *driver = to_usb_driver(dev->driver);
+       struct usb_interface *intf;
        const struct usb_device_id *id;
        int error = -ENODEV;
 
@@ -188,6 +409,11 @@ static int usb_probe_interface(struct de
 
        if (!driver->probe)
                return error;
+       if (is_usb_device(dev))         /* Sanity check */
+               return error;
+
+       intf = to_usb_interface(dev);
+
        /* FIXME we'd much prefer to just resume it ... */
        if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
                return -EHOSTUNREACH;
@@ -215,18 +441,20 @@ static int usb_probe_interface(struct de
        return error;
 }
 
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
 static int usb_unbind_interface(struct device *dev)
 {
-       struct usb_interface *intf = to_usb_interface(dev);
-       struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+       struct usb_driver *driver = to_usb_driver(dev->driver);
+       struct usb_interface *intf;
+
+       intf = to_usb_interface(dev);
 
        intf->condition = USB_INTERFACE_UNBINDING;
 
        /* release all urbs for this interface */
        usb_disable_interface(interface_to_usbdev(intf), intf);
 
-       if (driver && driver->disconnect)
+       if (driver->disconnect)
                driver->disconnect(intf);
 
        /* reset other interface state */
@@ -468,24 +696,36 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
 
 int usb_device_match(struct device *dev, struct device_driver *drv)
 {
+       struct usb_driver *usb_drv = to_usb_driver(drv);
        struct usb_interface *intf;
-       struct usb_driver *usb_drv;
        const struct usb_device_id *id;
 
-       /* check for generic driver, which we don't match any device with */
-       if (drv == &usb_generic_driver)
-               return 0;
+       /* devices and interfaces are handled separately */
+       if (is_usb_device(dev)) {
 
-       intf = to_usb_interface(dev);
-       usb_drv = to_usb_driver(drv);
+               /* interface drivers never match devices */
+               if (!usb_drv->for_devices)
+                       return 0;
 
-       id = usb_match_id(intf, usb_drv->id_table);
-       if (id)
+               /* TODO: Add real matching code */
                return 1;
 
-       id = usb_match_dynamic_id(intf, usb_drv);
-       if (id)
-               return 1;
+       } else {
+
+               /* device drivers never match interfaces */
+               if (usb_drv->for_devices)
+                       return 0;
+
+               intf = to_usb_interface(dev);
+
+               id = usb_match_id(intf, usb_drv->id_table);
+               if (id)
+                       return 1;
+
+               id = usb_match_dynamic_id(intf, usb_drv);
+               if (id)
+                       return 1;
+       }
        return 0;
 }
 
@@ -516,14 +756,14 @@ static int usb_uevent(struct device *dev
        /* driver is often null here; dev_dbg() would oops */
        pr_debug ("usb %s: uevent\n", dev->bus_id);
 
-       /* Must check driver_data here, as on remove driver is always NULL */
-       if ((dev->driver == &usb_generic_driver) || 
-           (dev->driver_data == &usb_generic_driver_data))
-               return 0;
-
-       intf = to_usb_interface(dev);
-       usb_dev = interface_to_usbdev (intf);
-       alt = intf->cur_altsetting;
+       if (is_usb_device(dev)) {
+               usb_dev = to_usb_device(dev);
+               alt = NULL;
+       } else {
+               intf = to_usb_interface(dev);
+               usb_dev = interface_to_usbdev (intf);
+               alt = intf->cur_altsetting;
+       }
 
        if (usb_dev->devnum < 0) {
                pr_debug ("usb %s: already deleted?\n", dev->bus_id);
@@ -566,15 +806,22 @@ static int usb_uevent(struct device *dev
                           usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
+       if (is_usb_device(dev)) {
+
+               /* FIXME: What is an appropriate MODALIAS line for a
+                * USB device (not interface)? */
+
+       } else {
+
+               if (add_uevent_var(envp, num_envp, &i,
                           buffer, buffer_size, &length,
                           "INTERFACE=%d/%d/%d",
                           alt->desc.bInterfaceClass,
                           alt->desc.bInterfaceSubClass,
                           alt->desc.bInterfaceProtocol))
-               return -ENOMEM;
+                       return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
+               if (add_uevent_var(envp, num_envp, &i,
                           buffer, buffer_size, &length,
                           
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
                           le16_to_cpu(usb_dev->descriptor.idVendor),
@@ -586,7 +833,8 @@ static int usb_uevent(struct device *dev
                           alt->desc.bInterfaceClass,
                           alt->desc.bInterfaceSubClass,
                           alt->desc.bInterfaceProtocol))
-               return -ENOMEM;
+                       return -ENOMEM;
+       }
 
        envp[i] = NULL;
 
@@ -626,8 +874,13 @@ int usb_register_driver(struct usb_drive
 
        new_driver->driver.name = (char *)new_driver->name;
        new_driver->driver.bus = &usb_bus_type;
-       new_driver->driver.probe = usb_probe_interface;
-       new_driver->driver.remove = usb_unbind_interface;
+       if (new_driver->for_devices) {
+               new_driver->driver.probe = usb_probe_device;
+               new_driver->driver.remove = usb_unbind_device;
+       } else {
+               new_driver->driver.probe = usb_probe_interface;
+               new_driver->driver.remove = usb_unbind_interface;
+       }
        new_driver->driver.owner = owner;
        spin_lock_init(&new_driver->dynids.lock);
        INIT_LIST_HEAD(&new_driver->dynids.list);
@@ -673,44 +926,34 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister)
 
 #ifdef CONFIG_PM
 
-static int verify_suspended(struct device *dev, void *unused)
-{
-       return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
-}
-
-static int usb_generic_suspend(struct device *dev, pm_message_t message)
+static int usb_core_suspend(struct device *dev, pm_message_t msg)
 {
+       struct usb_driver       *driver = to_usb_driver(dev->driver);
+       struct usb_device       *udev;
        struct usb_interface    *intf;
-       struct usb_driver       *driver;
        int                     status;
 
-       /* USB devices enter SUSPEND state through their hubs, but can be
-        * marked for FREEZE as soon as their children are already idled.
-        * But those semantics are useless, so we equate the two (sigh).
-        */
-       if (dev->driver == &usb_generic_driver) {
-               if (dev->power.power_state.event == message.event)
-                       return 0;
-               /* we need to rule out bogus requests through sysfs */
-               status = device_for_each_child(dev, NULL, verify_suspended);
-               if (status)
-                       return status;
-               return usb_suspend_device (to_usb_device(dev));
-       }
+       if (dev->power.power_state.event != PM_EVENT_ON)
+               return 0;
 
-       if ((dev->driver == NULL) ||
-           (dev->driver_data == &usb_generic_driver_data))
+       if (dev->driver == NULL)
                return 0;
 
+       if (is_usb_device(dev)) {
+               udev = to_usb_device(dev);
+
+               status = driver->suspend((struct usb_interface *) udev, msg);
+               return status;
+       }
+
        intf = to_usb_interface(dev);
-       driver = to_usb_driver(dev->driver);
 
        /* with no hardware, USB interfaces only use FREEZE and ON states */
        if (!is_active(intf))
                return 0;
 
        if (driver->suspend && driver->resume) {
-               status = driver->suspend(intf, message);
+               status = driver->suspend(intf, msg);
                if (status)
                        dev_err(dev, "%s error %d\n", "suspend", status);
                else
@@ -724,10 +967,10 @@ static int usb_generic_suspend(struct de
        return status;
 }
 
-static int usb_generic_resume(struct device *dev)
+static int usb_core_resume(struct device *dev)
 {
+       struct usb_driver       *driver = to_usb_driver(dev->driver);
        struct usb_interface    *intf;
-       struct usb_driver       *driver;
        struct usb_device       *udev;
        int                     status;
 
@@ -737,23 +980,20 @@ static int usb_generic_resume(struct dev
        /* mark things as "on" immediately, no matter what errors crop up */
        dev->power.power_state.event = PM_EVENT_ON;
 
-       /* devices resume through their hubs */
-       if (dev->driver == &usb_generic_driver) {
+       if (dev->driver == NULL) {
+               dev->power.power_state.event = PM_EVENT_FREEZE;
+               return 0;
+       }
+
+       if (is_usb_device(dev)) {
                udev = to_usb_device(dev);
+
                if (udev->state == USB_STATE_NOTATTACHED)
                        return 0;
-               return usb_resume_device (to_usb_device(dev));
-       }
-
-       if ((dev->driver == NULL) ||
-           (dev->driver_data == &usb_generic_driver_data)) {
-               dev->power.power_state.event = PM_EVENT_FREEZE;
-               return 0;
+               return driver->resume((struct usb_interface *) udev);
        }
 
        intf = to_usb_interface(dev);
-       driver = to_usb_driver(dev->driver);
-
        udev = interface_to_usbdev(intf);
        if (udev->state == USB_STATE_NOTATTACHED)
                return 0;
@@ -780,7 +1020,7 @@ struct bus_type usb_bus_type = {
        .match =        usb_device_match,
        .uevent =       usb_uevent,
 #ifdef CONFIG_PM
-       .suspend =      usb_generic_suspend,
-       .resume =       usb_generic_resume,
+       .suspend =      usb_core_suspend,
+       .resume =       usb_core_resume,
 #endif
 };
Index: usb-2.6/drivers/usb/core/usb.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/usb.c
+++ usb-2.6/drivers/usb/core/usb.c
@@ -124,7 +124,7 @@ static int __find_interface(struct devic
        struct usb_interface *intf;
 
        /* can't look at usb devices, only interfaces */
-       if (dev->driver == &usb_generic_driver)
+       if (is_usb_device(dev))
                return 0;
 
        intf = to_usb_interface(dev);
@@ -205,11 +205,12 @@ usb_alloc_dev(struct usb_device *parent,
        device_initialize(&dev->dev);
        dev->dev.bus = &usb_bus_type;
        dev->dev.dma_mask = bus->controller->dma_mask;
-       dev->dev.driver_data = &usb_generic_driver_data;
-       dev->dev.driver = &usb_generic_driver;
        dev->dev.release = usb_release_dev;
        dev->state = USB_STATE_ATTACHED;
 
+       /* This magic assignment distinguishes devices from interfaces */
+       dev->dev.platform_data = &usb_generic_driver;
+
        INIT_LIST_HEAD(&dev->ep0.urb_list);
        dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
        dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@@ -837,7 +838,7 @@ static int __init usb_init(void)
        retval = usb_hub_init();
        if (retval)
                goto hub_init_failed;
-       retval = driver_register(&usb_generic_driver);
+       retval = usb_register(&usb_generic_driver);
        if (!retval)
                goto out;
 
@@ -867,7 +868,7 @@ static void __exit usb_exit(void)
        if (nousb)
                return;
 
-       driver_unregister(&usb_generic_driver);
+       usb_deregister(&usb_generic_driver);
        usb_major_cleanup();
        usbfs_cleanup();
        usb_deregister(&usbfs_driver);
Index: usb-2.6/drivers/usb/core/usb.h
===================================================================
--- usb-2.6.orig/drivers/usb/core/usb.h
+++ usb-2.6/drivers/usb/core/usb.h
@@ -31,8 +31,16 @@ extern int usb_suspend_device(struct usb
 extern int usb_resume_device(struct usb_device *dev);
 
 extern struct bus_type usb_bus_type;
-extern struct device_driver usb_generic_driver;
-extern int usb_generic_driver_data;
+extern struct usb_driver usb_generic_driver;
+
+/* Here's how we tell apart devices and interfaces.  Luckily there's
+ * no such thing as a platform USB device, so we can steal the use
+ * of the platform field. */
+
+static inline int is_usb_device(struct device *dev)
+{
+       return dev->platform_data == &usb_generic_driver;
+}
 
 /* Interfaces and their "power state" are owned by usbcore */
 
Index: usb-2.6/include/linux/usb.h
===================================================================
--- usb-2.6.orig/include/linux/usb.h
+++ usb-2.6/include/linux/usb.h
@@ -581,6 +581,8 @@ extern ssize_t usb_store_new_id(struct u
  * @driver: the driver model core driver structure.
  * @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
  *     added to this driver by preventing the sysfs file from being created.
+ * @for_devices: indicates that the driver manages USB devices and not
+ *     USB interfaces (very uncommon).
  *
  * USB drivers must provide a name, probe() and disconnect() methods,
  * and an id_table.  Other driver fields are optional.
@@ -619,6 +621,8 @@ struct usb_driver {
        struct usb_dynids dynids;
        struct device_driver driver;
        unsigned int no_dynamic_id:1;
+
+       unsigned int for_devices:1;
 };
 #define        to_usb_driver(d) container_of(d, struct usb_driver, driver)
 
Index: usb-2.6/drivers/usb/core/hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/core/hub.c
+++ usb-2.6/drivers/usb/core/hub.c
@@ -1149,144 +1149,28 @@ void usb_disconnect(struct usb_device **
         * cleaning up all state associated with the current configuration
         * so that the hardware is now fully quiesced.
         */
+       dev_dbg (&udev->dev, "unregistering device\n");
        usb_disable_device(udev, 0);
 
-       usb_notify_remove_device(udev);
+       usb_unlock_device(udev);
+
+       /* Unregister the device.  The device driver is responsible
+        * for removing the device files from usbfs and sysfs and for
+        * de-configuring the device.
+        */
+       device_del(&udev->dev);
 
-       /* Free the device number, remove the /proc/bus/usb entry and
-        * the sysfs attributes, and delete the parent's children[]
+       /* Free the device number and delete the parent's children[]
         * (or root_hub) pointer.
         */
-       dev_dbg (&udev->dev, "unregistering device\n");
        release_address(udev);
-       usb_remove_sysfs_dev_files(udev);
 
        /* Avoid races with recursively_mark_NOTATTACHED() */
        spin_lock_irq(&device_state_lock);
        *pdev = NULL;
        spin_unlock_irq(&device_state_lock);
 
-       usb_unlock_device(udev);
-
-       device_unregister(&udev->dev);
-}
-
-static inline const char *plural(int n)
-{
-       return (n == 1 ? "" : "s");
-}
-
-static int choose_configuration(struct usb_device *udev)
-{
-       int i;
-       int num_configs;
-       int insufficient_power = 0;
-       struct usb_host_config *c, *best;
-
-       best = NULL;
-       c = udev->config;
-       num_configs = udev->descriptor.bNumConfigurations;
-       for (i = 0; i < num_configs; (i++, c++)) {
-               struct usb_interface_descriptor *desc = NULL;
-
-               /* It's possible that a config has no interfaces! */
-               if (c->desc.bNumInterfaces > 0)
-                       desc = &c->intf_cache[0]->altsetting->desc;
-
-               /*
-                * HP's USB bus-powered keyboard has only one configuration
-                * and it claims to be self-powered; other devices may have
-                * similar errors in their descriptors.  If the next test
-                * were allowed to execute, such configurations would always
-                * be rejected and the devices would not work as expected.
-                * In the meantime, we run the risk of selecting a config
-                * that requires external power at a time when that power
-                * isn't available.  It seems to be the lesser of two evils.
-                *
-                * Bugzilla #6448 reports a device that appears to crash
-                * when it receives a GET_DEVICE_STATUS request!  We don't
-                * have any other way to tell whether a device is self-powered,
-                * but since we don't use that information anywhere but here,
-                * the call has been removed.
-                *
-                * Maybe the GET_DEVICE_STATUS call and the test below can
-                * be reinstated when device firmwares become more reliable.
-                * Don't hold your breath.
-                */
-#if 0
-               /* Rule out self-powered configs for a bus-powered device */
-               if (bus_powered && (c->desc.bmAttributes &
-                                       USB_CONFIG_ATT_SELFPOWER))
-                       continue;
-#endif
-
-               /*
-                * The next test may not be as effective as it should be.
-                * Some hubs have errors in their descriptor, claiming
-                * to be self-powered when they are really bus-powered.
-                * We will overestimate the amount of current such hubs
-                * make available for each port.
-                *
-                * This is a fairly benign sort of failure.  It won't
-                * cause us to reject configurations that we should have
-                * accepted.
-                */
-
-               /* Rule out configs that draw too much bus current */
-               if (c->desc.bMaxPower * 2 > udev->bus_mA) {
-                       insufficient_power++;
-                       continue;
-               }
-
-               /* If the first config's first interface is COMM/2/0xff
-                * (MSFT RNDIS), rule it out unless Linux has host-side
-                * RNDIS support. */
-               if (i == 0 && desc
-                               && desc->bInterfaceClass == USB_CLASS_COMM
-                               && desc->bInterfaceSubClass == 2
-                               && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
-                       continue;
-#else
-                       best = c;
-#endif
-               }
-
-               /* From the remaining configs, choose the first one whose
-                * first interface is for a non-vendor-specific class.
-                * Reason: Linux is more likely to have a class driver
-                * than a vendor-specific driver. */
-               else if (udev->descriptor.bDeviceClass !=
-                                               USB_CLASS_VENDOR_SPEC &&
-                               (!desc || desc->bInterfaceClass !=
-                                               USB_CLASS_VENDOR_SPEC)) {
-                       best = c;
-                       break;
-               }
-
-               /* If all the remaining configs are vendor-specific,
-                * choose the first one. */
-               else if (!best)
-                       best = c;
-       }
-
-       if (insufficient_power > 0)
-               dev_info(&udev->dev, "rejected %d configuration%s "
-                       "due to insufficient available bus power\n",
-                       insufficient_power, plural(insufficient_power));
-
-       if (best) {
-               i = best->desc.bConfigurationValue;
-               dev_info(&udev->dev,
-                       "configuration #%d chosen from %d choice%s\n",
-                       i, num_configs, plural(num_configs));
-       } else {
-               i = -1;
-               dev_warn(&udev->dev,
-                       "no configuration chosen from %d choice%s\n",
-                       num_configs, plural(num_configs));
-       }
-       return i;
+       put_device(&udev->dev);
 }
 
 static void show_string(struct usb_device *udev, char *id, char *string)
@@ -1324,7 +1208,6 @@ static void show_string(struct usb_devic
 int usb_new_device(struct usb_device *udev)
 {
        int err;
-       int c;
 
        err = usb_get_configuration(udev);
        if (err < 0) {
@@ -1417,34 +1300,15 @@ int usb_new_device(struct usb_device *ud
        }
 #endif
 
-       /* put device-specific files into sysfs */
+       /* Register the device.  The device driver is responsible
+        * for adding the device files to usbfs and sysfs and for
+        * configuring the device.
+        */
        err = device_add (&udev->dev);
        if (err) {
                dev_err(&udev->dev, "can't device_add, error %d\n", err);
                goto fail;
        }
-       usb_create_sysfs_dev_files (udev);
-
-       usb_lock_device(udev);
-
-       /* choose and set the configuration. that registers the interfaces
-        * with the driver core, and lets usb device drivers bind to them.
-        */
-       c = choose_configuration(udev);
-       if (c >= 0) {
-               err = usb_set_configuration(udev, c);
-               if (err) {
-                       dev_err(&udev->dev, "can't set config #%d, error %d\n",
-                                       c, err);
-                       /* This need not be fatal.  The user can try to
-                        * set other configurations. */
-               }
-       }
-
-       /* USB device state == configured ... usable */
-       usb_notify_add_device(udev);
-
-       usb_unlock_device(udev);
 
        return 0;
 




_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to