Date: Mon, 2 Feb 2015 11:06:42 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r278071 - in head/sys/dev/usb: . controller Message-ID: <201502021106.t12B6gvc002807@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Mon Feb 2 11:06:41 2015 New Revision: 278071 URL: https://svnweb.freebsd.org/changeset/base/278071 Log: 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 Modified: head/sys/dev/usb/controller/xhci.c head/sys/dev/usb/usb_core.h head/sys/dev/usb/usb_transfer.c Modified: head/sys/dev/usb/controller/xhci.c ============================================================================== --- head/sys/dev/usb/controller/xhci.c Mon Feb 2 10:31:35 2015 (r278070) +++ head/sys/dev/usb/controller/xhci.c Mon Feb 2 11:06:41 2015 (r278071) @@ -1866,6 +1866,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 | @@ -2106,7 +2115,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: head/sys/dev/usb/usb_core.h ============================================================================== --- head/sys/dev/usb/usb_core.h Mon Feb 2 10:31:35 2015 (r278070) +++ head/sys/dev/usb/usb_core.h Mon Feb 2 11:06:41 2015 (r278071) @@ -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: head/sys/dev/usb/usb_transfer.c ============================================================================== --- head/sys/dev/usb/usb_transfer.c Mon Feb 2 10:31:35 2015 (r278070) +++ head/sys/dev/usb/usb_transfer.c Mon Feb 2 11:06:41 2015 (r278071) @@ -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?201502021106.t12B6gvc002807>