summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorReinhard Panhuber <[email protected]>2021-02-13 12:13:10 +0100
committerReinhard Panhuber <[email protected]>2021-02-13 12:13:10 +0100
commit59d6ed9ea409525899d398789b255ffb7f96660a (patch)
treefe2ff3fe0c5096091cfd0315dbe02f6f29df3da9 /src
parent9e2a1d2e6a22fb1cfb952a62f501403d372bbb45 (diff)
Implement dcd_edpt_iso_xfer() for dcd_esp32s2.c
Diffstat (limited to 'src')
-rw-r--r--src/portable/espressif/esp32s2/dcd_esp32s2.c176
1 files changed, 127 insertions, 49 deletions
diff --git a/src/portable/espressif/esp32s2/dcd_esp32s2.c b/src/portable/espressif/esp32s2/dcd_esp32s2.c
index 703841759..72fb4ba48 100644
--- a/src/portable/espressif/esp32s2/dcd_esp32s2.c
+++ b/src/portable/espressif/esp32s2/dcd_esp32s2.c
@@ -27,6 +27,7 @@
*/
#include "tusb_option.h"
+#include "common/tusb_fifo.h"
#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 && TUSB_OPT_DEVICE_ENABLED
@@ -59,6 +60,7 @@
typedef struct {
uint8_t *buffer;
+ tu_fifo_t * ff;
uint16_t total_len;
uint16_t queued_len;
uint16_t max_size;
@@ -354,6 +356,64 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to
return true;
}
+bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
+{
+ (void)rhport;
+
+ // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
+ TU_ASSERT(ff->item_size == 1);
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->buffer = NULL;
+ xfer->ff = ff;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->short_packet = false;
+
+ uint16_t num_packets = (total_bytes / xfer->max_size);
+ uint8_t short_packet_size = total_bytes % xfer->max_size;
+
+ // Zero-size packet is special case.
+ if (short_packet_size > 0 || (total_bytes == 0)) {
+ num_packets++;
+ }
+
+ // Set copy mode to constant address - required since data copied to or from the hardware USB FIFO needs to be written at a constant address
+ if (dir == TUSB_DIR_IN)
+ {
+ tu_fifo_set_copy_mode_write(ff, TU_FIFO_COPY_CST);
+ }
+ else
+ {
+ tu_fifo_set_copy_mode_read(ff, TU_FIFO_COPY_CST);
+ }
+
+ ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
+ epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
+ num_packets, total_bytes);
+
+ // 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.
+ USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
+ USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
+
+ // Enable fifo empty interrupt only if there are something to put in the fifo.
+ if(total_bytes != 0) {
+ USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
+ }
+ } else {
+ // Each complete packet for OUT xfers triggers XFRC.
+ USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
+ USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
+ }
+ return true;
+}
+
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
(void)rhport;
@@ -462,36 +522,46 @@ static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */
to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
}
- uint8_t to_recv_rem = to_recv_size % 4;
- uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
+ // Common buffer read
+ if (xfer->buffer)
+ {
+ uint8_t to_recv_rem = to_recv_size % 4;
+ uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
- // Do not assume xfer buffer is aligned.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
+ // Do not assume xfer buffer is aligned.
+ uint8_t *base = (xfer->buffer + xfer->queued_len);
- // This for loop always runs at least once- skip if less than 4 bytes
- // to collect.
- if (to_recv_size >= 4) {
- for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
- uint32_t tmp = (*rx_fifo);
- base[i] = tmp & 0x000000FF;
- base[i + 1] = (tmp & 0x0000FF00) >> 8;
- base[i + 2] = (tmp & 0x00FF0000) >> 16;
- base[i + 3] = (tmp & 0xFF000000) >> 24;
+ // This for loop always runs at least once- skip if less than 4 bytes
+ // to collect.
+ if (to_recv_size >= 4) {
+ for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
+ uint32_t tmp = (*rx_fifo);
+ base[i] = tmp & 0x000000FF;
+ base[i + 1] = (tmp & 0x0000FF00) >> 8;
+ base[i + 2] = (tmp & 0x00FF0000) >> 16;
+ base[i + 3] = (tmp & 0xFF000000) >> 24;
+ }
}
- }
- // Do not read invalid bytes from RX FIFO.
- if (to_recv_rem != 0) {
- uint32_t tmp = (*rx_fifo);
- uint8_t *last_32b_bound = base + to_recv_size_aligned;
+ // Do not read invalid bytes from RX FIFO.
+ if (to_recv_rem != 0) {
+ uint32_t tmp = (*rx_fifo);
+ uint8_t *last_32b_bound = base + to_recv_size_aligned;
- last_32b_bound[0] = tmp & 0x000000FF;
- if (to_recv_rem > 1) {
- last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
- }
- if (to_recv_rem > 2) {
- last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
+ last_32b_bound[0] = tmp & 0x000000FF;
+ if (to_recv_rem > 1) {
+ last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
+ }
+ if (to_recv_rem > 2) {
+ last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
+ }
}
+
+ }
+ else
+ {
+ // Ring buffer
+ tu_fifo_write_n(xfer->ff, (const void *) rx_fifo, to_recv_size);
}
xfer->queued_len += xfer_size;
@@ -510,37 +580,45 @@ static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep,
xfer->queued_len = xfer->total_len - remaining;
uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
- uint8_t to_xfer_rem = to_xfer_size % 4;
- uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
- // Buffer might not be aligned to 32b, so we need to force alignment
- // by copying to a temp var.
- uint8_t *base = (xfer->buffer + xfer->queued_len);
+ if (xfer->buffer)
+ {
+ uint8_t to_xfer_rem = to_xfer_size % 4;
+ uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
- // This for loop always runs at least once- skip if less than 4 bytes
- // to send off.
- if (to_xfer_size >= 4) {
- for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
- uint32_t tmp = base[i] | (base[i + 1] << 8) |
- (base[i + 2] << 16) | (base[i + 3] << 24);
- (*tx_fifo) = tmp;
+ // Buffer might not be aligned to 32b, so we need to force alignment
+ // by copying to a temp var.
+ uint8_t *base = (xfer->buffer + xfer->queued_len);
+
+ // This for loop always runs at least once- skip if less than 4 bytes
+ // to send off.
+ if (to_xfer_size >= 4) {
+ for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
+ uint32_t tmp = base[i] | (base[i + 1] << 8) |
+ (base[i + 2] << 16) | (base[i + 3] << 24);
+ (*tx_fifo) = tmp;
+ }
}
- }
- // Do not read beyond end of buffer if not divisible by 4.
- if (to_xfer_rem != 0) {
- uint32_t tmp = 0;
- uint8_t *last_32b_bound = base + to_xfer_size_aligned;
+ // Do not read beyond end of buffer if not divisible by 4.
+ if (to_xfer_rem != 0) {
+ uint32_t tmp = 0;
+ uint8_t *last_32b_bound = base + to_xfer_size_aligned;
- tmp |= last_32b_bound[0];
- if (to_xfer_rem > 1) {
- tmp |= (last_32b_bound[1] << 8);
- }
- if (to_xfer_rem > 2) {
- tmp |= (last_32b_bound[2] << 16);
- }
+ tmp |= last_32b_bound[0];
+ if (to_xfer_rem > 1) {
+ tmp |= (last_32b_bound[1] << 8);
+ }
+ if (to_xfer_rem > 2) {
+ tmp |= (last_32b_bound[2] << 16);
+ }
- (*tx_fifo) = tmp;
+ (*tx_fifo) = tmp;
+ }
+ }
+ else
+ {
+ tu_fifo_read_n(xfer->ff, (void *) tx_fifo, to_xfer_size);
}
}