Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Feb 2015 13:20:34 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r278509 - in stable/8/sys/dev/usb: . controller
Message-ID:  <201502101320.t1ADKYef098058@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Tue Feb 10 13:20:34 2015
New Revision: 278509
URL: https://svnweb.freebsd.org/changeset/base/278509

Log:
  MFC r278071:
  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.

Modified:
  stable/8/sys/dev/usb/controller/xhci.c
  stable/8/sys/dev/usb/usb_core.h
  stable/8/sys/dev/usb/usb_transfer.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/usb/   (props changed)

Modified: stable/8/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/xhci.c	Tue Feb 10 13:18:48 2015	(r278508)
+++ stable/8/sys/dev/usb/controller/xhci.c	Tue Feb 10 13:20:34 2015	(r278509)
@@ -1840,6 +1840,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 |
@@ -2079,7 +2088,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: stable/8/sys/dev/usb/usb_core.h
==============================================================================
--- stable/8/sys/dev/usb/usb_core.h	Tue Feb 10 13:18:48 2015	(r278508)
+++ stable/8/sys/dev/usb/usb_core.h	Tue Feb 10 13:20:34 2015	(r278509)
@@ -97,6 +97,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: stable/8/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/8/sys/dev/usb/usb_transfer.c	Tue Feb 10 13:18:48 2015	(r278508)
+++ stable/8/sys/dev/usb/usb_transfer.c	Tue Feb 10 13:20:34 2015	(r278509)
@@ -1344,6 +1344,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
@@ -1448,6 +1471,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) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502101320.t1ADKYef098058>