On Wed, Jun 05, 2002 at 09:19:55PM -0700, Greg KH wrote:
>
> Hm, maybe I'll try that out later tonight...
Here's a patch against 2.5.20 that splits out the pci specific parts of
hcd.c into hcd-pci.c. It also removes a bunch of unneeded #includes in
hcd.c (if I've broken compilation on any other archs, because of this,
please let me know.)
Christopher, does this patch make your patch easier?
David, any complaints about this patch?
thanks,
greg k-h
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile Wed Jun 5 22:29:18 2002
+++ b/drivers/usb/core/Makefile Wed Jun 5 22:29:18 2002
@@ -2,10 +2,14 @@
# Makefile for USB Core files and filesystem
#
-export-objs := usb.o hcd.o urb.o message.o config.o
+export-objs := usb.o hcd.o hcd-pci.o urb.o message.o config.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \
config.o
+
+ifeq ($(CONFIG_PCI),y)
+ usbcore-objs += hcd-pci.o
+endif
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += devio.o inode.o drivers.o devices.o
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/hcd-pci.c Wed Jun 5 22:29:18 2002
@@ -0,0 +1,401 @@
+/*
+ * (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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+
+/* 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 */
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+ struct usb_hcd *hcd = __hcd;
+ int start = hcd->state;
+
+ if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ return;
+
+ hcd->driver->irq (hcd);
+ if (hcd->state != start && hcd->state == USB_STATE_HALT)
+ hc_died (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hc_died (struct usb_hcd *hcd)
+{
+ struct list_head *devlist, *urblist;
+ struct hcd_dev *dev;
+ struct urb *urb;
+ unsigned long flags;
+
+ /* flag every pending urb as done */
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_for_each (devlist, &hcd->dev_list) {
+ dev = list_entry (devlist, struct hcd_dev, dev_list);
+ list_for_each (urblist, &dev->urb_list) {
+ urb = list_entry (urblist, struct urb, urb_list);
+ dbg ("shutdown %s urb %p pipe %x, current status %d",
+ hcd->self.bus_name, urb, urb->pipe, urb->status);
+ if (urb->status == -EINPROGRESS)
+ urb->status = -ESHUTDOWN;
+ }
+ }
+ urb = (struct urb *) hcd->rh_timer.data;
+ if (urb)
+ urb->status = -ESHUTDOWN;
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+ if (urb)
+ usb_rh_status_dequeue (hcd, urb);
+ hcd->driver->stop (hcd);
+}
+
+
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c Wed Jun 5 22:29:18 2002
+++ b/drivers/usb/core/hcd.c Wed Jun 5 22:29:18 2002
@@ -23,24 +23,12 @@
*/
#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 */
+#include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
@@ -52,12 +40,6 @@
#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>
-
// #define USB_BANDWIDTH_MESSAGES
@@ -110,9 +92,9 @@
DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */
/* used when updating hcd data */
-static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
-static struct usb_operations hcd_operations;
+struct usb_operations hcd_operations;
/*-------------------------------------------------------------------------*/
@@ -288,7 +270,7 @@
/*
* rh_string - provides manufacturer, product and serial strings for root hub
* @id: the string ID number (1: serial number, 2: product, 3: vendor)
- * @pci_desc: PCI device descriptor for the relevant HC
+ * @hcd: the host controller for this root hub
* @type: string describing our driver
* @data: return packet in UTF-16 LE
* @len: length of the return packet
@@ -559,7 +541,7 @@
/*-------------------------------------------------------------------------*/
-static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
@@ -590,7 +572,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));
@@ -924,327 +906,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,37 +946,6 @@
/*-------------------------------------------------------------------------*/
-static void hc_died (struct usb_hcd *hcd)
-{
- struct list_head *devlist, *urblist;
- struct hcd_dev *dev;
- struct urb *urb;
- unsigned long flags;
-
- /* flag every pending urb as done */
- spin_lock_irqsave (&hcd_data_lock, flags);
- list_for_each (devlist, &hcd->dev_list) {
- dev = list_entry (devlist, struct hcd_dev, dev_list);
- list_for_each (urblist, &dev->urb_list) {
- urb = list_entry (urblist, struct urb, urb_list);
- dbg ("shutdown %s urb %p pipe %x, current status %d",
- hcd->self.bus_name, urb, urb->pipe, urb->status);
- if (urb->status == -EINPROGRESS)
- urb->status = -ESHUTDOWN;
- }
- }
- urb = (struct urb *) hcd->rh_timer.data;
- if (urb)
- urb->status = -ESHUTDOWN;
- spin_unlock_irqrestore (&hcd_data_lock, flags);
-
- if (urb)
- rh_status_dequeue (hcd, urb);
- hcd->driver->stop (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
static void urb_unlink (struct urb *urb)
{
unsigned long flags;
@@ -1677,7 +1307,7 @@
spin_unlock_irqrestore (&urb->lock, flags);
if (urb == (struct urb *) hcd->rh_timer.data) {
- rh_status_dequeue (hcd, urb);
+ usb_rh_status_dequeue (hcd, urb);
retval = 0;
} else {
retval = hcd->driver->urb_dequeue (hcd, urb);
@@ -1751,28 +1381,13 @@
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,
unlink_urb: hcd_unlink_urb,
deallocate: hcd_free_dev,
};
-
-/*-------------------------------------------------------------------------*/
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
-{
- struct usb_hcd *hcd = __hcd;
- int start = hcd->state;
-
- if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
- return;
-
- hcd->driver->irq (hcd);
- if (hcd->state != start && hcd->state == USB_STATE_HALT)
- hc_died (hcd);
-}
/*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h Wed Jun 5 22:29:18 2002
+++ b/drivers/usb/core/hcd.h Wed Jun 5 22:29:18 2002
@@ -161,6 +161,11 @@
};
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_init_bus (struct usb_bus *bus);
+extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
+
+extern spinlock_t hcd_data_lock;
+extern struct usb_operations hcd_operations;
#ifdef CONFIG_PCI
struct pci_dev;
_______________________________________________________________
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