Date: Tue, 10 Feb 2015 13:16:54 +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-10@freebsd.org Subject: svn commit: r278507 - in stable/10/sys/dev/usb: . controller Message-ID: <201502101316.t1ADGsGH095290@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Tue Feb 10 13:16:53 2015 New Revision: 278507 URL: https://svnweb.freebsd.org/changeset/base/278507 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/10/sys/dev/usb/controller/xhci.c stable/10/sys/dev/usb/usb_core.h stable/10/sys/dev/usb/usb_transfer.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/usb/controller/xhci.c ============================================================================== --- stable/10/sys/dev/usb/controller/xhci.c Tue Feb 10 13:07:08 2015 (r278506) +++ stable/10/sys/dev/usb/controller/xhci.c Tue Feb 10 13:16:53 2015 (r278507) @@ -1870,6 +1870,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 | @@ -2110,7 +2119,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/10/sys/dev/usb/usb_core.h ============================================================================== --- stable/10/sys/dev/usb/usb_core.h Tue Feb 10 13:07:08 2015 (r278506) +++ stable/10/sys/dev/usb/usb_core.h Tue Feb 10 13:16:53 2015 (r278507) @@ -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: stable/10/sys/dev/usb/usb_transfer.c ============================================================================== --- stable/10/sys/dev/usb/usb_transfer.c Tue Feb 10 13:07:08 2015 (r278506) +++ stable/10/sys/dev/usb/usb_transfer.c Tue Feb 10 13:16:53 2015 (r278507) @@ -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) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201502101316.t1ADGsGH095290>