From e7549b926dd3ceec048f5689df90d4ec970c9419 Mon Sep 17 00:00:00 2001 From: Wolfgang Wiedmeyer Date: Fri, 23 Oct 2015 13:30:20 +0200 Subject: more driver stuff from 3.2.72 --- drivers/usb/musb/musb_gadget.c | 184 +++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 108 deletions(-) (limited to 'drivers/usb/musb/musb_gadget.c') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 99ceaef..9c8845a 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -643,6 +643,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) u16 len; u16 csr = musb_readw(epio, MUSB_RXCSR); struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; + u8 use_mode_1; if (hw_ep->is_shared_fifo) musb_ep = &hw_ep->ep_in; @@ -692,6 +693,18 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (csr & MUSB_RXCSR_RXPKTRDY) { len = musb_readw(epio, MUSB_RXCOUNT); + + /* + * Enable Mode 1 on RX transfers only when short_not_ok flag + * is set. Currently short_not_ok flag is set only from + * file_storage and f_mass_storage drivers + */ + + if (request->short_not_ok && len == musb_ep->packet_sz) + use_mode_1 = 1; + else + use_mode_1 = 0; + if (request->actual < request->length) { #ifdef CONFIG_USB_INVENTRA_DMA if (is_buffer_mapped(req)) { @@ -713,7 +726,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) * most these gadgets, end of is signified either by a short packet, * or filling the last byte of the buffer. (Sending extra data in * that last pckate should trigger an overflow fault.) But in mode 1, - * we don't get DMA completion interrrupt for short packets. + * we don't get DMA completion interrupt for short packets. * * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), * to get endpoint interrupt on every DMA req, but that didn't seem @@ -723,37 +736,41 @@ static void rxstate(struct musb *musb, struct musb_request *req) * then becomes usable as a runtime "use mode 1" hint... */ - csr |= MUSB_RXCSR_DMAENAB; -#ifdef USE_MODE1 - csr |= MUSB_RXCSR_AUTOCLEAR; - /* csr |= MUSB_RXCSR_DMAMODE; */ - - /* this special sequence (enabling and then - * disabling MUSB_RXCSR_DMAMODE) is required - * to get DMAReq to activate - */ - musb_writew(epio, MUSB_RXCSR, - csr | MUSB_RXCSR_DMAMODE); -#else - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) + /* Experimental: Mode1 works with mass storage use cases */ + if (use_mode_1) { csr |= MUSB_RXCSR_AUTOCLEAR; -#endif - musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + + /* + * this special sequence (enabling and then + * disabling MUSB_RXCSR_DMAMODE) is required + * to get DMAReq to activate + */ + musb_writew(epio, MUSB_RXCSR, + csr | MUSB_RXCSR_DMAMODE); + musb_writew(epio, MUSB_RXCSR, csr); + + } else { + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + } if (request->actual < request->length) { int transfer_size = 0; -#ifdef USE_MODE1 - transfer_size = min(request->length - request->actual, - channel->max_len); -#else - transfer_size = min(request->length - request->actual, - (unsigned)len); -#endif - if (transfer_size <= musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else + if (use_mode_1) { + transfer_size = min(request->length - request->actual, + channel->max_len); musb_ep->dma->desired_mode = 1; + } else { + transfer_size = min(request->length - request->actual, + (unsigned)len); + musb_ep->dma->desired_mode = 0; + } use_dma = c->channel_program( channel, @@ -1038,7 +1055,7 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; /* REVISIT this rules out high bandwidth periodic transfers */ - tmp = le16_to_cpu(desc->wMaxPacketSize); + tmp = usb_endpoint_maxp(desc); if (tmp & ~0x07ff) { int ok; @@ -1217,6 +1234,7 @@ static int musb_gadget_disable(struct usb_ep *ep) } musb_ep->desc = NULL; + musb_ep->end_point.desc = NULL; /* abort all pending DMA and requests */ nuke(musb_ep, -ESHUTDOWN); @@ -1681,8 +1699,8 @@ static void musb_pullup(struct musb *musb, int is_on) /* FIXME if on, HdrcStart; if off, HdrcStop */ - dev_dbg(musb->controller, "gadget %s D+ pullup %s\n", - musb->gadget_driver->function, is_on ? "on" : "off"); + dev_dbg(musb->controller, "gadget D+ pullup %s\n", + is_on ? "on" : "off"); musb_writeb(musb->mregs, MUSB_POWER, power); } @@ -1733,6 +1751,11 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int musb_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver); +static int musb_gadget_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver); + static const struct usb_gadget_ops musb_gadget_operations = { .get_frame = musb_gadget_get_frame, .wakeup = musb_gadget_wakeup, @@ -1740,6 +1763,8 @@ static const struct usb_gadget_ops musb_gadget_operations = { /* .vbus_session = musb_gadget_vbus_session, */ .vbus_draw = musb_gadget_vbus_draw, .pullup = musb_gadget_pullup, + .udc_start = musb_gadget_start, + .udc_stop = musb_gadget_stop, }; /* ----------------------------------------------------------------------- */ @@ -1750,7 +1775,6 @@ static const struct usb_gadget_ops musb_gadget_operations = { * about there being only one external upstream port. It assumes * all peripheral ports are external... */ -static struct musb *the_gadget; static void musb_gadget_release(struct device *dev) { @@ -1837,9 +1861,6 @@ int __init musb_gadget_setup(struct musb *musb) * musb peripherals at the same time, only the bus lock * is probably held. */ - if (the_gadget) - return -EBUSY; - the_gadget = musb; musb->g.ops = &musb_gadget_operations; musb->g.is_dualspeed = 1; @@ -1863,18 +1884,24 @@ int __init musb_gadget_setup(struct musb *musb) status = device_register(&musb->g.dev); if (status != 0) { put_device(&musb->g.dev); - the_gadget = NULL; + return status; } + status = usb_add_gadget_udc(musb->controller, &musb->g); + if (status) + goto err; + + return 0; +err: + musb->g.dev.parent = NULL; + device_unregister(&musb->g.dev); return status; } void musb_gadget_cleanup(struct musb *musb) { - if (musb != the_gadget) - return; - - device_unregister(&musb->g.dev); - the_gadget = NULL; + usb_del_gadget_udc(&musb->g); + if (musb->g.dev.parent) + device_unregister(&musb->g.dev); } /* @@ -1886,59 +1913,30 @@ void musb_gadget_cleanup(struct musb *musb) * -ENOMEM no memory 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_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int musb_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct musb *musb = the_gadget; + struct musb *musb = gadget_to_musb(g); unsigned long flags; int retval = -EINVAL; - if (!driver - || driver->speed != USB_SPEED_HIGH - || !bind || !driver->setup) - goto err0; - - /* driver must be initialized to support peripheral mode */ - if (!musb) { - dev_dbg(musb->controller, "no dev??\n"); - retval = -ENODEV; + if (driver->speed < USB_SPEED_HIGH) goto err0; - } pm_runtime_get_sync(musb->controller); dev_dbg(musb->controller, "registering driver %s\n", driver->function); - if (musb->gadget_driver) { - dev_dbg(musb->controller, "%s is already bound to %s\n", - musb_driver_name, - musb->gadget_driver->driver.name); - retval = -EBUSY; - goto err0; - } - - spin_lock_irqsave(&musb->lock, flags); + musb->softconnect = 0; musb->gadget_driver = driver; - musb->g.dev.driver = &driver->driver; - driver->driver.bus = NULL; - musb->softconnect = 1; - spin_unlock_irqrestore(&musb->lock, flags); - - retval = bind(&musb->g); - if (retval) { - dev_dbg(musb->controller, "bind to driver %s failed --> %d\n", - driver->driver.name, retval); - goto err1; - } spin_lock_irqsave(&musb->lock, flags); + musb->is_active = 1; otg_set_peripheral(musb->xceiv, &musb->g); musb->xceiv->state = OTG_STATE_B_IDLE; - musb->is_active = 1; /* * FIXME this ignores the softconnect flag. Drivers are @@ -1950,8 +1948,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, if (!is_otg_enabled(musb)) musb_start(musb); - otg_set_peripheral(musb->xceiv, &musb->g); - spin_unlock_irqrestore(&musb->lock, flags); if (is_otg_enabled(musb)) { @@ -1983,15 +1979,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, err2: if (!is_otg_enabled(musb)) musb_stop(musb); - -err1: - musb->gadget_driver = NULL; - musb->g.dev.driver = NULL; - err0: return retval; } -EXPORT_SYMBOL(usb_gadget_probe_driver); static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) { @@ -2028,10 +2018,6 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) nuke(&hw_ep->ep_out, -ESHUTDOWN); } } - - spin_unlock(&musb->lock); - driver->disconnect(&musb->g); - spin_lock(&musb->lock); } } @@ -2041,17 +2027,12 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) * * @param driver the gadget driver to unregister */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +static int musb_gadget_stop(struct usb_gadget *g, + struct usb_gadget_driver *driver) { - struct musb *musb = the_gadget; + struct musb *musb = gadget_to_musb(g); unsigned long flags; - if (!driver || !driver->unbind || !musb) - return -EINVAL; - - if (!musb->gadget_driver) - return -EINVAL; - if (musb->xceiv->last_event == USB_EVENT_NONE) pm_runtime_get_sync(musb->controller); @@ -2062,9 +2043,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&musb->lock, flags); -#ifdef CONFIG_USB_MUSB_OTG musb_hnp_stop(musb); -#endif (void) musb_gadget_vbus_draw(&musb->g, 0); @@ -2074,13 +2053,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) dev_dbg(musb->controller, "unregistering driver %s\n", driver->function); - spin_unlock_irqrestore(&musb->lock, flags); - driver->unbind(&musb->g); - spin_lock_irqsave(&musb->lock, flags); - - musb->gadget_driver = NULL; - musb->g.dev.driver = NULL; - musb->is_active = 0; musb_platform_try_idle(musb, 0); spin_unlock_irqrestore(&musb->lock, flags); @@ -2100,8 +2072,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return 0; } -EXPORT_SYMBOL(usb_gadget_unregister_driver); - /* ----------------------------------------------------------------------- */ @@ -2187,7 +2157,6 @@ void musb_g_disconnect(struct musb *musb) switch (musb->xceiv->state) { default: -#ifdef CONFIG_USB_MUSB_OTG dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_A_IDLE; @@ -2199,7 +2168,6 @@ void musb_g_disconnect(struct musb *musb) break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: -#endif case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: musb->xceiv->state = OTG_STATE_B_IDLE; -- cgit v1.1