* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
- * 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 $
*/
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)
{
__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,
// 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);
}
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
* 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 $
*/
#include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */
-#ifndef CONFIG_USB_DEBUG
- #define CONFIG_USB_DEBUG /* this is still experimental! */
-#endif
-
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
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);
{
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);
}
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;
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under GPL
* $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
- * 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 $
*/
/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
+#ifdef CONFIG_DEBUG_SLAB
# define OHCI_MEM_FLAGS SLAB_POISON
#else
# define OHCI_MEM_FLAGS 0
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);
}
return td;
}
-static inline void
+static void
td_free (struct ohci_hcd *hc, struct td *td)
{
hash_free_td (hc, td);
return ed;
}
-static inline void
+static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
hash_free_ed (hc, ed);
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
- * 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 $
*/
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,
? 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:
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,
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;
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;
}
int interval;
__u32 *ed_p;
- ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP);
+ ed->hwINFO |= ED_SKIP;
switch (ed->type) {
case PIPE_CONTROL:
}
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;
}
}
}
-#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;
}
}
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) {
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 ...
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 */
/* 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;
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) {
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;
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;
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)
}
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:
int cc = 0;
struct urb *urb;
urb_priv_t *urb_priv;
- __u32 tdINFO, edHeadP, edTailP;
+ __u32 tdINFO;
unsigned long flags;
/*
* 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)) {
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);
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
- * 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_ISO 0x00010000
-#define TD_DEL 0x00020000
-
-/* CC Codes */
+//#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];
+
+ /* rest are purely for the driver's use */
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct urb *urb;
+
+ 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
#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 <asm/io.h>) 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;
__u32 intrenable;
__u32 intrdisable;
- /* memory pointers */
+ /* memory pointers (section 7.2) */
__u32 hcca;
__u32 ed_periodcurrent;
__u32 ed_controlhead;
__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 */
#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
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 */