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);

Reply via email to