Hi,

Please find updated patch. The control_rem is pre-decremented and not post-decremented.


--HPS
Index: sys/dev/usb/controller/xhci.c
===================================================================
--- sys/dev/usb/controller/xhci.c	(revision 277724)
+++ sys/dev/usb/controller/xhci.c	(working copy)
@@ -1866,6 +1866,15 @@
 				    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 @@
 		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;
Index: sys/dev/usb/usb_core.h
===================================================================
--- sys/dev/usb/usb_core.h	(revision 277724)
+++ sys/dev/usb/usb_core.h	(working copy)
@@ -101,6 +101,7 @@
 					 * 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 sent */
 
 	uint8_t	short_frames_ok:1;	/* filtered version */
 	uint8_t	short_xfer_ok:1;	/* filtered version */
Index: sys/dev/usb/usb_transfer.c
===================================================================
--- sys/dev/usb/usb_transfer.c	(revision 277724)
+++ sys/dev/usb/usb_transfer.c	(working copy)
@@ -1409,6 +1409,28 @@
 }
 
 /*------------------------------------------------------------------------*
+ *	usbd_control_transfer_did_data
+ *
+ * This function returns non-zero if a control endpoint has done 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 +1535,11 @@
 		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) {
_______________________________________________
freebsd-usb@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "freebsd-usb-unsubscr...@freebsd.org"

Reply via email to