From 1029005107070a008a66183bcc8073df0cdb568c Mon Sep 17 00:00:00 2001 From: augustss Date: Wed, 21 Nov 2001 08:18:39 +0000 Subject: [PATCH] Pay more attention to if the HC is being unplugged. --- sys/dev/usb/ehci.c | 47 +++++++++++++++++++++++++++++++++++----------- sys/dev/usb/ohci.c | 33 +++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index c00a60e4071e..912cb854d455 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -1,7 +1,7 @@ /* TODO Add intrinfo. */ -/* $NetBSD: ehci.c,v 1.16 2001/11/21 02:47:07 augustss Exp $ */ +/* $NetBSD: ehci.c,v 1.17 2001/11/21 08:18:39 augustss Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -50,7 +50,7 @@ Add intrinfo. */ #include -__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.16 2001/11/21 02:47:07 augustss Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.17 2001/11/21 08:18:39 augustss Exp $"); #include #include @@ -273,8 +273,6 @@ Static struct usbd_pipe_methods ehci_device_isoc_methods = { ehci_device_isoc_done, }; -int ehcidisable = 0; - usbd_status ehci_init(ehci_softc_t *sc) { @@ -283,9 +281,6 @@ ehci_init(ehci_softc_t *sc) usbd_status err; ehci_soft_qh_t *sqh; - if (ehcidisable) - return (USBD_INVAL); - DPRINTF(("ehci_init: start\n")); #ifdef EHCI_DEBUG theehci = sc; @@ -433,7 +428,7 @@ ehci_intr(void *v) { ehci_softc_t *sc = v; - if (sc == NULL || sc->sc_dying || ehcidisable) + if (sc == NULL || sc->sc_dying) return (0); /* If we get an interrupt while polling, then just ignore it. */ @@ -591,6 +586,8 @@ ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer) xfer->status = USBD_IN_PROGRESS; for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) { usb_delay_ms(&sc->sc_bus, 1); + if (sc->sc_dying) + break; intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) & sc->sc_eintrs; DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs)); @@ -648,7 +645,7 @@ ehci_detach(struct ehci_softc *sc, int flags) if (sc->sc_shutdownhook != NULL) shutdownhook_disestablish(sc->sc_shutdownhook); - usb_delay_ms(&sc->sc_bus, 1000); /* XXX let stray task complete */ + usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ /* XXX free other data structures XXX */ @@ -955,6 +952,9 @@ ehci_open(usbd_pipe_handle pipe) DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", pipe, addr, ed->bEndpointAddress, sc->sc_addr)); + if (sc->sc_dying) + return (USBD_IOERROR); + if (addr == sc->sc_addr) { switch (ed->bEndpointAddress) { case USB_CONTROL_ENDPOINT: @@ -1537,10 +1537,18 @@ ehci_root_ctrl_start(usbd_xfer_handle xfer) EOWRITE4(sc, port, v | EHCI_PS_PR); /* Wait for reset to complete. */ usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY); + if (sc->sc_dying) { + err = USBD_IOERROR; + goto ret; + } /* Terminate reset sequence. */ EOWRITE4(sc, port, v); /* Wait for HC to complete reset. */ usb_delay_ms(&sc->sc_bus, EHCI_PORT_RESET_COMPLETE); + if (sc->sc_dying) { + err = USBD_IOERROR; + goto ret; + } v = EOREAD4(sc, port); DPRINTF(("ehci after reset, status=0x%08x\n", v)); if (v & EHCI_PS_PR) { @@ -1924,8 +1932,8 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; ehci_soft_qh_t *sqh = epipe->sqh; -#if 0 ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; +#if 0 ehci_soft_td_t *p, *n; ehci_physaddr_t headp; int hit; @@ -1934,6 +1942,16 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p sqh=%p\n", xfer, epipe,sqh)); + if (sc->sc_dying) { + /* If we're dying, just do the software part. */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer); + usb_transfer_complete(xfer); + splx(s); + return; + } + if (xfer->device->bus->intr_context || !curproc) panic("ehci_abort_xfer: not in process context\n"); @@ -1983,9 +2001,16 @@ void ehci_timeout(void *addr) { struct ehci_xfer *exfer = addr; + struct ehci_pipe *epipe = (struct ehci_pipe *)exfer->xfer.pipe; + ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; DPRINTF(("ehci_timeout: exfer=%p\n", exfer)); + if (sc->sc_dying) { + ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT); + return; + } + /* Execute the abort in a process context. */ usb_init_task(&exfer->abort_task, ehci_timeout_task, addr); usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task); @@ -2198,7 +2223,7 @@ ehci_device_request(usbd_xfer_handle xfer) } splx(s); -#if 1 +#ifdef EHCI_DEBUG if (ehcidebug > 10) { delay(10000); DPRINTF(("ehci_device_request: status=%x\n", diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c index 156d61da2969..61efd5fbe12d 100644 --- a/sys/dev/usb/ohci.c +++ b/sys/dev/usb/ohci.c @@ -1,4 +1,4 @@ -/* $NetBSD: ohci.c,v 1.115 2001/11/21 05:52:50 itojun Exp $ */ +/* $NetBSD: ohci.c,v 1.116 2001/11/21 08:18:40 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */ /* @@ -46,7 +46,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.115 2001/11/21 05:52:50 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.116 2001/11/21 08:18:40 augustss Exp $"); #include #include @@ -381,6 +381,8 @@ ohci_detach(struct ohci_softc *sc, int flags) shutdownhook_disestablish(sc->sc_shutdownhook); #endif + usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ + /* free data structures XXX */ return (rv); @@ -1057,7 +1059,7 @@ ohci_intr(void *p) { ohci_softc_t *sc = p; - if (sc->sc_dying) + if (sc == NULL || sc->sc_dying) return (0); /* If we get an interrupt while polling, then just ignore it. */ @@ -1516,6 +1518,8 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer) xfer->status = USBD_IN_PROGRESS; for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) { usb_delay_ms(&sc->sc_bus, 1); + if (sc->sc_dying) + break; intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); #ifdef OHCI_DEBUG @@ -1808,9 +1812,16 @@ void ohci_timeout(void *addr) { struct ohci_xfer *oxfer = addr; + struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe; + ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus; DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer)); + if (sc->sc_dying) { + ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT); + return; + } + /* Execute the abort in a process context. */ usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr); usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task); @@ -1929,6 +1940,9 @@ ohci_open(usbd_pipe_handle pipe) DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", pipe, addr, ed->bEndpointAddress, sc->sc_addr)); + if (sc->sc_dying) + return (USBD_IOERROR); + std = NULL; sed = NULL; @@ -2086,6 +2100,15 @@ ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed)); + if (sc->sc_dying) { + /* If we're dying, just do the software part. */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer); + usb_transfer_complete(xfer); + splx(s); + } + if (xfer->device->bus->intr_context || !curproc) panic("ohci_abort_xfer: not in process context\n"); @@ -2531,6 +2554,10 @@ ohci_root_ctrl_start(usbd_xfer_handle xfer) for (i = 0; i < 5; i++) { usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY); + if (sc->sc_dying) { + err = USBD_IOERROR; + goto ret; + } if ((OREAD4(sc, port) & UPS_RESET) == 0) break; }