diff options
Diffstat (limited to 'drivers/usb/musb/musb_gadget.c')
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 132 |
1 files changed, 76 insertions, 56 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d065e23f123e..5d815049cbaa 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -337,13 +337,15 @@ static void txstate(struct musb *musb, struct musb_request *req) csr |= (MUSB_TXCSR_DMAENAB | MUSB_TXCSR_MODE); /* against programming guide */ - } else - csr |= (MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB + } else { + csr |= (MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); - + if (!musb_ep->hb_mult) + csr |= MUSB_TXCSR_AUTOSET; + } csr &= ~MUSB_TXCSR_P_UNDERRUN; + musb_writew(epio, MUSB_TXCSR, csr); } } @@ -475,40 +477,39 @@ void musb_g_tx(struct musb *musb, u8 epnum) 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; } } @@ -643,7 +644,9 @@ static void rxstate(struct musb *musb, struct musb_request *req) */ csr |= MUSB_RXCSR_DMAENAB; - csr |= MUSB_RXCSR_AUTOCLEAR; + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; #ifdef USE_MODE1 /* csr |= MUSB_RXCSR_DMAMODE; */ @@ -772,7 +775,7 @@ void musb_g_rx(struct musb *musb, u8 epnum) musb_writew(epio, MUSB_RXCSR, csr); DBG(3, "%s iso overrun on %p\n", musb_ep->name, request); - if (request && request->status == -EINPROGRESS) + if (request->status == -EINPROGRESS) request->status = -EOVERFLOW; } if (csr & MUSB_RXCSR_INCOMPRX) { @@ -825,14 +828,8 @@ void musb_g_rx(struct musb *musb, u8 epnum) return; } - /* analyze request if the ep is hot */ - if (request) - rxstate(musb, to_musb_request(request)); - else - DBG(3, "packet waiting for %s%s request\n", - musb_ep->desc ? "" : "inactive ", - musb_ep->end_point.name); - return; + /* Analyze request */ + rxstate(musb, to_musb_request(request)); } /* ------------------------------------------------------------ */ @@ -875,9 +872,25 @@ static int musb_gadget_enable(struct usb_ep *ep, /* REVISIT this rules out high bandwidth periodic transfers */ tmp = le16_to_cpu(desc->wMaxPacketSize); - if (tmp & ~0x07ff) - goto fail; - musb_ep->packet_sz = tmp; + if (tmp & ~0x07ff) { + int ok; + + if (usb_endpoint_dir_in(desc)) + ok = musb->hb_iso_tx; + else + ok = musb->hb_iso_rx; + + if (!ok) { + DBG(4, "%s: not support ISO high bandwidth\n", __func__); + goto fail; + } + musb_ep->hb_mult = (tmp >> 11) & 3; + } else { + musb_ep->hb_mult = 0; + } + + musb_ep->packet_sz = tmp & 0x7ff; + tmp = musb_ep->packet_sz * (musb_ep->hb_mult + 1); /* enable the interrupts for the endpoint, set the endpoint * packet size (or fail), set the mode, clear the fifo @@ -890,8 +903,11 @@ static int musb_gadget_enable(struct usb_ep *ep, musb_ep->is_in = 1; if (!musb_ep->is_in) goto fail; - if (tmp > hw_ep->max_packet_sz_tx) + + if (tmp > hw_ep->max_packet_sz_tx) { + DBG(4, "%s: packet size beyond hw fifo size\n", __func__); goto fail; + } int_txe |= (1 << epnum); musb_writew(mbase, MUSB_INTRTXE, int_txe); @@ -906,7 +922,7 @@ static int musb_gadget_enable(struct usb_ep *ep, if (musb->hwvers < MUSB_HWVERS_2000) musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); else - musb_writew(regs, MUSB_TXMAXP, tmp); + musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; if (musb_readw(regs, MUSB_TXCSR) @@ -927,8 +943,11 @@ static int musb_gadget_enable(struct usb_ep *ep, musb_ep->is_in = 0; if (musb_ep->is_in) goto fail; - if (tmp > hw_ep->max_packet_sz_rx) + + if (tmp > hw_ep->max_packet_sz_rx) { + DBG(4, "%s: packet size beyond hw fifo size\n", __func__); goto fail; + } int_rxe |= (1 << epnum); musb_writew(mbase, MUSB_INTRRXE, int_rxe); @@ -942,7 +961,7 @@ static int musb_gadget_enable(struct usb_ep *ep, if (musb->hwvers < MUSB_HWVERS_2000) musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx); else - musb_writew(regs, MUSB_RXMAXP, tmp); + musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11)); /* force shared fifo to OUT-only mode */ if (hw_ep->is_shared_fifo) { @@ -1699,9 +1718,11 @@ void musb_gadget_cleanup(struct musb *musb) * -ENOMEM no memeory to perform the operation * * @param driver the gadget driver + * @param bind the driver's bind function * @return <0 if error, 0 if everything is fine */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) { int retval; unsigned long flags; @@ -1709,8 +1730,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (!driver || driver->speed != USB_SPEED_HIGH - || !driver->bind - || !driver->setup) + || !bind || !driver->setup) return -EINVAL; /* driver must be initialized to support peripheral mode */ @@ -1738,7 +1758,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_unlock_irqrestore(&musb->lock, flags); if (retval == 0) { - retval = driver->bind(&musb->g); + retval = bind(&musb->g); if (retval != 0) { DBG(3, "bind to driver %s failed --> %d\n", driver->driver.name, retval); @@ -1786,7 +1806,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) return retval; } -EXPORT_SYMBOL(usb_gadget_register_driver); +EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) { |