This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / usb / core / hcd-pci.c
index 0a273a8..5fdaae0 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
+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 */
 
@@ -70,15 +78,12 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
 
        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
@@ -87,8 +92,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
                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) {
@@ -98,7 +102,7 @@ clean_1:
                        release_mem_region (resource, len);
                        dev_err (&dev->dev, "init %s fail, %d\n",
                                pci_name(dev), retval);
-                       goto done;
+                       return retval;
                }
 
        } else {                                // UHCI
@@ -115,8 +119,7 @@ clean_1:
                }
                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;
        }
@@ -136,7 +139,7 @@ clean_2:
                        release_region (resource, len);
                        dev_err (&dev->dev, "init %s fail, %d\n",
                                pci_name(dev), retval);
-                       goto done;
+                       return retval;
                }
        }
        // hcd zeroed everything
@@ -157,7 +160,7 @@ clean_2:
 
        if ((retval = hcd_buffer_create (hcd)) != 0) {
 clean_3:
-               kfree (hcd);
+               driver->hcd_free (hcd);
                goto clean_2;
        }
 
@@ -185,14 +188,14 @@ clean_3:
        }
        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);
@@ -204,9 +207,6 @@ clean_3:
                usb_hcd_pci_remove (dev);
        }
 
-done:
-       if (retval != 0)
-               pci_disable_device (dev);
        return retval;
 } 
 EXPORT_SYMBOL (usb_hcd_pci_probe);
@@ -260,26 +260,12 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
        }
 
        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
@@ -300,82 +286,45 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
         * 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);
@@ -393,18 +342,16 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
        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)
@@ -417,8 +364,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
                        "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);