# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.466 -> 1.467
# drivers/usb/core/hcd.h 1.8 -> 1.9
# drivers/usb/core/hcd.c 1.21 -> 1.22
# drivers/usb/core/Makefile 1.7 -> 1.8
# (new) -> 1.1 drivers/usb/core/hcd-pci.c
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/06 [EMAIL PROTECTED] 1.467
# USB: split some pci specific pieces out of hcd.c into a separate file.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile Thu Jun 6 14:38:23 2002
+++ b/drivers/usb/core/Makefile Thu Jun 6 14:38:23 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 Thu Jun 6 14:38:23 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 Thu Jun 6 14:38:23 2002
+++ b/drivers/usb/core/hcd.c Thu Jun 6 14:38:23 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 Thu Jun 6 14:38:23 2002
+++ b/drivers/usb/core/hcd.h Thu Jun 6 14:38:23 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