static void handle_ep0_complete(bool is_ack) { switch(ep0_state) { case EP0_WAIT_SETUP: panicf("usb-drv: EP0 completion while waiting for SETUP"); case EP0_WAIT_ACK: if(is_ack) /* everything is done, prepare next setup */ prepare_setup_ep0(); else panicf("usb-drv: EP0 data completion while waiting for ACK"); break; case EP0_WAIT_DATA: if(is_ack) panicf("usb-drv: EP0 ACK while waiting for data completion"); else /* everything is done, prepare next setup */ prepare_setup_ep0(); break; case EP0_WAIT_DATA_ACK: /* update state */ if(is_ack) ep0_state = EP0_WAIT_DATA; else ep0_state = EP0_WAIT_ACK; break; default: panicf("usb-drv: invalid EP0 state"); } logf("usb-drv: EP0 state updated to %d", ep0_state); }
static void reset_endpoints(void) { for (int dir = 0; dir < 2; dir++) { bool out = dir == DIR_OUT; for (unsigned i = 0; i < num_eps(dir == DIR_OUT); i++) { int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i]; struct ep_type *endpoint = &endpoints[ep][out]; endpoint->active = false; endpoint->busy = false; endpoint->status = -1; endpoint->done = true; semaphore_release(&endpoint->complete); if (i != 0) DEPCTL(ep, out) = DEPCTL_setd0pid; } DEPCTL(0, out) = /*(DEPCTL_MPS_64 << DEPCTL_mps_bitp) | */ DEPCTL_usbactep; } /* Setup next chain for IN eps */ for (unsigned i = 0; i < num_eps(false); i++) { int ep = in_ep_list[i]; int next_ep = in_ep_list[(i + 1) % num_eps(false)]; DEPCTL(ep, false) |= next_ep << DEPCTL_nextep_bitp; } prepare_setup_ep0(); }
static void handle_ep_int(int ep, bool out) { unsigned long sts = DEPINT(ep, out); struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; logf("%s(%d %s): sts = 0x%lx", __func__, ep, out?"OUT":"IN", sts); if(sts & DEPINT_ahberr) panicf("usb-drv: ahb error on EP%d %s", ep, out ? "OUT" : "IN"); if(sts & DEPINT_xfercompl) { discard_dma_buffer_cache(); if(endpoint->busy) { endpoint->busy = false; endpoint->status = 0; /* works even for EP0 */ int size = (DEPTSIZ(ep, out) & DEPTSIZ_xfersize_bits); int transfered = endpoint->size - size; if(ep == 0) { bool is_ack = endpoint->size == 0; switch(ep0_state) { case EP0_WAIT_SETUP: panicf("usb-drv: EP0 completion while waiting for SETUP"); case EP0_WAIT_DATA_ACK: ep0_state = is_ack ? EP0_WAIT_DATA : EP0_WAIT_ACK; break; case EP0_WAIT_ACK: case EP0_WAIT_DATA: if((!is_ack && ep0_state == EP0_WAIT_ACK) || (is_ack && ep0_state == EP0_WAIT_DATA)) panicf("usb-drv: bad EP0 state"); prepare_setup_ep0(); break; } } if (!out) endpoint->size = size; usb_core_transfer_complete(ep, out ? USB_DIR_OUT : USB_DIR_IN, 0, transfered); endpoint->done = true; semaphore_release(&endpoint->complete); } } if(!out && (sts & DIEPINT_timeout)) { if (endpoint->busy) { endpoint->busy = false; endpoint->status = 1; endpoint->done = true; semaphore_release(&endpoint->complete); } } if(out && (sts & DOEPINT_setup)) { discard_dma_buffer_cache(); if(ep != 0) panicf("usb-drv: setup not on EP0, this is impossible"); if((DEPTSIZ(ep, true) & DEPTSIZ_xfersize_bits) != 0) { logf("usb-drv: ignore spurious setup (xfersize=%ld)", DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits); prepare_setup_ep0(); } else { if(ep0_state == EP0_WAIT_SETUP) { bool data_phase = ep0_setup_pkt->wLength != 0; ep0_state = data_phase ? EP0_WAIT_DATA_ACK : EP0_WAIT_ACK; } logf(" rt=%x r=%x", ep0_setup_pkt->bRequestType, ep0_setup_pkt->bRequest); if(ep0_setup_pkt->bRequestType == USB_TYPE_STANDARD && ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS) DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp); usb_core_control_request(ep0_setup_pkt); } } DEPINT(ep, out) = sts; }