more USB driver fixes, now it passes usbtests 1-14
SVN-Revision: 9599
This commit is contained in:
parent
679089c6a8
commit
717ff24d47
2 changed files with 30 additions and 9 deletions
|
@ -45,7 +45,7 @@
|
||||||
#include "../core/hcd.h"
|
#include "../core/hcd.h"
|
||||||
#include "../core/hub.h"
|
#include "../core/hub.h"
|
||||||
|
|
||||||
#define DRIVER_VERSION "v0.10.1"
|
#define DRIVER_VERSION "v0.14.0"
|
||||||
#define DRIVER_AUTHOR "Gabor Juhos <juhosg at openwrt.org>"
|
#define DRIVER_AUTHOR "Gabor Juhos <juhosg at openwrt.org>"
|
||||||
#define DRIVER_DESC "ADMtek USB 1.1 Host Controller Driver"
|
#define DRIVER_DESC "ADMtek USB 1.1 Host Controller Driver"
|
||||||
|
|
||||||
|
@ -142,10 +142,6 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
|
||||||
/* number of packets from URB */
|
/* number of packets from URB */
|
||||||
td_cnt = urb->number_of_packets;
|
td_cnt = urb->number_of_packets;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
/* paranoia */
|
|
||||||
admhc_err(ahcd, "bad EP type %d", ed->type);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
urb_priv = urb_priv_alloc(ahcd, td_cnt, mem_flags);
|
urb_priv = urb_priv_alloc(ahcd, td_cnt, mem_flags);
|
||||||
|
@ -207,6 +203,7 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
|
||||||
#ifdef ADMHC_VERBOSE_DEBUG
|
#ifdef ADMHC_VERBOSE_DEBUG
|
||||||
admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1);
|
admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fail0:
|
fail0:
|
||||||
spin_unlock(&urb->lock);
|
spin_unlock(&urb->lock);
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -231,6 +231,11 @@ static void periodic_unlink (struct admhcd *ahcd, struct ed *ed)
|
||||||
*/
|
*/
|
||||||
static void ed_deschedule(struct admhcd *ahcd, struct ed *ed)
|
static void ed_deschedule(struct admhcd *ahcd, struct ed *ed)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef ADMHC_VERBOSE_DEBUG
|
||||||
|
admhc_dump_ed(ahcd, "ED-DESCHED", ed, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
|
ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
|
||||||
wmb();
|
wmb();
|
||||||
ed->state = ED_UNLINK;
|
ed->state = ED_UNLINK;
|
||||||
|
@ -333,6 +338,11 @@ static struct ed *ed_get(struct admhcd *ahcd, struct usb_host_endpoint *ep,
|
||||||
*/
|
*/
|
||||||
static void start_ed_unlink(struct admhcd *ahcd, struct ed *ed)
|
static void start_ed_unlink(struct admhcd *ahcd, struct ed *ed)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef ADMHC_VERBOSE_DEBUG
|
||||||
|
admhc_dump_ed(ahcd, "ED-UNLINK", ed, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE);
|
ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE);
|
||||||
ed_deschedule(ahcd, ed);
|
ed_deschedule(ahcd, ed);
|
||||||
|
|
||||||
|
@ -735,7 +745,7 @@ skip_ed:
|
||||||
last = &ed->ed_rm_next;
|
last = &ed->ed_rm_next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if (!list_empty(&ed->td_list)) {
|
if (!list_empty(&ed->td_list)) {
|
||||||
struct td *td;
|
struct td *td;
|
||||||
u32 head;
|
u32 head;
|
||||||
|
@ -749,6 +759,7 @@ skip_ed:
|
||||||
if (td->td_dma != head)
|
if (td->td_dma != head)
|
||||||
goto skip_ed;
|
goto skip_ed;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reentrancy: if we drop the schedule lock, someone might
|
/* reentrancy: if we drop the schedule lock, someone might
|
||||||
|
@ -793,7 +804,9 @@ rescan_this:
|
||||||
*prev = td->hwNextTD | savebits;
|
*prev = td->hwNextTD | savebits;
|
||||||
|
|
||||||
/* HC may have partly processed this TD */
|
/* HC may have partly processed this TD */
|
||||||
urb_print(ahcd, urb, "PARTIAL", 1);
|
#ifdef ADMHC_VERBOSE_DEBUG
|
||||||
|
urb_print(ahcd, urb, "PARTIAL", 0);
|
||||||
|
#endif
|
||||||
td_done(ahcd, urb, td);
|
td_done(ahcd, urb, td);
|
||||||
|
|
||||||
/* if URB is done, clean up */
|
/* if URB is done, clean up */
|
||||||
|
@ -809,7 +822,7 @@ rescan_this:
|
||||||
ed->state = ED_IDLE;
|
ed->state = ED_IDLE;
|
||||||
ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H);
|
ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H);
|
||||||
ed->hwNextED = 0;
|
ed->hwNextED = 0;
|
||||||
wmb ();
|
wmb();
|
||||||
ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP | ED_DEQUEUE);
|
ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP | ED_DEQUEUE);
|
||||||
|
|
||||||
/* but if there's work queued, reschedule */
|
/* but if there's work queued, reschedule */
|
||||||
|
@ -865,6 +878,14 @@ static void ed_unhalt(struct admhcd *ahcd, struct ed *ed, struct urb *urb)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ed_intr_refill(struct admhcd *ahcd, struct ed *ed)
|
||||||
|
{
|
||||||
|
__hc32 toggle = ed->hwHeadP & cpu_to_hc32(ahcd, ED_C);
|
||||||
|
|
||||||
|
ed->hwHeadP = ed->hwTailP | toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int is_ed_halted(struct admhcd *ahcd, struct ed *ed)
|
static inline int is_ed_halted(struct admhcd *ahcd, struct ed *ed)
|
||||||
{
|
{
|
||||||
return ((hc32_to_cpup(ahcd, &ed->hwHeadP) & ED_H) == ED_H);
|
return ((hc32_to_cpup(ahcd, &ed->hwHeadP) & ED_H) == ED_H);
|
||||||
|
@ -882,7 +903,7 @@ static void ed_update(struct admhcd *ahcd, struct ed *ed)
|
||||||
struct list_head *entry,*tmp;
|
struct list_head *entry,*tmp;
|
||||||
|
|
||||||
#ifdef ADMHC_VERBOSE_DEBUG
|
#ifdef ADMHC_VERBOSE_DEBUG
|
||||||
admhc_dump_ed(ahcd, "UPDATE", ed, 0);
|
admhc_dump_ed(ahcd, "UPDATE", ed, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
list_for_each_safe(entry, tmp, &ed->td_list) {
|
list_for_each_safe(entry, tmp, &ed->td_list) {
|
||||||
|
@ -899,6 +920,9 @@ static void ed_update(struct admhcd *ahcd, struct ed *ed)
|
||||||
if (is_ed_halted(ahcd, ed) && is_td_halted(ahcd, ed, td))
|
if (is_ed_halted(ahcd, ed) && is_td_halted(ahcd, ed, td))
|
||||||
ed_unhalt(ahcd, ed, urb);
|
ed_unhalt(ahcd, ed, urb);
|
||||||
|
|
||||||
|
if (ed->type == PIPE_INTERRUPT)
|
||||||
|
ed_intr_refill(ahcd,ed);
|
||||||
|
|
||||||
/* If all this urb's TDs are done, call complete() */
|
/* If all this urb's TDs are done, call complete() */
|
||||||
if (urb_priv->td_idx == urb_priv->td_cnt)
|
if (urb_priv->td_idx == urb_priv->td_cnt)
|
||||||
finish_urb(ahcd, urb);
|
finish_urb(ahcd, urb);
|
||||||
|
|
Loading…
Reference in a new issue