Commit a5c9b326 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[PATCH] USB ohci-hcd driver update

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.
parent 25562ed9
......@@ -2,9 +2,9 @@
* 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 $
*/
......@@ -74,27 +74,34 @@ static void urb_print (struct urb * urb, char * str, int small)
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 @@ static void ohci_dump_status (struct ohci_hcd *controller)
__u32 temp;
temp = readl (&regs->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 (&regs->control);
dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
......@@ -225,8 +233,10 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
// 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);
}
......
......@@ -2,7 +2,7 @@
* 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 ]
......@@ -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 <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
......@@ -258,7 +254,9 @@ static int ohci_urb_enqueue (
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 @@ static int ohci_get_frame (struct usb_hcd *hcd)
{
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 +841,10 @@ static int ohci_resume (struct usb_hcd *hcd)
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;
......
......@@ -2,7 +2,7 @@
* 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 $
......
......@@ -2,9 +2,9 @@
* 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 $
*/
......@@ -42,7 +42,7 @@ static void ohci_hcd_free (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
#ifdef CONFIG_DEBUG_SLAB
# define OHCI_MEM_FLAGS SLAB_POISON
#else
# define OHCI_MEM_FLAGS 0
......@@ -64,16 +64,17 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
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 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
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 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
return ed;
}
static inline void
static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
hash_free_ed (hc, ed);
......
......@@ -2,9 +2,9 @@
* 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 $
*/
......@@ -95,11 +95,11 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
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 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
? 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 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
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 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
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 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
}
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 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
}
}
}
#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 @@ static struct ed *ep_add_ed (
}
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 @@ static struct ed *ep_add_ed (
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 @@ static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
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 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
/* 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 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
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 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
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 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
}
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 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
int cc = 0;
struct urb *urb;
urb_priv_t *urb_priv;
__u32 tdINFO, edHeadP, edTailP;
__u32 tdINFO;
unsigned long flags;
......@@ -968,7 +971,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
/*
* 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 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
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);
......
......@@ -2,86 +2,102 @@
* 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
......@@ -99,57 +115,50 @@ struct ed {
#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;
......@@ -157,7 +166,7 @@ struct ohci_regs {
__u32 intrenable;
__u32 intrdisable;
/* memory pointers */
/* memory pointers (section 7.2) */
__u32 hcca;
__u32 ed_periodcurrent;
__u32 ed_controlhead;
......@@ -166,23 +175,25 @@ struct ohci_regs {
__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 @@ struct ohci_regs {
#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 @@ struct ohci_hcd {
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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment