From: Greg KH To: torvalds@transmeta.com Cc: linux-usb-devel@lists.sourceforge.net Subject: [PATCH 9 of 9] USB ohci-hcd driver update Hi, Here's a patch against 2.5.3 for the USB ohci-hcd driver that does the following: - doesn't assume CONFIG_DEBUG_SLAB - unlink from interrupt completions now work - doesn't force debugging on - updated copyright / license statements - slightly smaller object size - fewer inlined magic numbers - removes unused fields from data structures - header file reorg, doc fixup This patch was done by David Brownell. thanks, greg k-h diff -Nru a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c --- a/drivers/usb/hcd/ohci-dbg.c Sun Feb 3 00:53:05 2002 +++ b/drivers/usb/hcd/ohci-dbg.c Sun Feb 3 00:53:05 2002 @@ -2,9 +2,9 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * - * This file is licenced under GPL + * This file is licenced under the GPL. * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $ */ @@ -74,27 +74,34 @@ static inline struct ed * dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma); +#ifdef OHCI_VERBOSE_DEBUG /* print non-empty branches of the periodic ed tree */ -void ep_print_int_eds (struct ohci_hcd *ohci, char * str) +void ohci_dump_periodic (struct ohci_hcd *ohci, char *label) { int i, j; - __u32 * ed_p; + u32 *ed_p; + int printed = 0; + for (i= 0; i < 32; i++) { j = 5; ed_p = &(ohci->hcca->int_table [i]); if (*ed_p == 0) - continue; - printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", - str, i, i); + continue; + printed = 1; + printk (KERN_DEBUG "%s, ohci %s frame %2d:", + label, ohci->hcd.bus_name, i); while (*ed_p != 0 && j--) { struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p)); - printk (" ed: %4x;", ed->hwINFO); + printk (" %p/%08x;", ed, ed->hwINFO); ed_p = &ed->hwNextED; } printk ("\n"); } + if (!printed) + printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n", + label, ohci->hcd.bus_name); } - +#endif static void ohci_dump_intr_mask (char *label, __u32 mask) { @@ -137,8 +144,9 @@ __u32 temp; temp = readl (®s->revision) & 0xff; - if (temp != 0x10) - dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + dbg ("OHCI %d.%d, %s legacy support registers", + 0x03 & (temp >> 4), (temp & 0x0f), + (temp & 0x10) ? "with" : "NO"); temp = readl (®s->control); dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, @@ -225,8 +233,10 @@ // dumps some of the state we know about ohci_dump_status (controller); +#ifdef OHCI_VERBOSE_DEBUG if (verbose) - ep_print_int_eds (controller, "hcca"); + ohci_dump_periodic (controller, "hcca"); +#endif dbg ("hcca frame #%04x", controller->hcca->frame_no); ohci_dump_roothub (controller, 1); } diff -Nru a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c --- a/drivers/usb/hcd/ohci-hcd.c Sun Feb 3 00:53:05 2002 +++ b/drivers/usb/hcd/ohci-hcd.c Sun Feb 3 00:53:05 2002 @@ -2,7 +2,7 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] @@ -55,7 +55,7 @@ * v2.0 1999/05/04 * v1.0 1999/04/27 initial release * - * This file is licenced under GPL + * This file is licenced under the GPL. * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $ */ @@ -74,10 +74,6 @@ #include #include /* for in_interrupt () */ -#ifndef CONFIG_USB_DEBUG - #define CONFIG_USB_DEBUG /* this is still experimental! */ -#endif - #ifdef CONFIG_USB_DEBUG #define DEBUG #else @@ -258,7 +254,9 @@ if (ed->state != ED_OPER) ep_link (ohci, ed); - /* fill the TDs and link it to the ed */ + /* fill the TDs and link them to the ed; and + * enable that part of the schedule, if needed + */ td_submit_urb (urb); spin_unlock_irqrestore (&ohci->lock, flags); @@ -357,7 +355,9 @@ { struct ohci_hcd *ohci = hcd_to_ohci (hcd); +#ifdef OHCI_VERBOSE_DEBUG dbg ("%s: ohci_get_frame", hcd->bus_name); +#endif return le16_to_cpu (ohci->hcca->frame_no); } @@ -841,9 +847,10 @@ dl_done_list (ohci, dl_reverse_done_list (ohci)); writel (OHCI_INTR_WDH, &ohci->regs->intrenable); -// writel (OHCI_BLF, &ohci->regs->cmdstatus); -// writel (OHCI_CLF, &ohci->regs->cmdstatus); -ohci_dump_status (ohci); + /* assume there are TDs on the bulk and control lists */ + writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus); + +// ohci_dump_status (ohci); dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled); break; diff -Nru a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c --- a/drivers/usb/hcd/ohci-hub.c Sun Feb 3 00:53:05 2002 +++ b/drivers/usb/hcd/ohci-hub.c Sun Feb 3 00:53:05 2002 @@ -2,7 +2,7 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * * This file is licenced under GPL * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $ diff -Nru a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c --- a/drivers/usb/hcd/ohci-mem.c Sun Feb 3 00:53:04 2002 +++ b/drivers/usb/hcd/ohci-mem.c Sun Feb 3 00:53:04 2002 @@ -2,9 +2,9 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * - * This file is licenced under GPL + * This file is licenced under the GPL. * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $ */ @@ -42,7 +42,7 @@ /*-------------------------------------------------------------------------*/ -#ifdef DEBUG +#ifdef CONFIG_DEBUG_SLAB # define OHCI_MEM_FLAGS SLAB_POISON #else # define OHCI_MEM_FLAGS 0 @@ -64,16 +64,17 @@ return scan->virt; } -static inline struct ed * +static struct ed * dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma) { return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]), ed_dma); } -static inline struct td * +static struct td * dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) { + td_dma &= TD_MASK; return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]), td_dma); } @@ -214,7 +215,7 @@ return td; } -static inline void +static void td_free (struct ohci_hcd *hc, struct td *td) { hash_free_td (hc, td); @@ -242,7 +243,7 @@ return ed; } -static inline void +static void ed_free (struct ohci_hcd *hc, struct ed *ed) { hash_free_ed (hc, ed); diff -Nru a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c --- a/drivers/usb/hcd/ohci-q.c Sun Feb 3 00:53:03 2002 +++ b/drivers/usb/hcd/ohci-q.c Sun Feb 3 00:53:03 2002 @@ -2,9 +2,9 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * - * This file is licenced under GPL + * This file is licenced under the GPL. * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $ */ @@ -95,11 +95,11 @@ urb_print (urb, "RET", usb_pipeout (urb->pipe)); #endif -// FIXME: but if urb->status says it was was unlinked ... - switch (usb_pipetype (urb->pipe)) { case PIPE_INTERRUPT: #ifdef CONFIG_PCI +// FIXME rewrite this resubmit path. use pci_dma_sync_single() +// and requeue more cheaply, and only if needed. pci_unmap_single (hc->hcd.pdev, urb_priv->td [0]->data_dma, urb->transfer_buffer_length, @@ -107,16 +107,22 @@ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); #endif + /* FIXME: MP race. If another CPU partially unlinks + * this URB (urb->status was updated, hasn't yet told + * us to dequeue) before we call complete() here, an + * extra "unlinked" completion will be reported... + */ urb->complete (urb); - /* implicitly requeued */ + /* always requeued, but ED_SKIP if complete() unlinks. + * removed from periodic table only at SOF intr. + */ urb->actual_length = 0; - urb->status = -EINPROGRESS; - if (urb_priv->state != URB_DEL) { - spin_lock_irqsave (&hc->lock, flags); - td_submit_urb (urb); - spin_unlock_irqrestore (&hc->lock, flags); - } + if (urb_priv->state != URB_DEL) + urb->status = -EINPROGRESS; + spin_lock_irqsave (&hc->lock, flags); + td_submit_urb (urb); + spin_unlock_irqrestore (&hc->lock, flags); break; case PIPE_ISOCHRONOUS: @@ -126,7 +132,7 @@ continue; if (urbt) { /* send the reply and requeue URB */ #ifdef CONFIG_PCI -// FIXME this style unmap is only done on this route ... +// FIXME rewrite this resubmit path too pci_unmap_single (hc->hcd.pdev, urb_priv->td [0]->data_dma, urb->transfer_buffer_length, @@ -290,8 +296,8 @@ ed->hwNextED = *ed_p; *ed_p = cpu_to_le32 (ed->dma); } -#ifdef DEBUG - ep_print_int_eds (ohci, "LINK_INT"); +#ifdef OHCI_VERBOSE_DEBUG + ohci_dump_periodic (ohci, "LINK_INT"); #endif break; @@ -313,8 +319,8 @@ ed->ed_prev = NULL; } ohci->ed_isotail = edi; -#ifdef DEBUG - ep_print_int_eds (ohci, "LINK_ISO"); +#ifdef OHCI_VERBOSE_DEBUG + ohci_dump_periodic (ohci, "LINK_ISO"); #endif break; } @@ -336,7 +342,7 @@ int interval; __u32 *ed_p; - ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO |= ED_SKIP; switch (ed->type) { case PIPE_CONTROL: @@ -394,8 +400,8 @@ } for (i = int_branch; i < NUM_INTS; i += interval) ohci->ohci_int_load [i] -= ed->int_load; -#ifdef DEBUG - ep_print_int_eds (ohci, "UNLINK_INT"); +#ifdef OHCI_VERBOSE_DEBUG + ohci_dump_periodic (ohci, "UNLINK_INT"); #endif break; @@ -421,11 +427,15 @@ } } } -#ifdef DEBUG - ep_print_int_eds (ohci, "UNLINK_ISO"); +#ifdef OHCI_VERBOSE_DEBUG + ohci_dump_periodic (ohci, "UNLINK_ISO"); #endif break; } + + /* FIXME ED's "unlink" state is indeterminate; + * the HC might still be caching it (till SOF). + */ ed->state = ED_UNLINK; return 0; } @@ -478,7 +488,7 @@ } if (ed->state == ED_NEW) { - ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO = ED_SKIP; /* dummy td; end of td list for ed */ td = td_alloc (ohci, SLAB_ATOMIC); if (!td) { @@ -492,8 +502,6 @@ ed->type = usb_pipetype (pipe); } - ohci->dev [usb_pipedevice (pipe)] = udev; - // FIXME: don't do this if it's linked to the HC, // we might clobber data toggle or other state ... @@ -531,7 +539,7 @@ return; ed->state |= ED_URB_DEL; - ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO |= ED_SKIP; switch (ed->type) { case PIPE_CONTROL: /* stop control list */ @@ -582,7 +590,7 @@ /* fill the old dummy TD */ td = urb_priv->td [index] = dma_to_td (ohci, - le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf); + le32_to_cpup (&urb_priv->ed->hwTailP)); td->ed = urb_priv->ed; td->next_dl_td = NULL; @@ -795,7 +803,7 @@ spin_lock_irqsave (&ohci->lock, flags); - td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; + td_list_hc = le32_to_cpup (&ohci->hcca->done_head); ohci->hcca->done_head = 0; while (td_list_hc) { @@ -806,26 +814,24 @@ dbg (" USB-error/status: %x : %p", TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list); - if (td_list->ed->hwHeadP - & __constant_cpu_to_le32 (0x1)) { + /* typically the endpoint halted too */ + if (td_list->ed->hwHeadP & ED_H) { if (urb_priv && ((td_list->index + 1) < urb_priv->length)) { td_list->ed->hwHeadP = (urb_priv->td [urb_priv->length - 1]->hwNextTD - & __constant_cpu_to_le32 (0xfffffff0)) - | (td_list->ed->hwHeadP - & __constant_cpu_to_le32 (0x2)); + & __constant_cpu_to_le32 (TD_MASK)) + | (td_list->ed->hwHeadP & ED_C); urb_priv->td_cnt += urb_priv->length - td_list->index - 1; } else - td_list->ed->hwHeadP &= - __constant_cpu_to_le32 (0xfffffff2); + td_list->ed->hwHeadP &= ~ED_H; } } td_list->next_dl_td = td_rev; td_rev = td_list; - td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0; + td_list_hc = le32_to_cpup (&td_list->hwNextTD); } spin_unlock_irqrestore (&ohci->lock, flags); return td_list; @@ -851,10 +857,8 @@ for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) { - tdTailP = dma_to_td (ohci, - le32_to_cpup (&ed->hwTailP) & 0xfffffff0); - tdHeadP = dma_to_td (ohci, - le32_to_cpup (&ed->hwHeadP) & 0xfffffff0); + tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP)); + tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP)); edINFO = le32_to_cpup (&ed->hwINFO); td_p = &ed->hwHeadP; @@ -863,7 +867,7 @@ urb_priv_t *urb_priv = td->urb->hcpriv; td_next = dma_to_td (ohci, - le32_to_cpup (&td->hwNextTD) & 0xfffffff0); + le32_to_cpup (&td->hwNextTD)); if ((urb_priv->state == URB_DEL)) { tdINFO = le32_to_cpup (&td->hwINFO); if (TD_CC_GET (tdINFO) < 0xE) @@ -882,17 +886,16 @@ } ed->state &= ~ED_URB_DEL; - tdHeadP = dma_to_td (ohci, - le32_to_cpup (&ed->hwHeadP) & 0xfffffff0); + tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP)); if (tdHeadP == tdTailP) { if (ed->state == ED_OPER) ep_unlink (ohci, ed); td_free (ohci, tdTailP); - ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO = ED_SKIP; ed->state = ED_NEW; } else - ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO &= ~ED_SKIP; switch (ed->type) { case PIPE_CONTROL: @@ -938,7 +941,7 @@ int cc = 0; struct urb *urb; urb_priv_t *urb_priv; - __u32 tdINFO, edHeadP, edTailP; + __u32 tdINFO; unsigned long flags; @@ -968,7 +971,7 @@ /* * Except for periodic transfers, both branches do * the same thing. Periodic urbs get reissued until - * they're "deleted" with usb_unlink_urb. + * they're "deleted" (in SOF intr) by usb_unlink_urb. */ if ((ed->state & (ED_OPER | ED_UNLINK)) && (urb_priv->state != URB_DEL)) { @@ -983,13 +986,11 @@ spin_lock_irqsave (&ohci->lock, flags); if (ed->state != ED_NEW) { - edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0; - edTailP = le32_to_cpup (&ed->hwTailP); - -// FIXME: ED_UNLINK is very fuzzy w.r.t. what the hc knows... + u32 edHeadP = ed->hwHeadP; /* unlink eds if they are not busy */ - if ((edHeadP == edTailP) && (ed->state == ED_OPER)) + edHeadP &= __constant_cpu_to_le32 (ED_MASK); + if ((edHeadP == ed->hwTailP) && (ed->state == ED_OPER)) ep_unlink (ohci, ed); } spin_unlock_irqrestore (&ohci->lock, flags); diff -Nru a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h --- a/drivers/usb/hcd/ohci.h Sun Feb 3 00:53:05 2002 +++ b/drivers/usb/hcd/ohci.h Sun Feb 3 00:53:05 2002 @@ -2,86 +2,102 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell + * (C) Copyright 2000-2002 David Brownell * - * This file is licenced under GPL + * This file is licenced under the GPL. * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $ */ -static const int cc_to_error [16] = { - -/* map OHCI status to errno values */ - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY -}; - - -/* ED States */ - +/* + * OHCI Endpoint Descriptor (ED) ... holds TD queue + * See OHCI spec, section 4.2 + */ +struct ed { + /* first fields are hardware-specified, le32 */ + __u32 hwINFO; /* endpoint config bitmap */ +#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(0x10 << 11) + __u32 hwTailP; /* tail of TD list */ + __u32 hwHeadP; /* head of TD list */ +#define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */ +#define ED_H __constant_cpu_to_le32(0x01) /* halted */ + __u32 hwNextED; /* next ED in list */ + + /* rest are purely for the driver's use */ + struct ed *ed_prev; + __u8 int_period; + __u8 int_branch; + __u8 int_load; + __u8 int_interval; + __u8 state; // ED_{NEW,UNLINK,OPER} #define ED_NEW 0x00 /* unused, no dummy td */ #define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */ #define ED_OPER 0x02 /* dummy td, _is_ linked to hc */ +#define ED_URB_DEL 0x08 /* for unlinking; masked in */ -#define ED_URB_DEL 0x08 /* masked in */ + __u8 type; + __u16 last_iso; + struct ed *ed_rm_list; -/* usb_ohci_ed */ -struct ed { - /* first fields are hardware-specified */ - __u32 hwINFO; - __u32 hwTailP; - __u32 hwHeadP; - __u32 hwNextED; - - struct ed * ed_prev; - __u8 int_period; - __u8 int_branch; - __u8 int_load; - __u8 int_interval; - __u8 state; // ED_{NEW,UNLINK,OPER} - __u8 type; - __u16 last_iso; - struct ed * ed_rm_list; - - dma_addr_t dma; - __u32 unused [3]; -} __attribute((aligned(16))); + dma_addr_t dma; /* addr of ED */ +} __attribute__ ((aligned(16))); + +#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ -/* TD info field */ -#define TD_CC 0xf0000000 +/* + * OHCI Transfer Descriptor (TD) ... one per transfer segment + * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) + * and 4.3.2 (iso) + */ +struct td { + /* first fields are hardware-specified, le32 */ + __u32 hwINFO; /* transfer info bitmask */ +#define TD_CC 0xf0000000 /* condition code */ #define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) -#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) -#define TD_EC 0x0C000000 -#define TD_T 0x03000000 -#define TD_T_DATA0 0x02000000 -#define TD_T_DATA1 0x03000000 -#define TD_T_TOGGLE 0x00000000 -#define TD_R 0x00040000 -#define TD_DI 0x00E00000 -#define TD_DI_SET(X) (((X) & 0x07)<< 21) -#define TD_DP 0x00180000 -#define TD_DP_SETUP 0x00000000 -#define TD_DP_IN 0x00100000 -#define TD_DP_OUT 0x00080000 +//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) +#define TD_EC 0x0C000000 /* error count */ +#define TD_T 0x03000000 /* data toggle state */ +#define TD_T_DATA0 0x02000000 /* DATA0 */ +#define TD_T_DATA1 0x03000000 /* DATA1 */ +#define TD_T_TOGGLE 0x00000000 /* uses ED_C */ +#define TD_DI 0x00E00000 /* frames before interrupt */ +//#define TD_DI_SET(X) (((X) & 0x07)<< 21) +#define TD_DP 0x00180000 /* direction/pid */ +#define TD_DP_SETUP 0x00000000 /* SETUP pid */ +#define TD_DP_IN 0x00100000 /* IN pid */ +#define TD_DP_OUT 0x00080000 /* OUT pid */ + /* 0x00180000 rsvd */ +#define TD_R 0x00040000 /* round: short packets OK? */ + /* bits 0x1ffff are defined by HCD */ +#define TD_ISO 0x00010000 /* copy of ED_ISO */ + + __u32 hwCBP; /* Current Buffer Pointer (or 0) */ + __u32 hwNextTD; /* Next TD Pointer */ + __u32 hwBE; /* Memory Buffer End Pointer */ + + /* PSW is only for ISO */ +#define MAXPSW 1 /* hardware allows 8 */ + __u16 hwPSW [MAXPSW]; -#define TD_ISO 0x00010000 -#define TD_DEL 0x00020000 + /* rest are purely for the driver's use */ + __u8 index; + struct ed *ed; + struct td *next_dl_td; + struct urb *urb; -/* CC Codes */ + dma_addr_t td_dma; /* addr of this TD */ + dma_addr_t data_dma; /* addr of data it points to */ +} __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */ + +#define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */ + +/* + * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW + */ #define TD_CC_NOERROR 0x00 #define TD_CC_CRC 0x01 #define TD_CC_BITSTUFFING 0x02 @@ -99,57 +115,50 @@ #define TD_NOTACCESSED 0x0F -#define MAXPSW 1 - -struct td { - /* first hardware fields are in all tds */ - __u32 hwINFO; - __u32 hwCBP; /* Current Buffer Pointer */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ - - __u16 hwPSW [MAXPSW]; /* PSW is only for ISO */ - - __u8 unused; - __u8 index; - struct ed *ed; - struct td *next_dl_td; - struct urb *urb; - - dma_addr_t td_dma; - dma_addr_t data_dma; - __u32 unused2 [2]; -} __attribute((aligned(32))); /* iso needs 32 */ +/* map OHCI TD status codes (CC) to errno values */ +static const int cc_to_error [16] = { + /* No Error */ 0, + /* CRC Error */ -EILSEQ, + /* Bit Stuff */ -EPROTO, + /* Data Togg */ -EILSEQ, + /* Stall */ -EPIPE, + /* DevNotResp */ -ETIMEDOUT, + /* PIDCheck */ -EPROTO, + /* UnExpPID */ -EPROTO, + /* DataOver */ -EOVERFLOW, + /* DataUnder */ -EREMOTEIO, + /* (for hw) */ -EIO, + /* (for hw) */ -EIO, + /* BufferOver */ -ECOMM, + /* BuffUnder */ -ENOSR, + /* (for HCD) */ -EALREADY, + /* (for HCD) */ -EALREADY +}; -#define OHCI_ED_SKIP (1 << 14) /* * The HCCA (Host Controller Communications Area) is a 256 byte - * structure defined in the OHCI spec. The host controller is + * structure defined section 4.4.1 of the OHCI spec. The HC is * told the base address of it. It must be 256-byte aligned. */ -#define NUM_INTS 32 /* part of the OHCI standard */ struct ohci_hcca { - __u32 int_table [NUM_INTS]; /* Interrupt ED table */ +#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 */ __u32 done_head; /* info returned for an interrupt */ u8 reserved_for_hc [116]; -} __attribute((aligned(256))); + u8 what [4]; /* spec only identifies 252 bytes :) */ +} __attribute__ ((aligned(256))); /* - * Maximum number of root hub ports. - */ -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ - -/* - * This is the structure of the OHCI controller's memory mapped I/O - * region. This is Memory Mapped I/O. You must use the readl() and - * writel() macros defined in asm/io.h to access these!! + * This is the structure of the OHCI controller's memory mapped I/O region. + * You must use readl() and writel() (in ) to access these fields!! + * Layout is in section 7 (and appendix B) of the spec. */ struct ohci_regs { - /* control and status registers */ + /* control and status registers (section 7.1) */ __u32 revision; __u32 control; __u32 cmdstatus; @@ -157,7 +166,7 @@ __u32 intrenable; __u32 intrdisable; - /* memory pointers */ + /* memory pointers (section 7.2) */ __u32 hcca; __u32 ed_periodcurrent; __u32 ed_controlhead; @@ -166,23 +175,25 @@ __u32 ed_bulkcurrent; __u32 donehead; - /* frame counters */ + /* frame counters (section 7.3) */ __u32 fminterval; __u32 fmremaining; __u32 fmnumber; __u32 periodicstart; __u32 lsthresh; - /* Root hub ports */ + /* Root hub ports (section 7.4) */ struct ohci_roothub_regs { __u32 a; __u32 b; __u32 status; +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */ __u32 portstatus [MAX_ROOT_PORTS]; } roothub; - /* and some optional registers for legacy compatibility */ -} __attribute((aligned(32))); + /* and optional "legacy support" registers (appendix B) at 0x0100 */ + +} __attribute__ ((aligned(32))); /* OHCI CONTROL AND STATUS REGISTER MASKS */ @@ -270,9 +281,8 @@ #define RH_A_POTPGT (0xff << 24) /* power on to power good time */ -/* urb */ -typedef struct urb_priv -{ +/* hcd-private per-urb state */ +typedef struct urb_priv { struct ed *ed; __u16 length; // # tds in this request __u16 td_cnt; // tds already serviced @@ -345,7 +355,6 @@ int sleeping; int ohci_int_load [NUM_INTS]; u32 hc_control; /* copy of hc control reg */ - struct usb_device *dev [128]; unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */