static void setup_received(void) { static uint32_t setup_data[2]; /* copy setup data from packet */ setup_data[0] = SETUP1; setup_data[1] = SETUP2; /* clear all pending control transfers * do we need this here? */ /* pass setup data to the upper layer */ usb_core_control_request((struct usb_ctrlrequest*)setup_data); }
/* IRQ handler */ void INT_USB_FUNC(void) { int i; uint32_t ints = GINTSTS; uint32_t epints; if (ints & 0x1000) /* bus reset */ { DCFG = 4; /* Address 0 */ reset_endpoints(1); usb_core_bus_reset(); } if (ints & 0x2000) /* enumeration done, we now know the speed */ { /* Set up the maximum packet sizes accordingly */ uint32_t maxpacket = usb_drv_port_speed() ? 512 : 64; DIEPCTL1 = (DIEPCTL1 & ~0x000003FF) | maxpacket; DOEPCTL2 = (DOEPCTL2 & ~0x000003FF) | maxpacket; DIEPCTL3 = (DIEPCTL3 & ~0x000003FF) | maxpacket; DOEPCTL4 = (DOEPCTL4 & ~0x000003FF) | maxpacket; } if (ints & 0x40000) /* IN EP event */ for (i = 0; i < 4; i += i + 1) // 0, 1, 3 if ((epints = DIEPINT(i))) { if (epints & 1) /* Transfer completed */ { invalidate_dcache(); int bytes = endpoints[i].size - (DIEPTSIZ(i) & 0x3FFFF); if (endpoints[i].busy) { endpoints[i].busy = false; endpoints[i].rc = 0; endpoints[i].done = true; usb_core_transfer_complete(i, USB_DIR_IN, 0, bytes); semaphore_release(&endpoints[i].complete); } } if (epints & 4) /* AHB error */ panicf("USB: AHB error on IN EP%d", i); if (epints & 8) /* Timeout */ { if (endpoints[i].busy) { endpoints[i].busy = false; endpoints[i].rc = 1; endpoints[i].done = true; semaphore_release(&endpoints[i].complete); } } DIEPINT(i) = epints; } if (ints & 0x80000) /* OUT EP event */ for (i = 0; i < USB_NUM_ENDPOINTS; i += 2) if ((epints = DOEPINT(i))) { if (epints & 1) /* Transfer completed */ { invalidate_dcache(); int bytes = endpoints[i].size - (DOEPTSIZ(i) & 0x3FFFF); if (endpoints[i].busy) { endpoints[i].busy = false; endpoints[i].rc = 0; endpoints[i].done = true; usb_core_transfer_complete(i, USB_DIR_OUT, 0, bytes); semaphore_release(&endpoints[i].complete); } } if (epints & 4) /* AHB error */ panicf("USB: AHB error on OUT EP%d", i); if (epints & 8) /* SETUP phase done */ { invalidate_dcache(); if (i == 0) { if (ctrlreq.bRequest == 5) { /* Already set the new address here, before passing the packet to the core. See below (usb_drv_set_address) for details. */ DCFG = (DCFG & ~0x7F0) | (ctrlreq.wValue << 4); } usb_core_control_request(&ctrlreq); } else panicf("USB: SETUP done on OUT EP%d!?", i); } /* Make sure EP0 OUT is set up to accept the next request */ if (!i) { DOEPTSIZ0 = 0x20080040; DOEPDMA0 = &ctrlreq; DOEPCTL0 |= 0x84000000; } DOEPINT(i) = epints; } GINTSTS = ints; }
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; }