Merge branch 'master' of github.com:HiFiPhile/tinyusb into vendor_fifo

This commit is contained in:
HiFiPhile
2024-04-08 21:44:14 +02:00
108 changed files with 6575 additions and 493 deletions

View File

@@ -924,6 +924,31 @@ typedef struct TU_ATTR_PACKED {
} subrange[numSubRanges]; \
}
// 6.1 Interrupt Data Message Format
typedef struct TU_ATTR_PACKED
{
uint8_t bInfo;
uint8_t bAttribute;
union
{
uint16_t wValue;
struct
{
uint8_t wValue_cn_or_mcn;
uint8_t wValue_cs;
};
};
union
{
uint16_t wIndex;
struct
{
uint8_t wIndex_ep_or_int;
uint8_t wIndex_entity_id;
};
};
} audio_interrupt_data_t;
/** @} */
#ifdef __cplusplus

View File

@@ -96,13 +96,6 @@
#define USE_LINEAR_BUFFER 1
#endif
// Temporarily put the check here
#if defined(TUP_USBIP_FSDEV) || defined(TUP_USBIP_DWC2)
#define USE_ISO_EP_ALLOCATION 1
#else
#define USE_ISO_EP_ALLOCATION 0
#endif
// Declaration of buffers
// Check for maximum supported numbers
@@ -301,10 +294,12 @@ typedef struct
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint8_t ep_int_ctr; // Audio control interrupt EP.
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
uint8_t ep_int; // Audio control interrupt EP.
#endif
bool mounted; // Device opened
/*------------- From this point, data is not cleared by bus reset -------------*/
uint16_t desc_length; // Length of audio function descriptor
@@ -358,8 +353,8 @@ typedef struct
#endif
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -486,23 +481,7 @@ bool tud_audio_n_mounted(uint8_t func_id)
TU_VERIFY(func_id < CFG_TUD_AUDIO);
audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (audio->ep_out == 0) return false;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (audio->ep_in == 0) return false;
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
if (audio->ep_int_ctr == 0) return false;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (audio->ep_fb == 0) return false;
#endif
return true;
return audio->mounted;
}
//--------------------------------------------------------------------+
@@ -825,24 +804,30 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user
uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len)
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user
bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
TU_VERIFY(_audiod_fct[func_id].ep_int != 0);
// We write directly into the EP's buffer - abort if previous transfer not complete
TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr));
TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int));
TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_ctr_buf, CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE, buffer, len)==0);
// Schedule transmit
TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len));
// Check length
if (tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf), data, sizeof(audio_interrupt_data_t)) == 0)
{
// Schedule transmit
TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf)), 0);
} else
{
// Release endpoint since we don't make any transfer
usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int);
}
return true;
}
#endif
// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
@@ -1404,6 +1389,10 @@ void audiod_init(void)
}
}
bool audiod_deinit(void) {
return false; // TODO not implemented yet
}
void audiod_reset(uint8_t rhport)
{
(void) rhport;
@@ -1447,10 +1436,11 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
// Verify version is correct - this check can be omitted
TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
// Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted
if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed
// Verify interrupt control EP is enabled if demanded by descriptor
TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed
if (itf_desc->bNumEndpoints == 1)
{
TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0);
TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP);
}
// Alternate setting MUST be zero - this check can be omitted
@@ -1483,7 +1473,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
#endif
}
#if USE_ISO_EP_ALLOCATION
#ifdef TUP_DCD_EDPT_ISO_ALLOC
{
#if CFG_TUD_AUDIO_ENABLE_EP_IN
uint8_t ep_in = 0;
@@ -1559,7 +1549,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
}
#endif
}
#endif // USE_ISO_EP_ALLOCATION
#endif // TUP_DCD_EDPT_ISO_ALLOC
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
{
@@ -1594,6 +1584,32 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
}
#endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
{
uint8_t const *p_desc = _audiod_fct[i].p_desc;
uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
while (p_desc_end - p_desc > 0)
{
// For each endpoint
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
uint8_t const ep_addr = desc_ep->bEndpointAddress;
// If endpoint is input-direction and interrupt-type
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT)
{
// Store endpoint number and open endpoint
_audiod_fct[i].ep_int = ep_addr;
TU_ASSERT(usbd_edpt_open(_audiod_fct[i].rhport, desc_ep));
}
}
p_desc = tu_desc_next(p_desc);
}
}
#endif
_audiod_fct[i].mounted = true;
break;
}
}
@@ -1655,7 +1671,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (audio->ep_in_as_intf_num == itf)
{
audio->ep_in_as_intf_num = 0;
#if !USE_ISO_EP_ALLOCATION
#ifndef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_close(rhport, audio->ep_in);
#endif
@@ -1686,7 +1702,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (audio->ep_out_as_intf_num == itf)
{
audio->ep_out_as_intf_num = 0;
#if !USE_ISO_EP_ALLOCATION
#ifndef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_close(rhport, audio->ep_out);
#endif
@@ -1707,7 +1723,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Close corresponding feedback EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#if !USE_ISO_EP_ALLOCATION
#ifndef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_close(rhport, audio->ep_fb);
#endif
audio->ep_fb = 0;
@@ -1739,7 +1755,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
#if USE_ISO_EP_ALLOCATION
#ifdef TUP_DCD_EDPT_ISO_ALLOC
TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep));
#else
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
@@ -2120,10 +2136,10 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
{
audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
// Data transmission of control interrupt finished
if (audio->ep_int_ctr == ep_addr)
if (audio->ep_int == ep_addr)
{
// According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
// In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
@@ -2132,7 +2148,8 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// I assume here, that things above are handled by PHY
// All transmission is done - what remains to do is to inform job was completed
if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes));
if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport);
return true;
}
#endif

View File

@@ -196,13 +196,9 @@
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1
#endif
// Audio interrupt control EP size - disabled if 0
#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74)
#endif
#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE
#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74)
// Enable/disable interrupt EP (required for notifying host of control changes)
#ifndef CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1
#endif
// Use software encoding/decoding
@@ -393,8 +389,8 @@ uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_i
tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx);
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len);
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data);
#endif
@@ -437,8 +433,8 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx);
// INT CTR API
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len);
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
static inline bool tud_audio_int_write (const audio_interrupt_data_t * data);
#endif
// Buffer control EP data and schedule a transmit
@@ -537,8 +533,8 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied);
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport);
#endif
// Invoked when audio set interface request received
@@ -669,10 +665,10 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx)
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len)
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
static inline bool tud_audio_int_write(const audio_interrupt_data_t * data)
{
return tud_audio_int_ctr_n_write(0, buffer, len);
return tud_audio_int_n_write(0, data);
}
#endif
@@ -689,6 +685,7 @@ static inline bool tud_audio_fb_set(uint32_t feedback)
// Internal Class Driver API
//--------------------------------------------------------------------+
void audiod_init (void);
bool audiod_deinit (void);
void audiod_reset (uint8_t rhport);
uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -91,11 +91,14 @@ bool tud_bt_acl_data_send(void *event, uint16_t event_len)
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void btd_init(void)
{
void btd_init(void) {
tu_memclr(&_btd_itf, sizeof(_btd_itf));
}
bool btd_deinit(void) {
return true;
}
void btd_reset(uint8_t rhport)
{
(void)rhport;

View File

@@ -104,6 +104,7 @@ bool tud_bt_acl_data_send(void *acl_data, uint16_t data_len);
// Internal Class Driver API
//--------------------------------------------------------------------+
void btd_init (void);
bool btd_deinit (void);
void btd_reset (uint8_t rhport);
uint16_t btd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool btd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const *request);

View File

@@ -253,11 +253,39 @@ void cdcd_init(void)
// In this way, the most current data is prioritized.
tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true);
tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex));
tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL);
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_rd = osal_mutex_create(&p_cdc->rx_ff_mutex);
osal_mutex_t mutex_wr = osal_mutex_create(&p_cdc->tx_ff_mutex);
TU_ASSERT(mutex_rd != NULL && mutex_wr != NULL, );
tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, mutex_rd);
tu_fifo_config_mutex(&p_cdc->tx_ff, mutex_wr, NULL);
#endif
}
}
bool cdcd_deinit(void) {
#if OSAL_MUTEX_REQUIRED
for(uint8_t i=0; i<CFG_TUD_CDC; i++) {
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
osal_mutex_t mutex_rd = p_cdc->rx_ff.mutex_rd;
osal_mutex_t mutex_wr = p_cdc->tx_ff.mutex_wr;
if (mutex_rd) {
osal_mutex_delete(mutex_rd);
tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, NULL);
}
if (mutex_wr) {
osal_mutex_delete(mutex_wr);
tu_fifo_config_mutex(&p_cdc->tx_ff, NULL, NULL);
}
}
#endif
return true;
}
void cdcd_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -247,6 +247,7 @@ static inline bool tud_cdc_write_clear(void)
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
void cdcd_init (void);
bool cdcd_deinit (void);
void cdcd_reset (uint8_t rhport);
uint16_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool cdcd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -160,11 +160,14 @@ void dfu_moded_reset(uint8_t rhport)
reset_state();
}
void dfu_moded_init(void)
{
void dfu_moded_init(void) {
dfu_moded_reset(0);
}
bool dfu_moded_deinit(void) {
return true;
}
uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
(void) rhport;

View File

@@ -86,6 +86,7 @@ TU_ATTR_WEAK void tud_dfu_abort_cb(uint8_t alt);
// Internal Class Driver API
//--------------------------------------------------------------------+
void dfu_moded_init(void);
bool dfu_moded_deinit(void);
void dfu_moded_reset(uint8_t rhport);
uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -51,8 +51,11 @@
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void dfu_rtd_init(void)
{
void dfu_rtd_init(void) {
}
bool dfu_rtd_deinit(void) {
return true;
}
void dfu_rtd_reset(uint8_t rhport)

View File

@@ -43,6 +43,7 @@ void tud_dfu_runtime_reboot_to_dfu_cb(void);
// Internal Class Driver API
//--------------------------------------------------------------------+
void dfu_rtd_init(void);
bool dfu_rtd_deinit(void);
void dfu_rtd_reset(uint8_t rhport);
uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -300,6 +300,19 @@ typedef struct TU_ATTR_PACKED
int8_t pan; // using AC Pan
} hid_mouse_report_t;
// Absolute Mouse: same as the Standard (relative) Mouse Report but
// with int16_t instead of int8_t for X and Y coordinates.
typedef struct TU_ATTR_PACKED
{
uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
int16_t x; /**< Current x position of the mouse. */
int16_t y; /**< Current y position of the mouse. */
int8_t wheel; /**< Current delta wheel movement on the mouse. */
int8_t pan; // using AC Pan
} hid_abs_mouse_report_t;
/// Standard Mouse Buttons Bitmap
typedef enum
{

View File

@@ -146,6 +146,19 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
hid_abs_mouse_report_t report =
{
.buttons = buttons,
.x = x,
.y = y,
.wheel = vertical,
.pan = horizontal
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) {
hid_gamepad_report_t report =
@@ -166,11 +179,14 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
//--------------------------------------------------------------------+
// USBD-CLASS API
//--------------------------------------------------------------------+
void hidd_init(void)
{
void hidd_init(void) {
hidd_reset(0);
}
bool hidd_deinit(void) {
return true;
}
void hidd_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -72,6 +72,16 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi
// use template layout report as defined by hid_mouse_report_t
bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
// ABSOLUTE MOUSE: convenient helper to send absolute mouse report if application
// use template layout report as defined by hid_abs_mouse_report_t
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_abs_mouse_report(uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
return tud_hid_n_abs_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
}
// Gamepad: convenient helper to send gamepad report if application
// use template layout report TUD_HID_REPORT_DESC_GAMEPAD
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
@@ -266,6 +276,55 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_COLLECTION_END , \
HID_COLLECTION_END \
// Absolute Mouse Report Descriptor Template
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
/* Report ID if any */\
__VA_ARGS__ \
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
HID_USAGE_MIN ( 1 ) ,\
HID_USAGE_MAX ( 5 ) ,\
HID_LOGICAL_MIN ( 0 ) ,\
HID_LOGICAL_MAX ( 1 ) ,\
/* Left, Right, Middle, Backward, Forward buttons */ \
HID_REPORT_COUNT( 5 ) ,\
HID_REPORT_SIZE ( 1 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
/* 3 bit padding */ \
HID_REPORT_COUNT( 1 ) ,\
HID_REPORT_SIZE ( 3 ) ,\
HID_INPUT ( HID_CONSTANT ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
/* X, Y absolute position [0, 32767] */ \
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
HID_LOGICAL_MIN ( 0x00 ) ,\
HID_LOGICAL_MAX_N( 0x7FFF, 2 ) ,\
HID_REPORT_SIZE ( 16 ) ,\
HID_REPORT_COUNT ( 2 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
/* Vertical wheel scroll [-127, 127] */ \
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
HID_LOGICAL_MIN ( 0x81 ) ,\
HID_LOGICAL_MAX ( 0x7f ) ,\
HID_REPORT_COUNT( 1 ) ,\
HID_REPORT_SIZE ( 8 ) ,\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
/* Horizontal wheel scroll [-127, 127] */ \
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
HID_LOGICAL_MIN ( 0x81 ), \
HID_LOGICAL_MAX ( 0x7f ), \
HID_REPORT_COUNT( 1 ), \
HID_REPORT_SIZE ( 8 ), \
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
HID_COLLECTION_END , \
HID_COLLECTION_END \
// Consumer Control Report Descriptor Template
#define TUD_HID_REPORT_DESC_CONSUMER(...) \
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\
@@ -406,6 +465,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
// Internal Class Driver API
//--------------------------------------------------------------------+
void hidd_init (void);
bool hidd_deinit (void);
void hidd_reset (uint8_t rhport);
uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -373,12 +373,10 @@ bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void midid_init(void)
{
void midid_init(void) {
tu_memclr(_midid_itf, sizeof(_midid_itf));
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
{
for (uint8_t i = 0; i < CFG_TUD_MIDI; i++) {
midid_interface_t* midi = &_midid_itf[i];
// config fifo
@@ -386,12 +384,38 @@ void midid_init(void)
tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, false); // OBVS.
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&midi->rx_ff, NULL, osal_mutex_create(&midi->rx_ff_mutex));
tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex), NULL);
osal_mutex_t mutex_rd = osal_mutex_create(&midi->rx_ff_mutex);
osal_mutex_t mutex_wr = osal_mutex_create(&midi->tx_ff_mutex);
TU_ASSERT(mutex_wr != NULL && mutex_wr != NULL, );
tu_fifo_config_mutex(&midi->rx_ff, NULL, mutex_rd);
tu_fifo_config_mutex(&midi->tx_ff, mutex_wr, NULL);
#endif
}
}
bool midid_deinit(void) {
#if CFG_FIFO_MUTEX
for(uint8_t i=0; i<CFG_TUD_MIDI; i++) {
midid_interface_t* midi = &_midid_itf[i];
osal_mutex_t mutex_rd = midi->rx_ff.mutex_rd;
osal_mutex_t mutex_wr = midi->tx_ff.mutex_wr;
if (mutex_rd) {
osal_mutex_delete(mutex_rd);
tu_fifo_config_mutex(&midi->rx_ff, NULL, NULL);
}
if (mutex_wr) {
osal_mutex_delete(mutex_wr);
tu_fifo_config_mutex(&midi->tx_ff, NULL, NULL);
}
}
#endif
return true;
}
void midid_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -158,6 +158,7 @@ static inline bool tud_midi_packet_write (uint8_t const packet[4])
// Internal Class Driver API
//--------------------------------------------------------------------+
void midid_init (void);
bool midid_deinit (void);
void midid_reset (uint8_t rhport);
uint16_t midid_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool midid_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -251,11 +251,15 @@ static inline void set_sense_medium_not_present(uint8_t lun)
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void mscd_init(void)
{
void mscd_init(void) {
tu_memclr(&_mscd_itf, sizeof(mscd_interface_t));
}
bool mscd_deinit(void) {
// nothing to do
return true;
}
void mscd_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -150,6 +150,7 @@ TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
// Internal Class Driver API
//--------------------------------------------------------------------+
void mscd_init (void);
bool mscd_deinit (void);
void mscd_reset (uint8_t rhport);
uint16_t mscd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool mscd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * p_request);

View File

@@ -132,11 +132,14 @@ void netd_report(uint8_t *buf, uint16_t len)
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void netd_init(void)
{
void netd_init(void) {
tu_memclr(&_netd_itf, sizeof(_netd_itf));
}
bool netd_deinit(void) {
return true;
}
void netd_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -260,6 +260,10 @@ void netd_init(void)
ncm_prepare_for_tx();
}
bool netd_deinit(void) {
return true;
}
void netd_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -105,6 +105,7 @@ void tud_network_link_state_cb(bool state);
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
void netd_init (void);
bool netd_deinit (void);
void netd_reset (uint8_t rhport);
uint16_t netd_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -260,6 +260,13 @@ void usbtmcd_init_cb(void)
usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
}
bool usbtmcd_deinit(void) {
#if OSAL_MUTEX_REQUIRED
osal_mutex_delete(usbtmcLock);
#endif
return true;
}
uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
(void)rhport;

View File

@@ -98,11 +98,12 @@ bool tud_usbtmc_start_bus_read(void);
/* "callbacks" from USB device core */
void usbtmcd_init_cb(void);
bool usbtmcd_deinit(void);
uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
void usbtmcd_reset_cb(uint8_t rhport);
bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
void usbtmcd_init_cb(void);
/************************************************************
* USBTMC Descriptor Templates

View File

@@ -202,27 +202,63 @@ uint32_t tud_vendor_n_write_available (uint8_t itf)
//--------------------------------------------------------------------+
// USBD Driver API
//--------------------------------------------------------------------+
void vendord_init(void)
{
void vendord_init(void) {
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
{
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 || CFG_TUD_VENDOR_TX_BUFSIZE > 0
vendord_interface_t* p_itf = &_vendord_itf[i];
#endif
// config fifo
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false);
tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex));
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_rd = osal_mutex_create(&p_itf->rx_ff_mutex);
TU_ASSERT(mutex_rd,);
tu_fifo_config_mutex(&p_itf->rx_ff, NULL, mutex_rd);
#endif
#endif
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false);
tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL);
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_wr = osal_mutex_create(&p_itf->tx_ff_mutex);
TU_ASSERT(mutex_wr,);
tu_fifo_config_mutex(&p_itf->tx_ff, mutex_wr, NULL);
#endif
#endif
}
}
bool vendord_deinit(void) {
#if OSAL_MUTEX_REQUIRED
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
osal_mutex_t mutex_rd = p_itf->rx_ff.mutex_rd;
if (mutex_rd) {
osal_mutex_delete(mutex_rd);
tu_fifo_config_mutex(&p_itf->rx_ff, NULL, NULL);
}
}
#endif
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
vendord_interface_t* p_itf = &_vendord_itf[i];
osal_mutex_t mutex_wr = p_itf->tx_ff.mutex_wr;
if (mutex_wr) {
osal_mutex_delete(mutex_wr);
tu_fifo_config_mutex(&p_itf->tx_ff, NULL, NULL);
}
}
#endif
#endif
return true;
}
void vendord_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -161,6 +161,7 @@ static inline uint32_t tud_vendor_write_available (void)
// Internal Class Driver API
//--------------------------------------------------------------------+
void vendord_init(void);
bool vendord_deinit(void);
void vendord_reset(uint8_t rhport);
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);

View File

@@ -755,15 +755,20 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
TU_LOG_DRV(" reopen VS %d\r\n", altnum);
uint8_t const *desc = _videod_itf[stm->index_vc].beg;
#ifndef TUP_DCD_EDPT_ISO_ALLOC
/* Close endpoints of previous settings. */
for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) {
uint_fast16_t ofs_ep = stm->desc.ep[i];
if (!ofs_ep) break;
uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep);
usbd_edpt_close(rhport, ep_adr);
stm->desc.ep[i] = 0;
TU_LOG_DRV(" close EP%02x\r\n", ep_adr);
tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep);
/* Only ISO endpoints needs to be closed */
if(ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
usbd_edpt_close(rhport, ep->bEndpointAddress);
stm->desc.ep[i] = 0;
TU_LOG_DRV(" close EP%02x\r\n", ep->bEndpointAddress);
}
}
#endif
/* clear transfer management information */
stm->buffer = NULL;
@@ -788,16 +793,18 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
TU_ASSERT(cur < end);
tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur;
uint_fast32_t max_size = stm->max_payload_transfer_size;
if (altnum) {
if ((TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer) &&
(tu_edpt_packet_size(ep) < max_size)) {
/* FS must be less than or equal to max packet size */
return false;
}
if (altnum && (TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer)) {
/* FS must be less than or equal to max packet size */
TU_VERIFY (tu_edpt_packet_size(ep) >= max_size);
#ifdef TUP_DCD_EDPT_ISO_ALLOC
usbd_edpt_iso_activate(rhport, ep);
#else
TU_ASSERT(usbd_edpt_open(rhport, ep));
#endif
} else {
TU_VERIFY(TUSB_XFER_BULK == ep->bmAttributes.xfer);
TU_ASSERT(usbd_edpt_open(rhport, ep));
}
TU_ASSERT(usbd_edpt_open(rhport, ep));
stm->desc.ep[i] = (uint16_t) (cur - desc);
TU_LOG_DRV(" open EP%02x\r\n", _desc_ep_addr(cur));
}
@@ -1229,6 +1236,10 @@ void videod_init(void) {
}
}
bool videod_deinit(void) {
return true;
}
void videod_reset(uint8_t rhport) {
(void) rhport;
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
@@ -1283,6 +1294,24 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
cur = _next_desc_itf(cur, end);
stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
stm->state = VS_STATE_PROBING;
#ifdef TUP_DCD_EDPT_ISO_ALLOC
/* Allocate ISO endpoints */
uint16_t ep_size = 0;
uint16_t ep_addr = 0;
uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
while (p_desc < p_desc_end) {
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) {
ep_addr = desc_ep->bEndpointAddress;
ep_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_size);
}
}
p_desc = tu_desc_next(p_desc);
}
if(ep_addr > 0 && ep_size > 0) usbd_edpt_iso_alloc(rhport, ep_addr, ep_size);
#endif
if (0 == stm_idx && 1 == bInCollection) {
/* If there is only one streaming interface and no alternate settings,
* host may not issue set_interface so open the streaming interface here. */

View File

@@ -85,6 +85,7 @@ TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
void videod_init (void);
bool videod_deinit (void);
void videod_reset (uint8_t rhport);
uint16_t videod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -100,6 +100,13 @@
#define TUP_DCD_ENDPOINT_MAX 8
#define TUP_RHPORT_HIGHSPEED 1
#elif TU_CHECK_MCU(OPT_MCU_MCXA15)
// USB0 is chipidea FS
#define TUP_USBIP_CHIPIDEA_FS
#define TUP_USBIP_CHIPIDEA_FS_MCX
#define TUP_DCD_ENDPOINT_MAX 16
#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
#define TUP_USBIP_CHIPIDEA_HS
#define TUP_USBIP_EHCI
@@ -434,4 +441,8 @@
#define TU_ATTR_FAST_FUNC
#endif
#if defined(TUP_USBIP_DWC2) || defined(TUP_USBIP_FSDEV)
#define TUP_DCD_EDPT_ISO_ALLOC
#endif
#endif

View File

@@ -122,6 +122,9 @@ void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_W
// Initialize controller to device mode
void dcd_init(uint8_t rhport);
// Deinitialize controller, unset device mode.
bool dcd_deinit(uint8_t rhport);
// Interrupt Handler
void dcd_int_handler(uint8_t rhport);

View File

@@ -43,8 +43,13 @@
#endif
//--------------------------------------------------------------------+
// Callback weak stubs (called if application does not provide)
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
(void) rhport;
return false;
}
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
(void)rhport;
(void)eventid;
@@ -96,6 +101,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
{
DRIVER_NAME("CDC")
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
.open = cdcd_open,
.control_xfer_cb = cdcd_control_xfer_cb,
@@ -108,6 +114,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
{
DRIVER_NAME("MSC")
.init = mscd_init,
.deinit = NULL,
.reset = mscd_reset,
.open = mscd_open,
.control_xfer_cb = mscd_control_xfer_cb,
@@ -118,121 +125,131 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_HID
{
DRIVER_NAME("HID")
.init = hidd_init,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
DRIVER_NAME("HID")
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
.open = hidd_open,
.control_xfer_cb = hidd_control_xfer_cb,
.xfer_cb = hidd_xfer_cb,
.sof = NULL
},
#endif
#if CFG_TUD_AUDIO
{
DRIVER_NAME("AUDIO")
.init = audiod_init,
.reset = audiod_reset,
.open = audiod_open,
.control_xfer_cb = audiod_control_xfer_cb,
.xfer_cb = audiod_xfer_cb,
.sof = audiod_sof_isr
DRIVER_NAME("AUDIO")
.init = audiod_init,
.deinit = audiod_deinit,
.reset = audiod_reset,
.open = audiod_open,
.control_xfer_cb = audiod_control_xfer_cb,
.xfer_cb = audiod_xfer_cb,
.sof = audiod_sof_isr
},
#endif
#if CFG_TUD_VIDEO
{
DRIVER_NAME("VIDEO")
.init = videod_init,
.reset = videod_reset,
.open = videod_open,
.control_xfer_cb = videod_control_xfer_cb,
.xfer_cb = videod_xfer_cb,
.sof = NULL
DRIVER_NAME("VIDEO")
.init = videod_init,
.deinit = videod_deinit,
.reset = videod_reset,
.open = videod_open,
.control_xfer_cb = videod_control_xfer_cb,
.xfer_cb = videod_xfer_cb,
.sof = NULL
},
#endif
#if CFG_TUD_MIDI
{
DRIVER_NAME("MIDI")
.init = midid_init,
.open = midid_open,
.reset = midid_reset,
.control_xfer_cb = midid_control_xfer_cb,
.xfer_cb = midid_xfer_cb,
.sof = NULL
DRIVER_NAME("MIDI")
.init = midid_init,
.deinit = midid_deinit,
.open = midid_open,
.reset = midid_reset,
.control_xfer_cb = midid_control_xfer_cb,
.xfer_cb = midid_xfer_cb,
.sof = NULL
},
#endif
#if CFG_TUD_VENDOR
{
DRIVER_NAME("VENDOR")
.init = vendord_init,
.reset = vendord_reset,
.open = vendord_open,
.control_xfer_cb = tud_vendor_control_xfer_cb,
.xfer_cb = vendord_xfer_cb,
.sof = NULL
DRIVER_NAME("VENDOR")
.init = vendord_init,
.deinit = vendord_deinit,
.reset = vendord_reset,
.open = vendord_open,
.control_xfer_cb = tud_vendor_control_xfer_cb,
.xfer_cb = vendord_xfer_cb,
.sof = NULL
},
#endif
#if CFG_TUD_USBTMC
{
DRIVER_NAME("TMC")
.init = usbtmcd_init_cb,
.reset = usbtmcd_reset_cb,
.open = usbtmcd_open_cb,
.control_xfer_cb = usbtmcd_control_xfer_cb,
.xfer_cb = usbtmcd_xfer_cb,
.sof = NULL
DRIVER_NAME("TMC")
.init = usbtmcd_init_cb,
.deinit = usbtmcd_deinit,
.reset = usbtmcd_reset_cb,
.open = usbtmcd_open_cb,
.control_xfer_cb = usbtmcd_control_xfer_cb,
.xfer_cb = usbtmcd_xfer_cb,
.sof = NULL
},
#endif
#if CFG_TUD_DFU_RUNTIME
{
DRIVER_NAME("DFU-RUNTIME")
.init = dfu_rtd_init,
.reset = dfu_rtd_reset,
.open = dfu_rtd_open,
.control_xfer_cb = dfu_rtd_control_xfer_cb,
.xfer_cb = NULL,
.sof = NULL
DRIVER_NAME("DFU-RUNTIME")
.init = dfu_rtd_init,
.deinit = dfu_rtd_deinit,
.reset = dfu_rtd_reset,
.open = dfu_rtd_open,
.control_xfer_cb = dfu_rtd_control_xfer_cb,
.xfer_cb = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_DFU
{
DRIVER_NAME("DFU")
.init = dfu_moded_init,
.reset = dfu_moded_reset,
.open = dfu_moded_open,
.control_xfer_cb = dfu_moded_control_xfer_cb,
.xfer_cb = NULL,
.sof = NULL
DRIVER_NAME("DFU")
.init = dfu_moded_init,
.deinit = dfu_moded_deinit,
.reset = dfu_moded_reset,
.open = dfu_moded_open,
.control_xfer_cb = dfu_moded_control_xfer_cb,
.xfer_cb = NULL,
.sof = NULL
},
#endif
#if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
{
DRIVER_NAME("NET")
.init = netd_init,
.reset = netd_reset,
.open = netd_open,
.control_xfer_cb = netd_control_xfer_cb,
.xfer_cb = netd_xfer_cb,
.sof = NULL,
DRIVER_NAME("NET")
.init = netd_init,
.deinit = netd_deinit,
.reset = netd_reset,
.open = netd_open,
.control_xfer_cb = netd_control_xfer_cb,
.xfer_cb = netd_xfer_cb,
.sof = NULL,
},
#endif
#if CFG_TUD_BTH
{
DRIVER_NAME("BTH")
.init = btd_init,
.reset = btd_reset,
.open = btd_open,
.control_xfer_cb = btd_control_xfer_cb,
.xfer_cb = btd_xfer_cb,
.sof = NULL
DRIVER_NAME("BTH")
.init = btd_init,
.deinit = btd_deinit,
.reset = btd_reset,
.open = btd_open,
.control_xfer_cb = btd_control_xfer_cb,
.xfer_cb = btd_xfer_cb,
.sof = NULL
},
#endif
};
@@ -402,7 +419,7 @@ bool tud_init(uint8_t rhport) {
// Init class drivers
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
usbd_class_driver_t const* driver = get_driver(i);
TU_ASSERT(driver);
TU_ASSERT(driver && driver->init);
TU_LOG_USBD("%s init\r\n", driver->name);
driver->init();
}
@@ -416,6 +433,41 @@ bool tud_init(uint8_t rhport) {
return true;
}
bool tud_deinit(uint8_t rhport) {
// skip if not initialized
if (!tud_inited()) return true;
TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport);
// Deinit device controller driver
dcd_int_disable(rhport);
dcd_disconnect(rhport);
dcd_deinit(rhport);
// Deinit class drivers
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
usbd_class_driver_t const* driver = get_driver(i);
if(driver && driver->deinit) {
TU_LOG_USBD("%s deinit\r\n", driver->name);
driver->deinit();
}
}
// Deinit device queue & task
osal_queue_delete(_usbd_q);
_usbd_q = NULL;
#if OSAL_MUTEX_REQUIRED
// TODO make sure there is no task waiting on this mutex
osal_mutex_delete(_usbd_mutex);
_usbd_mutex = NULL;
#endif
_usbd_rhport = RHPORT_INVALID;
return true;
}
static void configuration_reset(uint8_t rhport) {
for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
usbd_class_driver_t const* driver = get_driver(i);
@@ -1181,6 +1233,11 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t t
// TU_VERIFY(tud_ready());
TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
#if CFG_TUD_LOG_LEVEL >= 3
if(dir == TUSB_DIR_IN) {
TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2);
}
#endif
// Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);

View File

@@ -37,9 +37,12 @@ extern "C" {
// Application API
//--------------------------------------------------------------------+
// Init device stack
// Init device stack on roothub port
bool tud_init (uint8_t rhport);
// Deinit device stack on roothub port
bool tud_deinit(uint8_t rhport);
// Check if device stack is already initialized
bool tud_inited(void);
@@ -393,6 +396,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// For more channels, add definitions here
/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */
#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7
#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \
TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval
/* Standard AS Interface Descriptor(4.9.1) */
#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
@@ -468,7 +476,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -517,7 +525,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
@@ -565,7 +573,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\

View File

@@ -45,6 +45,7 @@ typedef struct {
#endif
void (* init ) (void);
bool (* deinit ) (void);
void (* reset ) (uint8_t rhport);
uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len);
bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);

View File

@@ -125,7 +125,7 @@ bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_W
//--------------------------------------------------------------------+
// optional hcd configuration, called by tuh_configure()
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_ATTR_WEAK;
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// Initialize controller to host mode
bool hcd_init(uint8_t rhport);

View File

@@ -52,6 +52,13 @@ TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) {
return false;
}
TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
(void) rhport;
(void) cfg_id;
(void) cfg_param;
return false;
}
TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
(void) rhport;
(void) eventid;
@@ -332,11 +339,7 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
//--------------------------------------------------------------------+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
if ( hcd_configure ) {
return hcd_configure(rhport, cfg_id, cfg_param);
} else {
return false;
}
return hcd_configure(rhport, cfg_id, cfg_param);
}
static void clear_device(usbh_device_t* dev) {
@@ -422,7 +425,7 @@ bool tuh_deinit(uint8_t rhport) {
// Class drivers
for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
usbh_class_driver_t const* driver = get_driver(drv_id);
if (driver) {
if (driver && driver->deinit) {
TU_LOG_USBH("%s deinit\r\n", driver->name);
driver->deinit();
}

View File

@@ -73,11 +73,25 @@ typedef struct {
tusb_desc_interface_t desc;
} tuh_itf_info_t;
// ConfigID for tuh_config()
// ConfigID for tuh_configure()
enum {
TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 << 8 // cfg_param: pio_usb_configuration_t
TUH_CFGID_INVALID = 0,
TUH_CFGID_RPI_PIO_USB_CONFIGURATION = 100, // cfg_param: pio_usb_configuration_t
TUH_CFGID_MAX3421 = 200,
};
typedef struct {
uint8_t max_nak; // max NAK per endpoint per frame
uint8_t cpuctl; // R16: CPU Control Register
uint8_t pinctl; // R17: Pin Control Register. FDUPSPI bit is ignored
} tuh_configure_max3421_t;
typedef union {
// For TUH_CFGID_RPI_PIO_USB_CONFIGURATION use pio_usb_configuration_t
tuh_configure_max3421_t max3421;
} tuh_configure_param_t;
//--------------------------------------------------------------------+
// APPLICATION CALLBACK
//--------------------------------------------------------------------+

View File

@@ -30,6 +30,7 @@
#include <stdatomic.h>
#include "host/hcd.h"
#include "host/usbh.h"
//--------------------------------------------------------------------+
//
@@ -166,6 +167,17 @@ enum {
DEFAULT_HIEN = HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ | HIRQ_RCVDAV_IRQ
};
enum {
MAX_NAK_DEFAULT = 1 // Number of NAK per endpoint per usb frame
};
enum {
EP_STATE_IDLE = 0,
EP_STATE_COMPLETE = 1,
EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt
EP_STATE_ATTEMPT_MAX = 15
};
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
@@ -173,18 +185,21 @@ enum {
typedef struct {
uint8_t daddr;
struct TU_ATTR_PACKED {
uint8_t ep_dir : 1;
uint8_t is_iso : 1;
uint8_t is_setup : 1;
uint8_t data_toggle : 1;
uint8_t xfer_pending : 1;
uint8_t xfer_complete : 1;
union { ;
struct TU_ATTR_PACKED {
uint8_t ep_num : 4;
uint8_t is_setup : 1;
uint8_t is_out : 1;
uint8_t is_iso : 1;
}hxfr_bm;
uint8_t hxfr;
};
struct TU_ATTR_PACKED {
uint8_t ep_num : 4;
uint16_t packet_size : 12;
uint8_t state : 4;
uint8_t data_toggle : 1;
uint16_t packet_size : 11;
};
uint16_t total_len;
@@ -195,6 +210,8 @@ typedef struct {
TU_VERIFY_STATIC(sizeof(max3421_ep_t) == 12, "size is not correct");
typedef struct {
volatile uint16_t frame_count;
// cached register
uint8_t sndbc;
uint8_t hirq;
@@ -204,18 +221,24 @@ typedef struct {
uint8_t hxfr;
atomic_flag busy; // busy transferring
volatile uint16_t frame_count;
max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
OSAL_MUTEX_DEF(spi_mutexdef);
#if OSAL_MUTEX_REQUIRED
OSAL_MUTEX_DEF(spi_mutexdef);
osal_mutex_t spi_mutex;
#endif
max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
} max3421_data_t;
static max3421_data_t _hcd_data;
// max NAK before giving up in a frame. 0 means infinite NAKs
static tuh_configure_max3421_t _tuh_cfg = {
.max_nak = MAX_NAK_DEFAULT,
.cpuctl = 0, // default: INT pulse width = 10.6 us
.pinctl = 0, // default: negative edge interrupt
};
//--------------------------------------------------------------------+
// API: SPI transfer with MAX3421E
// - spi_cs_api(), spi_xfer_api(), int_api(): must be implemented by application
@@ -304,7 +327,6 @@ static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint
tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len);
max3421_spi_unlock(rhport, in_isr);
}
static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_isr) {
@@ -359,10 +381,11 @@ TU_ATTR_ALWAYS_INLINE static inline void sndbc_write(uint8_t rhport, uint8_t dat
//--------------------------------------------------------------------+
static max3421_ep_t* find_ep_not_addr0(uint8_t daddr, uint8_t ep_num, uint8_t ep_dir) {
uint8_t const is_out = 1-ep_dir;
for(size_t i=1; i<CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
// for control endpoint, skip direction check
if (daddr == ep->daddr && ep_num == ep->ep_num && (ep_dir == ep->ep_dir || ep_num == 0)) {
// control endpoint is bi-direction (skip check)
if (daddr == ep->daddr && ep_num == ep->hxfr_bm.ep_num && (ep_num == 0 || is_out == ep->hxfr_bm.is_out)) {
return ep;
}
}
@@ -393,14 +416,23 @@ static void free_ep(uint8_t daddr) {
}
}
// Check if endpoint has an queued transfer and not reach max NAK
TU_ATTR_ALWAYS_INLINE static inline bool is_ep_pending(max3421_ep_t const * ep) {
uint8_t const state = ep->state;
return ep->packet_size && (state >= EP_STATE_ATTEMPT_1) &&
(_tuh_cfg.max_nak == 0 || state < EP_STATE_ATTEMPT_1 + _tuh_cfg.max_nak);
}
// Find the next pending endpoint using round-robin scheduling, starting from next endpoint.
// return NULL if not found
// TODO respect interrupt endpoint's interval
static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
size_t const idx = (size_t) (cur_ep - _hcd_data.ep);
// starting from next endpoint
for (size_t i = idx + 1; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
if (ep->xfer_pending && ep->packet_size) {
// TU_LOG3("next pending i = %u\r\n", i);
if (is_ep_pending(ep)) {
return ep;
}
}
@@ -408,8 +440,7 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// wrap around including current endpoint
for (size_t i = 0; i <= idx; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
if (ep->xfer_pending && ep->packet_size) {
// TU_LOG3("next pending i = %u\r\n", i);
if (is_ep_pending(ep)) {
return ep;
}
}
@@ -424,10 +455,11 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) {
// optional hcd configuration, called by tuh_configure()
bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
(void) rhport;
(void) cfg_id;
(void) cfg_param;
TU_VERIFY(cfg_id == TUH_CFGID_MAX3421 && cfg_param != NULL);
return false;
tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
_tuh_cfg = cfg->max3421;
return true;
}
// Initialize controller to host mode
@@ -438,6 +470,7 @@ bool hcd_init(uint8_t rhport) {
TU_LOG2_INT(sizeof(max3421_ep_t));
TU_LOG2_INT(sizeof(max3421_data_t));
TU_LOG2_INT(offsetof(max3421_data_t, ep));
tu_memclr(&_hcd_data, sizeof(_hcd_data));
_hcd_data.peraddr = 0xff; // invalid
@@ -447,7 +480,7 @@ bool hcd_init(uint8_t rhport) {
#endif
// full duplex, interrupt negative edge
reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false);
reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
// v1 is 0x01, v2 is 0x12, v3 is 0x13
uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
@@ -476,7 +509,7 @@ bool hcd_init(uint8_t rhport) {
tuh_max3421_int_api(rhport, true);
// Enable Interrupt pin
reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false);
reg_write(rhport, CPUCTL_ADDR, _tuh_cfg.cpuctl | CPUCTL_IE, false);
return true;
}
@@ -487,9 +520,9 @@ bool hcd_deinit(uint8_t rhport) {
// disable interrupt
tuh_max3421_int_api(rhport, false);
// reset max3421
// reset max3421 and power down
reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
reg_write(rhport, USBCTL_ADDR, 0, false);
reg_write(rhport, USBCTL_ADDR, USBCTL_PWRDOWN, false);
#if OSAL_MUTEX_REQUIRED
osal_mutex_delete(_hcd_data.spi_mutex);
@@ -557,7 +590,6 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// Open an endpoint
bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * ep_desc) {
(void) rhport;
(void) daddr;
uint8_t const ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
@@ -569,12 +601,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
ep = allocate_ep();
TU_ASSERT(ep);
ep->daddr = daddr;
ep->ep_num = (uint8_t) (ep_num & 0x0f);
ep->ep_dir = (ep_dir == TUSB_DIR_IN) ? 1 : 0;
}
if ( TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer ) {
ep->is_iso = 1;
ep->hxfr_bm.ep_num = (uint8_t) (ep_num & 0x0f);
ep->hxfr_bm.is_out = (ep_dir == TUSB_DIR_OUT) ? 1 : 0;
ep->hxfr_bm.is_iso = (TUSB_XFER_ISOCHRONOUS == ep_desc->bmAttributes.xfer) ? 1 : 0;
}
ep->packet_size = (uint16_t) (tu_edpt_packet_size(ep_desc) & 0x7ff);
@@ -582,7 +611,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
return true;
}
void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
static void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 12: Programming BULK-OUT Transfers
// TODO double buffered
if (switch_ep) {
@@ -598,12 +627,10 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
fifo_write(rhport, SNDFIFO_ADDR, ep->buf, xact_len, in_isr);
}
sndbc_write(rhport, xact_len, in_isr);
uint8_t const hxfr = (uint8_t ) (ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0));
hxfr_write(rhport, hxfr, in_isr);
hxfr_write(rhport, ep->hxfr, in_isr);
}
void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
static void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
// Page 13: Programming BULK-IN Transfers
if (switch_ep) {
peraddr_write(rhport, ep->daddr, in_isr);
@@ -612,34 +639,36 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
}
uint8_t const hxfr = (uint8_t) (ep->ep_num | (ep->is_iso ? HXFR_ISO : 0));
hxfr_write(rhport, hxfr, in_isr);
hxfr_write(rhport, ep->hxfr, in_isr);
}
TU_ATTR_ALWAYS_INLINE static inline
void xact_inout(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
if (ep->ep_num == 0 ) {
static void xact_setup(uint8_t rhport, max3421_ep_t *ep, bool in_isr) {
peraddr_write(rhport, ep->daddr, in_isr);
fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
hxfr_write(rhport, HXFR_SETUP, in_isr);
}
static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
if (ep->hxfr_bm.ep_num == 0 ) {
// setup
if (ep->is_setup) {
peraddr_write(rhport, ep->daddr, in_isr);
fifo_write(rhport, SUDFIFO_ADDR, ep->buf, 8, in_isr);
hxfr_write(rhport, HXFR_SETUP, in_isr);
if (ep->hxfr_bm.is_setup) {
xact_setup(rhport, ep, in_isr);
return;
}
// status
if (ep->buf == NULL || ep->total_len == 0) {
uint8_t const hxfr = HXFR_HS | (ep->ep_dir ? 0 : HXFR_OUT_NIN);
uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN));
peraddr_write(rhport, ep->daddr, in_isr);
hxfr_write(rhport, hxfr, in_isr);
return;
}
}
if (ep->ep_dir) {
xact_in(rhport, ep, switch_ep, in_isr);
}else {
if (ep->hxfr_bm.is_out) {
xact_out(rhport, ep, switch_ep, in_isr);
}else {
xact_in(rhport, ep, switch_ep, in_isr);
}
}
@@ -651,25 +680,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
TU_VERIFY(ep);
// control transfer can switch direction
ep->ep_dir = ep_dir ? 1u : 0u;
if (ep_num == 0) {
// control transfer can switch direction
ep->hxfr_bm.is_out = ep_dir ? 0 : 1;
ep->hxfr_bm.is_setup = 0;
ep->data_toggle = 1;
}
ep->buf = buffer;
ep->total_len = buflen;
ep->xferred_len = 0;
ep->xfer_complete = 0;
ep->xfer_pending = 1;
if ( ep_num == 0 ) {
ep->is_setup = 0;
ep->data_toggle = 1;
}
ep->state = EP_STATE_ATTEMPT_1;
// carry out transfer if not busy
if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
xact_inout(rhport, ep, true, false);
} else {
return true;
if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_generic(rhport, ep, true, false);
}
return true;
@@ -692,17 +717,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]
max3421_ep_t* ep = find_opened_ep(daddr, 0, 0);
TU_ASSERT(ep);
ep->ep_dir = 0;
ep->is_setup = 1;
ep->hxfr_bm.is_out = 1;
ep->hxfr_bm.is_setup = 1;
ep->buf = (uint8_t*)(uintptr_t) setup_packet;
ep->total_len = 8;
ep->xferred_len = 0;
ep->xfer_complete = 0;
ep->xfer_pending = 1;
ep->state = EP_STATE_ATTEMPT_1;
// carry out transfer if not busy
if ( !atomic_flag_test_and_set(&_hcd_data.busy) ) {
xact_inout(rhport, ep, true, false);
if (!atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_setup(rhport, ep, false);
}
return true;
@@ -767,22 +791,23 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
}
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
uint8_t const ep_dir = 1-ep->hxfr_bm.is_out;
uint8_t const ep_addr = tu_edpt_addr(ep->hxfr_bm.ep_num, ep_dir);
// save data toggle
if (ep->ep_dir) {
if (ep_dir) {
ep->data_toggle = (hrsl & HRSL_RCVTOGRD) ? 1u : 0u;
}else {
ep->data_toggle = (hrsl & HRSL_SNDTOGRD) ? 1u : 0u;
}
ep->xfer_pending = 0;
ep->state = EP_STATE_IDLE;
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
// Find next pending endpoint
max3421_ep_t *next_ep = find_next_pending_ep(ep);
max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (next_ep) {
xact_inout(rhport, next_ep, true, in_isr);
xact_generic(rhport, next_ep, true, in_isr);
}else {
// no more pending
atomic_flag_clear(&_hcd_data.busy);
@@ -812,20 +837,23 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
case HRSL_NAK:
if (ep_num == 0) {
// NAK on control, retry immediately
// control endpoint -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
}else {
// NAK on non-control, find next pending to switch
max3421_ep_t *next_ep = find_next_pending_ep(ep);
} else {
if (ep->state < EP_STATE_ATTEMPT_MAX) {
ep->state++;
}
max3421_ep_t * next_ep = find_next_pending_ep(ep);
if (ep == next_ep) {
// this endpoint is only one pending, retry immediately
// this endpoint is only one pending -> retry immediately
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
}else if (next_ep) {
// switch to next pending TODO could have issue with double buffered if not clear previously out data
xact_inout(rhport, next_ep, true, in_isr);
}else {
TU_ASSERT(false,);
} else if (next_ep) {
// switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
xact_generic(rhport, next_ep, true, in_isr);
} else {
// no more pending in this frame -> clear busy
atomic_flag_clear(&_hcd_data.busy);
}
}
return;
@@ -847,12 +875,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
if (ep_dir) {
// IN transfer: fifo data is already received in RCVDAV IRQ
if ( hxfr_type & HXFR_HS ) {
ep->xfer_complete = 1;
// mark control handshake as complete
if (hxfr_type & HXFR_HS) {
ep->state = EP_STATE_COMPLETE;
}
// short packet or all bytes transferred
if ( ep->xfer_complete ) {
if (ep->state == EP_STATE_COMPLETE) {
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
}else {
// more to transfer
@@ -886,13 +916,13 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
void print_hirq(uint8_t hirq) {
TU_LOG3_HEX(hirq);
if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
if (hirq & HIRQ_HXFRDN_IRQ) TU_LOG3(" HXFRDN");
if (hirq & HIRQ_FRAME_IRQ) TU_LOG3(" FRAME");
if (hirq & HIRQ_CONDET_IRQ) TU_LOG3(" CONDET");
if (hirq & HIRQ_SUSDN_IRQ) TU_LOG3(" SUSDN");
if (hirq & HIRQ_SNDBAV_IRQ) TU_LOG3(" SNDBAV");
if (hirq & HIRQ_RCVDAV_IRQ) TU_LOG3(" RCVDAV");
if (hirq & HIRQ_RWU_IRQ) TU_LOG3(" RWU");
if (hirq & HIRQ_BUSEVENT_IRQ) TU_LOG3(" BUSEVENT");
TU_LOG3("\r\n");
@@ -909,6 +939,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
max3421_ep_t* ep_retry = NULL;
// reset all endpoints attempt counter
for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
ep->state = EP_STATE_ATTEMPT_1;
if (ep_retry == NULL) {
ep_retry = ep;
}
}
}
// start usb transfer if not busy
if (ep_retry != NULL && !atomic_flag_test_and_set(&_hcd_data.busy)) {
xact_generic(rhport, ep_retry, true, in_isr);
}
}
if (hirq & HIRQ_CONDET_IRQ) {
@@ -917,17 +966,17 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
// not call this handler again. So we need to loop until all IRQ are cleared
while ( hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ) ) {
if ( hirq & HIRQ_RCVDAV_IRQ ) {
while (hirq & (HIRQ_RCVDAV_IRQ | HIRQ_HXFRDN_IRQ)) {
if (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
max3421_ep_t* ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
uint8_t xact_len = 0;
// RCVDAV_IRQ can trigger 2 times (dual buffered)
while ( hirq & HIRQ_RCVDAV_IRQ ) {
while (hirq & HIRQ_RCVDAV_IRQ) {
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
if ( xact_len ) {
if (xact_len) {
fifo_read(rhport, ep->buf, xact_len, in_isr);
ep->buf += xact_len;
ep->xferred_len += xact_len;
@@ -938,12 +987,12 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
}
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
ep->xfer_complete = 1;
if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
ep->state = EP_STATE_COMPLETE;
}
}
if ( hirq & HIRQ_HXFRDN_IRQ ) {
if (hirq & HIRQ_HXFRDN_IRQ) {
hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
handle_xfer_done(rhport, in_isr);
}

View File

@@ -29,19 +29,28 @@
#include "fsl_device_registers.h"
#define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
#define CI_REG CI_FS_REG(0)
#if CFG_TUSB_MCU == OPT_MCU_MCXN9
#define CI_FS_REG(_port) ((ci_fs_regs_t*) USBFS0_BASE)
#define CIFS_IRQN USB0_FS_IRQn
void dcd_int_enable(uint8_t rhport)
{
#elif CFG_TUSB_MCU == OPT_MCU_MCXA15
#define CI_FS_REG(_port) ((ci_fs_regs_t*) USB0_BASE)
#define CIFS_IRQN USB0_IRQn
#else
#error "MCU is not supported"
#endif
#define CI_REG CI_FS_REG(0)
void dcd_int_enable(uint8_t rhport) {
(void) rhport;
NVIC_EnableIRQ(USB0_FS_IRQn);
NVIC_EnableIRQ(CIFS_IRQN);
}
void dcd_int_disable(uint8_t rhport)
{
void dcd_int_disable(uint8_t rhport) {
(void) rhport;
NVIC_DisableIRQ(USB0_FS_IRQn);
NVIC_DisableIRQ(CIFS_IRQN);
}
#endif

View File

@@ -295,7 +295,7 @@ void dcd_init(uint8_t rhport)
CI_REG->INT_EN = USB_INTEN_USBRSTEN_MASK;
dcd_connect(rhport);
// NVIC_ClearPendingIRQ(USB0_IRQn);
// NVIC_ClearPendingIRQ(CIFS_IRQN);
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)

View File

@@ -407,6 +407,19 @@ void dcd_init(uint8_t rhport) {
dcd_connect(rhport);
}
bool dcd_deinit(uint8_t rhport) {
(void) rhport;
reset_non_control_endpoints();
irq_remove_handler(USBCTRL_IRQ, dcd_rp2040_irq);
// reset usb hardware into initial state
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
return true;
}
void dcd_int_enable(__unused uint8_t rhport) {
assert(rhport == 0);
irq_set_enabled(USBCTRL_IRQ, true);

View File

@@ -409,6 +409,16 @@ bool hcd_init(uint8_t rhport)
return true;
}
bool hcd_deinit(uint8_t rhport) {
(void) rhport;
irq_remove_handler(USBCTRL_IRQ, hcd_rp2040_irq);
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
return true;
}
void hcd_port_reset(uint8_t rhport)
{
(void) rhport;

View File

@@ -102,17 +102,25 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_
usbdev = dev;
usbdcd_driver.ep[0] = dev->ep0;
#ifdef EP_ALLOCREQ
// SDK v2
usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]);
if (usbdcd_driver.req[0] != NULL)
{
if (usbdcd_driver.req[0] != NULL) {
usbdcd_driver.req[0]->len = 64;
usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64);
if (!usbdcd_driver.req[0]->buf)
{
if (!usbdcd_driver.req[0]->buf) {
EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]);
usbdcd_driver.req[0] = NULL;
return ENOMEM;
}
}
#else
// SDK v3
usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0], 64);
if (usbdcd_driver.req[0] == NULL) {
return ENOMEM;
}
#endif
usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete;
@@ -295,13 +303,19 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
}
usbdcd_driver.req[epnum] = NULL;
#ifdef EP_ALLOCREQ
// sdk v2
usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]);
if (usbdcd_driver.req[epnum] != NULL)
{
if (usbdcd_driver.req[epnum] != NULL) {
usbdcd_driver.req[epnum]->len = ep_mps;
}
else
{
#else
// sdk v3
usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps);
#endif
if(usbdcd_driver.req[epnum] == NULL) {
return false;
}

View File

@@ -115,6 +115,11 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
#define FSDEV_BUS_32BIT
#if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
#define USB_DRD_BASE USB_DRD_FS_BASE
#endif
#define FSDEV_PMA_SIZE (2048u)
#undef USB_PMAADDR
#define USB_PMAADDR USB_DRD_PMAADDR

View File

@@ -97,7 +97,6 @@ static uint16_t ep0_pending[2]; // Index determines direction as t
// TX FIFO RAM allocation so far in words - RX FIFO size is readily available from dwc2->grxfsiz
static uint16_t _allocated_fifo_words_tx; // TX FIFO size in words (IN EPs)
static bool _out_ep_closed; // Flag to check if RX FIFO size needs an update (reduce its size)
// SOF enabling flag - required for SOF to not get disabled in ISR when SOF was enabled by
static bool _sof_en;
@@ -113,20 +112,6 @@ static inline uint16_t calc_grxfsiz(uint16_t max_ep_size, uint8_t ep_count) {
return 15 + 2 * (max_ep_size / 4) + 2 * ep_count;
}
static void update_grxfsiz(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
// Determine largest EP size for RX FIFO
uint16_t max_epsize = 0;
for (uint8_t epnum = 0; epnum < ep_count; epnum++) {
max_epsize = tu_max16(max_epsize, xfer_status[epnum][TUSB_DIR_OUT].max_size);
}
// Update size of RX FIFO
dwc2->grxfsiz = calc_grxfsiz(max_epsize, ep_count);
}
static bool fifo_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t packet_size) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
@@ -268,7 +253,6 @@ static void bus_reset(uint8_t rhport) {
uint8_t const ep_count = _dwc2_controller[rhport].ep_count;
tu_memclr(xfer_status, sizeof(xfer_status));
_out_ep_closed = false;
_sof_en = false;
@@ -791,26 +775,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t
}
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
edpt_disable(rhport, ep_addr, false);
// Update max_size
xfer_status[epnum][dir].max_size = 0; // max_size = 0 marks a disabled EP - required for changing FIFO allocation
if (dir == TUSB_DIR_IN) {
uint16_t const fifo_size = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXFD_Msk) >> DIEPTXF_INEPTXFD_Pos;
uint16_t const fifo_start = (dwc2->dieptxf[epnum - 1] & DIEPTXF_INEPTXSA_Msk) >> DIEPTXF_INEPTXSA_Pos;
// For now only the last opened endpoint can be closed without fuss.
TU_ASSERT(fifo_start == _dwc2_controller[rhport].ep_fifo_size / 4 - _allocated_fifo_words_tx,);
_allocated_fifo_words_tx -= fifo_size;
} else {
_out_ep_closed = true; // Set flag such that RX FIFO gets reduced in size once RX FIFO is empty
}
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
@@ -1181,14 +1146,6 @@ void dcd_int_handler(uint8_t rhport) {
handle_rxflvl_irq(rhport);
} while (dwc2->gotgint & GINTSTS_RXFLVL);
// Manage RX FIFO size
if (_out_ep_closed) {
update_grxfsiz(rhport);
// Disable flag
_out_ep_closed = false;
}
dwc2->gintmsk |= GINTMSK_RXFLVLM;
}

View File

@@ -34,7 +34,7 @@
#define TUSB_VERSION_MAJOR 0
#define TUSB_VERSION_MINOR 16
#define TUSB_VERSION_REVISION 0
#define TUSB_VERSION_BUILD 1
#define TUSB_VERSION_BUILD 3
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD)
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
@@ -144,7 +144,6 @@
#define OPT_MCU_RX72N 1402 ///< Renesas RX72N
#define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families
// Mind Motion
#define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327
@@ -181,6 +180,7 @@
// NXP LPC MCX
#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series
#define OPT_MCU_MCXA15 2301 ///< NXP MCX A15 Series
// Check if configured MCU is one of listed
// Apply _TU_CHECK_MCU with || as separator to list of input