svn commit: r191494 - in head/sys/dev/usb: . controller

Andrew Thompson thompsa at FreeBSD.org
Sat Apr 25 21:10:07 UTC 2009


Author: thompsa
Date: Sat Apr 25 21:10:06 2009
New Revision: 191494
URL: http://svn.freebsd.org/changeset/base/191494

Log:
  Track the usb device state as its powered on, addressed and configured. This helps
  to avoid touching the device when it is not going to respond and would otherwise
  timeout.
  
  Implement the suspend tracking as a udev state too.

Modified:
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/controller/ohci.c
  head/sys/dev/usb/controller/uhci.c
  head/sys/dev/usb/usb_core.h
  head/sys/dev/usb/usb_device.c
  head/sys/dev/usb/usb_device.h
  head/sys/dev/usb/usb_generic.c
  head/sys/dev/usb/usb_hub.c
  head/sys/dev/usb/usb_request.c
  head/sys/dev/usb/usb_revision.h
  head/sys/dev/usb/usb_transfer.c

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/controller/ehci.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -1964,7 +1964,7 @@ ehci_setup_standard_chain(struct usb2_xf
 
 	usb2_pc_cpu_flush(qh->page_cache);
 
-	if (xfer->xroot->udev->pwr_save.suspended == 0) {
+	if (xfer->xroot->udev->state != USB_STATE_SUSPENDED) {
 		EHCI_APPEND_QH(qh, *qh_last);
 	}
 }

Modified: head/sys/dev/usb/controller/ohci.c
==============================================================================
--- head/sys/dev/usb/controller/ohci.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/controller/ohci.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -1020,7 +1020,7 @@ ohci_check_transfer_sub(struct usb2_xfer
 		 * writing the BLF and CLF bits:
 		 */
 
-		if (xfer->xroot->udev->pwr_save.suspended) {
+		if (xfer->xroot->udev->state == USB_STATE_SUSPENDED) {
 			/* nothing to do */
 		} else if (xfer->pipe->methods == &ohci_device_bulk_methods) {
 			ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
@@ -1589,7 +1589,7 @@ ohci_setup_standard_chain(struct usb2_xf
 
 	ed->ed_headp = td->td_self;
 
-	if (xfer->xroot->udev->pwr_save.suspended == 0) {
+	if (xfer->xroot->udev->state != USB_STATE_SUSPENDED) {
 		/* the append function will flush the endpoint descriptor */
 		OHCI_APPEND_QH(ed, *ed_last);
 

Modified: head/sys/dev/usb/controller/uhci.c
==============================================================================
--- head/sys/dev/usb/controller/uhci.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/controller/uhci.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -1921,7 +1921,7 @@ uhci_device_bulk_start(struct usb2_xfer 
 	qh->e_next = td;
 	qh->qh_e_next = td->td_self;
 
-	if (xfer->xroot->udev->pwr_save.suspended == 0) {
+	if (xfer->xroot->udev->state != USB_STATE_SUSPENDED) {
 		UHCI_APPEND_QH(qh, sc->sc_bulk_p_last);
 		uhci_add_loop(sc);
 		xfer->flags_int.bandwidth_reclaimed = 1;
@@ -1982,7 +1982,7 @@ uhci_device_ctrl_start(struct usb2_xfer 
 	 * NOTE: some devices choke on bandwidth- reclamation for control
 	 * transfers
 	 */
-	if (xfer->xroot->udev->pwr_save.suspended == 0) {
+	if (xfer->xroot->udev->state != USB_STATE_SUSPENDED) {
 		if (xfer->xroot->udev->speed == USB_SPEED_LOW) {
 			UHCI_APPEND_QH(qh, sc->sc_ls_ctl_p_last);
 		} else {
@@ -2071,7 +2071,7 @@ uhci_device_intr_start(struct usb2_xfer 
 	qh->e_next = td;
 	qh->qh_e_next = td->td_self;
 
-	if (xfer->xroot->udev->pwr_save.suspended == 0) {
+	if (xfer->xroot->udev->state != USB_STATE_SUSPENDED) {
 
 		/* enter QHs into the controller data structures */
 		UHCI_APPEND_QH(qh, sc->sc_intr_p_last[xfer->qh_pos]);

Modified: head/sys/dev/usb/usb_core.h
==============================================================================
--- head/sys/dev/usb/usb_core.h	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_core.h	Sat Apr 25 21:10:06 2009	(r191494)
@@ -552,5 +552,6 @@ void	usb2_set_parent_iface(struct usb2_d
 uint8_t	usb2_get_bus_index(struct usb2_device *udev);
 uint8_t	usb2_get_device_index(struct usb2_device *udev);
 void	usb2_set_power_mode(struct usb2_device *udev, uint8_t power_mode);
+int	usb2_device_attached(struct usb2_device *udev);
 
 #endif					/* _USB2_CORE_H_ */

Modified: head/sys/dev/usb/usb_device.c
==============================================================================
--- head/sys/dev/usb/usb_device.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_device.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -457,6 +457,8 @@ usb2_set_config_index(struct usb2_device
 		 * the current config number and index.
 		 */
 		err = usb2_req_set_config(udev, NULL, USB_UNCONFIG_NO);
+		if (udev->state == USB_STATE_CONFIGURED)
+			usb2_set_device_state(udev, USB_STATE_ADDRESSED);
 		goto done;
 	}
 	/* get the full config descriptor */
@@ -524,6 +526,7 @@ usb2_set_config_index(struct usb2_device
 	udev->power = power;
 	udev->curr_config_no = cdp->bConfigurationValue;
 	udev->curr_config_index = index;
+	usb2_set_device_state(udev, USB_STATE_CONFIGURED);
 
 	/* Set the actual configuration value. */
 	err = usb2_req_set_config(udev, NULL, cdp->bConfigurationValue);
@@ -980,7 +983,7 @@ usb2_detach_device_sub(struct usb2_devic
 		    udev->port_no, udev->address);
 
 		if (device_is_attached(dev)) {
-			if (udev->flags.suspended) {
+			if (udev->state == USB_STATE_SUSPENDED) {
 				err = DEVICE_RESUME(dev);
 				if (err) {
 					device_printf(dev, "Resume failed!\n");
@@ -1120,7 +1123,7 @@ usb2_probe_and_attach_sub(struct usb2_de
 		uaa->temp_dev = NULL;
 		device_set_ivars(iface->subdev, NULL);
 
-		if (udev->flags.suspended) {
+		if (udev->state == USB_STATE_SUSPENDED) {
 			err = DEVICE_SUSPEND(iface->subdev);
 			if (err)
 				device_printf(iface->subdev, "Suspend failed\n");
@@ -1341,12 +1344,12 @@ usb2_suspend_resume(struct usb2_device *
 
 	USB_BUS_LOCK(udev->bus);
 	/* filter the suspend events */
-	if (udev->flags.suspended == do_suspend) {
+	if ((udev->state == USB_STATE_SUSPENDED && do_suspend) ||
+	    (udev->state != USB_STATE_SUSPENDED && !do_suspend)) {
 		USB_BUS_UNLOCK(udev->bus);
 		/* nothing to do */
 		return (0);
 	}
-	udev->flags.suspended = do_suspend;
 	USB_BUS_UNLOCK(udev->bus);
 
 	/* do the suspend or resume */
@@ -1471,6 +1474,7 @@ usb2_alloc_device(device_t parent_dev, s
 	udev->bus = bus;
 	udev->address = USB_START_ADDR;	/* default value */
 	udev->plugtime = (usb2_ticks_t)ticks;
+	usb2_set_device_state(udev, USB_STATE_POWERED);
 	/*
 	 * We need to force the power mode to "on" because there are plenty
 	 * of USB devices out there that do not work very well with
@@ -1572,6 +1576,7 @@ usb2_alloc_device(device_t parent_dev, s
 			goto done;
 		}
 	}
+	usb2_set_device_state(udev, USB_STATE_ADDRESSED);
 
 	/*
 	 * Get the first 8 bytes of the device descriptor !
@@ -1927,7 +1932,8 @@ usb2_free_device(struct usb2_device *ude
 
 	DPRINTFN(4, "udev=%p port=%d\n", udev, udev->port_no);
 
-	bus = udev->bus;;
+	bus = udev->bus;
+	usb2_set_device_state(udev, USB_STATE_DETACHED);
 
 #if USB_HAVE_UGEN
 	usb2_notify_addq("-", udev);
@@ -2438,3 +2444,28 @@ usb2_peer_can_wakeup(struct usb2_device 
 	}
 	return (0);			/* not supported */
 }
+
+void
+usb2_set_device_state(struct usb2_device *udev, enum usb_dev_state state)
+{
+	static const char* statestr[USB_STATE_MAX] = {
+		[USB_STATE_DETACHED]	= "DETACHED",
+		[USB_STATE_ATTACHED]	= "ATTACHED",
+		[USB_STATE_POWERED]	= "POWERED",
+		[USB_STATE_ADDRESSED]	= "ADDRESSED",
+		[USB_STATE_CONFIGURED]	= "CONFIGURED",
+		[USB_STATE_SUSPENDED]	= "SUSPENDED"
+	};
+
+	KASSERT(state < USB_STATE_MAX, ("invalid udev state"));
+
+	DPRINTF("udev %p state %s -> %s\n", udev,
+	    statestr[udev->state], statestr[state]);
+	udev->state = state;
+}
+
+int
+usb2_device_attached(struct usb2_device *udev)
+{
+	return (udev->state > USB_STATE_DETACHED);
+}

Modified: head/sys/dev/usb/usb_device.h
==============================================================================
--- head/sys/dev/usb/usb_device.h	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_device.h	Sat Apr 25 21:10:06 2009	(r191494)
@@ -85,7 +85,6 @@ struct usb2_interface {
 struct usb2_device_flags {
 	uint8_t	usb2_mode:1;		/* USB mode (see USB_MODE_XXX) */
 	uint8_t	self_powered:1;		/* set if USB device is self powered */
-	uint8_t	suspended:1;		/* set if USB device is suspended */
 	uint8_t	no_strings:1;		/* set if USB device does not support
 					 * strings */
 	uint8_t	remote_wakeup:1;	/* set if remote wakeup is enabled */
@@ -101,7 +100,6 @@ struct usb2_power_save {
 	usb2_size_t type_refs[4];	/* transfer reference count */
 	usb2_size_t read_refs;		/* data read references */
 	usb2_size_t write_refs;		/* data write references */
-	uint8_t	suspended;		/* set if USB device is suspended */
 };
 
 /*
@@ -139,6 +137,7 @@ struct usb2_device {
 #endif
 	usb2_ticks_t plugtime;		/* copy of "ticks" */
 
+	enum usb_dev_state state;
 	uint16_t refcount;
 #define	USB_DEV_REF_MAX 0xffff
 
@@ -205,5 +204,7 @@ void	*usb2_find_descriptor(struct usb2_d
 void	usb_linux_free_device(struct usb_device *dev);
 uint8_t	usb2_peer_can_wakeup(struct usb2_device *udev);
 struct usb2_pipe *usb2_pipe_foreach(struct usb2_device *udev, struct usb2_pipe *pipe);
+void	usb2_set_device_state(struct usb2_device *udev,
+	    enum usb_dev_state state);
 
 #endif					/* _USB2_DEVICE_H_ */

Modified: head/sys/dev/usb/usb_generic.c
==============================================================================
--- head/sys/dev/usb/usb_generic.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_generic.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -823,7 +823,7 @@ usb2_gen_fill_deviceinfo(struct usb2_fif
 	di->udi_speed = udev->speed;
 	di->udi_mode = udev->flags.usb2_mode;
 	di->udi_power_mode = udev->power_mode;
-	if (udev->flags.suspended) {
+	if (udev->state == USB_STATE_SUSPENDED) {
 		di->udi_suspended = 1;
 	} else {
 		di->udi_suspended = 0;

Modified: head/sys/dev/usb/usb_hub.c
==============================================================================
--- head/sys/dev/usb/usb_hub.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_hub.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -544,7 +544,7 @@ uhub_explore(struct usb2_device *udev)
 	if (udev->depth > USB_HUB_MAX_DEPTH) {
 		return (USB_ERR_TOO_DEEP);
 	}
-	if (udev->pwr_save.suspended) {
+	if (udev->state == USB_STATE_SUSPENDED) {
 		/* need to wait until the child signals resume */
 		DPRINTF("Device is suspended!\n");
 		return (0);
@@ -1518,7 +1518,7 @@ usb2_transfer_power_ref(struct usb2_xfer
 		udev->pwr_save.write_refs += val;
 	}
 
-	if (udev->pwr_save.suspended)
+	if (udev->state == USB_STATE_SUSPENDED)
 		needs_explore =
 		    (udev->pwr_save.write_refs != 0) ||
 		    ((udev->pwr_save.read_refs != 0) &&
@@ -1600,7 +1600,7 @@ usb2_bus_powerd(struct usb2_bus *bus)
 		    (rem_wakeup == 0))) {
 
 			/* check if we are suspended */
-			if (udev->pwr_save.suspended != 0) {
+			if (udev->state == USB_STATE_SUSPENDED) {
 				USB_BUS_UNLOCK(bus);
 				usb2_dev_resume_peer(udev);
 				USB_BUS_LOCK(bus);
@@ -1608,7 +1608,7 @@ usb2_bus_powerd(struct usb2_bus *bus)
 		} else if (temp >= limit) {
 
 			/* check if we are not suspended */
-			if (udev->pwr_save.suspended == 0) {
+			if (udev->state != USB_STATE_SUSPENDED) {
 				USB_BUS_UNLOCK(bus);
 				usb2_dev_suspend_peer(udev);
 				USB_BUS_LOCK(bus);
@@ -1647,7 +1647,7 @@ usb2_bus_powerd(struct usb2_bus *bus)
 		if (temp < mintime)
 			mintime = temp;
 
-		if (udev->pwr_save.suspended == 0) {
+		if (udev->state != USB_STATE_SUSPENDED) {
 			type_refs[0] += udev->pwr_save.type_refs[0];
 			type_refs[1] += udev->pwr_save.type_refs[1];
 			type_refs[2] += udev->pwr_save.type_refs[2];
@@ -1697,7 +1697,7 @@ usb2_dev_resume_peer(struct usb2_device 
 		return;
 
 	/* check if already resumed */
-	if (udev->pwr_save.suspended == 0)
+	if (udev->state != USB_STATE_SUSPENDED)
 		return;
 
 	/* we need a parent HUB to do resume */
@@ -1737,7 +1737,7 @@ usb2_dev_resume_peer(struct usb2_device 
 	}
 	USB_BUS_LOCK(bus);
 	/* set that this device is now resumed */
-	udev->pwr_save.suspended = 0;
+	usb2_set_device_state(udev, USB_STATE_CONFIGURED);
 #if USB_HAVE_POWERD
 	/* make sure that we don't go into suspend right away */
 	udev->pwr_save.last_xfer_time = ticks;
@@ -1797,7 +1797,7 @@ repeat:
 		return;
 
 	/* check if already suspended */
-	if (udev->pwr_save.suspended)
+	if (udev->state == USB_STATE_SUSPENDED)
 		return;
 
 	/* we need a parent HUB to do suspend */
@@ -1819,7 +1819,7 @@ repeat:
 			if (child == NULL)
 				continue;
 
-			if (child->pwr_save.suspended)
+			if (child->state == USB_STATE_SUSPENDED)
 				continue;
 
 			DPRINTFN(1, "Port %u is busy on the HUB!\n", x + 1);
@@ -1846,7 +1846,7 @@ repeat:
 	 * Set that this device is suspended. This variable must be set
 	 * before calling USB controller suspend callbacks.
 	 */
-	udev->pwr_save.suspended = 1;
+	usb2_set_device_state(udev, USB_STATE_SUSPENDED);
 	USB_BUS_UNLOCK(udev->bus);
 
 	if (udev->bus->methods->device_suspend != NULL) {

Modified: head/sys/dev/usb/usb_request.c
==============================================================================
--- head/sys/dev/usb/usb_request.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_request.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -271,6 +271,12 @@ usb2_do_request_flags(struct usb2_device
 	    req->wIndex[1], req->wIndex[0],
 	    req->wLength[1], req->wLength[0]);
 
+	/* Check if the device is still alive */
+	if (udev->state < USB_STATE_POWERED) {
+		DPRINTF("usb device has gone\n");
+		return (USB_ERR_NOT_CONFIGURED);
+	}
+
 	/*
 	 * Set "actlen" to a known value in case the caller does not
 	 * check the return value:

Modified: head/sys/dev/usb/usb_revision.h
==============================================================================
--- head/sys/dev/usb/usb_revision.h	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_revision.h	Sat Apr 25 21:10:06 2009	(r191494)
@@ -62,4 +62,16 @@ enum {
 	USB_MODE_MAX
 };
 
+/*
+ * The "USB_MODE" macro defines all the supported device states.
+ */
+enum usb_dev_state {
+	USB_STATE_DETACHED,
+	USB_STATE_ATTACHED,
+	USB_STATE_POWERED,
+	USB_STATE_ADDRESSED,
+	USB_STATE_CONFIGURED,
+	USB_STATE_SUSPENDED,
+	USB_STATE_MAX,
+};
 #endif					/* _USB2_REVISION_H_ */

Modified: head/sys/dev/usb/usb_transfer.c
==============================================================================
--- head/sys/dev/usb/usb_transfer.c	Sat Apr 25 20:42:21 2009	(r191493)
+++ head/sys/dev/usb/usb_transfer.c	Sat Apr 25 21:10:06 2009	(r191494)
@@ -1365,24 +1365,37 @@ error:
 void
 usb2_start_hardware(struct usb2_xfer *xfer)
 {
+	struct usb2_xfer_root *info;
+	struct usb2_bus *bus;
 	usb2_frcount_t x;
 
+	info = xfer->xroot;
+	bus = info->bus;
+
 	DPRINTF("xfer=%p, pipe=%p, nframes=%d, dir=%s\n",
 	    xfer, xfer->pipe, xfer->nframes, USB_GET_DATA_ISREAD(xfer) ?
 	    "read" : "write");
 
+	/* Check if the device is still alive */
+	if (info->udev->state < USB_STATE_POWERED) {
+		USB_BUS_LOCK(bus);
+		usb2_transfer_done(xfer, USB_ERR_NOT_CONFIGURED);
+		USB_BUS_UNLOCK(bus);
+		return;
+	}
+
 #if USB_DEBUG
 	if (USB_DEBUG_VAR > 0) {
-		USB_BUS_LOCK(xfer->xroot->bus);
+		USB_BUS_LOCK(bus);
 
 		usb2_dump_pipe(xfer->pipe);
 
-		USB_BUS_UNLOCK(xfer->xroot->bus);
+		USB_BUS_UNLOCK(bus);
 	}
 #endif
 
 	USB_XFER_LOCK_ASSERT(xfer, MA_OWNED);
-	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_NOTOWNED);
+	USB_BUS_LOCK_ASSERT(bus, MA_NOTOWNED);
 
 	/* Only open the USB transfer once! */
 	if (!xfer->flags_int.open) {
@@ -1390,9 +1403,9 @@ usb2_start_hardware(struct usb2_xfer *xf
 
 		DPRINTF("open\n");
 
-		USB_BUS_LOCK(xfer->xroot->bus);
+		USB_BUS_LOCK(bus);
 		(xfer->pipe->methods->open) (xfer);
-		USB_BUS_UNLOCK(xfer->xroot->bus);
+		USB_BUS_UNLOCK(bus);
 	}
 	/* set "transferring" flag */
 	xfer->flags_int.transferring = 1;
@@ -1406,9 +1419,9 @@ usb2_start_hardware(struct usb2_xfer *xf
 	 * frequently the "done_q":
 	 */
 	if (xfer->wait_queue) {
-		USB_BUS_LOCK(xfer->xroot->bus);
+		USB_BUS_LOCK(bus);
 		usb2_transfer_dequeue(xfer);
-		USB_BUS_UNLOCK(xfer->xroot->bus);
+		USB_BUS_UNLOCK(bus);
 	}
 	/* clear "did_dma_delay" flag */
 	xfer->flags_int.did_dma_delay = 0;
@@ -1441,16 +1454,16 @@ usb2_start_hardware(struct usb2_xfer *xf
 			 */
 			DPRINTF("xfer=%p nframes=0: stall "
 			    "or clear stall!\n", xfer);
-			USB_BUS_LOCK(xfer->xroot->bus);
+			USB_BUS_LOCK(bus);
 			xfer->flags_int.can_cancel_immed = 1;
 			/* start the transfer */
 			usb2_command_wrapper(&xfer->pipe->pipe_q, xfer);
-			USB_BUS_UNLOCK(xfer->xroot->bus);
+			USB_BUS_UNLOCK(bus);
 			return;
 		}
-		USB_BUS_LOCK(xfer->xroot->bus);
+		USB_BUS_LOCK(bus);
 		usb2_transfer_done(xfer, USB_ERR_INVAL);
-		USB_BUS_UNLOCK(xfer->xroot->bus);
+		USB_BUS_UNLOCK(bus);
 		return;
 	}
 	/* compute total transfer length */
@@ -1459,9 +1472,9 @@ usb2_start_hardware(struct usb2_xfer *xf
 		xfer->sumlen += xfer->frlengths[x];
 		if (xfer->sumlen < xfer->frlengths[x]) {
 			/* length wrapped around */
-			USB_BUS_LOCK(xfer->xroot->bus);
+			USB_BUS_LOCK(bus);
 			usb2_transfer_done(xfer, USB_ERR_INVAL);
-			USB_BUS_UNLOCK(xfer->xroot->bus);
+			USB_BUS_UNLOCK(bus);
 			return;
 		}
 	}
@@ -1476,9 +1489,9 @@ usb2_start_hardware(struct usb2_xfer *xf
 	if (xfer->flags_int.control_xfr) {
 
 		if (usb2_start_hardware_sub(xfer)) {
-			USB_BUS_LOCK(xfer->xroot->bus);
+			USB_BUS_LOCK(bus);
 			usb2_transfer_done(xfer, USB_ERR_STALLED);
-			USB_BUS_UNLOCK(xfer->xroot->bus);
+			USB_BUS_UNLOCK(bus);
 			return;
 		}
 	}


More information about the svn-src-head mailing list