📄 jz4730_udc.c
字号:
if (write_fifo(ep, req) == 1) req = 0; } } pio_irq_enable(ep); } else { /* EP5 ~ EP7 */ pio_irq_enable(ep); if (ep->irq_pending || (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) { u32 stats, count; stats = REG_UDC_EP5OutSR; if (stats & UDC_EPSR_OUT_RCVDATA) { ep->irq_pending = 0; REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5) REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; count = OUT_COUNT(stats); if (read_fifo(ep, req, count) == 1) req = 0; } } } } /* pio or dma irq handler advances the queue. */ if (likely(req != 0)) { list_add_tail(&req->queue, &ep->queue); } spin_unlock_irqrestore(&dev->lock, flags); return status;}/* dequeue ALL requests */static void nuke(struct jz4730_ep *ep, int status){ struct jz4730_request *req; if (list_empty(&ep->queue)) return; while (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct jz4730_request, queue); done(ep, req, status); }}/* dequeue JUST ONE request */static int jz4730_dequeue(struct usb_ep *_ep, struct usb_request *_req){ struct jz4730_request *req; struct jz4730_ep *ep; struct jz4730_udc *dev; unsigned long flags; int stopped; ep = container_of(_ep, struct jz4730_ep, ep); if (!_ep || !_req || (!ep->desc && ep->index != 0)) return -EINVAL; dev = ep->dev; if (!dev->driver) return -ESHUTDOWN; DEBUG("%s %s %p\n", __FUNCTION__, _ep->name,_req); spin_lock_irqsave(&dev->lock, flags); stopped = ep->stopped; ep->stopped = 1; /* make sure it's actually queued on this endpoint */ list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) break; } if (&req->req != _req) { spin_unlock_irqrestore (&dev->lock, flags); return -EINVAL; } /* queue head may be partially complete. */ if (ep->queue.next == &req->queue) { done (ep, req, -ECONNRESET); req = 0; } if (req) done (ep, req, -ECONNRESET); ep->stopped = stopped; spin_unlock_irqrestore (&ep->dev->lock, flags); return req ? 0 : -EOPNOTSUPP;}/*-------------------------------------------------------------------------*/static void jz4730_clear_halt(struct jz4730_ep *ep){ if (ep->stopped) { ep->stopped = 0; }}static int jz4730_set_halt(struct usb_ep *_ep, int value){ struct jz4730_ep *ep; unsigned long flags; int retval = 0; if (!_ep) return -ENODEV; ep = container_of (_ep, struct jz4730_ep, ep); if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC) return -EINVAL; if (ep->index == 0) { if (value) { ep->dev->ep0state = EP0_STALL; ep->dev->ep[0].stopped = 1; } else return -EINVAL; /* don't change EPxSTATUS_EP_INVALID to READY */ } else if (!ep->desc) { DEBUG("%s %s inactive?\n", __FUNCTION__, ep->ep.name); return -EINVAL; } spin_lock_irqsave(&ep->dev->lock, flags); if (!list_empty(&ep->queue)) retval = -EAGAIN; else if (!value) jz4730_clear_halt(ep); else { ep->stopped = 1; } spin_unlock_irqrestore(&ep->dev->lock, flags); return retval;}static int jz4730_fifo_status(struct usb_ep *_ep){ struct jz4730_ep *ep; u32 size = 0; if (!_ep) return -ENODEV; ep = container_of(_ep, struct jz4730_ep, ep); /* size is only reported sanely for OUT */ if (ep->is_in) return -EOPNOTSUPP; return size;}static void jz4730_fifo_flush(struct usb_ep *_ep){ struct jz4730_ep *ep; if (!_ep) return; ep = container_of(_ep, struct jz4730_ep, ep); /* don't change EPxSTATUS_EP_INVALID to READY */ if (!ep->desc && ep->index != 0) { return; }}static struct usb_ep_ops jz4730_ep_ops = { .enable = jz4730_ep_enable, .disable = jz4730_ep_disable, .alloc_request = jz4730_alloc_request, .free_request = jz4730_free_request,#if 0 .alloc_buffer = jz4730_alloc_buffer, .free_buffer = jz4730_free_buffer,#endif .queue = jz4730_queue, .dequeue = jz4730_dequeue, .set_halt = jz4730_set_halt, .fifo_status = jz4730_fifo_status, .fifo_flush = jz4730_fifo_flush,};/*-------------------------------------------------------------------------*/static int jz4730_get_frame(struct usb_gadget *_gadget){ return -EOPNOTSUPP;}static const struct usb_gadget_ops jz4730_ops = { .get_frame = jz4730_get_frame, // no remote wakeup // not selfpowered};/*-------------------------------------------------------------------------*/static void udc_reinit(struct jz4730_udc *dev){ static char *names [] = { "ep0", "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-iso", "ep5out-bulk", "ep6out-bulk", "ep7out-iso" }; int i; INIT_LIST_HEAD (&dev->gadget.ep_list); dev->gadget.ep0 = &dev->ep[0].ep; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->ep0state = EP0_DISCONNECT; for (i = 0; i < MAX_EP_NUM; i++) { struct jz4730_ep *ep = &dev->ep[i]; ep->index = i; ep->ep.name = names[i]; ep->fifo = ep_fifo[i]; ep->ep.maxpacket = 64; ep->ep.ops = &jz4730_ep_ops; list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; INIT_LIST_HEAD(&ep->queue); ep->desc = 0; ep->stopped = 1; ep->irq_pending = 0; } dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; list_del_init(&dev->ep[0].ep.ep_list);}/* Reset udc registers */static void udc_reset(struct jz4730_udc *dev){ REG_UDC_DevIntMR = 0x32; /* Enable RESET and SC interrupts */ REG_UDC_EPIntMR = 0x0; /* Enable all EP interrupts */ REG_UDC_DevCFGR = 0x17; REG_UDC_DevCR = 0x0; REG_UDC_EP0InCR = (0 << 4) | (1 << 1); REG_UDC_EP0InCR = (0 << 4); REG_UDC_EP1InCR = (3 << 4) | (1 << 1); REG_UDC_EP1InCR = (3 << 4); REG_UDC_EP2InCR = (2 << 4) | (1 << 1); REG_UDC_EP2InCR = (2 << 4); REG_UDC_EP3InCR = (2 << 4) | (1 << 1); REG_UDC_EP3InCR = (2 << 4); REG_UDC_EP4InCR = (1 << 4) | (1 << 1); REG_UDC_EP4InCR = (1 << 4); REG_UDC_EP0OutCR = (0 << 4); REG_UDC_EP5OutCR = (2 << 4); REG_UDC_EP6OutCR = (2 << 4); REG_UDC_EP7OutCR = (1 << 4); REG_UDC_EP0InSR = 0; REG_UDC_EP1InSR = 0; REG_UDC_EP2InSR = 0; REG_UDC_EP3InSR = 0; REG_UDC_EP4InSR = 0; REG_UDC_EP5OutSR = 0; REG_UDC_EP6OutSR = 0; REG_UDC_EP7OutSR = 0; REG_UDC_EP0InBSR = MAX_EP0_SIZE/4; REG_UDC_EP1InBSR = MAX_EP1_SIZE/4; REG_UDC_EP2InBSR = MAX_EP2_SIZE/4; REG_UDC_EP3InBSR = MAX_EP3_SIZE/4; REG_UDC_EP4InBSR = MAX_EP4_SIZE/4; REG_UDC_EP0InMPSR = MAX_EP0_SIZE; REG_UDC_EP1InMPSR = MAX_EP1_SIZE; REG_UDC_EP2InMPSR = MAX_EP2_SIZE; REG_UDC_EP3InMPSR = MAX_EP3_SIZE; REG_UDC_EP4InMPSR = MAX_EP4_SIZE; REG_UDC_EP0OutMPSR = MAX_EP0_SIZE; REG_UDC_EP5OutMPSR = MAX_EP5_SIZE; REG_UDC_EP6OutMPSR = MAX_EP6_SIZE; REG_UDC_EP7OutMPSR = MAX_EP7_SIZE; REG_UDC_EP0InfR = (MAX_EP0_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (0 << 5) | (0 << 4) | (0 << 0); REG_UDC_EP1InfR = (MAX_EP1_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (3 << 5) | (1 << 4) | (1 << 0); REG_UDC_EP2InfR = (MAX_EP2_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (2 << 0); REG_UDC_EP3InfR = (MAX_EP3_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (3 << 0); REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0); REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0); REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0); REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0); REG_UDC_STCMAR = 0xffff;}static void ep0_start(struct jz4730_udc *dev){ udc_reset(dev); udc_reinit(dev); /* expect ep0 requests when the host drops reset */ dev->gadget.speed = USB_SPEED_FULL; dev->ep0state = EP0_IDLE;}static void udc_enable(struct jz4730_udc *dev){ /* Enable udc and enable all interrupts */ __intc_unmask_irq(IRQ_UDC); __harb_usb0_udc(); /* start enumeration now, or after power detect irq */ ep0_start(dev);}/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second */static struct jz4730_udc *the_controller;/* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests. then usb traffic follows until a * disconnect is reported. then a host may connect again, or * the driver might get unbound. */int usb_gadget_register_driver(struct usb_gadget_driver *driver){ struct jz4730_udc *dev = the_controller; int retval; if (!driver// || driver->speed != USB_SPEED_FULL || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup) { printk("\n -EINVAL"); return -EINVAL; } if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* hook up the driver */ dev->driver = driver; retval = driver->bind(&dev->gadget); if (retval) { DEBUG("bind to driver %s --> error %d\n", driver->driver.name, retval); dev->driver = 0; return retval; } /* then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ udc_enable(dev); DEBUG("registered gadget driver '%s'\n", driver->driver.name); return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);static voidstop_activity(struct jz4730_udc *dev, struct usb_gadget_driver *driver){ unsigned i; DEBUG("%s\n", __FUNCTION__); if (dev->gadget.speed == USB_SPEED_UNKNOWN) driver = 0; /* disconnect gadget driver after quiesceing hw and the driver */ udc_reset (dev); for (i = 0; i < MAX_EP_NUM; i++) nuke(&dev->ep [i], -ESHUTDOWN); if (driver) { spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); spin_lock(&dev->lock); } if (dev->driver) udc_enable(dev);}int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){ struct jz4730_udc *dev = the_controller; unsigned long flags; /* disable UDC irq */ __intc_mask_irq(IRQ_UDC); __harb_usb0_uhc(); if (!dev) return -ENODEV; if (!driver || driver != dev->driver) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); dev->driver = 0; stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); DEBUG("unregistered driver '%s'\n", driver->driver.name); return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);static void jz4730_epn_out(struct jz4730_udc *dev, int ep_idx, u32 count){ struct jz4730_request *req; struct jz4730_ep *ep = &dev->ep[ep_idx]; req = list_entry(ep->queue.next, struct jz4730_request, queue); read_fifo(ep, req, count);}static void jz4730_epn_in(struct jz4730_udc *dev, int ep_idx){ struct jz4730_request *req; struct jz4730_ep *ep = &dev->ep[ep_idx]; req = list_entry(ep->queue.next, struct jz4730_request, queue); write_fifo(ep, req);}/****************************************************************//* End Point 0 related functions *//****************************************************************//* return: 0 = still running, 1 = completed, negative = errno */static int write_fifo_ep0(struct jz4730_ep *ep, struct jz4730_request *req){ u32 max, count; int is_last; max = ep->ep.maxpacket; count = write_packet(ep, req, max); /* last packet is usually short (or a zlp) */ if (unlikely(count != max)) is_last = 1; else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -