PERFORCE change 130743 for review

Hans Petter Selasky hselasky at FreeBSD.org
Wed Dec 12 14:36:17 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=130743

Change 130743 by hselasky at hselasky_laptop001 on 2007/12/12 22:36:05

	
	This commit is related to USB device side support.
	
	o In general: The code does the same like before
	  only that some functions have been refactored.
	
	o Removed "usb_discover". It looked more and more
	  like an "sx_xlock" implementation, and it was
	  time to replace it by something simpler.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb.c#27 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb.c#27 (text+ko) ====

@@ -84,8 +84,6 @@
 #define	USB_UCRED
 #endif
 
-uint8_t	usb_driver_added_refcount = 1;
-
 static uint8_t usb_post_init_called = 0;
 
 static device_probe_t usb_probe;
@@ -93,7 +91,6 @@
 static device_detach_t usb_detach;
 
 static int usb_dummy_open(struct cdev *dev, int oflags, int devtype, struct thread *td);
-static void usb_discover(struct usbd_bus *bus);
 static void usb_event_thread(struct usbd_bus *bus);
 static void usb_create_event_thread(struct usbd_bus *bus);
 static void usb_attach_sub(device_t dev, struct usbd_bus *bus);
@@ -142,84 +139,66 @@
 }
 
 /*------------------------------------------------------------------------*
- *	usb_discover - explore the device tree from the root
+ *	usb_event_thread - explore the device tree from the root
  *------------------------------------------------------------------------*/
 static void
-usb_discover(struct usbd_bus *bus)
+usb_event_thread(struct usbd_bus *bus)
 {
-	int32_t error;
+	int error;
 
 	PRINTFN(2, ("\n"));
 
-	mtx_assert(&usb_global_lock, MA_OWNED);
+	while (1) {
 
-	/*
-	 * check that only one thread is exploring at a time
-	 */
-	while (bus->is_exploring) {
-		bus->wait_explore = 1;
+		mtx_lock(&(bus->mtx));
+retry:
+		if (bus->needs.teardown) {
+			wakeup(&(bus->bdev));
+			mtx_unlock(&(bus->mtx));
+			break;
+		}
+		if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) ||
+		    (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL) ||
+		    (bus->needs.explore == 0)) {
 
-		error = mtx_sleep(&bus->wait_explore, &usb_global_lock, 0,
-		    "usb wait explore", 0);
-	}
+			if (bus->needs.sync) {
+				bus->needs.sync = 0;
+				wakeup(&(bus->needs));
+			}
+			bus->needs.wakeup = 1;
 
-	bus->is_exploring = 1;
+			error = mtx_sleep(bus, &(bus->mtx),
+			    0, "usbevt", hz * 240);
 
-	while (bus->devices[USB_START_ADDR] &&
-	    bus->devices[USB_START_ADDR]->hub &&
-	    bus->needs_explore &&
-	    (bus->wait_explore == 0)) {
-		bus->needs_explore = 0;
+			PRINTFN(2, ("woken up\n"));
 
-		/*
-		 * explore the hub (this call can sleep, exiting
-		 * usb_global_lock, which is actually Giant)
-		 */
-		(bus->devices[USB_START_ADDR]->hub->explore)
-		    (bus->devices[USB_START_ADDR]);
-	}
+			bus->needs.wakeup = 0;
+			goto retry;
+		}
+		bus->needs.explore = 0;
 
-	bus->is_exploring = 0;
+		if (bus->needs.probe_attach) {
+			bus->needs.probe_attach = 0;
+			bus->driver_added_refcount++;
+		}
+		if (bus->driver_added_refcount == 0) {
+			/* avoid zero, hence that is memory default */
+			bus->driver_added_refcount = 1;
+		}
+		mtx_unlock(&(bus->mtx));
 
-	if (bus->wait_explore) {
-		bus->wait_explore = 0;
-		wakeup(&bus->wait_explore);
-	}
-	return;
-}
-
-static void
-usb_event_thread(struct usbd_bus *bus)
-{
-	int32_t error;
-
-	mtx_lock(&usb_global_lock);
-
-	while (1) {
-		if (bus->devices[USB_START_ADDR] == 0) {
-			break;
-		}
-		usb_discover(bus);
+		mtx_lock(&usb_global_lock);
 
 		/*
-		 * Check if a detach happened during discover:
+		 * Explore the Root USB HUB (this call can sleep,
+		 * exiting usb_global_lock, which is actually Giant)
 		 */
-		if (bus->devices[USB_START_ADDR] == 0) {
-			break;
-		}
-		error = mtx_sleep(&bus->needs_explore, &usb_global_lock,
-		    0, "usbevt", hz * 60);
+		(bus->devices[USB_ROOT_HUB_ADDR]->hub->explore)
+		    (bus->devices[USB_ROOT_HUB_ADDR]);
 
-		PRINTFN(2, ("woke up\n"));
+		mtx_unlock(&usb_global_lock);
 	}
 
-	bus->event_thread = NULL;
-
-	/* in case parent is waiting for us to exit */
-	wakeup(bus);
-
-	mtx_unlock(&usb_global_lock);
-
 	PRINTF(("exit\n"));
 
 	usb_thread_exit(0);
@@ -227,54 +206,92 @@
 	return;
 }
 
+/*------------------------------------------------------------------------*
+ *	usb_needs_explore
+ *
+ * This functions is called when the USB event thread
+ * needs to be explored.
+ *------------------------------------------------------------------------*/
 void
-usb_needs_explore(struct usbd_device *udev)
+usb_needs_explore(struct usbd_bus *bus, uint8_t what)
 {
+	int err;
+
 	PRINTFN(2, ("\n"));
 
-	mtx_lock(&usb_global_lock);
-	udev->bus->needs_explore = 1;
-	wakeup(&udev->bus->needs_explore);
-	mtx_unlock(&usb_global_lock);
+	mtx_lock(&(bus->mtx));
+	if (bus->needs.wakeup) {
+		bus->needs.wakeup = 0;
+		wakeup(bus);
+	}
+	switch (what) {
+	case USB_BUS_EXPLORE_STOP:
+		bus->needs.teardown = 1;
+		err = mtx_sleep(&(bus->bdev), &(bus->mtx),
+		    0, "usbdrain", 0);
+		break;
+
+	case USB_BUS_EXPLORE_PROBE:
+		bus->needs.explore = 1;
+		bus->needs.probe_attach = 1;
+		break;
+
+	case USB_BUS_EXPLORE_SYNC:
+		bus->needs.sync = 1;
+		err = mtx_sleep(&(bus->needs), &(bus->mtx),
+		    0, "usbsync", 30 * hz);
+		break;
+
+	default:
+		/* just explore */
+		bus->needs.explore = 1;
+		break;
+	}
+	mtx_unlock(&(bus->mtx));
 	return;
 }
 
+/*------------------------------------------------------------------------*
+ *	usb_needs_probe_and_attach
+ *
+ * This function is called whenever a new driver is loaded and will
+ * cause that all USB busses are re-explored.
+ *------------------------------------------------------------------------*/
 void
 usb_needs_probe_and_attach(void)
 {
 	struct usbd_bus *bus;
 	devclass_t dc;
 	device_t dev;
+	uint8_t what;
 	int max;
 
 	PRINTFN(2, ("\n"));
 
-	mtx_lock(&usb_global_lock);
+	dc = devclass_find("usb");
+	if (dc == NULL) {
+		return;
+	}
+	/*
+	 * Explore all USB busses in parallell.
+	 */
 
-	usb_driver_added_refcount++;
-	if (usb_driver_added_refcount == 0) {
-		/* avoid zero, hence that is memory default */
-		usb_driver_added_refcount = 1;
+	what = USB_BUS_EXPLORE_PROBE;
+repeat:
+	max = devclass_get_maxunit(dc);
+	while (max >= 0) {
+		dev = devclass_get_device(dc, max);
+		if (dev) {
+			bus = device_get_softc(dev);
+			usb_needs_explore(bus, what);
+		}
+		max--;
 	}
-	dc = devclass_find("usb");
 
-	if (dc) {
-		max = devclass_get_maxunit(dc);
-		while (max >= 0) {
-			dev = devclass_get_device(dc, max);
-			if (dev) {
-				bus = device_get_softc(dev);
-
-				bus->needs_explore = 1;
-				wakeup(&bus->needs_explore);
-			}
-			max--;
-		}
-	} else {
-		printf("%s: \"usb\" devclass not present!\n",
-		    __FUNCTION__);
+	if (what == USB_BUS_EXPLORE_PROBE) {
+		what = USB_BUS_EXPLORE_SYNC;
+		goto repeat;
 	}
-	mtx_unlock(&usb_global_lock);
 	return;
 }
 
@@ -295,13 +312,14 @@
 usb_probe(device_t dev)
 {
 	PRINTF(("\n"));
-	return (UMATCH_GENERIC);
+	return (0);
 }
 
 static void
 usb_attach_sub(device_t dev, struct usbd_bus *bus)
 {
 	dev_clone_fn usb_clone_ptr = &usb_clone;
+	struct usbd_device *child;
 	usbd_status_t err;
 	uint8_t speed;
 
@@ -335,33 +353,29 @@
 		return;
 	}
 
-	err = usbd_new_device(bus->bdev, bus, NULL, 0, speed, 0, 0);
+	/* Allocate the Root USB device */
 
-	if (!err) {
-		err = usbd_probe_and_attach(bus->bdev, bus->devices[USB_START_ADDR]);
+	child = usbd_alloc_device(bus->bdev, bus, NULL, 0, 0, 1,
+	    speed, USB_MODE_HOST);
+	if (child) {
+		err = usbd_probe_and_attach(child,
+		    USB_IFACE_INDEX_ANY);
+		if (!err) {
+			if (!bus->devices[USB_ROOT_HUB_ADDR]->hub) {
+				err = USBD_NO_ROOT_HUB;
+			}
+		}
+	} else {
+		err = USBD_NOMEM;
 	}
-	if (!err) {
-		if (bus->devices[USB_START_ADDR]->hub == NULL) {
-			device_printf(bus->bdev,
-			    "root device is not a hub\n");
-			return;
-		}
-		/*
-		 * the USB bus is explored here so that devices,
-		 * for example the keyboard, can work during boot
-		 */
 
-		/* make sure that the bus is explored */
-		bus->needs_explore = 1;
-
-		usb_discover(bus);
-	} else {
-		device_printf(bus->bdev, "root hub problem, error=%s\n",
+	if (err) {
+		device_printf(bus->bdev, "Root HUB problem, error=%s\n",
 		    usbd_errstr(err));
 	}
+	/* Make sure that the USB BUS is explored */
+	bus->needs.explore = 1;
 
-	usb_create_event_thread(bus);
-
 	snprintf(bus->usb_name, sizeof(bus->usb_name), "usb%u", device_get_unit(dev));
 
 	bus->usb_clone_tag = EVENTHANDLER_REGISTER(dev_clone, usb_clone_ptr, bus, 1000);
@@ -376,6 +390,10 @@
 	if (bus->usb_cdev == NULL) {
 		device_printf(dev, "Creating dummy device failed!\n");
 	}
+	/* create and start the event thread */
+
+	usb_create_event_thread(bus);
+
 	return;
 }
 
@@ -408,22 +426,22 @@
 	dc = devclass_find("usb");
 
 	if (dc) {
-		max = devclass_get_maxunit(dc);
-		for (n = 0; n <= max; n++) {
+		max = devclass_get_maxunit(dc) + 1;
+		for (n = 0; n != max; n++) {
 			dev = devclass_get_device(dc, n);
 			if (dev) {
 				bus = device_get_softc(dev);
-
 				usb_attach_sub(dev, bus);
 			}
 		}
-	} else {
-		printf("%s: \"usb\" devclass not present!\n",
-		    __FUNCTION__);
 	}
 
 	usb_post_init_called = 1;
 
+	/* explore all USB busses in parallell */
+
+	usb_needs_probe_and_attach();
+
 	mtx_unlock(&usb_global_lock);
 
 	return;
@@ -435,38 +453,25 @@
 usb_detach(device_t dev)
 {
 	struct usbd_bus *bus = device_get_softc(dev);
-	int32_t error;
+	struct usbd_device *udev = bus->devices[USB_ROOT_HUB_ADDR];
 
 	PRINTF(("start\n"));
 
+	/* get rid of explore thread */
+	usb_needs_explore(bus, USB_BUS_EXPLORE_STOP);
+
 	mtx_lock(&usb_global_lock);
 
-	/* wait for any possible explore calls to finish */
-	while (bus->is_exploring) {
-		bus->wait_explore = 1;
-
-		error = mtx_sleep(&bus->wait_explore, &usb_global_lock, 0,
-		    "usb wait explore", 0);
-	}
-
 	/* detach children first */
 	bus_generic_detach(dev);
 
-	if (bus->devices[USB_START_ADDR] != NULL) {
-		/*
-		 * free device, but not sub-devices, hence they are freed by
-		 * the caller of this function
-		 */
-		usbd_free_device(bus->devices[USB_START_ADDR], 0);
-	}
-	/* kill off event thread */
-	if (bus->event_thread != NULL) {
-		wakeup(&bus->needs_explore);
+	/*
+	 * Free USB Root device, but not any sub-devices, hence they
+	 * are freed by the caller of this function
+	 */
+	usbd_detach_device(udev, USB_IFACE_INDEX_ANY, 0);
+	usbd_free_device(udev);
 
-		error = mtx_sleep(bus, &usb_global_lock, 0, "usbdet", 0);
-
-		PRINTF(("event thread dead\n"));
-	}
 	mtx_unlock(&usb_global_lock);
 
 	mtx_lock(&bus->mtx);
@@ -723,7 +728,6 @@
 		{
 			struct usb_device_enumerate *ude = (void *)addr;
 			struct usbd_device *parent_hub;
-			usb_port_status_t ps;
 			uint8_t old_addr;
 			uint8_t buf[8];
 
@@ -738,7 +742,7 @@
 				error = EINVAL;
 				goto ret002;
 			}
-			error = usbreq_reset_port(parent_hub, NULL, &ps, udev->port_no);
+			error = usbreq_reset_port(parent_hub, NULL, udev->port_no);
 			if (error) {
 				error = ENXIO;
 				goto ret002;


More information about the p4-projects mailing list