Hello Jérôme,

On 10/07/14(Thu) 19:45, Jérôme Frgacic wrote:
> Hello misc,
> 
> I'm currently trying to configure lpd to work with an HP Officejet 4500
> printer. 
> 
> After some researches and modifications, it works, but there still a
> problem : when all jobs are done I have this message that appear
> on the console : “ehci_idone: ex=0xXXXXXXXXXXXXXXXX is done!” and,
> sometimes, the printer still busy after printing (which forces me to push
> on the “cancel” button of the printer).
> 
> Can anyone help me about this issue ?

That's a known bug with our ehci(4), I see that you are running 5.5,
but if you want to update to -current and can try the diff below, let
me know if it fixes your problem or not.

Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.162
diff -u -p -r1.162 ehci.c
--- ehci.c      12 Jul 2014 20:13:48 -0000      1.162
+++ ehci.c      13 Jul 2014 14:05:36 -0000
@@ -82,7 +82,6 @@ struct pool *ehcixfer;
 struct ehci_pipe {
        struct usbd_pipe pipe;
 
-       struct ehci_soft_qh *sqh;
        union {
                /* Control pipe */
                struct {
@@ -156,11 +155,12 @@ void              ehci_pcd(struct ehci_softc *, stru
 void           ehci_disown(struct ehci_softc *, int, int);
 
 struct ehci_soft_qh *ehci_alloc_sqh(struct ehci_softc *);
-void           ehci_free_sqh(struct ehci_softc *, struct ehci_soft_qh *);
+void           ehci_free_sqh(struct ehci_softc *, struct usbd_xfer *);
+int            ehci_setup_sqh(struct ehci_softc *, struct usbd_xfer *);
 
 struct ehci_soft_qtd *ehci_alloc_sqtd(struct ehci_softc *);
 void           ehci_free_sqtd(struct ehci_softc *, struct ehci_soft_qtd *);
-usbd_status    ehci_alloc_sqtd_chain(struct ehci_softc *, u_int,
+int            ehci_alloc_sqtd_chain(struct ehci_softc *, u_int,
                    struct usbd_xfer *, struct ehci_soft_qtd **, struct 
ehci_soft_qtd **);
 void           ehci_free_sqtd_chain(struct ehci_softc *, struct ehci_xfer *);
 
@@ -178,7 +178,8 @@ usbd_status ehci_device_setintr(struct e
 
 void           ehci_add_qh(struct ehci_soft_qh *, struct ehci_soft_qh *);
 void           ehci_rem_qh(struct ehci_softc *, struct ehci_soft_qh *);
-void           ehci_set_qh_qtd(struct ehci_soft_qh *, struct ehci_soft_qtd *);
+void           ehci_insert_qh(struct ehci_softc *, struct usbd_xfer *,
+                   struct ehci_soft_qtd *);
 void           ehci_sync_hc(struct ehci_softc *);
 
 void           ehci_close_pipe(struct usbd_pipe *);
@@ -480,10 +481,6 @@ ehci_init(struct ehci_softc *sc)
 
        return (USBD_NORMAL_COMPLETION);
 
-#if 0
- bad2:
-       ehci_free_sqh(sc, sc->sc_async_head);
-#endif
  bad1:
        usb_freemem(&sc->sc_bus, &sc->sc_fldma);
        return (err);
@@ -720,6 +717,12 @@ ehci_check_qh_intr(struct ehci_softc *sc
        DPRINTFN(12, ("ehci_check_intr: ex=%p done\n", ex));
        timeout_del(&xfer->timeout_handle);
        usb_rem_task(xfer->pipe->device, &xfer->abort_task);
+       ehci_rem_qh(sc, ex->sqh);
+
+       /* XXX Not needed for all transfers. */
+       xfer->pipe->endpoint->savedtoggle =
+           EHCI_QTD_GET_TOGGLE(letoh32(ex->sqh->qh.qh_qtd.qtd_status));
+
        ehci_idone(xfer);
 }
 
@@ -777,9 +780,6 @@ void
 ehci_idone(struct usbd_xfer *xfer)
 {
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
-#ifdef EHCI_DEBUG
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
-#endif
        struct ehci_soft_qtd *sqtd;
        u_int32_t status = 0, nstatus = 0;
        int actlen, cerr;
@@ -809,7 +809,7 @@ ehci_idone(struct usbd_xfer *xfer)
        }
 
 #ifdef EHCI_DEBUG
-       DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, 
epipe));
+       DPRINTFN(2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, xfer->pipe));
        if (ehcidebug > 10)
                ehci_dump_sqtds(ex->sqtdstart);
 #endif
@@ -897,6 +897,7 @@ ehci_idone(struct usbd_xfer *xfer)
                        actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
        }
 
+
        cerr = EHCI_QTD_GET_CERR(status);
        DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, cerr=%d, "
            "status=0x%x\n", xfer->length, actlen, cerr, status));
@@ -916,7 +917,7 @@ ehci_idone(struct usbd_xfer *xfer)
                          xfer->pipe->endpoint->edesc->bEndpointAddress,
                          sbuf));
                if (ehcidebug > 2) {
-                       ehci_dump_sqh(epipe->sqh);
+                       ehci_dump_sqh(ex->sqh);
                        ehci_dump_sqtds(ex->sqtdstart);
                }
 #endif
@@ -1202,19 +1203,11 @@ ehci_freex(struct usbd_bus *bus, struct 
 void
 ehci_device_clear_toggle(struct usbd_pipe *pipe)
 {
-       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
-
-       DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n",
-           epipe, epipe->sqh->qh.qh_qtd.qtd_status));
 #if defined(EHCI_DEBUG) && defined(USB_DEBUG)
        if (ehcidebug)
                usbd_dump_pipe(pipe);
 #endif
-#ifdef DIAGNOSTIC
-       if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
-               panic("ehci_device_clear_toggle: queue active");
-#endif
-       epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
+       pipe->endpoint->savedtoggle = 0;
 }
 
 #ifdef EHCI_DEBUG
@@ -1416,32 +1409,18 @@ ehci_dump_exfer(struct ehci_xfer *ex)
 usbd_status
 ehci_open(struct usbd_pipe *pipe)
 {
-       struct usbd_device *dev = pipe->device;
-       struct ehci_softc *sc = (struct ehci_softc *)dev->bus;
-       usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
-       u_int8_t addr = dev->address;
-       u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
+       struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
        struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
-       struct ehci_soft_qh *sqh;
+       usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+       u_int8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
        usbd_status err;
-       int s;
-       int ival, speed, naks;
-       int hshubaddr, hshubport;
 
        DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d\n",
-           pipe, addr, ed->bEndpointAddress));
+           pipe, pipe->device->address, ed->bEndpointAddress));
 
        if (sc->sc_bus.dying)
                return (USBD_IOERROR);
 
-       if (dev->myhsport) {
-               hshubaddr = dev->myhsport->parent->address;
-               hshubport = dev->myhsport->portno;
-       } else {
-               hshubaddr = 0;
-               hshubport = 0;
-       }
-
        /* Root Hub */
        if (pipe->device->depth == 0) {
                switch (ed->bEndpointAddress) {
@@ -1457,125 +1436,115 @@ ehci_open(struct usbd_pipe *pipe)
                return (USBD_NORMAL_COMPLETION);
        }
 
-       /* XXX All this stuff is only valid for async. */
-       switch (dev->speed) {
-       case USB_SPEED_LOW:
-               speed = EHCI_QH_SPEED_LOW;
-               break;
-       case USB_SPEED_FULL:
-               speed = EHCI_QH_SPEED_FULL;
-               break;
-       case USB_SPEED_HIGH:
-               speed = EHCI_QH_SPEED_HIGH;
-               break;
-       default:
-               panic("ehci_open: bad device speed %d", dev->speed);
-       }
-       if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) {
-               printf("%s: Error opening low/full speed isoc endpoint.\n"
-                   "A low/full speed device is attached to a USB2 hub, and "
-                   "transaction translations are not yet supported.\n"
-                   "Reattach the device to the root hub instead.\n",
-                   sc->sc_bus.bdev.dv_xname);
-               DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n",
-                   hshubaddr, hshubport));
-               return (USBD_INVAL);
-       }
-
-       naks = 8;               /* XXX */
-
-       /* Allocate sqh for everything, save isoc xfers */
-       if (xfertype != UE_ISOCHRONOUS) {
-               sqh = ehci_alloc_sqh(sc);
-               if (sqh == NULL)
-                       return (USBD_NOMEM);
-               /* qh_link filled when the QH is added */
-               sqh->qh.qh_endp = htole32(
-                   EHCI_QH_SET_ADDR(addr) |
-                   EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
-                   EHCI_QH_SET_EPS(speed) |
-                   (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
-                   EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
-                   (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
-                   EHCI_QH_CTL : 0) |
-                   EHCI_QH_SET_NRL(naks)
-                   );
-               sqh->qh.qh_endphub = htole32(
-                   EHCI_QH_SET_MULT(1) |
-                   EHCI_QH_SET_HUBA(hshubaddr) |
-                   EHCI_QH_SET_PORT(hshubport) |
-                   EHCI_QH_SET_CMASK(0x1c) | /* XXX */
-                   EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
-                   );
-               sqh->qh.qh_curqtd = htole32(EHCI_LINK_TERMINATE);
-               /* Fill the overlay qTD */
-               sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
-               sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
-               sqh->qh.qh_qtd.qtd_status =
-                   htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
-
-               usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
-                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-               epipe->sqh = sqh;
-       } else {
-               sqh = NULL;
-       } /*xfertype == UE_ISOC*/
-
        switch (xfertype) {
        case UE_CONTROL:
                err = usb_allocmem(&sc->sc_bus, sizeof(usb_device_request_t),
                    0, &epipe->u.ctl.reqdma);
-#ifdef EHCI_DEBUG
-               if (err)
-                       printf("ehci_open: usb_allocmem()=%d\n", err);
-#endif
                if (err)
-                       goto bad;
+                       return (err);
                pipe->methods = &ehci_device_ctrl_methods;
-               s = splusb();
-               ehci_add_qh(sqh, sc->sc_async_head);
-               splx(s);
                break;
        case UE_BULK:
                pipe->methods = &ehci_device_bulk_methods;
-               s = splusb();
-               ehci_add_qh(sqh, sc->sc_async_head);
-               splx(s);
                break;
        case UE_INTERRUPT:
                pipe->methods = &ehci_device_intr_methods;
-               ival = pipe->interval;
-               if (ival == USBD_DEFAULT_INTERVAL)
-                       ival = ed->bInterval;
-               s = splusb();
-               err = ehci_device_setintr(sc, sqh, ival);
-               splx(s);
-               return (err);
+               break;
        case UE_ISOCHRONOUS:
-               pipe->methods = &ehci_device_isoc_methods;
+               if (pipe->device->speed != USB_SPEED_HIGH) {
+                       printf("%s: transaction translator not supported.\n",
+                           sc->sc_bus.bdev.dv_xname);
+                       return (USBD_INVAL);
+               }
+
                if (ed->bInterval == 0 || ed->bInterval > 16) {
                        printf("ehci: opening pipe with invalid bInterval\n");
-                       err = USBD_INVAL;
-                       goto bad;
+                       return (USBD_INVAL);
                }
                if (UGETW(ed->wMaxPacketSize) == 0) {
                        printf("ehci: zero length endpoint open request\n");
-                       err = USBD_INVAL;
-                       goto bad;
+                       return (USBD_INVAL);
                }
                epipe->u.isoc.next_frame = 0;
                epipe->u.isoc.cur_xfers = 0;
+               pipe->methods = &ehci_device_isoc_methods;
                break;
        default:
                DPRINTF(("ehci: bad xfer type %d\n", xfertype));
                return (USBD_INVAL);
        }
+
        return (USBD_NORMAL_COMPLETION);
+}
 
-bad:
-       if (sqh != NULL)
-               ehci_free_sqh(sc, sqh);
-       return (err);
+int
+ehci_setup_sqh(struct ehci_softc *sc, struct usbd_xfer *xfer)
+{
+       struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
+       usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
+       u_int8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+       int speed, hshubaddr, hshubport;
+       struct ehci_soft_qh *sqh;
+
+
+       if (xfer->device->myhsport) {
+               hshubaddr = xfer->device->myhsport->parent->address;
+               hshubport = xfer->device->myhsport->portno;
+       } else {
+               hshubaddr = 0;
+               hshubport = 0;
+       }
+
+       /* XXX All this stuff is only valid for async. */
+       switch (xfer->device->speed) {
+       case USB_SPEED_LOW:
+               speed = EHCI_QH_SPEED_LOW;
+               break;
+       case USB_SPEED_FULL:
+               speed = EHCI_QH_SPEED_FULL;
+               break;
+       case USB_SPEED_HIGH:
+               speed = EHCI_QH_SPEED_HIGH;
+               break;
+       default:
+               panic("ehci_open: bad device speed %d", xfer->device->speed);
+       }
+
+       sqh = ehci_alloc_sqh(sc);
+       if (sqh == NULL)
+               return (ENOMEM);
+
+       /* qh_link filled when the QH is added */
+       sqh->qh.qh_endp = htole32(
+           EHCI_QH_SET_ADDR(xfer->device->address) |
+           EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
+           EHCI_QH_SET_EPS(speed) |
+           (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
+           EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
+           (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
+           EHCI_QH_CTL : 0) |
+           EHCI_QH_SET_NRL(8)
+       );
+       sqh->qh.qh_endphub = htole32(
+           EHCI_QH_SET_MULT(1) |
+           EHCI_QH_SET_HUBA(hshubaddr) |
+           EHCI_QH_SET_PORT(hshubport) |
+           EHCI_QH_SET_CMASK(0x1c) | /* XXX */
+           EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
+       );
+       sqh->qh.qh_curqtd = htole32(EHCI_LINK_TERMINATE);
+
+       /* Fill the overlay qTD */
+       sqh->qh.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
+       sqh->qh.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+       sqh->qh.qh_qtd.qtd_status =
+            htole32(EHCI_QTD_SET_TOGGLE(xfer->pipe->endpoint->savedtoggle));
+
+       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+       ex->sqh = sqh;
+
+       return (0);
 }
 
 /*
@@ -1628,16 +1597,20 @@ ehci_rem_qh(struct ehci_softc *sc, struc
        usb_syncmem(&sqh->prev->dma,
            sqh->prev->offs + offsetof(struct ehci_qh, qh_link),
            sizeof(sqh->prev->qh.qh_link), BUS_DMASYNC_PREWRITE);
-
-       ehci_sync_hc(sc);
 }
 
 void
-ehci_set_qh_qtd(struct ehci_soft_qh *sqh, struct ehci_soft_qtd *sqtd)
+ehci_insert_qh(struct ehci_softc *sc, struct usbd_xfer *xfer,
+    struct ehci_soft_qtd *sqtd)
 {
-       int i;
+       struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
+       usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
+       struct ehci_soft_qh *sqh = ex->sqh;
+       int i, ival;
        u_int32_t status;
 
+       SPLUSBCHECK;
+
        /* Save toggle bit and ping status. */
        usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
            BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
@@ -1665,6 +1638,23 @@ ehci_set_qh_qtd(struct ehci_soft_qh *sqh
            sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
            sizeof(sqh->qh.qh_qtd.qtd_status),
            BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+       switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
+       case UE_CONTROL:
+       case UE_BULK:
+               ehci_add_qh(sqh, sc->sc_async_head);
+               break;
+       case UE_INTERRUPT:
+               ival = xfer->pipe->interval;
+               if (ival == USBD_DEFAULT_INTERVAL)
+                       ival = ed->bInterval;
+               ehci_device_setintr(sc, sqh, ival);
+               break;
+       default:
+               panic("wrong xfer type");
+       }
+
+       ehci_add_intr_list(sc, ex);
 }
 
 /*
@@ -2350,13 +2340,15 @@ out:
 }
 
 void
-ehci_free_sqh(struct ehci_softc *sc, struct ehci_soft_qh *sqh)
+ehci_free_sqh(struct ehci_softc *sc, struct usbd_xfer *xfer)
 {
+       struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        int s;
 
        s = splusb();
-       sqh->next = sc->sc_freeqhs;
-       sc->sc_freeqhs = sqh;
+       ex->sqh->next = sc->sc_freeqhs;
+       sc->sc_freeqhs = ex->sqh;
+       ex->sqh = NULL;
        splx(s);
 }
 
@@ -2408,7 +2400,7 @@ ehci_free_sqtd(struct ehci_softc *sc, st
        splx(s);
 }
 
-usbd_status
+int
 ehci_alloc_sqtd_chain(struct ehci_softc *sc, u_int alen, struct usbd_xfer 
*xfer,
     struct ehci_soft_qtd **sp, struct ehci_soft_qtd **ep)
 {
@@ -2434,6 +2426,7 @@ ehci_alloc_sqtd_chain(struct ehci_softc 
        mps = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
        forceshort = ((xfer->flags & USBD_FORCE_SHORT_XFER) || len == 0) &&
            len % mps == 0;
+
        /*
         * The control transfer data stage always starts with a toggle of 1.
         * For other transfers we let the hardware track the toggle state.
@@ -2548,18 +2541,16 @@ ehci_alloc_sqtd_chain(struct ehci_softc 
        DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
            *sp, *ep));
 
-       return (USBD_NORMAL_COMPLETION);
+       return (0);
 
  nomem:
        /* XXX free chain */
-       DPRINTFN(-1,("ehci_alloc_sqtd_chain: no memory\n"));
-       return (USBD_NOMEM);
+       return (ENOMEM);
 }
 
 void
 ehci_free_sqtd_chain(struct ehci_softc *sc, struct ehci_xfer *ex)
 {
-       struct ehci_pipe *epipe = (struct ehci_pipe *)ex->xfer.pipe;
        struct ehci_soft_qtd *sqtd, *next;
 
        DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p\n", ex->sqtdstart));
@@ -2569,7 +2560,8 @@ ehci_free_sqtd_chain(struct ehci_softc *
                ehci_free_sqtd(sc, sqtd);
        }
        ex->sqtdstart = ex->sqtdend = NULL;
-       epipe->sqh->sqtd = NULL;
+       ex->sqh->sqtd = NULL;
+       ex->sqh = NULL;
 }
 
 struct ehci_soft_itd *
@@ -2646,26 +2638,19 @@ ehci_free_itd(struct ehci_softc *sc, str
        splx(s);
 }
 
-/****************/
-
-/*
- * Close a reqular pipe.
- * Assumes that there are no pending transactions.
- */
 void
 ehci_close_pipe(struct usbd_pipe *pipe)
 {
-       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
        struct ehci_softc *sc = (struct ehci_softc *)pipe->device->bus;
-       struct ehci_soft_qh *sqh = epipe->sqh;
-       int s;
+       struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+       usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
 
-       s = splusb();
-       ehci_rem_qh(sc, sqh);
-       splx(s);
-       pipe->endpoint->savedtoggle =
-           EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
-       ehci_free_sqh(sc, epipe->sqh);
+       /* Root Hub */
+       if (pipe->device->depth == 0)
+               return;
+
+       if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_CONTROL)
+               usb_freemem(&sc->sc_bus, &epipe->u.ctl.reqdma);
 }
 
 /*
@@ -2682,13 +2667,10 @@ void
 ehci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer*)xfer;
-       struct ehci_soft_qh *sqh = epipe->sqh;
-       struct ehci_soft_qtd *sqtd;
        int s;
 
-       DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
+       DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, xfer->pipe));
 
        if (sc->sc_bus.dying) {
                /* If we're dying, just do the software part. */
@@ -2725,57 +2707,25 @@ ehci_abort_xfer(struct usbd_xfer *xfer, 
                return;
        }
 
-       /*
-        * Step 1: Make interrupt routine and timeouts ignore xfer.
-        */
+#ifdef DIAGNOSTIC
+       ex->isdone = 1;
+#endif
        s = splusb();
        ex->ehci_xfer_flags |= EHCI_XFER_ABORTING;
        xfer->status = status;  /* make software ignore it */
+
        timeout_del(&xfer->timeout_handle);
        usb_rem_task(xfer->device, &xfer->abort_task);
-       splx(s);
+       ehci_rem_qh(sc, ex->sqh);
 
-       /*
-        * Step 2: Deactivate all of the qTDs that we will be removing,
-        * otherwise the queue head may go active again.
-        */
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-       sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-       usb_syncmem(&sqh->dma,
-           sqh->offs + offsetof(struct ehci_qh, qh_qtd.qtd_status),
-           sizeof(sqh->qh.qh_qtd.qtd_status),
-           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-       for (sqtd = ex->sqtdstart; sqtd != NULL; sqtd = sqtd->nextqtd) {
-               usb_syncmem(&sqtd->dma,
-                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-                   sizeof(sqtd->qtd.qtd_status),
-                   BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-               sqtd->qtd.qtd_status = htole32(EHCI_QTD_HALTED);
-               usb_syncmem(&sqtd->dma,
-                   sqtd->offs + offsetof(struct ehci_qtd, qtd_status),
-                   sizeof(sqtd->qtd.qtd_status),
-                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-       }
+       /* Issue a handshake to ensure we can free the tranfer's DMA memory. */
        ehci_sync_hc(sc);
 
-       /*
-        * Step 3: Make sure the soft interrupt routine has run. This
-        * should remove any completed items off the queue.
-        * The hardware has no reference to completed items (TDs).
-        * It's safe to remove them at any time.
-        */
-       s = splusb();
-       sc->sc_softwake = 1;
-       usb_schedsoftintr(&sc->sc_bus);
-       tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
+       usb_syncmem(&ex->sqh->dma, ex->sqh->offs, sizeof(ex->sqh->qh),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+       xfer->pipe->endpoint->savedtoggle =
+           EHCI_QTD_GET_TOGGLE(letoh32(ex->sqh->qh.qh_qtd.qtd_status));
 
-#ifdef DIAGNOSTIC
-       ex->isdone = 1;
-#endif
        /* Do the wakeup first to avoid touching the xfer after the callback. */
        ex->ehci_xfer_flags &= ~EHCI_XFER_ABORTING;
        if (ex->ehci_xfer_flags & EHCI_XFER_ABORTWAIT) {
@@ -3002,7 +2952,6 @@ ehci_device_request(struct usbd_xfer *xf
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        usb_device_request_t *req = &xfer->request;
        struct ehci_soft_qtd *setup, *stat, *next;
-       struct ehci_soft_qh *sqh;
        u_int len = UGETW(req->wLength);
        usbd_status err;
        int s;
@@ -3013,6 +2962,9 @@ ehci_device_request(struct usbd_xfer *xf
            UGETW(req->wIndex), UGETW(req->wLength), xfer->device->address,
            xfer->pipe->endpoint->edesc->bEndpointAddress));
 
+       if (ehci_setup_sqh(sc, xfer))
+               return (USBD_NOMEM);
+
        setup = ehci_alloc_sqtd(sc);
        if (setup == NULL) {
                err = USBD_NOMEM;
@@ -3024,15 +2976,19 @@ ehci_device_request(struct usbd_xfer *xf
                goto bad2;
        }
 
-       sqh = epipe->sqh;
+       KASSERT(EHCI_QH_GET_ADDR(letoh32(ex->sqh->qh.qh_endp)) ==
+           xfer->device->address);
+       KASSERT(EHCI_QH_GET_MPL(letoh32(ex->sqh->qh.qh_endp)) ==
+           UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize));
 
        /* Set up data transaction */
        if (len != 0) {
                struct ehci_soft_qtd *end;
 
-               err = ehci_alloc_sqtd_chain(sc, len, xfer, &next, &end);
-               if (err)
+               if (ehci_alloc_sqtd_chain(sc, len, xfer, &next, &end)) {
+                       err = USBD_NOMEM;
                        goto bad3;
+               }
                end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC);
                end->nextqtd = stat;
                end->qtd.qtd_next =
@@ -3079,7 +3035,7 @@ ehci_device_request(struct usbd_xfer *xf
 #ifdef EHCI_DEBUG
        if (ehcidebug > 5) {
                DPRINTF(("ehci_device_request:\n"));
-               ehci_dump_sqh(sqh);
+               ehci_dump_sqh(ex->sqh);
                ehci_dump_sqtds(setup);
        }
 #endif
@@ -3087,22 +3043,18 @@ ehci_device_request(struct usbd_xfer *xf
        ex->sqtdstart = setup;
        ex->sqtdend = stat;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone) {
-               printf("ehci_device_request: not done, ex=%p\n", ex);
-       }
        ex->isdone = 0;
 #endif
 
-       /* Insert qTD in QH list. */
+       xfer->status = USBD_IN_PROGRESS;
+
        s = splusb();
-       ehci_set_qh_qtd(sqh, setup);
+       ehci_insert_qh(sc, xfer, setup);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
-       ehci_add_intr_list(sc, ex);
-       xfer->status = USBD_IN_PROGRESS;
        splx(s);
 
 #ifdef EHCI_DEBUG
@@ -3112,7 +3064,7 @@ ehci_device_request(struct usbd_xfer *xf
                delay(10000);
                ehci_dump_regs(sc);
                ehci_dump_sqh(sc->sc_async_head);
-               ehci_dump_sqh(sqh);
+               ehci_dump_sqh(ex->sqh);
                ehci_dump_sqtds(setup);
        }
 #endif
@@ -3125,6 +3077,7 @@ ehci_device_request(struct usbd_xfer *xf
        ehci_free_sqtd(sc, setup);
  bad1:
        DPRINTFN(-1,("ehci_device_request: no memory\n"));
+       ehci_free_sqh(sc, xfer);
        xfer->status = err;
        usb_transfer_complete(xfer);
        return (err);
@@ -3150,11 +3103,8 @@ usbd_status
 ehci_device_bulk_start(struct usbd_xfer *xfer)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
-       usbd_status err;
        int s;
 
        DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%u flags=%d\n",
@@ -3168,20 +3118,21 @@ ehci_device_bulk_start(struct usbd_xfer 
                panic("ehci_device_bulk_start: a request");
 #endif
 
-       sqh = epipe->sqh;
+       if (ehci_setup_sqh(sc, xfer))
+               return (USBD_NOMEM);
 
-       err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
-       if (err) {
+       if (ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend)) {
                DPRINTFN(-1,("ehci_device_bulk_start: no memory\n"));
-               xfer->status = err;
+               ehci_free_sqh(sc, xfer);
+               xfer->status = USBD_NOMEM;
                usb_transfer_complete(xfer);
-               return (err);
+               return (USBD_NOMEM);
        }
 
 #ifdef EHCI_DEBUG
        if (ehcidebug > 5) {
                DPRINTF(("ehci_device_bulk_start: data(1)\n"));
-               ehci_dump_sqh(sqh);
+               ehci_dump_sqh(ex->sqh);
                ehci_dump_sqtds(data);
        }
 #endif
@@ -3190,39 +3141,20 @@ ehci_device_bulk_start(struct usbd_xfer 
        ex->sqtdstart = data;
        ex->sqtdend = dataend;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone) {
-               printf("ehci_device_bulk_start: not done, ex=%p\n", ex);
-       }
        ex->isdone = 0;
 #endif
 
+       xfer->status = USBD_IN_PROGRESS;
+
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
+       ehci_insert_qh(sc, xfer, data);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
-       ehci_add_intr_list(sc, ex);
-       xfer->status = USBD_IN_PROGRESS;
        splx(s);
 
-#ifdef EHCI_DEBUG
-       if (ehcidebug > 10) {
-               DPRINTF(("ehci_device_bulk_start: data(2)\n"));
-               delay(10000);
-               DPRINTF(("ehci_device_bulk_start: data(3)\n"));
-               ehci_dump_regs(sc);
-#if 0
-               printf("async_head:\n");
-               ehci_dump_sqh(sc->sc_async_head);
-#endif
-               printf("sqh:\n");
-               ehci_dump_sqh(sqh);
-               ehci_dump_sqtds(data);
-       }
-#endif
-
        if (sc->sc_bus.use_polling)
                ehci_waitintr(sc, xfer);
 
@@ -3312,10 +3244,7 @@ ehci_device_intr_start(struct usbd_xfer 
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
-       usbd_status err;
        int s;
 
        DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%u flags=%d\n",
@@ -3329,20 +3258,21 @@ ehci_device_intr_start(struct usbd_xfer 
                panic("ehci_device_intr_start: a request");
 #endif
 
-       sqh = epipe->sqh;
+       if (ehci_setup_sqh(sc, xfer))
+               return (USBD_NOMEM);
 
-       err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend);
-       if (err) {
+       if (ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, &dataend)) {
                DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));
-               xfer->status = err;
+               ehci_free_sqh(sc, xfer);
+               xfer->status = USBD_NOMEM;
                usb_transfer_complete(xfer);
-               return (err);
+               return (USBD_NOMEM);
        }
 
 #ifdef EHCI_DEBUG
        if (ehcidebug > 5) {
                DPRINTF(("ehci_device_intr_start: data(1)\n"));
-               ehci_dump_sqh(sqh);
+               ehci_dump_sqh(ex->sqh);
                ehci_dump_sqtds(data);
        }
 #endif
@@ -3356,15 +3286,15 @@ ehci_device_intr_start(struct usbd_xfer 
        ex->isdone = 0;
 #endif
 
+       xfer->status = USBD_IN_PROGRESS;
+
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
+       ehci_insert_qh(sc, xfer, data);
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                timeout_del(&xfer->timeout_handle);
                timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
        }
-       ehci_add_intr_list(sc, ex);
-       xfer->status = USBD_IN_PROGRESS;
        splx(s);
 
 #ifdef EHCI_DEBUG
@@ -3374,7 +3304,7 @@ ehci_device_intr_start(struct usbd_xfer 
                DPRINTF(("ehci_device_intr_start: data(3)\n"));
                ehci_dump_regs(sc);
                printf("sqh:\n");
-               ehci_dump_sqh(sqh);
+               ehci_dump_sqh(ex->sqh);
                ehci_dump_sqtds(data);
        }
 #endif
@@ -3409,32 +3339,30 @@ void
 ehci_device_intr_done(struct usbd_xfer *xfer)
 {
        struct ehci_softc *sc = (struct ehci_softc *)xfer->device->bus;
-       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
        struct ehci_xfer *ex = (struct ehci_xfer *)xfer;
        struct ehci_soft_qtd *data, *dataend;
-       struct ehci_soft_qh *sqh;
-       usbd_status err;
        int s;
 
-       DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",
-           xfer, xfer->actlen));
-
-       if (xfer->pipe->repeat) {
+       if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
+               ehci_del_intr_list(sc, ex);     /* remove from active list */
                ehci_free_sqtd_chain(sc, ex);
-
                usb_syncmem(&xfer->dmabuf, 0, xfer->length,
                    usbd_xfer_isread(xfer) ?
                    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
-               sqh = epipe->sqh;
+       }
 
-               err = ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data, 
&dataend);
-               if (err) {
-                       DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));
-                       xfer->status = err;
+       if (xfer->pipe->repeat) {
+               if (ehci_setup_sqh(sc, xfer)) {
+                       xfer->status = USBD_NOMEM;
+                       return;
+               }
+
+               if (ehci_alloc_sqtd_chain(sc, xfer->length, xfer, &data,
+                    &dataend)) {
+                       xfer->status = USBD_NOMEM;
                        return;
                }
 
-               /* Set up interrupt info. */
                ex->sqtdstart = data;
                ex->sqtdend = dataend;
 #ifdef DIAGNOSTIC
@@ -3445,22 +3373,16 @@ ehci_device_intr_done(struct usbd_xfer *
                ex->isdone = 0;
 #endif
 
+               xfer->status = USBD_IN_PROGRESS;
+
                s = splusb();
-               ehci_set_qh_qtd(sqh, data);
+               ehci_insert_qh(sc, xfer, data);
                if (xfer->timeout && !sc->sc_bus.use_polling) {
                        timeout_del(&xfer->timeout_handle);
                        timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
                        timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
                }
                splx(s);
-
-               xfer->status = USBD_IN_PROGRESS;
-       } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
-               ehci_del_intr_list(sc, ex); /* remove from active list */
-               ehci_free_sqtd_chain(sc, ex);
-               usb_syncmem(&xfer->dmabuf, 0, xfer->length,
-                   usbd_xfer_isread(xfer) ?
-                   BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        }
 }
 
Index: ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.32
diff -u -p -r1.32 ehcivar.h
--- ehcivar.h   16 May 2014 18:17:03 -0000      1.32
+++ ehcivar.h   13 Jul 2014 14:05:36 -0000
@@ -79,6 +79,7 @@ struct ehci_soft_itd {
 struct ehci_xfer {
        struct usbd_xfer xfer;
        TAILQ_ENTRY(ehci_xfer) inext; /* list of active xfers */
+       struct ehci_soft_qh *sqh;
        struct ehci_soft_qtd *sqtdstart;
        struct ehci_soft_qtd *sqtdend;
        struct ehci_soft_itd *itdstart;

Reply via email to