This 3-part patch adds support for the big-endian OHCI implementations found on IBM's stb04xxx and Freescale's MPC52xx processors.
Patch 1 Removes byteswapped OHCI constants in preparation for dynamically handling endianness. Patch 2 Adds support for big-endian OHCI controllers. This is done primarily by applying the following transforms when dealing with controller data: ohci_readl(p) --> ohci_read(ohci, p) writel(v, p) --> ohci_writel(ohci, v, p) cpu_to_le16(v) --> cpu_to_ohci16(ohci, v) cpu_to_le16p(v) --> cpu_to_ohci16p(ohci, v) cpu_to_le32(v) --> cpu_to_ohci32(ohci, v) cpu_to_le32p(v) --> cpu_to_ohci32p(ohci, v) le16_to_cpu(v) --> ohci16_to_cpu(ohci, v) le16_to_cpup(v) --> ohci16_to_cpup(ohci, v) le32_to_cpu(v) --> ohci32_to_cpu(ohci, v) le32_to_cpup(v) --> ohci32_to_cpup(ohci, v) A bit in the flags field of struct ohci_hcd, OHCI_BIG_ENDIAN, enables the the transformed functions to support both big-endian and little-endian controllers at runtime, if needed. Patch 3 Adds support for ohci controllers (big-endian) on STB04xxx and MPC52xx Signed-off-by: Dale Farnsworth <[EMAIL PROTECTED]> diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h 2004-08-02 13:30:26 -07:00 +++ b/drivers/usb/host/ohci.h 2004-08-02 13:30:26 -07:00 @@ -15,20 +15,20 @@ * both EHCI and UHCI call similar structures a "QH". */ struct ed { - /* first fields are hardware-specified, le32 */ + /* first fields are hardware-specified */ __u32 hwINFO; /* endpoint config bitmap */ /* info bits defined by hcd */ -#define ED_DEQUEUE __constant_cpu_to_le32(1 << 27) +#define ED_DEQUEUE (1 << 27) /* info bits defined by the hardware */ -#define ED_ISO __constant_cpu_to_le32(1 << 15) -#define ED_SKIP __constant_cpu_to_le32(1 << 14) -#define ED_LOWSPEED __constant_cpu_to_le32(1 << 13) -#define ED_OUT __constant_cpu_to_le32(0x01 << 11) -#define ED_IN __constant_cpu_to_le32(0x02 << 11) +#define ED_ISO (1 << 15) +#define ED_SKIP (1 << 14) +#define ED_LOWSPEED (1 << 13) +#define ED_OUT (0x01 << 11) +#define ED_IN (0x02 << 11) __u32 hwTailP; /* tail of TD list */ __u32 hwHeadP; /* head of TD list (hc r/w) */ -#define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ -#define ED_H __constant_cpu_to_le32(0x01) /* halted */ +#define ED_C 0x02 /* toggle carry */ +#define ED_H 0x01 /* halted */ __u32 hwNextED; /* next ED in list */ /* rest are purely for the driver's use */ @@ -70,7 +70,7 @@ * and 4.3.2 (iso) */ struct td { - /* first fields are hardware-specified, le32 */ + /* first fields are hardware-specified */ __u32 hwINFO; /* transfer info bitmask */ /* hwINFO bits for both general and iso tds: */ diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c 2004-08-02 13:30:26 -07:00 +++ b/drivers/usb/host/ohci-dbg.c 2004-08-02 13:30:26 -07:00 @@ -336,7 +336,7 @@ ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, const struct ed *ed, int verbose) { - u32 tmp = ed->hwINFO; + u32 tmp = le32_to_cpu (ed->hwINFO); char *type = ""; ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n", @@ -349,19 +349,20 @@ /* else from TDs ... control */ } ohci_dbg (ohci, - " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", le32_to_cpu (tmp), - 0x03ff & (le32_to_cpu (tmp) >> 16), + " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp, + 0x03ff & (tmp >> 16), (tmp & ED_DEQUEUE) ? " DQ" : "", (tmp & ED_ISO) ? " ISO" : "", (tmp & ED_SKIP) ? " SKIP" : "", (tmp & ED_LOWSPEED) ? " LOW" : "", - 0x000f & (le32_to_cpu (tmp) >> 7), + 0x000f & (tmp >> 7), type, - 0x007f & le32_to_cpu (tmp)); + 0x007f & tmp); + tmp = le32_to_cpup (&ed->hwHeadP); ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n", - tmp = le32_to_cpup (&ed->hwHeadP), - (ed->hwHeadP & ED_C) ? data1 : data0, - (ed->hwHeadP & ED_H) ? " HALT" : "", + tmp, + (tmp & ED_C) ? data1 : data0, + (tmp & ED_H) ? " HALT" : "", le32_to_cpup (&ed->hwTailP), verbose ? "" : " (not listing)"); if (verbose) { @@ -415,8 +416,9 @@ /* dump a snapshot of the bulk or control schedule */ while (ed) { - u32 info = ed->hwINFO; + u32 info = le32_to_cpu (ed->hwINFO); u32 scratch = cpu_to_le32p (&ed->hwINFO); + u32 scratch2 = cpu_to_le32 (ed->hwHeadP); struct list_head *entry; struct td *td; @@ -430,8 +432,8 @@ 0x03ff & (scratch >> 16), scratch, (info & ED_SKIP) ? " s" : "", - (ed->hwHeadP & ED_H) ? " H" : "", - (ed->hwHeadP & ED_C) ? data1 : data0); + (scratch2 & ED_H) ? " H" : "", + (scratch2 & ED_C) ? data1 : data0); size -= temp; buf += temp; @@ -541,7 +543,7 @@ /* show more info the first time around */ if (temp == seen_count) { - u32 info = ed->hwINFO; + u32 info = ohci32_to_cpu(ohci, ed->hwINFO); u32 scratch = cpu_to_le32p (&ed->hwINFO); struct list_head *entry; unsigned qlen = 0; @@ -562,7 +564,8 @@ 0x03ff & (scratch >> 16), scratch, (info & ED_SKIP) ? " K" : "", - (ed->hwHeadP & ED_H) ? " H" : ""); + (le32_to_cpu(ed->hwHeadP) & + ED_H) ? " H" : ""); size -= temp; next += temp; diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c 2004-08-02 13:30:26 -07:00 +++ b/drivers/usb/host/ohci-hcd.c 2004-08-02 13:30:26 -07:00 @@ -730,7 +730,7 @@ switch (ed->state) { case ED_OPER: ed->state = ED_UNLINK; - ed->hwINFO |= ED_DEQUEUE; + ed->hwINFO |= cpu_to_le32(ED_DEQUEUE); ed_deschedule (ohci, ed); ed->ed_next = ohci->ed_rm_list; diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c --- a/drivers/usb/host/ohci-mem.c 2004-08-02 13:30:26 -07:00 +++ b/drivers/usb/host/ohci-mem.c 2004-08-02 13:30:26 -07:00 @@ -120,7 +120,7 @@ prev = &(*prev)->td_hash; if (*prev) *prev = td->td_hash; - else if ((td->hwINFO & TD_DONE) != 0) + else if ((le32_to_cpu(td->hwINFO) & TD_DONE) != 0) ohci_dbg (hc, "no hash for td %p\n", td); dma_pool_free (hc->td_cache, td, td->td_dma); } diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c 2004-08-02 13:30:26 -07:00 +++ b/drivers/usb/host/ohci-q.c 2004-08-02 13:30:26 -07:00 @@ -131,7 +131,7 @@ unsigned i; ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & ED_ISO) ? "iso " : "", + (ed->hwINFO & cpu_to_le32 (ED_ISO)) ? "iso " : "", ed, ed->branch, ed->load, ed->interval); for (i = ed->branch; i < NUM_INTS; i += ed->interval) { @@ -272,7 +272,7 @@ hcd_to_bus (&ohci->hcd)->bandwidth_allocated -= ed->load / ed->interval; ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & ED_ISO) ? "iso " : "", + (ed->hwINFO & cpu_to_le32 (ED_ISO)) ? "iso " : "", ed, ed->branch, ed->load, ed->interval); } @@ -300,7 +300,7 @@ */ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { - ed->hwINFO |= ED_SKIP; + ed->hwINFO |= cpu_to_le32 (ED_SKIP); wmb (); ed->state = ED_UNLINK; @@ -433,14 +433,14 @@ info |= usb_maxpacket (udev, pipe, is_out) << 16; info = cpu_to_le32 (info); if (udev->speed == USB_SPEED_LOW) - info |= ED_LOWSPEED; + info |= cpu_to_le32 (ED_LOWSPEED); /* only control transfers store pids in tds */ if (type != PIPE_CONTROL) { - info |= is_out ? ED_OUT : ED_IN; + info |= cpu_to_le32(is_out ? ED_OUT : ED_IN); if (type != PIPE_BULK) { /* periodic transfers... */ if (type == PIPE_ISOCHRONOUS) - info |= ED_ISO; + info |= cpu_to_le32 (ED_ISO); else if (interval > 32) /* iso can be bigger */ interval = 32; ed->interval = interval; @@ -469,7 +469,7 @@ */ static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) { - ed->hwINFO |= ED_DEQUEUE; + ed->hwINFO |= cpu_to_le32 (ED_DEQUEUE); ed_deschedule (ohci, ed); /* rm_list is just singly linked, for simplicity */ @@ -593,7 +593,7 @@ if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); - urb_priv->ed->hwHeadP &= ~ED_C; + urb_priv->ed->hwHeadP &= ~cpu_to_le32 (ED_C); } urb_priv->td_cnt = 0; @@ -795,14 +795,14 @@ struct urb *urb = td->urb; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; - u32 toggle = ed->hwHeadP & ED_C; + u32 toggle = ed->hwHeadP & cpu_to_ohci32 (ED_C); /* clear ed halt; this is the td that caused it, but keep it inactive * until its urb->complete() has a chance to clean up. */ - ed->hwINFO |= ED_SKIP; + ed->hwINFO |= cpu_to_le32 (ED_SKIP); wmb (); - ed->hwHeadP &= ~ED_H; + ed->hwHeadP &= ~cpu_to_le32 (ED_H); /* put any later tds from this urb onto the donelist, after 'td', * order won't matter here: no errors, and nothing was transferred. @@ -894,7 +894,8 @@ * and dequeue any other TDs from this urb. * No other TD could have caused the halt. */ - if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & ED_H)) + if (cc != TD_CC_NOERROR && + (td->ed->hwHeadP & cpu_to_le32 (ED_H))) td_rev = ed_halted (ohci, td, cc, td_rev); td->next_dl_td = td_rev; @@ -998,10 +999,10 @@ /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; - ed->hwHeadP &= ~ED_H; + ed->hwHeadP &= ~cpu_to_le32(ED_H); ed->hwNextED = 0; wmb (); - ed->hwINFO &= ~(ED_SKIP | ED_DEQUEUE); + ed->hwINFO &= ~cpu_to_le32 (ED_SKIP | ED_DEQUEUE); /* but if there's work queued, reschedule */ if (!list_empty (&ed->td_list)) { @@ -1080,10 +1081,10 @@ start_ed_unlink (ohci, ed); /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & (ED_SKIP | ED_DEQUEUE)) == ED_SKIP) { + } else if ((ed->hwINFO & cpu_to_le32 (ED_SKIP | ED_DEQUEUE)) == cpu_to_le32 (ED_SKIP)) { td = list_entry (ed->td_list.next, struct td, td_list); if (!(td->hwINFO & TD_DONE)) { - ed->hwINFO &= ~ED_SKIP; + ed->hwINFO &= ~cpu_to_le32 (ED_SKIP); /* ... hc may need waking-up */ switch (ed->type) { case PIPE_CONTROL: ------------------------------------------------------- This SF.Net email is sponsored by OSTG. Have you noticed the changes on Linux.com, ITManagersJournal and NewsForge in the past few weeks? Now, one more big change to announce. We are now OSTG- Open Source Technology Group. Come see the changes on the new OSTG site. www.ostg.com _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel