This is the 2.3.99 pre4-2 version of the rest of a patch I sent
by a few weeks ago (then marked as "experimental").

It reduces use of magic numbers when accessing OHCI registers,
and provides basic facilities to interpret their fields using
debug-only printing routines.

- Dave
--- linux/drivers/usb.1/usb-ohci.c      Fri Mar 31 11:15:35 2000
+++ linux/drivers/usb/usb-ohci.c        Sat Apr  1 12:20:08 2000
@@ -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;
@@ -145,14 +151,16 @@
        } 
        
 }
-/* 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 (&regs->revision) & 0xff;
+       if (temp != 0x10)
+               dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+       temp = readl (&regs->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 (&regs->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 (&regs->intrstatus));
+       ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+       // intrdisable always same as intrenable
+       // ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+       maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+       maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+       maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+       maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+       maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+       maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+       struct ohci_regs        *regs = controller->regs;
+       __u32                   temp, ndp, i;
+
+       temp = readl (&regs->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 (&regs->roothub.b);
+               dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+                       temp,
+                       (temp & RH_B_PPCM) >> 16,
+                       (temp & RH_B_DR)
+                       );
+               temp = readl (&regs->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 (&regs->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 */
        
@@ -787,10 +949,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 +1174,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 +1276,7 @@
  * Virtual Root Hub 
  *-------------------------------------------------------------------------*/
  
+/* Device descriptor */
 static __u8 root_hub_dev_des[] =
 {
        0x12,       /*  __u8  bLength; */
@@ -1170,23 +1335,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 +1351,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 +1374,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 +1420,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 +1462,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 +1482,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 +1529,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;
 
@@ -1441,8 +1604,9 @@
                        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)
@@ -1480,10 +1644,10 @@
        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_RWC) { /* 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_RWC) {
                        wait_ms (10);
                        if (--smm_timeout == 0) {
                                err("USB HC TakeOver failed!");
@@ -1492,13 +1656,17 @@
                }
        }       
                
-       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 -1;
@@ -1539,14 +1707,18 @@
        /* 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 */
+       /* start controller operations */
+       ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+       writel (ohci->hc_control, &ohci->regs->control);
+ 
        writel (mask, &ohci->regs->intrenable);
        writel (mask, &ohci->regs->intrstatus);
 
 #ifdef OHCI_USE_NPS
-       writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+       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 */
  
@@ -1584,10 +1756,11 @@
        } 
 
        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) {
@@ -1729,6 +1902,10 @@
                if (pmdev)
                        pmdev->data = ohci;
 
+#ifdef DEBUG
+               ohci_dump (ohci, 1);
+#endif
+
                return 0;
        }       
        err("request interrupt %d failed", irq);
@@ -1792,7 +1969,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;
                }
@@ -1812,16 +1990,30 @@
        ohci_t * ohci = (ohci_t*) dev->data;
        if (ohci) {
                switch (rqst) {
+               /*
+                *      We have to disable the OHCI irq. This sucks because we'd rather
+                *      not disable a potentially shared IRQ since the other user might
+                *      want an IRQ event during suspend. Unfortunately at least some
+                *      machines come back with the IRQ floating and if we don't do
+                *      this we are dead, defunct, pushing up the silicon daisies.
+                */
                case PM_SUSPEND:
                        dbg("USB-Bus suspend: %p", ohci);
-                       writel (ohci->hc_control = 0xFF, &ohci->regs->control);
+                       ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_SUSPEND;
+                       writel (ohci->hc_control, &ohci->regs->control);
                        wait_ms (10);
+                       if(ohci->irq > 0)
+                               disable_irq(ohci->irq);
                        break;
                case PM_RESUME:
                        dbg("USB-Bus resume: %p", ohci);
-                       writel (ohci->hc_control = 0x7F, &ohci->regs->control);
+                       ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_RESUME;
+                       writel (ohci->hc_control, &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);
+                       if(ohci->irq > 0)
+                               enable_irq(ohci->irq);
                        break;
                }
        }

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to