/*-------------------------------------------------------------------------*/
+static void hcd_pci_release(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = bus->hcpriv;
+
+ if (hcd)
+ hcd->driver->hcd_free(hcd);
+}
+
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
if (pci_enable_device (dev) < 0)
return -ENODEV;
- dev->current_state = 0;
- dev->dev.power.power_state = 0;
if (!dev->irq) {
dev_err (&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev));
- retval = -ENODEV;
- goto done;
+ return -ENODEV;
}
if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
len = pci_resource_len (dev, 0);
if (!request_mem_region (resource, len, driver->description)) {
dev_dbg (&dev->dev, "controller already in use\n");
- retval = -EBUSY;
- goto done;
+ return -EBUSY;
}
base = ioremap_nocache (resource, len);
if (base == NULL) {
release_mem_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- goto done;
+ return retval;
}
} else { // UHCI
}
if (region == PCI_ROM_RESOURCE) {
dev_dbg (&dev->dev, "no i/o regions available\n");
- retval = -EBUSY;
- goto done;
+ return -EBUSY;
}
base = (void __iomem *) resource;
}
release_region (resource, len);
dev_err (&dev->dev, "init %s fail, %d\n",
pci_name(dev), retval);
- goto done;
+ return retval;
}
}
// hcd zeroed everything
if ((retval = hcd_buffer_create (hcd)) != 0) {
clean_3:
- kfree (hcd);
+ driver->hcd_free (hcd);
goto clean_2;
}
}
hcd->irq = dev->irq;
- dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp,
+ dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp,
(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
- resource);
+ base);
usb_bus_init (&hcd->self);
hcd->self.op = &usb_hcd_operations;
- hcd->self.release = &usb_hcd_release;
hcd->self.hcpriv = (void *) hcd;
+ hcd->self.release = &hcd_pci_release;
init_timer (&hcd->rh_timer);
INIT_LIST_HEAD (&hcd->dev_list);
usb_hcd_pci_remove (dev);
}
-done:
- if (retval != 0)
- pci_disable_device (dev);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_probe);
}
usb_deregister_bus (&hcd->self);
-
- pci_disable_device(dev);
}
EXPORT_SYMBOL (usb_hcd_pci_remove);
#ifdef CONFIG_PM
-static char __attribute_used__ *pci_state(u32 state)
-{
- switch (state) {
- case 0: return "D0";
- case 1: return "D1";
- case 2: return "D2";
- case 3: return "D3hot";
- case 4: return "D3cold";
- }
- return NULL;
-}
-
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
* PM-sensitive HCDs may already have done this.
*/
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- if (state > 4)
- state = 4;
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "suspend D%d --> D%d\n",
+ dev->current_state, state);
switch (hcd->state) {
-
- /* entry if root hub wasn't yet suspended ... from sysfs,
- * without autosuspend, or if USB_SUSPEND isn't configured.
- */
- case USB_STATE_RUNNING:
- hcd->state = USB_STATE_QUIESCING;
+ case USB_STATE_HALT:
+ dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
+ break;
+ case HCD_STATE_SUSPENDED:
+ dev_dbg (hcd->self.controller, "hcd already suspended\n");
+ break;
+ default:
retval = hcd->driver->suspend (hcd, state);
- if (retval) {
+ if (retval)
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
- break;
- }
- hcd->state = HCD_STATE_SUSPENDED;
- /* FALLTHROUGH */
-
- /* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
- * controller and/or root hub will already have been suspended,
- * but it won't be ready for a PCI resume call.
- *
- * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
- * have been called, otherwise root hub timers still run ...
- */
- case HCD_STATE_SUSPENDED:
- if (state <= dev->current_state)
- break;
-
- /* no DMA or IRQs except in D0 */
- if (!dev->current_state) {
- pci_save_state (dev);
- pci_disable_device (dev);
- free_irq (hcd->irq, hcd);
- }
-
- if (!has_pci_pm) {
- dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
- break;
- }
-
- /* POLICY: ignore D1/D2/D3hot differences;
- * we know D3hot will always work.
- */
- retval = pci_set_power_state (dev, state);
- if (retval < 0 && state < 3) {
- retval = pci_set_power_state (dev, 3);
- if (retval == 0)
- state = 3;
- }
- if (retval == 0) {
- dev_dbg (hcd->self.controller, "--> PCI %s\n",
- pci_state(dev->current_state));
+ else {
+ hcd->state = HCD_STATE_SUSPENDED;
+ pci_save_state (dev, hcd->pci_state);
#ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, state, hcd->remote_wakeup);
pci_enable_wake (dev, 4, hcd->remote_wakeup);
#endif
- } else if (retval < 0) {
- dev_dbg (&dev->dev, "PCI %s suspend fail, %d\n",
- pci_state(state), retval);
- (void) usb_hcd_pci_resume (dev);
- break;
+ /* no DMA or IRQs except in D0 */
+ pci_disable_device (dev);
+ free_irq (hcd->irq, hcd);
+
+ if (has_pci_pm)
+ retval = pci_set_power_state (dev, state);
+ dev->dev.power.power_state = state;
+ if (retval < 0) {
+ dev_dbg (&dev->dev,
+ "PCI suspend fail, %d\n",
+ retval);
+ (void) usb_hcd_pci_resume (dev);
+ }
}
- break;
- default:
- dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
- hcd->state);
- retval = -EINVAL;
- break;
}
-
- /* update power_state **ONLY** to make sysfs happier */
- if (retval == 0)
- dev->dev.power.power_state = state;
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
int has_pci_pm;
hcd = pci_get_drvdata(dev);
+ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (has_pci_pm)
+ dev_dbg(hcd->self.controller, "resume from state D%d\n",
+ dev->current_state);
+
if (hcd->state != HCD_STATE_SUSPENDED) {
dev_dbg (hcd->self.controller,
"can't resume, not suspended!\n");
- return 0;
+ return -EL3HLT;
}
- has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
- /* D3cold resume isn't usually reported this way... */
- dev_dbg(hcd->self.controller, "resume from PCI %s%s\n",
- pci_state(dev->current_state),
- has_pci_pm ? "" : " (legacy)");
-
hcd->state = USB_STATE_RESUMING;
if (has_pci_pm)
"can't restore IRQ after resume!\n");
return retval;
}
- hcd->saw_irq = 0;
- pci_restore_state (dev);
+ pci_set_master (dev);
+ pci_restore_state (dev, hcd->pci_state);
#ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, dev->current_state, 0);
pci_enable_wake (dev, 4, 0);