summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_transfer.c
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-04-25 21:10:06 +0000
committerthompsa <thompsa@FreeBSD.org>2009-04-25 21:10:06 +0000
commit1253be32753b7ab96a90d57fc07991ae8a154177 (patch)
tree6204fa982868a9530323799ccff1606ec998c2ba /sys/dev/usb/usb_transfer.c
parent50a34549cf93908659f1fb58b36fc7ed8ecfc3b8 (diff)
downloadFreeBSD-src-1253be32753b7ab96a90d57fc07991ae8a154177.zip
FreeBSD-src-1253be32753b7ab96a90d57fc07991ae8a154177.tar.gz
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.
Diffstat (limited to 'sys/dev/usb/usb_transfer.c')
-rw-r--r--sys/dev/usb/usb_transfer.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c
index bc44177..d4efaff 100644
--- a/sys/dev/usb/usb_transfer.c
+++ b/sys/dev/usb/usb_transfer.c
@@ -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 *xfer)
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 *xfer)
* 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 *xfer)
*/
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 *xfer)
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 *xfer)
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;
}
}
OpenPOWER on IntegriCloud