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@jp.panasonic.com>
MFC after:	1 week
This commit is contained in:
Hans Petter Selasky 2015-02-02 11:06:41 +00:00
parent 87d352d5c6
commit add9e3e5d3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=278071
3 changed files with 40 additions and 1 deletions

View File

@ -1866,6 +1866,15 @@ xhci_setup_generic_chain_sub(struct xhci_std_temp *temp)
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 *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;

View File

@ -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 */

View File

@ -1408,6 +1408,29 @@ usbd_control_transfer_init(struct usb_xfer *xfer)
(req.bmRequestType & UT_READ) ? UE_DIR_IN : UE_DIR_OUT;
}
/*------------------------------------------------------------------------*
* 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
*
@ -1513,6 +1536,11 @@ usbd_setup_ctrl_transfer(struct usb_xfer *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) {