SVN maintenance:
[reactos.git] / reactos / drivers / usb / cromwell / host / ohci-pci.c
index 0ce7123..a7c3980 100644 (file)
-/*\r
- * OHCI HCD (Host Controller Driver) for USB.\r
- *\r
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>\r
- * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>\r
- * \r
- * [ Initialisation is based on Linus'  ]\r
- * [ uhci code and gregs ohci fragments ]\r
- * [ (C) Copyright 1999 Linus Torvalds  ]\r
- * [ (C) Copyright 1999 Gregory P. Smith]\r
- * \r
- * PCI Bus Glue\r
- *\r
- * This file is licenced under the GPL.\r
- */\r
\r
-#ifdef CONFIG_PMAC_PBOOK\r
-#include <asm/machdep.h>\r
-#include <asm/pmac_feature.h>\r
-#include <asm/pci-bridge.h>\r
-#include <asm/prom.h>\r
-#ifndef CONFIG_PM\r
-#      define CONFIG_PM\r
-#endif\r
-#endif\r
-\r
-#ifndef CONFIG_PCI\r
-#error "This file is PCI bus glue.  CONFIG_PCI must be defined."\r
-#endif\r
-\r
-#include "../linux/pci_ids.h"\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static int __devinit\r
-ohci_pci_start (struct usb_hcd *hcd)\r
-{\r
-       struct ohci_hcd *ohci = hcd_to_ohci (hcd);\r
-       int             ret;\r
-\r
-       DPRINT("ohci_pci_start()\n");\r
-\r
-       if (hcd->pdev) {\r
-               ohci->hcca = pci_alloc_consistent (hcd->pdev,\r
-                               sizeof *ohci->hcca, &ohci->hcca_dma);\r
-               if (!ohci->hcca)\r
-                       return -ENOMEM;\r
-\r
-               /* AMD 756, for most chips (early revs), corrupts register\r
-                * values on read ... so enable the vendor workaround.\r
-                */\r
-               if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD\r
-                               && hcd->pdev->device == 0x740c) {\r
-                       ohci->flags = OHCI_QUIRK_AMD756;\r
-                       ohci_info (ohci, "AMD756 erratum 4 workaround\n");\r
-               }\r
-\r
-               /* FIXME for some of the early AMD 760 southbridges, OHCI\r
-                * won't work at all.  blacklist them.\r
-                */\r
-\r
-               /* Apple's OHCI driver has a lot of bizarre workarounds\r
-                * for this chip.  Evidently control and bulk lists\r
-                * can get confused.  (B&W G3 models, and ...)\r
-                */\r
-               else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI\r
-                               && hcd->pdev->device == 0xc861) {\r
-                       ohci_info (ohci,\r
-                               "WARNING: OPTi workarounds unavailable\n");\r
-               }\r
-\r
-               /* Check for NSC87560. We have to look at the bridge (fn1) to\r
-                * identify the USB (fn2). This quirk might apply to more or\r
-                * even all NSC stuff.\r
-                */\r
-               else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {\r
-                       struct pci_dev  *b, *hc;\r
-\r
-                       hc = hcd->pdev;\r
-                       b  = pci_find_slot (hc->bus->number,\r
-                                       PCI_DEVFN (PCI_SLOT (hc->devfn), 1));\r
-                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO\r
-                                       && b->vendor == PCI_VENDOR_ID_NS) {\r
-                               ohci->flags |= OHCI_QUIRK_SUPERIO;\r
-                               ohci_info (ohci, "Using NSC SuperIO setup\n");\r
-                       }\r
-               }\r
-       \r
-       }\r
-\r
-    memset (ohci->hcca, 0, sizeof (struct ohci_hcca));\r
-       if ((ret = ohci_mem_init (ohci)) < 0) {\r
-               ohci_stop (hcd);\r
-               return ret;\r
-       }\r
-       ohci->regs = hcd->regs;\r
-\r
-    DPRINT("Controller memory init done\n");\r
-\r
-       if (hc_reset (ohci) < 0) {\r
-               ohci_stop (hcd);\r
-               return -ENODEV;\r
-       }\r
-       DPRINT("Controller reset done\n");\r
-\r
-       if (hc_start (ohci) < 0) {\r
-               ohci_err (ohci, "can't start\n");\r
-               ohci_stop (hcd);\r
-               return -EBUSY;\r
-       }\r
-       DPRINT("Controller start done\n");\r
-\r
-#ifdef DEBUG\r
-       ohci_dump (ohci, 1);\r
-#endif\r
-       return 0;\r
-}\r
-\r
-#ifdef CONFIG_PM\r
-\r
-static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       unsigned long           flags;\r
-       u16                     cmd;\r
-\r
-       if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {\r
-               ohci_dbg (ohci, "can't suspend (state is %s)\n",\r
-                       hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));\r
-               return -EIO;\r
-       }\r
-\r
-       /* act as if usb suspend can always be used */\r
-       ohci_dbg (ohci, "suspend to %d\n", state);\r
-       ohci->sleeping = 1;\r
-\r
-       /* First stop processing */\r
-       spin_lock_irqsave (&ohci->lock, flags);\r
-       ohci->hc_control &=\r
-               ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);\r
-       (void) readl (&ohci->regs->intrstatus);\r
-       spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-       /* Wait a frame or two */\r
-       mdelay (1);\r
-       if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)\r
-               mdelay (1);\r
-               \r
-#ifdef CONFIG_PMAC_PBOOK\r
-       if (_machine == _MACH_Pmac)\r
-               disable_irq (hcd->pdev->irq);\r
-       /* else, 2.4 assumes shared irqs -- don't disable */\r
-#endif\r
-\r
-       /* Enable remote wakeup */\r
-       writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,\r
-               &ohci->regs->intrenable);\r
-\r
-       /* Suspend chip and let things settle down a bit */\r
-       ohci->hc_control = OHCI_USB_SUSPEND;\r
-       writel (ohci->hc_control, &ohci->regs->control);\r
-       (void) readl (&ohci->regs->control);\r
-       mdelay (500); /* No schedule here ! */\r
-\r
-       switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {\r
-               case OHCI_USB_RESET:\r
-                       ohci_dbg (ohci, "suspend->reset ?\n");\r
-                       break;\r
-               case OHCI_USB_RESUME:\r
-                       ohci_dbg (ohci, "suspend->resume ?\n");\r
-                       break;\r
-               case OHCI_USB_OPER:\r
-                       ohci_dbg (ohci, "suspend->operational ?\n");\r
-                       break;\r
-               case OHCI_USB_SUSPEND:\r
-                       ohci_dbg (ohci, "suspended\n");\r
-                       break;\r
-       }\r
-\r
-       /* In some rare situations, Apple's OHCI have happily trashed\r
-        * memory during sleep. We disable its bus master bit during\r
-        * suspend\r
-        */\r
-       pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);\r
-       cmd &= ~PCI_COMMAND_MASTER;\r
-       pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);\r
-#ifdef CONFIG_PMAC_PBOOK\r
-       {\r
-               struct device_node      *of_node;\r
\r
-               /* Disable USB PAD & cell clock */\r
-               of_node = pci_device_to_OF_node (hcd->pdev);\r
-               if (of_node)\r
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);\r
-       }\r
-#endif\r
-       return 0;\r
-}\r
-\r
-\r
-static int ohci_pci_resume (struct usb_hcd *hcd)\r
-{\r
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);\r
-       int                     temp;\r
-       int                     retval = 0;\r
-       unsigned long           flags;\r
-\r
-#ifdef CONFIG_PMAC_PBOOK\r
-       {\r
-               struct device_node *of_node;\r
-\r
-               /* Re-enable USB PAD & cell clock */\r
-               of_node = pci_device_to_OF_node (hcd->pdev);\r
-               if (of_node)\r
-                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);\r
-       }\r
-#endif\r
-       /* did we suspend, or were we powered off? */\r
-       ohci->hc_control = readl (&ohci->regs->control);\r
-       temp = ohci->hc_control & OHCI_CTRL_HCFS;\r
-\r
-#ifdef DEBUG\r
-       /* the registers may look crazy here */\r
-       ohci_dump_status (ohci, 0, 0);\r
-#endif\r
-\r
-       /* Re-enable bus mastering */\r
-       pci_set_master (ohci->hcd.pdev);\r
-       \r
-       switch (temp) {\r
-\r
-       case OHCI_USB_RESET:    // lost power\r
-               ohci_info (ohci, "USB restart\n");\r
-               retval = hc_restart (ohci);\r
-               break;\r
-\r
-       case OHCI_USB_SUSPEND:  // host wakeup\r
-       case OHCI_USB_RESUME:   // remote wakeup\r
-               ohci_info (ohci, "USB continue from %s wakeup\n",\r
-                        (temp == OHCI_USB_SUSPEND)\r
-                               ? "host" : "remote");\r
-               ohci->hc_control = OHCI_USB_RESUME;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-               (void) readl (&ohci->regs->control);\r
-               mdelay (20); /* no schedule here ! */\r
-               /* Some controllers (lucent) need a longer delay here */\r
-               mdelay (15);\r
-\r
-               temp = readl (&ohci->regs->control);\r
-               temp = ohci->hc_control & OHCI_CTRL_HCFS;\r
-               if (temp != OHCI_USB_RESUME) {\r
-                       ohci_err (ohci, "controller won't resume\n");\r
-                       ohci->disabled = 1;\r
-                       retval = -EIO;\r
-                       break;\r
-               }\r
-\r
-               /* Some chips likes being resumed first */\r
-               writel (OHCI_USB_OPER, &ohci->regs->control);\r
-               (void) readl (&ohci->regs->control);\r
-               mdelay (3);\r
-\r
-               /* Then re-enable operations */\r
-               spin_lock_irqsave (&ohci->lock, flags);\r
-               ohci->disabled = 0;\r
-               ohci->sleeping = 0;\r
-               ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;\r
-               if (!ohci->ed_rm_list) {\r
-                       if (ohci->ed_controltail)\r
-                               ohci->hc_control |= OHCI_CTRL_CLE;\r
-                       if (ohci->ed_bulktail)\r
-                               ohci->hc_control |= OHCI_CTRL_BLE;\r
-               }\r
-               hcd->state = USB_STATE_READY;\r
-               writel (ohci->hc_control, &ohci->regs->control);\r
-\r
-               /* trigger a start-frame interrupt (why?) */\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);\r
-               writel (OHCI_INTR_SF, &ohci->regs->intrenable);\r
-\r
-               /* Check for a pending done list */\r
-               writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       \r
-               (void) readl (&ohci->regs->intrdisable);\r
-               spin_unlock_irqrestore (&ohci->lock, flags);\r
-\r
-#ifdef CONFIG_PMAC_PBOOK\r
-               if (_machine == _MACH_Pmac)\r
-                       enable_irq (hcd->pdev->irq);\r
-#endif\r
-               if (ohci->hcca->done_head)\r
-                       dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);\r
-               writel (OHCI_INTR_WDH, &ohci->regs->intrenable); \r
-\r
-               /* assume there are TDs on the bulk and control lists */\r
-               writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);\r
-\r
-// ohci_dump_status (ohci);\r
-ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",\r
-               ohci->sleeping, ohci->disabled);\r
-               break;\r
-\r
-       default:\r
-               ohci_warn (ohci, "odd PCI resume\n");\r
-       }\r
-       return retval;\r
-}\r
-\r
-#endif /* CONFIG_PM */\r
-\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-static const struct hc_driver ohci_pci_hc_driver = {\r
-       .description =          hcd_name,\r
-\r
-       /*\r
-        * generic hardware linkage\r
-        */\r
-       .irq =                  ohci_irq,\r
-       .flags =                HCD_MEMORY | HCD_USB11,\r
-\r
-       /*\r
-        * basic lifecycle operations\r
-        */\r
-       .start =                ohci_pci_start,\r
-#ifdef CONFIG_PM\r
-       .suspend =              ohci_pci_suspend,\r
-       .resume =               ohci_pci_resume,\r
-#endif\r
-       .stop =                 ohci_stop,\r
-\r
-       /*\r
-        * memory lifecycle (except per-request)\r
-        */\r
-       .hcd_alloc =            ohci_hcd_alloc,\r
-       .hcd_free =             ohci_hcd_free,\r
-\r
-       /*\r
-        * managing i/o requests and associated device resources\r
-        */\r
-       .urb_enqueue =          ohci_urb_enqueue,\r
-       .urb_dequeue =          ohci_urb_dequeue,\r
-       .endpoint_disable =     ohci_endpoint_disable,\r
-\r
-       /*\r
-        * scheduling support\r
-        */\r
-       .get_frame_number =     ohci_get_frame,\r
-\r
-       /*\r
-        * root hub support\r
-        */\r
-       .hub_status_data =      ohci_hub_status_data,\r
-       .hub_control =          ohci_hub_control,\r
-};\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-const struct pci_device_id __devinitdata pci_ids [] = { {\r
-\r
-       /* handle any USB OHCI controller */\r
-       .class =        (PCI_CLASS_SERIAL_USB << 8) | 0x10,\r
-       .class_mask =   ~0,\r
-       .driver_data =  (unsigned long) &ohci_pci_hc_driver,\r
-\r
-       /* no matter who makes it */\r
-       .vendor =       PCI_ANY_ID,\r
-       .device =       PCI_ANY_ID,\r
-       .subvendor =    PCI_ANY_ID,\r
-       .subdevice =    PCI_ANY_ID,\r
-\r
-       }, { /* end: all zeroes */ }\r
-};\r
-MODULE_DEVICE_TABLE (pci, pci_ids);\r
-\r
-/* pci driver glue; this is a "new style" PCI driver module */\r
-struct pci_driver ohci_pci_driver = {\r
-       .name =         (char *) hcd_name,\r
-       .id_table =     pci_ids,\r
-\r
-       .probe =        usb_hcd_pci_probe,\r
-       .remove =       usb_hcd_pci_remove,\r
-\r
-#ifdef CONFIG_PM\r
-       .suspend =      usb_hcd_pci_suspend,\r
-       .resume =       usb_hcd_pci_resume,\r
-#endif\r
-};\r
-\r
\r
-int ohci_hcd_pci_init (void) \r
-{\r
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);\r
-       if (usb_disabled())\r
-               return -ENODEV;\r
-\r
-       // causes page fault in reactos\r
-       //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,\r
-       //      sizeof (struct ed), sizeof (struct td));\r
-       return pci_module_init (&ohci_pci_driver);\r
-}\r
-/*module_init (ohci_hcd_pci_init);*/\r
-\r
-/*-------------------------------------------------------------------------*/\r
-\r
-void ohci_hcd_pci_cleanup (void) \r
-{      \r
-       pci_unregister_driver (&ohci_pci_driver);\r
-}\r
-/*module_exit (ohci_hcd_pci_cleanup);*/\r
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * PCI Bus Glue
+ *
+ * This file is licenced under the GPL.
+ */
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#ifndef CONFIG_PM
+#      define CONFIG_PM
+#endif
+#endif
+
+#ifndef CONFIG_PCI
+#error "This file is PCI bus glue.  CONFIG_PCI must be defined."
+#endif
+
+#include "../linux/pci_ids.h"
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pci_start (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ret;
+
+       DPRINT("ohci_pci_start()\n");
+
+       if (hcd->pdev) {
+               ohci->hcca = pci_alloc_consistent (hcd->pdev,
+                               sizeof *ohci->hcca, &ohci->hcca_dma);
+               if (!ohci->hcca)
+                       return -ENOMEM;
+
+               /* AMD 756, for most chips (early revs), corrupts register
+                * values on read ... so enable the vendor workaround.
+                */
+               if (hcd->pdev->vendor == PCI_VENDOR_ID_AMD
+                               && hcd->pdev->device == 0x740c) {
+                       ohci->flags = OHCI_QUIRK_AMD756;
+                       ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+               }
+
+               /* FIXME for some of the early AMD 760 southbridges, OHCI
+                * won't work at all.  blacklist them.
+                */
+
+               /* Apple's OHCI driver has a lot of bizarre workarounds
+                * for this chip.  Evidently control and bulk lists
+                * can get confused.  (B&W G3 models, and ...)
+                */
+               else if (hcd->pdev->vendor == PCI_VENDOR_ID_OPTI
+                               && hcd->pdev->device == 0xc861) {
+                       ohci_info (ohci,
+                               "WARNING: OPTi workarounds unavailable\n");
+               }
+
+               /* Check for NSC87560. We have to look at the bridge (fn1) to
+                * identify the USB (fn2). This quirk might apply to more or
+                * even all NSC stuff.
+                */
+               else if (hcd->pdev->vendor == PCI_VENDOR_ID_NS) {
+                       struct pci_dev  *b, *hc;
+
+                       hc = hcd->pdev;
+                       b  = pci_find_slot (hc->bus->number,
+                                       PCI_DEVFN (PCI_SLOT (hc->devfn), 1));
+                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+                                       && b->vendor == PCI_VENDOR_ID_NS) {
+                               ohci->flags |= OHCI_QUIRK_SUPERIO;
+                               ohci_info (ohci, "Using NSC SuperIO setup\n");
+                       }
+               }
+       
+       }
+
+    memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+       if ((ret = ohci_mem_init (ohci)) < 0) {
+               ohci_stop (hcd);
+               return ret;
+       }
+       ohci->regs = hcd->regs;
+
+    DPRINT("Controller memory init done\n");
+
+       if (hc_reset (ohci) < 0) {
+               ohci_stop (hcd);
+               return -ENODEV;
+       }
+       DPRINT("Controller reset done\n");
+
+       if (hc_start (ohci) < 0) {
+               ohci_err (ohci, "can't start\n");
+               ohci_stop (hcd);
+               return -EBUSY;
+       }
+       DPRINT("Controller start done\n");
+
+#ifdef DEBUG
+       ohci_dump (ohci, 1);
+#endif
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       unsigned long           flags;
+       u16                     cmd;
+
+       if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+               ohci_dbg (ohci, "can't suspend (state is %s)\n",
+                       hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+               return -EIO;
+       }
+
+       /* act as if usb suspend can always be used */
+       ohci_dbg (ohci, "suspend to %d\n", state);
+       ohci->sleeping = 1;
+
+       /* First stop processing */
+       spin_lock_irqsave (&ohci->lock, flags);
+       ohci->hc_control &=
+               ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+       writel (ohci->hc_control, &ohci->regs->control);
+       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+       (void) readl (&ohci->regs->intrstatus);
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       /* Wait a frame or two */
+       mdelay (1);
+       if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+               mdelay (1);
+               
+#ifdef CONFIG_PMAC_PBOOK
+       if (_machine == _MACH_Pmac)
+               disable_irq (hcd->pdev->irq);
+       /* else, 2.4 assumes shared irqs -- don't disable */
+#endif
+
+       /* Enable remote wakeup */
+       writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
+               &ohci->regs->intrenable);
+
+       /* Suspend chip and let things settle down a bit */
+       ohci->hc_control = OHCI_USB_SUSPEND;
+       writel (ohci->hc_control, &ohci->regs->control);
+       (void) readl (&ohci->regs->control);
+       mdelay (500); /* No schedule here ! */
+
+       switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+               case OHCI_USB_RESET:
+                       ohci_dbg (ohci, "suspend->reset ?\n");
+                       break;
+               case OHCI_USB_RESUME:
+                       ohci_dbg (ohci, "suspend->resume ?\n");
+                       break;
+               case OHCI_USB_OPER:
+                       ohci_dbg (ohci, "suspend->operational ?\n");
+                       break;
+               case OHCI_USB_SUSPEND:
+                       ohci_dbg (ohci, "suspended\n");
+                       break;
+       }
+
+       /* In some rare situations, Apple's OHCI have happily trashed
+        * memory during sleep. We disable its bus master bit during
+        * suspend
+        */
+       pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+       cmd &= ~PCI_COMMAND_MASTER;
+       pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+       {
+               struct device_node      *of_node;
+               /* Disable USB PAD & cell clock */
+               of_node = pci_device_to_OF_node (hcd->pdev);
+               if (of_node)
+                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+       }
+#endif
+       return 0;
+}
+
+
+static int ohci_pci_resume (struct usb_hcd *hcd)
+{
+       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
+       int                     temp;
+       int                     retval = 0;
+       unsigned long           flags;
+
+#ifdef CONFIG_PMAC_PBOOK
+       {
+               struct device_node *of_node;
+
+               /* Re-enable USB PAD & cell clock */
+               of_node = pci_device_to_OF_node (hcd->pdev);
+               if (of_node)
+                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+       }
+#endif
+       /* did we suspend, or were we powered off? */
+       ohci->hc_control = readl (&ohci->regs->control);
+       temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+       /* the registers may look crazy here */
+       ohci_dump_status (ohci, 0, 0);
+#endif
+
+       /* Re-enable bus mastering */
+       pci_set_master (ohci->hcd.pdev);
+       
+       switch (temp) {
+
+       case OHCI_USB_RESET:    // lost power
+               ohci_info (ohci, "USB restart\n");
+               retval = hc_restart (ohci);
+               break;
+
+       case OHCI_USB_SUSPEND:  // host wakeup
+       case OHCI_USB_RESUME:   // remote wakeup
+               ohci_info (ohci, "USB continue from %s wakeup\n",
+                        (temp == OHCI_USB_SUSPEND)
+                               ? "host" : "remote");
+               ohci->hc_control = OHCI_USB_RESUME;
+               writel (ohci->hc_control, &ohci->regs->control);
+               (void) readl (&ohci->regs->control);
+               mdelay (20); /* no schedule here ! */
+               /* Some controllers (lucent) need a longer delay here */
+               mdelay (15);
+
+               temp = readl (&ohci->regs->control);
+               temp = ohci->hc_control & OHCI_CTRL_HCFS;
+               if (temp != OHCI_USB_RESUME) {
+                       ohci_err (ohci, "controller won't resume\n");
+                       ohci->disabled = 1;
+                       retval = -EIO;
+                       break;
+               }
+
+               /* Some chips likes being resumed first */
+               writel (OHCI_USB_OPER, &ohci->regs->control);
+               (void) readl (&ohci->regs->control);
+               mdelay (3);
+
+               /* Then re-enable operations */
+               spin_lock_irqsave (&ohci->lock, flags);
+               ohci->disabled = 0;
+               ohci->sleeping = 0;
+               ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+               if (!ohci->ed_rm_list) {
+                       if (ohci->ed_controltail)
+                               ohci->hc_control |= OHCI_CTRL_CLE;
+                       if (ohci->ed_bulktail)
+                               ohci->hc_control |= OHCI_CTRL_BLE;
+               }
+               hcd->state = USB_STATE_READY;
+               writel (ohci->hc_control, &ohci->regs->control);
+
+               /* trigger a start-frame interrupt (why?) */
+               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+
+               /* Check for a pending done list */
+               writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       
+               (void) readl (&ohci->regs->intrdisable);
+               spin_unlock_irqrestore (&ohci->lock, flags);
+
+#ifdef CONFIG_PMAC_PBOOK
+               if (_machine == _MACH_Pmac)
+                       enable_irq (hcd->pdev->irq);
+#endif
+               if (ohci->hcca->done_head)
+                       dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
+               writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+
+               /* assume there are TDs on the bulk and control lists */
+               writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
+
+// ohci_dump_status (ohci);
+ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
+               ohci->sleeping, ohci->disabled);
+               break;
+
+       default:
+               ohci_warn (ohci, "odd PCI resume\n");
+       }
+       return retval;
+}
+
+#endif /* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pci_hc_driver = {
+       .description =          hcd_name,
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_MEMORY | HCD_USB11,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_pci_start,
+#ifdef CONFIG_PM
+       .suspend =              ohci_pci_suspend,
+       .resume =               ohci_pci_resume,
+#endif
+       .stop =                 ohci_stop,
+
+       /*
+        * memory lifecycle (except per-request)
+        */
+       .hcd_alloc =            ohci_hcd_alloc,
+       .hcd_free =             ohci_hcd_free,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+const struct pci_device_id __devinitdata pci_ids [] = { {
+
+       /* handle any USB OHCI controller */
+       .class =        (PCI_CLASS_SERIAL_USB << 8) | 0x10,
+       .class_mask =   ~0,
+       .driver_data =  (unsigned long) &ohci_pci_hc_driver,
+
+       /* no matter who makes it */
+       .vendor =       PCI_ANY_ID,
+       .device =       PCI_ANY_ID,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
+
+       }, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+struct pci_driver ohci_pci_driver = {
+       .name =         (char *) hcd_name,
+       .id_table =     pci_ids,
+
+       .probe =        usb_hcd_pci_probe,
+       .remove =       usb_hcd_pci_remove,
+
+#ifdef CONFIG_PM
+       .suspend =      usb_hcd_pci_suspend,
+       .resume =       usb_hcd_pci_resume,
+#endif
+};
+
+int ohci_hcd_pci_init (void) 
+{
+       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
+       if (usb_disabled())
+               return -ENODEV;
+
+       // causes page fault in reactos
+       //printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+       //      sizeof (struct ed), sizeof (struct td));
+       return pci_module_init (&ohci_pci_driver);
+}
+/*module_init (ohci_hcd_pci_init);*/
+
+/*-------------------------------------------------------------------------*/
+
+void ohci_hcd_pci_cleanup (void) 
+{      
+       pci_unregister_driver (&ohci_pci_driver);
+}
+/*module_exit (ohci_hcd_pci_cleanup);*/