Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / core / usb.c
index 0da70f7..b7fdc1c 100644 (file)
  */
 
 #include <linux/config.h>
-
-#ifdef CONFIG_USB_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
@@ -40,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include <asm/io.h>
 #include <asm/scatterlist.h>
 #include "hcd.h"
 #include "usb.h"
 
-extern int  usb_hub_init(void);
-extern void usb_hub_cleanup(void);
-extern int usb_major_init(void);
-extern void usb_major_cleanup(void);
-extern int usb_host_init(void);
-extern void usb_host_cleanup(void);
-
 
 const char *usbcore_name = "usbcore";
 
-int nousb;             /* Disable USB when built into kernel image */
-                       /* Not honored on modular build */
-
-
-static int generic_probe (struct device *dev)
-{
-       return 0;
-}
-static int generic_remove (struct device *dev)
-{
-       return 0;
-}
-
-static struct device_driver usb_generic_driver = {
-       .name = "usb",
-       .bus = &usb_bus_type,
-       .probe = generic_probe,
-       .remove = generic_remove,
-};
-
-static int usb_generic_driver_data;
-
-/* called from driver core with usb_bus_type.subsys writelock */
-int usb_probe_interface(struct device *dev)
-{
-       struct usb_interface * intf = to_usb_interface(dev);
-       struct usb_driver * driver = to_usb_driver(dev->driver);
-       const struct usb_device_id *id;
-       int error = -ENODEV;
-
-       dev_dbg(dev, "%s\n", __FUNCTION__);
-
-       if (!driver->probe)
-               return error;
-
-       id = usb_match_id (intf, driver->id_table);
-       if (id) {
-               dev_dbg (dev, "%s - got id\n", __FUNCTION__);
-               error = driver->probe (intf, id);
-       }
-
-       return error;
-}
-
-/* called from driver core with usb_bus_type.subsys writelock */
-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);
-
-       /* release all urbs for this interface */
-       usb_disable_interface(interface_to_usbdev(intf), intf);
-
-       if (driver && driver->disconnect)
-               driver->disconnect(intf);
-
-       /* reset other interface state */
-       usb_set_interface(interface_to_usbdev(intf),
-                       intf->altsetting[0].desc.bInterfaceNumber,
-                       0);
-       usb_set_intfdata(intf, NULL);
-
-       return 0;
-}
-
-/**
- * usb_register - register a USB driver
- * @new_driver: USB operations for the driver
- *
- * Registers a USB driver with the USB core.  The list of unattached
- * interfaces will be rescanned whenever a new driver is added, allowing
- * the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
- * 
- * NOTE: if you want your driver to use the USB major number, you must call
- * usb_register_dev() to enable that functionality.  This function no longer
- * takes care of that.
- */
-int usb_register(struct usb_driver *new_driver)
-{
-       int retval = 0;
-
-       if (nousb)
-               return -ENODEV;
-
-       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;
-
-       retval = driver_register(&new_driver->driver);
+static int nousb;      /* Disable USB when built into kernel image */
 
-       if (!retval) {
-               pr_info("%s: registered new driver %s\n",
-                       usbcore_name, new_driver->name);
-               usbfs_update_special();
-       } else {
-               printk(KERN_ERR "%s: error %d registering driver %s\n",
-                       usbcore_name, retval, new_driver->name);
-       }
-
-       return retval;
-}
-
-/**
- * usb_deregister - unregister a USB driver
- * @driver: USB operations of the driver to unregister
- * Context: must be able to sleep
- *
- * Unlinks the specified driver from the internal USB driver list.
- * 
- * NOTE: If you called usb_register_dev(), you still need to call
- * usb_deregister_dev() to clean up your driver's allocated minor numbers,
- * this * call will no longer do it for you.
- */
-void usb_deregister(struct usb_driver *driver)
-{
-       pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
-
-       driver_unregister (&driver->driver);
-
-       usbfs_update_special();
-}
 
 /**
  * usb_ifnum_to_if - get the interface object with a given interface number
@@ -198,6 +64,9 @@ void usb_deregister(struct usb_driver *driver)
  * This routine helps device drivers avoid such mistakes.
  * However, you should make sure that you do the right thing with any
  * alternate settings available for this interfaces.
+ *
+ * Don't call this function unless you are bound to one of the interfaces
+ * on this device or you have locked the device!
  */
 struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
 {
@@ -228,6 +97,9 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
  * it would be incorrect to assume that the first altsetting entry in
  * the array corresponds to altsetting zero.  This routine helps device
  * drivers avoid such mistakes.
+ *
+ * Don't call this function unless you are bound to the intf interface
+ * or you have locked the device!
  */
 struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
                unsigned int altnum)
@@ -241,44 +113,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
        return NULL;
 }
 
-/**
- * usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
- * @dev: the device whose current configuration+altsettings is considered
- * @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
- *
- * This walks the device descriptor for the currently active configuration,
- * and returns a pointer to the endpoint with that particular endpoint
- * number, or null.
- *
- * Note that interface descriptors are not required to list endpoint
- * numbers in any standardized order, so that it would be wrong to
- * assume that ep2in precedes either ep5in, ep2out, or even ep1out.
- * This routine helps device drivers avoid such mistakes.
- */
-struct usb_endpoint_descriptor *
-usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
-{
-       struct usb_host_config *config = dev->actconfig;
-       int i, k;
-
-       if (!config)
-               return NULL;
-       for (i = 0; i < config->desc.bNumInterfaces; i++) {
-               struct usb_interface            *intf;
-               struct usb_host_interface       *alt;
-
-               /* only endpoints in current altsetting are active */
-               intf = config->interface[i];
-               alt = intf->cur_altsetting;
-
-               for (k = 0; k < alt->desc.bNumEndpoints; k++)
-                       if (epnum == alt->endpoint[k].desc.bEndpointAddress)
-                               return &alt->endpoint[k].desc;
-       }
-
-       return NULL;
-}
-
 /**
  * usb_driver_claim_interface - bind a driver to an interface
  * @driver: the driver to be bound
@@ -295,11 +129,12 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
  * way to bind to an interface is to return the private data from
  * the driver's probe() method.
  *
- * Callers must own the driver model's usb bus writelock.  So driver
- * probe() entries don't need extra locking, but other call contexts
- * may need to explicitly claim that lock.
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock.  So driver probe() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
  */
-int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
+int usb_driver_claim_interface(struct usb_driver *driver,
+                               struct usb_interface *iface, void* priv)
 {
        struct device *dev = &iface->dev;
 
@@ -308,11 +143,13 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *
 
        dev->driver = &driver->driver;
        usb_set_intfdata(iface, priv);
+       iface->condition = USB_INTERFACE_BOUND;
+       mark_active(iface);
 
        /* if interface was already added, bind now; else let
         * the future device_add() bind it, bypassing probe()
         */
-       if (!list_empty (&dev->bus_list))
+       if (device_is_registered(dev))
                device_bind_driver(dev);
 
        return 0;
@@ -328,8 +165,8 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *
  * also causes the driver disconnect() method to be called.
  *
  * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the usb_device serialize semaphore and the driver model's
- * usb bus writelock.  So driver disconnect() entries don't need extra locking,
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock.  So driver disconnect() entries don't need extra locking,
  * but other call contexts may need to explicitly claim those locks.
  */
 void usb_driver_release_interface(struct usb_driver *driver,
@@ -341,143 +178,42 @@ void usb_driver_release_interface(struct usb_driver *driver,
        if (!dev->driver || dev->driver != &driver->driver)
                return;
 
-       /* don't disconnect from disconnect(), or before dev_add() */
-       if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list))
+       /* don't release from within disconnect() */
+       if (iface->condition != USB_INTERFACE_BOUND)
+               return;
+
+       /* don't release if the interface hasn't been added yet */
+       if (device_is_registered(dev)) {
+               iface->condition = USB_INTERFACE_UNBINDING;
                device_release_driver(dev);
+       }
 
        dev->driver = NULL;
        usb_set_intfdata(iface, NULL);
+       iface->condition = USB_INTERFACE_UNBOUND;
+       mark_quiesced(iface);
 }
 
-/**
- * usb_match_id - find first usb_device_id matching device or interface
- * @interface: the interface of interest
- * @id: array of usb_device_id structures, terminated by zero entry
- *
- * usb_match_id searches an array of usb_device_id's and returns
- * the first one matching the device or interface, or null.
- * This is used when binding (or rebinding) a driver to an interface.
- * Most USB device drivers will use this indirectly, through the usb core,
- * but some layered driver frameworks use it directly.
- * These device tables are exported with MODULE_DEVICE_TABLE, through
- * modutils and "modules.usbmap", to support the driver loading
- * functionality of USB hotplugging.
- *
- * What Matches:
- *
- * The "match_flags" element in a usb_device_id controls which
- * members are used.  If the corresponding bit is set, the
- * value in the device_id must match its corresponding member
- * in the device or interface descriptor, or else the device_id
- * does not match.
- *
- * "driver_info" is normally used only by device drivers,
- * but you can create a wildcard "matches anything" usb_device_id
- * as a driver's "modules.usbmap" entry if you provide an id with
- * only a nonzero "driver_info" field.  If you do this, the USB device
- * driver's probe() routine should use additional intelligence to
- * decide whether to bind to the specified interface.
- * 
- * What Makes Good usb_device_id Tables:
- *
- * The match algorithm is very simple, so that intelligence in
- * driver selection must come from smart driver id records.
- * Unless you have good reasons to use another selection policy,
- * provide match elements only in related groups, and order match
- * specifiers from specific to general.  Use the macros provided
- * for that purpose if you can.
- *
- * The most specific match specifiers use device descriptor
- * data.  These are commonly used with product-specific matches;
- * the USB_DEVICE macro lets you provide vendor and product IDs,
- * and you can also match against ranges of product revisions.
- * These are widely used for devices with application or vendor
- * specific bDeviceClass values.
- *
- * Matches based on device class/subclass/protocol specifications
- * are slightly more general; use the USB_DEVICE_INFO macro, or
- * its siblings.  These are used with single-function devices
- * where bDeviceClass doesn't specify that each interface has
- * its own class. 
- *
- * Matches based on interface class/subclass/protocol are the
- * most general; they let drivers bind to any interface on a
- * multiple-function device.  Use the USB_INTERFACE_INFO
- * macro, or its siblings, to match class-per-interface style 
- * devices (as recorded in bDeviceClass).
- *  
- * Within those groups, remember that not all combinations are
- * meaningful.  For example, don't give a product version range
- * without vendor and product IDs; or specify a protocol without
- * its associated class and subclass.
- */   
-const struct usb_device_id *
-usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
-{
-       struct usb_host_interface *intf;
-       struct usb_device *dev;
-
-       /* proc_connectinfo in devio.c may call us with id == NULL. */
-       if (id == NULL)
-               return NULL;
-
-       intf = interface->cur_altsetting;
-       dev = interface_to_usbdev(interface);
-
-       /* It is important to check that id->driver_info is nonzero,
-          since an entry that is all zeroes except for a nonzero
-          id->driver_info is the way to create an entry that
-          indicates that the driver want to examine every
-          device and interface. */
-       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
-              id->driver_info; id++) {
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
-                   id->idVendor != dev->descriptor.idVendor)
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
-                   id->idProduct != dev->descriptor.idProduct)
-                       continue;
-
-               /* No need to test id->bcdDevice_lo != 0, since 0 is never
-                  greater than any unsigned number. */
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
-                   (id->bcdDevice_lo > dev->descriptor.bcdDevice))
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
-                   (id->bcdDevice_hi < dev->descriptor.bcdDevice))
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
-                   (id->bDeviceClass != dev->descriptor.bDeviceClass))
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-                   (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
-                   (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
-                       continue;
-
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
-                   (id->bInterfaceClass != intf->desc.bInterfaceClass))
-                       continue;
+struct find_interface_arg {
+       int minor;
+       struct usb_interface *interface;
+};
 
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
-                   (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
-                       continue;
+static int __find_interface(struct device * dev, void * data)
+{
+       struct find_interface_arg *arg = data;
+       struct usb_interface *intf;
 
-               if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
-                   (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
-                       continue;
+       /* can't look at usb devices, only interfaces */
+       if (dev->driver == &usb_generic_driver)
+               return 0;
 
-               return id;
+       intf = to_usb_interface(dev);
+       if (intf->minor != -1 && intf->minor == arg->minor) {
+               arg->interface = intf;
+               return 1;
        }
-
-       return NULL;
+       return 0;
 }
 
 /**
@@ -491,58 +227,18 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
  */
 struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
 {
-       struct list_head *entry;
-       struct device *dev;
-       struct usb_interface *intf;
-
-       list_for_each(entry, &drv->driver.devices) {
-               dev = container_of(entry, struct device, driver_list);
+       struct find_interface_arg argb;
 
-               /* can't look at usb devices, only interfaces */
-               if (dev->driver == &usb_generic_driver)
-                       continue;
-
-               intf = to_usb_interface(dev);
-               if (intf->minor == -1)
-                       continue;
-               if (intf->minor == minor)
-                       return intf;
-       }
-
-       /* no device found that matches */
-       return NULL;    
+       argb.minor = minor;
+       argb.interface = NULL;
+       driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
+       return argb.interface;
 }
 
-static int usb_device_match (struct device *dev, struct device_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;
-
-       intf = to_usb_interface(dev);
-
-       usb_drv = to_usb_driver(drv);
-       id = usb_drv->id_table;
-       
-       id = usb_match_id (intf, usb_drv->id_table);
-       if (id)
-               return 1;
-
-       return 0;
-}
-
-
 #ifdef CONFIG_HOTPLUG
 
 /*
- * USB hotplugging invokes what /proc/sys/kernel/hotplug says
- * (normally /sbin/hotplug) when USB devices get added or removed.
- *
- * This invokes a user mode policy agent, typically helping to load driver
+ * This sends an uevent to userspace, typically helping to load driver
  * or other modules, configure the device, and more.  Drivers can provide
  * a MODULE_DEVICE_TABLE to help with module loading subtasks.
  *
@@ -551,12 +247,12 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
  * delays in event delivery.  Use sysfs (and DEVPATH) to make sure the
  * device (and this configuration!) are still present.
  */
-static int usb_hotplug (struct device *dev, char **envp, int num_envp,
-                       char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, char **envp, int num_envp,
+                     char *buffer, int buffer_size)
 {
        struct usb_interface *intf;
        struct usb_device *usb_dev;
-       char *scratch;
+       struct usb_host_interface *alt;
        int i = 0;
        int length = 0;
 
@@ -564,7 +260,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
                return -ENODEV;
 
        /* driver is often null here; dev_dbg() would oops */
-       pr_debug ("usb %s: hotplug\n", dev->bus_id);
+       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) || 
@@ -573,7 +269,8 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
 
        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);
                return -ENODEV;
@@ -583,8 +280,6 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
                return -ENODEV;
        }
 
-       scratch = buffer;
-
 #ifdef CONFIG_USB_DEVICEFS
        /* If this is available, userspace programs can directly read
         * all the device descriptors we don't tell them about.  Or
@@ -592,65 +287,61 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
         *
         * FIXME reduce hardwired intelligence here
         */
-       envp [i++] = scratch;
-       length += snprintf (scratch, buffer_size - length,
-                           "DEVICE=/proc/bus/usb/%03d/%03d",
-                           usb_dev->bus->busnum, usb_dev->devnum);
-       if ((buffer_size - length <= 0) || (i >= num_envp))
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "DEVICE=/proc/bus/usb/%03d/%03d",
+                          usb_dev->bus->busnum, usb_dev->devnum))
                return -ENOMEM;
-       ++length;
-       scratch += length;
 #endif
 
        /* per-device configurations are common */
-       envp [i++] = scratch;
-       length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
-                           usb_dev->descriptor.idVendor,
-                           usb_dev->descriptor.idProduct,
-                           usb_dev->descriptor.bcdDevice);
-       if ((buffer_size - length <= 0) || (i >= num_envp))
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "PRODUCT=%x/%x/%x",
+                          le16_to_cpu(usb_dev->descriptor.idVendor),
+                          le16_to_cpu(usb_dev->descriptor.idProduct),
+                          le16_to_cpu(usb_dev->descriptor.bcdDevice)))
                return -ENOMEM;
-       ++length;
-       scratch += length;
 
        /* class-based driver binding models */
-       envp [i++] = scratch;
-       length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
-                           usb_dev->descriptor.bDeviceClass,
-                           usb_dev->descriptor.bDeviceSubClass,
-                           usb_dev->descriptor.bDeviceProtocol);
-       if ((buffer_size - length <= 0) || (i >= num_envp))
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "TYPE=%d/%d/%d",
+                          usb_dev->descriptor.bDeviceClass,
+                          usb_dev->descriptor.bDeviceSubClass,
+                          usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
-       ++length;
-       scratch += length;
-
-       if (usb_dev->descriptor.bDeviceClass == 0) {
-               struct usb_host_interface *alt = intf->cur_altsetting;
-
-               /* 2.4 only exposed interface zero.  in 2.5, hotplug
-                * agents are called for all interfaces, and can use
-                * $DEVPATH/bInterfaceNumber if necessary.
-                */
-               envp [i++] = scratch;
-               length += snprintf (scratch, buffer_size - length,
-                           "INTERFACE=%d/%d/%d",
-                           alt->desc.bInterfaceClass,
-                           alt->desc.bInterfaceSubClass,
-                           alt->desc.bInterfaceProtocol);
-               if ((buffer_size - length <= 0) || (i >= num_envp))
-                       return -ENOMEM;
-               ++length;
-               scratch += length;
 
-       }
-       envp [i++] = 0;
+       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;
+
+       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),
+                          le16_to_cpu(usb_dev->descriptor.idProduct),
+                          le16_to_cpu(usb_dev->descriptor.bcdDevice),
+                          usb_dev->descriptor.bDeviceClass,
+                          usb_dev->descriptor.bDeviceSubClass,
+                          usb_dev->descriptor.bDeviceProtocol,
+                          alt->desc.bInterfaceClass,
+                          alt->desc.bInterfaceSubClass,
+                          alt->desc.bInterfaceProtocol))
+               return -ENOMEM;
+
+       envp[i] = NULL;
 
        return 0;
 }
 
 #else
 
-static int usb_hotplug (struct device *dev, char **envp,
+static int usb_uevent(struct device *dev, char **envp,
                        int num_envp, char *buffer, int buffer_size)
 {
        return -ENODEV;
@@ -671,18 +362,19 @@ static void usb_release_dev(struct device *dev)
 
        udev = to_usb_device(dev);
 
-       if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
-               udev->bus->op->deallocate(udev);
        usb_destroy_configuration(udev);
        usb_bus_put(udev->bus);
-       kfree (udev);
+       kfree(udev->product);
+       kfree(udev->manufacturer);
+       kfree(udev->serial);
+       kfree(udev);
 }
 
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
- * @port: zero based index of port; ignored for root hubs
+ * @port1: one-based index of port; ignored for root hubs
  * Context: !in_interrupt ()
  *
  * Only hub drivers (including virtual root hub drivers for host
@@ -691,16 +383,14 @@ static void usb_release_dev(struct device *dev)
  * This call may not be used in a non-sleeping context.
  */
 struct usb_device *
-usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
+usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
        struct usb_device *dev;
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return NULL;
 
-       memset(dev, 0, sizeof(*dev));
-
        bus = usb_bus_get(bus);
        if (!bus) {
                kfree(dev);
@@ -715,6 +405,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
        dev->dev.release = usb_release_dev;
        dev->state = USB_STATE_ATTACHED;
 
+       INIT_LIST_HEAD(&dev->ep0.urb_list);
+       dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
+       dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
+       /* ep0 maxpacket comes later, from device descriptor */
+       dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+
        /* Save readable and stable topology id, distinguishing devices
         * by location for diagnostics, tools, driver model, etc.  The
         * string is a path along hub ports, from the root.  Each device's
@@ -732,10 +428,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
                /* match any labeling on the hubs; it's one-based */
                if (parent->devpath [0] == '0')
                        snprintf (dev->devpath, sizeof dev->devpath,
-                               "%d", port + 1);
+                               "%d", port1);
                else
                        snprintf (dev->devpath, sizeof dev->devpath,
-                               "%s.%d", parent->devpath, port + 1);
+                               "%s.%d", parent->devpath, port1);
 
                dev->dev.parent = &parent->dev;
                sprintf (&dev->dev.bus_id[0], "%d-%s",
@@ -744,15 +440,11 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port)
                /* hub driver sets up TT records */
        }
 
+       dev->portnum = port1;
        dev->bus = bus;
        dev->parent = parent;
        INIT_LIST_HEAD(&dev->filelist);
 
-       init_MUTEX(&dev->serialize);
-
-       if (dev->bus->op->allocate)
-               dev->bus->op->allocate(dev);
-
        return dev;
 }
 
@@ -822,6 +514,80 @@ void usb_put_intf(struct usb_interface *intf)
                put_device(&intf->dev);
 }
 
+
+/*                     USB device locking
+ *
+ * USB devices and interfaces are locked using the semaphore in their
+ * embedded struct device.  The hub driver guarantees that whenever a
+ * device is connected or disconnected, drivers are called with the
+ * USB device locked as well as their particular interface.
+ *
+ * Complications arise when several devices are to be locked at the same
+ * time.  Only hub-aware drivers that are part of usbcore ever have to
+ * do this; nobody else needs to worry about it.  The rule for locking
+ * is simple:
+ *
+ *     When locking both a device and its parent, always lock the
+ *     the parent first.
+ */
+
+/**
+ * usb_lock_device_for_reset - cautiously acquire the lock for a
+ *     usb device structure
+ * @udev: device that's being locked
+ * @iface: interface bound to the driver making the request (optional)
+ *
+ * Attempts to acquire the device lock, but fails if the device is
+ * NOTATTACHED or SUSPENDED, or if iface is specified and the interface
+ * is neither BINDING nor BOUND.  Rather than sleeping to wait for the
+ * lock, the routine polls repeatedly.  This is to prevent deadlock with
+ * disconnect; in some drivers (such as usb-storage) the disconnect()
+ * or suspend() method will block waiting for a device reset to complete.
+ *
+ * Returns a negative error code for failure, otherwise 1 or 0 to indicate
+ * that the device will or will not have to be unlocked.  (0 can be
+ * returned when an interface is given and is BINDING, because in that
+ * case the driver already owns the device lock.)
+ */
+int usb_lock_device_for_reset(struct usb_device *udev,
+               struct usb_interface *iface)
+{
+       unsigned long jiffies_expire = jiffies + HZ;
+
+       if (udev->state == USB_STATE_NOTATTACHED)
+               return -ENODEV;
+       if (udev->state == USB_STATE_SUSPENDED)
+               return -EHOSTUNREACH;
+       if (iface) {
+               switch (iface->condition) {
+                 case USB_INTERFACE_BINDING:
+                       return 0;
+                 case USB_INTERFACE_BOUND:
+                       break;
+                 default:
+                       return -EINTR;
+               }
+       }
+
+       while (usb_trylock_device(udev) != 0) {
+
+               /* If we can't acquire the lock after waiting one second,
+                * we're probably deadlocked */
+               if (time_after(jiffies, jiffies_expire))
+                       return -EBUSY;
+
+               msleep(15);
+               if (udev->state == USB_STATE_NOTATTACHED)
+                       return -ENODEV;
+               if (udev->state == USB_STATE_SUSPENDED)
+                       return -EHOSTUNREACH;
+               if (iface && iface->condition != USB_INTERFACE_BOUND)
+                       return -EINTR;
+       }
+       return 1;
+}
+
+
 static struct usb_device *match_device(struct usb_device *dev,
                                       u16 vendor_id, u16 product_id)
 {
@@ -829,12 +595,12 @@ static struct usb_device *match_device(struct usb_device *dev,
        int child;
 
        dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n",
-           dev->descriptor.idVendor,
-           dev->descriptor.idProduct);
+           le16_to_cpu(dev->descriptor.idVendor),
+           le16_to_cpu(dev->descriptor.idProduct));
 
        /* see if this device matches */
-       if ((dev->descriptor.idVendor == vendor_id) &&
-           (dev->descriptor.idProduct == product_id)) {
+       if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
+           (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
                dev_dbg (&dev->dev, "matched this device!\n");
                ret_dev = usb_get_dev(dev);
                goto exit;
@@ -843,8 +609,10 @@ static struct usb_device *match_device(struct usb_device *dev,
        /* look through all of the children of this device */
        for (child = 0; child < dev->maxchild; ++child) {
                if (dev->children[child]) {
+                       usb_lock_device(dev->children[child]);
                        ret_dev = match_device(dev->children[child],
                                               vendor_id, product_id);
+                       usb_unlock_device(dev->children[child]);
                        if (ret_dev)
                                goto exit;
                }
@@ -872,17 +640,21 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
        struct usb_bus *bus;
        struct usb_device *dev = NULL;
        
-       down(&usb_bus_list_lock);
+       mutex_lock(&usb_bus_list_lock);
        for (buslist = usb_bus_list.next;
             buslist != &usb_bus_list; 
             buslist = buslist->next) {
                bus = container_of(buslist, struct usb_bus, bus_list);
+               if (!bus->root_hub)
+                       continue;
+               usb_lock_device(bus->root_hub);
                dev = match_device(bus->root_hub, vendor_id, product_id);
+               usb_unlock_device(bus->root_hub);
                if (dev)
                        goto exit;
        }
 exit:
-       up(&usb_bus_list_lock);
+       mutex_unlock(&usb_bus_list_lock);
        return dev;
 }
 
@@ -938,300 +710,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
        return -1;
 }
 
-/**
- * usb_disconnect - disconnect a device (usbcore-internal)
- * @pdev: pointer to device being disconnected
- * Context: !in_interrupt ()
- *
- * Something got disconnected. Get rid of it, and all of its children.
- *
- * Only hub drivers (including virtual root hub drivers for host
- * controllers) should ever call this.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- */
-void usb_disconnect(struct usb_device **pdev)
-{
-       struct usb_device       *dev = *pdev;
-       struct usb_bus          *bus;
-       struct usb_operations   *ops;
-       int                     i;
-
-       might_sleep ();
-
-       if (!dev) {
-               pr_debug ("%s nodev\n", __FUNCTION__);
-               return;
-       }
-       bus = dev->bus;
-       if (!bus) {
-               pr_debug ("%s nobus\n", __FUNCTION__);
-               return;
-       }
-       ops = bus->op;
-
-       *pdev = NULL;
-
-       /* mark the device as inactive, so any further urb submissions for
-        * this device will fail.
-        */
-       dev->state = USB_STATE_NOTATTACHED;
-       down(&dev->serialize);
-
-       dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
-
-       /* Free up all the children before we remove this device */
-       for (i = 0; i < USB_MAXCHILDREN; i++) {
-               struct usb_device **child = dev->children + i;
-               if (*child)
-                       usb_disconnect(child);
-       }
-
-       /* deallocate hcd/hardware state ... nuking all pending urbs and
-        * cleaning up all state associated with the current configuration
-        */
-       usb_disable_device(dev, 0);
-
-       dev_dbg (&dev->dev, "unregistering device\n");
-       /* 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);
-       }
-       up(&dev->serialize);
-       device_unregister(&dev->dev);
-}
-
-/**
- * usb_choose_address - pick device address (usbcore-internal)
- * @dev: newly detected device (in DEFAULT state)
- *
- * Picks a device address.  It's up to the hub (or root hub) driver
- * to handle and manage enumeration, starting from the DEFAULT state.
- * Only hub drivers (but not virtual root hub drivers for host
- * controllers) should ever call this.
- */
-void usb_choose_address(struct usb_device *dev)
-{
-       int devnum;
-       // FIXME needs locking for SMP!!
-       /* why? this is called only from the hub thread, 
-        * which hopefully doesn't run on multiple CPU's simultaneously 8-)
-        */
-
-       /* Try to allocate the next devnum beginning at bus->devnum_next. */
-       devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
-       if (devnum >= 128)
-               devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
-
-       dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
-
-       if (devnum < 128) {
-               set_bit(devnum, dev->bus->devmap.devicemap);
-               dev->devnum = devnum;
-       }
-}
-
-
-// hub-only!! ... and only exported for reset/reinit path.
-// otherwise used internally, for usb_new_device()
-int usb_set_address(struct usb_device *dev)
-{
-       int retval;
-
-       if (dev->devnum == 0)
-               return -EINVAL;
-       if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
-               return -EINVAL;
-       retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-               0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-       if (retval == 0)
-               dev->state = USB_STATE_ADDRESS;
-       return retval;
-}
-
-static inline void usb_show_string(struct usb_device *dev, char *id, int index)
-{
-       char *buf;
-
-       if (!index)
-               return;
-       if (!(buf = kmalloc(256, GFP_KERNEL)))
-               return;
-       if (usb_string(dev, index, buf, 256) > 0)
-               dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
-       kfree(buf);
-}
-
-/*
- * By the time we get here, we chose a new device address
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
- *
- * Returns 0 for success, != 0 for error.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver should ever call this; root hub registration
- * uses it only indirectly.
- */
-#define NEW_DEVICE_RETRYS      2
-#define SET_ADDRESS_RETRYS     2
-int usb_new_device(struct usb_device *dev)
-{
-       int err = -EINVAL;
-       int i;
-       int j;
-       int config;
-
-       /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
-        * it's fixed size except for full speed devices.
-        */
-       switch (dev->speed) {
-       case USB_SPEED_HIGH:            /* fixed at 64 */
-               i = 64;
-               break;
-       case USB_SPEED_FULL:            /* 8, 16, 32, or 64 */
-               /* to determine the ep0 maxpacket size, read the first 8
-                * bytes from the device descriptor to get bMaxPacketSize0;
-                * then correct our initial (small) guess.
-                */
-               // FALLTHROUGH
-       case USB_SPEED_LOW:             /* fixed at 8 */
-               i = 8;
-               break;
-       default:
-               goto fail;
-       }
-       dev->epmaxpacketin [0] = i;
-       dev->epmaxpacketout[0] = i;
-
-       for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
-
-               for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
-                       err = usb_set_address(dev);
-                       if (err >= 0)
-                               break;
-                       wait_ms(200);
-               }
-               if (err < 0) {
-                       dev_err(&dev->dev,
-                               "device not accepting address %d, error %d\n",
-                               dev->devnum, err);
-                       goto fail;
-               }
-
-               wait_ms(10);    /* Let the SET_ADDRESS settle */
-
-               /* high and low speed devices don't need this... */
-               err = usb_get_device_descriptor(dev, 8);
-               if (err >= 8)
-                       break;
-               wait_ms(100);
-       }
-
-       if (err < 8) {
-               dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
-               goto fail;
-       }
-       if (dev->speed == USB_SPEED_FULL) {
-               usb_disable_endpoint(dev, 0);
-               usb_endpoint_running(dev, 0, 1);
-               usb_endpoint_running(dev, 0, 0);
-               dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
-               dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
-       }
-
-       /* USB device state == addressed ... still not usable */
-
-       err = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
-       if (err != (signed)sizeof(dev->descriptor)) {
-               dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
-               goto fail;
-       }
-
-       err = usb_get_configuration(dev);
-       if (err < 0) {
-               dev_err(&dev->dev, "can't read configurations, error %d\n",
-                       err);
-               goto fail;
-       }
-
-       /* Tell the world! */
-       dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
-               dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
-
-#ifdef DEBUG
-       if (dev->descriptor.iProduct)
-               usb_show_string(dev, "Product", dev->descriptor.iProduct);
-       if (dev->descriptor.iManufacturer)
-               usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
-       if (dev->descriptor.iSerialNumber)
-               usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
-#endif
-
-       down(&dev->serialize);
-
-       /* put device-specific files into sysfs */
-       err = device_add (&dev->dev);
-       if (err) {
-               dev_err(&dev->dev, "can't device_add, error %d\n", err);
-               up(&dev->serialize);
-               goto fail;
-       }
-       usb_create_driverfs_dev_files (dev);
-
-       /* choose and set the configuration. that registers the interfaces
-        * with the driver core, and lets usb device drivers bind to them.
-        * NOTE:  should interact with hub power budgeting.
-        */
-       config = dev->config[0].desc.bConfigurationValue;
-       if (dev->descriptor.bNumConfigurations != 1) {
-               for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-                       struct usb_interface_descriptor *desc;
-
-                       /* heuristic:  Linux is more likely to have class
-                        * drivers, so avoid vendor-specific interfaces.
-                        */
-                       desc = &dev->config[i].interface[0]
-                                       ->altsetting->desc;
-                       if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
-                               continue;
-                       /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
-                       if (desc->bInterfaceClass == USB_CLASS_COMM
-                                       && desc->bInterfaceSubClass == 2
-                                       && desc->bInterfaceProtocol == 0xff)
-                               continue;
-                       config = dev->config[i].desc.bConfigurationValue;
-                       break;
-               }
-               dev_info(&dev->dev,
-                       "configuration #%d chosen from %d choices\n",
-                       config,
-                       dev->descriptor.bNumConfigurations);
-       }
-       err = usb_set_configuration(dev, config);
-       up(&dev->serialize);
-       if (err) {
-               dev_err(&dev->dev, "can't set config #%d, error %d\n",
-                       config, err);
-               device_del(&dev->dev);
-               goto fail;
-       }
-
-       /* USB device state == configured ... usable */
-
-       /* add a /proc/bus/usb entry */
-       usbfs_add_device(dev);
-
-       return 0;
-fail:
-       dev->state = USB_STATE_DEFAULT;
-       clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-       dev->devnum = -1;
-       return err;
-}
-
 /**
  * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
  * @dev: device the buffer will be used with
@@ -1256,12 +734,12 @@ fail:
 void *usb_buffer_alloc (
        struct usb_device *dev,
        size_t size,
-       int mem_flags,
+       gfp_t mem_flags,
        dma_addr_t *dma
 )
 {
        if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
-               return 0;
+               return NULL;
        return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
 }
 
@@ -1304,6 +782,7 @@ void usb_buffer_free (
  *
  * Reverse the effect of this call with usb_buffer_unmap().
  */
+#if 0
 struct urb *usb_buffer_map (struct urb *urb)
 {
        struct usb_bus          *bus;
@@ -1313,7 +792,7 @@ struct urb *usb_buffer_map (struct urb *urb)
                        || !urb->dev
                        || !(bus = urb->dev->bus)
                        || !(controller = bus->controller))
-               return 0;
+               return NULL;
 
        if (controller->dma_mask) {
                urb->transfer_dma = dma_map_single (controller,
@@ -1333,6 +812,7 @@ struct urb *usb_buffer_map (struct urb *urb)
                                | URB_NO_SETUP_DMA_MAP);
        return urb;
 }
+#endif  /*  0  */
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
  * XXX please determine whether the sync is to transfer ownership of
@@ -1377,6 +857,7 @@ void usb_buffer_dmasync (struct urb *urb)
  *
  * Reverses the effect of usb_buffer_map().
  */
+#if 0
 void usb_buffer_unmap (struct urb *urb)
 {
        struct usb_bus          *bus;
@@ -1403,6 +884,7 @@ void usb_buffer_unmap (struct urb *urb)
        urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
                                | URB_NO_SETUP_DMA_MAP);
 }
+#endif  /*  0  */
 
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
@@ -1507,62 +989,116 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
                        usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
-static int usb_device_suspend(struct device *dev, u32 state)
+static int verify_suspended(struct device *dev, void *unused)
 {
-       struct usb_interface *intf;
-       struct usb_driver *driver;
+       return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
+}
+
+static int usb_generic_suspend(struct device *dev, pm_message_t message)
+{
+       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->driver == NULL) ||
-           (dev->driver == &usb_generic_driver) ||
            (dev->driver_data == &usb_generic_driver_data))
                return 0;
 
        intf = to_usb_interface(dev);
        driver = to_usb_driver(dev->driver);
 
-       if (driver->suspend)
-               return driver->suspend(intf, state);
-       return 0;
+       /* 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);
+               if (status)
+                       dev_err(dev, "%s error %d\n", "suspend", status);
+               else
+                       mark_quiesced(intf);
+       } else {
+               // FIXME else if there's no suspend method, disconnect...
+               dev_warn(dev, "no suspend for driver %s?\n", driver->name);
+               mark_quiesced(intf);
+               status = 0;
+       }
+       return status;
 }
 
-static int usb_device_resume(struct device *dev)
+static int usb_generic_resume(struct device *dev)
 {
-       struct usb_interface *intf;
-       struct usb_driver *driver;
+       struct usb_interface    *intf;
+       struct usb_driver       *driver;
+       struct usb_device       *udev;
+       int                     status;
+
+       if (dev->power.power_state.event == PM_EVENT_ON)
+               return 0;
+
+       /* 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) {
+               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 == &usb_generic_driver) ||
-           (dev->driver_data == &usb_generic_driver_data))
+           (dev->driver_data == &usb_generic_driver_data)) {
+               dev->power.power_state.event = PM_EVENT_FREEZE;
                return 0;
+       }
 
        intf = to_usb_interface(dev);
        driver = to_usb_driver(dev->driver);
 
-       if (driver->resume)
-               return driver->resume(intf);
+       udev = interface_to_usbdev(intf);
+       if (udev->state == USB_STATE_NOTATTACHED)
+               return 0;
+
+       /* if driver was suspended, it has a resume method;
+        * however, sysfs can wrongly mark things as suspended
+        * (on the "no suspend method" FIXME path above)
+        */
+       if (driver->resume) {
+               status = driver->resume(intf);
+               if (status) {
+                       dev_err(dev, "%s error %d\n", "resume", status);
+                       mark_quiesced(intf);
+               }
+       } else
+               dev_warn(dev, "no resume for driver %s?\n", driver->name);
        return 0;
 }
 
 struct bus_type usb_bus_type = {
        .name =         "usb",
        .match =        usb_device_match,
-       .hotplug =      usb_hotplug,
-       .suspend =      usb_device_suspend,
-       .resume =       usb_device_resume,
+       .uevent =       usb_uevent,
+       .suspend =      usb_generic_suspend,
+       .resume =       usb_generic_resume,
 };
 
-#ifndef MODULE
-
-static int __init usb_setup_disable(char *str)
-{
-       nousb = 1;
-       return 1;
-}
-
 /* format to disable USB on kernel command line is: nousb */
-__setup("nousb", usb_setup_disable);
-
-#endif
+__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
 
 /*
  * for external read access to <nousb>
@@ -1577,20 +1113,52 @@ int usb_disabled(void)
  */
 static int __init usb_init(void)
 {
+       int retval;
        if (nousb) {
                pr_info ("%s: USB support disabled\n", usbcore_name);
                return 0;
        }
 
-       bus_register(&usb_bus_type);
-       usb_host_init();
-       usb_major_init();
-       usbfs_init();
-       usb_hub_init();
-
-       driver_register(&usb_generic_driver);
+       retval = bus_register(&usb_bus_type);
+       if (retval) 
+               goto out;
+       retval = usb_host_init();
+       if (retval)
+               goto host_init_failed;
+       retval = usb_major_init();
+       if (retval)
+               goto major_init_failed;
+       retval = usb_register(&usbfs_driver);
+       if (retval)
+               goto driver_register_failed;
+       retval = usbdev_init();
+       if (retval)
+               goto usbdevice_init_failed;
+       retval = usbfs_init();
+       if (retval)
+               goto fs_init_failed;
+       retval = usb_hub_init();
+       if (retval)
+               goto hub_init_failed;
+       retval = driver_register(&usb_generic_driver);
+       if (!retval)
+               goto out;
 
-       return 0;
+       usb_hub_cleanup();
+hub_init_failed:
+       usbfs_cleanup();
+fs_init_failed:
+       usbdev_cleanup();
+usbdevice_init_failed:
+       usb_deregister(&usbfs_driver);
+driver_register_failed:
+       usb_major_cleanup();
+major_init_failed:
+       usb_host_cleanup();
+host_init_failed:
+       bus_unregister(&usb_bus_type);
+out:
+       return retval;
 }
 
 /*
@@ -1605,6 +1173,8 @@ static void __exit usb_exit(void)
        driver_unregister(&usb_generic_driver);
        usb_major_cleanup();
        usbfs_cleanup();
+       usb_deregister(&usbfs_driver);
+       usbdev_cleanup();
        usb_hub_cleanup();
        usb_host_cleanup();
        bus_unregister(&usb_bus_type);
@@ -1618,26 +1188,25 @@ module_exit(usb_exit);
  * These symbols are exported for device (or host controller)
  * driver modules to use.
  */
-EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
-EXPORT_SYMBOL(usb_register);
-EXPORT_SYMBOL(usb_deregister);
 EXPORT_SYMBOL(usb_disabled);
 
-EXPORT_SYMBOL(usb_alloc_dev);
+EXPORT_SYMBOL_GPL(usb_get_intf);
+EXPORT_SYMBOL_GPL(usb_put_intf);
+
 EXPORT_SYMBOL(usb_put_dev);
 EXPORT_SYMBOL(usb_get_dev);
 EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
+EXPORT_SYMBOL(usb_lock_device_for_reset);
+
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_driver_release_interface);
-EXPORT_SYMBOL(usb_match_id);
 EXPORT_SYMBOL(usb_find_interface);
 EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_altnum_to_altsetting);
 
 EXPORT_SYMBOL(usb_reset_device);
-EXPORT_SYMBOL(usb_disconnect);
 
 EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
@@ -1647,11 +1216,11 @@ EXPORT_SYMBOL(usb_get_current_frame_number);
 EXPORT_SYMBOL (usb_buffer_alloc);
 EXPORT_SYMBOL (usb_buffer_free);
 
-EXPORT_SYMBOL (usb_buffer_map);
 #if 0
+EXPORT_SYMBOL (usb_buffer_map);
 EXPORT_SYMBOL (usb_buffer_dmasync);
-#endif
 EXPORT_SYMBOL (usb_buffer_unmap);
+#endif
 
 EXPORT_SYMBOL (usb_buffer_map_sg);
 #if 0