vserver 2.0 rc7
[linux-2.6.git] / drivers / usb / host / ohci.h
index 437e8b0..22e1ac1 100644 (file)
@@ -111,8 +111,10 @@ struct td {
        __hc32          hwNextTD;       /* Next TD Pointer */
        __hc32          hwBE;           /* Memory Buffer End Pointer */
 
-       /* PSW is only for ISO */
-#define MAXPSW 1               /* hardware allows 8 */
+       /* PSW is only for ISO.  Only 1 PSW entry is used, but on
+        * big-endian PPC hardware that's the second entry.
+        */
+#define MAXPSW 2
        __hc16          hwPSW [MAXPSW];
 
        /* rest are purely for the driver's use */
@@ -183,7 +185,7 @@ struct ohci_hcca {
        /* 
         * OHCI defines u16 frame_no, followed by u16 zero pad.
         * Since some processors can't do 16 bit bus accesses,
-        * portable access must be a 32 bit byteswapped access.
+        * portable access must be a 32 bits wide.
         */
        __hc32  frame_no;               /* current frame number */
        __hc32  done_head;              /* info returned for an interrupt */
@@ -191,8 +193,6 @@ struct ohci_hcca {
        u8      what [4];               /* spec only identifies 252 bytes :) */
 } __attribute__ ((aligned(256)));
 
-#define ohci_frame_no(ohci) ((u16)hc32_to_cpup(ohci,&(ohci)->hcca->frame_no))
-  
 /*
  * This is the structure of the OHCI controller's memory mapped I/O region.
  * You must use readl() and writel() (in <asm/io.h>) to access these fields!!
@@ -396,6 +396,7 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */
 #define        OHCI_QUIRK_INITRESET    0x04                    /* SiS, OPTi, ... */
 #define        OHCI_BIG_ENDIAN         0x08                    /* big endian HC */
+#define        OHCI_QUIRK_ZFMICRO      0x10                    /* Compaq ZFMicro chipset*/
        // there are also chip quirks/bugs in init logic
 
 };
@@ -554,19 +555,61 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 
 /*-------------------------------------------------------------------------*/
 
+/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+ * hardware handles 16 bit reads.  That creates a different confusion on
+ * some big-endian SOC implementations.  Same thing happens with PSW access.
+ */
+
+#ifdef CONFIG_STB03xxx
+#define OHCI_BE_FRAME_NO_SHIFT 16
+#else
+#define OHCI_BE_FRAME_NO_SHIFT 0
+#endif
+
+static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+{
+       u32 tmp;
+       if (big_endian(ohci)) {
+               tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+               tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+       } else
+               tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
+
+       return (u16)tmp;
+}
+
+static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+                                 const struct td *td, int index)
+{
+       return (__hc16 *)(big_endian(ohci) ?
+                       &td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+}
+
+static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
+                               const struct td *td, int index)
+{
+       return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index));
+}
+
+/*-------------------------------------------------------------------------*/
+
 static inline void disable (struct ohci_hcd *ohci)
 {
-       ohci_to_hcd(ohci)->state = USB_STATE_HALT;
+       ohci_to_hcd(ohci)->state = HC_STATE_HALT;
 }
 
 #define        FI                      0x2edf          /* 12000 bits per frame (-1) */
 #define        FSMP(fi)                (0x7fff & ((6 * ((fi) - 210)) / 7))
+#define        FIT                     (1 << 31)
 #define LSTHRESH               0x628           /* lowspeed bit threshold */
 
-static inline void periodic_reinit (struct ohci_hcd *ohci)
+static void periodic_reinit (struct ohci_hcd *ohci)
 {
-       u32     fi = ohci->fminterval & 0x0ffff;
+       u32     fi = ohci->fminterval & 0x03fff;
+       u32     fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
 
+       ohci_writel (ohci, (fit ^ FIT) | ohci->fminterval,
+                                               &ohci->regs->fminterval);
        ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff,
                                                &ohci->regs->periodicstart);
 }