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: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Lukasz Majewski 2012-05-04 14:17:04 +02:00 committed by Felipe Balbi
parent 71225beeeb
commit d3ca0259c5
1 changed files with 32 additions and 2 deletions

View File

@ -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);
/* if we did all of the transfer, and there is more data left
* around, then try restarting the rest of the request */
/*
* 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);
return;
}
if (!size_left && hs_req->req.actual < hs_req->req.length) {
dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);