usb: ci_udc: terminate ep0 INs with a zlp when required
PATCH 1/1 usb: ci_udc: terminate ep0 INs with a zlp when required
From: Stephen Warren <[email protected]>
Sometimes, a zero-length packet is required at the end of an IN transaction so that the host knows the device is done sending data. Enhance ci_udc to send a zlp when necessary. See the comments for more details.
---
This depends on all the other ci_udc patches I've sent previously at least for diff context if nothing else.
--- drivers/usb/gadget/ci_udc.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-)
drivers/usb/gadget/ci_udc.c +35 -3
@@ -369,18 +369,50 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue); len = ci_req->req.length; - item->next =TERMINATE ; - item->info =INFO_BYTES (len) |INFO_IOC |INFO_ACTIVE ; + item->info =INFO_BYTES (len) |INFO_ACTIVE ; item->page0 = (uint32_t )ci_req->hw_buf; item->page1 = ((uint32_t )ci_req->hw_buf &0xfffff000 ) +0x1000 ; item->page2 = ((uint32_t )ci_req->hw_buf &0xfffff000 ) +0x2000 ; item->page3 = ((uint32_t )ci_req->hw_buf &0xfffff000 ) +0x3000 ; item->page4 = ((uint32_t )ci_req->hw_buf &0xfffff000 ) +0x4000 ; -ci_flush_qtd (num); head->next = (unsigned ) item; head->info =0 ; +/* +* When sending the data for an IN transaction, the attached host +* knows that all data for the IN is sent when one of the following +* occurs: +* a) A zero-length packet is transmitted. +* b) A packet with length that isn't an exact multiple of the ep's +* maxpacket is transmitted. +* c) Enough data is sent to exactly fill the host's maximum expected +* IN transaction size. +* +* One of these conditions MUST apply at the end of an IN transaction, +* or the transaction will not be considered complete by the host. If +* none of (a)..(c) already applies, then we must force (a) to apply +* by explicitly sending an extra zero-length packet. +*/ +/* IN !a !b !c */ +if (in && len && !(len % ci_ep->ep.maxpacket) && ci_req->req.zero) { +/* +* Each endpoint has 2 items allocated, even though typically +* only 1 is used at a time since either an IN or an OUT but +* not both is queued. For an IN transaction, item currently +* points at the second of these items, so we know that we +* can use (item - 1) to transmit the extra zero-length packet +*/ + item->next = (unsigned )(item -1 ); + item--; + item->info =INFO_ACTIVE ; + } + + item->next =TERMINATE ; + item->info |=INFO_IOC ; + +ci_flush_qtd (num); +DBG ("ept%d %s queue len %x, req %p, buffer %p\n" , num, in ?"in" :"out" , len, ci_req, ci_req->hw_buf);ci_flush_qh (num);
Signature · 1 line
1.8.1.5
Marek Vasut
AppliedPATCH 1/1 usb: ci_udc: terminate ep0 INs with a zlp when required
Quoted 8 lines · Stephen Warren
From: Stephen Warren <[email protected]>
Sometimes, a zero-length packet is required at the end of an IN transaction so that the host knows the device is done sending data. Enhance
ci_udcto send a zlp when necessary. See the comments for more details.Signed-off-by Stephen Warren <[email protected]>
Applied, thanks!
Best regards,
Marek Vasut