void INT_USB_FUNC(void) { /* some bits in GINTSTS can be set even though we didn't enable the interrupt source * so AND it with the actual mask */ unsigned long sts = GINTSTS & GINTMSK; logf("usb-drv: INT 0x%lx", sts); if(sts & GINTMSK_usbreset) { DCFG &= ~bitm(DCFG, devadr); /* Address 0 */ reset_endpoints(); usb_core_bus_reset(); } if(sts & GINTMSK_enumdone) /* enumeration done, we now know the speed */ { /* Set up the maximum packet sizes accordingly */ uint32_t maxpacket = (usb_drv_port_speed() ? 512 : 64) << DEPCTL_mps_bitp; for (int dir = 0; dir < 2; dir++) { bool out = dir == DIR_OUT; for (unsigned i = 1; i < num_eps(out); i++) { int ep = (out ? out_ep_list : in_ep_list)[i]; DEPCTL(ep, out) &= ~(DEPCTL_mps_bits << DEPCTL_mps_bitp); DEPCTL(ep, out) |= maxpacket; } } } if(sts & (GINTMSK_outepintr | GINTMSK_inepintr)) { unsigned long daint = DAINT; for (int i = 0; i < USB_NUM_ENDPOINTS; i++) { if (daint & DAINT_IN_EP(i)) handle_ep_int(i, false); if (daint & DAINT_OUT_EP(i)) handle_ep_int(i, true); } DAINT = daint; } if(sts & GINTMSK_disconnect) cancel_all_transfers(true); GINTSTS = sts; }
/* 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; }