int usb_drv_recv(int ep, void *ptr, int len) { struct usb_dev_dma_desc *uc_desc = endpoints[ep][1].uc_desc; ep &= 0x7f; logf("usb_drv_recv(%d,%x,%d)\n", ep, (int)ptr, len); if (len > USB_DMA_DESC_RXTX_BYTES) panicf("usb_recv: len=%d > %d", len, USB_DMA_DESC_RXTX_BYTES); if ((int)ptr & 31) { logf("addr %08x not aligned!\n", (int)ptr); } endpoints[ep][1].state |= EP_STATE_BUSY; endpoints[ep][1].len = len; endpoints[ep][1].rc = -1; /* remove data buffer from cache */ discard_dcache_range(ptr, len); /* DMA setup */ uc_desc->status = USB_DMA_DESC_BS_HST_RDY | USB_DMA_DESC_LAST | len; if (len == 0) { uc_desc->status |= USB_DMA_DESC_ZERO_LEN; uc_desc->data_ptr = 0; } else { uc_desc->data_ptr = AS3525_PHYSICAL_ADDR(ptr); } USB_OEP_DESC_PTR(ep) = AS3525_PHYSICAL_ADDR((int)&dmadescs[ep][1]); USB_OEP_STS(ep) = USB_EP_STAT_OUT_RCVD; /* clear status */ /* Make sure receive DMA is on */ if (!(USB_DEV_CTRL & USB_DEV_CTRL_RDE)){ USB_DEV_CTRL |= USB_DEV_CTRL_RDE; if (!(USB_DEV_CTRL & USB_DEV_CTRL_RDE)) logf("failed to enable RDE!\n"); } USB_OEP_CTRL(ep) |= USB_EP_CTRL_CNAK; /* Go! */ if (USB_OEP_CTRL(ep) & USB_EP_CTRL_NAK) { int i = 0; while (USB_OEP_CTRL(ep) & USB_EP_CTRL_NAK) { USB_OEP_CTRL(ep) |= USB_EP_CTRL_CNAK; /* Go! */ i++; } logf("ep%d CNAK needed %d retries CTRL=%x\n", ep, i, (int)USB_OEP_CTRL(ep)); } return 0; }
static void ep_send(int ep, void *ptr, int len) { struct usb_dev_dma_desc *uc_desc = endpoints[ep][0].uc_desc; endpoints[ep][0].state |= EP_STATE_BUSY; endpoints[ep][0].len = len; endpoints[ep][0].rc = -1; /* * I'm seeing a problem where Linux sends two SETUP requests, * but fails to read the response from the first one. * We then have the response we wanted to send still in our fifo, * so flush the fifo before sending on the control endpoint. */ if (ep == 0) USB_IEP_CTRL(ep) |= USB_EP_CTRL_FLUSH; /* Make sure data is committed to memory */ commit_dcache_range(ptr, len); logf("xx%s\n", make_hex(ptr, len)); uc_desc->status = USB_DMA_DESC_BS_HST_RDY | USB_DMA_DESC_LAST | len; if (len == 0) uc_desc->status |= USB_DMA_DESC_ZERO_LEN; uc_desc->data_ptr = AS3525_PHYSICAL_ADDR(ptr); USB_IEP_DESC_PTR(ep) = AS3525_PHYSICAL_ADDR((int)&dmadescs[ep][0]); USB_IEP_STS(ep) = 0xffffffff; /* clear status */ /* start transfer */ USB_IEP_CTRL(ep) |= USB_EP_CTRL_CNAK | USB_EP_CTRL_PD; /* HW automatically sets NAK bit later */ }
static void prepare_setup_ep0(void) { logf("usb-drv: prepare EP0"); /* setup DMA */ DOEPDMA(0) = (unsigned long)AS3525_PHYSICAL_ADDR(&_ep0_setup_pkt); /* Setup EP0 OUT with the following parameters: * packet count = 1 * setup packet count = 1 * transfer size = 8 (setup packet) */ DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 8; /* Enable endpoint, clear nak */ ep0_state = EP0_WAIT_SETUP; DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak; }
static void reset_endpoints(int init) { int i; /* * OUT EP 2 is an alias for OUT EP 0 on this HW! * * Resonates with "3 bidirectional- plus 1 in-endpoints in device mode" * from the datasheet, but why ep2 and not ep3? * * Reserve it here so we will skip over it in request_endpoint(). */ endpoints[2][1].state |= EP_STATE_ALLOCATED; for(i = 0; i < USB_NUM_EPS; i++) { /* * MPS sizes depending on speed: * LS: 8 (control), no bulk available * FS: 64 (control), 64 (bulk) * HS: 64 (control), 512 (bulk) * * We don't need to handle LS since there is no low-speed only * host AFAIK. */ int mps = i == 0 ? 64 : (usb_drv_port_speed() ? 512 : 64); if (init) { if (endpoints[i][0].state & EP_STATE_BUSY) { if (endpoints[i][0].state & EP_STATE_ASYNC) { endpoints[i][0].rc = -1; semaphore_release(&endpoints[i][0].complete); } else { usb_core_transfer_complete(i, USB_DIR_IN, -1, 0); } } endpoints[i][0].state = 0; semaphore_wait(&endpoints[i][0].complete, TIMEOUT_NOBLOCK); if (i != 2) { /* Skip the OUT EP0 alias */ if (endpoints[i][1].state & EP_STATE_BUSY) usb_core_transfer_complete(i, USB_DIR_OUT, -1, 0); endpoints[i][1].state = 0; semaphore_wait(&endpoints[i][1].complete, TIMEOUT_NOBLOCK); USB_OEP_SUP_PTR(i) = 0; } } dma_desc_init(i, 0); USB_IEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK; USB_IEP_MPS (i) = mps; /* in bytes */ /* We don't care about the 'IN token received' event */ USB_IEP_STS_MASK(i) = USB_EP_STAT_IN; /* OF: 0x840 */ USB_IEP_TXFSIZE (i) = mps/2; /* in dwords => mps*2 bytes */ USB_IEP_STS (i) = 0xffffffff; /* clear status */ USB_IEP_DESC_PTR(i) = 0; if (i != 2) { /* Skip the OUT EP0 alias */ dma_desc_init(i, 1); USB_OEP_CTRL (i) = USB_EP_CTRL_FLUSH|USB_EP_CTRL_SNAK; USB_OEP_MPS (i) = (mps/2 << 16) | mps; USB_OEP_STS_MASK(i) = USB_EP_STAT_BNA; /* OF: 0x1800 */ USB_OEP_RXFR (i) = 0; /* Always 0 in OF trace? */ USB_OEP_STS (i) = 0xffffffff; /* clear status */ USB_OEP_DESC_PTR(i) = 0; } } setup_desc_init(setup_desc); USB_OEP_SUP_PTR(0) = AS3525_PHYSICAL_ADDR((int)setup_desc); }