Here is a patch to 2.6.0-test9 that addresses mips bit-endian bus accesses breaking 
endianness in EHCI and OHCI. It also fixes a problem with ohci_dbg() not endian 
swapping the frame number field in a debug print. 

Untested on x86, but the changes are trivial so it should work there as well. I assume 
the sanity test will catch any coarse errors there rather quickly.


diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci-dbg.c 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-dbg.c
--- linux-2.6.0-test9/drivers/usb/host/ehci-dbg.c       2003-10-25 11:44:31.000000000 
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-dbg.c        2003-10-28 
09:41:05.000000000 -0800
@@ -591,7 +591,7 @@
        spin_lock_irqsave (&ehci->lock, flags);
 
        /* Capability Registers */
-       i = readw (&ehci->caps->hci_version);
+       i = HC_VERSION(readl (&ehci->caps->hc_capbase));
        temp = snprintf (next, size,
                "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION 
")\n",
                pci_name(hcd->pdev),
diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci.h 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci.h
--- linux-2.6.0-test9/drivers/usb/host/ehci.h   2003-10-25 11:44:35.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci.h    2003-10-28 
09:42:11.000000000 -0800
@@ -153,9 +153,9 @@
 
 /* Section 2.2 Host Controller Capability Registers */
 struct ehci_caps {
-       u8              length;         /* CAPLENGTH - size of this struct */
-       u8              reserved;       /* offset 0x1 */
-       u16             hci_version;    /* HCIVERSION - offset 0x2 */
+       u32     hc_capbase; /* HCCAPBASE - must be a u32 to be endian-neutral */
+#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
+#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
        u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
 #define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
 #define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
diff -Naur linux-2.6.0-test9/drivers/usb/host/ehci-hcd.c 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-hcd.c
--- linux-2.6.0-test9/drivers/usb/host/ehci-hcd.c       2003-10-25 11:44:01.000000000 
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ehci-hcd.c        2003-10-28 
09:41:38.000000000 -0800
@@ -324,8 +324,8 @@
        spin_lock_init (&ehci->lock);
 
        ehci->caps = (struct ehci_caps *) hcd->regs;
-       ehci->regs = (struct ehci_regs *) (hcd->regs +
-                               readb (&ehci->caps->length));
+       ehci->regs = (struct ehci_regs *) (hcd->regs + 
+                               HC_LENGTH(ehci->caps->hc_capbase));
        dbg_hcs_params (ehci, "reset");
        dbg_hcc_params (ehci, "reset");
 
@@ -486,7 +486,7 @@
 
         /* PCI Serial Bus Release Number is at 0x60 offset */
        pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
-       temp = readw (&ehci->caps->hci_version);
+       temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
        ehci_info (ehci,
                "USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
                ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-dbg.c 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-dbg.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-dbg.c       2003-10-25 11:44:36.000000000 
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-dbg.c        2003-10-28 
09:35:45.000000000 -0800
@@ -269,7 +269,7 @@
        ohci_dump_status (controller, NULL, 0);
        if (controller->hcca)
                ohci_dbg (controller,
-                       "hcca frame #%04x\n", controller->hcca->frame_no);
+                       "hcca frame #%04x\n", OHCI_FRAME_NO(controller->hcca));
        ohci_dump_roothub (controller, 1, NULL, 0);
 }
 
@@ -617,7 +617,7 @@
        /* hcca */
        if (ohci->hcca)
                ohci_dbg_sw (ohci, &next, &size,
-                       "hcca frame 0x%04x\n", ohci->hcca->frame_no);
+                       "hcca frame 0x%04x\n", OHCI_FRAME_NO(ohci->hcca));
 
        /* other registers mostly affect frame timings */
        rdata = readl (&regs->fminterval);
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci.h 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci.h
--- linux-2.6.0-test9/drivers/usb/host/ohci.h   2003-10-25 11:44:57.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci.h    2003-10-28 
09:43:51.000000000 -0800
@@ -172,8 +172,18 @@
 struct ohci_hcca {
 #define NUM_INTS 32
        __u32   int_table [NUM_INTS];   /* periodic schedule */
-       __u16   frame_no;               /* current frame number */
-       __u16   pad1;                   /* set to 0 on each frame_no change */
+
+       /* 
+        * Note that the specification defines u16 frame_no, followed by u16 pad, 
+        * which breaks endianness on big endian processors that do 32-bit bus
+        * accesses. The solution is to use a u32 to represent the frame number on
+        * all architectures. The pad is handled automatically as the zeroed
+        * upper word of the frame number. In the LE case, the frame_no (ls byte)
+        * goes out first, with no swapping. In the BE case, the frame_no (ls byte)
+        * also goes out first, after the 32-bit endian swap.
+        */
+       __u32   frame_no;               /* current frame number */
+#define OHCI_FRAME_NO(hccap) (u16)((le32_to_cpu(hccap->frame_no) & 0xffff))
        __u32   done_head;              /* info returned for an interrupt */
        u8      reserved_for_hc [116];
        u8      what [4];               /* spec only identifies 252 bytes :) */
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-hcd.c 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-hcd.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-hcd.c       2003-10-25 11:42:54.000000000 
-0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-hcd.c        2003-10-27 
17:01:33.000000000 -0800
@@ -226,7 +226,7 @@
                if (retval < 0)
                        goto fail;
                if (ed->type == PIPE_ISOCHRONOUS) {
-                       u16     frame = le16_to_cpu (ohci->hcca->frame_no);
+                       u16     frame = OHCI_FRAME_NO(ohci->hcca);
 
                        /* delay a few frames before the first TD */
                        frame += max_t (u16, 8, ed->interval);
@@ -363,7 +363,7 @@
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
 
-       return le16_to_cpu (ohci->hcca->frame_no);
+       return OHCI_FRAME_NO(ohci->hcca);
 }
 
 /*-------------------------------------------------------------------------*
@@ -591,7 +591,7 @@
         */
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
-               finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
+               finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca),
                                ptregs);
        if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
                        && HCD_IS_RUNNING(ohci->hcd.state))
diff -Naur linux-2.6.0-test9/drivers/usb/host/ohci-q.c 
linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-q.c
--- linux-2.6.0-test9/drivers/usb/host/ohci-q.c 2003-10-25 11:44:44.000000000 -0700
+++ linux-2.6.0-test9-BigEndianFixes/drivers/usb/host/ohci-q.c  2003-10-27 
17:02:56.000000000 -0800
@@ -441,7 +441,7 @@
         * behave.  frame_no wraps every 2^16 msec, and changes right before
         * SF is triggered.
         */
-       ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
+       ed->tick = OHCI_FRAME_NO(ohci->hcca) + 1;
 
        /* rm_list is just singly linked, for simplicity */
        ed->ed_next = ohci->ed_rm_list;





-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive?  Does it
help you create better code?   SHARE THE LOVE, and help us help
YOU!  Click Here: http://sourceforge.net/donate/
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to