usb: musb: gadget: fix ZLP sending in musb_g_tx(v1)
This patch fixes the problem reported by Sergei:
>how come? we need to send ZLP before giving back the request.
>Well, look at the code ionce again. We need to send ZLP *after*
>request->actual == request->length, but as the check is inserted
>after the ZLP send, ZLP *may* be sent once the first DMA completes,
>not the last.
The patch also has been discussed on the link below:
http://marc.info/?t=128454814900001&r=1&w=2
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Reported-by: Sergei Shtylyov <sshtylyov@mvista.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Anand Gadiyar <gadiyar@ti.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 6a8c061..3f1cc5a 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -477,40 +477,39 @@
epnum, csr, musb_ep->dma->actual_len, request);
}
- if (is_dma || request->actual == request->length) {
- /*
- * First, maybe a terminating short packet. Some DMA
- * engines might handle this by themselves.
- */
- if ((request->zero && request->length
- && request->length % musb_ep->packet_sz == 0)
+ /*
+ * First, maybe a terminating short packet. Some DMA
+ * engines might handle this by themselves.
+ */
+ if ((request->zero && request->length
+ && (request->length % musb_ep->packet_sz == 0)
+ && (request->actual == request->length))
#ifdef CONFIG_USB_INVENTRA_DMA
- || (is_dma && (!dma->desired_mode ||
- (request->actual &
- (musb_ep->packet_sz - 1))))
+ || (is_dma && (!dma->desired_mode ||
+ (request->actual &
+ (musb_ep->packet_sz - 1))))
#endif
- ) {
- /*
- * On DMA completion, FIFO may not be
- * available yet...
- */
- if (csr & MUSB_TXCSR_TXPKTRDY)
- return;
+ ) {
+ /*
+ * On DMA completion, FIFO may not be
+ * available yet...
+ */
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+ return;
- DBG(4, "sending zero pkt\n");
- musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
- | MUSB_TXCSR_TXPKTRDY);
- request->zero = 0;
- }
+ DBG(4, "sending zero pkt\n");
+ musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
+ | MUSB_TXCSR_TXPKTRDY);
+ request->zero = 0;
+ }
- if (request->actual == request->length) {
- musb_g_giveback(musb_ep, request, 0);
- request = musb_ep->desc ? next_request(musb_ep) : NULL;
- if (!request) {
- DBG(4, "%s idle now\n",
- musb_ep->end_point.name);
- return;
- }
+ if (request->actual == request->length) {
+ musb_g_giveback(musb_ep, request, 0);
+ request = musb_ep->desc ? next_request(musb_ep) : NULL;
+ if (!request) {
+ DBG(4, "%s idle now\n",
+ musb_ep->end_point.name);
+ return;
}
}