diff options
author | joe <joe@FreeBSD.org> | 2003-07-14 19:50:06 +0000 |
---|---|---|
committer | joe <joe@FreeBSD.org> | 2003-07-14 19:50:06 +0000 |
commit | 0d823209d1aef242dfc6360e1f1afc4d72f489b1 (patch) | |
tree | d364b5d8259c6678e8d9d25a073a3e3339a6a20d | |
parent | 51cf62b6924ba2387c4e71ed845e9ce7de2f21e3 (diff) | |
download | FreeBSD-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.c | 76 |
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; } |