Commit d3ca0259 authored by Lukasz Majewski's avatar Lukasz Majewski Committed by Felipe Balbi

usb:hsotg:samsung: Sending ZLP packet for IN EP0 transfers

This commit targets following scenarios for IN requests:

1. HOST requests e.g. 256B (which is a multiple of MPS = 64B).
Then NO ZLP shall be sent, since host expects exact number of bytes.

2. HOST requested 4096B, but our data for sending is 256B. In this
situation ZLP shall be send to tell HOST that no more data is available
and it shall not wait for more data. This prevents HOST from hanging.

Tested with:
- DFU gadget (various size of the sent data - also packet = MPS)
- Ethernet gadget (CDC and RNDIS)
- Multi Function Gadget (g_multi)

HW:
- Samsung's C210 Universal rev.0
- Samsung's C110 GONI
Signed-off-by: default avatarLukasz Majewski <l.majewski@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 71225bee
......@@ -1555,6 +1555,10 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
}
if (epnum == 0) {
/*
* Condition req->complete != s3c_hsotg_complete_setup says:
* send ZLP when we have an asynchronous request from gadget
*/
if (!was_setup && req->complete != s3c_hsotg_complete_setup)
s3c_hsotg_send_zlp(hsotg, hs_req);
}
......@@ -1809,6 +1813,13 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
return;
}
/* Finish ZLP handling for IN EP0 transactions */
if (hsotg->eps[0].sent_zlp) {
dev_dbg(hsotg->dev, "zlp packet received\n");
s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
return;
}
/* Calculate the size of the transfer by checking how much is left
* in the endpoint size register and then working it out from
* the amount we loaded for the transfer.
......@@ -1828,9 +1839,28 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
__func__, hs_req->req.actual, size_done);
hs_req->req.actual = size_done;
dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
/*
* Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
* When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
* ,256B ... ), after last MPS sized packet send IN ZLP packet to
* inform the host that no more data is available.
* The state of req.zero member is checked to be sure that the value to
* send is smaller than wValue expected from host.
* Check req.length to NOT send another ZLP when the current one is
* under completion (the one for which this completion has been called).
*/
if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
hs_req->req.length == hs_req->req.actual &&
!(hs_req->req.length % hs_ep->ep.maxpacket)) {
dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
s3c_hsotg_send_zlp(hsotg, hs_req);
/* if we did all of the transfer, and there is more data left
* around, then try restarting the rest of the request */
return;
}
if (!size_left && hs_req->req.actual < hs_req->req.length) {
dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
......
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