summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/ohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/ohci.c')
-rw-r--r--sys/dev/usb/ohci.c425
1 files changed, 241 insertions, 184 deletions
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 0b84a32..c8e6b17 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -217,6 +217,8 @@ Static void ohci_device_isoc_done(usbd_xfer_handle);
Static usbd_status ohci_device_setintr(ohci_softc_t *sc,
struct ohci_pipe *pipe, int ival);
+Static usbd_status ohci_device_intr_insert(ohci_softc_t *sc,
+ usbd_xfer_handle xfer);
Static int ohci_str(usb_string_descriptor_t *, int, const char *);
@@ -510,11 +512,11 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
ohci_soft_td_t *sp, ohci_soft_td_t **ep)
{
ohci_soft_td_t *next, *cur;
- ohci_physaddr_t dataphys;
+ ohci_physaddr_t dataphys, physend;
u_int32_t tdflags;
int offset = 0;
- int len, curlen;
- usb_dma_t *dma = &xfer->dmabuf;
+ int len, maxp, curlen, curlen2, seg, segoff;
+ struct usb_dma_mapping *dma = &xfer->dmamap;
u_int16_t flags = xfer->flags;
DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen));
@@ -522,22 +524,22 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
len = alen;
cur = sp;
+ maxp = UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
tdflags = htole32(
(rd ? OHCI_TD_IN : OHCI_TD_OUT) |
(flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_SET_DI(6));
+ seg = 0;
+ segoff = 0;
for (;;) {
next = ohci_alloc_std(sc);
if (next == NULL)
goto nomem;
- dataphys = DMAADDR(dma, offset);
-
/*
* The OHCI hardware can handle at most one 4k crossing.
- * XXX - currently we only allocate contigous buffers, but
- * the OHCI spec says: If during the data transfer the buffer
+ * The OHCI spec says: If during the data transfer the buffer
* address contained in the HC's working copy of
* CurrentBufferPointer crosses a 4K boundary, the upper 20
* bits of Buffer End are copied to the working value of
@@ -545,34 +547,67 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
* be the 0th byte in the same 4K page that contains the
* last byte of the buffer (the 4K boundary crossing may
* occur within a data packet transfer.)
- *
- * If/when dma has multiple segments, this will need to
- * properly handle fragmenting TD's.
- *
- * Note that if we are gathering data from multiple SMALL
- * segments, e.g. mbufs, we need to do special gymnastics,
- * e.g. bounce buffering or data aggregation,
- * BEFORE WE GET HERE because a bulk USB transfer must
- * consist of maximally sized packets right up to the end.
- * A shorter than maximal packet means that it is the end
- * of the transfer. If the data transfer length is a
- * multiple of the packet size, then a 0 byte
- * packet will be the signal of the end of transfer.
- * Since packets can't cross TDs this means that
- * each TD except the last one must cover an exact multiple
- * of the maximal packet length.
*/
- if (OHCI_PAGE_OFFSET(dataphys) + len <= (2 * OHCI_PAGE_SIZE)) {
- /* We can handle all that remains in this TD */
+ KASSERT(seg < dma->nsegs, ("ohci_alloc_std_chain: overrun"));
+ dataphys = dma->segs[seg].ds_addr + segoff;
+ curlen = dma->segs[seg].ds_len - segoff;
+ if (curlen > len)
curlen = len;
+ physend = dataphys + curlen - 1;
+ if (OHCI_PAGE(dataphys) != OHCI_PAGE(physend)) {
+ /* Truncate to two OHCI pages if there are more. */
+ if (curlen > 2 * OHCI_PAGE_SIZE -
+ OHCI_PAGE_OFFSET(dataphys))
+ curlen = 2 * OHCI_PAGE_SIZE -
+ OHCI_PAGE_OFFSET(dataphys);
+ if (curlen < len)
+ curlen -= curlen % maxp;
+ physend = dataphys + curlen - 1;
+ } else if (OHCI_PAGE_OFFSET(physend + 1) == 0 && curlen < len &&
+ curlen + segoff == dma->segs[seg].ds_len) {
+ /* We can possibly include another segment. */
+ KASSERT(seg + 1 < dma->nsegs,
+ ("ohci_alloc_std_chain: overrun2"));
+ seg++;
+
+ /* Determine how much of the second segment to use. */
+ curlen2 = dma->segs[seg].ds_len;
+ if (curlen + curlen2 > len)
+ curlen2 = len - curlen;
+ if (OHCI_PAGE(dma->segs[seg].ds_addr) !=
+ OHCI_PAGE(dma->segs[seg].ds_addr + curlen2 - 1))
+ curlen2 = OHCI_PAGE_SIZE -
+ OHCI_PAGE_OFFSET(dma->segs[seg].ds_addr);
+ if (curlen + curlen2 < len)
+ curlen2 -= (curlen + curlen2) % maxp;
+
+ if (curlen2 > 0) {
+ /* We can include a second segment */
+ segoff = curlen2;
+ physend = dma->segs[seg].ds_addr + curlen2 - 1;
+ curlen += curlen2;
+ } else {
+ /* Second segment not usable now. */
+ seg--;
+ segoff += curlen;
+ }
} else {
- /* must use multiple TDs, fill as much as possible. */
- curlen = 2 * OHCI_PAGE_SIZE -
- OHCI_PAGE_OFFSET(dataphys);
- /* the length must be a multiple of the max size */
- curlen -= curlen %
- UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
- KASSERT((curlen != 0), ("ohci_alloc_std: curlen == 0"));
+ /* Simple case where there is just one OHCI page. */
+ segoff += curlen;
+ }
+ if (curlen == 0 && len != 0) {
+ /*
+ * A maxp length packet would need to be split.
+ * This shouldn't be possible if PAGE_SIZE >= 4k
+ * and the buffer is contiguous in virtual memory.
+ */
+ panic("ohci_alloc_std_chain: XXX need to copy");
+ }
+ if (segoff >= dma->segs[seg].ds_len) {
+ KASSERT(segoff == dma->segs[seg].ds_len,
+ ("ohci_alloc_std_chain: overlap"));
+ seg++;
+ segoff = 0;
}
DPRINTFN(4,("ohci_alloc_std_chain: dataphys=0x%08x "
"len=%d curlen=%d\n",
@@ -583,7 +618,7 @@ ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
cur->td.td_cbp = htole32(dataphys);
cur->nexttd = next;
cur->td.td_nexttd = htole32(next->physaddr);
- cur->td.td_be = htole32(DMAADDR(dma, offset + curlen - 1));
+ cur->td.td_be = htole32(physend);
cur->len = curlen;
cur->flags = OHCI_ADD_LEN;
cur->xfer = xfer;
@@ -1009,14 +1044,6 @@ void
ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
{
struct ohci_softc *sc = (struct ohci_softc *)bus;
- struct ohci_xfer *oxfer = (struct ohci_xfer *)xfer;
- ohci_soft_itd_t *sitd;
-
- if (oxfer->ohci_xfer_flags & OHCI_ISOC_DIRTY) {
- for (sitd = xfer->hcpriv; sitd != NULL && sitd->xfer == xfer;
- sitd = sitd->nextitd)
- ohci_free_sitd(sc, sitd);
- }
#ifdef DIAGNOSTIC
if (xfer->busy_free != XFER_BUSY) {
@@ -1535,6 +1562,11 @@ ohci_softintr(void *v)
if (sitd->flags & OHCI_CALL_DONE)
break;
}
+ for (sitd = xfer->hcpriv; sitd->xfer == xfer;
+ sitd = next) {
+ next = sitd->nextitd;
+ ohci_free_sitd(sc, sitd);
+ }
s = splusb();
usb_transfer_complete(xfer);
@@ -1571,42 +1603,18 @@ ohci_device_intr_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_ed_t *sed = opipe->sed;
- ohci_soft_td_t *data, *tail;
-
+ usbd_status err;
DPRINTFN(10,("ohci_device_intr_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
xfer->hcpriv = NULL;
-
if (xfer->pipe->repeat) {
- data = opipe->tail.td;
- tail = ohci_alloc_std(sc); /* XXX should reuse TD */
- if (tail == NULL) {
- xfer->status = USBD_NOMEM;
+ err = ohci_device_intr_insert(sc, xfer);
+ if (err) {
+ xfer->status = err;
return;
}
- tail->xfer = NULL;
-
- data->td.td_flags = htole32(
- OHCI_TD_IN | OHCI_TD_NOCC |
- OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
- if (xfer->flags & USBD_SHORT_XFER_OK)
- data->td.td_flags |= htole32(OHCI_TD_R);
- data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
- data->nexttd = tail;
- data->td.td_nexttd = htole32(tail->physaddr);
- data->td.td_be = htole32(le32toh(data->td.td_cbp) +
- xfer->length - 1);
- data->len = xfer->length;
- data->xfer = xfer;
- data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN;
- xfer->hcpriv = data;
- xfer->actlen = 0;
-
- sed->ed.ed_tailp = htole32(tail->physaddr);
- opipe->tail.td = tail;
}
}
@@ -1638,7 +1646,7 @@ ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
pipe = xfer->pipe;
- p = KERNADDR(&xfer->dmabuf, 0);
+ p = xfer->buffer;
m = min(sc->sc_noport, xfer->length * 8 - 1);
memset(p, 0, xfer->length);
for (i = 1; i <= m; i++) {
@@ -2284,6 +2292,7 @@ ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
usb_rem_task(xfer->pipe->device, &OXFER(xfer)->abort_task);
usb_transfer_complete(xfer);
splx(s);
+ return;
}
if (xfer->device->bus->intr_context || !curproc)
@@ -2519,7 +2528,7 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer)
index = UGETW(req->wIndex);
if (len != 0)
- buf = KERNADDR(&xfer->dmabuf, 0);
+ buf = xfer->buffer;
#define C(x,y) ((x) | ((y) << 8))
switch(C(req->bRequest, req->bmRequestType)) {
@@ -3099,26 +3108,44 @@ Static usbd_status
ohci_device_intr_start(usbd_xfer_handle xfer)
{
struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
- usbd_device_handle dev = opipe->pipe.device;
- ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
+ ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
ohci_soft_ed_t *sed = opipe->sed;
- ohci_soft_td_t *data, *tail;
- int len;
- int s;
+ usbd_status err;
if (sc->sc_dying)
return (USBD_IOERROR);
- DPRINTFN(3, ("ohci_device_intr_transfer: xfer=%p len=%d "
+ DPRINTFN(3, ("ohci_device_intr_start: xfer=%p len=%d "
"flags=%d priv=%p\n",
xfer, xfer->length, xfer->flags, xfer->priv));
#ifdef DIAGNOSTIC
if (xfer->rqflags & URQ_REQUEST)
- panic("ohci_device_intr_transfer: a request");
+ panic("ohci_device_intr_start: a request");
#endif
- len = xfer->length;
+ err = ohci_device_intr_insert(sc, xfer);
+ if (err)
+ return (err);
+
+ sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
+
+ return (USBD_IN_PROGRESS);
+}
+
+/*
+ * Insert an interrupt transfer into an endpoint descriptor list
+ */
+Static usbd_status
+ohci_device_intr_insert(ohci_softc_t *sc, usbd_xfer_handle xfer)
+{
+ struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
+ ohci_soft_ed_t *sed = opipe->sed;
+ ohci_soft_td_t *data, *tail;
+ ohci_physaddr_t dataphys, physend;
+ int s;
+
+ DPRINTFN(4, ("ohci_device_intr_insert: xfer=%p", xfer));
data = opipe->tail.td;
tail = ohci_alloc_std(sc);
@@ -3131,18 +3158,43 @@ ohci_device_intr_start(usbd_xfer_handle xfer)
OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
if (xfer->flags & USBD_SHORT_XFER_OK)
data->td.td_flags |= htole32(OHCI_TD_R);
- data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
+ /*
+ * Assume a short mapping with no complications, which
+ * should always be true for <= 4k buffers in contiguous
+ * virtual memory. The data can take the following forms:
+ * 1 segment in 1 OHCI page
+ * 1 segment in 2 OHCI pages
+ * 2 segments in 2 OHCI pages
+ * (see comment in ohci_alloc_std_chain() for details)
+ */
+ KASSERT(xfer->length > 0 && xfer->length <= OHCI_PAGE_SIZE,
+ ("ohci_device_intr_insert: bad length %d", xfer->length));
+ dataphys = xfer->dmamap.segs[0].ds_addr;
+ physend = dataphys + xfer->length - 1;
+ if (xfer->dmamap.nsegs == 2) {
+ KASSERT(OHCI_PAGE_OFFSET(dataphys +
+ xfer->dmamap.segs[0].ds_len) == 0,
+ ("ohci_device_intr_insert: bad seg 0 termination"));
+ physend = xfer->dmamap.segs[1].ds_addr + xfer->length -
+ xfer->dmamap.segs[0].ds_len - 1;
+ } else {
+ KASSERT(xfer->dmamap.nsegs == 1,
+ ("ohci_device_intr_insert: bad seg count %d",
+ (u_int)xfer->dmamap.nsegs));
+ }
+ data->td.td_cbp = htole32(dataphys);
data->nexttd = tail;
data->td.td_nexttd = htole32(tail->physaddr);
- data->td.td_be = htole32(le32toh(data->td.td_cbp) + len - 1);
- data->len = len;
+ data->td.td_be = htole32(physend);
+ data->len = xfer->length;
data->xfer = xfer;
data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN;
xfer->hcpriv = data;
+ xfer->actlen = 0;
#ifdef USB_DEBUG
if (ohcidebug > 5) {
- DPRINTF(("ohci_device_intr_transfer:\n"));
+ DPRINTF(("ohci_device_intr_insert:\n"));
ohci_dump_ed(sed);
ohci_dump_tds(data);
}
@@ -3152,25 +3204,9 @@ ohci_device_intr_start(usbd_xfer_handle xfer)
s = splusb();
sed->ed.ed_tailp = htole32(tail->physaddr);
opipe->tail.td = tail;
- sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
-
-#if 0
-/*
- * This goes horribly wrong, printing thousands of descriptors,
- * because false references are followed due to the fact that the
- * TD is gone.
- */
- if (ohcidebug > 5) {
- usb_delay_ms(&sc->sc_bus, 5);
- DPRINTF(("ohci_device_intr_transfer: status=%x\n",
- OREAD4(sc, OHCI_COMMAND_STATUS)));
- ohci_dump_ed(sed);
- ohci_dump_tds(data);
- }
-#endif
splx(s);
- return (USBD_IN_PROGRESS);
+ return (USBD_NORMAL_COMPLETION);
}
/* Abort a device control request. */
@@ -3325,10 +3361,10 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
ohci_soft_ed_t *sed = opipe->sed;
struct iso *iso = &opipe->u.iso;
- struct ohci_xfer *oxfer = (struct ohci_xfer *)xfer;
+ struct usb_dma_mapping *dma = &xfer->dmamap;
ohci_soft_itd_t *sitd, *nsitd;
- ohci_physaddr_t buf, offs, noffs, bp0, tdphys;
- int i, ncur, nframes;
+ ohci_physaddr_t dataphys, bp0, physend, prevpage;
+ int curlen, i, len, ncur, nframes, npages, seg, segoff;
int s;
DPRINTFN(1,("ohci_device_isoc_enter: used=%d next=%d xfer=%p "
@@ -3345,94 +3381,115 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
iso->next));
}
- if (xfer->hcpriv) {
- for (sitd = xfer->hcpriv; sitd != NULL && sitd->xfer == xfer;
- sitd = sitd->nextitd)
- ohci_free_sitd(sc, sitd); /* Free ITDs in prev xfer*/
-
- if (sitd == NULL) {
- sitd = ohci_alloc_sitd(sc);
- if (sitd == NULL)
- panic("cant alloc isoc");
- opipe->tail.itd = sitd;
- tdphys = sitd->physaddr;
- sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* Stop*/
- sed->ed.ed_headp =
- sed->ed.ed_tailp = htole32(tdphys);
- sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* Start.*/
- }
- }
-
sitd = opipe->tail.itd;
- buf = DMAADDR(&xfer->dmabuf, 0);
- bp0 = OHCI_PAGE(buf);
- offs = OHCI_PAGE_OFFSET(buf);
nframes = xfer->nframes;
xfer->hcpriv = sitd;
- for (i = ncur = 0; i < nframes; i++, ncur++) {
- noffs = offs + xfer->frlengths[i];
- if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */
- OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */
-
- /* Allocate next ITD */
- nsitd = ohci_alloc_sitd(sc);
- if (nsitd == NULL) {
- /* XXX what now? */
- printf("%s: isoc TD alloc failed\n",
- USBDEVNAME(sc->sc_bus.bdev));
- return;
+ seg = 0;
+ segoff = 0;
+ i = 0;
+ while (i < nframes) {
+ /*
+ * Fill in as many ITD frames as possible.
+ */
+ KASSERT(seg < dma->nsegs, ("ohci_device_isoc_enter: overrun"));
+ bp0 = dma->segs[seg].ds_addr + segoff;
+ sitd->itd.itd_bp0 = htole32(bp0);
+ prevpage = OHCI_PAGE(bp0);
+ npages = 1;
+
+ ncur = 0;
+ while (ncur < OHCI_ITD_NOFFSET && i < nframes) {
+ /* Find the frame start and end physical addresses. */
+ len = xfer->frlengths[i];
+ dataphys = dma->segs[seg].ds_addr + segoff;
+ curlen = dma->segs[seg].ds_len - segoff;
+ if (len > curlen) {
+ KASSERT(seg + 1 < dma->nsegs,
+ ("ohci_device_isoc_enter: overrun2"));
+ seg++;
+ segoff = len - curlen;
+ } else {
+ segoff += len;
+ }
+ KASSERT(segoff <= dma->segs[seg].ds_len,
+ ("ohci_device_isoc_enter: overrun3"));
+ physend = dma->segs[seg].ds_addr + segoff - 1;
+
+ /* Check if there would be more than 2 pages . */
+ if (OHCI_PAGE(dataphys) != prevpage) {
+ prevpage = OHCI_PAGE(dataphys);
+ npages++;
+ }
+ if (OHCI_PAGE(physend) != prevpage) {
+ prevpage = OHCI_PAGE(physend);
+ npages++;
+ }
+ if (npages > 2) {
+ /* We cannot fit this frame now. */
+ segoff -= len;
+ if (segoff < 0) {
+ seg--;
+ segoff += dma->segs[seg].ds_len;
+ }
+ break;
}
- /* Fill current ITD */
+ sitd->itd.itd_be = htole32(physend);
+ sitd->itd.itd_offset[ncur] =
+ htole16(OHCI_ITD_MK_OFFS(OHCI_PAGE(dataphys) ==
+ OHCI_PAGE(bp0) ? 0 : 1, dataphys));
+ i++;
+ ncur++;
+ }
+ if (segoff >= dma->segs[seg].ds_len) {
+ KASSERT(segoff == dma->segs[seg].ds_len,
+ ("ohci_device_isoc_enter: overlap"));
+ seg++;
+ segoff = 0;
+ }
+
+ /* Allocate next ITD */
+ nsitd = ohci_alloc_sitd(sc);
+ if (nsitd == NULL) {
+ /* XXX what now? */
+ printf("%s: isoc TD alloc failed\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ return;
+ }
+
+ /* Fill out remaining fields of current ITD */
+ sitd->nextitd = nsitd;
+ sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
+ sitd->xfer = xfer;
+ if (i < nframes) {
sitd->itd.itd_flags = htole32(
OHCI_ITD_NOCC |
OHCI_ITD_SET_SF(iso->next) |
OHCI_ITD_SET_DI(6) | /* delay intr a little */
OHCI_ITD_SET_FC(ncur));
- sitd->itd.itd_bp0 = htole32(bp0);
- sitd->nextitd = nsitd;
- sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
- sitd->itd.itd_be = htole32(bp0 + offs - 1);
- sitd->xfer = xfer;
sitd->flags = OHCI_ITD_ACTIVE;
-
- sitd = nsitd;
- iso->next = iso->next + ncur;
- bp0 = OHCI_PAGE(buf + offs);
- ncur = 0;
+ } else {
+ sitd->itd.itd_flags = htole32(
+ OHCI_ITD_NOCC |
+ OHCI_ITD_SET_SF(iso->next) |
+ OHCI_ITD_SET_DI(0) |
+ OHCI_ITD_SET_FC(ncur));
+ sitd->flags = OHCI_CALL_DONE | OHCI_ITD_ACTIVE;
}
- sitd->itd.itd_offset[ncur] = htole16(OHCI_ITD_MK_OFFS(offs));
- offs = noffs;
- }
- nsitd = ohci_alloc_sitd(sc);
- if (nsitd == NULL) {
- /* XXX what now? */
- printf("%s: isoc TD alloc failed\n",
- USBDEVNAME(sc->sc_bus.bdev));
- return;
+ iso->next += ncur;
+
+ sitd = nsitd;
}
- /* Fixup last used ITD */
- sitd->itd.itd_flags = htole32(
- OHCI_ITD_NOCC |
- OHCI_ITD_SET_SF(iso->next) |
- OHCI_ITD_SET_DI(0) |
- OHCI_ITD_SET_FC(ncur));
- sitd->itd.itd_bp0 = htole32(bp0);
- sitd->nextitd = nsitd;
- sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
- sitd->itd.itd_be = htole32(bp0 + offs - 1);
- sitd->xfer = xfer;
- sitd->flags = OHCI_CALL_DONE | OHCI_ITD_ACTIVE;
-
- iso->next = iso->next + ncur;
+
iso->inuse += nframes;
- xfer->actlen = offs; /* XXX pretend we did it all */
+ /* XXX pretend we did it all */
+ xfer->actlen = 0;
+ for (i = 0; i < nframes; i++)
+ xfer->actlen += xfer->frlengths[i];
xfer->status = USBD_IN_PROGRESS;
- oxfer->ohci_xfer_flags |= OHCI_ISOC_DIRTY;
-
#ifdef USB_DEBUG
if (ohcidebug > 5) {
DPRINTF(("ohci_device_isoc_enter: frame=%d\n",
@@ -3443,9 +3500,9 @@ ohci_device_isoc_enter(usbd_xfer_handle xfer)
#endif
s = splusb();
- opipe->tail.itd = nsitd;
+ opipe->tail.itd = sitd;
sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
- sed->ed.ed_tailp = htole32(nsitd->physaddr);
+ sed->ed.ed_tailp = htole32(sitd->physaddr);
splx(s);
#ifdef USB_DEBUG
@@ -3493,7 +3550,7 @@ ohci_device_isoc_abort(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_ed_t *sed;
- ohci_soft_itd_t *sitd, *tmp_sitd;
+ ohci_soft_itd_t *sitd, *sitdnext, *tmp_sitd;
int s,undone,num_sitds;
s = splusb();
@@ -3556,20 +3613,20 @@ ohci_device_isoc_abort(usbd_xfer_handle xfer)
}
} while( undone != 0 );
+ /* Free the sitds */
+ for (sitd = xfer->hcpriv; sitd->xfer == xfer;
+ sitd = sitdnext) {
+ sitdnext = sitd->nextitd;
+ ohci_free_sitd(sc, sitd);
+ }
s = splusb();
/* Run callback. */
usb_transfer_complete(xfer);
- if (sitd != NULL)
- /*
- * Only if there is a `next' sitd in next xfer...
- * unlink this xfer's sitds.
- */
- sed->ed.ed_headp = htole32(sitd->physaddr);
- else
- sed->ed.ed_headp = 0;
+ /* There is always a `next' sitd so link it up. */
+ sed->ed.ed_headp = htole32(sitd->physaddr);
sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */
OpenPOWER on IntegriCloud