Commit e0672b3c authored by Stephen Warren's avatar Stephen Warren Committed by Marek Vasut
Browse files

usb: ci_udc: terminate ep0 INs with a zlp when required

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.
Signed-off-by: default avatarStephen Warren <>
parent b7c00516
......@@ -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;
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-> {
* 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->info = INFO_ACTIVE;
item->next = TERMINATE;
item->info |= INFO_IOC;
DBG("ept%d %s queue len %x, req %p, buffer %p\n",
num, in ? "in" : "out", len, ci_req, ci_req->hw_buf);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment