Open FFBoard
Open source force feedback firmware
dcd_samx7x.c
Go to the documentation of this file.
1/*
2* The MIT License (MIT)
3*
4* Copyright (c) 2018, hathach (tinyusb.org)
5* Copyright (c) 2021, HiFiPhile
6*
7* Permission is hereby granted, free of charge, to any person obtaining a copy
8* of this software and associated documentation files (the "Software"), to deal
9* in the Software without restriction, including without limitation the rights
10* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11* copies of the Software, and to permit persons to whom the Software is
12* furnished to do so, subject to the following conditions:
13*
14* The above copyright notice and this permission notice shall be included in
15* all copies or substantial portions of the Software.
16*
17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23* THE SOFTWARE.
24*
25* This file is part of the TinyUSB stack.
26*/
27
28#include "tusb_option.h"
29
30#if CFG_TUD_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMX7X
31
32#include "device/dcd.h"
33#include "sam.h"
34#include "common_usb_regs.h"
35//--------------------------------------------------------------------+
36// MACRO TYPEDEF CONSTANT ENUM DECLARATION
37//--------------------------------------------------------------------+
38
39// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval)
40// We disable SOF for now until needed later on
41#ifndef USE_SOF
42# define USE_SOF 0
43#endif
44
45// Dual bank can improve performance, but need 2 times bigger packet buffer
46// As SAM7x has only 4KB packet buffer, use with caution !
47// Enable in FS mode as packets are smaller
48#ifndef USE_DUAL_BANK
49# if TUD_OPT_HIGH_SPEED
50# define USE_DUAL_BANK 0
51# else
52# define USE_DUAL_BANK 1
53# endif
54#endif
55
56#define EP_GET_FIFO_PTR(ep, scale) (((TU_XSTRCAT(TU_STRCAT(uint, scale),_t) (*)[0x8000 / ((scale) / 8)])FIFO_RAM_ADDR)[(ep)])
57
58// DMA Channel Transfer Descriptor
59typedef struct {
60 volatile uint32_t next_desc;
61 volatile uint32_t buff_addr;
62 volatile uint32_t chnl_ctrl;
63 uint32_t padding;
65
66// Transfer control context
67typedef struct {
68 uint8_t * buffer;
69 uint16_t total_len;
70 uint16_t queued_len;
71 uint16_t max_packet_size;
72 uint8_t interval;
75
76static tusb_speed_t get_speed(void);
77static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix);
78
79// DMA descriptors shouldn't be placed in ITCM !
80CFG_TUD_MEM_SECTION static dma_desc_t dma_desc[6];
81
82static xfer_ctl_t xfer_status[EP_MAX];
83
85{
86 .bEndpointAddress = 0x00,
87 .wMaxPacketSize = CFG_TUD_ENDPOINT0_SIZE,
88};
89
90TU_ATTR_ALWAYS_INLINE static inline void CleanInValidateCache(uint32_t *addr, int32_t size)
91{
92 if (SCB->CCR & SCB_CCR_DC_Msk)
93 {
94 SCB_CleanInvalidateDCache_by_Addr(addr, size);
95 }
96 else
97 {
98 __DSB();
99 __ISB();
100 }
101}
102//------------------------------------------------------------------
103// Device API
104//------------------------------------------------------------------
105
106// Initialize controller to device mode
107bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
108 (void) rh_init;
109 dcd_connect(rhport);
110 return true;
111}
112
113// Enable device interrupt
114void dcd_int_enable (uint8_t rhport)
115{
116 (void) rhport;
117 NVIC_EnableIRQ((IRQn_Type) ID_USBHS);
118}
119
120// Disable device interrupt
121void dcd_int_disable (uint8_t rhport)
122{
123 (void) rhport;
124 NVIC_DisableIRQ((IRQn_Type) ID_USBHS);
125}
126
127// Receive Set Address request, mcu port must also include status IN response
128void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
129{
130 (void) dev_addr;
131 // DCD can only set address after status for this request is complete
132 // do it at dcd_edpt0_status_complete()
133
134 // Response with zlp status
135 dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
136}
137
138// Wake up host
139void dcd_remote_wakeup (uint8_t rhport)
140{
141 (void) rhport;
142 USB_REG->DEVCTRL |= DEVCTRL_RMWKUP;
143}
144
145// Connect by enabling internal pull-up resistor on D+/D-
146void dcd_connect(uint8_t rhport)
147{
148 (void) rhport;
149 dcd_int_disable(rhport);
150 // Enable the USB controller in device mode
151 USB_REG->CTRL = CTRL_UIMOD | CTRL_USBE;
152 while (!(USB_REG->SR & SR_CLKUSABLE));
153#if TUD_OPT_HIGH_SPEED
154 USB_REG->DEVCTRL &= ~DEVCTRL_SPDCONF;
155#else
156 USB_REG->DEVCTRL |= DEVCTRL_SPDCONF_LOW_POWER;
157#endif
158 // Enable the End Of Reset, Suspend & Wakeup interrupts
159 USB_REG->DEVIER = (DEVIER_EORSTES | DEVIER_SUSPES | DEVIER_WAKEUPES);
160#if USE_SOF
161 USB_REG->DEVIER = DEVIER_SOFES;
162#endif
163 // Clear the End Of Reset, SOF & Wakeup interrupts
164 USB_REG->DEVICR = (DEVICR_EORSTC | DEVICR_SOFC | DEVICR_WAKEUPC);
165 // Manually set the Suspend Interrupt
166 USB_REG->DEVIFR |= DEVIFR_SUSPS;
167 // Ack the Wakeup Interrupt
168 USB_REG->DEVICR = DEVICR_WAKEUPC;
169 // Attach the device
170 USB_REG->DEVCTRL &= ~DEVCTRL_DETACH;
171 // Freeze USB clock
172 USB_REG->CTRL |= CTRL_FRZCLK;
173}
174
175// Disconnect by disabling internal pull-up resistor on D+/D-
176void dcd_disconnect(uint8_t rhport)
177{
178 (void) rhport;
179 dcd_int_disable(rhport);
180 // Disable all endpoints
181 USB_REG->DEVEPT &= ~(0x3FF << DEVEPT_EPEN0_Pos);
182 // Unfreeze USB clock
183 USB_REG->CTRL &= ~CTRL_FRZCLK;
184 while (!(USB_REG->SR & SR_CLKUSABLE));
185 // Clear all the pending interrupts
186 USB_REG->DEVICR = DEVICR_Msk;
187 // Disable all interrupts
188 USB_REG->DEVIDR = DEVIDR_Msk;
189 // Detach the device
190 USB_REG->DEVCTRL |= DEVCTRL_DETACH;
191 // Disable the device address
192 USB_REG->DEVCTRL &=~(DEVCTRL_ADDEN | DEVCTRL_UADD);
193}
194
195void dcd_sof_enable(uint8_t rhport, bool en)
196{
197 (void) rhport;
198 (void) en;
199
200 // TODO implement later
201}
202
204{
205 switch (USB_REG->SR & SR_SPEED) {
206 case SR_SPEED_FULL_SPEED:
207 default:
208 return TUSB_SPEED_FULL;
209 case SR_SPEED_HIGH_SPEED:
210 return TUSB_SPEED_HIGH;
211 case SR_SPEED_LOW_SPEED:
212 return TUSB_SPEED_LOW;
213 }
214}
215
216static void dcd_ep_handler(uint8_t ep_ix)
217{
218 uint32_t int_status = USB_REG->DEVEPTISR[ep_ix];
219 int_status &= USB_REG->DEVEPTIMR[ep_ix];
220
221 uint16_t count = (USB_REG->DEVEPTISR[ep_ix] &
222 DEVEPTISR_BYCT) >> DEVEPTISR_BYCT_Pos;
223 xfer_ctl_t *xfer = &xfer_status[ep_ix];
224
225 if (ep_ix == 0U)
226 {
227 static uint8_t ctrl_dir;
228
229 if (int_status & DEVEPTISR_CTRL_RXSTPI)
230 {
231 ctrl_dir = (USB_REG->DEVEPTISR[0] & DEVEPTISR_CTRL_CTRLDIR) >> DEVEPTISR_CTRL_CTRLDIR_Pos;
232 // Setup packet should always be 8 bytes. If not, ignore it, and try again.
233 if (count == 8)
234 {
235 uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
236 dcd_event_setup_received(0, ptr, true);
237 }
238 // Ack and disable SETUP interrupt
239 USB_REG->DEVEPTICR[0] = DEVEPTICR_CTRL_RXSTPIC;
240 USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_RXSTPEC;
241 }
242 if (int_status & DEVEPTISR_RXOUTI)
243 {
244 uint8_t *ptr = EP_GET_FIFO_PTR(0,8);
245
246 if (count && xfer->total_len)
247 {
248 uint16_t remain = xfer->total_len - xfer->queued_len;
249 if (count > remain)
250 {
251 count = remain;
252 }
253 if (xfer->buffer)
254 {
255 memcpy(xfer->buffer + xfer->queued_len, ptr, count);
256 } else
257 {
258 tu_fifo_write_n(xfer->fifo, ptr, count);
259 }
260 xfer->queued_len = (uint16_t)(xfer->queued_len + count);
261 }
262 // Acknowledge the interrupt
263 USB_REG->DEVEPTICR[0] = DEVEPTICR_RXOUTIC;
264 if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
265 {
266 // RX COMPLETE
267 dcd_event_xfer_complete(0, 0, xfer->queued_len, XFER_RESULT_SUCCESS, true);
268 // Disable the interrupt
269 USB_REG->DEVEPTIDR[0] = DEVEPTIDR_RXOUTEC;
270 // Re-enable SETUP interrupt
271 if (ctrl_dir == 1)
272 {
273 USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
274 }
275 }
276 }
277 if (int_status & DEVEPTISR_TXINI)
278 {
279 // Disable the interrupt
280 USB_REG->DEVEPTIDR[0] = DEVEPTIDR_TXINEC;
281 if ((xfer->total_len != xfer->queued_len))
282 {
283 // TX not complete
285 } else
286 {
287 // TX complete
289 // Re-enable SETUP interrupt
290 if (ctrl_dir == 0)
291 {
292 USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
293 }
294 }
295 }
296 } else
297 {
298 if (int_status & DEVEPTISR_RXOUTI)
299 {
300 if (count && xfer->total_len)
301 {
302 uint16_t remain = xfer->total_len - xfer->queued_len;
303 if (count > remain)
304 {
305 count = remain;
306 }
307 uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
308 if (xfer->buffer)
309 {
310 memcpy(xfer->buffer + xfer->queued_len, ptr, count);
311 } else {
312 tu_fifo_write_n(xfer->fifo, ptr, count);
313 }
314 xfer->queued_len = (uint16_t)(xfer->queued_len + count);
315 }
316 // Clear the FIFO control flag to receive more data.
317 USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
318 // Acknowledge the interrupt
319 USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_RXOUTIC;
320 if ((count < xfer->max_packet_size) || (xfer->queued_len == xfer->total_len))
321 {
322 // RX COMPLETE
323 dcd_event_xfer_complete(0, ep_ix, xfer->queued_len, XFER_RESULT_SUCCESS, true);
324 // Disable the interrupt
325 USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_RXOUTEC;
326 // Though the host could still send, we don't know.
327 }
328 }
329 if (int_status & DEVEPTISR_TXINI)
330 {
331 // Acknowledge the interrupt
332 USB_REG->DEVEPTICR[ep_ix] = DEVEPTICR_TXINIC;
333 if ((xfer->total_len != xfer->queued_len))
334 {
335 // TX not complete
337 } else
338 {
339 // TX complete
341 // Disable the interrupt
342 USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_TXINEC;
343 }
344 }
345 }
346}
347
348static void dcd_dma_handler(uint8_t ep_ix)
349{
350 uint32_t status = USB_REG->DEVDMA[ep_ix - 1].DEVDMASTATUS;
351 if (status & DEVDMASTATUS_CHANN_ENB)
352 {
353 return; // Ignore EOT_STA interrupt
354 }
355 // Disable DMA interrupt
356 USB_REG->DEVIDR = DEVIDR_DMA_1 << (ep_ix - 1);
357
358 xfer_ctl_t *xfer = &xfer_status[ep_ix];
359 uint16_t count = xfer->total_len - ((status & DEVDMASTATUS_BUFF_COUNT) >> DEVDMASTATUS_BUFF_COUNT_Pos);
360 if(USB_REG->DEVEPTCFG[ep_ix] & DEVEPTCFG_EPDIR)
361 {
362 dcd_event_xfer_complete(0, 0x80 + ep_ix, count, XFER_RESULT_SUCCESS, true);
363 } else
364 {
365 dcd_event_xfer_complete(0, ep_ix, count, XFER_RESULT_SUCCESS, true);
366 }
367}
368
369void dcd_int_handler(uint8_t rhport)
370{
371 (void) rhport;
372 uint32_t int_status = USB_REG->DEVISR;
373 int_status &= USB_REG->DEVIMR;
374 // End of reset interrupt
375 if (int_status & DEVISR_EORST)
376 {
377 // Unfreeze USB clock
378 USB_REG->CTRL &= ~CTRL_FRZCLK;
379 while(!(USB_REG->SR & SR_CLKUSABLE));
380 // Reset all endpoints
381 for (int ep_ix = 1; ep_ix < EP_MAX; ep_ix++)
382 {
383 USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + ep_ix);
384 USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + ep_ix));
385 }
387 USB_REG->DEVICR = DEVICR_EORSTC;
388 USB_REG->DEVICR = DEVICR_WAKEUPC;
389 USB_REG->DEVICR = DEVICR_SUSPC;
390 USB_REG->DEVIER = DEVIER_SUSPES;
391
392 dcd_event_bus_reset(rhport, get_speed(), true);
393 }
394 // End of Wakeup interrupt
395 if (int_status & DEVISR_WAKEUP)
396 {
397 USB_REG->CTRL &= ~CTRL_FRZCLK;
398 while (!(USB_REG->SR & SR_CLKUSABLE));
399 USB_REG->DEVICR = DEVICR_WAKEUPC;
400 USB_REG->DEVIDR = DEVIDR_WAKEUPEC;
401 USB_REG->DEVIER = DEVIER_SUSPES;
402
403 dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
404 }
405 // Suspend interrupt
406 if (int_status & DEVISR_SUSP)
407 {
408 // Unfreeze USB clock
409 USB_REG->CTRL &= ~CTRL_FRZCLK;
410 while (!(USB_REG->SR & SR_CLKUSABLE));
411 USB_REG->DEVICR = DEVICR_SUSPC;
412 USB_REG->DEVIDR = DEVIDR_SUSPEC;
413 USB_REG->DEVIER = DEVIER_WAKEUPES;
414 USB_REG->CTRL |= CTRL_FRZCLK;
415
416 dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
417 }
418#if USE_SOF
419 if(int_status & DEVISR_SOF)
420 {
421 USB_REG->DEVICR = DEVICR_SOFC;
422
423 dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
424 }
425#endif
426 // Endpoints interrupt
427 for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
428 {
429 if (int_status & (DEVISR_PEP_0 << ep_ix))
430 {
431 dcd_ep_handler(ep_ix);
432 }
433 }
434 // Endpoints DMA interrupt
435 for (int ep_ix = 0; ep_ix < EP_MAX; ep_ix++)
436 {
437 if (EP_DMA_SUPPORT(ep_ix))
438 {
439 if (int_status & (DEVISR_DMA_1 << (ep_ix - 1)))
440 {
441 dcd_dma_handler(ep_ix);
442 }
443 }
444 }
445}
446
447//--------------------------------------------------------------------+
448// Endpoint API
449//--------------------------------------------------------------------+
450// Invoked when a control transfer's status stage is complete.
451// May help DCD to prepare for next control transfer, this API is optional.
453{
454 (void) rhport;
455
459 {
460 uint8_t const dev_addr = (uint8_t) request->wValue;
461
462 USB_REG->DEVCTRL |= dev_addr | DEVCTRL_ADDEN;
463 }
464}
465
466// Configure endpoint's registers according to descriptor
467bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
468{
469 (void) rhport;
470 uint8_t const epnum = tu_edpt_number(ep_desc->bEndpointAddress);
471 uint8_t const dir = tu_edpt_dir(ep_desc->bEndpointAddress);
472 uint16_t const epMaxPktSize = tu_edpt_packet_size(ep_desc);
473 tusb_xfer_type_t const eptype = (tusb_xfer_type_t)ep_desc->bmAttributes.xfer;
474 uint8_t fifoSize = 0; // FIFO size
475 uint16_t defaultEndpointSize = 8; // Default size of Endpoint
476 // Find upper 2 power number of epMaxPktSize
477 if (epMaxPktSize)
478 {
479 while (defaultEndpointSize < epMaxPktSize)
480 {
481 fifoSize++;
482 defaultEndpointSize <<= 1;
483 }
484 }
485 xfer_status[epnum].max_packet_size = epMaxPktSize;
486
487 USB_REG->DEVEPT |= 1 << (DEVEPT_EPRST0_Pos + epnum);
488 USB_REG->DEVEPT &=~(1 << (DEVEPT_EPRST0_Pos + epnum));
489
490 if (epnum == 0)
491 {
492 // Enable the control endpoint - Endpoint 0
493 USB_REG->DEVEPT |= DEVEPT_EPEN0;
494 // Configure the Endpoint 0 configuration register
495 USB_REG->DEVEPTCFG[0] =
496 (
497 (fifoSize << DEVEPTCFG_EPSIZE_Pos) |
498 (TUSB_XFER_CONTROL << DEVEPTCFG_EPTYPE_Pos) |
499 (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
500 DEVEPTCFG_ALLOC
501 );
502 USB_REG->DEVEPTIER[0] = DEVEPTIER_RSTDTS;
503 USB_REG->DEVEPTIDR[0] = DEVEPTIDR_CTRL_STALLRQC;
504 if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[0] & DEVEPTISR_CFGOK))
505 {
506 // Endpoint configuration is successful
507 USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
508 // Enable Endpoint 0 Interrupts
509 USB_REG->DEVIER = DEVIER_PEP_0;
510 return true;
511 } else
512 {
513 // Endpoint configuration is not successful
514 return false;
515 }
516 } else
517 {
518 // Enable the endpoint
519 USB_REG->DEVEPT |= ((0x01 << epnum) << DEVEPT_EPEN0_Pos);
520 // Set up the maxpacket size, fifo start address fifosize
521 // and enable the interrupt. CLear the data toggle.
522 // AUTOSW is needed for DMA ack !
523 USB_REG->DEVEPTCFG[epnum] =
524 (
525 (fifoSize << DEVEPTCFG_EPSIZE_Pos) |
526 (eptype << DEVEPTCFG_EPTYPE_Pos) |
527 (DEVEPTCFG_EPBK_1_BANK << DEVEPTCFG_EPBK_Pos) |
528 DEVEPTCFG_AUTOSW |
529 ((dir & 0x01) << DEVEPTCFG_EPDIR_Pos)
530 );
531 if (eptype == TUSB_XFER_ISOCHRONOUS)
532 {
533 USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_NBTRANS_1_TRANS;
534 }
535#if USE_DUAL_BANK
536 if (eptype == TUSB_XFER_ISOCHRONOUS || eptype == TUSB_XFER_BULK)
537 {
538 USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_EPBK_2_BANK;
539 }
540#endif
541 USB_REG->DEVEPTCFG[epnum] |= DEVEPTCFG_ALLOC;
542 USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RSTDTS;
543 USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
544 if (DEVEPTISR_CFGOK == (USB_REG->DEVEPTISR[epnum] & DEVEPTISR_CFGOK))
545 {
546 USB_REG->DEVIER = ((0x01 << epnum) << DEVIER_PEP_0_Pos);
547 return true;
548 } else
549 {
550 // Endpoint configuration is not successful
551 return false;
552 }
553 }
554}
555
556void dcd_edpt_close_all (uint8_t rhport)
557{
558 (void) rhport;
559 // TODO implement dcd_edpt_close_all()
560}
561
562void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
563{
564 (void) rhport;
565 uint8_t const epnum = tu_edpt_number(ep_addr);
566
567 // Disable endpoint interrupt
568 USB_REG->DEVIDR = 1 << (DEVIDR_PEP_0_Pos + epnum);
569 // Disable EP
570 USB_REG->DEVEPT &=~(1 << (DEVEPT_EPEN0_Pos + epnum));
571}
572
573static void dcd_transmit_packet(xfer_ctl_t * xfer, uint8_t ep_ix)
574{
575 uint16_t len = (uint16_t)(xfer->total_len - xfer->queued_len);
576 if (len)
577 {
578 if (len > xfer->max_packet_size)
579 {
580 len = xfer->max_packet_size;
581 }
582 uint8_t *ptr = EP_GET_FIFO_PTR(ep_ix,8);
583 if(xfer->buffer)
584 {
585 memcpy(ptr, xfer->buffer + xfer->queued_len, len);
586 }
587 else
588 {
589 tu_fifo_read_n(xfer->fifo, ptr, len);
590 }
591 __DSB();
592 __ISB();
593 xfer->queued_len = (uint16_t)(xfer->queued_len + len);
594 }
595 if (ep_ix == 0U)
596 {
597 // Control endpoint: clear the interrupt flag to send the data
598 USB_REG->DEVEPTICR[0] = DEVEPTICR_TXINIC;
599 } else
600 {
601 // Other endpoint types: clear the FIFO control flag to send the data
602 USB_REG->DEVEPTIDR[ep_ix] = DEVEPTIDR_FIFOCONC;
603 }
604 USB_REG->DEVEPTIER[ep_ix] = DEVEPTIER_TXINES;
605}
606
607// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
608bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
609{
610 (void) rhport;
611 uint8_t const epnum = tu_edpt_number(ep_addr);
612 uint8_t const dir = tu_edpt_dir(ep_addr);
613
614 xfer_ctl_t * xfer = &xfer_status[epnum];
615
616 xfer->buffer = buffer;
618 xfer->queued_len = 0;
619 xfer->fifo = NULL;
620
621 if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
622 {
623 // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
624 // address to 32-byte boundaries.
625 CleanInValidateCache((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
626 uint32_t udd_dma_ctrl = total_bytes << DEVDMACONTROL_BUFF_LENGTH_Pos;
627 if (dir == TUSB_DIR_OUT)
628 {
629 udd_dma_ctrl |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
630 } else {
631 udd_dma_ctrl |= DEVDMACONTROL_END_B_EN;
632 }
633 USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)buffer;
634 udd_dma_ctrl |= DEVDMACONTROL_END_BUFFIT | DEVDMACONTROL_CHANN_ENB;
635 // Disable IRQs to have a short sequence
636 // between read of EOT_STA and DMA enable
637 uint32_t irq_state = __get_PRIMASK();
638 __disable_irq();
639 if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
640 {
641 USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl;
642 USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
643 __set_PRIMASK(irq_state);
644 return true;
645 }
646 __set_PRIMASK(irq_state);
647
648 // Here a ZLP has been received
649 // and the DMA transfer must be not started.
650 // It is the end of transfer
651 return false;
652 } else
653 {
654 if (dir == TUSB_DIR_OUT)
655 {
656 USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
657 } else
658 {
660 }
661 }
662 return true;
663}
664
665// The number of bytes has to be given explicitly to allow more flexible control of how many
666// bytes should be written and second to keep the return value free to give back a boolean
667// success message. If total_bytes is too big, the FIFO will copy only what is available
668// into the USB buffer!
669bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
670{
671 (void) rhport;
672 uint8_t const epnum = tu_edpt_number(ep_addr);
673 uint8_t const dir = tu_edpt_dir(ep_addr);
674
675 xfer_ctl_t * xfer = &xfer_status[epnum];
676 if(epnum == 0x80)
677 xfer = &xfer_status[EP_MAX];
678
679 xfer->buffer = NULL;
681 xfer->queued_len = 0;
682 xfer->fifo = ff;
683
684 if (EP_DMA_SUPPORT(epnum) && total_bytes != 0)
685 {
687 uint32_t udd_dma_ctrl_lin = DEVDMACONTROL_CHANN_ENB;
688 uint32_t udd_dma_ctrl_wrap = DEVDMACONTROL_CHANN_ENB | DEVDMACONTROL_END_BUFFIT;
689 if (dir == TUSB_DIR_OUT)
690 {
692 udd_dma_ctrl_lin |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
693 udd_dma_ctrl_wrap |= DEVDMACONTROL_END_TR_IT | DEVDMACONTROL_END_TR_EN;
694 } else {
696 if(info.len_wrap == 0)
697 {
698 udd_dma_ctrl_lin |= DEVDMACONTROL_END_B_EN;
699 }
700 udd_dma_ctrl_wrap |= DEVDMACONTROL_END_B_EN;
701 }
702
703 // Clean invalidate cache of linear part
704 CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_lin, 4), info.len_lin + 31);
705
706 USB_REG->DEVDMA[epnum - 1].DEVDMAADDRESS = (uint32_t)info.ptr_lin;
707 if (info.len_wrap)
708 {
709 // Clean invalidate cache of wrapped part
710 CleanInValidateCache((uint32_t*) tu_align((uint32_t) info.ptr_wrap, 4), info.len_wrap + 31);
711
712 dma_desc[epnum - 1].next_desc = 0;
713 dma_desc[epnum - 1].buff_addr = (uint32_t)info.ptr_wrap;
714 dma_desc[epnum - 1].chnl_ctrl =
715 udd_dma_ctrl_wrap | (info.len_wrap << DEVDMACONTROL_BUFF_LENGTH_Pos);
716 // Clean cache of wrapped DMA descriptor
717 CleanInValidateCache((uint32_t*)&dma_desc[epnum - 1], sizeof(dma_desc_t));
718
719 udd_dma_ctrl_lin |= DEVDMASTATUS_DESC_LDST;
720 USB_REG->DEVDMA[epnum - 1].DEVDMANXTDSC = (uint32_t)&dma_desc[epnum - 1];
721 } else {
722 udd_dma_ctrl_lin |= DEVDMACONTROL_END_BUFFIT;
723 }
724 udd_dma_ctrl_lin |= (info.len_lin << DEVDMACONTROL_BUFF_LENGTH_Pos);
725 // Disable IRQs to have a short sequence
726 // between read of EOT_STA and DMA enable
727 uint32_t irq_state = __get_PRIMASK();
728 __disable_irq();
729 if (!(USB_REG->DEVDMA[epnum - 1].DEVDMASTATUS & DEVDMASTATUS_END_TR_ST))
730 {
731 USB_REG->DEVDMA[epnum - 1].DEVDMACONTROL = udd_dma_ctrl_lin;
732 USB_REG->DEVIER = DEVIER_DMA_1 << (epnum - 1);
733 __set_PRIMASK(irq_state);
734 return true;
735 }
736 __set_PRIMASK(irq_state);
737
738 // Here a ZLP has been received
739 // and the DMA transfer must be not started.
740 // It is the end of transfer
741 return false;
742 } else
743 {
744 if (dir == TUSB_DIR_OUT)
745 {
746 USB_REG->DEVEPTIER[epnum] = DEVEPTIER_RXOUTES;
747 } else
748 {
750 }
751 }
752 return true;
753}
754
755// Stall endpoint
756void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
757{
758 (void) rhport;
759 uint8_t const epnum = tu_edpt_number(ep_addr);
760 USB_REG->DEVEPTIER[epnum] = DEVEPTIER_CTRL_STALLRQS;
761 // Re-enable SETUP interrupt
762 if (epnum == 0)
763 {
764 USB_REG->DEVEPTIER[0] = DEVEPTIER_CTRL_RXSTPES;
765 }
766}
767
768// clear stall, data toggle is also reset to DATA0
769void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
770{
771 (void) rhport;
772 uint8_t const epnum = tu_edpt_number(ep_addr);
773 USB_REG->DEVEPTIDR[epnum] = DEVEPTIDR_CTRL_STALLRQC;
774 USB_REG->DEVEPTIER[epnum] = HSTPIPIER_RSTDTS;
775}
776
777#endif
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
dma_desc_t
Definition: dcd_lpc17_40.c:72
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
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
Definition: dcd_samx7x.c:669
static CFG_TUD_MEM_SECTION dma_desc_t dma_desc[6]
Definition: dcd_samx7x.c:80
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_samx7x.c:756
static tusb_speed_t get_speed(void)
Definition: dcd_samx7x.c:203
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_samx7x.c:562
static const tusb_desc_endpoint_t ep0_desc
Definition: dcd_samx7x.c:84
void dcd_int_handler(uint8_t rhport)
Definition: dcd_samx7x.c:369
void dcd_disconnect(uint8_t rhport)
Definition: dcd_samx7x.c:176
static void dcd_ep_handler(uint8_t ep_ix)
Definition: dcd_samx7x.c:216
void dcd_edpt_close_all(uint8_t rhport)
Definition: dcd_samx7x.c:556
void dcd_int_disable(uint8_t rhport)
Definition: dcd_samx7x.c:121
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc)
Definition: dcd_samx7x.c:467
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_samx7x.c:769
static xfer_ctl_t xfer_status[EP_MAX]
Definition: dcd_samx7x.c:82
void dcd_connect(uint8_t rhport)
Definition: dcd_samx7x.c:146
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: dcd_samx7x.c:608
static TU_ATTR_ALWAYS_INLINE void CleanInValidateCache(uint32_t *addr, int32_t size)
Definition: dcd_samx7x.c:90
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
Definition: dcd_samx7x.c:452
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
Definition: dcd_samx7x.c:128
static void dcd_transmit_packet(xfer_ctl_t *xfer, uint8_t ep_ix)
Definition: dcd_samx7x.c:573
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: dcd_samx7x.c:107
void dcd_int_enable(uint8_t rhport)
Definition: dcd_samx7x.c:114
void dcd_remote_wakeup(uint8_t rhport)
Definition: dcd_samx7x.c:139
void dcd_sof_enable(uint8_t rhport, bool en)
Definition: dcd_samx7x.c:195
static void dcd_dma_handler(uint8_t ep_ix)
Definition: dcd_samx7x.c:348
uint8_t const * buffer
Definition: midi_device.h:100
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint16_t wValue
Definition: audio.h:934
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
volatile uint32_t next_desc
Definition: dcd_samx7x.c:60
uint32_t padding
Definition: dcd_samx7x.c:63
volatile uint32_t buff_addr
Definition: dcd_samx7x.c:61
volatile uint32_t chnl_ctrl
Definition: dcd_samx7x.c:62
tu_fifo_t * fifo
Definition: dcd_samx7x.c:73
uint16_t max_packet_size
Definition: dcd_da146xx.c:216
uint16_t total_len
Definition: dcd_nrf5x.c:100
uint8_t * buffer
Definition: dcd_nrf5x.c:99
static TU_ATTR_ALWAYS_INLINE uint32_t tu_align(uint32_t value, uint32_t alignment)
Definition: tusb_common.h:164
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get linear write info.
Definition: tusb_fifo.c:1057
uint16_t tu_fifo_write_n(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:861
uint16_t tu_fifo_read_n(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:730
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get read info.
Definition: tusb_fifo.c:989
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_REQ_SET_ADDRESS
Definition: tusb_types.h:127
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
Definition: tusb_types.h:49
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
@ TUSB_SPEED_LOW
Definition: tusb_types.h:51
@ TUSB_SPEED_HIGH
Definition: tusb_types.h:52
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
@ TUSB_REQ_RCPT_DEVICE
Definition: tusb_types.h:151
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_type_t
defined base on USB Specs Endpoint's bmAttributes
Definition: tusb_types.h:58
@ TUSB_XFER_CONTROL
Definition: tusb_types.h:59
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
@ TUSB_XFER_BULK
Definition: tusb_types.h:61
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
@ TUSB_REQ_TYPE_STANDARD
Definition: tusb_types.h:144
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259