Merge branch 'master' into fork/HiFiPhile/async_io

This commit is contained in:
hathach
2025-06-30 21:09:40 +07:00
17 changed files with 2461 additions and 1294 deletions

View File

@@ -31,6 +31,13 @@ Notable contributors
- Most features development
`Heiko Kuester <https://github.com/IngHK>`__
--------------------------------------------
- Add CH34x and PL2303 support (CDC host)
- Improve FTDI and CP210x support (CDC host)
`Hristo Gochkov <https://github.com/me-no-dev>`__
-------------------------------------------------

View File

@@ -74,7 +74,7 @@ Host Stack
- Human Interface Device (HID): Keyboard, Mouse, Generic
- Mass Storage Class (MSC)
- Communication Device Class: CDC-ACM
- Vendor serial over USB: FTDI, CP210x, CH34x
- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303
- Hub with multiple-level support
Similar to the Device Stack, if you have a special requirement, ``usbh_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack.

View File

@@ -31,8 +31,7 @@ static size_t get_console_inputs(uint8_t* buf, size_t bufsize) {
size_t count = 0;
while (count < bufsize) {
int ch = board_getchar();
if (ch <= 0) break;
if (ch <= 0) { break; }
buf[count] = (uint8_t) ch;
count++;
}
@@ -69,10 +68,12 @@ void tuh_cdc_rx_cb(uint8_t idx) {
uint32_t const bufsize = sizeof(buf) - 1;
// forward cdc interfaces -> console
uint32_t count = tuh_cdc_read(idx, buf, bufsize);
const uint32_t count = tuh_cdc_read(idx, buf, bufsize);
if (count) {
buf[count] = 0;
printf("%s", (char*) buf);
fflush(stdout);
}
}
// Invoked when a device with CDC interface is mounted
@@ -88,7 +89,7 @@ void tuh_cdc_mount_cb(uint8_t idx) {
// If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack
// while eneumerating new cdc device
cdc_line_coding_t line_coding = {0};
if (tuh_cdc_get_local_line_coding(idx, &line_coding)) {
if (tuh_cdc_get_line_coding_local(idx, &line_coding)) {
printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits);
printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits);
}

View File

@@ -103,10 +103,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
#define CFG_TUH_CDC 1 // CDC ACM
#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -122,7 +123,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width

View File

@@ -108,10 +108,11 @@
#define CFG_TUH_ENUMERATION_BUFSIZE 256
#define CFG_TUH_HUB 1 // number of supported hubs
#define CFG_TUH_CDC 1 // CDC ACM
#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM
#define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
@@ -127,7 +128,7 @@
// Set Line Control state on enumeration/mounted:
// DTR ( bit 0), RTS (bit 1)
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS)
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
// bit rate = 115200, 1 stop bit, no parity, 8 bit data width

View File

@@ -1003,22 +1003,24 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
ep_fb = desc_ep->bEndpointAddress;
}
#endif
// Data EP
if (desc_ep->bmAttributes.usage == 0) {
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
#if CFG_TUD_AUDIO_ENABLE_EP_IN
// Data or data with implicit feedback IN EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
&& (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
ep_in = desc_ep->bEndpointAddress;
ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
}
#endif
} else {
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
// Data OUT EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT
&& desc_ep->bmAttributes.usage == 0) {
ep_out = desc_ep->bEndpointAddress;
ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
}
#endif
}
}
}
}
p_desc = tu_desc_next(p_desc);
}
@@ -1052,12 +1054,12 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
if (desc_ep->bmAttributes.usage == 0) {
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
// For data or data with implicit feedback IN EP
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
&& (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
_audiod_fct[i].interval_tx = desc_ep->bInterval;
}
}
}
} else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) {
if (tu_unaligned_read16(p_desc + 4) == AUDIO_TERM_TYPE_USB_STREAMING) {
_audiod_fct[i].bclock_id_tx = p_desc[8];
@@ -1227,7 +1229,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
usbd_edpt_clear_stall(rhport, ep_addr);
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP
// For data or data with implicit feedback IN EP
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2))
{
// Save address
audio->ep_in = ep_addr;

View File

@@ -192,6 +192,11 @@ typedef enum {
CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits
} cdc_line_coding_stopbits_t;
#define CDC_LINE_CODING_STOP_BITS_TEXT(STOP_BITS) ( \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \
STOP_BITS == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?" )
// TODO Backward compatible for typos. Maybe removed in the future release
#define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1
#define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5
@@ -205,6 +210,13 @@ typedef enum {
CDC_LINE_CODING_PARITY_SPACE = 4,
} cdc_line_coding_parity_t;
#define CDC_LINE_CODING_PARITY_CHAR(PARITY) ( \
PARITY == CDC_LINE_CODING_PARITY_NONE ? 'N' : \
PARITY == CDC_LINE_CODING_PARITY_ODD ? 'O' : \
PARITY == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \
PARITY == CDC_LINE_CODING_PARITY_MARK ? 'M' : \
PARITY == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?' )
//--------------------------------------------------------------------+
// Management Element Notification (Notification Endpoint)
//--------------------------------------------------------------------+
@@ -392,8 +404,7 @@ static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc)
//--------------------------------------------------------------------+
// Requests
//--------------------------------------------------------------------+
typedef struct TU_ATTR_PACKED
{
typedef struct TU_ATTR_PACKED {
uint32_t bit_rate;
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
@@ -402,15 +413,16 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
typedef struct TU_ATTR_PACKED
{
uint16_t dtr : 1;
uint16_t rts : 1;
uint16_t : 6;
uint16_t : 8;
typedef union TU_ATTR_PACKED {
struct {
uint8_t dtr : 1;
uint8_t rts : 1;
uint8_t : 6;
};
uint8_t value;
} cdc_line_control_state_t;
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct");
TU_ATTR_PACKED_END // End of all packed definitions
TU_ATTR_BIT_FIELD_ORDER_END

File diff suppressed because it is too large Load Diff

View File

@@ -37,16 +37,6 @@
// Class Driver Configuration
//--------------------------------------------------------------------+
// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1)
#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0
#endif
// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
//#endif
// RX FIFO size
#ifndef CFG_TUH_CDC_RX_BUFSIZE
#define CFG_TUH_CDC_RX_BUFSIZE TUH_EPSIZE_BULK_MPS
@@ -79,14 +69,27 @@ uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num);
// return true if index is correct and interface is currently mounted
bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info);
// Check if a interface is mounted
// Check if an interface is mounted
bool tuh_cdc_mounted(uint8_t idx);
// Get local (cached) line state
// This function should return correct values if tuh_cdc_set_control_line_state() / tuh_cdc_get_control_line_state()
// are invoked previously or CFG_TUH_CDC_LINE_STATE_ON_ENUM is defined.
bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state);
// Get current DTR status
bool tuh_cdc_get_dtr(uint8_t idx);
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_dtr(uint8_t idx) {
uint16_t line_state;
TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
return (line_state & CDC_CONTROL_LINE_STATE_DTR) != 0;
}
// Get current RTS status
bool tuh_cdc_get_rts(uint8_t idx);
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_rts(uint8_t idx) {
uint16_t line_state;
TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state));
return (line_state & CDC_CONTROL_LINE_STATE_RTS) != 0;
}
// Check if interface is connected (DTR active)
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
@@ -97,7 +100,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding()
// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined.
// NOTE: This function does not make any USB transfer request to device.
bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding);
bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t* line_coding);
#define tuh_cdc_get_local_line_coding tuh_cdc_get_line_coding_local // backward compatibility
//--------------------------------------------------------------------+
// Write API
@@ -132,18 +137,31 @@ bool tuh_cdc_peek(uint8_t idx, uint8_t* ch);
bool tuh_cdc_read_clear (uint8_t idx);
//--------------------------------------------------------------------+
// Control Endpoint (Request) API
// Control Request API
// Each Function will make a USB control transfer request to/from device
// - If complete_cb is provided, the function will return immediately and invoke
// the callback when request is complete.
// - If complete_cb is NULL, the function will block until request is complete.
// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result.
// - The function will return true if transfer is successful, false otherwise.
// In this case, user_data should be usb_xfer_result_t* to hold the transfer result.
//--------------------------------------------------------------------+
// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Request to Set DTR
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
cdc_line_control_state_t line_state = { .dtr = dtr_state };
line_state.rts = tuh_cdc_get_rts(idx);
return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
}
// Request to Set RTS
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
cdc_line_control_state_t line_state = { .rts = rts_state };
line_state.dtr = tuh_cdc_get_dtr(idx);
return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data);
}
// Request to set baudrate
bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
@@ -160,17 +178,52 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding,
// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding);
// Connect by set both DTR, RTS
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data);
}
// Disconnect by clear both DTR, RTS
TU_ATTR_ALWAYS_INLINE static inline
bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data);
}
//--------------------------------------------------------------------+
// Control Request Sync API
// Each Function will make a USB control transfer request to/from device the function will block until request is
// complete. The function will return the transfer request result
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_control_line_state_sync(uint8_t idx, uint16_t line_state) {
TU_API_SYNC(tuh_cdc_set_control_line_state, idx, line_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_dtr_sync(uint8_t idx, bool dtr_state) {
TU_API_SYNC(tuh_cdc_set_dtr, idx, dtr_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_rts_sync(uint8_t idx, bool rts_state) {
TU_API_SYNC(tuh_cdc_set_rts, idx, rts_state);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_baudrate_sync(uint8_t idx, uint32_t baudrate) {
TU_API_SYNC(tuh_cdc_set_baudrate, idx, baudrate);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_data_format_sync(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits) {
TU_API_SYNC(tuh_cdc_set_data_format, idx, stop_bits, parity, data_bits);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_line_coding_sync(uint8_t idx, cdc_line_coding_t const* line_coding) {
TU_API_SYNC(tuh_cdc_set_line_coding, idx, line_coding);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_connect_sync(uint8_t idx) {
TU_API_SYNC(tuh_cdc_connect, idx);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(uint8_t idx) {
TU_API_SYNC(tuh_cdc_disconnect, idx);
}
//--------------------------------------------------------------------+
// CDC APPLICATION CALLBACKS
//--------------------------------------------------------------------+

View File

@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _CH34X_H_
#define _CH34X_H_
#ifndef TUSB_CH34X_H
#define TUSB_CH34X_H
// There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found
// - https://github.com/WCHSoftGroup/ch341ser_linux
@@ -81,4 +81,4 @@
#define CH34X_LCR_CS5 0x00
#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
#endif /* _CH34X_H_ */
#endif // TUSB_CH34X_H

View File

@@ -28,9 +28,10 @@
// Protocol details can be found at AN571: CP210x Virtual COM Port Interface
// https://www.silabs.com/documents/public/application-notes/AN571.pdf
#define TU_CP210X_VID 0x10C4
// parts are overtaken from vendors driver
// https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz
/* Config request codes */
// Config request codes
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
@@ -59,4 +60,55 @@
#define CP210X_SET_BAUDRATE 0x1E
#define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device
// SILABSER_IFC_ENABLE_REQUEST_CODE
#define CP210X_UART_ENABLE 0x0001
#define CP210X_UART_DISABLE 0x0000
// SILABSER_SET_BAUDDIV_REQUEST_CODE
#define CP210X_BAUD_RATE_GEN_FREQ 0x384000
// SILABSER_SET_LINE_CTL_REQUEST_CODE
#define CP210X_BITS_DATA_MASK 0x0f00
#define CP210X_BITS_DATA_5 0x0500
#define CP210X_BITS_DATA_6 0x0600
#define CP210X_BITS_DATA_7 0x0700
#define CP210X_BITS_DATA_8 0x0800
#define CP210X_BITS_DATA_9 0x0900
#define CP210X_BITS_PARITY_MASK 0x00f0
#define CP210X_BITS_PARITY_NONE 0x0000
#define CP210X_BITS_PARITY_ODD 0x0010
#define CP210X_BITS_PARITY_EVEN 0x0020
#define CP210X_BITS_PARITY_MARK 0x0030
#define CP210X_BITS_PARITY_SPACE 0x0040
#define CP210X_BITS_STOP_MASK 0x000f
#define CP210X_BITS_STOP_1 0x0000
#define CP210X_BITS_STOP_1_5 0x0001
#define CP210X_BITS_STOP_2 0x0002
// SILABSER_SET_BREAK_REQUEST_CODE
#define CP210X_BREAK_ON 0x0001
#define CP210X_BREAK_OFF 0x0000
// SILABSER_SET_MHS_REQUEST_CODE
#define CP210X_MCR_DTR 0x0001
#define CP210X_MCR_RTS 0x0002
#define CP210X_MCR_ALL 0x0003
#define CP210X_MSR_CTS 0x0010
#define CP210X_MSR_DSR 0x0020
#define CP210X_MSR_RING 0x0040
#define CP210X_MSR_DCD 0x0080
#define CP210X_MSR_ALL 0x00F0
#define CP210X_CONTROL_WRITE_DTR 0x0100UL
#define CP210X_CONTROL_WRITE_RTS 0x0200UL
#define CP210X_LSR_BREAK 0x0001
#define CP210X_LSR_FRAMING_ERROR 0x0002
#define CP210X_LSR_HW_OVERRUN 0x0004
#define CP210X_LSR_QUEUE_OVERRUN 0x0008
#define CP210X_LSR_PARITY_ERROR 0x0010
#define CP210X_LSR_ALL 0x001F
#endif //TUSB_CP210X_H

View File

@@ -25,210 +25,131 @@
#ifndef TUSB_FTDI_SIO_H
#define TUSB_FTDI_SIO_H
// VID for matching FTDI devices
#define TU_FTDI_VID 0x0403
#include <stdint.h>
// Commands
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
#define FTDI_SIO_RESET 0 // Reset the port
#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register
#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register
#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate
#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port
#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register
#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character
#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character
#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer
#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer
#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode
#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins
#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM
/* FTDI_SIO_RESET */
// Channel indices for FT2232, FT2232H and FT4232H devices
#define CHANNEL_A 1
#define CHANNEL_B 2
#define CHANNEL_C 3
#define CHANNEL_D 4
// Port Identifier Table
#define PIT_DEFAULT 0 // SIOA
#define PIT_SIOA 1 // SIOA
// The device this driver is tested with one has only one port
#define PIT_SIOB 2 // SIOB
#define PIT_PARALLEL 3 // Parallel
// FTDI_SIO_RESET
#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
#define FTDI_SIO_RESET_REQUEST_TYPE 0x40
#define FTDI_SIO_RESET_SIO 0
#define FTDI_SIO_RESET_PURGE_RX 1
#define FTDI_SIO_RESET_PURGE_TX 2
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_RESET
* wValue: Control Value
* 0 = Reset SIO
* 1 = Purge RX buffer
* 2 = Purge TX buffer
* wIndex: Port
* wLength: 0
* Data: None
*
* The Reset SIO command has this effect:
*
* Sets flow control set to 'none'
* Event char = $0D
* Event trigger = disabled
* Purge RX buffer
* Purge TX buffer
* Clear DTR
* Clear RTS
* baud and data format not reset
*
* The Purge RX and TX buffer commands affect nothing except the buffers
*
*/
// FTDI_SIO_SET_BAUDRATE
#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
/* FTDI_SIO_MODEM_CTRL */
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_MODEM_CTRL
* wValue: ControlValue (see below)
* wIndex: Port
* wLength: 0
* Data: None
*
* NOTE: If the device is in RTS/CTS flow control, the RTS set by this
* command will be IGNORED without an error being returned
* Also - you can not set DTR and RTS with one control message
*/
enum ftdi_sio_baudrate {
ftdi_sio_b300 = 0,
ftdi_sio_b600 = 1,
ftdi_sio_b1200 = 2,
ftdi_sio_b2400 = 3,
ftdi_sio_b4800 = 4,
ftdi_sio_b9600 = 5,
ftdi_sio_b19200 = 6,
ftdi_sio_b38400 = 7,
ftdi_sio_b57600 = 8,
ftdi_sio_b115200 = 9
};
#define FTDI_SIO_SET_DTR_MASK 0x1
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
#define FTDI_SIO_SET_RTS_MASK 0x2
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
/*
* ControlValue
* B0 DTR state
* 0 = reset
* 1 = set
* B1 RTS state
* 0 = reset
* 1 = set
* B2..7 Reserved
* B8 DTR state enable
* 0 = ignore
* 1 = use DTR state
* B9 RTS state enable
* 0 = ignore
* 1 = use RTS state
* B10..15 Reserved
*/
/* FTDI_SIO_SET_FLOW_CTRL */
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
/*
* BmRequestType: 0100 0000b
* bRequest: FTDI_SIO_SET_FLOW_CTRL
* wValue: Xoff/Xon
* wIndex: Protocol/Port - hIndex is protocol / lIndex is port
* wLength: 0
* Data: None
*
* hIndex protocol is:
* B0 Output handshaking using RTS/CTS
* 0 = disabled
* 1 = enabled
* B1 Output handshaking using DTR/DSR
* 0 = disabled
* 1 = enabled
* B2 Xon/Xoff handshaking
* 0 = disabled
* 1 = enabled
*
* A value of zero in the hIndex field disables handshaking
*
* If Xon/Xoff handshaking is specified, the hValue field should contain the
* XOFF character and the lValue field contains the XON character.
*/
/* FTDI_SIO_SET_BAUD_RATE */
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_BAUDRATE
* wValue: BaudDivisor value - see below
* wIndex: Port
* wLength: 0
* Data: None
* The BaudDivisor values are calculated as follows (too complicated):
*/
/* FTDI_SIO_SET_DATA */
// FTDI_SIO_SET_DATA
#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) // same coding as ACM
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) // 1.5 not supported, for future use?
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
#define FTDI_SIO_SET_BREAK (0x1 << 14)
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_DATA
* wValue: Data characteristics (see below)
* wIndex: Port
* wLength: 0
* Data: No
*
* Data characteristics
*
* B0..7 Number of data bits
* B8..10 Parity
* 0 = None
* 1 = Odd
* 2 = Even
* 3 = Mark
* 4 = Space
* B11..13 Stop Bits
* 0 = 1
* 1 = 1.5
* 2 = 2
* B14
* 1 = TX ON (break)
* 0 = TX OFF (normal state)
* B15 Reserved
*
*/
// FTDI_SIO_MODEM_CTRL
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
#define FTDI_SIO_SET_DTR_MASK 0x1UL
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1UL)
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0UL)
#define FTDI_SIO_SET_RTS_MASK 0x2UL
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2UL)
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0UL)
// FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
// FTDI_SIO_GET_LATENCY_TIMER
#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER
#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0
// FTDI_SIO_SET_LATENCY_TIMER
#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER
#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40
// FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
// FTDI_SIO_GET_MODEM_STATUS
#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0
#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS
#define FTDI_SIO_CTS_MASK 0x10
#define FTDI_SIO_DSR_MASK 0x20
#define FTDI_SIO_RI_MASK 0x40
#define FTDI_SIO_RLSD_MASK 0x80
// FTDI_SIO_SET_BITMODE
#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
// Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST
#define FTDI_SIO_BITMODE_RESET 0x00
#define FTDI_SIO_BITMODE_CBUS 0x20
// FTDI_SIO_READ_PINS
#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0
#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
// FTDI_SIO_READ_EEPROM
#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
#define FTDI_FTX_CBUS_MUX_GPIO 0x8
#define FTDI_FT232R_CBUS_MUX_GPIO 0xa
/*
* DATA FORMAT
*
* IN Endpoint
*
* The device reserves the first two bytes of data on this endpoint to contain
* the current values of the modem and line status registers. In the absence of
* data, the device generates a message consisting of these two status bytes
* every 40 ms
*
* Byte 0: Modem Status
*
* Offset Description
* B0 Reserved - must be 1
* B1 Reserved - must be 0
* B2 Reserved - must be 0
* B3 Reserved - must be 0
* B4 Clear to Send (CTS)
* B5 Data Set Ready (DSR)
* B6 Ring Indicator (RI)
* B7 Receive Line Signal Detect (RLSD)
*
* Byte 1: Line Status
*
* Offset Description
* B0 Data Ready (DR)
* B1 Overrun Error (OE)
* B2 Parity Error (PE)
* B3 Framing Error (FE)
* B4 Break Interrupt (BI)
* B5 Transmitter Holding Register (THRE)
* B6 Transmitter Empty (TEMT)
* B7 Error in RCVR FIFO
*
*/
#define FTDI_RS0_CTS (1 << 4)
#define FTDI_RS0_DSR (1 << 5)
#define FTDI_RS0_RI (1 << 6)
@@ -243,4 +164,68 @@
#define FTDI_RS_TEMT (1 << 6)
#define FTDI_RS_FIFO (1 << 7)
// chip types and names
typedef enum ftdi_chip_type {
FTDI_SIO = 0,
// FTDI_FT232A,
FTDI_FT232B,
FTDI_FT2232C,
FTDI_FT232R,
FTDI_FT232H,
FTDI_FT2232H,
FTDI_FT4232H,
FTDI_FT4232HA,
FTDI_FT232HP,
FTDI_FT233HP,
FTDI_FT2232HP,
FTDI_FT2233HP,
FTDI_FT4232HP,
FTDI_FT4233HP,
FTDI_FTX,
FTDI_UNKNOWN
} ftdi_chip_type_t;
#define FTDI_CHIP_NAMES \
[FTDI_SIO] = "SIO", /* the serial part of FT8U100AX */ \
/* [FTDI_FT232A] = "FT232A", */ \
[FTDI_FT232B] = "FT232B", \
[FTDI_FT2232C] = "FT2232C/D", \
[FTDI_FT232R] = "FT232R", \
[FTDI_FT232H] = "FT232H", \
[FTDI_FT2232H] = "FTDI_FT2232H", \
[FTDI_FT4232H] = "FT4232H", \
[FTDI_FT4232HA] = "FT4232HA", \
[FTDI_FT232HP] = "FT232HP", \
[FTDI_FT233HP] = "FT233HP", \
[FTDI_FT2232HP] = "FT2232HP", \
[FTDI_FT2233HP] = "FT2233HP", \
[FTDI_FT4232HP] = "FT4232HP", \
[FTDI_FT4233HP] = "FT4233HP", \
[FTDI_FTX] = "FT-X", \
[FTDI_UNKNOWN] = "UNKNOWN"
// private interface data
typedef struct ftdi_private {
ftdi_chip_type_t chip_type;
uint8_t channel; // channel index, or 0 for legacy types
} ftdi_private_t;
#define FTDI_OK true
#define FTDI_FAIL false
#define FTDI_NOT_POSSIBLE -1
#define FTDI_REQUESTED -2
// division and round function overtaken from math.h
#define DIV_ROUND_CLOSEST(x, divisor)( \
{ \
typeof(x) __x = x; \
typeof(divisor) __d = divisor; \
(((typeof(x))-1) > 0 || \
((typeof(divisor))-1) > 0 || \
(((__x) > 0) == ((__d) > 0))) ? \
(((__x) + ((__d) / 2)) / (__d)) : \
(((__x) - ((__d) / 2)) / (__d)); \
} \
)
#endif //TUSB_FTDI_SIO_H

View File

@@ -0,0 +1,159 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2024 Heiko Kuester
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef TUSB_PL2303_H
#define TUSB_PL2303_H
#include <stdbool.h>
#include <stdint.h>
// There is no official documentation for the PL2303 chips.
// Reference can be found
// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.h and
// https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c
// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c
// quirks
#define PL2303_QUIRK_UART_STATE_IDX0 1
#define PL2303_QUIRK_LEGACY 2
#define PL2303_QUIRK_ENDPOINT_HACK 4
// requests and bits
#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_SET_LINE_REQUEST 0x20 // dec 32
#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34
#define PL2303_CONTROL_DTR 0x01 // dec 1
#define PL2303_CONTROL_RTS 0x02 // dec 2
#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface
#define PL2303_BREAK_REQUEST 0x23 // dec 35
#define PL2303_BREAK_ON 0xffff
#define PL2303_BREAK_OFF 0x0000
#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface
#define PL2303_GET_LINE_REQUEST 0x21 // dec 33
#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface
#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1
#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128
#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface
#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1
#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129
#define PL2303_UART_STATE_INDEX 8
#define PL2303_UART_STATE_MSR_MASK 0x8b
#define PL2303_UART_STATE_TRANSIENT_MASK 0x74
#define PL2303_UART_DCD 0x01
#define PL2303_UART_DSR 0x02
#define PL2303_UART_BREAK_ERROR 0x04
#define PL2303_UART_RING 0x08
#define PL2303_UART_FRAME_ERROR 0x10
#define PL2303_UART_PARITY_ERROR 0x20
#define PL2303_UART_OVERRUN_ERROR 0x40
#define PL2303_UART_CTS 0x80
#define PL2303_FLOWCTRL_MASK 0xf0
#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint
// registers via vendor read/write requests
#define PL2303_READ_TYPE_HX_STATUS 0x8080
#define PL2303_HXN_RESET_REG 0x07
#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
#define PL2303_HXN_FLOWCTRL_REG 0x0a
#define PL2303_HXN_FLOWCTRL_MASK 0x1c
#define PL2303_HXN_FLOWCTRL_NONE 0x1c
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
// type data
typedef enum pl2303_type {
PL2303_TYPE_H = 0, // 0
PL2303_TYPE_HX, // 1
PL2303_TYPE_TA, // 2
PL2303_TYPE_TB, // 3
PL2303_TYPE_HXD, // 4
PL2303_TYPE_HXN, // 5
PL2303_TYPE_COUNT,
PL2303_TYPE_NEED_SUPPORTS_HX_STATUS,
PL2303_TYPE_UNKNOWN,
} pl2303_type_t;
typedef struct pl2303_type_data {
uint32_t max_baud_rate;
uint8_t quirks;
uint8_t no_autoxonxoff : 1;
uint8_t no_divisors : 1;
uint8_t alt_divisors : 1;
} pl2303_type_data_t;
#define PL2303_TYPE_DATA \
[PL2303_TYPE_H] = { \
.max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, \
.no_autoxonxoff = 1, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_HX] = { \
.max_baud_rate = 6000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_TA] = { \
.max_baud_rate = 6000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
}, \
[PL2303_TYPE_TB] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \
}, \
[PL2303_TYPE_HXD] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \
}, \
[PL2303_TYPE_HXN] = { \
.max_baud_rate = 12000000, .quirks = 0, \
.no_autoxonxoff = 0, .no_divisors = 1, .alt_divisors = 0 \
}
typedef struct TU_ATTR_PACKED {
pl2303_type_t type;
uint8_t quirks;
bool supports_hx_status;
} pl2303_private_t;
// buffer sizes for line coding data
#define PL2303_LINE_CODING_BUFSIZE 7
#define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4
// bulk endpoints
#define PL2303_OUT_EP 0x02
#define PL2303_IN_EP 0x83
#endif // TUSB_PL2303_H

View File

@@ -278,6 +278,8 @@ typedef enum {
XFER_RESULT_INVALID
} xfer_result_t;
#define tusb_xfer_result_t xfer_result_t
// TODO remove
enum {
DESC_OFFSET_LEN = 0,
@@ -345,7 +347,6 @@ typedef struct TU_ATTR_PACKED {
uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
uint8_t iProduct ; ///< Index of string descriptor describing product.
uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
uint8_t bNumConfigurations ; ///< Number of possible configurations.
} tusb_desc_device_t;

View File

@@ -94,6 +94,20 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
typedef struct {
tuh_bus_info_t bus_info;
// Device Descriptor
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
// Device State
struct TU_ATTR_PACKED {
volatile uint8_t connected : 1; // After 1st transfer
@@ -103,18 +117,6 @@ typedef struct {
// volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh
};
// Device Descriptor
uint8_t ep0_size;
uint16_t idVendor;
uint16_t idProduct;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
// Configuration Descriptor
// uint8_t interface_count; // bNumInterfaces alias
// Endpoint & Interface
uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
@@ -373,6 +375,28 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) {
return true;
}
bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device) {
usbh_device_t *dev = get_device(daddr);
TU_VERIFY(dev && desc_device);
desc_device->bLength = sizeof(tusb_desc_device_t);
desc_device->bDescriptorType = TUSB_DESC_DEVICE;
desc_device->bcdUSB = dev->bcdUSB;
desc_device->bDeviceClass = dev->bDeviceClass;
desc_device->bDeviceSubClass = dev->bDeviceSubClass;
desc_device->bDeviceProtocol = dev->bDeviceProtocol;
desc_device->bMaxPacketSize0 = dev->bMaxPacketSize0;
desc_device->idVendor = dev->idVendor;
desc_device->idProduct = dev->idProduct;
desc_device->bcdDevice = dev->bcdDevice;
desc_device->iManufacturer = dev->iManufacturer;
desc_device->iProduct = dev->iProduct;
desc_device->iSerialNumber = dev->iSerialNumber;
desc_device->bNumConfigurations = dev->bNumConfigurations;
return true;
}
tusb_speed_t tuh_speed_get(uint8_t daddr) {
tuh_bus_info_t bus_info;
tuh_bus_info_get(daddr, &bus_info);
@@ -1085,7 +1109,8 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
// generic helper to get a descriptor
// if blocking, user_data is pointed to xfer_result
static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
TU_ATTR_ALWAYS_INLINE static inline
bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
tusb_control_request_t const request = {
.bmRequestType_bit = {
@@ -1127,7 +1152,6 @@ bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer
}
//------------- String Descriptor -------------//
bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data);
@@ -1265,47 +1289,6 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
return tuh_control_xfer(&xfer);
}
//--------------------------------------------------------------------+
// Descriptor Sync
//--------------------------------------------------------------------+
#define _CONTROL_SYNC_API(_async_func, ...) \
xfer_result_t result = XFER_RESULT_INVALID;\
TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
return (uint8_t) result
uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len);
}
uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len);
}
uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len);
}
uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
}
uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
}
uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
_CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
}
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+
@@ -1596,7 +1579,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
usbh_device_t* new_dev = get_device(new_addr);
new_dev->bus_info = *dev0_bus;
new_dev->connected = 1;
new_dev->ep0_size = desc_device->bMaxPacketSize0;
new_dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0;
TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),);
break;
@@ -1613,7 +1596,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
usbh_device_close(dev0_bus->rhport, 0); // close dev0
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint
TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
@@ -1626,8 +1609,14 @@ static void process_enumeration(tuh_xfer_t* xfer) {
case ENUM_GET_STRING_LANGUAGE_ID_LEN: {
// save the received device descriptor
tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl;
dev->bcdUSB = desc_device->bcdUSB;
dev->bDeviceClass = desc_device->bDeviceClass;
dev->bDeviceSubClass = desc_device->bDeviceSubClass;
dev->bDeviceProtocol = desc_device->bDeviceProtocol;
dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0;
dev->idVendor = desc_device->idVendor;
dev->idProduct = desc_device->idProduct;
dev->bcdDevice = desc_device->bcdDevice;
dev->iManufacturer = desc_device->iManufacturer;
dev->iProduct = desc_device->iProduct;
dev->iSerialNumber = desc_device->iSerialNumber;

View File

@@ -204,6 +204,9 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active);
// Get VID/PID of device
bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
// Get local (cached) device descriptor once device is enumerated
bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device);
// Get speed of device
tusb_speed_t tuh_speed_get(uint8_t daddr);
@@ -231,8 +234,18 @@ bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info);
//--------------------------------------------------------------------+
// Transfer API
// Each Function will make a USB transfer request to device. If
// - complete_cb != NULL, the function will return immediately and invoke the callback when request is complete.
// - complete_cb == NULL, the function will block until request is complete.
// In this case, user_data should be tusb_xfer_result_t* to hold the transfer result.
//--------------------------------------------------------------------+
// Helper to make Sync API from async one
#define TU_API_SYNC(_async_api, ...) \
xfer_result_t result = XFER_RESULT_INVALID;\
TU_VERIFY(_async_api(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \
return result
// Submit a control transfer
// - async: complete callback invoked when finished.
// - sync : blocking if complete callback is NULL.
@@ -324,45 +337,54 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void*
//--------------------------------------------------------------------+
// Descriptors Synchronous (blocking)
// Sync API which is blocking until transfer is complete.
// return transfer result
//--------------------------------------------------------------------+
// Sync (blocking) version of tuh_descriptor_get()
// return transfer result
uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get, daddr, type, index, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_device()
// return transfer result
uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_device()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_device, daddr, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_configuration()
// return transfer result
uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_configuration()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_configuration, daddr, index, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_hid_report()
// return transfer result
uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_hid_report()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_string()
// return transfer result
uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_string()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_string, daddr, index, language_id, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_string_langid()
TU_ATTR_ALWAYS_INLINE static inline
uint8_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
// Sync version of tuh_descriptor_get_string_langid()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
return tuh_descriptor_get_string_sync(daddr, 0, 0, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
// return transfer result
uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_manufacturer_string()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_product_string()
// return transfer result
uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_product_string()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_product_string, daddr, language_id, buffer, len);
}
// Sync (blocking) version of tuh_descriptor_get_serial_string()
// return transfer result
uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
// Sync version of tuh_descriptor_get_serial_string()
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) {
TU_API_SYNC(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len);
}
#ifdef __cplusplus
}

View File

@@ -602,9 +602,22 @@
// List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID
#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST
#define CFG_TUH_CDC_FTDI_VID_PID_LIST \
{0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \
{0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \
{0x0403, 0xCD18}
{0x0403, 0x6001}, /* Similar device to SIO above */ \
{0x0403, 0x6006}, /* FTDI's alternate PID for above */ \
{0x0403, 0x6010}, /* Dual channel device */ \
{0x0403, 0x6011}, /* Quad channel hi-speed device */ \
{0x0403, 0x6014}, /* Single channel hi-speed device */ \
{0x0403, 0x6015}, /* FT-X series (FT201X, FT230X, FT231X, etc) */ \
{0x0403, 0x6040}, /* Dual channel hi-speed device with PD */ \
{0x0403, 0x6041}, /* Quad channel hi-speed device with PD */ \
{0x0403, 0x6042}, /* Dual channel hi-speed device with PD */ \
{0x0403, 0x6043}, /* Quad channel hi-speed device with PD */ \
{0x0403, 0x6044}, /* Dual channel hi-speed device with PD */ \
{0x0403, 0x6045}, /* Dual channel hi-speed device with PD */ \
{0x0403, 0x6048}, /* Quad channel automotive grade hi-speed device */ \
{0x0403, 0x8372}, /* Product Id SIO application of 8U100AX */ \
{0x0403, 0xFBFA}, /* Product ID for FT232RL */ \
{0x0403, 0xCD18}, /* ??? */
#endif
// CP210X is not part of CDC class, only to re-use CDC driver API
@@ -615,7 +628,9 @@
// List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID
#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST
#define CFG_TUH_CDC_CP210X_VID_PID_LIST \
{0x10C4, 0xEA60}, {0x10C4, 0xEA70}
{ 0x10C4, 0xEA60 }, /* Silicon Labs factory default */ \
{ 0x10C4, 0xEA61 }, /* Silicon Labs factory default */ \
{ 0x10C4, 0xEA70 } /* Silicon Labs Dual Port factory default */
#endif
#ifndef CFG_TUH_CDC_CH34X
@@ -635,6 +650,24 @@
{ 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */
#endif
#ifndef CFG_TUH_CDC_PL2303
// PL2303 is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_PL2303 0
#endif
#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST
// List of product IDs that can use the PL2303 CDC driver
#define CFG_TUH_CDC_PL2303_VID_PID_LIST \
{ 0x067b, 0x2303 }, /* initial 2303 */ \
{ 0x067b, 0x2304 }, /* TB */ \
{ 0x067b, 0x23a3 }, /* GC */ \
{ 0x067b, 0x23b3 }, /* GB */ \
{ 0x067b, 0x23c3 }, /* GT */ \
{ 0x067b, 0x23d3 }, /* GL */ \
{ 0x067b, 0x23e3 }, /* GE */ \
{ 0x067b, 0x23f3 } /* GS */
#endif
#ifndef CFG_TUH_HID
#define CFG_TUH_HID 0
#endif