svn commit: r278071 - in head/sys/dev/usb: . controller
Hans Petter Selasky
hselasky at FreeBSD.org
Mon Feb 2 11:06:43 UTC 2015
Author: hselasky
Date: Mon Feb 2 11:06:41 2015
New Revision: 278071
URL: https://svnweb.freebsd.org/changeset/base/278071
Log:
Section 3.2.9 in the XHCI specification about control transfers says
that we should use a normal-TRB if there are more TRBs extending the
data-stage TRB. Add a dedicated state bit to the internal USB transfer
flags to handle this case.
Reported by: Kohji Okuno <okuno.kohji at jp.panasonic.com>
MFC after: 1 week
Modified:
head/sys/dev/usb/controller/xhci.c
head/sys/dev/usb/usb_core.h
head/sys/dev/usb/usb_transfer.c
Modified: head/sys/dev/usb/controller/xhci.c
==============================================================================
--- head/sys/dev/usb/controller/xhci.c Mon Feb 2 10:31:35 2015 (r278070)
+++ head/sys/dev/usb/controller/xhci.c Mon Feb 2 11:06:41 2015 (r278071)
@@ -1866,6 +1866,15 @@ restart:
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DATA_STAGE);
if (temp->direction == UE_DIR_IN)
dword |= XHCI_TRB_3_DIR_IN | XHCI_TRB_3_ISP_BIT;
+ /*
+ * Section 3.2.9 in the XHCI
+ * specification about control
+ * transfers says that we should use a
+ * normal-TRB if there are more TRBs
+ * extending the data-stage
+ * TRB. Update the "trb_type".
+ */
+ temp->trb_type = XHCI_TRB_TYPE_NORMAL;
break;
case XHCI_TRB_TYPE_STATUS_STAGE:
dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT |
@@ -2106,7 +2115,8 @@ xhci_setup_generic_chain(struct usb_xfer
mult = 1;
temp.isoc_delta = 0;
temp.isoc_frame = 0;
- temp.trb_type = XHCI_TRB_TYPE_DATA_STAGE;
+ temp.trb_type = xfer->flags_int.control_did_data ?
+ XHCI_TRB_TYPE_NORMAL : XHCI_TRB_TYPE_DATA_STAGE;
} else {
x = 0;
mult = 1;
Modified: head/sys/dev/usb/usb_core.h
==============================================================================
--- head/sys/dev/usb/usb_core.h Mon Feb 2 10:31:35 2015 (r278070)
+++ head/sys/dev/usb/usb_core.h Mon Feb 2 11:06:41 2015 (r278071)
@@ -101,6 +101,7 @@ struct usb_xfer_flags_int {
* sent */
uint8_t control_act:1; /* set if control transfer is active */
uint8_t control_stall:1; /* set if control transfer should be stalled */
+ uint8_t control_did_data:1; /* set if control DATA has been transferred */
uint8_t short_frames_ok:1; /* filtered version */
uint8_t short_xfer_ok:1; /* filtered version */
Modified: head/sys/dev/usb/usb_transfer.c
==============================================================================
--- head/sys/dev/usb/usb_transfer.c Mon Feb 2 10:31:35 2015 (r278070)
+++ head/sys/dev/usb/usb_transfer.c Mon Feb 2 11:06:41 2015 (r278071)
@@ -1409,6 +1409,29 @@ usbd_control_transfer_init(struct usb_xf
}
/*------------------------------------------------------------------------*
+ * usbd_control_transfer_did_data
+ *
+ * This function returns non-zero if a control endpoint has
+ * transferred the first DATA packet after the SETUP packet.
+ * Else it returns zero.
+ *------------------------------------------------------------------------*/
+static uint8_t
+usbd_control_transfer_did_data(struct usb_xfer *xfer)
+{
+ struct usb_device_request req;
+
+ /* SETUP packet is not yet sent */
+ if (xfer->flags_int.control_hdr != 0)
+ return (0);
+
+ /* copy out the USB request header */
+ usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));
+
+ /* compare remainder to the initial value */
+ return (xfer->flags_int.control_rem != UGETW(req.wLength));
+}
+
+/*------------------------------------------------------------------------*
* usbd_setup_ctrl_transfer
*
* This function handles initialisation of control transfers. Control
@@ -1513,6 +1536,11 @@ usbd_setup_ctrl_transfer(struct usb_xfer
len = (xfer->sumlen - sizeof(struct usb_device_request));
}
+ /* update did data flag */
+
+ xfer->flags_int.control_did_data =
+ usbd_control_transfer_did_data(xfer);
+
/* check if there is a length mismatch */
if (len > xfer->flags_int.control_rem) {
More information about the svn-src-head
mailing list