/* USB speed and corresponding string calculated from status register value */ #define GR_SPEED(status) \
((status & GR_STATUS_SP) ? USB_SPEED_FULL : USB_SPEED_HIGH) #define GR_SPEED_STR(status) usb_speed_string(GR_SPEED(status))
/* Size of hardware buffer calculated from epctrl register value */ #define GR_BUFFER_SIZE(epctrl) \
((((epctrl) & GR_EPCTRL_BUFSZ_MASK) >> GR_EPCTRL_BUFSZ_POS) * \
GR_EPCTRL_BUFSZ_SCALER)
if (likely(req->req.status == -EINPROGRESS))
req->req.status = status; else
status = req->req.status;
dev = ep->dev;
usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
gr_free_dma_desc_chain(dev, req);
if (ep->is_in) { /* For OUT, req->req.actual gets updated bit by bit */
req->req.actual = req->req.length;
} elseif (req->oddlen && req->req.actual > req->evenlen) { /* *Copytouserbufferinthiscasewherelengthwasnotevenly *divisiblebyep->ep.maxpacketandthelastdescriptorwas *actuallyused.
*/ char *buftail = ((char *)req->req.buf + req->evenlen);
memcpy(buftail, ep->tailbuf, req->oddlen);
if (req->req.actual > req->req.length) { /* We got more data than was requested */
dev_dbg(ep->dev->dev, "Overflow for ep %s\n",
ep->ep.name);
gr_dbgprint_request("OVFL", ep, req);
req->req.status = -EOVERFLOW;
}
}
if (!status) { if (ep->is_in)
gr_dbgprint_request("SENT", ep, req); else
gr_dbgprint_request("RECV", ep, req);
}
/* Prevent changes to ep->queue during callback */
ep->callback = 1; if (req == dev->ep0reqo && !status) { if (req->setup)
gr_ep0_setup(dev, req); else
dev_err(dev->dev, "Unexpected non setup packet on ep0in\n");
} elseif (req->req.complete) {
spin_unlock(&dev->lock);
/* Must be called with dev->lock held */ staticint gr_queue(struct gr_ep *ep, struct gr_request *req, gfp_t gfp_flags)
{ struct gr_udc *dev = ep->dev; int ret;
if (unlikely(!ep->ep.desc && ep->num != 0)) {
dev_err(dev->dev, "No ep descriptor for %s\n", ep->ep.name); return -EINVAL;
}
if (unlikely(!req->req.buf || !list_empty(&req->queue))) {
dev_err(dev->dev, "Invalid request for %s: buf=%p list_empty=%d\n",
ep->ep.name, req->req.buf, list_empty(&req->queue)); return -EINVAL;
}
/* Can't touch registers when suspended */ if (dev->ep0state == GR_EP0_SUSPEND) {
dev_err(dev->dev, "-EBUSY"); return -EBUSY;
}
/* Set up DMA mapping in case the caller didn't */
ret = usb_gadget_map_request(&dev->gadget, &req->req, ep->is_in); if (ret) {
dev_err(dev->dev, "usb_gadget_map_request"); return ret;
}
if (ep->is_in)
ret = gr_setup_in_desc_list(ep, req, gfp_flags); else
ret = gr_setup_out_desc_list(ep, req, gfp_flags); if (ret) return ret;
/* *Halts,haltsandwedges,orclearshaltforanendpoint. * *Mustbecalledwithdev->lockheld.
*/ staticint gr_ep_halt_wedge(struct gr_ep *ep, int halt, int wedge, int fromhost)
{
u32 epctrl; int retval = 0;
if (ep->num && !ep->ep.desc) return -EINVAL;
if (ep->num && ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) return -EOPNOTSUPP;
/* Never actually halt ep0, and therefore never clear halt for ep0 */ if (!ep->num) { if (halt && !fromhost) { /* ep0 halt from gadget - generate protocol stall */
gr_control_stall(ep->dev);
dev_dbg(ep->dev->dev, "EP: stall ep0\n"); return0;
} return -EINVAL;
}
epctrl = gr_read32(&ep->regs->epctrl); if (halt) { /* Set HALT */
gr_write32(&ep->regs->epctrl, epctrl | GR_EPCTRL_EH);
ep->stopped = 1; if (wedge)
ep->wedged = 1;
} else {
gr_write32(&ep->regs->epctrl, epctrl & ~GR_EPCTRL_EH);
ep->stopped = 0;
ep->wedged = 0;
/* Things might have been queued up in the meantime */ if (!ep->dma_start)
gr_start_dma(ep);
}
return retval;
}
/* Must be called with dev->lock held */ staticinlinevoid gr_set_ep0state(struct gr_udc *dev, enum gr_ep0state value)
{ if (dev->ep0state != value)
dev_vdbg(dev->dev, "STATE: ep0state=%s\n",
gr_ep0state_string(value));
dev->ep0state = value;
}
/* *Shouldonlybecalledwhenendpointscannotgenerateinterrupts. * *Mustbecalledwithdev->lockheld.
*/ staticvoid gr_disable_interrupts_and_pullup(struct gr_udc *dev)
{
gr_write32(&dev->regs->control, 0);
wmb(); /* Make sure that we do not deny one of our interrupts */
dev->irq_enabled = 0;
}
case USB_REQ_SET_FEATURE: switch (value) { case USB_DEVICE_REMOTE_WAKEUP: /* Allow remote wakeup */
dev->remote_wakeup = 1; return gr_ep0_respond_empty(dev);
case USB_DEVICE_TEST_MODE: /* The hardware does not support USB_TEST_FORCE_ENABLE */
test = index >> 8; if (test >= USB_TEST_J && test <= USB_TEST_PACKET) {
dev->test_mode = test; return gr_ep0_respond(dev, NULL, 0,
gr_ep0_testmode_complete);
}
} break;
case USB_REQ_CLEAR_FEATURE: switch (value) { case USB_DEVICE_REMOTE_WAKEUP: /* Disallow remote wakeup */
dev->remote_wakeup = 0; return gr_ep0_respond_empty(dev);
} break;
}
case USB_REQ_SET_FEATURE: switch (value) { case USB_ENDPOINT_HALT:
status = gr_ep_halt_wedge(ep, 1, 0, 1); if (status >= 0)
status = gr_ep0_respond_empty(dev); return status;
} break;
case USB_REQ_CLEAR_FEATURE: switch (value) { case USB_ENDPOINT_HALT: if (ep->wedged) return -1;
status = gr_ep_halt_wedge(ep, 0, 0, 1); if (status >= 0)
status = gr_ep0_respond_empty(dev); return status;
} break;
}
return1; /* Delegate the rest */
}
/* Must be called with dev->lock held */ staticvoid gr_ep0out_requeue(struct gr_udc *dev)
{ int ret = gr_queue_int(&dev->epo[0], dev->ep0reqo, GFP_ATOMIC);
if (ret)
dev_err(dev->dev, "Could not queue ep0out setup request: %d\n",
ret);
}
/* Restore from ep0 halt */ if (dev->ep0state == GR_EP0_STALL) {
gr_set_ep0state(dev, GR_EP0_SETUP); if (!req->req.actual) goto out;
}
if (dev->ep0state == GR_EP0_ISTATUS) {
gr_set_ep0state(dev, GR_EP0_SETUP); if (req->req.actual > 0)
dev_dbg(dev->dev, "Unexpected setup packet at state %s\n",
gr_ep0state_string(GR_EP0_ISTATUS)); else goto out; /* Got expected ZLP */
} elseif (dev->ep0state != GR_EP0_SETUP) {
dev_info(dev->dev, "Unexpected ep0out request at state %s - stalling\n",
gr_ep0state_string(dev->ep0state));
gr_control_stall(dev);
gr_set_ep0state(dev, GR_EP0_SETUP); goto out;
} elseif (!req->req.actual) {
dev_dbg(dev->dev, "Unexpected ZLP at state %s\n",
gr_ep0state_string(dev->ep0state)); goto out;
}
/* Handle SETUP packet */ for (i = 0; i < req->req.actual; i++)
u.raw[i] = ((u8 *)req->req.buf)[i];
type = u.ctrl.bRequestType;
request = u.ctrl.bRequest;
value = le16_to_cpu(u.ctrl.wValue);
index = le16_to_cpu(u.ctrl.wIndex);
length = le16_to_cpu(u.ctrl.wLength);
/* Turn on full interrupts and pullup */
control = (GR_CONTROL_SI | GR_CONTROL_UI | GR_CONTROL_VI |
GR_CONTROL_SP | GR_CONTROL_EP);
gr_write32(&dev->regs->control, control);
}
/* Must be called with dev->lock held */ staticvoid gr_enable_vbus_detect(struct gr_udc *dev)
{
u32 status;
dev->irq_enabled = 1;
wmb(); /* Make sure we do not ignore an interrupt */
gr_write32(&dev->regs->control, GR_CONTROL_VI);
/* Take care of the case we are already plugged in at this point */
status = gr_read32(&dev->regs->status); if (status & GR_STATUS_VB)
gr_vbus_connected(dev, status);
}
/* Must be called with dev->lock held and irqs disabled */ staticvoid gr_vbus_disconnected(struct gr_udc *dev)
{
gr_stop_activity(dev);
/* Report disconnect */ if (dev->driver && dev->driver->disconnect) {
spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
spin_lock(&dev->lock);
}
gr_enable_vbus_detect(dev);
}
/* Must be called with dev->lock held and irqs disabled */ staticvoid gr_udc_usbreset(struct gr_udc *dev, u32 status)
{
gr_set_address(dev, 0);
gr_set_ep0state(dev, GR_EP0_SETUP);
usb_gadget_set_state(&dev->gadget, USB_STATE_DEFAULT);
dev->gadget.speed = GR_SPEED(status);
gr_dma_advance(ep, 0);
} else { /* Not done yet. Enable the next descriptor to receive more. */
req->curr_desc = req->curr_desc->next_desc;
req->curr_desc->ctrl |= GR_DESC_OUT_CTRL_EN;
/* *CheckINepinterrupts.WecheckthesebeforetheOUTepsbecause *somegadgetsreusetherequestthatmightalreadybecurrently *outstandingandneedstobecompleted(mainlysetuprequests).
*/ for (i = 0; i < dev->nepi; i++) {
ep = &dev->epi[i]; if (!ep->stopped && !ep->callback && !list_empty(&ep->queue))
handled = gr_handle_in_ep(ep) || handled;
}
/* Check OUT ep interrupts */ for (i = 0; i < dev->nepo; i++) {
ep = &dev->epo[i]; if (!ep->stopped && !ep->callback && !list_empty(&ep->queue))
handled = gr_handle_out_ep(ep) || handled;
}
/* Check status interrupts */
handled = gr_handle_state_changes(dev) || handled;
/* *CheckAMBADMAerrors.Onlycheckifwedidn'tfindanythingelseto *handlebecausethisshouldn'thappenifwedideverythingright.
*/ if (!handled) {
list_for_each_entry(ep, &dev->ep_list, ep_list) { if (gr_read32(&ep->regs->dmactrl) & GR_DMACTRL_AE) {
dev_err(dev->dev, "AMBA Error occurred for %s\n",
ep->ep.name);
handled = 1;
}
}
}
if (ep->is_in)
gr_dbgprint_request("EXTERN", ep, req);
ret = gr_queue(ep, req, GFP_ATOMIC);
spin_unlock(&ep->dev->lock);
return ret;
}
/* Dequeue JUST ONE request */ staticint gr_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{ struct gr_request *req = NULL, *iter; struct gr_ep *ep; struct gr_udc *dev; int ret = 0; unsignedlong flags;
ep = container_of(_ep, struct gr_ep, ep); if (!_ep || !_req || (!ep->ep.desc && ep->num != 0)) return -EINVAL;
dev = ep->dev; if (!dev->driver) return -ESHUTDOWN;
/* We can't touch (DMA) registers when suspended */ if (dev->ep0state == GR_EP0_SUSPEND) return -EBUSY;
spin_lock_irqsave(&dev->lock, flags);
/* Make sure it's actually queued on this endpoint */
list_for_each_entry(iter, &ep->queue, queue) { if (&iter->req != _req) continue;
req = iter; break;
} if (!req) {
ret = -EINVAL; goto out;
}
if (list_first_entry(&ep->queue, struct gr_request, queue) == req) { /* This request is currently being processed */
gr_abort_dma(ep); if (ep->stopped)
gr_finish_request(ep, req, -ECONNRESET); else
gr_dma_advance(ep, -ECONNRESET);
} elseif (!list_empty(&req->queue)) { /* Not being processed - gr_finish_request dequeues it */
gr_finish_request(ep, req, -ECONNRESET);
} else {
ret = -EOPNOTSUPP;
}
out:
spin_unlock_irqrestore(&dev->lock, flags);
return ret;
}
/* Helper for gr_set_halt and gr_set_wedge */ staticint gr_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
{ int ret; struct gr_ep *ep;
if (!_ep) return -ENODEV;
ep = container_of(_ep, struct gr_ep, ep);
spin_lock(&ep->dev->lock);
/* Halting an IN endpoint should fail if queue is not empty */ if (halt && ep->is_in && !list_empty(&ep->queue)) {
ret = -EAGAIN; goto out;
}
ret = gr_ep_halt_wedge(ep, halt, wedge, 0);
out:
spin_unlock(&ep->dev->lock);
return ret;
}
/* Halt endpoint */ staticint gr_set_halt(struct usb_ep *_ep, int halt)
{ return gr_set_halt_wedge(_ep, halt, 0);
}
/* Halt and wedge endpoint */ staticint gr_set_wedge(struct usb_ep *_ep)
{ return gr_set_halt_wedge(_ep, 1, 1);
}
if (!_gadget) return -ENODEV;
dev = container_of(_gadget, struct gr_udc, gadget);
spin_lock(&dev->lock);
control = gr_read32(&dev->regs->control); if (is_on)
control |= GR_CONTROL_EP; else
control &= ~GR_CONTROL_EP;
gr_write32(&dev->regs->control, control);
/* Must be called with dev->lock held */ staticint gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit)
{ struct gr_ep *ep; struct gr_request *req; struct usb_request *_req; void *buf;
if (is_in) {
ep = &dev->epi[num];
ep->ep.name = inames[num];
ep->regs = &dev->regs->epi[num];
} else {
ep = &dev->epo[num];
ep->ep.name = onames[num];
ep->regs = &dev->regs->epo[num];
}
if (is_in)
ep->ep.caps.dir_in = true; else
ep->ep.caps.dir_out = true;
ep->tailbuf = dma_alloc_coherent(dev->dev, ep->ep.maxpacket_limit,
&ep->tailbuf_paddr, GFP_ATOMIC); if (!ep->tailbuf) return -ENOMEM;
return0;
}
/* Must be called with dev->lock held */ staticint gr_udc_init(struct gr_udc *dev)
{ struct device_node *np = dev->dev->of_node;
u32 epctrl_val;
u32 dmactrl_val; int i; int ret = 0;
u32 bufsize;
for (i = 0; i < dev->nepo; i++) { if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize))
bufsize = 1024;
ret = gr_ep_init(dev, i, 0, bufsize); if (ret) return ret;
}
for (i = 0; i < dev->nepi; i++) { if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize))
bufsize = 1024;
ret = gr_ep_init(dev, i, 1, bufsize); if (ret) return ret;
}
/* Must be disabled by default */
dev->remote_wakeup = 0;
if (dev->added)
usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ if (dev->driver) {
dev_err(&pdev->dev, "Driver still in use but removing anyhow\n"); return;
}
for (i = 0; i < dev->nepo; i++)
gr_ep_remove(dev, i, 0); for (i = 0; i < dev->nepi; i++)
gr_ep_remove(dev, i, 1);
} staticint gr_request_irq(struct gr_udc *dev, int irq)
{ return devm_request_threaded_irq(dev->dev, irq, gr_irq, gr_irq_handler,
IRQF_SHARED, driver_name, dev);
}
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM;
dev->dev = &pdev->dev;
regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs);
dev->irq = platform_get_irq(pdev, 0); if (dev->irq < 0) return dev->irq;
/* Some core configurations has separate irqs for IN and OUT events */
dev->irqi = platform_get_irq(pdev, 1); if (dev->irqi > 0) {
dev->irqo = platform_get_irq(pdev, 2); if (dev->irqo < 0) return dev->irqo;
} else {
dev->irqi = 0;
}
/* Determine number of endpoints and data interface mode */
status = gr_read32(&dev->regs->status);
dev->nepi = ((status & GR_STATUS_NEPI_MASK) >> GR_STATUS_NEPI_POS) + 1;
dev->nepo = ((status & GR_STATUS_NEPO_MASK) >> GR_STATUS_NEPO_POS) + 1;
if (!(status & GR_STATUS_DM)) {
dev_err(dev->dev, "Slave mode cores are not supported\n"); return -ENODEV;
}
/* --- Effects of the following calls might need explicit cleanup --- */
/* Create DMA pool for descriptors */
dev->desc_pool = dma_pool_create("desc_pool", dev->dev, sizeof(struct gr_dma_desc), 4, 0); if (!dev->desc_pool) {
dev_err(dev->dev, "Could not allocate DMA pool"); return -ENOMEM;
}
/* Inside lock so that no gadget can use this udc until probe is done */
retval = usb_add_gadget_udc(dev->dev, &dev->gadget); if (retval) {
dev_err(dev->dev, "Could not add gadget udc"); goto out;
}
dev->added = 1;
spin_lock(&dev->lock);
retval = gr_udc_init(dev); if (retval) {
spin_unlock(&dev->lock); goto out;
}
/* Clear all interrupt enables that might be left on since last boot */
gr_disable_interrupts_and_pullup(dev);
spin_unlock(&dev->lock);
gr_dfs_create(dev);
retval = gr_request_irq(dev, dev->irq); if (retval) {
dev_err(dev->dev, "Failed to request irq %d\n", dev->irq); goto out;
}
if (dev->irqi) {
retval = gr_request_irq(dev, dev->irqi); if (retval) {
dev_err(dev->dev, "Failed to request irqi %d\n",
dev->irqi); goto out;
}
retval = gr_request_irq(dev, dev->irqo); if (retval) {
dev_err(dev->dev, "Failed to request irqo %d\n",
dev->irqo); goto out;
}
}
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.