From 42edbc000665e555bc5f44046d2ed72f4597de5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20D=C3=BCmpelmann?= Date: Fri, 15 May 2020 22:26:14 +0200 Subject: [PATCH] Allow EP0 to use xfer sizes larger than one packet --- src/portable/st/synopsys/dcd_synopsys.c | 50 +++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/portable/st/synopsys/dcd_synopsys.c b/src/portable/st/synopsys/dcd_synopsys.c index 73e6ca827..06f41ceec 100644 --- a/src/portable/st/synopsys/dcd_synopsys.c +++ b/src/portable/st/synopsys/dcd_synopsys.c @@ -109,6 +109,9 @@ typedef volatile uint32_t * usb_fifo_t; xfer_ctl_t xfer_status[EP_MAX][2]; #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] +// EP0 transfers are limited to 1 packet - larger sizes has to be split +static uint16_t ep0_pending[2]; // Index determines direction as tusb_dir_t type + // Setup the control endpoint 0. static void bus_reset(void) { @@ -356,13 +359,26 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer->total_len = total_bytes; uint16_t num_packets = (total_bytes / xfer->max_size); - uint8_t short_packet_size = total_bytes % xfer->max_size; + uint8_t const short_packet_size = total_bytes % xfer->max_size; // Zero-size packet is special case. if(short_packet_size > 0 || (total_bytes == 0)) { num_packets++; } + // EP0 can only handle one packet + if(epnum == 0) { + num_packets = 1; + if(total_bytes > xfer->max_size) { + ep0_pending[dir] = total_bytes - xfer->max_size; + total_bytes = xfer->max_size; + // Decrement pointer to make EP0 buffers compatible with existing routines. + xfer->buffer -= ep0_pending[dir]; + } else { + ep0_pending[dir] = 0; + } + } + // IN and OUT endpoint xfers are interrupt-driven, we just schedule them here. if(dir == TUSB_DIR_IN) { // A full IN transfer (multiple packets, possibly) triggers XFRC. @@ -549,6 +565,9 @@ static void handle_rxflvl_ints(USB_OTG_OUTEndpointTypeDef * out_ep) { uint16_t remaining_bytes = ((out_ep[epnum].DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ_Msk) \ >> USB_OTG_DOEPTSIZ_XFRSIZ_Pos) + bcnt; + // Adjust remaining bytes in case of multi packet EP0 transfer + if(epnum == 0) remaining_bytes += ep0_pending[TUSB_DIR_OUT]; + // Read packet off RxFIFO read_fifo_packet((xfer->buffer + xfer->total_len - remaining_bytes), bcnt); } @@ -592,7 +611,18 @@ static void handle_epout_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_OUTEndpointTy // OUT XFER complete if(out_ep[n].DOEPINT & USB_OTG_DOEPINT_XFRC) { out_ep[n].DOEPINT = USB_OTG_DOEPINT_XFRC; - dcd_event_xfer_complete(0, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + + // EP0 can only handle one packet + if((n == 0) && ep0_pending[TUSB_DIR_OUT]){ + uint16_t const total_bytes = tu_min16(ep0_pending[TUSB_DIR_OUT], xfer->max_size); + ep0_pending[TUSB_DIR_OUT] -= total_bytes; + // Schedule another packet to be received. + out_ep[0].DOEPTSIZ |= (1 << USB_OTG_DOEPTSIZ_PKTCNT_Pos) | + ((total_bytes << USB_OTG_DOEPTSIZ_XFRSIZ_Pos) & USB_OTG_DOEPTSIZ_XFRSIZ_Msk); + out_ep[0].DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; + } else { + dcd_event_xfer_complete(0, n, xfer->total_len, XFER_RESULT_SUCCESS, true); + } } } } @@ -612,7 +642,18 @@ static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointType if ( in_ep[n].DIEPINT & USB_OTG_DIEPINT_XFRC ) { in_ep[n].DIEPINT = USB_OTG_DIEPINT_XFRC; - dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + + // EP0 can only handle one packet + if((n == 0) && ep0_pending[TUSB_DIR_IN]){ + uint16_t const total_bytes = tu_min16(ep0_pending[TUSB_DIR_IN], xfer->max_size); + ep0_pending[TUSB_DIR_IN] -= total_bytes; + // Schedule another packet to be received. + in_ep[0].DIEPTSIZ |= (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | + ((total_bytes << USB_OTG_DIEPTSIZ_XFRSIZ_Pos) & USB_OTG_DIEPTSIZ_XFRSIZ_Msk); + in_ep[0].DIEPCTL |= USB_OTG_DIEPCTL_EPENA | USB_OTG_DIEPCTL_CNAK; + } else { + dcd_event_xfer_complete(0, n | TUSB_DIR_IN_MASK, xfer->total_len, XFER_RESULT_SUCCESS, true); + } } // XFER FIFO empty @@ -637,6 +678,9 @@ static void handle_epin_ints(USB_OTG_DeviceTypeDef * dev, USB_OTG_INEndpointType break; } + // Adjust remaining bytes in case of multi packet EP0 transfer + if(n == 0) remaining_bytes += ep0_pending[TUSB_DIR_IN]; + // Push packet to Tx-FIFO write_fifo_packet(n, (xfer->buffer + xfer->total_len - remaining_bytes), packet_size); }