PERFORCE change 180523 for review

Hans Petter Selasky hselasky at FreeBSD.org
Tue Jul 6 09:52:33 UTC 2010


http://p4web.freebsd.org/@@180523?ac=10

Change 180523 by hselasky at hselasky_laptop001 on 2010/07/06 09:51:56

	
	USB CORE: (bugfixes)
		- there are two more conditions for waking up 
		an USB device (See: usb_peer_should_wakeup() function):
		 a) when a new driver has been loaded
		 b) when we are re-enumerating
		- rework the re-enumerate code, so it
		runs in series with the rest of the USB
		explore code, so that we avoid re-enumerating
		the wrong USB device. The re-enumerate feature
		is not very commonly used.
		- patch by: HPS @

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_dev.c#46 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_device.h#37 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_generic.c#32 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_hub.c#48 edit

Differences ...

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

@@ -1085,21 +1085,45 @@
 		err = usb_ioctl_f_sub(f, cmd, addr, td);
 	}
 	KASSERT(f != NULL, ("fifo not found"));
-	if (err == ENOIOCTL) {
-		err = (f->methods->f_ioctl) (f, cmd, addr, fflags);
-		DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err);
-		if (err == ENOIOCTL) {
-			if (usb_usb_ref_device(cpd, &refs)) {
-				err = ENXIO;
-				goto done;
-			}
-			err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags);
-			DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err);
-		}
+	if (err != ENOIOCTL)
+		goto done;
+
+	err = (f->methods->f_ioctl) (f, cmd, addr, fflags);
+
+	DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err);
+
+	if (err != ENOIOCTL)
+		goto done;
+
+	if (usb_usb_ref_device(cpd, &refs)) {
+		err = ENXIO;
+		goto done;
 	}
-	if (err == ENOIOCTL) {
+
+	err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags);
+
+	DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err);
+
+	if (err == ENOIOCTL)
 		err = ENOTTY;
+
+	if (err)
+		goto done;
+
+	/* Wait for re-enumeration, if any */
+
+	while (f->udev->re_enumerate_wait != 0) {
+
+		usb_unref_device(cpd, &refs);
+
+		usb_pause_mtx(NULL, hz / 128);
+
+		if (usb_ref_device(cpd, &refs, 1 /* need uref */)) {
+			err = ENXIO;
+			goto done;
+		}
 	}
+
 done:
 	usb_unref_device(cpd, &refs);
 	return (err);

==== //depot/projects/usb/src/sys/dev/usb/usb_device.h#37 (text+ko) ====

@@ -160,6 +160,7 @@
 	uint8_t	hs_port_no;		/* high-speed HUB port number */
 	uint8_t	driver_added_refcount;	/* our driver added generation count */
 	uint8_t	power_mode;		/* see USB_POWER_XXX */
+	uint8_t re_enumerate_wait;	/* set if re-enum. is in progress */
 	uint8_t ifaces_max;		/* number of interfaces present */
 	uint8_t endpoints_max;		/* number of endpoints present */
 

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

@@ -109,7 +109,7 @@
 static int	ugen_re_enumerate(struct usb_fifo *);
 static int	ugen_iface_ioctl(struct usb_fifo *, u_long, void *, int);
 static uint8_t	ugen_fs_get_complete(struct usb_fifo *, uint8_t *);
-static int ugen_fs_uninit(struct usb_fifo *f);
+static int	ugen_fs_uninit(struct usb_fifo *f);
 
 /* structures */
 
@@ -951,23 +951,19 @@
 	if (error) {
 		return (error);
 	}
-	/* get the device unconfigured */
-	error = ugen_set_config(f, USB_UNCONFIG_INDEX);
-	if (error) {
-		return (error);
+	if (udev->flags.usb_mode != USB_MODE_HOST) {
+		/* not possible in device side mode */
+		return (ENOTTY);
 	}
-	/* do a bus-reset */
-	mtx_lock(f->priv_mtx);
-	error = usbd_req_re_enumerate(udev, f->priv_mtx);
-	mtx_unlock(f->priv_mtx);
-
-	if (error) {
-		return (ENXIO);
+	/* make sure all FIFO's are gone */
+	/* else there can be a deadlock */
+	if (ugen_fs_uninit(f)) {
+		/* ignore any errors */
+		DPRINTFN(6, "no FIFOs\n");
 	}
-	/* restore configuration to index 0 */
-	error = ugen_set_config(f, 0);
-	if (error) {
-		return (error);
+	if (udev->re_enumerate_wait == 0) {
+		udev->re_enumerate_wait = 1;
+		usb_needs_explore(udev->bus, 0);
 	}
 	return (0);
 }
@@ -1775,9 +1771,11 @@
 
 	/* if we are powered off we need to re-enumerate first */
 	if (old_mode == USB_POWER_MODE_OFF) {
-		err = ugen_re_enumerate(f);
-		if (err)
-			return (err);
+		if (udev->flags.usb_mode == USB_MODE_HOST) {
+			if (udev->re_enumerate_wait == 0)
+				udev->re_enumerate_wait = 1;
+		}
+		/* set power mode will wake up the explore thread */
 	}
 
 	/* set new power mode */

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

@@ -234,6 +234,24 @@
 		/* nothing to do */
 		goto done;
 	}
+
+	/* check if device should be re-enumerated */
+
+	if (child->flags.usb_mode == USB_MODE_HOST) {
+		usbd_enum_lock(child);
+		if (child->re_enumerate_wait) {
+			err = usbd_set_config_index(child, USB_UNCONFIG_INDEX);
+			if (err == 0)
+				err = usbd_req_re_enumerate(child, NULL);
+			if (err == 0)
+				err = usbd_set_config_index(child, 0);
+
+			child->re_enumerate_wait = 0;
+			err = 0;
+		}
+		usbd_enum_unlock(child);
+	}
+
 	/* check if probe and attach should be done */
 
 	if (child->driver_added_refcount != refcount) {
@@ -1761,6 +1779,8 @@
 usb_peer_should_wakeup(struct usb_device *udev)
 {
 	return ((udev->power_mode == USB_POWER_MODE_ON) ||
+	    (udev->driver_added_refcount != udev->bus->driver_added_refcount) ||
+	    (udev->re_enumerate_wait != 0) ||
 	    (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0) ||
 	    (udev->pwr_save.write_refs != 0) ||
 	    ((udev->pwr_save.read_refs != 0) &&


More information about the p4-projects mailing list