The driver did not take the zero flag in the USB request. If the request length is the same as the endpoint's maxpacket, an additional ZLP with no data has to be transmitted. The method used here is inspired to what is done in fsl_udc_core.c (and pxa27x_udc.c and at91_udc.c) where this is supported. This is the first version of the patch, it may still contain mistakes, but I send it as a RFC since there already was a discussion about this topic with people from Keymile: http://thread.gmane.org/gmane.linux.usb.general/38951 Signed-off-by: Valentin Longchamp <valentin.longchamp@xxxxxxxxxxx> --- drivers/usb/gadget/fsl_qe_udc.c | 28 +++++++++++++++++++++++----- 1 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 8dc15da..08538f5 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -1150,6 +1150,12 @@ static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame) static int txcomplete(struct qe_ep *ep, unsigned char restart) { if (ep->tx_req != NULL) { + struct qe_req *req = ep->tx_req; + unsigned zlp = 0, last_len = 0; + + last_len = min_t(unsigned, req->req.length - ep->sent, + ep->ep.maxpacket); + if (!restart) { int asent = ep->last; ep->sent += asent; @@ -1158,13 +1164,24 @@ static int txcomplete(struct qe_ep *ep, unsigned char restart) ep->last = 0; } + /* zlp needed when req->re.zero is set */ + if (req->req.zero) { + if (last_len == 0 || + (req->req.length % ep->ep.maxpacket) != 0) + zlp = 0; + else + zlp = 1; + } else + zlp = 0; + /* a request already were transmitted completely */ if ((ep->tx_req->req.length - ep->sent) <= 0) { - ep->tx_req->req.actual = (unsigned int)ep->sent; - done(ep, ep->tx_req, 0); - ep->tx_req = NULL; - ep->last = 0; - ep->sent = 0; + if (!zlp) { + done(ep, ep->tx_req, 0); + ep->tx_req = NULL; + ep->last = 0; + ep->sent = 0; + } } } @@ -1193,6 +1210,7 @@ static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame) buf = (u8 *)ep->tx_req->req.buf + ep->sent; if (buf && size) { ep->last = size; + ep->tx_req->req.actual += size; frame_set_data(frame, buf); frame_set_length(frame, size); frame_set_status(frame, FRAME_OK); -- 1.7.0.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html