Do not pass an xfer pointer to the timeout routine checking for root hub
authormpi <mpi@openbsd.org>
Sun, 18 May 2014 17:10:27 +0000 (17:10 +0000)
committermpi <mpi@openbsd.org>
Sun, 18 May 2014 17:10:27 +0000 (17:10 +0000)
status changes because it might be freed when detaching the root uhub(4).

Also do not reschedule a timeout if the pipe is being aborted.

Finally do not add more code to retrieve the 'bInterval' value of the
root hub endpoint descriptor since this value is hardcoded in the uhci(4)
driver.

sys/dev/usb/uhci.c
sys/dev/usb/uhcivar.h

index e3bd38a..04d6f0f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhci.c,v 1.118 2014/05/16 19:00:18 mpi Exp $  */
+/*     $OpenBSD: uhci.c,v 1.119 2014/05/18 17:10:27 mpi Exp $  */
 /*     $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $        */
 /*     $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $       */
 
@@ -481,7 +481,7 @@ uhci_init(struct uhci_softc *sc)
 
        LIST_INIT(&sc->sc_intrhead);
 
-       timeout_set(&sc->sc_poll_handle, NULL, NULL);
+       timeout_set(&sc->sc_root_intr, uhci_poll_hub, sc);
 
        /* Set up the bus struct. */
        sc->sc_bus.methods = &uhci_bus_methods;
@@ -511,8 +511,6 @@ uhci_activate(struct device *self, int act)
                        uhci_dumpregs(sc);
 #endif
                rv = config_activate_children(self, act);
-               if (sc->sc_intr_xfer != NULL)
-                       timeout_del(&sc->sc_poll_handle);
                sc->sc_bus.use_polling++;
                uhci_run(sc, 0); /* stop the controller */
 
@@ -557,12 +555,6 @@ uhci_activate(struct device *self, int act)
                uhci_run(sc, 1); /* and start traffic again */
                usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
                sc->sc_bus.use_polling--;
-               if (sc->sc_intr_xfer != NULL) {
-                       timeout_del(&sc->sc_poll_handle);
-                       timeout_set(&sc->sc_poll_handle, uhci_poll_hub,
-                           sc->sc_intr_xfer);
-                       timeout_add_msec(&sc->sc_poll_handle, sc->sc_ival);
-               }
 #ifdef UHCI_DEBUG
                if (uhcidebug > 2)
                        uhci_dumpregs(sc);
@@ -587,10 +579,7 @@ uhci_detach(struct device *self, int flags)
        if (rv != 0)
                return (rv);
 
-       if (sc->sc_intr_xfer != NULL) {
-               timeout_del(&sc->sc_poll_handle);
-               sc->sc_intr_xfer = NULL;
-       }
+       KASSERT(sc->sc_intrxfer == NULL);
 
        /* XXX free other data structures XXX */
 
@@ -820,19 +809,17 @@ void exdump(void) { uhci_dump_xfers(thesc); }
 void
 uhci_poll_hub(void *addr)
 {
-       struct usbd_xfer *xfer = addr;
-       struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
+       struct uhci_softc *sc = addr;
+       struct usbd_xfer *xfer;
        int s;
        u_char *p;
 
-       DPRINTFN(20, ("uhci_poll_hub\n"));
-
        if (sc->sc_bus.dying)
                return;
 
-       timeout_del(&sc->sc_poll_handle);
-       timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
-       timeout_add_msec(&sc->sc_poll_handle, sc->sc_ival);
+       xfer = sc->sc_intrxfer;
+       if (xfer == NULL)
+               return;
 
        p = KERNADDR(&xfer->dmabuf, 0);
        p[0] = 0;
@@ -840,12 +827,15 @@ uhci_poll_hub(void *addr)
                p[0] |= 1<<1;
        if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
                p[0] |= 1<<2;
-       if (p[0] == 0)
+       if (p[0] == 0) {
                /* No change, try again in a while */
+               timeout_add_msec(&sc->sc_root_intr, 255);
                return;
+       }
 
-       xfer->actlen = 1;
+       xfer->actlen = xfer->length;
        xfer->status = USBD_NORMAL_COMPLETION;
+
        s = splusb();
        xfer->device->bus->intr_context++;
        usb_transfer_complete(xfer);
@@ -853,11 +843,6 @@ uhci_poll_hub(void *addr)
        splx(s);
 }
 
-void
-uhci_root_intr_done(struct usbd_xfer *xfer)
-{
-}
-
 void
 uhci_root_ctrl_done(struct usbd_xfer *xfer)
 {
@@ -3297,8 +3282,8 @@ uhci_root_intr_abort(struct usbd_xfer *xfer)
        struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
        int s;
 
-       timeout_del(&sc->sc_poll_handle);
-       sc->sc_intr_xfer = NULL;
+       timeout_del(&sc->sc_root_intr);
+       sc->sc_intrxfer = NULL;
 
        xfer->status = USBD_CANCELLED;
        s = splusb();
@@ -3328,27 +3313,25 @@ uhci_root_intr_start(struct usbd_xfer *xfer)
 {
        struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
 
-       DPRINTFN(3, ("uhci_root_intr_start: xfer=%p len=%u flags=%d\n",
-                    xfer, xfer->length, xfer->flags));
-
        if (sc->sc_bus.dying)
                return (USBD_IOERROR);
 
-       sc->sc_ival = xfer->pipe->endpoint->edesc->bInterval;
-       timeout_del(&sc->sc_poll_handle);
-       timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
-       timeout_add_msec(&sc->sc_poll_handle, sc->sc_ival);
-       sc->sc_intr_xfer = xfer;
+       sc->sc_intrxfer = xfer;
+       timeout_add_msec(&sc->sc_root_intr, 255);
+
        return (USBD_IN_PROGRESS);
 }
 
-/* Close the root interrupt pipe. */
 void
 uhci_root_intr_close(struct usbd_pipe *pipe)
 {
-       struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
+}
+
+void
+uhci_root_intr_done(struct usbd_xfer *xfer)
+{
+       struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
 
-       timeout_del(&sc->sc_poll_handle);
-       sc->sc_intr_xfer = NULL;
-       DPRINTF(("uhci_root_intr_close\n"));
+       if (xfer->pipe->repeat)
+               timeout_add_msec(&sc->sc_root_intr, 255);
 }
index 8e4c45c..77801bb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhcivar.h,v 1.32 2014/05/16 18:17:03 mpi Exp $ */
+/*     $OpenBSD: uhcivar.h,v 1.33 2014/05/18 17:10:27 mpi Exp $ */
 /*     $NetBSD: uhcivar.h,v 1.36 2002/12/31 00:39:11 augustss Exp $    */
 /*     $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $    */
 
@@ -151,9 +151,8 @@ struct uhci_softc {
        LIST_HEAD(, uhci_xfer) sc_intrhead;
 
        /* Info for the root hub interrupt "pipe". */
-       int sc_ival;                    /* time between root hub intrs */
-       struct usbd_xfer *sc_intr_xfer; /* root hub interrupt transfer */
-       struct timeout sc_poll_handle;
+       struct usbd_xfer        *sc_intrxfer;
+       struct timeout           sc_root_intr;
 
        char sc_vendor[32];             /* vendor string for root hub */
        int sc_id_vendor;               /* vendor ID for root hub */