# 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 greg@kroah.com 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 +#include +#include +#include + +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#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 -#include #include -#include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include #include /* for UTS_SYSNAME */ +#include #ifdef CONFIG_USB_DEBUG @@ -52,12 +40,6 @@ #include #include "hcd.h" -#include -#include -#include -#include -#include - // #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;