diff -X dontdiff.txt -Naur linux-2.5.20/drivers/usb/core/hcd.c 
linux-2.5.20-usbwork/drivers/usb/core/hcd.c
--- linux-2.5.20/drivers/usb/core/hcd.c Sun Jun  2 18:44:50 2002
+++ linux-2.5.20-usbwork/drivers/usb/core/hcd.c Wed Jun  5 17:46:26 2002
@@ -44,9 +44,9 @@
 
 
 #ifdef CONFIG_USB_DEBUG
-       #define DEBUG
+#      define DEBUG
 #else
-       #undef DEBUG
+#      undef DEBUG
 #endif
 
 #include <linux/usb.h>
@@ -58,7 +58,6 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
-
 // #define USB_BANDWIDTH_MESSAGES
 
 /*-------------------------------------------------------------------------*/
@@ -112,7 +111,8 @@
 /* used when updating hcd data */
 static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
 
-static struct usb_operations hcd_operations;
+struct usb_operations hcd_operations;
+EXPORT_SYMBOL(hcd_operations);
 
 /*-------------------------------------------------------------------------*/
 
@@ -590,7 +590,7 @@
 /*-------------------------------------------------------------------------*/
 
 /* shared initialization code */
-static void usb_init_bus (struct usb_bus *bus)
+void usb_init_bus (struct usb_bus *bus)
 {
        memset (&bus->devmap, 0, sizeof(struct usb_devmap));
 
@@ -609,6 +609,7 @@
 
        atomic_set (&bus->refcnt, 1);
 }
+EXPORT_SYMBOL (usb_init_bus);
 
 /**
  * usb_alloc_bus - creates a new USB host controller structure
@@ -924,327 +925,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_PCI
-
-/* PCI-based HCs are normal, but custom bus glue should be ok */
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
-static void hc_died (struct usb_hcd *hcd);
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-/**
- * usb_hcd_pci_probe - initialize PCI-based HCDs
- * @dev: USB Host Controller being probed
- * @id: pci hotplug id connecting controller to HCD framework
- * Context: !in_interrupt()
- *
- * Allocates basic PCI resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
- */
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct hc_driver        *driver;
-       unsigned long           resource, len;
-       void                    *base;
-       u8                      latency, limit;
-       struct usb_hcd          *hcd;
-       int                     retval, region;
-       char                    buf [8], *bufp = buf;
-
-       if (!id || !(driver = (struct hc_driver *) id->driver_data))
-               return -EINVAL;
-
-       if (pci_enable_device (dev) < 0)
-               return -ENODEV;
-       
-        if (!dev->irq) {
-               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
-                       dev->slot_name);
-               return -ENODEV;
-        }
-       
-       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
-               region = 0;
-               resource = pci_resource_start (dev, 0);
-               len = pci_resource_len (dev, 0);
-               if (!request_mem_region (resource, len, driver->description)) {
-                       dbg ("controller already in use");
-                       return -EBUSY;
-               }
-               base = ioremap_nocache (resource, len);
-               if (base == NULL) {
-                       dbg ("error mapping memory");
-                       retval = -EFAULT;
-clean_1:
-                       release_mem_region (resource, len);
-                       err ("init %s fail, %d", dev->slot_name, retval);
-                       return retval;
-               }
-
-       } else {                                // UHCI
-               resource = len = 0;
-               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
-                               continue;
-
-                       resource = pci_resource_start (dev, region);
-                       len = pci_resource_len (dev, region);
-                       if (request_region (resource, len,
-                                       driver->description))
-                               break;
-               }
-               if (region == PCI_ROM_RESOURCE) {
-                       dbg ("no i/o regions available");
-                       return -EBUSY;
-               }
-               base = (void *) resource;
-       }
-
-       // driver->start(), later on, will transfer device from
-       // control by SMM/BIOS to control by Linux (if needed)
-
-       pci_set_master (dev);
-       hcd = driver->hcd_alloc ();
-       if (hcd == NULL){
-               dbg ("hcd alloc fail");
-               retval = -ENOMEM;
-clean_2:
-               if (driver->flags & HCD_MEMORY) {
-                       iounmap (base);
-                       goto clean_1;
-               } else {
-                       release_region (resource, len);
-                       err ("init %s fail, %d", dev->slot_name, retval);
-                       return retval;
-               }
-       }
-       pci_set_drvdata(dev, hcd);
-       hcd->driver = driver;
-       hcd->description = driver->description;
-       hcd->pdev = dev;
-       info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
-
-       pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
-       if (latency) {
-               pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
-               if (limit && limit < latency) {
-                       dbg ("PCI latency reduced to max %d", limit);
-                       pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
-               }
-       }
-
-#ifndef __sparc__
-       sprintf (buf, "%d", dev->irq);
-#else
-       bufp = __irq_itoa(dev->irq);
-#endif
-       if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
-                       != 0) {
-               err ("request interrupt %s failed", bufp);
-               retval = -EBUSY;
-               driver->hcd_free (hcd);
-               goto clean_2;
-       }
-       hcd->irq = dev->irq;
-
-       hcd->regs = base;
-       hcd->region = region;
-       info ("irq %s, %s %p", bufp,
-               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
-               base);
-
-       usb_init_bus (&hcd->self);
-       hcd->self.op = &hcd_operations;
-       hcd->self.hcpriv = (void *) hcd;
-       hcd->self.bus_name = dev->slot_name;
-       hcd->product_desc = dev->name;
-
-       INIT_LIST_HEAD (&hcd->dev_list);
-
-       usb_register_bus (&hcd->self);
-
-       if ((retval = driver->start (hcd)) < 0)
-               usb_hcd_pci_remove (dev);
-
-       return retval;
-} 
-EXPORT_SYMBOL (usb_hcd_pci_probe);
-
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_pci_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- *
- * Store this function in the HCD's struct pci_driver as remove().
- */
-void usb_hcd_pci_remove (struct pci_dev *dev)
-{
-       struct usb_hcd          *hcd;
-       struct usb_device       *hub;
-
-       hcd = pci_get_drvdata(dev);
-       if (!hcd)
-               return;
-       info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-       if (in_interrupt ()) BUG ();
-
-       hub = hcd->self.root_hub;
-       hcd->state = USB_STATE_QUIESCING;
-
-       dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
-       usb_disconnect (&hub);
-
-       hcd->driver->stop (hcd);
-       hcd->state = USB_STATE_HALT;
-
-       free_irq (hcd->irq, hcd);
-       if (hcd->driver->flags & HCD_MEMORY) {
-               iounmap (hcd->regs);
-               release_mem_region (pci_resource_start (dev, 0),
-                       pci_resource_len (dev, 0));
-       } else {
-               release_region (pci_resource_start (dev, hcd->region),
-                       pci_resource_len (dev, hcd->region));
-       }
-
-       usb_deregister_bus (&hcd->self);
-       if (atomic_read (&hcd->self.refcnt) != 1)
-               err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
-
-       hcd->driver->hcd_free (hcd);
-}
-EXPORT_SYMBOL (usb_hcd_pci_remove);
-
-
-#ifdef CONFIG_PM
-
-/*
- * Some "sleep" power levels imply updating struct usb_driver
- * to include a callback asking hcds to do their bit by checking
- * if all the drivers can suspend.  Gets involved with remote wakeup.
- *
- * If there are pending urbs, then HCs will need to access memory,
- * causing extra power drain.  New sleep()/wakeup() PM calls might
- * be needed, beyond PCI suspend()/resume().  The root hub timer
- * still be accessing memory though ...
- *
- * FIXME:  USB should have some power budgeting support working with
- * all kinds of hubs.
- *
- * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
- * D1 and D2 states should do something, yes?
- *
- * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
- * for all supported states, so that USB remote wakeup can work for any
- * devices that support it (and are connected via powered hubs).
- *
- * FIXME:  resume doesn't seem to work right any more...
- */
-
-
-// 2.4 kernels have issued concurrent resumes (w/APM)
-// we defend against that error; PCI doesn't yet.
-
-/**
- * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
- * @dev: USB Host Controller being suspended
- *
- * Store this function in the HCD's struct pci_driver as suspend().
- */
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
-{
-       struct usb_hcd          *hcd;
-       int                     retval;
-
-       hcd = pci_get_drvdata(dev);
-       info ("suspend %s to state %d", hcd->self.bus_name, state);
-
-       pci_save_state (dev, hcd->pci_state);
-
-       // FIXME for all connected devices, leaf-to-root:
-       // driver->suspend()
-       // proposed "new 2.5 driver model" will automate that
-
-       /* driver may want to disable DMA etc */
-       retval = hcd->driver->suspend (hcd, state);
-       hcd->state = USB_STATE_SUSPENDED;
-
-       pci_set_power_state (dev, state);
-       return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_suspend);
-
-/**
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD
- * @dev: USB Host Controller being resumed
- *
- * Store this function in the HCD's struct pci_driver as resume().
- */
-int usb_hcd_pci_resume (struct pci_dev *dev)
-{
-       struct usb_hcd          *hcd;
-       int                     retval;
-
-       hcd = pci_get_drvdata(dev);
-       info ("resume %s", hcd->self.bus_name);
-
-       /* guard against multiple resumes (APM bug?) */
-       atomic_inc (&hcd->resume_count);
-       if (atomic_read (&hcd->resume_count) != 1) {
-               err ("concurrent PCI resumes for %s", hcd->self.bus_name);
-               retval = 0;
-               goto done;
-       }
-
-       retval = -EBUSY;
-       if (hcd->state != USB_STATE_SUSPENDED) {
-               dbg ("can't resume, not suspended!");
-               goto done;
-       }
-       hcd->state = USB_STATE_RESUMING;
-
-       pci_set_power_state (dev, 0);
-       pci_restore_state (dev, hcd->pci_state);
-
-       retval = hcd->driver->resume (hcd);
-       if (!HCD_IS_RUNNING (hcd->state)) {
-               dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
-               hc_died (hcd);
-// FIXME:  recover, reset etc.
-       } else {
-               // FIXME for all connected devices, root-to-leaf:
-               // driver->resume ();
-               // proposed "new 2.5 driver model" will automate that
-       }
-
-done:
-       atomic_dec (&hcd->resume_count);
-       return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_resume);
-
-#endif /* CONFIG_PM */
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
 /*
  * Generic HC operations.
  */
@@ -1285,7 +965,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void hc_died (struct usb_hcd *hcd)
+void usb_hc_died (struct usb_hcd *hcd)
 {
        struct list_head        *devlist, *urblist;
        struct hcd_dev          *dev;
@@ -1313,6 +993,7 @@
                rh_status_dequeue (hcd, urb);
        hcd->driver->stop (hcd);
 }
+EXPORT_SYMBOL(usb_hc_died);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1751,7 +1432,7 @@
        return 0;
 }
 
-static struct usb_operations hcd_operations = {
+struct usb_operations hcd_operations = {
        allocate:               hcd_alloc_dev,
        get_frame_number:       hcd_get_frame_number,
        submit_urb:             hcd_submit_urb,
@@ -1761,7 +1442,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+void usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
 {
        struct usb_hcd          *hcd = __hcd;
        int                     start = hcd->state;
@@ -1771,8 +1452,9 @@
 
        hcd->driver->irq (hcd);
        if (hcd->state != start && hcd->state == USB_STATE_HALT)
-               hc_died (hcd);
+               usb_hc_died (hcd);
 }
+EXPORT_SYMBOL (usb_hcd_irq);
 
 /*-------------------------------------------------------------------------*/
 
diff -X dontdiff.txt -Naur linux-2.5.20/drivers/usb/core/hcd.h 
linux-2.5.20-usbwork/drivers/usb/core/hcd.h
--- linux-2.5.20/drivers/usb/core/hcd.h Sun Jun  2 18:44:46 2002
+++ linux-2.5.20-usbwork/drivers/usb/core/hcd.h Wed Jun  5 18:05:02 2002
@@ -50,9 +50,9 @@
        int                     irq;            /* irq allocated */
        void                    *regs;          /* device memory/io */
 
-#ifdef CONFIG_PCI
        /* a few non-PCI controllers exist, mostly for OHCI */
        struct pci_dev          *pdev;          /* pci is typical */
+#ifdef CONFIG_PCI
        int                     region;         /* pci region for regs */
        u32                     pci_state [16]; /* for PM state save */
        atomic_t                resume_count;   /* multiple resumes issue */
@@ -161,6 +161,9 @@
 };
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+extern void usb_hc_died (struct usb_hcd *hcd);
+
 
 #ifdef CONFIG_PCI
 struct pci_dev;
@@ -181,6 +184,8 @@
 
 /* -------------------------------------------------------------------------- */
 
+extern struct usb_operations hcd_operations;
+
 /* Enumeration is only for the hub driver, or HCD virtual root hubs */
 extern int usb_new_device(struct usb_device *dev);
 extern void usb_connect(struct usb_device *dev);
@@ -281,6 +286,7 @@
 
 /*-------------------------------------------------------------------------*/
 
+extern void usb_init_bus (struct usb_bus *bus);
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 extern void usb_free_bus (struct usb_bus *);
 
diff -X dontdiff.txt -Naur linux-2.5.20/drivers/usb/core/hcd-pci.c 
linux-2.5.20-usbwork/drivers/usb/core/hcd-pci.c
--- linux-2.5.20/drivers/usb/core/hcd-pci.c     Wed Dec 31 16:00:00 1969
+++ linux-2.5.20-usbwork/drivers/usb/core/hcd-pci.c     Wed Jun  5 18:22:52 2002
@@ -0,0 +1,380 @@
+/*
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This is PCI bus glue.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/uts.h>                 /* for UTS_SYSNAME */
+
+
+#ifdef CONFIG_USB_DEBUG
+#      define DEBUG
+#else
+#      undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct hc_driver        *driver;
+       unsigned long           resource, len;
+       void                    *base;
+       u8                      latency, limit;
+       struct usb_hcd          *hcd;
+       int                     retval, region;
+       char                    buf [8], *bufp = buf;
+
+       if (!id || !(driver = (struct hc_driver *) id->driver_data))
+               return -EINVAL;
+
+       if (pci_enable_device (dev) < 0)
+               return -ENODEV;
+       
+        if (!dev->irq) {
+               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+                       dev->slot_name);
+               return -ENODEV;
+        }
+       
+       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
+               region = 0;
+               resource = pci_resource_start (dev, 0);
+               len = pci_resource_len (dev, 0);
+               if (!request_mem_region (resource, len, driver->description)) {
+                       dbg ("controller already in use");
+                       return -EBUSY;
+               }
+               base = ioremap_nocache (resource, len);
+               if (base == NULL) {
+                       dbg ("error mapping memory");
+                       retval = -EFAULT;
+clean_1:
+                       release_mem_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+
+       } else {                                // UHCI
+               resource = len = 0;
+               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+                               continue;
+
+                       resource = pci_resource_start (dev, region);
+                       len = pci_resource_len (dev, region);
+                       if (request_region (resource, len,
+                                       driver->description))
+                               break;
+               }
+               if (region == PCI_ROM_RESOURCE) {
+                       dbg ("no i/o regions available");
+                       return -EBUSY;
+               }
+               base = (void *) resource;
+       }
+
+       // driver->start(), later on, will transfer device from
+       // control by SMM/BIOS to control by Linux (if needed)
+
+       pci_set_master (dev);
+       hcd = driver->hcd_alloc ();
+       if (hcd == NULL){
+               dbg ("hcd alloc fail");
+               retval = -ENOMEM;
+clean_2:
+               if (driver->flags & HCD_MEMORY) {
+                       iounmap (base);
+                       goto clean_1;
+               } else {
+                       release_region (resource, len);
+                       err ("init %s fail, %d", dev->slot_name, retval);
+                       return retval;
+               }
+       }
+       pci_set_drvdata(dev, hcd);
+       hcd->driver = driver;
+       hcd->description = driver->description;
+       hcd->pdev = dev;
+       info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+
+       pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+       if (latency) {
+               pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+               if (limit && limit < latency) {
+                       dbg ("PCI latency reduced to max %d", limit);
+                       pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+               }
+       }
+
+#ifndef __sparc__
+       sprintf (buf, "%d", dev->irq);
+#else
+       bufp = __irq_itoa(dev->irq);
+#endif
+       if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
+                       != 0) {
+               err ("request interrupt %s failed", bufp);
+               retval = -EBUSY;
+               driver->hcd_free (hcd);
+               goto clean_2;
+       }
+       hcd->irq = dev->irq;
+
+       hcd->regs = base;
+       hcd->region = region;
+       info ("irq %s, %s %p", bufp,
+               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+               base);
+
+       usb_init_bus (&hcd->self);
+       hcd->self.op = &hcd_operations;
+       hcd->self.hcpriv = (void *) hcd;
+       hcd->self.bus_name = dev->slot_name;
+       hcd->product_desc = dev->name;
+
+       INIT_LIST_HEAD (&hcd->dev_list);
+
+       usb_register_bus (&hcd->self);
+
+       if ((retval = driver->start (hcd)) < 0)
+               usb_hcd_pci_remove (dev);
+
+       return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       struct usb_device       *hub;
+
+       hcd = pci_get_drvdata(dev);
+       if (!hcd)
+               return;
+       info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+       if (in_interrupt ()) BUG ();
+
+       hub = hcd->self.root_hub;
+       hcd->state = USB_STATE_QUIESCING;
+
+       dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
+       usb_disconnect (&hub);
+
+       hcd->driver->stop (hcd);
+       hcd->state = USB_STATE_HALT;
+
+       free_irq (hcd->irq, hcd);
+       if (hcd->driver->flags & HCD_MEMORY) {
+               iounmap (hcd->regs);
+               release_mem_region (pci_resource_start (dev, 0),
+                       pci_resource_len (dev, 0));
+       } else {
+               release_region (pci_resource_start (dev, hcd->region),
+                       pci_resource_len (dev, hcd->region));
+       }
+
+       usb_deregister_bus (&hcd->self);
+       if (atomic_read (&hcd->self.refcnt) != 1)
+               err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
+
+       hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = pci_get_drvdata(dev);
+       info ("suspend %s to state %d", hcd->self.bus_name, state);
+
+       pci_save_state (dev, hcd->pci_state);
+
+       // FIXME for all connected devices, leaf-to-root:
+       // driver->suspend()
+       // proposed "new 2.5 driver model" will automate that
+
+       /* driver may want to disable DMA etc */
+       retval = hcd->driver->suspend (hcd, state);
+       hcd->state = USB_STATE_SUSPENDED;
+
+       pci_set_power_state (dev, state);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+       int                     retval;
+
+       hcd = pci_get_drvdata(dev);
+       info ("resume %s", hcd->self.bus_name);
+
+       /* guard against multiple resumes (APM bug?) */
+       atomic_inc (&hcd->resume_count);
+       if (atomic_read (&hcd->resume_count) != 1) {
+               err ("concurrent PCI resumes for %s", hcd->self.bus_name);
+               retval = 0;
+               goto done;
+       }
+
+       retval = -EBUSY;
+       if (hcd->state != USB_STATE_SUSPENDED) {
+               dbg ("can't resume, not suspended!");
+               goto done;
+       }
+       hcd->state = USB_STATE_RESUMING;
+
+       pci_set_power_state (dev, 0);
+       pci_restore_state (dev, hcd->pci_state);
+
+       retval = hcd->driver->resume (hcd);
+       if (!HCD_IS_RUNNING (hcd->state)) {
+               dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
+               usb_hc_died (hcd);
+// FIXME:  recover, reset etc.
+       } else {
+               // FIXME for all connected devices, root-to-leaf:
+               // driver->resume ();
+               // proposed "new 2.5 driver model" will automate that
+       }
+
+done:
+       atomic_dec (&hcd->resume_count);
+       return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif /* CONFIG_PM */
+
+#endif
+

_______________________________________________________________

Don't miss the 2002 Sprint PCS Application Developer's Conference
August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm

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

Reply via email to