summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authoraugustss <augustss@NetBSD.org>1999-08-02 19:30:34 +0000
committeraugustss <augustss@NetBSD.org>1999-08-02 19:30:34 +0000
commitd2db8329099d526c17d9516ecf01a6990ea215bd (patch)
tree66ba6b0bce04d5cb3cc5c5d41b1f7c531fba9d60 /sys/dev
parent3954583ce774c6d46c0678c82907cb775e1ea40d (diff)
Do abort of transfers in a sane way. Fixes PR 8041.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/uhci.c106
1 files changed, 69 insertions, 37 deletions
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 94ee974cf14..25df5dee353 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.32 1999/07/12 05:22:50 augustss Exp $ */
+/* $NetBSD: uhci.c,v 1.33 1999/08/02 19:30:34 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -147,7 +147,9 @@ usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *,
void uhci_timo __P((void *));
void uhci_waitintr __P((uhci_softc_t *, usbd_request_handle));
void uhci_check_intr __P((uhci_softc_t *, uhci_intr_info_t *));
-void uhci_ii_done __P((uhci_intr_info_t *, int));
+void uhci_ii_done __P((uhci_intr_info_t *));
+void uhci_ii_finish __P((uhci_intr_info_t *));
+void uhci_abort_req __P((usbd_request_handle, usbd_status status));
void uhci_timeout __P((void *));
void uhci_wakeup_ctrl __P((void *, int, int, void *, int));
void uhci_lock_frames __P((uhci_softc_t *));
@@ -813,27 +815,36 @@ uhci_check_intr(sc, ii)
usb_untimeout(uhci_timeout, ii, ii->timeout_handle);
upipe = (struct uhci_pipe *)ii->reqh->pipe;
upipe->pipe.endpoint->toggle = upipe->nexttoggle;
- uhci_ii_done(ii, 0);
+ uhci_ii_done(ii);
}
void
-uhci_ii_done(ii, timo)
+uhci_ii_done(ii)
uhci_intr_info_t *ii;
- int timo;
{
usbd_request_handle reqh = ii->reqh;
uhci_soft_td_t *std;
u_int32_t status;
int actlen;
- DPRINTFN(10, ("uhci_ii_done: ii=%p ready %d\n", ii, timo));
+#ifdef USB_DEBUG
+ DPRINTFN(10, ("uhci_ii_done: ii=%p ready\n", ii));
+ if (uhcidebug > 10)
+ uhci_dump_tds(ii->stdstart);
+#endif
+
+ if (reqh->status == USBD_CANCELLED ||
+ reqh->status == USBD_TIMEOUT) {
+ DPRINTF(("uhci_ii_done: aborted reqh=%p\n", reqh));
+ return;
+ }
#ifdef DIAGNOSTIC
{
int s = splhigh();
if (ii->isdone) {
splx(s);
- printf("uhci_ii_done: is done!\n");
+ printf("uhci_ii_done: ii=%p is done!\n", ii);
return;
}
ii->isdone = 1;
@@ -842,7 +853,6 @@ uhci_ii_done(ii, timo)
#endif
/* The transfer is done, compute actual length and status. */
- /* XXX Should stop at first inactive to get toggle right. */
/* XXX Is this correct for control xfers? */
actlen = 0;
for (std = ii->stdstart; std; std = std->td->link.std) {
@@ -872,14 +882,16 @@ uhci_ii_done(ii, timo)
} else {
reqh->status = USBD_NORMAL_COMPLETION;
}
- if (timo) {
- /* We got a timeout. Make sure transaction is not active. */
- reqh->status = USBD_TIMEOUT;
- for (std = ii->stdstart; std != 0; std = std->td->link.std)
- std->td->td_status &= ~UHCI_TD_ACTIVE;
- /* XXX should we wait 1 ms */
- }
- DPRINTFN(5, ("uhci_ii_done: calling handler ii=%p\n", ii));
+ uhci_ii_finish(ii);
+}
+
+void
+uhci_ii_finish(ii)
+ uhci_intr_info_t *ii;
+{
+ usbd_request_handle reqh = ii->reqh;
+
+ DPRINTFN(5, ("uhci_ii_finish: calling handler ii=%p\n", ii));
switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
@@ -911,12 +923,9 @@ uhci_timeout(addr)
void *addr;
{
uhci_intr_info_t *ii = addr;
- int s;
DPRINTF(("uhci_timeout: ii=%p\n", ii));
- s = splusb();
- uhci_ii_done(ii, 1);
- splx(s);
+ uhci_abort_req(ii->reqh, USBD_TIMEOUT);
}
/*
@@ -953,7 +962,7 @@ uhci_waitintr(sc, reqh)
ii = LIST_NEXT(ii, list))
;
if (ii)
- uhci_ii_done(ii, 1);
+ uhci_ii_done(ii);
else
panic("uhci_waitintr: lost intr_info\n");
}
@@ -1153,10 +1162,10 @@ uhci_free_std_chain(sc, std, stdend)
}
usbd_status
-uhci_alloc_std_chain(upipe, sc, len, rd, spd, dma, sp, ep)
+uhci_alloc_std_chain(upipe, sc, len, rd, shortok, dma, sp, ep)
struct uhci_pipe *upipe;
uhci_softc_t *sc;
- int len, rd, spd;
+ int len, rd, shortok;
usb_dma_t *dma;
uhci_soft_td_t **sp, **ep;
{
@@ -1167,9 +1176,9 @@ uhci_alloc_std_chain(upipe, sc, len, rd, spd, dma, sp, ep)
int addr = upipe->pipe.device->address;
int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
- DPRINTFN(15, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d "
- "spd=%d\n", addr, UE_GET_ADDR(endpt), len,
- upipe->pipe.device->lowspeed, spd));
+ DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d ls=%d "
+ "shortok=%d\n", addr, UE_GET_ADDR(endpt), len,
+ upipe->pipe.device->lowspeed, shortok));
if (len == 0) {
*sp = *ep = 0;
DPRINTFN(-1,("uhci_alloc_std_chain: len=0\n"));
@@ -1188,10 +1197,10 @@ uhci_alloc_std_chain(upipe, sc, len, rd, spd, dma, sp, ep)
lastp = 0;
lastlink = UHCI_PTR_T;
ntd--;
- status = UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE;
+ status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
if (upipe->pipe.device->lowspeed)
status |= UHCI_TD_LS;
- if (spd)
+ if (shortok)
status |= UHCI_TD_SPD;
for (i = ntd; i >= 0; i--) {
p = uhci_alloc_std(sc);
@@ -1219,7 +1228,7 @@ uhci_alloc_std_chain(upipe, sc, len, rd, spd, dma, sp, ep)
}
*sp = lastp;
/*upipe->pipe.endpoint->toggle = tog;*/
- DPRINTFN(10, ("uhci_alloc_std_chain: oldtog=%d newtog=%d\n",
+ DPRINTFN(10, ("uhci_alloc_std_chain: oldtog=%d nexttog=%d\n",
upipe->pipe.endpoint->toggle, upipe->nexttoggle));
return (USBD_NORMAL_COMPLETION);
}
@@ -1284,7 +1293,7 @@ uhci_device_bulk_start(reqh)
memcpy(KERNADDR(dmap), reqh->buffer, len);
#ifdef USB_DEBUG
- if (uhcidebug > 10) {
+ if (uhcidebug > 8) {
printf("uhci_device_bulk_transfer: xfer(1)\n");
uhci_dump_tds(xfer);
}
@@ -1336,9 +1345,33 @@ void
uhci_device_bulk_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1);/* make sure it is done */
- /* XXX call done */
+ DPRINTF(("uhci_device_bulk_abort:\n"));
+ uhci_abort_req(reqh, USBD_CANCELLED);
+}
+
+void
+uhci_abort_req(reqh, status)
+ usbd_request_handle reqh;
+ usbd_status status;
+{
+ struct uhci_pipe *upipe = (struct uhci_pipe *)reqh->pipe;
+ uhci_intr_info_t *ii = upipe->iinfo;
+ uhci_soft_td_t *std;
+ int s;
+
+ /* Make interrupt routine ignore it, */
+ reqh->status = USBD_CANCELLED;
+
+ /* make hardware ignore it, */
+ for (std = ii->stdstart; std != 0; std = std->td->link.std)
+ std->td->td_status &= ~UHCI_TD_ACTIVE;
+ /* make sure hardware has completed, */
+ usb_delay_ms(reqh->pipe->device->bus, 1);
+
+ /* and call final part of interrupt handler. */
+ s = splusb();
+ uhci_ii_finish(ii);
+ splx(s);
}
/* Close a device bulk pipe. */
@@ -1491,9 +1524,8 @@ void
uhci_device_ctrl_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX inactivate */
- usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */
- /* XXX call done */
+ DPRINTF(("uhci_device_ctrl_abort:\n"));
+ uhci_abort_req(reqh, USBD_CANCELLED);
}
/* Close a device control pipe. */
@@ -1729,7 +1761,7 @@ void
uhci_device_isoc_abort(reqh)
usbd_request_handle reqh;
{
- /* XXX Can't abort a single request. */
+ /* XXX Can't abort this. */
}
void