/* * handle_epinirq() */ static int write_ep_fifo(struct rt_ep_struct *rt_ep, struct rt_request *req) { u8 *buf, epcs; int length, i, ep_no = EP_NO(rt_ep); DBG; xprintk("w ep%d req=%p,r.l=%d,r.a=%d\n",EP_NO(rt_ep),&req->req,req->req.length,req->req.actual); epcs = read_epcs(rt_ep); if(epcs & EP_CS_BSY) FATAL_ERROR("EP%d busy. epcs=%x\n", ep_no, epcs); /* check INEP byte count is zero? */ if(read_inbc(ep_no)) FATAL_ERROR("EP%d bc=%d\n", ep_no, read_inbc(ep_no)); buf = req->req.buf + req->req.actual; length = (req->req.length - req->req.actual) < rt_ep->ep.maxpacket ? (req->req.length - req->req.actual) : rt_ep->ep.maxpacket; req->req.actual += length; if (!length) { /* zlp */ // for debug xprintk("<%s> zero packet\n", __func__); write_ep_fifo_zlp(rt_ep); return 0; } // write to ep in fifo for (i=0; i< length; i++) usb_write(0x80+ep_no*4, *buf++); epcs = read_epcs(rt_ep); write_epcs(rt_ep, epcs); return length; }
static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) { int bytes = 0, count, completed = 0; while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) & FSTAT_FR) { count = read_packet(imx_ep, req); bytes += count; completed = (count != imx_ep->fifosize); if (completed || req->req.actual == req->req.length) { completed = 1; break; } } if (completed || !req->req.length) { done(imx_ep, req, 0); D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", __func__, imx_ep->ep.name, req, completed ? "completed" : "not completed"); if (!EP_NO(imx_ep)) ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); } D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes); return completed; }
void imx_flush(struct imx_ep_struct *imx_ep) { struct imx_udc_struct *imx_usb = imx_ep->imx_usb; int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); __raw_writel(temp | EPSTAT_FLUSH, imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); }
int imx_ep_empty(struct imx_ep_struct *imx_ep) { struct imx_udc_struct *imx_usb = imx_ep->imx_usb; return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) & FSTAT_EMPTY; }
unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep) { struct imx_udc_struct *imx_usb = imx_ep->imx_usb; return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_BCOUNT) >> 16; }
/* ******************************************************************************* * Data tansfer over USB functions ******************************************************************************* */ static int read_ep0_fifo(struct rt_ep_struct *rt_ep, struct rt_request *req) { u8 *buf; int byte_count, req_bufferspace, count, i; DBG; if(!in_irq()) FATAL_ERROR("not irq context."); byte_count = read_outbc(EP_NO(rt_ep)); req_bufferspace = req->req.length - req->req.actual; buf = req->req.buf + req->req.actual; if(!req_bufferspace) FATAL_ERROR("zlp"); if(byte_count > req_bufferspace) FATAL_ERROR("buffer overflow, byte_count=%d, req->req.length=%d, req->req.actual=%d\n", byte_count, req->req.length ,req->req.actual); count = min(byte_count, req_bufferspace); for (i = 0; i < count; i++){ *buf = usb_read(EP0OUTDAT+i); buf++; } req->req.actual += count; return count; }
static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) { int bytes = 0, count, completed = 0; while (!completed) { count = write_packet(imx_ep, req); if (count < 0) break; /* */ bytes += count; /* */ completed = (count != imx_ep->fifosize); if (unlikely(completed)) { done(imx_ep, req, 0); D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", __func__, imx_ep->ep.name, req, completed ? "completed" : "not completed"); if (!EP_NO(imx_ep)) ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); } } D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes); return completed; }
void imx_ep_irq_disable(struct imx_ep_struct *imx_ep) { int i = EP_NO(imx_ep); __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); }
static void write_epcs(struct rt_ep_struct *rt_ep, u8 val) { int idx = EP_NO(rt_ep); int dir = EP_DIR(rt_ep); if(idx == 0) usb_write(EP0CS, val); else (dir == EP_IN ? /*IN */ usb_write(0x7 + idx*8, val) : usb_write(0x3 + idx*8, val) ); }
static u8 read_epcs(struct rt_ep_struct *rt_ep) { int idx = EP_NO(rt_ep); int dir = EP_DIR(rt_ep); if(idx == 0) return usb_read(EP0CS); return (dir == EP_IN ? usb_read(0x7 + idx*8) : usb_read(0x3 + idx*8) ); }
static int write_ep_fifo_zlp(struct rt_ep_struct *rt_ep) { u8 epcs; int ep_no = EP_NO(rt_ep); DBG; xprintk("w%d ZLP\n", EP_NO(rt_ep)); epcs = read_epcs(rt_ep); if(epcs & EP_CS_BSY) FATAL_ERROR("EP%d busy. cs=%x\n", ep_no, epcs); /* check INEP byte count is zero? */ if(read_inbc(ep_no)) FATAL_ERROR("EP%d bc zero. bc=%d\n", ep_no, read_inbc(ep_no)); epcs = read_epcs(rt_ep); write_epcs(rt_ep, epcs); return 0; }
void imx_ep_irq_enable(struct imx_ep_struct *imx_ep) { int i = EP_NO(imx_ep); __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF), imx_ep->imx_usb->base + USB_EP_MASK(i)); }
static void rt_ep_rst(struct rt_ep_struct *rt_ep) { u8 reg = 0; u8 idx = EP_NO(rt_ep); u8 dir = EP_DIR(rt_ep); if(dir == EP_IN ) reg |= ENDPRST_IO | idx; usb_write(ENDPRST, reg); reg |= ENDPRST_TOGRST | ENDPRST_FIFORST; usb_write(ENDPRST, reg); }
void imx_ep_stall(struct imx_ep_struct *imx_ep) { struct imx_udc_struct *imx_usb = imx_ep->imx_usb; int temp, i; D_ERR(imx_usb->dev, "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); imx_flush(imx_ep); /* */ if (!EP_NO(imx_ep)) { temp = __raw_readl(imx_usb->base + USB_CTRL); __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, imx_usb->base + USB_CTRL); do { } while (__raw_readl(imx_usb->base + USB_CTRL) & CTRL_CMDOVER); temp = __raw_readl(imx_usb->base + USB_CTRL); __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL); } else { temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); __raw_writel(temp | EPSTAT_STALL, imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); for (i = 0; i < 100; i ++) { temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); if (!(temp & EPSTAT_STALL)) break; udelay(20); } if (i == 100) D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n", __func__, imx_ep->ep.name); } }
static void rt_ep_irq_disable(struct rt_ep_struct *rt_ep) { u8 reg; u8 idx = EP_NO(rt_ep); u8 dir = EP_DIR(rt_ep); if(idx == 0 /* ep0 */){ usb_write(IN07IEN, (usb_read(IN07IEN) & ~(0x1)) ); usb_write(OUT07IEN, (usb_read(OUT07IEN) & ~(0x1)) ); }else{ reg = usb_read(dir ? IN07IEN : OUT07IEN); reg = reg & ~(0x1 << idx); usb_write(dir == EP_IN ? IN07IEN : OUT07IEN, reg); reg = usb_read(dir ? IN07IEN : OUT07IEN); } }
void rt_ep_stall(struct rt_ep_struct *rt_ep) { u8 tmp; u32 addr; int idx = EP_NO(rt_ep); int dir = EP_DIR(rt_ep); if(idx == 0){ tmp = usb_read(EP0CS); tmp |= 0x1; usb_write(EP0CS, tmp); }else{ addr = (dir == EP_IN ? 0x006 : 0x002) + idx * 8; tmp = usb_read(addr); tmp |= 0x40; usb_write(addr, tmp); } return; }
static u32 rt_fifo_bcount(struct rt_ep_struct *rt_ep) { u8 low, high; u32 rc; int idx = EP_NO(rt_ep); int dir = EP_DIR(rt_ep); if(idx == 0) return 0; if(dir /* IN */){ low = usb_read(0x004 + idx*8); high = usb_read( (0x004 + idx*8)+1 ); }else{ /* OUT */ low = usb_read(0x000 + idx*8); high = usb_read( (0x000 + idx*8)+1 ); } rc = high | low; return rc; }
static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) { u8 *buf; int length, count, temp; if (unlikely(__raw_readl(imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) { D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n", __func__, imx_ep->ep.name); return -1; } buf = req->req.buf + req->req.actual; prefetch(buf); length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize); if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) { D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n", __func__, imx_ep->ep.name); return -1; } req->req.actual += length; count = length; if (!count && req->req.zero) { /* */ temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__); return 0; } while (count--) { if (count == 0) { /* */ temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_FCTRL(EP_NO(imx_ep))); __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base + USB_EP_FCTRL(EP_NO(imx_ep))); } __raw_writeb(*buf++, imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep))); } return length; }
static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) { u8 *buf; int bytes_ep, bufferspace, count, i; bytes_ep = imx_fifo_bcount(imx_ep); bufferspace = req->req.length - req->req.actual; buf = req->req.buf + req->req.actual; prefetchw(buf); if (unlikely(imx_ep_empty(imx_ep))) count = 0; /* */ else count = min(bytes_ep, bufferspace); for (i = count; i > 0; i--) *buf++ = __raw_readb(imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep))); req->req.actual += count; return count; }
static int read_ep_fifo(struct rt_ep_struct *rt_ep, struct rt_request *req) { u8 *buf, ep_no, ep_no_shift; int byte_count, req_bufferspace, count, i; DBG; ep_no = EP_NO(rt_ep); byte_count = read_outbc(ep_no); if(unlikely(!byte_count)) FATAL_ERROR("ep_no:%d bc = 0", ep_no); req_bufferspace = req->req.length - req->req.actual; buf = req->req.buf + req->req.actual; if(unlikely(!req_bufferspace)) FATAL_ERROR("zlp"); xprintk("bc=%d,r.l=%d,r.a=%d\n", byte_count, req->req.length ,req->req.actual); if(unlikely(byte_count > req_bufferspace)) FATAL_ERROR("buffer overflow, byte_count=%d, req->req.length=%d, req->req.actual=%d\n", byte_count, req->req.length ,req->req.actual); count = min(byte_count, req_bufferspace); ep_no_shift = 0x80+ep_no * 4; for (i = 0; i < count; i++){ *buf = usb_read(ep_no_shift); buf++; } req->req.actual += count; // EP Out irq handler would arm another transaction. return count; }