summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb/usb_transfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/usb/usb_transfer.c')
-rw-r--r--freebsd/sys/dev/usb/usb_transfer.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/freebsd/sys/dev/usb/usb_transfer.c b/freebsd/sys/dev/usb/usb_transfer.c
index b2528186..205a72f7 100644
--- a/freebsd/sys/dev/usb/usb_transfer.c
+++ b/freebsd/sys/dev/usb/usb_transfer.c
@@ -334,6 +334,7 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm)
usb_frcount_t n_frlengths;
usb_frcount_t n_frbuffers;
usb_frcount_t x;
+ uint16_t maxp_old;
uint8_t type;
uint8_t zmps;
@@ -419,6 +420,11 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm)
if (xfer->max_packet_count > parm->hc_max_packet_count) {
xfer->max_packet_count = parm->hc_max_packet_count;
}
+
+ /* store max packet size value before filtering */
+
+ maxp_old = xfer->max_packet_size;
+
/* filter "wMaxPacketSize" according to HC capabilities */
if ((xfer->max_packet_size > parm->hc_max_packet_size) ||
@@ -451,6 +457,13 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm)
}
}
+ /*
+ * Check if the max packet size was outside its allowed range
+ * and clamped to a valid value:
+ */
+ if (maxp_old != xfer->max_packet_size)
+ xfer->flags_int.maxp_was_clamped = 1;
+
/* compute "max_frame_size" */
usbd_update_max_frame_size(xfer);
@@ -2396,7 +2409,9 @@ usbd_transfer_enqueue(struct usb_xfer_queue *pq, struct usb_xfer *xfer)
void
usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
{
- USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
+ struct usb_xfer_root *info = xfer->xroot;
+
+ USB_BUS_LOCK_ASSERT(info->bus, MA_OWNED);
DPRINTF("err=%s\n", usbd_errstr(error));
@@ -2410,10 +2425,10 @@ usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
xfer->flags_int.control_act = 0;
return;
}
- /* only set transfer error if not already set */
- if (!xfer->error) {
+ /* only set transfer error, if not already set */
+ if (xfer->error == USB_ERR_NORMAL_COMPLETION)
xfer->error = error;
- }
+
/* stop any callouts */
usb_callout_stop(&xfer->timeout_handle);
@@ -2425,14 +2440,14 @@ usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
usbd_transfer_dequeue(xfer);
#if USB_HAVE_BUSDMA
- if (mtx_owned(xfer->xroot->xfer_mtx)) {
+ if (mtx_owned(info->xfer_mtx)) {
struct usb_xfer_queue *pq;
/*
* If the private USB lock is not locked, then we assume
* that the BUS-DMA load stage has been passed:
*/
- pq = &xfer->xroot->dma_q;
+ pq = &info->dma_q;
if (pq->curr == xfer) {
/* start the next BUS-DMA load, if any */
@@ -2442,10 +2457,10 @@ usbd_transfer_done(struct usb_xfer *xfer, usb_error_t error)
#endif
/* keep some statistics */
if (xfer->error) {
- xfer->xroot->bus->stats_err.uds_requests
+ info->bus->stats_err.uds_requests
[xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
} else {
- xfer->xroot->bus->stats_ok.uds_requests
+ info->bus->stats_ok.uds_requests
[xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE]++;
}
@@ -2685,7 +2700,7 @@ usbd_transfer_timeout_ms(struct usb_xfer *xfer,
/* defer delay */
usb_callout_reset(&xfer->timeout_handle,
- USB_MS_TO_TICKS(ms), cb, xfer);
+ USB_MS_TO_TICKS(ms) + USB_CALLOUT_ZERO_TICKS, cb, xfer);
}
/*------------------------------------------------------------------------*
@@ -2811,6 +2826,22 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer)
/* end of control transfer, if any */
xfer->flags_int.control_act = 0;
+#if USB_HAVE_TT_SUPPORT
+ switch (xfer->error) {
+ case USB_ERR_NORMAL_COMPLETION:
+ case USB_ERR_SHORT_XFER:
+ case USB_ERR_STALLED:
+ case USB_ERR_CANCELLED:
+ /* nothing to do */
+ break;
+ default:
+ /* try to reset the TT, if any */
+ USB_BUS_LOCK(bus);
+ uhub_tt_buffer_reset_async_locked(xfer->xroot->udev, xfer->endpoint);
+ USB_BUS_UNLOCK(bus);
+ break;
+ }
+#endif
/* check if we should block the execution queue */
if ((xfer->error != USB_ERR_CANCELLED) &&
(xfer->flags.pipe_bof)) {
@@ -3377,3 +3408,13 @@ usbd_xfer_get_timestamp(struct usb_xfer *xfer)
{
return (xfer->isoc_time_complete);
}
+
+/*
+ * The following function returns non-zero if the max packet size
+ * field was clamped to a valid value. Else it returns zero.
+ */
+uint8_t
+usbd_xfer_maxp_was_clamped(struct usb_xfer *xfer)
+{
+ return (xfer->flags_int.maxp_was_clamped);
+}