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:
parent
87d352d5c6
commit
add9e3e5d3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=278071
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user