patch-2.3.99-pre4 linux/drivers/usb/usb-ohci.c
Next file: linux/drivers/usb/usb-storage.c
Previous file: linux/drivers/usb/usb-debug.c
Back to the patch index
Back to the overall index
- Lines: 624
- Date:
Mon Apr 10 22:53:24 2000
- Orig file:
v2.3.99-pre3/linux/drivers/usb/usb-ohci.c
- Orig date:
Mon Mar 27 08:08:28 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
@@ -49,7 +49,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#define OHCI_USE_NPS
+#define OHCI_USE_NPS // force NoPowerSwitching mode
#include "usb-ohci.h"
@@ -61,6 +61,12 @@
#include <linux/pmu.h>
#endif
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) \
+ | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
@@ -143,16 +149,18 @@
printk ("%s stat:%d\n", i < len? "...": "", urb->status);
}
}
-
}
-/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
void ep_print_int_eds (ohci_t * ohci, char * str) {
int i, j;
__u32 * ed_p;
for (i= 0; i < 32; i++) {
j = 5;
- printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
ed_p = &(ohci->hcca.int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
while (*ed_p != 0 && j--) {
ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
printk (" ed: %4x;", ed->hwINFO);
@@ -161,7 +169,161 @@
printk ("\n");
}
}
-
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+ dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+ if (value)
+ dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET: return "reset";
+ case OHCI_USB_RESUME: return "resume";
+ case OHCI_USB_OPER: return "operational";
+ case OHCI_USB_SUSPEND: return "suspend";
+ }
+ return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl (®s->revision) & 0xff;
+ if (temp != 0x10)
+ dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl (®s->control);
+ dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string (temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl (®s->cmdstatus);
+ dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus));
+ ohci_dump_intr_mask ("intrenable", readl (®s->intrenable));
+ // intrdisable always same as intrenable
+ // ohci_dump_intr_mask ("intrdisable", readl (®s->intrdisable));
+
+ maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent));
+
+ maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead));
+ maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent));
+
+ maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead));
+ maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent));
+
+ maybe_print_eds ("donehead", readl (®s->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp, ndp, i;
+
+ temp = readl (®s->roothub.a);
+ ndp = (temp & RH_A_NDP);
+
+ if (verbose) {
+ dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = readl (®s->roothub.b);
+ dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = readl (®s->roothub.status);
+ dbg ("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = readl (®s->roothub.portstatus [i]);
+ dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+ dbg ("OHCI controller %p state", controller->regs);
+
+ // dumps some of the state we know about
+ ohci_dump_status (controller);
+ if (verbose)
+ ep_print_int_eds (controller, "hcca");
+ dbg ("hcca frame #%04x", controller->hcca.frame_no);
+ ohci_dump_roothub (controller, 1);
+}
+
#endif
@@ -365,12 +527,12 @@
if (!urb) /* just to be sure */
return -EINVAL;
+ ohci = (ohci_t *) urb->dev->bus->hcpriv;
+
#ifdef DEBUG
urb_print (urb, "UNLINK", 1);
#endif
- ohci = (ohci_t *) urb->dev->bus->hcpriv;
-
if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
return rh_unlink_urb (urb); /* a request to the virtual root hub */
@@ -448,8 +610,8 @@
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
- if (cnt > 0) {
- dev->wait = &wait;
+ if (cnt > 0) {
+ dev->wait = &wait;
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout (HZ / 10);
remove_wait_queue (&op_wakeup, &wait);
@@ -673,10 +835,12 @@
}
}
}
- for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
+ for (i = int_branch; i < 32; i += interval)
+ ohci->ohci_int_load[i] -= ed->int_load;
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_INT");
-#endif break;
+#endif
+ break;
case ISO:
if (ohci->ed_isotail == ed)
@@ -787,10 +951,10 @@
switch (ed->type) {
case CTRL: /* stop CTRL list */
- writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control);
break;
case BULK: /* stop BULK list */
- writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control);
+ writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control);
break;
}
}
@@ -1012,8 +1176,10 @@
if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
if (bulk) writel (0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */
- if (!ohci->ed_rm_list[!frame]) /* start CTRL u. BULK list */
- writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);
+ if (!ohci->ed_rm_list[!frame]) { /* enable CTRL and BULK lists */
+ ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
+ writel (ohci->hc_control, &ohci->regs->control);
+ }
ohci->ed_rm_list[frame] = NULL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
@@ -1112,6 +1278,7 @@
* Virtual Root Hub
*-------------------------------------------------------------------------*/
+/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
@@ -1170,23 +1337,8 @@
0xff /* __u8 ep_bInterval; 255 ms */
};
-/*
-For OHCI we need just the 2nd Byte, so we
-don't need this constant byte-array
+/* Hub class-specific descriptor is constructed dynamically */
-static __u8 root_hub_hub_des[] =
-{
- 0x00, * __u8 bLength; *
- 0x29, * __u8 bDescriptorType; Hub-descriptor *
- 0x02, * __u8 bNbrPorts; *
- 0x00, * __u16 wHubCharacteristics; *
- 0x00,
- 0x01, * __u8 bPwrOn2pwrGood; 2ms *
- 0x00, * __u8 bHubContrCurrent; 0 mA *
- 0x00, * __u8 DeviceRemovable; *** 8 Ports max *** *
- 0xff * __u8 PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
/*-------------------------------------------------------------------------*/
@@ -1201,13 +1353,16 @@
__u8 data[8];
- num_ports = readl (&ohci->regs->roothub.a) & 0xff;
- *(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
+ num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP;
+ *(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+ ? 1: 0;
ret = *(__u8 *) data;
for ( i = 0; i < num_ports; i++) {
*(__u8 *) (data + (i + 1) / 8) |=
- ((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
+ ((readl (&ohci->regs->roothub.portstatus[i]) &
+ (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+ ? 1: 0) << ((i + 1) % 8);
ret += *(__u8 *) (data + (i + 1) / 8);
}
len = i/8 + 1;
@@ -1221,7 +1376,7 @@
/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
static void rh_int_timer_do (unsigned long ptr)
{
@@ -1267,10 +1422,10 @@
/*-------------------------------------------------------------------------*/
-#define OK(x) len = (x); break
+#define OK(x) len = (x); break
#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT readl(&ohci->regs->roothub.status)
+#define RD_RH_STAT readl(&ohci->regs->roothub.status)
#define RD_RH_PORTSTAT readl(&ohci->regs->roothub.portstatus[wIndex-1])
/* request to virtual root hub */
@@ -1309,6 +1464,10 @@
wValue = le16_to_cpu (cmd->value);
wIndex = le16_to_cpu (cmd->index);
wLength = le16_to_cpu (cmd->length);
+
+ dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+ bmRType_bReq, wLength);
+
switch (bmRType_bReq) {
/* Request Destination:
without flags: Device,
@@ -1325,7 +1484,9 @@
case RH_GET_STATUS | RH_ENDPOINT:
*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32 (RD_RH_STAT & 0x7fff7fff); OK (4);
+ *(__u32 *) data_buf = cpu_to_le32 (
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK (4);
case RH_GET_STATUS | RH_OTHER | RH_CLASS:
*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
@@ -1370,11 +1531,15 @@
case (RH_PORT_SUSPEND):
WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PRS);
+ OK (0);
case (RH_PORT_POWER):
WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT (RH_PS_PES );
+ OK (0);
}
break;
@@ -1438,11 +1603,13 @@
case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
default:
+ dbg ("unsupported root hub command");
status = TD_CC_STALL;
}
- dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
- dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
+#ifdef DEBUG
+ ohci_dump_roothub (ohci, 0);
+#endif
len = min(len, leni);
if (data != data_buf)
@@ -1473,39 +1640,44 @@
* HC functions
*-------------------------------------------------------------------------*/
-/* reset the HC not the BUS */
+/* reset the HC and BUS */
-static void hc_reset (ohci_t * ohci)
+static int hc_reset (ohci_t * ohci)
{
int timeout = 30;
int smm_timeout = 50; /* 0,5 sec */
- if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
- writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
+ if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+ writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
dbg("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & 0x100) {
+ while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
if (--smm_timeout == 0) {
err("USB HC TakeOver failed!");
- break;
+ return -1;
}
}
}
- writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+ /* Disable HC interrupts */
+ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
- /* this seems to be needed for the lucent controller on powerbooks.. */
- writel (0, &ohci->regs->control); /* Move USB to reset state */
+
+ /* Reset USB (needed by some controllers) */
+ writel (0, &ohci->regs->control);
- writel (1, &ohci->regs->cmdstatus); /* HC Reset */
- while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+ /* HC Reset requires max 10 ms delay */
+ writel (OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--timeout == 0) {
err("USB HC reset timed out!");
- return;
+ return -1;
}
udelay (1);
}
ohci->disabled = 0;
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -1516,7 +1688,7 @@
static int hc_start (ohci_t * ohci)
{
- unsigned int mask;
+ __u32 mask;
unsigned int fminterval;
struct usb_device * usb_dev;
struct ohci_device * dev;
@@ -1535,31 +1707,35 @@
writel (fminterval, &ohci->regs->fminterval);
writel (0x628, &ohci->regs->lsthresh);
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
+
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-
- writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
writel (mask, &ohci->regs->intrstatus);
-#ifdef OHCI_USE_NPS
- writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+#ifdef OHCI_USE_NPS
+ writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
- writel (0x10000, &ohci->regs->roothub.status);
+ writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+ // POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
+#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
-
+ ohci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev) return -1;
+ if (!usb_dev)
+ return -ENOMEM;
dev = usb_to_ohci (usb_dev);
ohci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
- return -1;
+ return -ENODEV;
}
return 0;
@@ -1582,11 +1758,12 @@
return;
}
- dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
-
+ // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+
if (ints & OHCI_INTR_UE) {
ohci->disabled++;
err ("OHCI Unrecoverable Error, controller disabled");
+ // e.g. due to PCI Master/Target Abort
}
if (ints & OHCI_INTR_WDH) {
@@ -1661,8 +1838,9 @@
dbg("USB HC release ohci");
/* disconnect all devices */
- if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
-
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+
hc_reset (ohci);
writel (OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
@@ -1698,6 +1876,7 @@
#endif
printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
(unsigned long) mem_base, bufp);
+ printk(KERN_INFO __FILE__ ": %s\n", dev->name);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
@@ -1707,12 +1886,16 @@
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
- hc_reset (ohci);
+ if (hc_reset (ohci) < 0) {
+ hc_release_ohci (ohci);
+ return -ENODEV;
+ }
+
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
usb_register_bus (ohci->bus);
- if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+ if (request_irq (irq, hc_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
struct pm_dev *pmdev;
ohci->irq = irq;
@@ -1724,6 +1907,10 @@
if (pmdev)
pmdev->data = ohci;
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
+
return 0;
}
err("request interrupt %d failed", irq);
@@ -1787,7 +1974,8 @@
case PBOOK_WAKE:
writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ writel (ohci->hc_control, &ohci->regs->control);
enable_irq (ohci->irq);
break;
}
@@ -1801,22 +1989,24 @@
#endif /* CONFIG_PMAC_PBOOK */
/*-------------------------------------------------------------------------*/
-
+
static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
{
ohci_t * ohci = (ohci_t*) dev->data;
+ int temp = 0;
+
if (ohci) {
switch (rqst) {
case PM_SUSPEND:
- dbg("USB-Bus suspend: %p", ohci);
- writel (ohci->hc_control = 0xFF, &ohci->regs->control);
- wait_ms (10);
+ dbg("USB-Bus suspend: %p", ohci->regs);
+ if (ohci->bus->root_hub)
+ usb_disconnect (&ohci->bus->root_hub);
+ hc_reset (ohci);
break;
case PM_RESUME:
- dbg("USB-Bus resume: %p", ohci);
- writel (ohci->hc_control = 0x7F, &ohci->regs->control);
- wait_ms (20);
- writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+ dbg("USB-Bus resume: %p", ohci->regs);
+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0)
+ err ("can't restart controller, %d", temp);
break;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)