static void int_write(int ep) { int ep_num = EP_NUM(ep); int max = usb_drv_port_speed() ? 1024 : 64; int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt; unsigned int timeout = current_tick + HZ/10; while (IIN_TXBUF(ep_num) & (1<<0)) /* TXFULL flag */ { if(TIME_AFTER(current_tick, timeout)) break; } IIN_TXSTAT(ep_num) = xfer_size; /* size of the transfer */ IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */ IIN_DMAINCTL(ep_num) = (1<<0); /* start DMA */ IIN_TXCON(ep_num) &= ~(1<<2); /* clear NAK */ /* Decrement by max packet size is intentional. * This way if we have final packet short one we will get negative len * after transfer, which in turn indicates we *don't* need to send * zero length packet. If the final packet is max sized packet we will * get zero len after transfer which indicates we need to send * zero length packet to signal host end of the transfer. */ endpoints[ep_num].cnt -= max; endpoints[ep_num].buf += xfer_size; }
static void ep_transfer(int ep, void *ptr, int len, bool out) { /* disable interrupts to avoid any race */ int oldlevel = disable_irq_save(); struct ep_type *endpoint = &endpoints[ep][out ? DIR_OUT : DIR_IN]; endpoint->busy = true; endpoint->size = len; endpoint->status = -1; if (out) DEPCTL(ep, out) &= ~DEPCTL_stall; int mps = usb_drv_port_speed() ? 512 : 64; int nb_packets = (len + mps - 1) / mps; if (nb_packets == 0) nb_packets = 1; DEPDMA(ep, out) = len ? (void*)PHYSICAL_ADDR(ptr) : NULL; DEPTSIZ(ep, out) = (nb_packets << DEPTSIZ_pkcnt_bitp) | len; if(out) discard_dcache_range(ptr, len); else commit_dcache_range(ptr, len); logf("pkt=%d dma=%lx", nb_packets, DEPDMA(ep, out)); // if (!out) while (((GNPTXSTS & 0xffff) << 2) < MIN(mps, length)); DEPCTL(ep, out) |= DEPCTL_epena | DEPCTL_cnak; restore_irq(oldlevel); }
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; }
static void ep_send(int ep, const void *ptr, int length) { endpoints[ep].busy = true; endpoints[ep].size = length; DIEPCTL(ep) |= 0x8000; /* EPx OUT ACTIVE */ int blocksize = usb_drv_port_speed() ? 512 : 64; int packets = (length + blocksize - 1) / blocksize; if (!length) { DIEPTSIZ(ep) = 1 << 19; /* one empty packet */ DIEPDMA(ep) = NULL; } else { DIEPTSIZ(ep) = length | (packets << 19); DIEPDMA(ep) = ptr; } clean_dcache(); DIEPCTL(ep) |= 0x84000000; /* EPx OUT ENABLE CLEARNAK */ }
static void handle_std_dev_desc(struct usb_ctrlrequest *req) { int size; const void* ptr = NULL; unsigned index = req->wValue & 0xff; switch(req->wValue >> 8) { case USB_DT_DEVICE: ptr = &device_descriptor; size = sizeof(struct usb_device_descriptor); break; case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_CONFIG: { int max_packet_size; /* config desc */ if((req->wValue >> 8) ==USB_DT_CONFIG) { max_packet_size = (usb_drv_port_speed() ? 512 : 64); config_descriptor.bDescriptorType = USB_DT_CONFIG; } else { max_packet_size=(usb_drv_port_speed() ? 64 : 512); config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG; } size = sizeof(struct usb_config_descriptor); /* interface */ memcpy(usb_buffer + size, (void *)&interface_descriptor, sizeof(interface_descriptor)); size += sizeof(interface_descriptor); /* endpoint 1: bulk out */ endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_OUT; endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; endpoint_descriptor.wMaxPacketSize = 512; memcpy(usb_buffer + size, (void *)&endpoint_descriptor, sizeof(endpoint_descriptor)); size += sizeof(endpoint_descriptor); /* endpoint 2: bulk in */ endpoint_descriptor.bEndpointAddress = EP_BULK | USB_DIR_IN; endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK; endpoint_descriptor.wMaxPacketSize = 512; memcpy(usb_buffer + size, (void *)&endpoint_descriptor, sizeof(endpoint_descriptor)); size += sizeof(endpoint_descriptor); /* endpoint 3: int in */ endpoint_descriptor.bEndpointAddress = EP_INT | USB_DIR_IN; endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_INT; endpoint_descriptor.wMaxPacketSize = 1024; memcpy(usb_buffer + size, (void *)&endpoint_descriptor, sizeof(endpoint_descriptor)); size += sizeof(endpoint_descriptor); /* fix config descriptor */ config_descriptor.bNumInterfaces = 1; config_descriptor.wTotalLength = size; memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor)); ptr = usb_buffer; break; } case USB_DT_STRING: if(index < USB_NUM_STRINGS) { size = usb_strings[index]->bLength; ptr = usb_strings[index]; } else usb_drv_stall(EP_CONTROL, true, true); break; default: break; }
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); }
/* 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_std_dev_desc(struct usb_ctrlrequest *req) { int size; void* ptr = NULL; unsigned index = req->wValue & 0xff; switch(req->wValue >> 8) { case USB_DT_DEVICE: ptr = &device_descriptor; size = sizeof(struct usb_device_descriptor); break; case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_CONFIG: { int max_packet_size; /* config desc */ if((req->wValue >> 8) ==USB_DT_CONFIG) { max_packet_size = (usb_drv_port_speed() ? 512 : 64); config_descriptor.bDescriptorType = USB_DT_CONFIG; } else { max_packet_size=(usb_drv_port_speed() ? 64 : 512); config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG; } size = sizeof(struct usb_config_descriptor); /* hwstub version */ memcpy(usb_buffer + size, (void *)&version_descriptor, sizeof(version_descriptor)); size += sizeof(version_descriptor); /* hwstub layout */ fill_layout_info(); memcpy(usb_buffer + size, (void *)&layout_descriptor, sizeof(layout_descriptor)); size += sizeof(layout_descriptor); /* hwstub target */ fill_layout_info(); memcpy(usb_buffer + size, (void *)&target_descriptor, sizeof(target_descriptor)); size += sizeof(target_descriptor); /* target specific descriptors */ target_get_config_desc(usb_buffer + size, &size); /* fix config descriptor */ config_descriptor.bNumInterfaces = 1; config_descriptor.wTotalLength = size; memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor)); ptr = usb_buffer; break; } case USB_DT_STRING: if(index < USB_NUM_STRINGS) { size = usb_strings[index]->bLength; ptr = (void *)usb_strings[index]; } else usb_drv_stall(EP_CONTROL, true, true); break; case HWSTUB_DT_VERSION: ptr = &version_descriptor; size = sizeof(version_descriptor); break; case HWSTUB_DT_LAYOUT: ptr = &layout_descriptor; size = sizeof(layout_descriptor); break; case HWSTUB_DT_TARGET: ptr = &target_descriptor; size = sizeof(target_descriptor); break; default: target_get_desc(req->wValue >> 8, &ptr); if(ptr != 0) size = ((struct usb_descriptor_header *)ptr)->bLength; break; }