📄 superh_udc.c
字号:
} ep->desc = desc; ep->dma = -1; ep->stopped = 0; /* flush fifo (mostly for OUT buffers), enable irq */ superh_ep_fifo_flush (_ep); /* ... reset halt state too, if we could ... */#ifdef USE_DMA#endif DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); return 0;}static int superh_ep_disable (struct usb_ep *_ep){ struct superh_ep *ep; DBG(DBG_NOISY, "superh_ep_disable\n"); ep = container_of (_ep, struct superh_ep, ep); if (!_ep || !ep->desc) { DMSG("%s, %s not enabled\n", __FUNCTION__, _ep ? ep->ep.name : NULL); return -EINVAL; } nuke (ep, -ESHUTDOWN);#ifdef USE_DMA /* TODO */ if (ep->dma >= 0) { *ep->reg_drcmr = 0; pxa_free_dma (ep->dma); ep->dma = -1; }#endif /* flush fifo (mostly for IN buffers) */ superh_ep_fifo_flush (_ep); ep->desc = 0; ep->stopped = 1; DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); return 0;}/* for the superh, these can just wrap kmalloc/kfree. gadget drivers * must still pass correctly initialized endpoints, since other controller * drivers may care about how it's currently set up (dma issues etc). *//* * superh_ep_alloc_request - allocate a request data structure */static struct usb_request *superh_ep_alloc_request (struct usb_ep *_ep, int gfp_flags){ struct superh_request *req; /* FIXME for bulk out-dma endpoints, preallocate a frame's worth of * (aligned) dma descriptors at the end of the request */ req = kmalloc (sizeof *req, gfp_flags); if (!req) return 0; memset (req, 0, sizeof *req); INIT_LIST_HEAD (&req->queue); DBG(DBG_VERY_NOISY, "superh_ep_alloc_request: %p %d\n", req, list_empty(&req->queue)); return &req->req;}/* * superh_ep_free_request - deallocate a request data structure */static voidsuperh_ep_free_request (struct usb_ep *_ep, struct usb_request *_req){ struct superh_request *req; req = container_of (_req, struct superh_request, req); WARN_ON (!list_empty (&req->queue)); kfree(req);}/* SH cache needs flushing with DMA I/O (it's dma-incoherent), but there's * no device-affinity and the heap works perfectly well for i/o buffers. * TODO: check this */static void *superh_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes, dma_addr_t *dma, int gfp_flags){ char *retval; retval = kmalloc (bytes, gfp_flags); if (retval) *dma = virt_to_bus (retval); return retval;}static voidsuperh_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes){ kfree (buf);}static struct superh_request*process_ep_req(struct superh_ep *ep, struct superh_request *req){ struct superh_udc *dev = ep->dev; if (ep->desc == 0 /* ep0 */) { switch (dev->ep0state) { case EP0_IN_DATA_PHASE: DBG(DBG_VERY_NOISY, "superh_ep_queue: EP0_IN_DATA_PHASE\n"); dev->stats.write.ops++; if (write_ep0_fifo(ep, req)) req = 0; break; case EP0_OUT_DATA_PHASE: DBG(DBG_VERY_NOISY, "superh_ep_queue: EP0_OUT_DATA_PHASE\n"); dev->stats.read.ops++; if (read_ep0_fifo(ep, req)) req = 0; break; default: DMSG("ep0 i/o, odd state %d\n", dev->ep0state); return 0; }#ifdef USE_DMA /* either start dma or prime pio pump */ } else if (ep->dma >= 0) { kick_dma(ep, req);#endif /* can the FIFO can satisfy the request immediately? */ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { if ((ep->desc->bEndpointAddress & 0x0f) == 2 && (ctrl_inb(USBIFR0) & EP2_TR) != 0 && write_fifo(ep, req)) { req = 0; } else if ((ep->desc->bEndpointAddress & 0x0f) == 3 && (ctrl_inb(USBIFR1) & EP3_TR) != 0 && write_fifo(ep, req)) { req = 0; } } if (likely (((req && ep->desc) && ep->dma < 0) || ep->desc == 0)) pio_irq_enable(ep); return req;} static intsuperh_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags){ struct superh_request *req; struct superh_ep *ep; struct superh_udc *dev; unsigned long flags; req = container_of(_req, struct superh_request, req); ep = container_of(_ep, struct superh_ep, ep); DBG(DBG_VERY_NOISY, "superh_ep_queue\n"); /* If we have just sent a fake configuration request then * this is the reply. We don't want to send it to the host * so just ignore it. */ if (ep->desc == 0 /* ep0 */ && ep->dev->fake_config) { DBG(DBG_NOISY, "Ignoring bogus SET_CONFIGURATION response\n"); done(ep, req, 0); ep->dev->fake_config = 0; return 1; } if (unlikely (!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { DMSG("%s, bad params %s, %p, %p, %p, %d\n", __FUNCTION__, ep->ep.name, _req, _req->complete, _req->buf, list_empty(&req->queue)); return -EINVAL; } if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { DMSG("%s, bad ep\n", __FUNCTION__); return -EINVAL; } dev = ep->dev; if (unlikely (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { DMSG("%s, bogus device state\n", __FUNCTION__); return -ESHUTDOWN; }#ifdef USE_DMA /* TODO */ if (ep->dma >= 0) { unsigned long start = (unsigned long) _req->buf; clean_dcache_range(start, start + _req->length); /* or for USB_DIR_OUT, invalidate_dcache_range (...) */ }#endif DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, _req->buf); local_irq_save(flags); _req->status = -EINPROGRESS; _req->actual = 0; /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped && !ep->halted) { req = process_ep_req(ep, req); } /* pio or dma irq handler advances the queue. */ if (likely (req != 0)) list_add_tail(&req->queue, &ep->queue); local_irq_restore(flags); return 0;}static intsuperh_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req){ struct superh_ep *ep; struct superh_request *req; unsigned long flags; DBG(DBG_NOISY, "superh_ep_dequeue %s\n", _ep->name); ep = container_of(_ep, struct superh_ep, ep); req = container_of(_req, struct superh_request, req); if (!_ep || !_req || ep->ep.name == ep0name) return -EINVAL; local_irq_save(flags);#ifdef USE_DMA if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) { cancel_dma(ep); done(ep, req, -ECONNRESET); /* restart i/o */ if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct superh_request, queue); kick_dma(ep, req); } } else#endif if (!list_empty(&req->queue)) done(ep, req, -ECONNRESET); else req = 0; local_irq_restore(flags); return req ? 0 : -EOPNOTSUPP;}/* stall/unstall an endpoint, 0 clears the stall, 1 sets it */static intsuperh_ep_set_halt(struct usb_ep *_ep, int value){ struct superh_ep *ep; unsigned long flags; ep = container_of(_ep, struct superh_ep, ep); if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name)) || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { DMSG("%s, bad ep\n", __FUNCTION__); return -EINVAL; } if (ep->halted == value) return 0; local_irq_save(flags); if (value == 1 && (ep->bEndpointAddress & USB_DIR_IN) != 0 && ((ctrl_inb(USBDASTS) & ep->data_present_mask) != 0 || !list_empty(&ep->queue))) { local_irq_restore(flags); DBG(DBG_VERBOSE, "Can't %s on %s\n", value ? " halt" : "clear halt", _ep->name); return -EAGAIN; } if (value) { or_b(ep->stall_mask, USBEPSTL); if (!ep->desc) { ep->dev->ep0state = EP0_STALL; } /* disable ep interrupts and set a timer to clear the stall */ pio_irq_disable(ep); mod_timer(&ep->dev->timer, jiffies + STALL_TIME); } else { and_b(~ep->stall_mask, USBEPSTL); } ep->halted = value; local_irq_restore(flags); DBG(DBG_VERBOSE, "%s %s\n", _ep->name, value ? " halt" : "clear halt"); return 0;}static int superh_ep_fifo_status(struct usb_ep *_ep){ struct superh_ep *ep; DBG(DBG_NOISY, "superh_ep_fifo_status\n"); ep = container_of(_ep, struct superh_ep, ep); if (!_ep) { DMSG("%s, bad ep\n", __FUNCTION__); return -ENODEV; } if ((ep->bEndpointAddress & USB_DIR_IN) != 0) return -EOPNOTSUPP; if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return 0; else { switch (ep->desc->bEndpointAddress & 0x0f) { case 0: return ctrl_inb(USBEPSZ0O); case 1: return ctrl_inb(USBEPSZ1); } } return 0;}static void superh_ep_fifo_flush(struct usb_ep *_ep){ struct superh_ep *ep; DBG(DBG_NOISY, "superh_ep_fifo_flush\n"); ep = container_of(_ep, struct superh_ep, ep); if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { DMSG("%s, bad ep\n", __FUNCTION__); return; } or_b(ep->clear_mask, USBFCLR);}static struct usb_ep_ops superh_ep_ops = { .enable = superh_ep_enable, .disable = superh_ep_disable, .alloc_request = superh_ep_alloc_request, .free_request = superh_ep_free_request, .alloc_buffer = superh_ep_alloc_buffer, .free_buffer = superh_ep_free_buffer, .queue = superh_ep_queue, .dequeue = superh_ep_dequeue, .set_halt = superh_ep_set_halt, .fifo_status = superh_ep_fifo_status, .fifo_flush = superh_ep_fifo_flush,};/* --------------------------------------------------------------------------- * device-scoped parts of the api to the usb controller hardware * --------------------------------------------------------------------------- */static int superh_udc_get_frame(struct usb_gadget *_gadget){ DBG(DBG_VERY_NOISY, "superh_udc_get_frame\n"); return -EOPNOTSUPP;}static const struct usb_gadget_ops superh_udc_ops = { .get_frame = superh_udc_get_frame, // no remote wakeup // always selfpowered};/* if we're trying to save space, don't bother with this proc file */#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)# define UDC_PROC_FILE#endif#ifdef UDC_PROC_FILEstatic const char proc_node_name [] = "driver/udc";static intudc_proc_read(char *page, char **start, off_t off, int count, int *eof, void *_dev){ char *buf = page; struct superh_udc *dev = _dev; char *next = buf; unsigned size = count; unsigned long flags; int t; int i; local_irq_save(flags); /* basic device status */ t = snprintf(next, size, "%s\n%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_desc, driver_name, DRIVER_VERSION, dev->driver ? dev->driver->driver.name : "(none)", is_usb_connected ? "full speed" : "disconnected"); size -= t; next += t; /* device registers */ t = snprintf(next, size, "ifr0 %02X, ifr1 %02X, isr0 %02X, isr1 %02X, ier0 %02X, ier1 %02X\n", ctrl_inb(USBIFR0), ctrl_inb(USBIFR1), ctrl_inb(USBISR0), ctrl_inb(USBISR1), ctrl_inb(USBIER0), ctrl_inb(USBIER1)); size -= t; next += t; t = snprintf(next, size, "epsz0o %02X, epsz1 %02X, dasts %02X, dmar %02X\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -