/* Check if DMA engine can handle this request. * DMA code must reject the USB request explicitly. * Default behaviour is to map the request.
*/ if (dma->is_compatible)
compatible = dma->is_compatible(musb_ep->dma,
musb_ep->packet_sz, request->request.buf,
request->request.length); if (!compatible) return;
if (request->request.dma == DMA_ADDR_INVALID) {
dma_addr_t dma_addr; int ret;
dma_addr = dma_map_single(
musb->controller,
request->request.buf,
request->request.length,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
ret = dma_mapping_error(musb->controller, dma_addr); if (ret) return;
/* Unmap the buffer from dma and maps it back to cpu */ staticinlinevoid unmap_dma_buffer(struct musb_request *request, struct musb *musb)
{ struct musb_ep *musb_ep = request->ep;
if (!is_buffer_mapped(request) || !musb_ep->dma) return;
/* * Immediately complete a request. * * @param request the request to complete * @param status the status to complete the request with * Context: controller locked, IRQs blocked.
*/ void musb_g_giveback( struct musb_ep *ep, struct usb_request *request, int status)
__releases(ep->musb->lock)
__acquires(ep->musb->lock)
{ struct musb_request *req; struct musb *musb; int busy = ep->busy;
/* * Abort requests queued to an endpoint using the status. Synchronous. * caller locked controller and blocked irqs, and selected this ep.
*/ staticvoid nuke(struct musb_ep *ep, constint status)
{ struct musb *musb = ep->musb; struct musb_request *req = NULL; void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs;
ep->busy = 1;
if (is_dma_capable() && ep->dma) { struct dma_controller *c = ep->musb->dma_controller; int value;
if (ep->is_in) { /* * The programming guide says that we must not clear * the DMAMODE bit before DMAENAB, so we only * clear it in the second write...
*/
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO);
musb_writew(epio, MUSB_TXCSR,
0 | MUSB_TXCSR_FLUSHFIFO);
} else {
musb_writew(epio, MUSB_RXCSR,
0 | MUSB_RXCSR_FLUSHFIFO);
musb_writew(epio, MUSB_RXCSR,
0 | MUSB_RXCSR_FLUSHFIFO);
}
/* * An endpoint is transmitting data. This can be called either from * the IRQ routine or from ep.queue() to kickstart a request on an * endpoint. * * Context: controller locked, IRQs blocked, endpoint selected
*/ staticvoid txstate(struct musb *musb, struct musb_request *req)
{
u8 epnum = req->epnum; struct musb_ep *musb_ep; void __iomem *epio = musb->endpoints[epnum].regs; struct usb_request *request;
u16 fifo_count = 0, csr; int use_dma = 0;
musb_ep = req->ep;
/* Check if EP is disabled */ if (!musb_ep->desc) {
musb_dbg(musb, "ep:%s disabled - ignore request",
musb_ep->end_point.name); return;
}
/* we shouldn't get here while DMA is active ... but we do ... */ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
musb_dbg(musb, "dma pending..."); return;
}
/* read TXCSR before */
csr = musb_readw(epio, MUSB_TXCSR);
/* ensure writebuffer is empty */
csr = musb_readw(epio, MUSB_TXCSR);
/* * NOTE host side sets DMAENAB later than this; both are * OK since the transfer dma glue (between CPPI and * Mentor fifos) just tells CPPI it could start. Data * only moves to the USB TX fifo when both fifos are * ready.
*/ /* * "mode" is irrelevant here; handle terminating ZLPs * like PIO does, since the hardware RNDIS mode seems * unreliable except for the * last-packet-is-already-short case.
*/
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
0,
request->dma + request->actual,
request_size); if (!use_dma) {
c->channel_release(musb_ep->dma);
musb_ep->dma = NULL;
csr &= ~MUSB_TXCSR_DMAENAB;
musb_writew(epio, MUSB_TXCSR, csr); /* invariant: prequest->buf is non-null */
}
} elseif (tusb_dma_omap(musb))
use_dma = use_dma && c->channel_program(
musb_ep->dma, musb_ep->packet_sz,
request->zero,
request->dma + request->actual,
request_size);
} #endif
if (!use_dma) { /* * Unmap the dma buffer back to cpu if dma channel * programming fails
*/
unmap_dma_buffer(req, musb);
/* * REVISIT: for high bandwidth, MUSB_TXCSR_P_INCOMPTX * probably rates reporting as a host error.
*/ if (csr & MUSB_TXCSR_P_SENTSTALL) {
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~MUSB_TXCSR_P_SENTSTALL;
musb_writew(epio, MUSB_TXCSR, csr); return;
}
if (csr & MUSB_TXCSR_P_UNDERRUN) { /* We NAKed, no big deal... little reason to care. */
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
musb_writew(epio, MUSB_TXCSR, csr);
dev_vdbg(musb->controller, "underrun on ep%d, req %p\n",
epnum, request);
}
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { /* * SHOULD NOT HAPPEN... has with CPPI though, after * changing SENDSTALL (and other cases); harmless?
*/
musb_dbg(musb, "%s dma still busy?", musb_ep->end_point.name); return;
}
if (request->actual == request->length) {
musb_g_giveback(musb_ep, request, 0); /* * In the giveback function the MUSB lock is * released and acquired after sometime. During * this time period the INDEX register could get * changed by the gadget_queue function especially * on SMP systems. Reselect the INDEX to be sure * we are reading/modifying the right registers
*/
musb_ep_select(mbase, epnum);
req = musb_ep->desc ? next_request(musb_ep) : NULL; if (!req) {
musb_dbg(musb, "%s idle now",
musb_ep->end_point.name); return;
}
}
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in; else
musb_ep = &hw_ep->ep_out;
fifo_count = musb_ep->packet_sz;
/* Check if EP is disabled */ if (!musb_ep->desc) {
musb_dbg(musb, "ep:%s disabled - ignore request",
musb_ep->end_point.name); return;
}
/* We shouldn't get here while DMA is active, but we do... */ if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
musb_dbg(musb, "DMA pending..."); return;
}
/* NOTE: CPPI won't actually stop advancing the DMA * queue after short packet transfers, so this is almost * always going to run as IRQ-per-packet DMA so that * faults will be handled correctly.
*/ if (c->channel_program(channel,
musb_ep->packet_sz,
!request->short_not_ok,
request->dma + request->actual,
request->length - request->actual)) {
/* make sure that if an rxpkt arrived after the irq, * the cppi engine will be ready to take it as soon * as DMA is enabled
*/
csr &= ~(MUSB_RXCSR_AUTOCLEAR
| MUSB_RXCSR_DMAMODE);
csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS;
musb_writew(epio, MUSB_RXCSR, csr); return;
}
}
if (csr & MUSB_RXCSR_RXPKTRDY) {
fifo_count = 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->actual < request->length) { if (!is_buffer_mapped(req)) goto buffer_aint_mapped;
if (musb_dma_inventra(musb)) { struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; unsignedint transfer_size;
c = musb->dma_controller;
channel = musb_ep->dma;
/* We use DMA Req mode 0 in rx_csr, and DMA controller operates in * mode 0 only. So we do not get endpoint interrupts due to DMA * completion. We only get interrupts from DMA controller. * * We could operate in DMA mode 1 if we knew the size of the transfer * in advance. For mass storage class, request->length = what the host * sends, so that'd work. But for pretty much everything else, * request->length is routinely more than what the host sends. For * 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 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 * to work reliably. * * REVISIT an updated g_file_storage can set req->short_not_ok, which * then becomes usable as a runtime "use mode 1" hint...
*/
/* Experimental: Mode1 works with mass storage use cases */ if (use_mode_1) {
csr |= MUSB_RXCSR_AUTOCLEAR;
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);
ret = c->channel_program(channel,
musb_ep->packet_sz,
channel->desired_mode,
dma_addr,
fifo_count); if (ret) return;
}
/* * Unmap the dma buffer back to cpu if dma channel * programming fails. This buffer is mapped if the * channel allocation is successful
*/
unmap_dma_buffer(req, musb);
/* * Clear DMAENAB and AUTOCLEAR for the * PIO mode transfer
*/
csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
musb_writew(epio, MUSB_RXCSR, csr);
/* reach the end or short packet detected */ if (request->actual == request->length ||
fifo_count < musb_ep->packet_sz)
musb_g_giveback(musb_ep, request, 0);
}
/* * Data ready for a request; called from IRQ
*/ void musb_g_rx(struct musb *musb, u8 epnum)
{
u16 csr; struct musb_request *req; struct usb_request *request; void __iomem *mbase = musb->mregs; struct musb_ep *musb_ep; void __iomem *epio = musb->endpoints[epnum].regs; struct dma_channel *dma; struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in; else
musb_ep = &hw_ep->ep_out;
#ifdefined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ defined(CONFIG_USB_UX500_DMA) /* Autoclear doesn't clear RxPktRdy for short packets */ if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered)
|| (dma->actual_len
& (musb_ep->packet_sz - 1))) { /* ack the read! */
csr &= ~MUSB_RXCSR_RXPKTRDY;
musb_writew(epio, MUSB_RXCSR, csr);
}
/* incomplete, and not short? wait for next IN packet */ if ((request->actual < request->length)
&& (musb_ep->dma->actual_len
== musb_ep->packet_sz)) { /* In double buffer case, continue to unload fifo if * there is Rx packet in FIFO.
**/
csr = musb_readw(epio, MUSB_RXCSR); if ((csr & MUSB_RXCSR_RXPKTRDY) &&
hw_ep->rx_double_buffered) gotoexit; return;
} #endif
musb_g_giveback(musb_ep, request, 0); /* * In the giveback function the MUSB lock is * released and acquired after sometime. During * this time period the INDEX register could get * changed by the gadget_queue function especially * on SMP systems. Reselect the INDEX to be sure * we are reading/modifying the right registers
*/
musb_ep_select(mbase, epnum);
/* enable the interrupts for the endpoint, set the endpoint * packet size (or fail), set the mode, clear the fifo
*/
musb_ep_select(mbase, epnum); if (usb_endpoint_dir_in(desc)) {
if (hw_ep->is_shared_fifo)
musb_ep->is_in = 1; if (!musb_ep->is_in) goto fail;
/* REVISIT if can_bulk_split(), use by updating "tmp"; * likewise high bandwidth periodic tx
*/ /* Set TXMAXP with the FIFO size of the endpoint * to disable double buffering mode.
*/ if (can_bulk_split(musb, musb_ep->type))
musb_ep->hb_mult = (hw_ep->max_packet_sz_tx /
musb_ep->packet_sz) - 1;
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)
& MUSB_TXCSR_FIFONOTEMPTY)
csr |= MUSB_TXCSR_FLUSHFIFO; if (musb_ep->type == USB_ENDPOINT_XFER_ISOC)
csr |= MUSB_TXCSR_P_ISO;
/* set twice in case of double buffering */
musb_writew(regs, MUSB_TXCSR, csr); /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */
musb_writew(regs, MUSB_TXCSR, csr);
} else {
if (hw_ep->is_shared_fifo)
musb_ep->is_in = 0; if (musb_ep->is_in) goto fail;
/* REVISIT if can_bulk_combine() use by updating "tmp" * likewise high bandwidth periodic rx
*/ /* Set RXMAXP with the FIFO size of the endpoint * to disable double buffering mode.
*/
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) {
csr = musb_readw(regs, MUSB_TXCSR);
csr &= ~(MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY);
musb_writew(regs, MUSB_TXCSR, csr);
}
/* set twice in case of double buffering */
musb_writew(regs, MUSB_RXCSR, csr);
musb_writew(regs, MUSB_RXCSR, csr);
}
/* NOTE: all the I/O code _should_ work fine without DMA, in case * for some reason you run out of channels here.
*/ if (is_dma_capable() && musb->dma_controller) { struct dma_controller *c = musb->dma_controller;
status = pm_runtime_get(musb->controller); if ((status != -EINPROGRESS) && status < 0) {
dev_err(musb->controller, "pm runtime get failed in %s\n",
__func__);
pm_runtime_put_noidle(musb->controller);
/* don't queue if the ep is down */ if (!musb_ep->desc) {
musb_dbg(musb, "req %p queued to %s while ep %s",
req, ep->name, "disabled");
status = -ESHUTDOWN;
unmap_dma_buffer(request, musb); goto unlock;
}
/* add request to the list */
list_add_tail(&request->list, &musb_ep->req_list);
/* it this is the head of the queue, start i/o ... */ if (!musb_ep->busy && &request->list == musb_ep->req_list.next) {
status = musb_queue_resume_work(musb,
musb_ep_restart_resume_work,
request); if (status < 0) {
dev_err(musb->controller, "%s resume work: %i\n",
__func__, status);
list_del(&request->list);
}
}
if (!ep || !request || req->ep != musb_ep) return -EINVAL;
trace_musb_req_deq(req);
spin_lock_irqsave(&musb->lock, flags);
list_for_each_entry(r, &musb_ep->req_list, list) { if (r == req) break;
} if (r != req) {
dev_err(musb->controller, "request %p not queued to %s\n",
request, ep->name);
status = -EINVAL; goto done;
}
/* if the hardware doesn't have the request, easy ... */ if (musb_ep->req_list.next != &req->list || musb_ep->busy)
musb_g_giveback(musb_ep, request, -ECONNRESET);
/* ... else abort the dma transfer ... */ elseif (is_dma_capable() && musb_ep->dma) { struct dma_controller *c = musb->dma_controller;
musb_ep_select(musb->mregs, musb_ep->current_epnum); if (c->channel_abort)
status = c->channel_abort(musb_ep->dma); else
status = -EBUSY; if (status == 0)
musb_g_giveback(musb_ep, request, -ECONNRESET);
} else { /* NOTE: by sticking to easily tested hardware/driver states, * we leave counting of in-flight packets imprecise.
*/
musb_g_giveback(musb_ep, request, -ECONNRESET);
}
/* * Set or clear the halt bit of an endpoint. A halted endpoint won't tx/rx any * data but will queue requests. * * exported to ep0 code
*/ staticint musb_gadget_set_halt(struct usb_ep *ep, int value)
{ struct musb_ep *musb_ep = to_musb_ep(ep);
u8 epnum = musb_ep->current_epnum; struct musb *musb = musb_ep->musb; void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *mbase; unsignedlong flags;
u16 csr; struct musb_request *request; int status = 0;
if (!ep) return -EINVAL;
mbase = musb->mregs;
spin_lock_irqsave(&musb->lock, flags);
if ((USB_ENDPOINT_XFER_ISOC == musb_ep->type)) {
status = -EINVAL; goto done;
}
musb_ep_select(mbase, epnum);
request = next_request(musb_ep); if (value) { if (request) {
musb_dbg(musb, "request in progress, cannot halt %s",
ep->name);
status = -EAGAIN; goto done;
} /* Cannot portably stall with non-empty FIFO */ if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR); if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
musb_dbg(musb, "FIFO busy, cannot halt %s",
ep->name);
status = -EAGAIN; goto done;
}
}
} else
musb_ep->wedged = 0;
/* maybe start the first request in the queue */ if (!musb_ep->busy && !value && request) {
musb_dbg(musb, "restarting the request");
musb_ep_restart(musb, request);
}
/* NOTE: this assumes we are sensing vbus; we'd rather * not pullup unless the B-session is active.
*/
spin_lock_irqsave(&musb->lock, flags); if (is_on != musb->softconnect) {
musb->softconnect = is_on;
schedule_delayed_work(&musb->gadget_work, 0);
}
spin_unlock_irqrestore(&musb->lock, flags);
/* Only this registration code "knows" the rule (from USB standards) * about there being only one external upstream port. It assumes * all peripheral ports are external...
*/
/* * Initialize the endpoints exposed to peripheral drivers, with backlinks * to the rest of the driver state.
*/ staticinlinevoid musb_g_init_endpoints(struct musb *musb)
{
u8 epnum; struct musb_hw_ep *hw_ep;
/* initialize endpoint list just once */
INIT_LIST_HEAD(&(musb->g.ep_list));
/* called once during driver setup to initialize and link into * the driver model; memory is zeroed.
*/ int musb_gadget_setup(struct musb *musb)
{ int status;
/* REVISIT minor race: if (erroneously) setting up two * musb peripherals at the same time, only the bus lock * is probably held.
*/
/* * Register the gadget driver. Used by gadget drivers when * registering themselves with the controller. * * -EINVAL something went wrong (not driver) * -EBUSY another gadget is already using the controller * -ENOMEM no memory to perform the operation * * @param driver the gadget driver * @return <0 if error, 0 if everything is fine
*/ staticint musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver)
{ struct musb *musb = gadget_to_musb(g); unsignedlong flags; int retval = 0;
/* REVISIT: funcall to other code, which also * handles power budgeting ... this way also * ensures HdrcStart is indirectly called.
*/ if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID)
musb_platform_set_vbus(musb, 1);
/* * Unregister the gadget driver. Used by gadget drivers when * unregistering themselves from the controller. * * @param driver the gadget driver to unregister
*/ staticint musb_gadget_stop(struct usb_gadget *g)
{ struct musb *musb = gadget_to_musb(g); unsignedlong flags;
pm_runtime_get_sync(musb->controller);
/* * REVISIT always use otg_set_peripheral() here too; * this needs to shut down the OTG engine.
*/
/* * FIXME we need to be able to register another * gadget driver here and have everything work; * that currently misbehaves.
*/
usb_gadget_set_state(g, USB_STATE_NOTATTACHED);
/* Force check of devctl register for PM runtime */
pm_runtime_mark_last_busy(musb->controller);
pm_runtime_put_autosuspend(musb->controller);
/* what speed did we negotiate? */
power = musb_readb(mbase, MUSB_POWER);
musb->g.speed = (power & MUSB_POWER_HSMODE)
? USB_SPEED_HIGH : USB_SPEED_FULL;
/* Normal reset, as B-Device; * or else after HNP, as A-Device
*/ if (!musb->g.is_otg) { /* USB device controllers that are not OTG compatible * may not have DEVCTL register in silicon. * In that case, do not rely on devctl for setting * peripheral mode.
*/
musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->g.is_a_peripheral = 0;
} elseif (devctl & MUSB_DEVCTL_BDEVICE) {
musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
musb->g.is_a_peripheral = 0;
} else {
musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
musb->g.is_a_peripheral = 1;
}
/* start with default limits on VBUS power draw */
(void) musb_gadget_vbus_draw(&musb->g, 8);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.