-/*\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);*/