Open FFBoard
Open source force feedback firmware
dcd_esp32sx.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
5 * Copyright (c) 2019 Ha Thach (tinyusb.org)
6 * Additions Copyright (c) 2020, Espressif Systems (Shanghai) Co. Ltd.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 * This file is part of the TinyUSB stack.
27 */
28
29#include "tusb_option.h"
30
31#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
32
33// Espressif
34#include "xtensa/xtensa_api.h"
35
36#include "esp_intr_alloc.h"
37#include "esp_log.h"
38#include "soc/dport_reg.h"
39#include "soc/gpio_sig_map.h"
40#include "soc/usb_periph.h"
41#include "soc/usb_reg.h"
42#include "soc/usb_struct.h"
43#include "soc/periph_defs.h" // for interrupt source
44
45#include "device/dcd.h"
46
47#ifndef USB_OUT_EP_NUM
48#define USB_OUT_EP_NUM ((int) (sizeof(USB0.out_ep_reg) / sizeof(USB0.out_ep_reg[0])))
49#endif
50
51#ifndef USB_IN_EP_NUM
52#define USB_IN_EP_NUM ((int) (sizeof(USB0.in_ep_reg) / sizeof(USB0.in_ep_reg[0])))
53#endif
54
55// Max number of bi-directional endpoints including EP0
56// Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0
57// We should probably prohibit enabling Endpoint IN > 4 (not done yet)
58#define EP_MAX USB_OUT_EP_NUM
59
60// FIFO size in bytes
61#define EP_FIFO_SIZE 1024
62
63// Max number of IN EP FIFOs
64#define EP_FIFO_NUM 5
65
66typedef struct {
67 uint8_t *buffer;
68 // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
69 uint16_t total_len;
70 uint16_t queued_len;
71 uint16_t max_size;
73 uint8_t interval;
75
76static const char *TAG = "TUSB:DCD";
77static intr_handle_t usb_ih;
78
79
80static uint32_t _setup_packet[2];
81
82#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
83static xfer_ctl_t xfer_status[EP_MAX][2];
84
85// Keep count of how many FIFOs are in use
86static uint8_t _allocated_fifos = 1; //FIFO0 is always in use
87
88// Will either return an unused FIFO number, or 0 if all are used.
89static uint8_t get_free_fifo(void)
90{
91 if (_allocated_fifos < EP_FIFO_NUM) return _allocated_fifos++;
92 return 0;
93}
94
95// Setup the control endpoint 0.
96static void bus_reset(void)
97{
98 for (int ep_num = 0; ep_num < USB_OUT_EP_NUM; ep_num++) {
99 USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
100 }
101
102 // clear device address
103 USB0.dcfg &= ~USB_DEVADDR_M;
104
105 USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
106 USB0.doepmsk = USB_SETUPMSK_M | USB_XFERCOMPLMSK;
107 USB0.diepmsk = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/;
108
109 // "USB Data FIFOs" section in reference manual
110 // Peripheral FIFO architecture
111 //
112 // --------------- 320 or 1024 ( 1280 or 4096 bytes )
113 // | IN FIFO MAX |
114 // ---------------
115 // | ... |
116 // --------------- y + x + 16 + GRXFSIZ
117 // | IN FIFO 2 |
118 // --------------- x + 16 + GRXFSIZ
119 // | IN FIFO 1 |
120 // --------------- 16 + GRXFSIZ
121 // | IN FIFO 0 |
122 // --------------- GRXFSIZ
123 // | OUT FIFO |
124 // | ( Shared ) |
125 // --------------- 0
126 //
127 // According to "FIFO RAM allocation" section in RM, FIFO RAM are allocated as follows (each word 32-bits):
128 // - Each EP IN needs at least max packet size, 16 words is sufficient for EP0 IN
129 //
130 // - All EP OUT shared a unique OUT FIFO which uses
131 // * 10 locations in hardware for setup packets + setup control words (up to 3 setup packets).
132 // * 2 locations for OUT endpoint control words.
133 // * 16 for largest packet size of 64 bytes. ( TODO Highspeed is 512 bytes)
134 // * 1 location for global NAK (not required/used here).
135 // * It is recommended to allocate 2 times the largest packet size, therefore
136 // Recommended value = 10 + 1 + 2 x (16+2) = 47 --> Let's make it 52
137 USB0.grstctl |= 0x10 << USB_TXFNUM_S; // fifo 0x10,
138 USB0.grstctl |= USB_TXFFLSH_M; // Flush fifo
139 USB0.grxfsiz = 52;
140
141 // Control IN uses FIFO 0 with 64 bytes ( 16 32-bit word )
142 USB0.gnptxfsiz = (16 << USB_NPTXFDEP_S) | (USB0.grxfsiz & 0x0000ffffUL);
143
144 // Ready to receive SETUP packet
145 USB0.out_ep_reg[0].doeptsiz |= USB_SUPCNT0_M;
146
147 USB0.gintmsk |= USB_IEPINTMSK_M | USB_OEPINTMSK_M;
148}
149
150static void enum_done_processing(void)
151{
152 ESP_EARLY_LOGV(TAG, "dcd_int_handler - Speed enumeration done! Sending DCD_EVENT_BUS_RESET then");
153 // On current silicon on the Full Speed core, speed is fixed to Full Speed.
154 // However, keep for debugging and in case Low Speed is ever supported.
155 uint32_t enum_spd = (USB0.dsts >> USB_ENUMSPD_S) & (USB_ENUMSPD_V);
156
157 // Maximum packet size for EP 0 is set for both directions by writing DIEPCTL
158 if (enum_spd == 0x03) { // Full-Speed (PHY on 48 MHz)
159 USB0.in_ep_reg[0].diepctl &= ~USB_D_MPS0_V; // 64 bytes
160 USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
163 } else {
164 USB0.in_ep_reg[0].diepctl |= USB_D_MPS0_V; // 8 bytes
165 USB0.in_ep_reg[0].diepctl &= ~USB_D_STALL0_M; // clear Stall
168 }
169}
170
171
172/*------------------------------------------------------------------*/
173/* Controller API
174 *------------------------------------------------------------------*/
175bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
176 (void) rh_init;
177 ESP_LOGV(TAG, "DCD init - Start");
178
179 // A. Disconnect
180 ESP_LOGV(TAG, "DCD init - Soft DISCONNECT and Setting up");
181 USB0.dctl |= USB_SFTDISCON_M; // Soft disconnect
182
183 // B. Programming DCFG
184 /* If USB host misbehaves during status portion of control xfer
185 (non zero-length packet), send STALL back and discard. Full speed. */
186 USB0.dcfg |= USB_NZSTSOUTHSHK_M | // NonZero .... STALL
187 (3 << 0); // dev speed: fullspeed 1.1 on 48 mhz // TODO no value in usb_reg.h (IDF-1476)
188
189 USB0.gahbcfg |= USB_NPTXFEMPLVL_M | USB_GLBLLNTRMSK_M; // Global interruptions ON
190 USB0.gusbcfg |= USB_FORCEDEVMODE_M; // force devmode
191 USB0.gotgctl &= ~(USB_BVALIDOVVAL_M | USB_BVALIDOVEN_M | USB_VBVALIDOVVAL_M); //no overrides
192
193 // C. Setting SNAKs, then connect
194 for (int n = 0; n < USB_OUT_EP_NUM; n++) {
195 USB0.out_ep_reg[n].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK
196 }
197
198 // D. Interruption masking
199 USB0.gintmsk = 0; //mask all
200 USB0.gotgint = ~0U; //clear OTG ints
201 USB0.gintsts = ~0U; //clear pending ints
202 USB0.gintmsk = USB_OTGINTMSK_M |
203 USB_MODEMISMSK_M |
204 USB_RXFLVIMSK_M |
205 USB_ERLYSUSPMSK_M |
206 USB_USBSUSPMSK_M |
207 USB_USBRSTMSK_M |
208 USB_ENUMDONEMSK_M |
209 USB_RESETDETMSK_M |
210 USB_WKUPINT_M |
211 USB_DISCONNINTMSK_M; // host most only
212
213 dcd_connect(rhport);
214 return true;
215}
216
217void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
218{
219 (void)rhport;
220 ESP_LOGV(TAG, "DCD init - Set address : %u", dev_addr);
221 USB0.dcfg |= ((dev_addr & USB_DEVADDR_V) << USB_DEVADDR_S);
222 // Response with status after changing device address
223 dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
224}
225
226void dcd_remote_wakeup(uint8_t rhport)
227{
228 (void)rhport;
229
230 // set remote wakeup
231 USB0.dctl |= USB_RMTWKUPSIG_M;
232
233 // enable SOF to detect bus resume
234 USB0.gintsts = USB_SOF_M;
235 USB0.gintmsk |= USB_SOFMSK_M;
236
237 // Per specs: remote wakeup signal bit must be clear within 1-15ms
238 vTaskDelay(pdMS_TO_TICKS(1));
239
240 USB0.dctl &= ~USB_RMTWKUPSIG_M;
241}
242
243// connect by enabling internal pull-up resistor on D+/D-
244void dcd_connect(uint8_t rhport)
245{
246 (void) rhport;
247 USB0.dctl &= ~USB_SFTDISCON_M;
248}
249
250// disconnect by disabling internal pull-up resistor on D+/D-
251void dcd_disconnect(uint8_t rhport)
252{
253 (void) rhport;
254 USB0.dctl |= USB_SFTDISCON_M;
255}
256
257void dcd_sof_enable(uint8_t rhport, bool en)
258{
259 (void) rhport;
260 (void) en;
261
262 // TODO implement later
263}
264
265/*------------------------------------------------------------------*/
266/* DCD Endpoint port
267 *------------------------------------------------------------------*/
268
269bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
270{
271 ESP_LOGV(TAG, "DCD endpoint opened");
272 (void)rhport;
273
274 usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
275 usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
276
277 uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
278 uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
279
280 TU_ASSERT(epnum < EP_MAX);
281
282 xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
283 xfer->max_size = tu_edpt_packet_size(desc_edpt);
284 xfer->interval = desc_edpt->bInterval;
285
286 if (dir == TUSB_DIR_OUT) {
287 out_ep[epnum].doepctl |= USB_USBACTEP1_M |
288 desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S |
289 (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) |
290 xfer->max_size << USB_MPS1_S;
291 USB0.daintmsk |= (1 << (16 + epnum));
292 } else {
293 // "USB Data FIFOs" section in reference manual
294 // Peripheral FIFO architecture
295 //
296 // --------------- 320 or 1024 ( 1280 or 4096 bytes )
297 // | IN FIFO MAX |
298 // ---------------
299 // | ... |
300 // --------------- y + x + 16 + GRXFSIZ
301 // | IN FIFO 2 |
302 // --------------- x + 16 + GRXFSIZ
303 // | IN FIFO 1 |
304 // --------------- 16 + GRXFSIZ
305 // | IN FIFO 0 |
306 // --------------- GRXFSIZ
307 // | OUT FIFO |
308 // | ( Shared ) |
309 // --------------- 0
310 //
311 // Since OUT FIFO = GRXFSIZ, FIFO 0 = 16, for simplicity, we equally allocated for the rest of endpoints
312 // - Size : (FIFO_SIZE/4 - GRXFSIZ - 16) / (EP_MAX-1)
313 // - Offset: GRXFSIZ + 16 + Size*(epnum-1)
314 // - IN EP 1 gets FIFO 1, IN EP "n" gets FIFO "n".
315
316 uint8_t fifo_num = get_free_fifo();
317 TU_ASSERT(fifo_num != 0);
318
319 in_ep[epnum].diepctl &= ~(USB_D_TXFNUM1_M | USB_D_EPTYPE1_M | USB_DI_SETD0PID1 | USB_D_MPS1_M);
320 in_ep[epnum].diepctl |= USB_D_USBACTEP1_M |
321 fifo_num << USB_D_TXFNUM1_S |
322 desc_edpt->bmAttributes.xfer << USB_D_EPTYPE1_S |
323 (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? (1 << USB_DI_SETD0PID1_S) : 0) |
324 xfer->max_size << 0;
325
326 USB0.daintmsk |= (1 << (0 + epnum));
327
328 // Both TXFD and TXSA are in unit of 32-bit words.
329 // IN FIFO 0 was configured during enumeration, hence the "+ 16".
330 uint16_t const allocated_size = (USB0.grxfsiz & 0x0000ffff) + 16;
331 uint16_t const fifo_size = (EP_FIFO_SIZE/4 - allocated_size) / (EP_FIFO_NUM-1);
332 uint32_t const fifo_offset = allocated_size + fifo_size*(fifo_num-1);
333
334 // DIEPTXF starts at FIFO #1.
335 USB0.dieptxf[epnum - 1] = (fifo_size << USB_NPTXFDEP_S) | fifo_offset;
336 }
337 return true;
338}
339
340void dcd_edpt_close_all(uint8_t rhport)
341{
342 (void) rhport;
343
344 usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
345 usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
346
347 // Disable non-control interrupt
348 USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M;
349
350 for(uint8_t n = 1; n < EP_MAX; n++)
351 {
352 // disable OUT endpoint
353 out_ep[n].doepctl = 0;
355
356 // disable IN endpoint
357 in_ep[n].diepctl = 0;
359 }
360
362}
363
364bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
365{
366 (void)rhport;
367
368 uint8_t const epnum = tu_edpt_number(ep_addr);
369 uint8_t const dir = tu_edpt_dir(ep_addr);
370
371 xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir);
372 xfer->buffer = buffer;
373 // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
375 xfer->queued_len = 0;
376 xfer->short_packet = false;
377
378 uint16_t num_packets = (total_bytes / xfer->max_size);
379 uint8_t short_packet_size = total_bytes % xfer->max_size;
380
381 // Zero-size packet is special case.
382 if (short_packet_size > 0 || (total_bytes == 0)) {
383 num_packets++;
384 }
385
386 ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i",
387 epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"),
388 num_packets, total_bytes);
389
390 // IN and OUT endpoint xfers are interrupt-driven, we just schedule them
391 // here.
392 if (dir == TUSB_DIR_IN) {
393 // A full IN transfer (multiple packets, possibly) triggers XFRC.
394 USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes;
395 USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK
396
397 // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
398 if ((USB0.in_ep_reg[epnum].diepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
399 // Take odd/even bit from frame counter.
400 uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
401 USB0.in_ep_reg[epnum].diepctl |= (odd_frame_now ? USB_DI_SETD0PID1 : USB_DI_SETD1PID1);
402 }
403
404 // Enable fifo empty interrupt only if there are something to put in the fifo.
405 if(total_bytes != 0) {
406 USB0.dtknqr4_fifoemptymsk |= (1 << epnum);
407 }
408 } else {
409 // Each complete packet for OUT xfers triggers XFRC.
410 USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
411 USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
412
413 // For ISO endpoint with interval=1 set correct DATA0/DATA1 bit for next frame
414 if ((USB0.out_ep_reg[epnum].doepctl & USB_D_EPTYPE0_M) == (1 << USB_D_EPTYPE1_S) && xfer->interval == 1) {
415 // Take odd/even bit from frame counter.
416 uint32_t const odd_frame_now = (USB0.dsts & (1u << USB_SOFFN_S));
417 USB0.out_ep_reg[epnum].doepctl |= (odd_frame_now ? USB_DO_SETD0PID1 : USB_DO_SETD1PID1);
418 }
419 }
420 return true;
421}
422
423#if 0 // TODO support dcd_edpt_xfer_fifo API
424bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
425{
426 (void)rhport;
427}
428#endif
429
430void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
431{
432 (void)rhport;
433
434 usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
435 usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
436
437 uint8_t const epnum = tu_edpt_number(ep_addr);
438 uint8_t const dir = tu_edpt_dir(ep_addr);
439
440 if (dir == TUSB_DIR_IN) {
441 // Only disable currently enabled non-control endpoint
442 if ((epnum == 0) || !(in_ep[epnum].diepctl & USB_D_EPENA1_M)) {
443 in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M);
444 } else {
445 // Stop transmitting packets and NAK IN xfers.
446 in_ep[epnum].diepctl |= USB_DI_SNAK1_M;
447 while ((in_ep[epnum].diepint & USB_DI_SNAK1_M) == 0) ;
448
449 // Disable the endpoint. Note that both SNAK and STALL are set here.
450 in_ep[epnum].diepctl |= (USB_DI_SNAK1_M | USB_D_STALL1_M | USB_D_EPDIS1_M);
451 while ((in_ep[epnum].diepint & USB_D_EPDISBLD0_M) == 0) ;
452 in_ep[epnum].diepint = USB_D_EPDISBLD0_M;
453 }
454
455 // Flush the FIFO, and wait until we have confirmed it cleared.
456 uint8_t const fifo_num = ((in_ep[epnum].diepctl >> USB_D_TXFNUM1_S) & USB_D_TXFNUM1_V);
457 USB0.grstctl |= (fifo_num << USB_TXFNUM_S);
458 USB0.grstctl |= USB_TXFFLSH_M;
459 while ((USB0.grstctl & USB_TXFFLSH_M) != 0) ;
460 } else {
461 // Only disable currently enabled non-control endpoint
462 if ((epnum == 0) || !(out_ep[epnum].doepctl & USB_EPENA0_M)) {
463 out_ep[epnum].doepctl |= USB_STALL0_M;
464 } else {
465 // Asserting GONAK is required to STALL an OUT endpoint.
466 // Simpler to use polling here, we don't use the "B"OUTNAKEFF interrupt
467 // anyway, and it can't be cleared by user code. If this while loop never
468 // finishes, we have bigger problems than just the stack.
469 USB0.dctl |= USB_SGOUTNAK_M;
470 while ((USB0.gintsts & USB_GOUTNAKEFF_M) == 0) ;
471
472 // Ditto here- disable the endpoint. Note that only STALL and not SNAK
473 // is set here.
474 out_ep[epnum].doepctl |= (USB_STALL0_M | USB_EPDIS0_M);
475 while ((out_ep[epnum].doepint & USB_EPDISBLD0_M) == 0) ;
476 out_ep[epnum].doepint = USB_EPDISBLD0_M;
477
478 // Allow other OUT endpoints to keep receiving.
479 USB0.dctl |= USB_CGOUTNAK_M;
480 }
481 }
482}
483
484void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
485{
486 (void)rhport;
487
488 usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]);
489 usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]);
490
491 uint8_t const epnum = tu_edpt_number(ep_addr);
492 uint8_t const dir = tu_edpt_dir(ep_addr);
493
494 if (dir == TUSB_DIR_IN) {
495 in_ep[epnum].diepctl &= ~USB_D_STALL1_M;
496
497 uint8_t eptype = (in_ep[epnum].diepctl & USB_D_EPTYPE1_M) >> USB_D_EPTYPE1_S;
498 // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
499 // and bulk endpoints.
500 if (eptype == 2 || eptype == 3) {
501 in_ep[epnum].diepctl |= USB_DI_SETD0PID1_M;
502 }
503 } else {
504 out_ep[epnum].doepctl &= ~USB_STALL1_M;
505
506 uint8_t eptype = (out_ep[epnum].doepctl & USB_EPTYPE1_M) >> USB_EPTYPE1_S;
507 // Required by USB spec to reset DATA toggle bit to DATA0 on interrupt
508 // and bulk endpoints.
509 if (eptype == 2 || eptype == 3) {
510 out_ep[epnum].doepctl |= USB_DO_SETD0PID1_M;
511 }
512 }
513}
514
515/*------------------------------------------------------------------*/
516
517static void receive_packet(xfer_ctl_t *xfer, /* usb_out_endpoint_t * out_ep, */ uint16_t xfer_size)
518{
519 ESP_EARLY_LOGV(TAG, "USB - receive_packet");
520 volatile uint32_t *rx_fifo = USB0.fifo[0];
521
522 // See above TODO
523 // uint16_t remaining = (out_ep->DOEPTSIZ & UsbDOEPTSIZ_XFRSIZ_Msk) >> UsbDOEPTSIZ_XFRSIZ_Pos;
524 // xfer->queued_len = xfer->total_len - remaining;
525
526 uint16_t remaining = xfer->total_len - xfer->queued_len;
527 uint16_t to_recv_size;
528
529 if (remaining <= xfer->max_size) {
530 // Avoid buffer overflow.
531 to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
532 } else {
533 // Room for full packet, choose recv_size based on what the microcontroller
534 // claims.
535 to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
536 }
537
538 // Common buffer read
539#if 0 // TODO support dcd_edpt_xfer_fifo API
540 if (xfer->ff)
541 {
542 // Ring buffer
543 tu_fifo_write_n_const_addr_full_words(xfer->ff, (const void *) rx_fifo, to_recv_size);
544 }
545 else
546#endif
547 {
548 uint8_t to_recv_rem = to_recv_size % 4;
549 uint16_t to_recv_size_aligned = to_recv_size - to_recv_rem;
550
551 // Do not assume xfer buffer is aligned.
552 uint8_t *base = (xfer->buffer + xfer->queued_len);
553
554 // This for loop always runs at least once- skip if less than 4 bytes
555 // to collect.
556 if (to_recv_size >= 4) {
557 for (uint16_t i = 0; i < to_recv_size_aligned; i += 4) {
558 uint32_t tmp = (*rx_fifo);
559 base[i] = tmp & 0x000000FF;
560 base[i + 1] = (tmp & 0x0000FF00) >> 8;
561 base[i + 2] = (tmp & 0x00FF0000) >> 16;
562 base[i + 3] = (tmp & 0xFF000000) >> 24;
563 }
564 }
565
566 // Do not read invalid bytes from RX FIFO.
567 if (to_recv_rem != 0) {
568 uint32_t tmp = (*rx_fifo);
569 uint8_t *last_32b_bound = base + to_recv_size_aligned;
570
571 last_32b_bound[0] = tmp & 0x000000FF;
572 if (to_recv_rem > 1) {
573 last_32b_bound[1] = (tmp & 0x0000FF00) >> 8;
574 }
575 if (to_recv_rem > 2) {
576 last_32b_bound[2] = (tmp & 0x00FF0000) >> 16;
577 }
578 }
579 }
580
581 xfer->queued_len += xfer_size;
582
583 // Per USB spec, a short OUT packet (including length 0) is always
584 // indicative of the end of a transfer (at least for ctl, bulk, int).
585 xfer->short_packet = (xfer_size < xfer->max_size);
586}
587
588static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint8_t fifo_num)
589{
590 ESP_EARLY_LOGV(TAG, "USB - transmit_packet");
591 volatile uint32_t *tx_fifo = USB0.fifo[fifo_num];
592
593 uint16_t remaining = (in_ep->dieptsiz & 0x7FFFFU) >> USB_D_XFERSIZE0_S;
594 xfer->queued_len = xfer->total_len - remaining;
595
596 uint16_t to_xfer_size = (remaining > xfer->max_size) ? xfer->max_size : remaining;
597
598#if 0 // TODO support dcd_edpt_xfer_fifo API
599 if (xfer->ff)
600 {
601 tu_fifo_read_n_const_addr_full_words(xfer->ff, (void *) tx_fifo, to_xfer_size);
602 }
603 else
604#endif
605 {
606 uint8_t to_xfer_rem = to_xfer_size % 4;
607 uint16_t to_xfer_size_aligned = to_xfer_size - to_xfer_rem;
608
609 // Buffer might not be aligned to 32b, so we need to force alignment
610 // by copying to a temp var.
611 uint8_t *base = (xfer->buffer + xfer->queued_len);
612
613 // This for loop always runs at least once- skip if less than 4 bytes
614 // to send off.
615 if (to_xfer_size >= 4) {
616 for (uint16_t i = 0; i < to_xfer_size_aligned; i += 4) {
617 uint32_t tmp = base[i] | (base[i + 1] << 8) |
618 (base[i + 2] << 16) | (base[i + 3] << 24);
619 (*tx_fifo) = tmp;
620 }
621 }
622
623 // Do not read beyond end of buffer if not divisible by 4.
624 if (to_xfer_rem != 0) {
625 uint32_t tmp = 0;
626 uint8_t *last_32b_bound = base + to_xfer_size_aligned;
627
628 tmp |= last_32b_bound[0];
629 if (to_xfer_rem > 1) {
630 tmp |= (last_32b_bound[1] << 8);
631 }
632 if (to_xfer_rem > 2) {
633 tmp |= (last_32b_bound[2] << 16);
634 }
635
636 (*tx_fifo) = tmp;
637 }
638 }
639}
640
641static void read_rx_fifo(void)
642{
643 // Pop control word off FIFO (completed xfers will have 2 control words,
644 // we only pop one ctl word each interrupt).
645 uint32_t const ctl_word = USB0.grxstsp;
646 uint8_t const pktsts = (ctl_word & USB_PKTSTS_M) >> USB_PKTSTS_S;
647 uint8_t const epnum = (ctl_word & USB_CHNUM_M ) >> USB_CHNUM_S;
648 uint16_t const bcnt = (ctl_word & USB_BCNT_M ) >> USB_BCNT_S;
649
650 switch (pktsts) {
651 case 0x01: // Global OUT NAK (Interrupt)
652 ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Global OUT NAK");
653 break;
654
655 case 0x02: { // Out packet recvd
656 ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet");
657 xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
658 receive_packet(xfer, bcnt);
659 }
660 break;
661
662 case 0x03: // Out packet done (Interrupt)
663 ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX type : Out packet done");
664 break;
665
666 case 0x04: // Step 2: Setup transaction completed (Interrupt)
667 // After this event, OEPINT interrupt will occur with SETUP bit set
668 ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet done");
669 USB0.out_ep_reg[epnum].doeptsiz |= USB_SUPCNT0_M;
670 break;
671
672 case 0x06: { // Step1: Setup data packet received
673 volatile uint32_t *rx_fifo = USB0.fifo[0];
674
675 // We can receive up to three setup packets in succession, but
676 // only the last one is valid. Therefore we just overwrite it
677 _setup_packet[0] = (*rx_fifo);
678 _setup_packet[1] = (*rx_fifo);
679
680 ESP_EARLY_LOGV(TAG, "TUSB IRQ - RX : Setup packet : 0x%08x 0x%08x", _setup_packet[0], _setup_packet[1]);
681 }
682 break;
683
684 default: // Invalid, do something here, like breakpoint?
685 TU_BREAKPOINT();
686 break;
687 }
688}
689
690static void handle_epout_ints(void)
691{
692 // GINTSTS will be cleared with DAINT == 0
693 // DAINT for a given EP clears when DOEPINTx is cleared.
694 // DOEPINT will be cleared when DAINT's out bits are cleared.
695 for (int n = 0; n < USB_OUT_EP_NUM; n++) {
696 xfer_ctl_t *xfer = XFER_CTL_BASE(n, TUSB_DIR_OUT);
697
698 if (USB0.daint & (1 << (16 + n))) {
699 // SETUP packet Setup Phase done.
700 if ((USB0.out_ep_reg[n].doepint & USB_SETUP0_M)) {
701 USB0.out_ep_reg[n].doepint = USB_STUPPKTRCVD0_M | USB_SETUP0_M; // clear
702 dcd_event_setup_received(0, (uint8_t *)&_setup_packet[0], true);
703 }
704
705 // OUT XFER complete (single packet).q
706 if (USB0.out_ep_reg[n].doepint & USB_XFERCOMPL0_M) {
707
708 ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP OUT - XFER complete (single packet)");
709 USB0.out_ep_reg[n].doepint = USB_XFERCOMPL0_M;
710
711 // Transfer complete if short packet or total len is transferred
712 if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
713 xfer->short_packet = false;
714 dcd_event_xfer_complete(0, n, xfer->queued_len, XFER_RESULT_SUCCESS, true);
715 } else {
716 // Schedule another packet to be received.
717 USB0.out_ep_reg[n].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S);
718 USB0.out_ep_reg[n].doepctl |= USB_EPENA0_M | USB_CNAK0_M;
719 }
720 }
721 }
722 }
723}
724
725static void handle_epin_ints(void)
726{
727 // GINTSTS will be cleared with DAINT == 0
728 // DAINT for a given EP clears when DIEPINTx is cleared.
729 // IEPINT will be cleared when DAINT's out bits are cleared.
730 for (uint32_t n = 0; n < USB_IN_EP_NUM; n++) {
732
733 if (USB0.daint & (1 << (0 + n))) {
734 ESP_EARLY_LOGV(TAG, "TUSB IRQ - EP IN %u", n);
735 // IN XFER complete (entire xfer).
736 if (USB0.in_ep_reg[n].diepint & USB_D_XFERCOMPL0_M) {
737 ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER complete!");
738 USB0.in_ep_reg[n].diepint = USB_D_XFERCOMPL0_M;
740 }
741
742 // XFER FIFO empty
743 if (USB0.in_ep_reg[n].diepint & USB_D_TXFEMP0_M) {
744 ESP_EARLY_LOGV(TAG, "TUSB IRQ - IN XFER FIFO empty!");
745 USB0.in_ep_reg[n].diepint = USB_D_TXFEMP0_M;
746 transmit_packet(xfer, &USB0.in_ep_reg[n], n);
747
748 // Turn off TXFE if all bytes are written.
749 if (xfer->queued_len == xfer->total_len)
750 {
751 USB0.dtknqr4_fifoemptymsk &= ~(1 << n);
752 }
753 }
754
755 // XFER Timeout
756 if (USB0.in_ep_reg[n].diepint & USB_D_TIMEOUT0_M) {
757 // Clear interrupt or endpoint will hang.
758 USB0.in_ep_reg[n].diepint = USB_D_TIMEOUT0_M;
759 // Maybe retry?
760 }
761 }
762 }
763}
764
765
766static void _dcd_int_handler(void* arg)
767{
768 (void) arg;
769 uint8_t const rhport = 0;
770
771 const uint32_t int_msk = USB0.gintmsk;
772 const uint32_t int_status = USB0.gintsts & int_msk;
773
774 if (int_status & USB_USBRST_M) {
775 // start of reset
776 ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset");
777 USB0.gintsts = USB_USBRST_M;
778 // FIFOs will be reassigned when the endpoints are reopen
780 bus_reset();
781 }
782
783 if (int_status & USB_RESETDET_M) {
784 ESP_EARLY_LOGV(TAG, "dcd_int_handler - reset while suspend");
785 USB0.gintsts = USB_RESETDET_M;
786 bus_reset();
787 }
788
789 if (int_status & USB_ENUMDONE_M) {
790 // ENUMDNE detects speed of the link. For full-speed, we
791 // always expect the same value. This interrupt is considered
792 // the end of reset.
793 USB0.gintsts = USB_ENUMDONE_M;
796 }
797
798 if(int_status & USB_USBSUSP_M)
799 {
800 USB0.gintsts = USB_USBSUSP_M;
801 dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
802 }
803
804 if(int_status & USB_WKUPINT_M)
805 {
806 USB0.gintsts = USB_WKUPINT_M;
807 dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
808 }
809
810 if (int_status & USB_OTGINT_M)
811 {
812 // OTG INT bit is read-only
813 ESP_EARLY_LOGV(TAG, "dcd_int_handler - disconnected");
814
815 uint32_t const otg_int = USB0.gotgint;
816
817 if (otg_int & USB_SESENDDET_M)
818 {
819 dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true);
820 }
821
822 USB0.gotgint = otg_int;
823 }
824
825 if (int_status & USB_SOF_M) {
826 USB0.gintsts = USB_SOF_M;
827
828 // Disable SOF interrupt since currently only used for remote wakeup detection
829 USB0.gintmsk &= ~USB_SOFMSK_M;
830
831 dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
832 }
833
834
835 if (int_status & USB_RXFLVI_M) {
836 // RXFLVL bit is read-only
837 ESP_EARLY_LOGV(TAG, "dcd_int_handler - rx!");
838
839 // Mask out RXFLVL while reading data from FIFO
840 USB0.gintmsk &= ~USB_RXFLVIMSK_M;
841 read_rx_fifo();
842 USB0.gintmsk |= USB_RXFLVIMSK_M;
843 }
844
845 // OUT endpoint interrupt handling.
846 if (int_status & USB_OEPINT_M) {
847 // OEPINT is read-only
848 ESP_EARLY_LOGV(TAG, "dcd_int_handler - OUT endpoint!");
850 }
851
852 // IN endpoint interrupt handling.
853 if (int_status & USB_IEPINT_M) {
854 // IEPINT bit read-only
855 ESP_EARLY_LOGV(TAG, "dcd_int_handler - IN endpoint!");
857 }
858
859 // Without handling
860 USB0.gintsts |= USB_CURMOD_INT_M |
861 USB_MODEMIS_M |
862 USB_OTGINT_M |
863 USB_NPTXFEMP_M |
864 USB_GINNAKEFF_M |
865 USB_GOUTNAKEFF |
866 USB_ERLYSUSP_M |
867 USB_USBSUSP_M |
868 USB_ISOOUTDROP_M |
869 USB_EOPF_M |
870 USB_EPMIS_M |
871 USB_INCOMPISOIN_M |
872 USB_INCOMPIP_M |
873 USB_FETSUSP_M |
874 USB_PTXFEMP_M;
875}
876
877void dcd_int_enable (uint8_t rhport)
878{
879 (void) rhport;
880 esp_intr_alloc(ETS_USB_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, (intr_handler_t) _dcd_int_handler, NULL, &usb_ih);
881}
882
883void dcd_int_disable (uint8_t rhport)
884{
885 (void) rhport;
886 esp_intr_free(usb_ih);
887}
888
889#endif // #if OPT_MCU_ESP32S2 || OPT_MCU_ESP32S3
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_signal(uint8_t rhport, dcd_eventid_t eid, bool in_isr)
Definition: dcd.h:196
static TU_ATTR_ALWAYS_INLINE void dcd_event_xfer_complete(uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
Definition: dcd.h:222
static TU_ATTR_ALWAYS_INLINE void dcd_event_setup_received(uint8_t rhport, uint8_t const *setup, bool in_isr)
Definition: dcd.h:213
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_reset(uint8_t rhport, tusb_speed_t speed, bool in_isr)
Definition: dcd.h:204
xfer_ctl_t
Definition: dcd_dwc2.c:52
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
Definition: dcd_esp32sx.c:424
static uint32_t _setup_packet[2]
Definition: dcd_esp32sx.c:80
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_esp32sx.c:430
static void transmit_packet(xfer_ctl_t *xfer, volatile usb_in_endpoint_t *in_ep, uint8_t fifo_num)
Definition: dcd_esp32sx.c:588
static void bus_reset(void)
Definition: dcd_esp32sx.c:96
static const char * TAG
Definition: dcd_esp32sx.c:76
void dcd_disconnect(uint8_t rhport)
Definition: dcd_esp32sx.c:251
static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size)
Definition: dcd_esp32sx.c:517
static xfer_ctl_t xfer_status[EP_MAX][2]
Definition: dcd_esp32sx.c:83
void dcd_edpt_close_all(uint8_t rhport)
Definition: dcd_esp32sx.c:340
void dcd_int_disable(uint8_t rhport)
Definition: dcd_esp32sx.c:883
static void handle_epout_ints(void)
Definition: dcd_esp32sx.c:690
static void _dcd_int_handler(void *arg)
Definition: dcd_esp32sx.c:766
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_esp32sx.c:484
void dcd_connect(uint8_t rhport)
Definition: dcd_esp32sx.c:244
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
Definition: dcd_esp32sx.c:269
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: dcd_esp32sx.c:364
static void read_rx_fifo(void)
Definition: dcd_esp32sx.c:641
static uint8_t _allocated_fifos
Definition: dcd_esp32sx.c:86
static void handle_epin_ints(void)
Definition: dcd_esp32sx.c:725
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
Definition: dcd_esp32sx.c:217
static void enum_done_processing(void)
Definition: dcd_esp32sx.c:150
static intr_handle_t usb_ih
Definition: dcd_esp32sx.c:77
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: dcd_esp32sx.c:175
static uint8_t get_free_fifo(void)
Definition: dcd_esp32sx.c:89
void dcd_int_enable(uint8_t rhport)
Definition: dcd_esp32sx.c:877
void dcd_remote_wakeup(uint8_t rhport)
Definition: dcd_esp32sx.c:226
void dcd_sof_enable(uint8_t rhport, bool en)
Definition: dcd_esp32sx.c:257
xfer_td_t xfer[EP_CBI_COUNT+1][2]
Definition: dcd_nrf5x.c:119
uint16_t total_bytes
Definition: dcd_nuc505.c:113
uint8_t dev_addr
Definition: dcd_pic32mz.c:81
uint8_t const * buffer
Definition: midi_device.h:100
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint8_t bInterval
Definition: tusb_types.h:372
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint8_t bEndpointAddress
Definition: video.h:306
uint16_t max_size
Definition: dcd_esp32sx.c:71
uint16_t queued_len
Definition: dcd_esp32sx.c:70
uint8_t interval
Definition: dcd_esp32sx.c:73
bool short_packet
Definition: dcd_esp32sx.c:72
uint16_t total_len
Definition: dcd_nrf5x.c:100
uint8_t * buffer
Definition: dcd_nrf5x.c:99
uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t *f, const void *data, uint16_t n)
This function will write n elements into the array index specified by the write pointer and increment...
Definition: tusb_fifo.c:882
uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t *f, void *buffer, uint16_t n)
This function will read n elements from the array index specified by the read pointer and increment t...
Definition: tusb_fifo.c:753
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_DIR_IN_MASK
Definition: tusb_types.h:69
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
Definition: tusb_types.h:507
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
Definition: tusb_types.h:511