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 @@ ...@@ -2,9 +2,9 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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 $ * $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) ...@@ -74,27 +74,34 @@ static void urb_print (struct urb * urb, char * str, int small)
static inline struct ed * static inline struct ed *
dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma); 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 */ /* 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; int i, j;
__u32 * ed_p; u32 *ed_p;
int printed = 0;
for (i= 0; i < 32; i++) { for (i= 0; i < 32; i++) {
j = 5; j = 5;
ed_p = &(ohci->hcca->int_table [i]); ed_p = &(ohci->hcca->int_table [i]);
if (*ed_p == 0) if (*ed_p == 0)
continue; continue;
printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", printed = 1;
str, i, i); printk (KERN_DEBUG "%s, ohci %s frame %2d:",
label, ohci->hcd.bus_name, i);
while (*ed_p != 0 && j--) { while (*ed_p != 0 && j--) {
struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p)); 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; ed_p = &ed->hwNextED;
} }
printk ("\n"); 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) static void ohci_dump_intr_mask (char *label, __u32 mask)
{ {
...@@ -137,8 +144,9 @@ static void ohci_dump_status (struct ohci_hcd *controller) ...@@ -137,8 +144,9 @@ static void ohci_dump_status (struct ohci_hcd *controller)
__u32 temp; __u32 temp;
temp = readl (&regs->revision) & 0xff; temp = readl (&regs->revision) & 0xff;
if (temp != 0x10) dbg ("OHCI %d.%d, %s legacy support registers",
dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); 0x03 & (temp >> 4), (temp & 0x0f),
(temp & 0x10) ? "with" : "NO");
temp = readl (&regs->control); temp = readl (&regs->control);
dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, 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) ...@@ -225,8 +233,10 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
// dumps some of the state we know about // dumps some of the state we know about
ohci_dump_status (controller); ohci_dump_status (controller);
#ifdef OHCI_VERBOSE_DEBUG
if (verbose) if (verbose)
ep_print_int_eds (controller, "hcca"); ohci_dump_periodic (controller, "hcca");
#endif
dbg ("hcca frame #%04x", controller->hcca->frame_no); dbg ("hcca frame #%04x", controller->hcca->frame_no);
ohci_dump_roothub (controller, 1); ohci_dump_roothub (controller, 1);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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' ] * [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ] * [ uhci code and gregs ohci fragments ]
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
* v2.0 1999/05/04 * v2.0 1999/05/04
* v1.0 1999/04/27 initial release * 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 $ * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
*/ */
...@@ -74,10 +74,6 @@ ...@@ -74,10 +74,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */ #include <linux/interrupt.h> /* for in_interrupt () */
#ifndef CONFIG_USB_DEBUG
#define CONFIG_USB_DEBUG /* this is still experimental! */
#endif
#ifdef CONFIG_USB_DEBUG #ifdef CONFIG_USB_DEBUG
#define DEBUG #define DEBUG
#else #else
...@@ -258,7 +254,9 @@ static int ohci_urb_enqueue ( ...@@ -258,7 +254,9 @@ static int ohci_urb_enqueue (
if (ed->state != ED_OPER) if (ed->state != ED_OPER)
ep_link (ohci, ed); 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); td_submit_urb (urb);
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
...@@ -357,7 +355,9 @@ static int ohci_get_frame (struct usb_hcd *hcd) ...@@ -357,7 +355,9 @@ static int ohci_get_frame (struct usb_hcd *hcd)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
#ifdef OHCI_VERBOSE_DEBUG
dbg ("%s: ohci_get_frame", hcd->bus_name); dbg ("%s: ohci_get_frame", hcd->bus_name);
#endif
return le16_to_cpu (ohci->hcca->frame_no); return le16_to_cpu (ohci->hcca->frame_no);
} }
...@@ -841,9 +841,10 @@ static int ohci_resume (struct usb_hcd *hcd) ...@@ -841,9 +841,10 @@ static int ohci_resume (struct usb_hcd *hcd)
dl_done_list (ohci, dl_reverse_done_list (ohci)); dl_done_list (ohci, dl_reverse_done_list (ohci));
writel (OHCI_INTR_WDH, &ohci->regs->intrenable); writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
// writel (OHCI_BLF, &ohci->regs->cmdstatus); /* assume there are TDs on the bulk and control lists */
// writel (OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
ohci_dump_status (ohci);
// ohci_dump_status (ohci);
dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled); dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
break; break;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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 GPL
* $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $ * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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 $ * $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) ...@@ -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 # define OHCI_MEM_FLAGS SLAB_POISON
#else #else
# define OHCI_MEM_FLAGS 0 # define OHCI_MEM_FLAGS 0
...@@ -64,16 +64,17 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma) ...@@ -64,16 +64,17 @@ dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
return scan->virt; return scan->virt;
} }
static inline struct ed * static struct ed *
dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma) 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)]), return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
ed_dma); ed_dma);
} }
static inline struct td * static struct td *
dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) 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)]), return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),
td_dma); td_dma);
} }
...@@ -214,7 +215,7 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -214,7 +215,7 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
return td; return td;
} }
static inline void static void
td_free (struct ohci_hcd *hc, struct td *td) td_free (struct ohci_hcd *hc, struct td *td)
{ {
hash_free_td (hc, td); hash_free_td (hc, td);
...@@ -242,7 +243,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -242,7 +243,7 @@ ed_alloc (struct ohci_hcd *hc, int mem_flags)
return ed; return ed;
} }
static inline void static void
ed_free (struct ohci_hcd *hc, struct ed *ed) ed_free (struct ohci_hcd *hc, struct ed *ed)
{ {
hash_free_ed (hc, ed); hash_free_ed (hc, ed);
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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 $ * $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) ...@@ -95,11 +95,11 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
urb_print (urb, "RET", usb_pipeout (urb->pipe)); urb_print (urb, "RET", usb_pipeout (urb->pipe));
#endif #endif
// FIXME: but if urb->status says it was was unlinked ...
switch (usb_pipetype (urb->pipe)) { switch (usb_pipetype (urb->pipe)) {
case PIPE_INTERRUPT: case PIPE_INTERRUPT:
#ifdef CONFIG_PCI #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, pci_unmap_single (hc->hcd.pdev,
urb_priv->td [0]->data_dma, urb_priv->td [0]->data_dma,
urb->transfer_buffer_length, urb->transfer_buffer_length,
...@@ -107,16 +107,22 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb) ...@@ -107,16 +107,22 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
? PCI_DMA_TODEVICE ? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE); : PCI_DMA_FROMDEVICE);
#endif #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); 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->actual_length = 0;
urb->status = -EINPROGRESS; if (urb_priv->state != URB_DEL)
if (urb_priv->state != URB_DEL) { urb->status = -EINPROGRESS;
spin_lock_irqsave (&hc->lock, flags); spin_lock_irqsave (&hc->lock, flags);
td_submit_urb (urb); td_submit_urb (urb);
spin_unlock_irqrestore (&hc->lock, flags); spin_unlock_irqrestore (&hc->lock, flags);
}
break; break;
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
...@@ -126,7 +132,7 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb) ...@@ -126,7 +132,7 @@ static int return_urb (struct ohci_hcd *hc, struct urb *urb)
continue; continue;
if (urbt) { /* send the reply and requeue URB */ if (urbt) { /* send the reply and requeue URB */
#ifdef CONFIG_PCI #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, pci_unmap_single (hc->hcd.pdev,
urb_priv->td [0]->data_dma, urb_priv->td [0]->data_dma,
urb->transfer_buffer_length, urb->transfer_buffer_length,
...@@ -290,8 +296,8 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi) ...@@ -290,8 +296,8 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
ed->hwNextED = *ed_p; ed->hwNextED = *ed_p;
*ed_p = cpu_to_le32 (ed->dma); *ed_p = cpu_to_le32 (ed->dma);
} }
#ifdef DEBUG #ifdef OHCI_VERBOSE_DEBUG
ep_print_int_eds (ohci, "LINK_INT"); ohci_dump_periodic (ohci, "LINK_INT");
#endif #endif
break; break;
...@@ -313,8 +319,8 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi) ...@@ -313,8 +319,8 @@ static int ep_link (struct ohci_hcd *ohci, struct ed *edi)
ed->ed_prev = NULL; ed->ed_prev = NULL;
} }
ohci->ed_isotail = edi; ohci->ed_isotail = edi;
#ifdef DEBUG #ifdef OHCI_VERBOSE_DEBUG
ep_print_int_eds (ohci, "LINK_ISO"); ohci_dump_periodic (ohci, "LINK_ISO");
#endif #endif
break; break;
} }
...@@ -336,7 +342,7 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -336,7 +342,7 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
int interval; int interval;
__u32 *ed_p; __u32 *ed_p;
ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP); ed->hwINFO |= ED_SKIP;
switch (ed->type) { switch (ed->type) {
case PIPE_CONTROL: case PIPE_CONTROL:
...@@ -394,8 +400,8 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -394,8 +400,8 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
} }
for (i = int_branch; i < NUM_INTS; i += interval) for (i = int_branch; i < NUM_INTS; i += interval)
ohci->ohci_int_load [i] -= ed->int_load; ohci->ohci_int_load [i] -= ed->int_load;
#ifdef DEBUG #ifdef OHCI_VERBOSE_DEBUG
ep_print_int_eds (ohci, "UNLINK_INT"); ohci_dump_periodic (ohci, "UNLINK_INT");
#endif #endif
break; break;
...@@ -421,11 +427,15 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -421,11 +427,15 @@ static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed)
} }
} }
} }
#ifdef DEBUG #ifdef OHCI_VERBOSE_DEBUG
ep_print_int_eds (ohci, "UNLINK_ISO"); ohci_dump_periodic (ohci, "UNLINK_ISO");
#endif #endif
break; break;
} }
/* FIXME ED's "unlink" state is indeterminate;
* the HC might still be caching it (till SOF).
*/
ed->state = ED_UNLINK; ed->state = ED_UNLINK;
return 0; return 0;
} }
...@@ -478,7 +488,7 @@ static struct ed *ep_add_ed ( ...@@ -478,7 +488,7 @@ static struct ed *ep_add_ed (
} }
if (ed->state == ED_NEW) { 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 */ /* dummy td; end of td list for ed */
td = td_alloc (ohci, SLAB_ATOMIC); td = td_alloc (ohci, SLAB_ATOMIC);
if (!td) { if (!td) {
...@@ -492,8 +502,6 @@ static struct ed *ep_add_ed ( ...@@ -492,8 +502,6 @@ static struct ed *ep_add_ed (
ed->type = usb_pipetype (pipe); ed->type = usb_pipetype (pipe);
} }
ohci->dev [usb_pipedevice (pipe)] = udev;
// FIXME: don't do this if it's linked to the HC, // FIXME: don't do this if it's linked to the HC,
// we might clobber data toggle or other state ... // we might clobber data toggle or other state ...
...@@ -531,7 +539,7 @@ static void ed_unlink (struct usb_device *usb_dev, struct ed *ed) ...@@ -531,7 +539,7 @@ static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
return; return;
ed->state |= ED_URB_DEL; ed->state |= ED_URB_DEL;
ed->hwINFO |= __constant_cpu_to_le32 (OHCI_ED_SKIP); ed->hwINFO |= ED_SKIP;
switch (ed->type) { switch (ed->type) {
case PIPE_CONTROL: /* stop control list */ case PIPE_CONTROL: /* stop control list */
...@@ -582,7 +590,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info, ...@@ -582,7 +590,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
/* fill the old dummy TD */ /* fill the old dummy TD */
td = urb_priv->td [index] = dma_to_td (ohci, 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->ed = urb_priv->ed;
td->next_dl_td = NULL; td->next_dl_td = NULL;
...@@ -795,7 +803,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -795,7 +803,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
spin_lock_irqsave (&ohci->lock, flags); 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; ohci->hcca->done_head = 0;
while (td_list_hc) { while (td_list_hc) {
...@@ -806,26 +814,24 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) ...@@ -806,26 +814,24 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
dbg (" USB-error/status: %x : %p", dbg (" USB-error/status: %x : %p",
TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
td_list); td_list);
if (td_list->ed->hwHeadP /* typically the endpoint halted too */
& __constant_cpu_to_le32 (0x1)) { if (td_list->ed->hwHeadP & ED_H) {
if (urb_priv && ((td_list->index + 1) if (urb_priv && ((td_list->index + 1)
< urb_priv->length)) { < urb_priv->length)) {
td_list->ed->hwHeadP = td_list->ed->hwHeadP =
(urb_priv->td [urb_priv->length - 1]->hwNextTD (urb_priv->td [urb_priv->length - 1]->hwNextTD
& __constant_cpu_to_le32 (0xfffffff0)) & __constant_cpu_to_le32 (TD_MASK))
| (td_list->ed->hwHeadP | (td_list->ed->hwHeadP & ED_C);
& __constant_cpu_to_le32 (0x2));
urb_priv->td_cnt += urb_priv->length urb_priv->td_cnt += urb_priv->length
- td_list->index - 1; - td_list->index - 1;
} else } else
td_list->ed->hwHeadP &= td_list->ed->hwHeadP &= ~ED_H;
__constant_cpu_to_le32 (0xfffffff2);
} }
} }
td_list->next_dl_td = td_rev; td_list->next_dl_td = td_rev;
td_rev = td_list; 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); spin_unlock_irqrestore (&ohci->lock, flags);
return td_list; return td_list;
...@@ -851,10 +857,8 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame) ...@@ -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) { for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
tdTailP = dma_to_td (ohci, tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP));
le32_to_cpup (&ed->hwTailP) & 0xfffffff0); tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
tdHeadP = dma_to_td (ohci,
le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
edINFO = le32_to_cpup (&ed->hwINFO); edINFO = le32_to_cpup (&ed->hwINFO);
td_p = &ed->hwHeadP; td_p = &ed->hwHeadP;
...@@ -863,7 +867,7 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame) ...@@ -863,7 +867,7 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
urb_priv_t *urb_priv = td->urb->hcpriv; urb_priv_t *urb_priv = td->urb->hcpriv;
td_next = dma_to_td (ohci, td_next = dma_to_td (ohci,
le32_to_cpup (&td->hwNextTD) & 0xfffffff0); le32_to_cpup (&td->hwNextTD));
if ((urb_priv->state == URB_DEL)) { if ((urb_priv->state == URB_DEL)) {
tdINFO = le32_to_cpup (&td->hwINFO); tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE) if (TD_CC_GET (tdINFO) < 0xE)
...@@ -882,17 +886,16 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame) ...@@ -882,17 +886,16 @@ static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
} }
ed->state &= ~ED_URB_DEL; ed->state &= ~ED_URB_DEL;
tdHeadP = dma_to_td (ohci, tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
if (tdHeadP == tdTailP) { if (tdHeadP == tdTailP) {
if (ed->state == ED_OPER) if (ed->state == ED_OPER)
ep_unlink (ohci, ed); ep_unlink (ohci, ed);
td_free (ohci, tdTailP); td_free (ohci, tdTailP);
ed->hwINFO = __constant_cpu_to_le32 (OHCI_ED_SKIP); ed->hwINFO = ED_SKIP;
ed->state = ED_NEW; ed->state = ED_NEW;
} else } else
ed->hwINFO &= ~__constant_cpu_to_le32 (OHCI_ED_SKIP); ed->hwINFO &= ~ED_SKIP;
switch (ed->type) { switch (ed->type) {
case PIPE_CONTROL: case PIPE_CONTROL:
...@@ -938,7 +941,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list) ...@@ -938,7 +941,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
int cc = 0; int cc = 0;
struct urb *urb; struct urb *urb;
urb_priv_t *urb_priv; urb_priv_t *urb_priv;
__u32 tdINFO, edHeadP, edTailP; __u32 tdINFO;
unsigned long flags; unsigned long flags;
...@@ -968,7 +971,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list) ...@@ -968,7 +971,7 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
/* /*
* Except for periodic transfers, both branches do * Except for periodic transfers, both branches do
* the same thing. Periodic urbs get reissued until * 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)) if ((ed->state & (ED_OPER | ED_UNLINK))
&& (urb_priv->state != URB_DEL)) { && (urb_priv->state != URB_DEL)) {
...@@ -983,13 +986,11 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list) ...@@ -983,13 +986,11 @@ static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
if (ed->state != ED_NEW) { if (ed->state != ED_NEW) {
edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0; u32 edHeadP = ed->hwHeadP;
edTailP = le32_to_cpup (&ed->hwTailP);
// FIXME: ED_UNLINK is very fuzzy w.r.t. what the hc knows...
/* unlink eds if they are not busy */ /* 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); ep_unlink (ohci, ed);
} }
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
......
...@@ -2,86 +2,102 @@ ...@@ -2,86 +2,102 @@
* OHCI HCD (Host Controller Driver) for USB. * OHCI HCD (Host Controller Driver) for USB.
* *
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (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 $ * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
*/ */
static const int cc_to_error [16] = { /*
* OHCI Endpoint Descriptor (ED) ... holds TD queue
/* map OHCI status to errno values */ * See OHCI spec, section 4.2
/* No Error */ 0, */
/* CRC Error */ -EILSEQ, struct ed {
/* Bit Stuff */ -EPROTO, /* first fields are hardware-specified, le32 */
/* Data Togg */ -EILSEQ, __u32 hwINFO; /* endpoint config bitmap */
/* Stall */ -EPIPE, #define ED_ISO __constant_cpu_to_le32(1 << 15)
/* DevNotResp */ -ETIMEDOUT, #define ED_SKIP __constant_cpu_to_le32(1 << 14)
/* PIDCheck */ -EPROTO, #define ED_LOWSPEED __constant_cpu_to_le32(1 << 13)
/* UnExpPID */ -EPROTO, #define ED_OUT __constant_cpu_to_le32(0x01 << 11)
/* DataOver */ -EOVERFLOW, #define ED_IN __constant_cpu_to_le32(0x10 << 11)
/* DataUnder */ -EREMOTEIO, __u32 hwTailP; /* tail of TD list */
/* (for hw) */ -EIO, __u32 hwHeadP; /* head of TD list */
/* (for hw) */ -EIO, #define ED_C __constant_cpu_to_le32(0x02) /* toggle carry */
/* BufferOver */ -ECOMM, #define ED_H __constant_cpu_to_le32(0x01) /* halted */
/* BuffUnder */ -ENOSR, __u32 hwNextED; /* next ED in list */
/* (for HCD) */ -EALREADY,
/* (for HCD) */ -EALREADY /* rest are purely for the driver's use */
}; struct ed *ed_prev;
__u8 int_period;
__u8 int_branch;
/* ED States */ __u8 int_load;
__u8 int_interval;
__u8 state; // ED_{NEW,UNLINK,OPER}
#define ED_NEW 0x00 /* unused, no dummy td */ #define ED_NEW 0x00 /* unused, no dummy td */
#define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */ #define ED_UNLINK 0x01 /* dummy td, maybe linked to hc */
#define ED_OPER 0x02 /* dummy td, _is_ 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 */ dma_addr_t dma; /* addr of ED */
struct ed { } __attribute__ ((aligned(16)));
/* first fields are hardware-specified */
__u32 hwINFO; #define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */
__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)));
/* 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_GET(td_p) ((td_p >>28) & 0x0f)
#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) //#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
#define TD_EC 0x0C000000 #define TD_EC 0x0C000000 /* error count */
#define TD_T 0x03000000 #define TD_T 0x03000000 /* data toggle state */
#define TD_T_DATA0 0x02000000 #define TD_T_DATA0 0x02000000 /* DATA0 */
#define TD_T_DATA1 0x03000000 #define TD_T_DATA1 0x03000000 /* DATA1 */
#define TD_T_TOGGLE 0x00000000 #define TD_T_TOGGLE 0x00000000 /* uses ED_C */
#define TD_R 0x00040000 #define TD_DI 0x00E00000 /* frames before interrupt */
#define TD_DI 0x00E00000 //#define TD_DI_SET(X) (((X) & 0x07)<< 21)
#define TD_DI_SET(X) (((X) & 0x07)<< 21) #define TD_DP 0x00180000 /* direction/pid */
#define TD_DP 0x00180000 #define TD_DP_SETUP 0x00000000 /* SETUP pid */
#define TD_DP_SETUP 0x00000000 #define TD_DP_IN 0x00100000 /* IN pid */
#define TD_DP_IN 0x00100000 #define TD_DP_OUT 0x00080000 /* OUT pid */
#define TD_DP_OUT 0x00080000 /* 0x00180000 rsvd */
#define TD_R 0x00040000 /* round: short packets OK? */
#define TD_ISO 0x00010000 /* bits 0x1ffff are defined by HCD */
#define TD_DEL 0x00020000 #define TD_ISO 0x00010000 /* copy of ED_ISO */
/* CC Codes */ __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_NOERROR 0x00
#define TD_CC_CRC 0x01 #define TD_CC_CRC 0x01
#define TD_CC_BITSTUFFING 0x02 #define TD_CC_BITSTUFFING 0x02
...@@ -99,57 +115,50 @@ struct ed { ...@@ -99,57 +115,50 @@ struct ed {
#define TD_NOTACCESSED 0x0F #define TD_NOTACCESSED 0x0F
#define MAXPSW 1 /* map OHCI TD status codes (CC) to errno values */
static const int cc_to_error [16] = {
struct td { /* No Error */ 0,
/* first hardware fields are in all tds */ /* CRC Error */ -EILSEQ,
__u32 hwINFO; /* Bit Stuff */ -EPROTO,
__u32 hwCBP; /* Current Buffer Pointer */ /* Data Togg */ -EILSEQ,
__u32 hwNextTD; /* Next TD Pointer */ /* Stall */ -EPIPE,
__u32 hwBE; /* Memory Buffer End Pointer */ /* DevNotResp */ -ETIMEDOUT,
/* PIDCheck */ -EPROTO,
__u16 hwPSW [MAXPSW]; /* PSW is only for ISO */ /* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
__u8 unused; /* DataUnder */ -EREMOTEIO,
__u8 index; /* (for hw) */ -EIO,
struct ed *ed; /* (for hw) */ -EIO,
struct td *next_dl_td; /* BufferOver */ -ECOMM,
struct urb *urb; /* BuffUnder */ -ENOSR,
/* (for HCD) */ -EALREADY,
dma_addr_t td_dma; /* (for HCD) */ -EALREADY
dma_addr_t data_dma; };
__u32 unused2 [2];
} __attribute((aligned(32))); /* iso needs 32 */
#define OHCI_ED_SKIP (1 << 14)
/* /*
* The HCCA (Host Controller Communications Area) is a 256 byte * 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. * told the base address of it. It must be 256-byte aligned.
*/ */
#define NUM_INTS 32 /* part of the OHCI standard */
struct ohci_hcca { 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 frame_no; /* current frame number */
__u16 pad1; /* set to 0 on each frame_no change */ __u16 pad1; /* set to 0 on each frame_no change */
__u32 done_head; /* info returned for an interrupt */ __u32 done_head; /* info returned for an interrupt */
u8 reserved_for_hc [116]; 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. * 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!!
#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ * Layout is in section 7 (and appendix B) of the spec.
/*
* 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!!
*/ */
struct ohci_regs { struct ohci_regs {
/* control and status registers */ /* control and status registers (section 7.1) */
__u32 revision; __u32 revision;
__u32 control; __u32 control;
__u32 cmdstatus; __u32 cmdstatus;
...@@ -157,7 +166,7 @@ struct ohci_regs { ...@@ -157,7 +166,7 @@ struct ohci_regs {
__u32 intrenable; __u32 intrenable;
__u32 intrdisable; __u32 intrdisable;
/* memory pointers */ /* memory pointers (section 7.2) */
__u32 hcca; __u32 hcca;
__u32 ed_periodcurrent; __u32 ed_periodcurrent;
__u32 ed_controlhead; __u32 ed_controlhead;
...@@ -166,23 +175,25 @@ struct ohci_regs { ...@@ -166,23 +175,25 @@ struct ohci_regs {
__u32 ed_bulkcurrent; __u32 ed_bulkcurrent;
__u32 donehead; __u32 donehead;
/* frame counters */ /* frame counters (section 7.3) */
__u32 fminterval; __u32 fminterval;
__u32 fmremaining; __u32 fmremaining;
__u32 fmnumber; __u32 fmnumber;
__u32 periodicstart; __u32 periodicstart;
__u32 lsthresh; __u32 lsthresh;
/* Root hub ports */ /* Root hub ports (section 7.4) */
struct ohci_roothub_regs { struct ohci_roothub_regs {
__u32 a; __u32 a;
__u32 b; __u32 b;
__u32 status; __u32 status;
#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */
__u32 portstatus [MAX_ROOT_PORTS]; __u32 portstatus [MAX_ROOT_PORTS];
} roothub; } roothub;
/* and some optional registers for legacy compatibility */ /* and optional "legacy support" registers (appendix B) at 0x0100 */
} __attribute((aligned(32)));
} __attribute__ ((aligned(32)));
/* OHCI CONTROL AND STATUS REGISTER MASKS */ /* OHCI CONTROL AND STATUS REGISTER MASKS */
...@@ -270,9 +281,8 @@ struct ohci_regs { ...@@ -270,9 +281,8 @@ struct ohci_regs {
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ #define RH_A_POTPGT (0xff << 24) /* power on to power good time */
/* urb */ /* hcd-private per-urb state */
typedef struct urb_priv typedef struct urb_priv {
{
struct ed *ed; struct ed *ed;
__u16 length; // # tds in this request __u16 length; // # tds in this request
__u16 td_cnt; // tds already serviced __u16 td_cnt; // tds already serviced
...@@ -345,7 +355,6 @@ struct ohci_hcd { ...@@ -345,7 +355,6 @@ struct ohci_hcd {
int sleeping; int sleeping;
int ohci_int_load [NUM_INTS]; int ohci_int_load [NUM_INTS];
u32 hc_control; /* copy of hc control reg */ u32 hc_control; /* copy of hc control reg */
struct usb_device *dev [128];
unsigned long flags; /* for HC bugs */ unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #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