diff options
author | Andrew Thompson <thompsa@FreeBSD.org> | 2009-11-04 21:28:50 +0000 |
---|---|---|
committer | Andrew Thompson <thompsa@FreeBSD.org> | 2009-11-04 21:28:50 +0000 |
commit | fd805728662697d1e229ac07e05f7ed850e59bee (patch) | |
tree | 61df86b8ebf21ed8d665aa3b380a840f82e02cb4 /sys/dev/usb | |
parent | b9bd7bf67826f0ebde7bb6248101af92474b9858 (diff) | |
download | src-test2-fd805728662697d1e229ac07e05f7ed850e59bee.tar.gz src-test2-fd805728662697d1e229ac07e05f7ed850e59bee.zip |
Notes
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/usb_core.h | 1 | ||||
-rw-r--r-- | sys/dev/usb/usb_transfer.c | 20 |
2 files changed, 20 insertions, 1 deletions
diff --git a/sys/dev/usb/usb_core.h b/sys/dev/usb/usb_core.h index 84c163b381c0..a9d273d427f6 100644 --- a/sys/dev/usb/usb_core.h +++ b/sys/dev/usb/usb_core.h @@ -112,6 +112,7 @@ struct usb_xfer_flags_int { uint8_t curr_dma_set:1; /* used by USB HC/DC driver */ uint8_t can_cancel_immed:1; /* set if USB transfer can be * cancelled immediately */ + uint8_t doing_callback:1; /* set if executing the callback */ }; /* diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 8daf475a4b8a..878f64499a50 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -1785,8 +1785,18 @@ usbd_transfer_drain(struct usb_xfer *xfer) usbd_transfer_stop(xfer); - while (usbd_transfer_pending(xfer)) { + while (usbd_transfer_pending(xfer) || + xfer->flags_int.doing_callback) { + + /* + * It is allowed that the callback can drop its + * transfer mutex. In that case checking only + * "usbd_transfer_pending()" is not enough to tell if + * the USB transfer is fully drained. We also need to + * check the internal "doing_callback" flag. + */ xfer->flags_int.draining = 1; + /* * Wait until the current outstanding USB * transfer is complete ! @@ -2031,6 +2041,9 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) /* get next USB transfer in the queue */ info->done_q.curr = NULL; + /* set flag in case of drain */ + xfer->flags_int.doing_callback = 1; + USB_BUS_UNLOCK(info->bus); USB_BUS_LOCK_ASSERT(info->bus, MA_NOTOWNED); @@ -2083,12 +2096,17 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) if ((!xfer->flags_int.open) && (xfer->flags_int.started) && (xfer->usb_state == USB_ST_ERROR)) { + /* clear flag in case of drain */ + xfer->flags_int.doing_callback = 0; /* try to loop, but not recursivly */ usb_command_wrapper(&info->done_q, xfer); return; } done: + /* clear flag in case of drain */ + xfer->flags_int.doing_callback = 0; + /* * Check if we are draining. */ |