Module Name: src Committed By: dyoung Date: Thu Nov 12 20:11:35 UTC 2009
Modified Files: src/sys/dev/usb: uhub.c usb.c usb_subr.c usbdivar.h Log Message: Re-order operations in usb_detach() so that if a usb(4) instance's children will not detach, the instance is not left in an inconsistent state. If uhub(4) port is disconnected, forcefully detach the children on that port. Simplify detachment hooks. (sc_dying must die!) Pass along and respect detachment flags, esp. DETACH_FORCE, throughout. To generate a diff of this commit: cvs rdiff -u -r1.107 -r1.108 src/sys/dev/usb/uhub.c cvs rdiff -u -r1.118 -r1.119 src/sys/dev/usb/usb.c cvs rdiff -u -r1.166 -r1.167 src/sys/dev/usb/usb_subr.c cvs rdiff -u -r1.90 -r1.91 src/sys/dev/usb/usbdivar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/uhub.c diff -u src/sys/dev/usb/uhub.c:1.107 src/sys/dev/usb/uhub.c:1.108 --- src/sys/dev/usb/uhub.c:1.107 Fri Sep 4 18:14:41 2009 +++ src/sys/dev/usb/uhub.c Thu Nov 12 20:11:35 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: uhub.c,v 1.107 2009/09/04 18:14:41 dyoung Exp $ */ +/* $NetBSD: uhub.c,v 1.108 2009/11/12 20:11:35 dyoung Exp $ */ /* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */ /* @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.107 2009/09/04 18:14:41 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.108 2009/11/12 20:11:35 dyoung Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -98,13 +98,12 @@ int uhub_rescan(device_t, const char *, const int *); void uhub_childdet(device_t, device_t); int uhub_detach(device_t, int); -int uhub_activate(device_t, enum devact); extern struct cfdriver uhub_cd; CFATTACH_DECL3_NEW(uhub, sizeof(struct uhub_softc), uhub_match, - uhub_attach, uhub_detach, uhub_activate, uhub_rescan, uhub_childdet, + uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet, DVF_DETACH_SHUTDOWN); CFATTACH_DECL2_NEW(uroothub, sizeof(struct uhub_softc), uhub_match, - uhub_attach, uhub_detach, uhub_activate, uhub_rescan, uhub_childdet); + uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet); int uhub_match(device_t parent, cfdata_t match, void *aux) @@ -470,7 +469,7 @@ /* Disconnected */ DPRINTF(("uhub_explore: device addr=%d disappeared " "on port %d\n", up->device->address, port)); - usb_disconnect_port(up, sc->sc_dev); + usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE); usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION); } @@ -554,35 +553,6 @@ return (USBD_NORMAL_COMPLETION); } -int -uhub_activate(device_t self, enum devact act) -{ - struct uhub_softc *sc = device_private(self); - struct usbd_hub *hub = sc->sc_hub->hub; - usbd_device_handle dev; - int nports, port, i; - - switch (act) { - case DVACT_ACTIVATE: - return (EOPNOTSUPP); - - case DVACT_DEACTIVATE: - if (hub == NULL) /* malfunctioning hub */ - break; - nports = hub->hubdesc.bNbrPorts; - for(port = 0; port < nports; port++) { - dev = hub->ports[port].device; - if (!dev) - continue; - for (i = 0; i < dev->subdevlen; i++) - if (dev->subdevs[i]) - config_deactivate(dev->subdevs[i]); - } - break; - } - return (0); -} - /* * Called from process context when the hub is gone. * Detach all devices on active ports. @@ -593,24 +563,26 @@ struct uhub_softc *sc = device_private(self); struct usbd_hub *hub = sc->sc_hub->hub; struct usbd_port *rup; - int port, nports; + int nports, port, rc; DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags)); if (hub == NULL) /* Must be partially working */ return (0); - pmf_device_deregister(self); - usbd_abort_pipe(sc->sc_ipipe); - usbd_close_pipe(sc->sc_ipipe); - nports = hub->hubdesc.bNbrPorts; for(port = 0; port < nports; port++) { rup = &hub->ports[port]; - if (rup->device != NULL) - usb_disconnect_port(rup, self); + if (rup->device == NULL) + continue; + if ((rc = usb_disconnect_port(rup, self, flags)) != 0) + return rc; } + pmf_device_deregister(self); + usbd_abort_pipe(sc->sc_ipipe); + usbd_close_pipe(sc->sc_ipipe); + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev); #if 0 Index: src/sys/dev/usb/usb.c diff -u src/sys/dev/usb/usb.c:1.118 src/sys/dev/usb/usb.c:1.119 --- src/sys/dev/usb/usb.c:1.118 Tue Jun 16 19:42:44 2009 +++ src/sys/dev/usb/usb.c Thu Nov 12 20:11:35 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: usb.c,v 1.118 2009/06/16 19:42:44 dyoung Exp $ */ +/* $NetBSD: usb.c,v 1.119 2009/11/12 20:11:35 dyoung Exp $ */ /* * Copyright (c) 1998, 2002, 2008 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.118 2009/06/16 19:42:44 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.119 2009/11/12 20:11:35 dyoung Exp $"); #include "opt_compat_netbsd.h" @@ -937,25 +937,14 @@ usb_activate(device_t self, enum devact act) { struct usb_softc *sc = device_private(self); - usbd_device_handle dev = sc->sc_port.device; - int i, rv = 0; switch (act) { - case DVACT_ACTIVATE: - return (EOPNOTSUPP); - case DVACT_DEACTIVATE: sc->sc_dying = 1; - if (dev != NULL && dev->cdesc != NULL && dev->subdevlen > 0) { - for (i = 0; i < dev->subdevlen; i++) { - if (!dev->subdevs[i]) - continue; - rv |= config_deactivate(dev->subdevs[i]); - } - } - break; + return 0; + default: + return EOPNOTSUPP; } - return (rv); } void @@ -978,21 +967,24 @@ { struct usb_softc *sc = device_private(self); struct usb_event *ue; + int rc; DPRINTF(("usb_detach: start\n")); + /* Make all devices disconnect. */ + if (sc->sc_port.device != NULL && + (rc = usb_disconnect_port(&sc->sc_port, self, flags)) != 0) + return rc; + pmf_device_deregister(self); /* Kill off event thread. */ + sc->sc_dying = 1; while (sc->sc_event_thread != NULL) { wakeup(&sc->sc_bus->needs_explore); tsleep(sc, PWAIT, "usbdet", hz * 60); } DPRINTF(("usb_detach: event thread dead\n")); - /* Make all devices disconnect. */ - if (sc->sc_port.device != NULL) - usb_disconnect_port(&sc->sc_port, self); - #ifdef USB_USE_SOFTINTR if (sc->sc_bus->soft != NULL) { softint_disestablish(sc->sc_bus->soft); Index: src/sys/dev/usb/usb_subr.c diff -u src/sys/dev/usb/usb_subr.c:1.166 src/sys/dev/usb/usb_subr.c:1.167 --- src/sys/dev/usb/usb_subr.c:1.166 Thu Nov 12 08:41:49 2009 +++ src/sys/dev/usb/usb_subr.c Thu Nov 12 20:11:35 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: usb_subr.c,v 1.166 2009/11/12 08:41:49 uebayasi Exp $ */ +/* $NetBSD: usb_subr.c,v 1.167 2009/11/12 20:11:35 dyoung Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ /* @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.166 2009/11/12 08:41:49 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.167 2009/11/12 20:11:35 dyoung Exp $"); #include "opt_compat_netbsd.h" #include "opt_usbverbose.h" @@ -1480,34 +1480,38 @@ * Called from process context when we discover that a port has * been disconnected. */ -void -usb_disconnect_port(struct usbd_port *up, device_t parent) +int +usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) { usbd_device_handle dev = up->device; + device_t subdev; + char subdevname[16]; const char *hubname = device_xname(parent); - int i; + int i, rc; DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", up, dev, up->portno)); -#ifdef DIAGNOSTIC if (dev == NULL) { +#ifdef DIAGNOSTIC printf("usb_disconnect_port: no device\n"); - return; - } #endif + return 0; + } if (dev->subdevlen > 0) { DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n")); for (i = 0; i < dev->subdevlen; i++) { - if (!dev->subdevs[i]) + if ((subdev = dev->subdevs[i]) == NULL) continue; - printf("%s: at %s", device_xname(dev->subdevs[i]), - hubname); + strlcpy(subdevname, device_xname(subdev), + sizeof(subdevname)); + if ((rc = config_detach(subdev, flags)) != 0) + return rc; + printf("%s: at %s", subdevname, hubname); if (up->portno != 0) printf(" port %d", up->portno); printf(" (addr %d) disconnected\n", dev->address); - config_detach(dev->subdevs[i], DETACH_FORCE); } KASSERT(!dev->nifaces_claimed); } @@ -1516,4 +1520,5 @@ dev->bus->devices[dev->address] = NULL; up->device = NULL; usb_free_device(dev); + return 0; } Index: src/sys/dev/usb/usbdivar.h diff -u src/sys/dev/usb/usbdivar.h:1.90 src/sys/dev/usb/usbdivar.h:1.91 --- src/sys/dev/usb/usbdivar.h:1.90 Thu Nov 12 08:16:50 2009 +++ src/sys/dev/usb/usbdivar.h Thu Nov 12 20:11:35 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: usbdivar.h,v 1.90 2009/11/12 08:16:50 uebayasi Exp $ */ +/* $NetBSD: usbdivar.h,v 1.91 2009/11/12 20:11:35 dyoung Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */ /* @@ -251,7 +251,7 @@ usbd_status usb_insert_transfer(usbd_xfer_handle); void usb_transfer_complete(usbd_xfer_handle); -void usb_disconnect_port(struct usbd_port *, device_t); +int usb_disconnect_port(struct usbd_port *, device_t, int); /* Routines from usb.c */ void usb_needs_explore(usbd_device_handle);