Open FFBoard
Open source force feedback firmware
dcd_ch32_usbhs.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2022 Greg Davill
5 * Copyright (c) 2023 Denis Krasutski
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 && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS
31#include "ch32_usbhs_reg.h"
32
33#include "device/dcd.h"
34
35// Max number of bi-directional endpoints including EP0
36#define EP_MAX 16
37
38typedef struct {
39 uint8_t* buffer;
40 uint16_t total_len;
41 uint16_t queued_len;
42 uint16_t max_size;
44 bool is_iso;
46
47typedef enum {
51
52#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
53static xfer_ctl_t xfer_status[EP_MAX][2];
54
55#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
56#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
57#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
58#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2)
59
60#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
61#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
62
63/* Endpoint Buffer */
64TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE];
65
66static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) {
67 if (ep_dir == TUSB_DIR_IN) {
68 uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK;
69 if (ep_num == 0) {
70 if (response_type == EP_RESPONSE_ACK) {
71 if (EP_TX_LEN(ep_num) == 0) {
72 EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1;
73 } else {
74 EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1;
75 }
76 }
77 }
78 if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) {
79 EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG;
80 } else {
81 EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response;
82 }
83 } else {
84 uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK;
85 if (ep_num == 0) {
86 if (response_type == EP_RESPONSE_ACK) {
87 if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) {
88 EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1;
89 }
90 } else {
91 EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1;
92 }
93 }
94 EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response;
95 }
96}
97
98static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) {
99 if (ep_dir == TUSB_DIR_IN) {
100 uint16_t remaining = xfer->total_len - xfer->queued_len;
101 uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size);
102
103 if (ep_num == 0) {
104 memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size);
105 } else {
106 EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
107 }
108
109 EP_TX_LEN(ep_num) = next_tx_size;
110 xfer->queued_len += next_tx_size;
111 if (xfer->queued_len == xfer->total_len) {
112 xfer->is_last_packet = true;
113 }
114 if (xfer->is_iso == true) {
115 /* Enable EP to generate ISA_ACT interrupt */
116 USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
117 }
118 } else { /* TUSB_DIR_OUT */
119 uint16_t left_to_receive = xfer->total_len - xfer->queued_len;
120 uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive);
121
122 if (max_possible_rx_size == left_to_receive) {
123 xfer->is_last_packet = true;
124 }
125
126 if (ep_num > 0) {
127 EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
128 EP_RX_MAX_LEN(ep_num) = max_possible_rx_size;
129 }
130 }
131 ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK);
132}
133
134bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
135 (void) rhport;
136 (void) rh_init;
137
138 memset(&xfer_status, 0, sizeof(xfer_status));
139
140 USBHSD->HOST_CTRL = 0x00;
141 USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
142
143 USBHSD->CONTROL = 0;
144
145#if TUD_OPT_HIGH_SPEED
146 USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
147#else
148 #error OPT_MODE_FULL_SPEED not currently supported on CH32
149 USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
150#endif
151
152 USBHSD->INT_EN = 0;
153 USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN;
154
155 USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
156 USBHSD->ENDP_TYPE = 0x00;
157 USBHSD->BUF_MODE = 0x00;
158
159 for (int ep = 0; ep < EP_MAX; ep++) {
160 EP_TX_LEN(ep) = 0;
161 EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
162 EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
163
164 EP_RX_MAX_LEN(ep) = 0;
165 }
166
167 USBHSD->UEP0_DMA = (uint32_t) ep0_buffer;
168 USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE;
169 xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE;
170 xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
171
172 USBHSD->DEV_AD = 0;
173 USBHSD->CONTROL |= USBHS_DEV_PU_EN;
174
175 return true;
176}
177
178void dcd_int_enable(uint8_t rhport) {
179 (void) rhport;
180 NVIC_EnableIRQ(USBHS_IRQn);
181}
182
183void dcd_int_disable(uint8_t rhport) {
184 (void) rhport;
185 NVIC_DisableIRQ(USBHS_IRQn);
186}
187
188void dcd_edpt_close_all(uint8_t rhport) {
189 (void) rhport;
190
191 for (size_t ep = 1; ep < EP_MAX; ep++) {
192 EP_TX_LEN(ep) = 0;
193 EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
194 EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
195
196 EP_RX_MAX_LEN(ep) = 0;
197 }
198
199 USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
200}
201
202void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
203 (void) dev_addr;
204
205 // Response with zlp status
206 dcd_edpt_xfer(rhport, 0x80, NULL, 0);
207}
208
209void dcd_remote_wakeup(uint8_t rhport) {
210 (void) rhport;
211}
212
213void dcd_sof_enable(uint8_t rhport, bool en) {
214 (void) rhport;
215 if (en) {
216 USBHSD->INT_EN |= USBHS_SOF_ACT_EN;
217 } else {
218 USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN);
219 }
220}
221
223 (void) rhport;
224
228 USBHSD->DEV_AD = (uint8_t) request->wValue;
229 }
230
231 EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
232 EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
233}
234
235bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
236 (void) rhport;
237
238 uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress);
239 tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
240
241 TU_ASSERT(ep_num < EP_MAX);
242
243 if (ep_num == 0) {
244 return true;
245 }
246
247 xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
248 xfer->max_size = tu_edpt_packet_size(desc_edpt);
249
250 xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
251 if (dir == TUSB_DIR_OUT) {
252 USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num);
253 EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
254 if (xfer->is_iso == true) {
255 USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num);
256 }
257 EP_RX_MAX_LEN(ep_num) = xfer->max_size;
258 } else {
259 if (xfer->is_iso == true) {
260 USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num);
261 } else {
262 /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */
263 USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
264 }
265 EP_TX_LEN(ep_num) = 0;
266 EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
267 }
268
269 return true;
270}
271
272void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
273 (void) rhport;
274
275 uint8_t const ep_num = tu_edpt_number(ep_addr);
276 tusb_dir_t const dir = tu_edpt_dir(ep_addr);
277
278 if (dir == TUSB_DIR_OUT) {
279 EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
280 EP_RX_MAX_LEN(ep_num) = 0;
281 USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num);
282 USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num);
283 } else { // TUSB_DIR_IN
284 EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
285 EP_TX_LEN(ep_num) = 0;
286 USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num);
287 USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
288 }
289}
290
291void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
292 (void) rhport;
293
294 uint8_t const ep_num = tu_edpt_number(ep_addr);
295 tusb_dir_t const dir = tu_edpt_dir(ep_addr);
296
297 if (dir == TUSB_DIR_OUT) {
298 EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL;
299 } else {
300 EP_TX_LEN(0) = 0;
301 EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL;
302 }
303}
304
305void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
306 (void) rhport;
307
308 uint8_t const ep_num = tu_edpt_number(ep_addr);
309 tusb_dir_t const dir = tu_edpt_dir(ep_addr);
310
311 if (dir == TUSB_DIR_OUT) {
312 EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
313 } else {
314 EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK;
315 }
316}
317
318bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
319 (void) rhport;
320 uint8_t const ep_num = tu_edpt_number(ep_addr);
321 tusb_dir_t const dir = tu_edpt_dir(ep_addr);
322
323 xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
324 xfer->buffer = buffer;
326 xfer->queued_len = 0;
327 xfer->is_last_packet = false;
328
329 xfer_data_packet(ep_num, dir, xfer);
330
331 return true;
332}
333
334void dcd_int_handler(uint8_t rhport) {
335 (void) rhport;
336
337 uint8_t int_flag = USBHSD->INT_FG;
338 uint8_t int_status = USBHSD->INT_ST;
339
340 if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) {
341 uint8_t const token = int_status & MASK_UIS_TOKEN;
342
343 if (token == USBHS_TOKEN_PID_SOF) {
344 uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK;
345 dcd_event_sof(rhport, frame_count, true);
346 }else {
347 uint8_t const ep_num = int_status & MASK_UIS_ENDP;
348 tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT;
349 uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir);
350 xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir);
351
352 if (token == USBHS_TOKEN_PID_OUT) {
353 uint16_t rx_len = USBHSD->RX_LEN;
354
355 if (ep_num == 0) {
356 memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len);
357 }
358
359 xfer->queued_len += rx_len;
360 if (rx_len < xfer->max_size) {
361 xfer->is_last_packet = true;
362 }
363 } else if (token == USBHS_TOKEN_PID_IN) {
364 if (xfer->is_iso && xfer->is_last_packet) {
365 /* Disable EP to avoid ISO_ACT interrupt generation */
366 USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
367 } else {
368 // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet
369 }
370 }
371
372 if (xfer->is_last_packet == true) {
373 ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK);
374 dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
375 } else {
376 /* prepare next part of packet to xref */
377 xfer_data_packet(ep_num, ep_dir, xfer);
378 }
379 }
380
381 USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */
382 } else if (int_flag & USBHS_SETUP_FLAG) {
383 ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK);
384 ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK);
385 dcd_event_setup_received(0, ep0_buffer, true);
386
387 USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
388 } else if (int_flag & USBHS_BUS_RST_FLAG) {
389 // TODO CH32 does not detect actual speed at this time (should be known at end of reset)
390 // This interrupt probably triggered at start of bus reset
391// tusb_speed_t actual_speed;
392// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){
393// case USBHS_SPEED_TYPE_HIGH:
394// actual_speed = TUSB_SPEED_HIGH;
395// break;
396// case USBHS_SPEED_TYPE_FULL:
397// actual_speed = TUSB_SPEED_FULL;
398// break;
399// case USBHS_SPEED_TYPE_LOW:
400// actual_speed = TUSB_SPEED_LOW;
401// break;
402// default:
403// TU_ASSERT(0,);
404// break;
405// }
406// dcd_event_bus_reset(0, actual_speed, true);
407
409
410 USBHSD->DEV_AD = 0;
411 EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
412 EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
413
414 USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */
415 } else if (int_flag & USBHS_SUSPEND_FLAG) {
416 dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
417 dcd_event_handler(&event, true);
418
419 USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
420 }
421}
422
423#endif
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_sof(uint8_t rhport, uint32_t frame_count, bool in_isr)
Definition: dcd.h:232
static TU_ATTR_ALWAYS_INLINE void dcd_event_setup_received(uint8_t rhport, uint8_t const *setup, bool in_isr)
Definition: dcd.h:213
dcd_event_t
Definition: dcd.h:86
void dcd_event_handler(dcd_event_t const *event, bool in_isr)
Definition: usbd.c:1153
static TU_ATTR_ALWAYS_INLINE void dcd_event_bus_reset(uint8_t rhport, tusb_speed_t speed, bool in_isr)
Definition: dcd.h:204
ep_response_list_t
@ EP_RESPONSE_NAK
@ EP_RESPONSE_ACK
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t *xfer)
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
void dcd_int_handler(uint8_t rhport)
TU_ATTR_ALIGNED(4)
static xfer_ctl_t xfer_status[EP_MAX][2]
void dcd_edpt_close_all(uint8_t rhport)
void dcd_int_disable(uint8_t rhport)
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt)
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request)
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
void dcd_int_enable(uint8_t rhport)
void dcd_remote_wakeup(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
xfer_ctl_t
Definition: dcd_dwc2.c:52
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
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
uint16_t max_size
Definition: dcd_esp32sx.c:71
bool is_last_packet
uint16_t total_len
Definition: dcd_nrf5x.c:100
uint8_t * buffer
Definition: dcd_nrf5x.c:99
tusb_dir_t
Definition: tusb_types.h:65
@ 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_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_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
@ TUSB_REQ_TYPE_STANDARD
Definition: tusb_types.h:144
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259