summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoe <joe@FreeBSD.org>2003-07-14 19:50:06 +0000
committerjoe <joe@FreeBSD.org>2003-07-14 19:50:06 +0000
commit0d823209d1aef242dfc6360e1f1afc4d72f489b1 (patch)
treed364b5d8259c6678e8d9d25a073a3e3339a6a20d
parent51cf62b6924ba2387c4e71ed845e9ce7de2f21e3 (diff)
downloadFreeBSD-src-0d823209d1aef242dfc6360e1f1afc4d72f489b1.zip
FreeBSD-src-0d823209d1aef242dfc6360e1f1afc4d72f489b1.tar.gz
MFNetBSD: revision 1.134
date: 2002/12/07 07:33:20; author: toshii; state: Exp; lines: +50 -29 Update xfer->frlengths for input isoc transfer. Based on patches from SOMEYA Yoshihiko. Also fix error handling for isoc transfer somewhat; usb_transfer_complete shouldn't be called for more than once.
-rw-r--r--sys/dev/usb/ohci.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index fc05bfe..26e9222 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -9,6 +9,7 @@
* $NetBSD: ohci.c,v 1.131 2002/09/30 16:36:19 augustss Exp $
* $NetBSD: ohci.c,v 1.132 2002/12/07 06:52:11 toshii Exp $
* $NetBSD: ohci.c,v 1.133 2002/12/07 07:14:28 toshii Exp $
+ * $NetBSD: ohci.c,v 1.134 2002/12/07 07:33:20 toshii Exp $
* $NetBSD: ohci.c,v 1.138 2003/02/08 03:32:50 ichiro Exp $
* $NetBSD: ohci.c,v 1.140 2003/05/13 04:42:00 gson Exp $
*/
@@ -682,6 +683,8 @@ ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
panic("ohci_free_sitd: sitd=%p not done", sitd);
return;
}
+ /* Warn double free */
+ sitd->isdone = 0;
#endif
s = splusb();
@@ -1335,7 +1338,9 @@ ohci_softintr(void *v)
ohci_soft_itd_t *sitd, *sidone, *sitdnext;
ohci_soft_td_t *std, *sdone, *stdnext;
usbd_xfer_handle xfer;
+ struct ohci_pipe *opipe;
int len, cc, s;
+ int i, j, actlen, iframes, uedir;
DPRINTFN(10,("ohci_softintr: enter\n"));
@@ -1405,8 +1410,7 @@ ohci_softintr(void *v)
* the endpoint.
*/
ohci_soft_td_t *p, *n;
- struct ohci_pipe *opipe =
- (struct ohci_pipe *)xfer->pipe;
+ opipe = (struct ohci_pipe *)xfer->pipe;
DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n",
OHCI_TD_GET_CC(le32toh(std->td.td_flags)),
@@ -1467,22 +1471,50 @@ ohci_softintr(void *v)
printf("ohci_softintr: sitd=%p is done\n", sitd);
sitd->isdone = 1;
#endif
- cc = OHCI_ITD_GET_CC(le32toh(sitd->itd.itd_flags));
- if (cc == OHCI_CC_NO_ERROR) {
- /* XXX compute length for input */
- struct ohci_pipe *opipe =
- (struct ohci_pipe *)xfer->pipe;
- if (sitd->flags & OHCI_CALL_DONE) {
- opipe->u.iso.inuse -= xfer->nframes;
- /* XXX update frlengths with actual length */
- /* XXX xfer->actlen = actlen; */
- xfer->status = USBD_NORMAL_COMPLETION;
- usb_transfer_complete(xfer);
+ if (sitd->flags & OHCI_CALL_DONE) {
+ ohci_soft_itd_t *next;
+
+ opipe = (struct ohci_pipe *)xfer->pipe;
+ opipe->u.iso.inuse -= xfer->nframes;
+ uedir = UE_GET_DIR(xfer->pipe->endpoint->edesc->
+ bEndpointAddress);
+ xfer->status = USBD_NORMAL_COMPLETION;
+ actlen = 0;
+ for (i = 0, sitd = xfer->hcpriv;;
+ sitd = next) {
+ next = sitd->nextitd;
+ if (OHCI_ITD_GET_CC(sitd->itd.itd_flags)
+ != OHCI_CC_NO_ERROR)
+ xfer->status = USBD_IOERROR;
+ /* For input, update frlengths with actual */
+ /* XXX anything necessary for output? */
+ if (uedir == UE_DIR_IN &&
+ xfer->status == USBD_NORMAL_COMPLETION) {
+ iframes = OHCI_ITD_GET_FC(sitd->
+ itd.itd_flags);
+ for (j = 0; j < iframes; i++, j++) {
+ len = le16toh(sitd->
+ itd.itd_offset[j]);
+ len =
+ (OHCI_ITD_PSW_GET_CC(len) ==
+ OHCI_CC_NOT_ACCESSED) ? 0 :
+ OHCI_ITD_PSW_LENGTH(len);
+ xfer->frlengths[i] = len;
+ actlen += len;
+ }
+ }
+ if (sitd->flags & OHCI_CALL_DONE)
+ break;
+ ohci_free_sitd(sc, sitd);
}
- } else {
- /* XXX Do more */
- xfer->status = USBD_IOERROR;
+ ohci_free_sitd(sc, sitd);
+ if (uedir == UE_DIR_IN &&
+ xfer->status == USBD_NORMAL_COMPLETION)
+ xfer->actlen = actlen;
+
+ s = splusb();
usb_transfer_complete(xfer);
+ splx(s);
}
}
@@ -3338,6 +3370,7 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
s = splusb();
opipe->tail.itd = nsitd;
+ sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
sed->ed.ed_tailp = htole32(nsitd->physaddr);
splx(s);
@@ -3433,20 +3466,9 @@ ohci_device_isoc_abort(usbd_xfer_handle xfer)
void
ohci_device_isoc_done(usbd_xfer_handle xfer)
{
- struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
- ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
- ohci_soft_itd_t *sitd, *nsitd;
DPRINTFN(1,("ohci_device_isoc_done: xfer=%p\n", xfer));
- for (sitd = xfer->hcpriv;
- !(sitd->flags & OHCI_CALL_DONE);
- sitd = nsitd) {
- nsitd = sitd->nextitd;
- DPRINTFN(1,("ohci_device_isoc_done: free sitd=%p\n", sitd));
- ohci_free_sitd(sc, sitd);
- }
- ohci_free_sitd(sc, sitd);
xfer->hcpriv = NULL;
}
OpenPOWER on IntegriCloud