From 21c3ee93867694e8c7382ff77b4645b50d3233e9 Mon Sep 17 00:00:00 2001 From: Igor Kotrasinski Date: Tue, 15 Sep 2015 16:55:29 +0200 Subject: usb: gadget: dummy_hcd: emulate sending zlp in packet logic currently, when a zlp flag is set and an urb/usb_request buffer is filled without a short packet, transfer() leaves its status at -EINPROGRESS and does not rescan for short packet. In a scenario where ep.maxpacket bytes are copied, URB_ZERO_PACKET is set, urb buffer is filled and usb_request buffer is not, transfer() returns with an urb with -EINPROGRESS status, which dummy_hcd treats as incomplete transfer. Check for zlp and rescan appropriately. Signed-off-by: Igor Kotrasinski Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/usb/gadget/udc/dummy_hcd.c') diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1379ad4..93b38f8 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1429,15 +1429,24 @@ top: req->req.status = 0; } - /* many requests terminate without a short packet */ + /* + * many requests terminate without a short packet. + * send a zlp if demanded by flags. + */ } else { - if (req->req.length == req->req.actual - && !req->req.zero) - req->req.status = 0; - if (urb->transfer_buffer_length == urb->actual_length - && !(urb->transfer_flags - & URB_ZERO_PACKET)) - *status = 0; + if (req->req.length == req->req.actual) { + if (req->req.zero && to_host) + rescan = 1; + else + req->req.status = 0; + } + if (urb->transfer_buffer_length == urb->actual_length) { + if (urb->transfer_flags & URB_ZERO_PACKET && + !to_host) + rescan = 1; + else + *status = 0; + } } /* device side completion --> continuable */ -- cgit v1.1 From 5dda5be9d501084e8a6242e6dbeb8eea1daf01c8 Mon Sep 17 00:00:00 2001 From: Igor Kotrasinski Date: Tue, 15 Sep 2015 16:55:30 +0200 Subject: usb: gadget: dummy_hcd: fix unneeded else-if condition We already know at this point that to_host is false. Signed-off-by: Igor Kotrasinski Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget/udc/dummy_hcd.c') diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 93b38f8..69a0b3f 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1421,7 +1421,7 @@ top: *status = -EOVERFLOW; else *status = 0; - } else if (!to_host) { + } else { *status = 0; if (host_len > dev_len) req->req.status = -EOVERFLOW; -- cgit v1.1 From e42bd6a54b97e2a39b5004deac66a0fcd6ebbe75 Mon Sep 17 00:00:00 2001 From: Igor Kotrasinski Date: Tue, 15 Sep 2015 16:55:31 +0200 Subject: usb: gadget: dummy_hcd: fix rescan logic for transfer transfer() schedules a rescan for transfers larger than maxpacket, which is wrong for transfers that are multiples of maxpacket. Rewrite to fix and clarify packet multiple / remainder transfer logic. Signed-off-by: Igor Kotrasinski Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/usb/gadget/udc/dummy_hcd.c') diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 69a0b3f..ab7e015 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1385,12 +1385,15 @@ top: if (len == 0) break; - /* use an extra pass for the final short packet */ - if (len > ep->ep.maxpacket) { - rescan = 1; - len -= (len % ep->ep.maxpacket); + /* send multiple of maxpacket first, then remainder */ + if (len >= ep->ep.maxpacket) { + is_short = 0; + if (len % ep->ep.maxpacket) + rescan = 1; + len -= len % ep->ep.maxpacket; + } else { + is_short = 1; } - is_short = (len % ep->ep.maxpacket) != 0; len = dummy_perform_transfer(urb, req, len); -- cgit v1.1 From 9a9ce1dfaef9aa15980cec22b806b39a65a9467e Mon Sep 17 00:00:00 2001 From: Igor Kotrasinski Date: Tue, 15 Sep 2015 16:55:32 +0200 Subject: usb: gadget: dummy_hcd: in transfer(), return data sent, not limit dummy_timer uses transfer() to update transfer limit. However, limit passed to dummy_timer changes depending on transfer type, so the actual limit is overwritten. This can cause unpredictably slow / fast bulk transfers when coupled with control / interrupt transfers. Fix by returning actual amount of data sent in transfer() and substracting from total. Signed-off-by: Igor Kotrasinski Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget/udc/dummy_hcd.c') diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index ab7e015..27af0f0 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1348,6 +1348,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, { struct dummy *dum = dum_hcd->dum; struct dummy_request *req; + int sent = 0; top: /* if there's no request queued, the device is NAKing; return */ @@ -1402,6 +1403,7 @@ top: req->req.status = len; } else { limit -= len; + sent += len; urb->actual_length += len; req->req.actual += len; } @@ -1472,7 +1474,7 @@ top: if (rescan) goto top; } - return limit; + return sent; } static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep) @@ -1902,7 +1904,7 @@ restart: default: treat_control_like_bulk: ep->last_io = jiffies; - total = transfer(dum_hcd, urb, ep, limit, &status); + total -= transfer(dum_hcd, urb, ep, limit, &status); break; } -- cgit v1.1