# 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.481 -> 1.482 # drivers/usb/host/ohci-hcd.c 1.15 -> 1.16 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/06/13 david-b@pacbell.net 1.482 # [PATCH] ohci-hcd init err detect # # Here's a followup patch, should apply on top of what I sent # this morning ... please do so! (Sorry, same name but the # patch is different.) # # Along with some cleanups, this actually restores a line that # was dropped somewhere in 2.5 ... basically, at least SiS and # OPTi violate the OHCI spec so they don't init "by the book". # -------------------------------------------- # diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Fri Jun 14 14:15:33 2002 +++ b/drivers/usb/host/ohci-hcd.c Fri Jun 14 14:15:33 2002 @@ -106,7 +106,6 @@ /*-------------------------------------------------------------------------*/ -#define OHCI_USE_NPS // force NoPowerSwitching mode // #define OHCI_VERBOSE_DEBUG /* not always helpful */ /* For initializing controller (mask in an HCFS mode too) */ @@ -349,22 +348,23 @@ static int hc_reset (struct ohci_hcd *ohci) { - int timeout = 30; - int smm_timeout = 50; /* 0,5 sec */ - - if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */ + u32 temp; + + /* SMM owns the HC? not for long! */ + if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { + temp = 50; /* arbitrary: half second */ writel (OHCI_INTR_OC, &ohci->regs->intrenable); writel (OHCI_OCR, &ohci->regs->cmdstatus); dbg ("USB HC TakeOver from SMM"); while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { wait_ms (10); - if (--smm_timeout == 0) { + if (--temp == 0) { err ("USB HC TakeOver failed!"); return -1; } } - } - + } + /* Disable HC interrupts */ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); @@ -372,22 +372,34 @@ ohci->hcd.self.bus_name, readl (&ohci->regs->control)); - /* Reset USB (needed by some controllers) */ - writel (0, &ohci->regs->control); - - /* HC Reset requires max 10 ms delay */ + /* Reset USB (needed by some controllers); RemoteWakeupConnected + * saved if boot firmware (BIOS/SMM/...) told us it's connected + */ + ohci->hc_control = readl (&ohci->regs->control); + ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */ + writel (ohci->hc_control, &ohci->regs->control); + wait_ms (50); + + /* HC Reset requires max 10 us delay */ writel (OHCI_HCR, &ohci->regs->cmdstatus); + temp = 30; /* ... allow extra time */ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--timeout == 0) { + if (--temp == 0) { err ("USB HC reset timed out!"); return -1; } udelay (1); - } + } /* now we're in the SUSPEND state ... must go OPERATIONAL * within 2msec else HC enters RESUME + * + * ... but some hardware won't init fmInterval "by the book" + * (SiS, OPTi ...), so reset again instead. SiS doesn't need + * this if we write fmInterval after we're OPERATIONAL. */ + writel (ohci->hc_control, &ohci->regs->control); + return 0; } @@ -434,7 +446,8 @@ } /* start controller operations */ - ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->hc_control &= OHCI_CTRL_RWC; + ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci->disabled = 0; writel (ohci->hc_control, &ohci->regs->control); @@ -443,13 +456,11 @@ writel (mask, &ohci->regs->intrstatus); writel (mask, &ohci->regs->intrenable); -#ifdef OHCI_USE_NPS - /* required for AMD-756 and some Mac platforms */ + /* hub power always on: required for AMD-756 and some Mac platforms */ writel ((roothub_a (ohci) | RH_A_NPS) & ~(RH_A_PSM | RH_A_OCPM), &ohci->regs->roothub.a); writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (0, &ohci->regs->roothub.b); -#endif /* OHCI_USE_NPS */ // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((roothub_a (ohci) >> 23) & 0x1fe); @@ -458,9 +469,10 @@ ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); ohci->hcd.state = USB_STATE_READY; if (!udev) { - ohci->disabled = 1; -// FIXME cleanup - return -ENOMEM; + ohci->disabled = 1; + ohci->hc_control &= ~OHCI_CTRL_HCFS; + writel (ohci->hc_control, &ohci->regs->control); + return -ENOMEM; } usb_connect (udev); @@ -468,10 +480,11 @@ if (usb_register_root_hub (udev, ohci->parent_dev) != 0) { usb_free_dev (udev); ohci->disabled = 1; -// FIXME cleanup + ohci->hc_control &= ~OHCI_CTRL_HCFS; + writel (ohci->hc_control, &ohci->regs->control); return -ENODEV; } - + return 0; }