void imx_udc_init_ep(struct imx_udc_struct *imx_usb) { int i, max, temp; struct imx_ep_struct *imx_ep; for (i = 0; i < IMX_USB_NB_EP; i++) { imx_ep = &imx_usb->imx_ep[i]; switch (imx_ep->fifosize) { case 8: max = 0; break; case 16: max = 1; break; case 32: max = 2; break; case 64: max = 3; break; default: max = 1; break; } temp = (EP_DIR(imx_ep) << 7) | (max << 5) | (imx_ep->bmAttributes << 3); __raw_writel(temp, imx_usb->base + USB_EP_STAT(i)); __raw_writel(temp | EPSTAT_FLUSH, imx_usb->base + USB_EP_STAT(i)); D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i, __raw_readl(imx_usb->base + USB_EP_STAT(i))); } }
/* Reserve endpoint */ int usb_drv_request_endpoint(int type, int dir) { int ep_num, ep_dir; int ep_type; /* Safety */ ep_dir = EP_DIR(dir); ep_type = type & USB_ENDPOINT_XFERTYPE_MASK; logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type)); /* Find an available ep/dir pair */ for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) { struct endpoint_t* endpoint = &endpoints[ep_num]; if (endpoint->type == ep_type && endpoint->dir == ep_dir && !endpoint->allocated) { /* mark endpoint as taken */ endpoint->allocated = true; /* enable interrupt from this endpoint */ EN_INT |= (1<<(ep_num+7)); logf("add: ep%d %s", ep_num, XFER_DIR_STR(ep_dir)); return (ep_num | (dir & USB_ENDPOINT_DIR_MASK)); } } return -1; }
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 struct rt_request *get_unhandled_req(struct rt_ep_struct *rt_ep) { struct rt_request *req = NULL; if(EP_DIR(rt_ep) == EP_OUT) FATAL_ERROR("Out EP"); if (!list_empty(&rt_ep->queue)){ req = list_entry(rt_ep->queue.next, struct rt_request, queue); }else {
void imx_udc_config(struct imx_udc_struct *imx_usb) { u8 ep_conf[5]; u8 i, j, cfg; struct imx_ep_struct *imx_ep; /* */ do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); /* */ for (j = 0; j < 5; j++) { i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00); __raw_writeb(i, imx_usb->base + USB_DDAT); do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); } /* */ for (cfg = 1; cfg < 3; cfg++) { for (i = 1; i < IMX_USB_NB_EP; i++) { imx_ep = &imx_usb->imx_ep[i]; /* */ ep_conf[0] = (i << 4) | (cfg << 2); /* */ ep_conf[1] = (imx_ep->bmAttributes << 3) | (EP_DIR(imx_ep) << 2); /* */ ep_conf[2] = imx_ep->fifosize; /* */ ep_conf[3] = 0xC0; /* */ ep_conf[4] = i; D_INI(imx_usb->dev, "<%s> ep%d_conf[%d]:" "[%02x-%02x-%02x-%02x-%02x]\n", __func__, i, cfg, ep_conf[0], ep_conf[1], ep_conf[2], ep_conf[3], ep_conf[4]); for (j = 0; j < 5; j++) { __raw_writeb(ep_conf[j], imx_usb->base + USB_DDAT); do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); } } } /* */ do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG); }
void imx_udc_config(struct imx_udc_struct *imx_usb) { u8 ep_conf[5]; u8 i, j, cfg; struct imx_ep_struct *imx_ep; /* wait CFG bit to assert */ do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); /* Download the endpoint buffer for endpoint 0. */ for (j = 0; j < 5; j++) { i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00); __raw_writeb(i, imx_usb->base + USB_DDAT); do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); } /* Download the endpoint buffers for endpoints 1-5. * We specify two configurations, one interface */ for (cfg = 1; cfg < 3; cfg++) { for (i = 1; i < IMX_USB_NB_EP; i++) { imx_ep = &imx_usb->imx_ep[i]; /* EP no | Config no */ ep_conf[0] = (i << 4) | (cfg << 2); /* Type | Direction */ ep_conf[1] = (imx_ep->bmAttributes << 3) | (EP_DIR(imx_ep) << 2); /* Max packet size */ ep_conf[2] = imx_ep->fifosize; /* TRXTYP */ ep_conf[3] = 0xC0; /* FIFO no */ ep_conf[4] = i; D_INI(imx_usb->dev, "<%s> ep%d_conf[%d]:" "[%02x-%02x-%02x-%02x-%02x]\n", __func__, i, cfg, ep_conf[0], ep_conf[1], ep_conf[2], ep_conf[3], ep_conf[4]); for (j = 0; j < 5; j++) { __raw_writeb(ep_conf[j], imx_usb->base + USB_DDAT); do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); } } } /* wait CFG bit to clear */ do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG); }
/* Free endpoint */ void usb_drv_release_endpoint(int ep) { int ep_num = EP_NUM(ep); int ep_dir = EP_DIR(ep); logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir)); endpoints[ep_num].allocated = false; /* disable interrupt from this endpoint */ EN_INT &= ~(1<<(ep_num+7)); }
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 usb_core_release_endpoint(int ep) { int dir; usb_drv_release_endpoint(ep); dir = EP_DIR(ep); ep = EP_NUM(ep); ep_data[ep].completion_handler[dir] = NULL; ep_data[ep].control_handler[dir] = NULL; }
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); } }
int usb_core_request_endpoint(int type, int dir, struct usb_class_driver* drv) { int ret, ep; ret = usb_drv_request_endpoint(type, dir); if(ret == -1) return -1; dir = EP_DIR(ret); ep = EP_NUM(ret); ep_data[ep].completion_handler[dir] = drv->transfer_complete; ep_data[ep].control_handler[dir] = drv->control_request; return ret; }
void usb_core_handle_transfer_completion( struct usb_transfer_completion_event_data* event) { completion_handler_t handler; int ep = event->endpoint; switch(ep) { case EP_CONTROL: logf("ctrl handled %ld",current_tick); usb_core_control_request_handler( (struct usb_ctrlrequest*)event->data); break; default: handler = ep_data[ep].completion_handler[EP_DIR(event->dir)]; if(handler != NULL) handler(ep, event->dir, event->status, event->length); break; } }
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; }
void imx_udc_init_fifo(struct imx_udc_struct *imx_usb) { int i, temp; struct imx_ep_struct *imx_ep; for (i = 0; i < IMX_USB_NB_EP; i++) { imx_ep = &imx_usb->imx_ep[i]; /* */ temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000; __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i)); D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i, __raw_readl(imx_usb->base + USB_EP_FCTRL(i))); /* */ temp = (i ? imx_ep->fifosize / 2 : 0); __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i)); D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i, __raw_readl(imx_usb->base + USB_EP_FALRM(i))); } }
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 handle_ep(struct imx_ep_struct *imx_ep) { struct imx_request *req; int completed = 0; do { if (!list_empty(&imx_ep->queue)) req = list_entry(imx_ep->queue.next, struct imx_request, queue); else { D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n", __func__, imx_ep->ep.name); return 0; } if (EP_DIR(imx_ep)) /* */ completed = write_fifo(imx_ep, req); else /* */ completed = read_fifo(imx_ep, req); dump_ep_stat(__func__, imx_ep); } while (completed);
void usb_drv_release_endpoint(int ep) { if ((ep & 0x7f) == 0) return; endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; }