Open FFBoard
Open source force feedback firmware
cdc_host.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 *
26 * Contribution
27 * - Heiko Kuester: CH34x support
28 */
29
30#include "tusb_option.h"
31
32#if (CFG_TUH_ENABLED && CFG_TUH_CDC)
33
34#include "host/usbh.h"
35#include "host/usbh_pvt.h"
36
37#include "cdc_host.h"
38
39// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
40#ifndef CFG_TUH_CDC_LOG_LEVEL
41 #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL
42#endif
43
44#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__)
45
46//--------------------------------------------------------------------+
47// Host CDC Interface
48//--------------------------------------------------------------------+
49
50typedef struct {
51 uint8_t daddr;
55
56 uint8_t ep_notif;
57 uint8_t serial_drid; // Serial Driver ID
58 bool mounted; // Enumeration is complete
60
61 TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
62 uint8_t line_state; // DTR (bit0), RTS (bit1)
63
64 #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X
65 cdc_line_coding_t requested_line_coding;
66 // 1 byte padding
67 #endif
68
69 tuh_xfer_cb_t user_control_cb;
70
71 struct {
74
75 uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
76 CFG_TUH_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
77
78 uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
79 CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
80 } stream;
82
83CFG_TUH_MEM_SECTION
84static cdch_interface_t cdch_data[CFG_TUH_CDC];
85
86//--------------------------------------------------------------------+
87// Serial Driver
88//--------------------------------------------------------------------+
89
90//------------- ACM prototypes -------------//
91static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
93
94static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
95static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
96static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
97static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
98
99//------------- FTDI prototypes -------------//
100#if CFG_TUH_CDC_FTDI
101#include "serial/ftdi_sio.h"
102
103static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST};
104
105static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
107
108static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
109static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
110static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
111static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
112#endif
113
114//------------- CP210X prototypes -------------//
115#if CFG_TUH_CDC_CP210X
116#include "serial/cp210x.h"
117
118static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST};
119
120static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
122
123static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
124static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
125static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
126static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
127#endif
128
129//------------- CH34x prototypes -------------//
130#if CFG_TUH_CDC_CH34X
131#include "serial/ch34x.h"
132
133static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST};
134
135static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len);
137
138static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
139static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
140static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
141static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
142#endif
143
144//------------- Common -------------//
145enum {
147
148#if CFG_TUH_CDC_FTDI
150#endif
151
152#if CFG_TUH_CDC_CP210X
154#endif
155
156#if CFG_TUH_CDC_CH34X
158#endif
159
162
163typedef struct {
164 uint16_t const (*vid_pid_list)[2];
165 uint16_t const vid_pid_count;
166 bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len);
168 bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
169 bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
170 bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
171 bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
173
174// Note driver list must be in the same order as SERIAL_DRIVER enum
176 {
177 .vid_pid_list = NULL,
178 .vid_pid_count = 0,
179 .open = acm_open,
180 .process_set_config = acm_process_config,
181 .set_control_line_state = acm_set_control_line_state,
182 .set_baudrate = acm_set_baudrate,
183 .set_data_format = acm_set_data_format,
184 .set_line_coding = acm_set_line_coding
185 },
186
187 #if CFG_TUH_CDC_FTDI
188 {
189 .vid_pid_list = ftdi_vid_pid_list,
190 .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list),
191 .open = ftdi_open,
192 .process_set_config = ftdi_process_config,
193 .set_control_line_state = ftdi_sio_set_modem_ctrl,
194 .set_baudrate = ftdi_sio_set_baudrate,
195 .set_data_format = ftdi_set_data_format,
196 .set_line_coding = ftdi_set_line_coding
197 },
198 #endif
199
200 #if CFG_TUH_CDC_CP210X
201 {
202 .vid_pid_list = cp210x_vid_pid_list,
203 .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list),
204 .open = cp210x_open,
205 .process_set_config = cp210x_process_config,
206 .set_control_line_state = cp210x_set_modem_ctrl,
207 .set_baudrate = cp210x_set_baudrate,
208 .set_data_format = cp210x_set_data_format,
209 .set_line_coding = cp210x_set_line_coding
210 },
211 #endif
212
213 #if CFG_TUH_CDC_CH34X
214 {
215 .vid_pid_list = ch34x_vid_pid_list,
216 .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list),
217 .open = ch34x_open,
218 .process_set_config = ch34x_process_config,
219 .set_control_line_state = ch34x_set_modem_ctrl,
220 .set_baudrate = ch34x_set_baudrate,
221 .set_data_format = ch34x_set_data_format,
222 .set_line_coding = ch34x_set_line_coding
223 },
224 #endif
225};
226
227TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch");
228
229//--------------------------------------------------------------------+
230// INTERNAL OBJECT & FUNCTION DECLARATION
231//--------------------------------------------------------------------+
232
233static inline cdch_interface_t* get_itf(uint8_t idx) {
234 TU_ASSERT(idx < CFG_TUH_CDC, NULL);
235 cdch_interface_t* p_cdc = &cdch_data[idx];
236
237 return (p_cdc->daddr != 0) ? p_cdc : NULL;
238}
239
240static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) {
241 for(uint8_t i=0; i<CFG_TUH_CDC; i++) {
242 cdch_interface_t* p_cdc = &cdch_data[i];
243 if ( (p_cdc->daddr == daddr) &&
244 (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) {
245 return i;
246 }
247 }
248
250}
251
252static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) {
253 for(uint8_t i=0; i<CFG_TUH_CDC; i++) {
254 if (cdch_data[i].daddr == 0) {
255 cdch_interface_t* p_cdc = &cdch_data[i];
256 p_cdc->daddr = daddr;
257 p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
258 p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
259 p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
260 p_cdc->line_state = 0;
261 return p_cdc;
262 }
263 }
264
265 return NULL;
266}
267
268static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep);
269static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num);
271
272//--------------------------------------------------------------------+
273// APPLICATION API
274//--------------------------------------------------------------------+
275
276uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) {
277 for (uint8_t i = 0; i < CFG_TUH_CDC; i++) {
278 const cdch_interface_t* p_cdc = &cdch_data[i];
279 if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i;
280 }
281
283}
284
285bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) {
286 cdch_interface_t* p_cdc = get_itf(idx);
287 TU_VERIFY(p_cdc && info);
288
289 info->daddr = p_cdc->daddr;
290
291 // re-construct descriptor
293 desc->bLength = sizeof(tusb_desc_interface_t);
294 desc->bDescriptorType = TUSB_DESC_INTERFACE;
295
296 desc->bInterfaceNumber = p_cdc->bInterfaceNumber;
297 desc->bAlternateSetting = 0;
298 desc->bNumEndpoints = 2u + (p_cdc->ep_notif ? 1u : 0u);
299 desc->bInterfaceClass = TUSB_CLASS_CDC;
300 desc->bInterfaceSubClass = p_cdc->bInterfaceSubClass;
301 desc->bInterfaceProtocol = p_cdc->bInterfaceProtocol;
302 desc->iInterface = 0; // not used yet
303
304 return true;
305}
306
307bool tuh_cdc_mounted(uint8_t idx) {
308 cdch_interface_t* p_cdc = get_itf(idx);
309 TU_VERIFY(p_cdc);
310 return p_cdc->mounted;
311}
312
313bool tuh_cdc_get_dtr(uint8_t idx) {
314 cdch_interface_t* p_cdc = get_itf(idx);
315 TU_VERIFY(p_cdc);
316
317 return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false;
318}
319
320bool tuh_cdc_get_rts(uint8_t idx) {
321 cdch_interface_t* p_cdc = get_itf(idx);
322 TU_VERIFY(p_cdc);
323
324 return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false;
325}
326
327bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) {
328 cdch_interface_t* p_cdc = get_itf(idx);
329 TU_VERIFY(p_cdc);
330
331 *line_coding = p_cdc->line_coding;
332
333 return true;
334}
335
336//--------------------------------------------------------------------+
337// Write
338//--------------------------------------------------------------------+
339
340uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) {
341 cdch_interface_t* p_cdc = get_itf(idx);
342 TU_VERIFY(p_cdc);
343
344 return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize);
345}
346
347uint32_t tuh_cdc_write_flush(uint8_t idx) {
348 cdch_interface_t* p_cdc = get_itf(idx);
349 TU_VERIFY(p_cdc);
350
351 return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx);
352}
353
354bool tuh_cdc_write_clear(uint8_t idx) {
355 cdch_interface_t* p_cdc = get_itf(idx);
356 TU_VERIFY(p_cdc);
357
358 return tu_edpt_stream_clear(&p_cdc->stream.tx);
359}
360
361uint32_t tuh_cdc_write_available(uint8_t idx) {
362 cdch_interface_t* p_cdc = get_itf(idx);
363 TU_VERIFY(p_cdc);
364
365 return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx);
366}
367
368//--------------------------------------------------------------------+
369// Read
370//--------------------------------------------------------------------+
371
372uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) {
373 cdch_interface_t* p_cdc = get_itf(idx);
374 TU_VERIFY(p_cdc);
375
376 return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize);
377}
378
379uint32_t tuh_cdc_read_available(uint8_t idx) {
380 cdch_interface_t* p_cdc = get_itf(idx);
381 TU_VERIFY(p_cdc);
382
383 return tu_edpt_stream_read_available(&p_cdc->stream.rx);
384}
385
386bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) {
387 cdch_interface_t* p_cdc = get_itf(idx);
388 TU_VERIFY(p_cdc);
389
390 return tu_edpt_stream_peek(&p_cdc->stream.rx, ch);
391}
392
393bool tuh_cdc_read_clear (uint8_t idx) {
394 cdch_interface_t* p_cdc = get_itf(idx);
395 TU_VERIFY(p_cdc);
396
397 bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx);
398 tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
399 return ret;
400}
401
402//--------------------------------------------------------------------+
403// Control Endpoint API
404//--------------------------------------------------------------------+
405
406static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) {
407 uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
408 cdch_interface_t* p_cdc = get_itf(idx);
409 TU_ASSERT(p_cdc, );
410 uint16_t const value = tu_le16toh(xfer->setup->wValue);
411
412 if (xfer->result == XFER_RESULT_SUCCESS) {
413 switch (p_cdc->serial_drid) {
415 switch (xfer->setup->bRequest) {
417 p_cdc->line_state = (uint8_t) value;
418 break;
419
421 uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
422 memcpy(&p_cdc->line_coding, xfer->buffer, len);
423 break;
424 }
425
426 default: break;
427 }
428 break;
429
430 #if CFG_TUH_CDC_FTDI
432 switch (xfer->setup->bRequest) {
433 case FTDI_SIO_MODEM_CTRL:
434 p_cdc->line_state = (uint8_t) value;
435 break;
436
437 case FTDI_SIO_SET_BAUD_RATE:
438 p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
439 break;
440
441 default: break;
442 }
443 break;
444 #endif
445
446 #if CFG_TUH_CDC_CP210X
448 switch(xfer->setup->bRequest) {
449 case CP210X_SET_MHS:
450 p_cdc->line_state = (uint8_t) value;
451 break;
452
453 case CP210X_SET_BAUDRATE: {
454 uint32_t baudrate;
455 memcpy(&baudrate, xfer->buffer, sizeof(uint32_t));
456 p_cdc->line_coding.bit_rate = tu_le32toh(baudrate);
457 break;
458 }
459
460 default: break;
461 }
462 break;
463 #endif
464
465 #if CFG_TUH_CDC_CH34X
467 switch (xfer->setup->bRequest) {
468 case CH34X_REQ_WRITE_REG:
469 // register write request
470 switch (value) {
471 case CH34X_REG16_DIVISOR_PRESCALER:
472 // baudrate
473 p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
474 break;
475
476 case CH32X_REG16_LCR2_LCR:
477 // data format
478 p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits;
479 p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity;
480 p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits;
481 break;
482
483 default: break;
484 }
485 break;
486
487 case CH34X_REQ_MODEM_CTRL: {
488 // set modem controls RTS/DTR request. Note: signals are inverted
489 uint16_t const modem_signal = ~value;
490 if (modem_signal & CH34X_BIT_RTS) {
491 p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS;
492 } else {
493 p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS;
494 }
495
496 if (modem_signal & CH34X_BIT_DTR) {
497 p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR;
498 } else {
499 p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR;
500 }
501 break;
502 }
503
504 default: break;
505 }
506 break;
507 #endif
508
509 default: break;
510 }
511 }
512
513 xfer->complete_cb = p_cdc->user_control_cb;
514 if (xfer->complete_cb) {
515 xfer->complete_cb(xfer);
516 }
517}
518
519// internal control complete to update state such as line state, encoding
521 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
523}
524
525bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
526 cdch_interface_t* p_cdc = get_itf(idx);
527 TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
528 cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
529
530 if (complete_cb) {
531 return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data);
532 } else {
533 // blocking
535 bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result);
536
537 if (user_data) {
538 // user_data is not NULL, return result via user_data
539 *((xfer_result_t*) user_data) = result;
540 }
541
542 TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
543 p_cdc->line_state = (uint8_t) line_state;
544 return true;
545 }
546}
547
548bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
549 cdch_interface_t* p_cdc = get_itf(idx);
550 TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
551 cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
552
553 if (complete_cb) {
554 return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data);
555 } else {
556 // blocking
558 bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result);
559
560 if (user_data) {
561 // user_data is not NULL, return result via user_data
562 *((xfer_result_t*) user_data) = result;
563 }
564
565 TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
566 p_cdc->line_coding.bit_rate = baudrate;
567 return true;
568 }
569}
570
571bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
573 cdch_interface_t* p_cdc = get_itf(idx);
574 TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
575 cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
576
577 if (complete_cb) {
578 return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data);
579 } else {
580 // blocking
582 bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result);
583
584 if (user_data) {
585 // user_data is not NULL, return result via user_data
586 *((xfer_result_t*) user_data) = result;
587 }
588
589 TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
590 p_cdc->line_coding.stop_bits = stop_bits;
591 p_cdc->line_coding.parity = parity;
592 p_cdc->line_coding.data_bits = data_bits;
593 return true;
594 }
595}
596
597bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
598 cdch_interface_t* p_cdc = get_itf(idx);
599 TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
600 cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid];
601
602 if ( complete_cb ) {
603 return driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data);
604 } else {
605 // blocking
607 bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result);
608
609 if (user_data) {
610 // user_data is not NULL, return result via user_data
611 *((xfer_result_t*) user_data) = result;
612 }
613
614 TU_VERIFY(ret && result == XFER_RESULT_SUCCESS);
615 p_cdc->line_coding = *line_coding;
616 return true;
617 }
618}
619
620//--------------------------------------------------------------------+
621// CLASS-USBH API
622//--------------------------------------------------------------------+
623
624bool cdch_init(void) {
625 TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t));
626 tu_memclr(cdch_data, sizeof(cdch_data));
627 for (size_t i = 0; i < CFG_TUH_CDC; i++) {
628 cdch_interface_t* p_cdc = &cdch_data[i];
629 tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false,
630 p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE,
631 p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE);
632
633 tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false,
634 p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE,
635 p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE);
636 }
637
638 return true;
639}
640
641bool cdch_deinit(void) {
642 for (size_t i = 0; i < CFG_TUH_CDC; i++) {
643 cdch_interface_t* p_cdc = &cdch_data[i];
644 tu_edpt_stream_deinit(&p_cdc->stream.tx);
645 tu_edpt_stream_deinit(&p_cdc->stream.rx);
646 }
647 return true;
648}
649
650void cdch_close(uint8_t daddr) {
651 for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) {
652 cdch_interface_t* p_cdc = &cdch_data[idx];
653 if (p_cdc->daddr == daddr) {
654 TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx);
655
656 // Invoke application callback
658
659 p_cdc->daddr = 0;
660 p_cdc->bInterfaceNumber = 0;
661 p_cdc->mounted = false;
662 tu_edpt_stream_close(&p_cdc->stream.tx);
663 tu_edpt_stream_close(&p_cdc->stream.rx);
664 }
665 }
666}
667
668bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
669 // TODO handle stall response, retry failed transfer ...
670 TU_ASSERT(event == XFER_RESULT_SUCCESS);
671
672 uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr);
673 cdch_interface_t * p_cdc = get_itf(idx);
674 TU_ASSERT(p_cdc);
675
676 if ( ep_addr == p_cdc->stream.tx.ep_addr ) {
677 // invoke tx complete callback to possibly refill tx fifo
679
680 if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) {
681 // If there is no data left, a ZLP should be sent if:
682 // - xferred_bytes is multiple of EP Packet size and not zero
683 tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes);
684 }
685 } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) {
686 #if CFG_TUH_CDC_FTDI
687 if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) {
688 // FTDI reserve 2 bytes for status
689 // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]};
690 tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2);
691 }else
692 #endif
693 {
694 tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
695 }
696
697 // invoke receive callback
699
700 // prepare for next transfer if needed
702 }else if ( ep_addr == p_cdc->ep_notif ) {
703 // TODO handle notification endpoint
704 }else {
705 TU_ASSERT(false);
706 }
707
708 return true;
709}
710
711//--------------------------------------------------------------------+
712// Enumeration
713//--------------------------------------------------------------------+
714
715static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) {
716 for (size_t i = 0; i < 2; i++) {
717 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
718 TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
719 TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep));
720
721 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
722 tu_edpt_stream_open(&p_cdc->stream.rx, desc_ep);
723 } else {
724 tu_edpt_stream_open(&p_cdc->stream.tx, desc_ep);
725 }
726
727 desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep);
728 }
729
730 return true;
731}
732
733bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
734 (void) rhport;
735
736 // For CDC: only support ACM subclass
737 // Note: Protocol 0xFF can be RNDIS device
738 if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
739 CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) {
740 return acm_open(daddr, itf_desc, max_len);
741 }
742 else if (SERIAL_DRIVER_COUNT > 1 &&
744 uint16_t vid, pid;
745 TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid));
746
747 for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) {
748 cdch_serial_driver_t const* driver = &serial_drivers[dr];
749 for (size_t i = 0; i < driver->vid_pid_count; i++) {
750 if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) {
751 return driver->open(daddr, itf_desc, max_len);
752 }
753 }
754 }
755 }
756
757 return false;
758}
759
760static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) {
761 TU_LOG_DRV("CDCh Set Configure complete\r\n");
762 p_cdc->mounted = true;
764
765 // Prepare for incoming data
766 tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
767
768 // notify usbh that driver enumeration is complete
769 usbh_driver_set_config_complete(p_cdc->daddr, itf_num);
770}
771
772bool cdch_set_config(uint8_t daddr, uint8_t itf_num) {
774 request.wIndex = tu_htole16((uint16_t) itf_num);
775
776 // fake transfer to kick-off process
778 xfer.daddr = daddr;
779 xfer.result = XFER_RESULT_SUCCESS;
780 xfer.setup = &request;
781 xfer.user_data = 0; // initial state
782
783 uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num);
784 cdch_interface_t * p_cdc = get_itf(idx);
785 TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
786
788 return true;
789}
790
791//--------------------------------------------------------------------+
792// ACM
793//--------------------------------------------------------------------+
794
795enum {
799};
800
801static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) {
802 uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len;
803
804 cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc);
805 TU_VERIFY(p_cdc);
807
808 //------------- Control Interface -------------//
809 uint8_t const* p_desc = tu_desc_next(itf_desc);
810
811 // Communication Functional Descriptors
812 while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) {
814 // save ACM bmCapabilities
815 p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities;
816 }
817
818 p_desc = tu_desc_next(p_desc);
819 }
820
821 // Open notification endpoint of control interface if any
822 if (itf_desc->bNumEndpoints == 1) {
823 TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc));
824 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
825
826 TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
827 p_cdc->ep_notif = desc_ep->bEndpointAddress;
828
829 p_desc = tu_desc_next(p_desc);
830 }
831
832 //------------- Data Interface (if any) -------------//
833 if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
834 (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) {
835 // next to endpoint descriptor
836 p_desc = tu_desc_next(p_desc);
837
838 // data endpoints expected to be in pairs
839 TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc));
840 }
841
842 return true;
843}
844
846 uintptr_t const state = xfer->user_data;
847 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
848 uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
849 cdch_interface_t* p_cdc = get_itf(idx);
850 TU_ASSERT(p_cdc,);
851
852 switch (state) {
854 #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
856 TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),);
857 break;
858 }
859 #endif
860 TU_ATTR_FALLTHROUGH;
861
863 #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
865 cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
866 TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),);
867 break;
868 }
869 #endif
870 TU_ATTR_FALLTHROUGH;
871
873 // itf_num+1 to account for data interface as well
874 set_config_complete(p_cdc, idx, itf_num + 1);
875 break;
876
877 default:
878 break;
879 }
880}
881
882static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
883 TU_VERIFY(p_cdc->acm_capability.support_line_request);
884 TU_LOG_DRV("CDC ACM Set Control Line State\r\n");
885
888 .recipient = TUSB_REQ_RCPT_INTERFACE,
889 .type = TUSB_REQ_TYPE_CLASS,
890 .direction = TUSB_DIR_OUT
891 },
893 .wValue = tu_htole16(line_state),
894 .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
895 .wLength = 0
896 };
897
898 p_cdc->user_control_cb = complete_cb;
899
900 tuh_xfer_t xfer = {
901 .daddr = p_cdc->daddr,
902 .ep_addr = 0,
903 .setup = &request,
904 .buffer = NULL,
905 .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
906 .user_data = user_data
907 };
908
909 TU_ASSERT(tuh_control_xfer(&xfer));
910 return true;
911}
912
914 TU_LOG_DRV("CDC ACM Set Line Conding\r\n");
915
918 .recipient = TUSB_REQ_RCPT_INTERFACE,
919 .type = TUSB_REQ_TYPE_CLASS,
920 .direction = TUSB_DIR_OUT
921 },
922 .bRequest = CDC_REQUEST_SET_LINE_CODING,
923 .wValue = 0,
924 .wIndex = tu_htole16(p_cdc->bInterfaceNumber),
925 .wLength = tu_htole16(sizeof(cdc_line_coding_t))
926 };
927
928 // use usbh enum buf to hold line coding since user line_coding variable does not live long enough
929 uint8_t* enum_buf = usbh_get_enum_buf();
930 memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
931
932 p_cdc->user_control_cb = complete_cb;
933 tuh_xfer_t xfer = {
934 .daddr = p_cdc->daddr,
935 .ep_addr = 0,
936 .setup = &request,
937 .buffer = enum_buf,
938 .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call
939 .user_data = user_data
940 };
941
942 TU_ASSERT(tuh_control_xfer(&xfer));
943 return true;
944}
945
946static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
948 TU_LOG_DRV("CDC ACM Set Data Format\r\n");
949
950 cdc_line_coding_t line_coding;
951 line_coding.bit_rate = p_cdc->line_coding.bit_rate;
952 line_coding.stop_bits = stop_bits;
953 line_coding.parity = parity;
954 line_coding.data_bits = data_bits;
955
956 return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data);
957}
958
959static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
960 TU_VERIFY(p_cdc->acm_capability.support_line_request);
961 cdc_line_coding_t line_coding = p_cdc->line_coding;
962 line_coding.bit_rate = baudrate;
963 return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data);
964}
965
966//--------------------------------------------------------------------+
967// FTDI
968//--------------------------------------------------------------------+
969#if CFG_TUH_CDC_FTDI
970
971enum {
978
979static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) {
980 // FTDI Interface includes 1 vendor interface + 2 bulk endpoints
981 TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2);
982 TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
983
984 cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
985 TU_VERIFY(p_cdc);
986
987 TU_LOG_DRV("FTDI opened\r\n");
989
990 // endpoint pair
991 tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
992
993 // data endpoints expected to be in pairs
994 return open_ep_stream_pair(p_cdc, desc_ep);
995}
996
997// set request without data
998static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1001 .recipient = TUSB_REQ_RCPT_DEVICE,
1002 .type = TUSB_REQ_TYPE_VENDOR,
1003 .direction = TUSB_DIR_OUT
1004 },
1005 .bRequest = command,
1006 .wValue = tu_htole16(value),
1007 .wIndex = 0,
1008 .wLength = 0
1009 };
1010
1011 tuh_xfer_t xfer = {
1012 .daddr = p_cdc->daddr,
1013 .ep_addr = 0,
1014 .setup = &request,
1015 .buffer = NULL,
1016 .complete_cb = complete_cb,
1017 .user_data = user_data
1018 };
1019
1020 return tuh_control_xfer(&xfer);
1021}
1022
1024 return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data);
1025}
1026
1027static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
1028 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1029 (void) p_cdc;
1030 (void) stop_bits;
1031 (void) parity;
1032 (void) data_bits;
1033 (void) complete_cb;
1034 (void) user_data;
1035 // TODO not implemented yet
1036 return false;
1037}
1038
1040 (void) p_cdc;
1041 (void) line_coding;
1042 (void) complete_cb;
1043 (void) user_data;
1044 // TODO not implemented yet
1045 return false;
1046}
1047
1048static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1049 TU_LOG_DRV("CDC FTDI Set Control Line State\r\n");
1050 p_cdc->user_control_cb = complete_cb;
1051 TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state,
1053 return true;
1054}
1055
1056static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) {
1057 const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
1058 uint32_t divisor;
1059
1060 /* divisor shifted 3 bits to the left */
1061 uint32_t divisor3 = base / (2 * baud);
1062 divisor = (divisor3 >> 3);
1063 divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14;
1064
1065 /* Deal with special cases for highest baud rates. */
1066 if (divisor == 1) { /* 1.0 */
1067 divisor = 0;
1068 }
1069 else if (divisor == 0x4001) { /* 1.5 */
1070 divisor = 1;
1071 }
1072
1073 return divisor;
1074}
1075
1076static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) {
1077 return ftdi_232bm_baud_base_to_divisor(baud, 48000000u);
1078}
1079
1080static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1081 uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate);
1082 TU_LOG_DRV("CDC FTDI Set BaudRate = %" PRIu32 ", divisor = 0x%04x\r\n", baudrate, divisor);
1083
1084 p_cdc->user_control_cb = complete_cb;
1085 p_cdc->requested_line_coding.bit_rate = baudrate;
1086 TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor,
1088
1089 return true;
1090}
1091
1093 uintptr_t const state = xfer->user_data;
1094 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
1095 uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
1096 cdch_interface_t * p_cdc = get_itf(idx);
1097 TU_ASSERT(p_cdc, );
1098
1099 switch(state) {
1100 // Note may need to read FTDI eeprom
1101 case CONFIG_FTDI_RESET:
1103 break;
1104
1106 #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
1107 TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),);
1108 break;
1109 #else
1110 TU_ATTR_FALLTHROUGH;
1111 #endif
1112
1114 #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
1115 cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
1117 break;
1118 #else
1119 TU_ATTR_FALLTHROUGH;
1120 #endif
1121 }
1122
1123 case CONFIG_FTDI_SET_DATA: {
1124 #if 0 // TODO set data format
1125 #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
1126 cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
1127 TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),);
1128 break;
1129 #endif
1130 #endif
1131
1132 TU_ATTR_FALLTHROUGH;
1133 }
1134
1136 set_config_complete(p_cdc, idx, itf_num);
1137 break;
1138
1139 default:
1140 break;
1141 }
1142}
1143
1144#endif
1145
1146//--------------------------------------------------------------------+
1147// CP210x
1148//--------------------------------------------------------------------+
1149
1150#if CFG_TUH_CDC_CP210X
1151
1152enum {
1159
1160static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
1161 // CP210x Interface includes 1 vendor interface + 2 bulk endpoints
1162 TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2);
1163 TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len);
1164
1165 cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc);
1166 TU_VERIFY(p_cdc);
1167
1168 TU_LOG_DRV("CP210x opened\r\n");
1170
1171 // endpoint pair
1172 tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
1173
1174 // data endpoints expected to be in pairs
1175 return open_ep_stream_pair(p_cdc, desc_ep);
1176}
1177
1178static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1181 .recipient = TUSB_REQ_RCPT_INTERFACE,
1182 .type = TUSB_REQ_TYPE_VENDOR,
1183 .direction = TUSB_DIR_OUT
1184 },
1185 .bRequest = command,
1186 .wValue = tu_htole16(value),
1187 .wIndex = p_cdc->bInterfaceNumber,
1188 .wLength = tu_htole16(length)
1189 };
1190
1191 // use usbh enum buf since application variable does not live long enough
1192 uint8_t* enum_buf = NULL;
1193
1194 if (buffer && length > 0) {
1195 enum_buf = usbh_get_enum_buf();
1196 tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length);
1197 }
1198
1199 tuh_xfer_t xfer = {
1200 .daddr = p_cdc->daddr,
1201 .ep_addr = 0,
1202 .setup = &request,
1203 .buffer = enum_buf,
1204 .complete_cb = complete_cb,
1205 .user_data = user_data
1206 };
1207
1208 return tuh_control_xfer(&xfer);
1209}
1210
1211static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1212 return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data);
1213}
1214
1216 // TODO implement later
1217 (void) p_cdc;
1218 (void) line_coding;
1219 (void) complete_cb;
1220 (void) user_data;
1221 return false;
1222}
1223
1224static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1225 TU_LOG_DRV("CDC CP210x Set BaudRate = %" PRIu32 "\r\n", baudrate);
1226 uint32_t baud_le = tu_htole32(baudrate);
1227 p_cdc->user_control_cb = complete_cb;
1228 return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4,
1230}
1231
1232static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
1233 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1234 (void) p_cdc;
1235 (void) stop_bits;
1236 (void) parity;
1237 (void) data_bits;
1238 (void) complete_cb;
1239 (void) user_data;
1240 // TODO not implemented yet
1241 return false;
1242}
1243
1244static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1245 TU_LOG_DRV("CDC CP210x Set Control Line State\r\n");
1246 p_cdc->user_control_cb = complete_cb;
1247 return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0,
1249}
1250
1252 uintptr_t const state = xfer->user_data;
1253 uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
1254 uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
1255 cdch_interface_t *p_cdc = get_itf(idx);
1256 TU_ASSERT(p_cdc,);
1257
1258 switch (state) {
1261 break;
1262
1264 #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
1265 cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
1267 break;
1268 #else
1269 TU_ATTR_FALLTHROUGH;
1270 #endif
1271 }
1272
1274 #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now
1275 cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
1276 break;
1277 #else
1278 TU_ATTR_FALLTHROUGH;
1279 #endif
1280 }
1281
1283 #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
1284 TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),);
1285 break;
1286 #else
1287 TU_ATTR_FALLTHROUGH;
1288 #endif
1289
1291 set_config_complete(p_cdc, idx, itf_num);
1292 break;
1293
1294 default: break;
1295 }
1296}
1297
1298#endif
1299
1300//--------------------------------------------------------------------+
1301// CH34x (CH340 & CH341)
1302//--------------------------------------------------------------------+
1303
1304#if CFG_TUH_CDC_CH34X
1305
1306static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits);
1307static uint16_t ch34x_get_divisor_prescaler(uint32_t baval);
1308
1309//------------- control request -------------//
1310
1311static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value,
1312 uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1313 tusb_control_request_t const request_setup = {
1315 .recipient = TUSB_REQ_RCPT_DEVICE,
1316 .type = TUSB_REQ_TYPE_VENDOR,
1317 .direction = direction & 0x01u
1318 },
1319 .bRequest = request,
1320 .wValue = tu_htole16 (value),
1321 .wIndex = tu_htole16 (index),
1322 .wLength = tu_htole16 (length)
1323 };
1324
1325 // use usbh enum buf since application variable does not live long enough
1326 uint8_t* enum_buf = NULL;
1327
1328 if (buffer && length > 0) {
1329 enum_buf = usbh_get_enum_buf();
1330 if (direction == TUSB_DIR_OUT) {
1331 tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length);
1332 }
1333 }
1334
1335 tuh_xfer_t xfer = {
1336 .daddr = p_cdc->daddr,
1337 .ep_addr = 0,
1338 .setup = &request_setup,
1339 .buffer = enum_buf,
1340 .complete_cb = complete_cb,
1341 .user_data = user_data
1342 };
1343
1344 return tuh_control_xfer(&xfer);
1345}
1346
1347static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index,
1348 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1349 return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data);
1350}
1351
1352static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index,
1353 uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1354 return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize,
1356}
1357
1358static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1359 return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data);
1360}
1361
1362//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg,
1363// uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data )
1364//{
1365// return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data );
1366//}
1367
1368static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
1369 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1370 uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate);
1371 TU_VERIFY(div_ps);
1372 TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps,
1374 return true;
1375}
1376
1377//------------- Driver API -------------//
1378
1379// internal control complete to update state such as line state, encoding
1381 // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
1383}
1384
1385static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits,
1386 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1387 p_cdc->requested_line_coding.stop_bits = stop_bits;
1388 p_cdc->requested_line_coding.parity = parity;
1389 p_cdc->requested_line_coding.data_bits = data_bits;
1390
1391 uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits);
1392 TU_VERIFY(lcr);
1393 TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr,
1395 return true;
1396}
1397
1398static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
1399 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1400 p_cdc->requested_line_coding.bit_rate = baudrate;
1401 p_cdc->user_control_cb = complete_cb;
1402 TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate,
1404 return true;
1405}
1406
1408 // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
1409 uint8_t const itf_num = 0;
1410 uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
1411 cdch_interface_t* p_cdc = get_itf(idx);
1412 TU_ASSERT(p_cdc, );
1413
1414 if (xfer->result == XFER_RESULT_SUCCESS) {
1415 // stage 1 success, continue to stage 2
1416 p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
1417 TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity,
1418 p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), );
1419 } else {
1420 // stage 1 failed, notify user
1421 xfer->complete_cb = p_cdc->user_control_cb;
1422 if (xfer->complete_cb) {
1423 xfer->complete_cb(xfer);
1424 }
1425 }
1426}
1427
1428// 2 stages: set baudrate (stage1) + set data format (stage2)
1429static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding,
1430 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1431 p_cdc->requested_line_coding = *line_coding;
1432 p_cdc->user_control_cb = complete_cb;
1433
1434 if (complete_cb) {
1435 // stage 1 set baudrate
1436 TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate,
1438 } else {
1439 // sync call
1440 xfer_result_t result;
1441
1442 // stage 1 set baudrate
1443 TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result));
1444 TU_VERIFY(result == XFER_RESULT_SUCCESS);
1445 p_cdc->line_coding.bit_rate = line_coding->bit_rate;
1446
1447 // stage 2 set data format
1448 TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits,
1449 NULL, (uintptr_t) &result));
1450 TU_VERIFY(result == XFER_RESULT_SUCCESS);
1451 p_cdc->line_coding.stop_bits = line_coding->stop_bits;
1452 p_cdc->line_coding.parity = line_coding->parity;
1453 p_cdc->line_coding.data_bits = line_coding->data_bits;
1454
1455 // update transfer result, user_data is expected to point to xfer_result_t
1456 if (user_data) {
1457 *((xfer_result_t*) user_data) = result;
1458 }
1459 }
1460
1461 return true;
1462}
1463
1464static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state,
1465 tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
1466 uint8_t control = 0;
1467 if (line_state & CDC_CONTROL_LINE_STATE_RTS) {
1468 control |= CH34X_BIT_RTS;
1469 }
1470 if (line_state & CDC_CONTROL_LINE_STATE_DTR) {
1471 control |= CH34X_BIT_DTR;
1472 }
1473
1474 // CH34x signals are inverted
1475 control = ~control;
1476
1477 p_cdc->user_control_cb = complete_cb;
1478 TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0,
1480 return true;
1481}
1482
1483//------------- Enumeration -------------//
1484enum {
1492
1493static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) {
1494 // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints
1495 TU_VERIFY (itf_desc->bNumEndpoints == 3);
1496 TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len);
1497
1498 cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc);
1499 TU_VERIFY (p_cdc);
1500
1501 TU_LOG_DRV ("CH34x opened\r\n");
1503
1504 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc);
1505
1506 // data endpoints expected to be in pairs
1507 TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep));
1508 desc_ep += 2;
1509
1510 // Interrupt endpoint: not used for now
1511 TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) &&
1512 TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer);
1513 TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
1514 p_cdc->ep_notif = desc_ep->bEndpointAddress;
1515
1516 return true;
1517}
1518
1520 // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber
1521 uint8_t const itf_num = 0;
1522 uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
1523 cdch_interface_t* p_cdc = get_itf(idx);
1524 uintptr_t const state = xfer->user_data;
1525 uint8_t buffer[2]; // TODO remove
1526 TU_ASSERT (p_cdc,);
1527 TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,);
1528
1529 switch (state) {
1531 TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr);
1532 TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),);
1533 break;
1534
1536 // handle version read data, set CH34x line coding (incl. baudrate)
1537 uint8_t const version = xfer->buffer[0];
1538 TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version);
1539 // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD
1540 TU_ASSERT (version >= 0x30,);
1541 // init CH34x with line coding
1542 cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
1543 uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate);
1544 TU_ASSERT(div_ps, );
1545 uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits);
1546 TU_ASSERT(lcr, );
1547 TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps,
1549 break;
1550 }
1551
1553 // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver
1554 p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X);
1555 TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),);
1556 break;
1557
1559 // no hardware flow control
1560 TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),);
1561 break;
1562
1564 // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT)
1565 TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),);
1566 break;
1567
1569 set_config_complete(p_cdc, idx, itf_num);
1570 break;
1571
1572 default:
1573 TU_ASSERT (false,);
1574 break;
1575 }
1576}
1577
1578//------------- CH34x helper -------------//
1579
1580// calculate divisor and prescaler for baudrate, return it as 16-bit combined value
1581static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) {
1582 uint8_t a;
1583 uint8_t b;
1584 uint32_t c;
1585
1586 TU_VERIFY(baval != 0 && baval <= 2000000, 0);
1587 switch (baval) {
1588 case 921600:
1589 a = 0xf3;
1590 b = 7;
1591 break;
1592
1593 case 307200:
1594 a = 0xd9;
1595 b = 7;
1596 break;
1597
1598 default:
1599 if (baval > 6000000 / 255) {
1600 b = 3;
1601 c = 6000000;
1602 } else if (baval > 750000 / 255) {
1603 b = 2;
1604 c = 750000;
1605 } else if (baval > 93750 / 255) {
1606 b = 1;
1607 c = 93750;
1608 } else {
1609 b = 0;
1610 c = 11719;
1611 }
1612 a = (uint8_t) (c / baval);
1613 if (a == 0 || a == 0xFF) {
1614 return 0;
1615 }
1616 if ((c / a - baval) > (baval - c / (a + 1))) {
1617 a++;
1618 }
1619 a = (uint8_t) (256 - a);
1620 break;
1621 }
1622
1623 // reg divisor = a, reg prescaler = b
1624 // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE,
1625 // otherwise the chip will buffer data.
1626 return (uint16_t) ((uint16_t)a << 8 | 0x80 | b);
1627}
1628
1629// calculate lcr value from data coding
1630static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) {
1631 uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX;
1632 TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0);
1633 lcr |= (uint8_t) (data_bits - 5);
1634
1635 switch(parity) {
1637 break;
1638
1640 lcr |= CH34X_LCR_ENABLE_PAR;
1641 break;
1642
1644 lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN;
1645 break;
1646
1648 lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE;
1649 break;
1650
1652 lcr |= CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN;
1653 break;
1654
1655 default: break;
1656 }
1657
1658 // 1.5 stop bits not supported
1659 TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0);
1660 if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) {
1661 lcr |= CH34X_LCR_STOP_BITS_2;
1662 }
1663
1664 return lcr;
1665}
1666
1667
1668#endif // CFG_TUH_CDC_CH34X
1669
1670#endif
bool tuh_cdc_write_clear(uint8_t idx)
Definition: cdc_host.c:354
@ CONFIG_ACM_SET_CONTROL_LINE_STATE
Definition: cdc_host.c:796
@ CONFIG_ACM_SET_LINE_CODING
Definition: cdc_host.c:797
@ CONFIG_ACM_COMPLETE
Definition: cdc_host.c:798
static bool acm_set_control_line_state(cdch_interface_t *p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:882
bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:571
bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: cdc_host.c:733
static bool ch34x_control_in(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1352
static bool ch34x_set_modem_ctrl(cdch_interface_t *p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1464
@ CONFIG_FTDI_SET_DATA
Definition: cdc_host.c:975
@ CONFIG_FTDI_SET_BAUDRATE
Definition: cdc_host.c:974
@ CONFIG_FTDI_MODEM_CTRL
Definition: cdc_host.c:973
@ CONFIG_FTDI_COMPLETE
Definition: cdc_host.c:976
@ CONFIG_FTDI_RESET
Definition: cdc_host.c:972
static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: cdc_host.c:801
static uint16_t const ch34x_vid_pid_list[][2]
Definition: cdc_host.c:133
static uint16_t const ftdi_vid_pid_list[][2]
Definition: cdc_host.c:103
static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len)
Definition: cdc_host.c:979
static void process_internal_control_complete(tuh_xfer_t *xfer, uint8_t itf_num)
Definition: cdc_host.c:406
static bool acm_set_baudrate(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:959
static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1224
static bool acm_set_line_coding(cdch_interface_t *p_cdc, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:913
static CFG_TUH_MEM_SECTION cdch_interface_t cdch_data[CFG_TUH_CDC]
Definition: cdc_host.c:84
bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
Definition: cdc_host.c:772
static void acm_process_config(tuh_xfer_t *xfer)
Definition: cdc_host.c:845
static bool ftdi_sio_set_request(cdch_interface_t *p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:998
TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers)==SERIAL_DRIVER_COUNT, "Serial driver count mismatch")
static bool ch34x_set_line_coding(cdch_interface_t *p_cdc, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1429
static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1244
bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:548
static bool ftdi_sio_set_baudrate(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1080
static bool ftdi_sio_set_modem_ctrl(cdch_interface_t *p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1048
static bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1211
@ CONFIG_CH34X_MODEM_CONTROL
Definition: cdc_host.c:1489
@ CONFIG_CH34X_COMPLETE
Definition: cdc_host.c:1490
@ CONFIG_CH34X_SERIAL_INIT
Definition: cdc_host.c:1486
@ CONFIG_CH34X_READ_VERSION
Definition: cdc_host.c:1485
@ CONFIG_CH34X_FLOW_CONTROL
Definition: cdc_host.c:1488
@ CONFIG_CH34X_SPECIAL_REG_WRITE
Definition: cdc_host.c:1487
static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud)
Definition: cdc_host.c:1076
static uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr)
Definition: cdc_host.c:240
static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t const *desc_ep)
Definition: cdc_host.c:715
uint32_t tuh_cdc_write_available(uint8_t idx)
Definition: cdc_host.c:361
bool tuh_cdc_read_clear(uint8_t idx)
Definition: cdc_host.c:393
static void set_config_complete(cdch_interface_t *p_cdc, uint8_t idx, uint8_t itf_num)
Definition: cdc_host.c:760
static bool ch34x_control_out(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1347
static const cdch_serial_driver_t serial_drivers[]
Definition: cdc_host.c:175
static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1215
uint32_t tuh_cdc_read(uint8_t idx, void *buffer, uint32_t bufsize)
Definition: cdc_host.c:372
static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc)
Definition: cdc_host.c:252
bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t *info)
Definition: cdc_host.c:285
static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: cdc_host.c:1160
bool tuh_cdc_mounted(uint8_t idx)
Definition: cdc_host.c:307
static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer)
Definition: cdc_host.c:1407
static void cdch_internal_control_complete(tuh_xfer_t *xfer)
Definition: cdc_host.c:520
bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t *line_coding)
Definition: cdc_host.c:327
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:525
bool tuh_cdc_peek(uint8_t idx, uint8_t *ch)
Definition: cdc_host.c:386
bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:597
void cdch_close(uint8_t daddr)
Definition: cdc_host.c:650
static uint16_t const cp210x_vid_pid_list[][2]
Definition: cdc_host.c:118
static bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1023
static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1398
static void ch34x_control_complete(tuh_xfer_t *xfer)
Definition: cdc_host.c:1380
static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits)
Definition: cdc_host.c:1630
@ CONFIG_CP210X_IFC_ENABLE
Definition: cdc_host.c:1153
@ CONFIG_CP210X_SET_BAUDRATE
Definition: cdc_host.c:1154
@ CONFIG_CP210X_SET_LINE_CTL
Definition: cdc_host.c:1155
@ CONFIG_CP210X_SET_DTR_RTS
Definition: cdc_host.c:1156
@ CONFIG_CP210X_COMPLETE
Definition: cdc_host.c:1157
static bool cp210x_set_data_format(cdch_interface_t *p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1232
static bool ftdi_set_line_coding(cdch_interface_t *p_cdc, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1039
bool tuh_cdc_get_rts(uint8_t idx)
Definition: cdc_host.c:320
static cdch_interface_t * get_itf(uint8_t idx)
Definition: cdc_host.c:233
@ SERIAL_DRIVER_ACM
Definition: cdc_host.c:146
@ SERIAL_DRIVER_FTDI
Definition: cdc_host.c:149
@ SERIAL_DRIVER_CP210X
Definition: cdc_host.c:153
@ SERIAL_DRIVER_CH34X
Definition: cdc_host.c:157
@ SERIAL_DRIVER_COUNT
Definition: cdc_host.c:160
static bool cp210x_set_request(cdch_interface_t *p_cdc, uint8_t command, uint16_t value, uint8_t *buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1178
bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
Definition: cdc_host.c:668
bool tuh_cdc_get_dtr(uint8_t idx)
Definition: cdc_host.c:313
static uint16_t ch34x_get_divisor_prescaler(uint32_t baval)
Definition: cdc_host.c:1581
uint32_t tuh_cdc_write(uint8_t idx, void const *buffer, uint32_t bufsize)
Definition: cdc_host.c:340
static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1368
static bool ftdi_set_data_format(cdch_interface_t *p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1027
bool cdch_init(void)
Definition: cdc_host.c:624
static bool ch34x_set_data_format(cdch_interface_t *p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1385
static bool acm_set_data_format(cdch_interface_t *p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:946
uint32_t tuh_cdc_write_flush(uint8_t idx)
Definition: cdc_host.c:347
bool cdch_deinit(void)
Definition: cdc_host.c:641
uint32_t tuh_cdc_read_available(uint8_t idx)
Definition: cdc_host.c:379
static bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1358
static bool ch34x_set_request(cdch_interface_t *p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t *buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:1311
uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num)
Definition: cdc_host.c:276
static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: cdc_host.c:1493
static void ch34x_process_config(tuh_xfer_t *xfer)
Definition: cdc_host.c:1519
static void cp210x_process_config(tuh_xfer_t *xfer)
Definition: cdc_host.c:1251
static void ftdi_process_config(tuh_xfer_t *xfer)
Definition: cdc_host.c:1092
static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base)
Definition: cdc_host.c:1056
TU_ATTR_WEAK void tuh_cdc_mount_cb(uint8_t idx)
TU_ATTR_WEAK void tuh_cdc_umount_cb(uint8_t idx)
TU_ATTR_WEAK void tuh_cdc_rx_cb(uint8_t idx)
TU_ATTR_WEAK void tuh_cdc_tx_complete_cb(uint8_t idx)
xfer_td_t xfer[EP_CBI_COUNT+1][2]
Definition: dcd_nrf5x.c:119
static usb_descriptor_buffers_t desc
Definition: dcd_pio_usb.c:46
struct TU_ATTR_PACKED cdc_line_coding_t
static uint8_t cdc_functional_desc_typeof(uint8_t const *p_desc)
Definition: cdc.h:387
@ CDC_REQUEST_SET_LINE_CODING
Definition: cdc.h:153
@ CDC_REQUEST_SET_CONTROL_LINE_STATE
Definition: cdc.h:155
@ CDC_LINE_CODING_STOP_BITS_1_5
Definition: cdc.h:191
@ CDC_LINE_CODING_STOP_BITS_2
Definition: cdc.h:192
@ CDC_LINE_CODING_PARITY_MARK
Definition: cdc.h:204
@ CDC_LINE_CODING_PARITY_ODD
Definition: cdc.h:202
@ CDC_LINE_CODING_PARITY_SPACE
Definition: cdc.h:205
@ CDC_LINE_CODING_PARITY_EVEN
Definition: cdc.h:203
@ CDC_LINE_CODING_PARITY_NONE
Definition: cdc.h:201
@ CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT
Abstract Control Management Functional Descriptor.
Definition: cdc.h:85
@ CDC_CONTROL_LINE_STATE_DTR
Definition: cdc.h:185
@ CDC_CONTROL_LINE_STATE_RTS
Definition: cdc.h:186
static void process_set_config(tuh_xfer_t *xfer)
Definition: hid_host.c:553
uint8_t const * buffer
Definition: midi_device.h:100
uint32_t bufsize
Definition: midi_device.h:95
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 stop_bits
0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
Definition: cdc.h:398
uint8_t support_line_request
Device supports the request combination of Set_Line_Coding, Set_Control_Line_State,...
Definition: cdc.h:304
uint8_t * buffer
Definition: video_device.c:111
uint16_t wIndex
Definition: audio.h:943
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
Definition: audio.h:657
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
Definition: tusb_types.h:349
uint8_t parity
0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
Definition: cdc.h:399
struct TU_ATTR_PACKED::@5 bmCapabilities
uint8_t data_bits
can be 5, 6, 7, 8 or 16
Definition: cdc.h:400
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Definition: tusb_types.h:350
uint32_t bit_rate
Definition: cdc.h:397
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
Definition: tusb_types.h:348
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Definition: tusb_types.h:351
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
Definition: tusb_types.h:346
uint8_t bInterfaceSubClass
Definition: cdc_host.c:53
cdc_acm_capability_t acm_capability
Definition: cdc_host.c:59
uint8_t serial_drid
Definition: cdc_host.c:57
uint8_t bInterfaceProtocol
Definition: cdc_host.c:54
uint8_t daddr
Definition: cdc_host.c:51
uint8_t ep_notif
Definition: cdc_host.c:56
uint8_t bInterfaceNumber
Definition: cdc_host.c:52
bool(*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len)
Definition: cdc_host.c:166
uint16_t const vid_pid_count
Definition: cdc_host.c:165
uint16_t const (* vid_pid_list)[2]
Definition: cdc_host.c:164
bool(*const set_data_format)(cdch_interface_t *p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:170
void(*const process_set_config)(tuh_xfer_t *xfer)
Definition: cdc_host.c:167
bool(*const set_control_line_state)(cdch_interface_t *p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:168
bool(*const set_baudrate)(cdch_interface_t *p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:169
bool(*const set_line_coding)(cdch_interface_t *p_cdc, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
Definition: cdc_host.c:171
uint8_t * buffer
Definition: dcd_nrf5x.c:99
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
static TU_ATTR_ALWAYS_INLINE int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count)
Definition: tusb_common.h:114
static TU_ATTR_ALWAYS_INLINE uint16_t tu_u16(uint8_t high, uint8_t low)
Definition: tusb_common.h:133
bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t *s, uint32_t last_xferred_bytes)
Definition: tusb.c:353
static TU_ATTR_ALWAYS_INLINE bool tu_edpt_stream_clear(tu_edpt_stream_t *s)
Definition: tusb_private.h:110
static TU_ATTR_ALWAYS_INLINE void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t *s, uint32_t xferred_bytes, uint32_t skip_offset)
Definition: tusb_private.h:151
static TU_ATTR_ALWAYS_INLINE void tu_edpt_stream_close(tu_edpt_stream_t *s)
Definition: tusb_private.h:104
static TU_ATTR_ALWAYS_INLINE bool tu_edpt_stream_peek(tu_edpt_stream_t *s, uint8_t *ch)
Definition: tusb_private.h:164
static TU_ATTR_ALWAYS_INLINE uint32_t tu_edpt_stream_read_available(tu_edpt_stream_t *s)
Definition: tusb_private.h:159
uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t *s)
Definition: tusb.c:426
uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t *s, void *buffer, uint32_t bufsize)
Definition: tusb.c:461
uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t *s)
Definition: tusb.c:405
uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t *s)
Definition: tusb.c:362
uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t *s, void const *buffer, uint32_t bufsize)
Definition: tusb.c:382
static TU_ATTR_ALWAYS_INLINE void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t *s, uint32_t xferred_bytes)
Definition: tusb_private.h:143
static TU_ATTR_ALWAYS_INLINE void tu_edpt_stream_open(tu_edpt_stream_t *s, tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_private.h:97
bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool overwritable, void *ff_buf, uint16_t ff_bufsize, uint8_t *ep_buf, uint16_t ep_bufsize)
Definition: tusb.c:282
bool tu_edpt_stream_deinit(tu_edpt_stream_t *s)
Definition: tusb.c:302
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_CLASS_CDC
Definition: tusb_types.h:161
@ TUSB_CLASS_CDC_DATA
Definition: tusb_types.h:169
@ TUSB_CLASS_VENDOR_SPECIFIC
Definition: tusb_types.h:181
xfer_result_t
Definition: tusb_types.h:236
@ XFER_RESULT_SUCCESS
Definition: tusb_types.h:237
@ XFER_RESULT_INVALID
Definition: tusb_types.h:241
@ TUSB_REQ_RCPT_DEVICE
Definition: tusb_types.h:151
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
@ TUSB_XFER_INTERRUPT
Definition: tusb_types.h:62
@ 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_desc_type(void const *desc)
Definition: tusb_types.h:537
@ TUSB_REQ_TYPE_VENDOR
Definition: tusb_types.h:146
@ TUSB_REQ_TYPE_CLASS
Definition: tusb_types.h:145
struct TU_ATTR_PACKED tusb_desc_interface_t
USB Interface Descriptor.
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
Definition: tusb_types.h:531
@ TUSB_DESC_CS_INTERFACE
Definition: tusb_types.h:114
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
@ TUSB_INDEX_INVALID_8
Definition: tusb_types.h:274
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid)
Definition: usbh.c:297
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
Definition: usbh.c:1717
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
uint8_t daddr
Definition: usbh.c:264
uintptr_t user_data
Definition: usbh.c:262
uint8_t * usbh_get_enum_buf(void)
Definition: usbh.c:819
bool tuh_control_xfer(tuh_xfer_t *xfer)
Definition: usbh.c:602
tuh_xfer_cb_t complete_cb
Definition: usbh.c:261
bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep)
Definition: usbh.c:930
void(* tuh_xfer_cb_t)(tuh_xfer_t *xfer)
Definition: usbh.h:44