summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorGordon McNab <[email protected]>2021-12-08 08:36:43 +0000
committerGordon McNab <[email protected]>2021-12-08 08:36:43 +0000
commit9a7db985931ae215e808d40e7bacd52535d45305 (patch)
treea4d75e2c3823766da53a006280c0d805630d996e /src/device
parentedf3f3501656b010ad4a9e1d0a0d62573dd0b3fb (diff)
parentcde824f17f73b5ce4fcec8c176827297854a76c2 (diff)
Merge branch 'master' into port-ft90x
Diffstat (limited to 'src/device')
-rw-r--r--src/device/dcd.h14
-rw-r--r--src/device/dcd_attr.h122
-rw-r--r--src/device/usbd.c274
-rw-r--r--src/device/usbd.h108
-rw-r--r--src/device/usbd_pvt.h3
5 files changed, 358 insertions, 163 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 66767c1fe..c042cc708 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -106,7 +106,14 @@ typedef struct TU_ATTR_ALIGNED(4)
void dcd_init (uint8_t rhport);
// Interrupt Handler
+#if __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
void dcd_int_handler(uint8_t rhport);
+#if __GNUC__
+#pragma GCC diagnostic pop
+#endif
// Enable device interrupt
void dcd_int_enable (uint8_t rhport);
@@ -137,6 +144,11 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
// Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
+// Close all non-control endpoints, cancel all pending transfers if any.
+// Invoked when switching from a non-zero Configuration by SET_CONFIGURE therefore
+// required for multiple configuration support.
+void dcd_edpt_close_all (uint8_t rhport);
+
// Close an endpoint.
// Since it is weak, caller must TU_ASSERT this function's existence before calling it.
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
@@ -148,7 +160,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer
// This API is optional, may be useful for register-based for transferring data.
bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK;
-// Stall endpoint
+// Stall endpoint, any queuing transfer should be removed from endpoint
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
// clear stall, data toggle is also reset to DATA0
diff --git a/src/device/dcd_attr.h b/src/device/dcd_attr.h
index 638a17814..c51940573 100644
--- a/src/device/dcd_attr.h
+++ b/src/device/dcd_attr.h
@@ -36,121 +36,167 @@
// - PORT_HIGHSPEED: mask to indicate which port support highspeed mode, bit0 for port0 and so on.
//------------- NXP -------------//
-#if TU_CHECK_MCU(LPC11UXX) || TU_CHECK_MCU(LPC13XX) || TU_CHECK_MCU(LPC15XX)
+#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
#define DCD_ATTR_ENDPOINT_MAX 5
-#elif TU_CHECK_MCU(LPC175X_6X) || TU_CHECK_MCU(LPC177X_8X) || TU_CHECK_MCU(LPC40XX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
#define DCD_ATTR_ENDPOINT_MAX 16
-#elif TU_CHECK_MCU(LPC18XX) || TU_CHECK_MCU(LPC43XX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
// TODO USB0 has 6, USB1 has 4
+ #define DCD_ATTR_CONTROLLER_CHIPIDEA_HS
#define DCD_ATTR_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(LPC51UXX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC51UXX)
#define DCD_ATTR_ENDPOINT_MAX 5
-#elif TU_CHECK_MCU(LPC54XXX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC54XXX)
// TODO USB0 has 5, USB1 has 6
#define DCD_ATTR_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(LPC55XX)
+#elif TU_CHECK_MCU(OPT_MCU_LPC55XX)
// TODO USB0 has 5, USB1 has 6
#define DCD_ATTR_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(MIMXRT10XX)
+#elif TU_CHECK_MCU(OPT_MCU_MIMXRT10XX)
+ #define DCD_ATTR_CONTROLLER_CHIPIDEA_HS
#define DCD_ATTR_ENDPOINT_MAX 8
-#elif TU_CHECK_MCU(MKL25ZXX) || TU_CHECK_MCU(K32L2BXX)
+#elif TU_CHECK_MCU(OPT_MCU_MKL25ZXX, OPT_MCU_K32L2BXX)
+ #define DCD_ATTR_ENDPOINT_MAX 16
+
+#elif TU_CHECK_MCU(OPT_MCU_MM32F327X)
#define DCD_ATTR_ENDPOINT_MAX 16
//------------- Nordic -------------//
-#elif TU_CHECK_MCU(NRF5X)
+#elif TU_CHECK_MCU(OPT_MCU_NRF5X)
// 8 CBI + 1 ISO
#define DCD_ATTR_ENDPOINT_MAX 9
//------------- Microchip -------------//
-#elif TU_CHECK_MCU(SAMD21) || TU_CHECK_MCU(SAMD51) || TU_CHECK_MCU(SAME5X) || \
- TU_CHECK_MCU(SAMD11) || TU_CHECK_MCU(SAML21) || TU_CHECK_MCU(SAML22)
+#elif TU_CHECK_MCU(OPT_MCU_SAMD21, OPT_MCU_SAMD51, OPT_MCU_SAME5X) || \
+ TU_CHECK_MCU(OPT_MCU_SAMD11, OPT_MCU_SAML21, OPT_MCU_SAML22)
#define DCD_ATTR_ENDPOINT_MAX 8
-#elif TU_CHECK_MCU(SAMG)
+#elif TU_CHECK_MCU(OPT_MCU_SAMG)
#define DCD_ATTR_ENDPOINT_MAX 6
#define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
-#elif TU_CHECK_MCU(SAMX7X)
+#elif TU_CHECK_MCU(OPT_MCU_SAMX7X)
#define DCD_ATTR_ENDPOINT_MAX 10
#define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
//------------- ST -------------//
-#elif TU_CHECK_MCU(STM32F0) || TU_CHECK_MCU(STM32F1) || TU_CHECK_MCU(STM32F3) || \
- TU_CHECK_MCU(STM32L0) || TU_CHECK_MCU(STM32L1) || TU_CHECK_MCU(STM32L4)
- // F1: F102, F103
- // L4: L4x2, L4x3
+#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
+ #if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
+ defined (STM32F107xB) || defined (STM32F107xC)
+ #define DCD_ATTR_ENDPOINT_MAX 4
+ #define DCD_ATTR_DWC2_STM32
+ #else
+ #define DCD_ATTR_ENDPOINT_MAX 8
+ #endif
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F2)
+ // FS has 4 ep, HS has 5 ep
+ #define DCD_ATTR_ENDPOINT_MAX 6
+ #define DCD_ATTR_DWC2_STM32
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
#define DCD_ATTR_ENDPOINT_MAX 8
-#elif TU_CHECK_MCU(STM32F2) || TU_CHECK_MCU(STM32F4) || TU_CHECK_MCU(STM32F3)
- // F1: F105, F107 only has 4
- // L4: L4x5, L4x6 has 6
- // For most mcu, FS has 4, HS has 6
+#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
+ // For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
#define DCD_ATTR_ENDPOINT_MAX 6
+ #define DCD_ATTR_DWC2_STM32
-#elif TU_CHECK_MCU(STM32F7)
+#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
// FS has 6, HS has 9
#define DCD_ATTR_ENDPOINT_MAX 9
+ #define DCD_ATTR_DWC2_STM32
-#elif TU_CHECK_MCU(STM32H7)
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
#define DCD_ATTR_ENDPOINT_MAX 9
+ #define DCD_ATTR_DWC2_STM32
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
+ #if defined (STM32L475xx) || defined (STM32L476xx) || \
+ defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
+ defined (STM32L4A6xx) || defined (STM32L4P5xx) || defined (STM32L4Q5xx) || \
+ defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
+ defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
+ #define DCD_ATTR_ENDPOINT_MAX 6
+ #define DCD_ATTR_DWC2_STM32
+ #else
+ #define DCD_ATTR_ENDPOINT_MAX 8
+ #endif
//------------- Sony -------------//
-#elif TU_CHECK_MCU(CXD56)
+#elif TU_CHECK_MCU(OPT_MCU_CXD56)
#define DCD_ATTR_ENDPOINT_MAX 7
#define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
//------------- TI -------------//
-#elif TU_CHECK_MCU(MSP430x5xx)
+#elif TU_CHECK_MCU(OPT_MCU_MSP430x5xx)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_MSP432E4, OPT_MCU_TM4C123, OPT_MCU_TM4C129)
#define DCD_ATTR_ENDPOINT_MAX 8
//------------- ValentyUSB -------------//
-#elif TU_CHECK_MCU(VALENTYUSB_EPTRI)
+#elif TU_CHECK_MCU(OPT_MCU_VALENTYUSB_EPTRI)
#define DCD_ATTR_ENDPOINT_MAX 16
//------------- Nuvoton -------------//
-#elif TU_CHECK_MCU(NUC121) || TU_CHECK_MCU(NUC126)
+#elif TU_CHECK_MCU(OPT_MCU_NUC121, OPT_MCU_NUC126)
#define DCD_ATTR_ENDPOINT_MAX 8
-#elif TU_CHECK_MCU(NUC120)
+#elif TU_CHECK_MCU(OPT_MCU_NUC120)
#define DCD_ATTR_ENDPOINT_MAX 6
-#elif TU_CHECK_MCU(NUC505)
+#elif TU_CHECK_MCU(OPT_MCU_NUC505)
#define DCD_ATTR_ENDPOINT_MAX 12
//------------- Espressif -------------//
-#elif TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
+#elif TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)
#define DCD_ATTR_ENDPOINT_MAX 6
//------------- Dialog -------------//
-#elif TU_CHECK_MCU(DA1469X)
+#elif TU_CHECK_MCU(OPT_MCU_DA1469X)
#define DCD_ATTR_ENDPOINT_MAX 4
//------------- Raspberry Pi -------------//
-#elif TU_CHECK_MCU(RP2040)
+#elif TU_CHECK_MCU(OPT_MCU_RP2040)
#define DCD_ATTR_ENDPOINT_MAX 16
//------------- Silabs -------------//
-#elif TU_CHECK_MCU(EFM32GG) || TU_CHECK_MCU(EFM32GG11) || TU_CHECK_MCU(EFM32GG12)
+#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
#define DCD_ATTR_ENDPOINT_MAX 7
//------------- Renesas -------------//
-#elif TU_CHECK_MCU(RX63X) || TU_CHECK_MCU(RX65X) || TU_CHECK_MCU(RX72N)
+#elif TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
#define DCD_ATTR_ENDPOINT_MAX 10
-//#elif TU_CHECK_MCU(MM32F327X)
-// #define DCD_ATTR_ENDPOINT_MAX not known yet
-
//------------- GigaDevice -------------//
-#elif TU_CHECK_MCU(GD32VF103)
+#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
#define DCD_ATTR_ENDPOINT_MAX 4
+//------------- Broadcom -------------//
+#elif TU_CHECK_MCU(OPT_MCU_BCM2711)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+//------------- Broadcom -------------//
+#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
//------------- BridgeTek -------------//
#elif TU_CHECK_MCU(FT90X)
#define DCD_ATTR_ENDPOINT_MAX 8
diff --git a/src/device/usbd.c b/src/device/usbd.c
index e12dafcfd..6a5210b34 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -38,7 +38,7 @@
//--------------------------------------------------------------------+
// Debug level of USBD
-#define USBD_DBG_LVL 2
+#define USBD_DBG 2
#ifndef CFG_TUD_TASK_QUEUE_SZ
#define CFG_TUD_TASK_QUEUE_SZ 16
@@ -143,6 +143,18 @@ static usbd_class_driver_t const _usbd_driver[] =
},
#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
+ },
+ #endif
+
#if CFG_TUD_MIDI
{
DRIVER_NAME("MIDI")
@@ -203,7 +215,7 @@ static usbd_class_driver_t const _usbd_driver[] =
},
#endif
- #if CFG_TUD_NET
+ #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
{
DRIVER_NAME("NET")
.init = netd_init,
@@ -432,19 +444,22 @@ bool tud_init (uint8_t rhport)
return true;
}
-static void usbd_reset(uint8_t rhport)
+static void configuration_reset(uint8_t rhport)
{
- tu_varclr(&_usbd_dev);
+ for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
+ {
+ get_driver(i)->reset(rhport);
+ }
+ tu_varclr(&_usbd_dev);
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
+}
+static void usbd_reset(uint8_t rhport)
+{
+ configuration_reset(rhport);
usbd_control_reset();
-
- for ( uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++ )
- {
- get_driver(i)->reset(rhport);
- }
}
bool tud_task_event_ready(void)
@@ -686,9 +701,29 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
{
uint8_t const cfg_num = (uint8_t) p_request->wValue;
- if ( !_usbd_dev.cfg_num && cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
- _usbd_dev.cfg_num = cfg_num;
+ // Only process if new configure is different
+ if (_usbd_dev.cfg_num != cfg_num)
+ {
+ if ( _usbd_dev.cfg_num )
+ {
+ // already configured: need to clear all endpoints and driver first
+ TU_LOG(USBD_DBG, " Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
+
+ // close all non-control endpoints, cancel all pending transfers if any
+ dcd_edpt_close_all(rhport);
+ // close all drivers and current configured state except bus speed
+ uint8_t const speed = _usbd_dev.speed;
+ configuration_reset(rhport);
+
+ _usbd_dev.speed = speed; // restore speed
+ }
+
+ // switch to new configuration if not zero
+ if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
+ }
+
+ _usbd_dev.cfg_num = cfg_num;
tud_control_status(rhport, p_request);
}
break;
@@ -701,7 +736,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Only support remote wakeup for device feature
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
- TU_LOG(USBD_DBG_LVL, " Enable Remote Wakeup\r\n");
+ TU_LOG(USBD_DBG, " Enable Remote Wakeup\r\n");
// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
@@ -712,7 +747,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// Only support remote wakeup for device feature
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
- TU_LOG(USBD_DBG_LVL, " Disable Remote Wakeup\r\n");
+ TU_LOG(USBD_DBG, " Disable Remote Wakeup\r\n");
// Host may disable remote wake up after resuming
_usbd_dev.remote_wakeup_en = false;
@@ -751,16 +786,24 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// driver doesn't use alternate settings or implement this
TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
- if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+ switch(p_request->bRequest)
{
- uint8_t alternate = 0;
- tud_control_xfer(rhport, p_request, &alternate, 1);
- }else if (TUSB_REQ_SET_INTERFACE == p_request->bRequest)
- {
- tud_control_status(rhport, p_request);
- } else
- {
- return false;
+ case TUSB_REQ_GET_INTERFACE:
+ case TUSB_REQ_SET_INTERFACE:
+ // Clear complete callback if driver set since it can also stall the request.
+ usbd_control_set_complete_callback(NULL);
+
+ if (TUSB_REQ_GET_INTERFACE == p_request->bRequest)
+ {
+ uint8_t alternate = 0;
+ tud_control_xfer(rhport, p_request, &alternate, 1);
+ }else
+ {
+ tud_control_status(rhport, p_request);
+ }
+ break;
+
+ default: return false;
}
}
}
@@ -843,12 +886,13 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// This function parse configuration descriptor & open drivers accordingly
static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
{
- tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1); // index is cfg_num-1
+ // index is cfg_num-1
+ tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_descriptor_configuration_cb(cfg_num-1);
TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
// Parse configuration descriptor
_usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1 : 0;
- _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED) ? 1 : 0;
+ _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1 : 0;
// Parse interface descriptor
uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
@@ -856,66 +900,75 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
while( p_desc < desc_end )
{
- tusb_desc_interface_assoc_t const * desc_iad = NULL;
+ uint8_t assoc_itf_count = 1;
// Class will always starts with Interface Association (if any) and then Interface descriptor
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
- desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+ tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
+ assoc_itf_count = desc_iad->bInterfaceCount;
+
p_desc = tu_desc_next(p_desc); // next to Interface
+
+ // IAD's first interface number and class should match with opened interface
+ //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
+ // desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
}
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
-
tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc;
- uint16_t const remaining_len = desc_end-p_desc;
-
- // Interface number must not be used already
- TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber]);
-
- // TODO usbd can calculate the total length used for driver --> driver open() does not need to calculate it
- // uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, desc_iad ? desc_iad->bInterfaceCount : 1, desc_end-p_desc);
// Find driver for this interface
+ uint16_t const remaining_len = desc_end-p_desc;
uint8_t drv_id;
for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++)
{
usbd_class_driver_t const *driver = get_driver(drv_id);
uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len);
- if ( drv_len > 0 )
+ if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) )
{
- // Open successfully, check if length is correct
- TU_ASSERT( sizeof(tusb_desc_interface_t) <= drv_len && drv_len <= remaining_len);
-
+ // Open successfully
TU_LOG2(" %s opened\r\n", driver->name);
- // bind interface to found driver
- _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
+ // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or
+ // BTH (even CDC) with class in device descriptor (single interface)
+ if ( assoc_itf_count == 1)
+ {
+ #if CFG_TUD_CDC
+ if ( driver->open == cdcd_open ) assoc_itf_count = 2;
+ #endif
- // If using IAD, bind all interfaces to the same driver
- if (desc_iad)
+ #if CFG_TUD_MIDI
+ if ( driver->open == midid_open ) assoc_itf_count = 2;
+ #endif
+
+ #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT
+ if ( driver->open == btd_open ) assoc_itf_count = 2;
+ #endif
+ }
+
+ // bind (associated) interfaces to found driver
+ for(uint8_t i=0; i<assoc_itf_count; i++)
{
- // IAD's first interface number and class should match with opened interface
- TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
- desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
+ uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
- for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
- {
- _usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
- }
+ // Interface number must not be used already
+ TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[itf_num]);
+ _usbd_dev.itf2drv[itf_num] = drv_id;
}
// bind all endpoints to found driver
tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id);
- p_desc += drv_len; // next interface
+ // next Interface
+ p_desc += drv_len;
break; // exit driver find loop
}
}
- // Failed if cannot find supported driver
+ // Failed if there is no supported drivers
TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT);
}
@@ -937,19 +990,23 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
{
TU_LOG2(" Device\r\n");
- uint16_t len = sizeof(tusb_desc_device_t);
+ void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
- // Only send up to EP0 Packet Size if not addressed
+ // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
// This only happens with the very first get device descriptor and EP0 size = 8 or 16.
- if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed)
+ if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
+ ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t))
{
- len = CFG_TUD_ENDPOINT0_SIZE;
-
// Hack here: we modify the request length to prevent usbd_control response with zlp
- ((tusb_control_request_t*) p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE;
- }
+ // since we are responding with 1 packet & less data than wLength.
+ tusb_control_request_t mod_request = *p_request;
+ mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE;
- return tud_control_xfer(rhport, p_request, (void*) tud_descriptor_device_cb(), len);
+ return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
+ }else
+ {
+ return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
+ }
}
break;
@@ -960,24 +1017,37 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
// requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
if (!tud_descriptor_bos_cb) return false;
- tusb_desc_bos_t const* desc_bos = (tusb_desc_bos_t const*) tud_descriptor_bos_cb();
+ uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
+ TU_ASSERT(desc_bos);
// Use offsetof to avoid pointer to the odd/misaligned address
- uint16_t const total_len = tu_le16toh( tu_unaligned_read16((uint8_t*) desc_bos + offsetof(tusb_desc_bos_t, wTotalLength)) );
+ uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
}
break;
case TUSB_DESC_CONFIGURATION:
+ case TUSB_DESC_OTHER_SPEED_CONFIG:
{
- TU_LOG2(" Configuration[%u]\r\n", desc_index);
+ uintptr_t desc_config;
+
+ if ( desc_type == TUSB_DESC_CONFIGURATION )
+ {
+ TU_LOG2(" Configuration[%u]\r\n", desc_index);
+ desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
+ }else
+ {
+ // Host only request this after getting Device Qualifier descriptor
+ TU_LOG2(" Other Speed Configuration\r\n");
+ TU_VERIFY( tud_descriptor_other_speed_configuration_cb );
+ desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
+ }
- tusb_desc_configuration_t const* desc_config = (tusb_desc_configuration_t const*) tud_descriptor_configuration_cb(desc_index);
TU_ASSERT(desc_config);
// Use offsetof to avoid pointer to the odd/misaligned address
- uint16_t const total_len = tu_le16toh( tu_unaligned_read16((uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) );
+ uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
}
@@ -988,38 +1058,26 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
TU_LOG2(" String[%u]\r\n", desc_index);
// String Descriptor always uses the desc set from user
- uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
+ uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex));
TU_VERIFY(desc_str);
// first byte of descriptor is its size
- return tud_control_xfer(rhport, p_request, (void*) desc_str, desc_str[0]);
+ return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
}
break;
case TUSB_DESC_DEVICE_QUALIFIER:
+ {
TU_LOG2(" Device Qualifier\r\n");
- // Host sends this request to ask why our device with USB BCD from 2.0
- // but is running at Full/Low Speed. If not highspeed capable stall this request,
- // otherwise return the descriptor that could work in highspeed mode
- if ( tud_descriptor_device_qualifier_cb )
- {
- uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
- TU_ASSERT(desc_qualifier);
+ TU_VERIFY( tud_descriptor_device_qualifier_cb );
- // first byte of descriptor is its size
- return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]);
- }else
- {
- return false;
- }
- break;
+ uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
+ TU_VERIFY(desc_qualifier);
- case TUSB_DESC_OTHER_SPEED_CONFIG:
- TU_LOG2(" Other Speed Configuration\r\n");
-
- // After Device Qualifier descriptor is received host will ask for this descriptor
- return false; // not supported
+ // first byte of descriptor is its size
+ return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
+ }
break;
default: return false;
@@ -1034,15 +1092,11 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
switch (event->event_id)
{
case DCD_EVENT_UNPLUGGED:
- // UNPLUGGED event can be bouncing, only processing if we are currently connected
- if ( _usbd_dev.connected )
- {
- _usbd_dev.connected = 0;
- _usbd_dev.addressed = 0;
- _usbd_dev.cfg_num = 0;
- _usbd_dev.suspended = 0;
- osal_queue_send(_usbd_q, event, in_isr);
- }
+ _usbd_dev.connected = 0;
+ _usbd_dev.addressed = 0;
+ _usbd_dev.cfg_num = 0;
+ _usbd_dev.suspended = 0;
+ osal_queue_send(_usbd_q, event, in_isr);
break;
case DCD_EVENT_SUSPEND:
@@ -1301,27 +1355,33 @@ bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
- TU_LOG(USBD_DBG_LVL, " Stall EP %02X", ep_addr);
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- dcd_edpt_stall(rhport, ep_addr);
- _usbd_dev.ep_status[epnum][dir].stalled = true;
- _usbd_dev.ep_status[epnum][dir].busy = true;
+ // only stalled if currently cleared
+ if ( !_usbd_dev.ep_status[epnum][dir].stalled )
+ {
+ TU_LOG(USBD_DBG, " Stall EP %02X\r\n", ep_addr);
+ dcd_edpt_stall(rhport, ep_addr);
+ _usbd_dev.ep_status[epnum][dir].stalled = true;
+ _usbd_dev.ep_status[epnum][dir].busy = true;
+ }
}
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
- TU_LOG(USBD_DBG_LVL, " Clear Stall EP %02X", ep_addr);
-
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
-
- dcd_edpt_clear_stall(rhport, ep_addr);
- _usbd_dev.ep_status[epnum][dir].stalled = false;
- _usbd_dev.ep_status[epnum][dir].busy = false;
+ // only clear if currently stalled
+ if ( _usbd_dev.ep_status[epnum][dir].stalled )
+ {
+ TU_LOG(USBD_DBG, " Clear Stall EP %02X\r\n", ep_addr);
+ dcd_edpt_clear_stall(rhport, ep_addr);
+ _usbd_dev.ep_status[epnum][dir].stalled = false;
+ _usbd_dev.ep_status[epnum][dir].busy = false;
+ }
}
bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
@@ -1345,7 +1405,13 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
TU_ASSERT(dcd_edpt_close, /**/);
TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
dcd_edpt_close(rhport, ep_addr);
+ _usbd_dev.ep_status[epnum][dir].stalled = false;
+ _usbd_dev.ep_status[epnum][dir].busy = false;
+ _usbd_dev.ep_status[epnum][dir].claimed = false;
return;
}
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 9becf2d0d..ec34817fa 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -113,9 +113,16 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid);
TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
-// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
+// device_qualifier descriptor describes information about a high-speed capable device that would
+// change if the device were operating at the other speed. If not highspeed capable stall this request.
TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void);
+// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
+TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index);
+
// Invoked when device is mounted (configured)
TU_ATTR_WEAK void tud_mount_cb(void);
@@ -171,17 +178,18 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
//--------------------------------------------------------------------+
-// Configuration & Interface Descriptor Templates
+// Configuration Descriptor Templates
//--------------------------------------------------------------------+
-//------------- Configuration -------------//
#define TUD_CONFIG_DESC_LEN (9)
// Config number, interface count, string index, total length, attribute, power in mA
#define TUD_CONFIG_DESCRIPTOR(config_num, _itfcount, _stridx, _total_len, _attribute, _power_ma) \
9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, config_num, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
-//------------- CDC -------------//
+//--------------------------------------------------------------------+
+// CDC Descriptor Templates
+//--------------------------------------------------------------------+
// Length of template descriptor: 66 bytes
#define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7)
@@ -210,7 +218,9 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
-//------------- MSC -------------//
+//--------------------------------------------------------------------+
+// MSC Descriptor Templates
+//--------------------------------------------------------------------+
// Length of template descriptor: 23 bytes
#define TUD_MSC_DESC_LEN (9 + 7 + 7)
@@ -224,7 +234,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
-//------------- HID -------------//
+
+//--------------------------------------------------------------------+
+// HID Descriptor Templates
+//--------------------------------------------------------------------+
// Length of template descriptor: 25 bytes
#define TUD_HID_DESC_LEN (9 + 9 + 7)
@@ -254,8 +267,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
-//------------- MIDI -------------//
-// MIDI v1.0 is based on Audio v1.0
+//--------------------------------------------------------------------+
+// MIDI Descriptor Templates
+// Note: MIDI v1.0 is based on Audio v1.0
+//--------------------------------------------------------------------+
#define TUD_MIDI_DESC_HEAD_LEN (9 + 9 + 9 + 7)
#define TUD_MIDI_DESC_HEAD(_itfnum, _stridx, _numcables) \
@@ -312,7 +327,9 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
TUD_MIDI_DESC_EP(_epin, _epsize, 1),\
TUD_MIDI_JACKID_OUT_EMB(1)
-//------------- AUDIO -------------//
+//--------------------------------------------------------------------+
+// Audio v2.0 Descriptor Templates
+//--------------------------------------------------------------------+
/* Standard Interface Association Descriptor (IAD) */
#define TUD_AUDIO_DESC_IAD_LEN 8
@@ -544,7 +561,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
((((_maxFrequency + ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 7999 : 999)) / ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels)
-//------------- TUD_USBTMC/USB488 -------------//
+//--------------------------------------------------------------------+
+// USBTMC/USB488 Descriptor Templates
+//--------------------------------------------------------------------+
+
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
#define TUD_USBTMC_APP_SUBCLASS 0x03u
@@ -574,8 +594,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
+//--------------------------------------------------------------------+
+// Vendor Descriptor Templates
+//--------------------------------------------------------------------+
-//------------- Vendor -------------//
#define TUD_VENDOR_DESC_LEN (9+7+7)
// Interface number, string index, EP Out & IN address, EP size
@@ -587,7 +609,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
-//------------- DFU Runtime -------------//
+//--------------------------------------------------------------------+
+// DFU Runtime Descriptor Templates
+//--------------------------------------------------------------------+
+
#define TUD_DFU_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
#define TUD_DFU_APP_SUBCLASS (APP_SUBCLASS_DFU_RUNTIME)
@@ -602,6 +627,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Function */ \
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+//--------------------------------------------------------------------+
+// DFU Descriptor Templates
+//--------------------------------------------------------------------+
+
// Length of template descriptor: 9 bytes + number of alternatives * 9
#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9)
@@ -647,8 +676,9 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
_TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
_TUD_DFU_ALT_7(_itfnum, _alt_count+1, _stridx+1)
-
-//------------- CDC-ECM -------------//
+//--------------------------------------------------------------------+
+// CDC-ECM Descriptor Templates
+//--------------------------------------------------------------------+
// Length of template descriptor: 71 bytes
#define TUD_CDC_ECM_DESC_LEN (8+9+5+5+13+7+9+9+7+7)
@@ -677,8 +707,9 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
-
-//------------- RNDIS -------------//
+//--------------------------------------------------------------------+
+// RNDIS Descriptor Templates
+//--------------------------------------------------------------------+
#if 0
/* Windows XP */
@@ -719,7 +750,10 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Endpoint Out */\
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
-//------------- BT Radio -------------//
+//--------------------------------------------------------------------+
+// Bluetooth Radio Descriptor Templates
+//--------------------------------------------------------------------+
+
#define TUD_BT_APP_CLASS (TUSB_CLASS_WIRELESS_CONTROLLER)
#define TUD_BT_APP_SUBCLASS 0x01
#define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01
@@ -729,8 +763,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
#define CFG_TUD_BTH_ISO_ALT_COUNT 0
#endif
-// Length of template descriptor: 30 bytes + number of ISO alternatives * 23
-#define TUD_BTH_DESC_LEN (9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7))
+// Length of template descriptor: 38 bytes + number of ISO alternatives * 23
+#define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7))
/* Primary Interface */
#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
@@ -770,10 +804,46 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// BT Primary controller descriptor
// Interface number, string index, attributes, event endpoint, event endpoint size, interval, data in, data out, data endpoint size, iso endpoint sizes
+// TODO BTH should also use IAD like CDC for composite device
#define TUD_BTH_DESCRIPTOR(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size,...) \
+ /* Interface Associate */\
+ 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0,\
TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
TUD_BTH_ISO_ITFS(_itfnum + 1, _ep_in + 1, _ep_out + 1, __VA_ARGS__)
+//--------------------------------------------------------------------+
+// CDC-NCM Descriptor Templates
+//--------------------------------------------------------------------+
+
+// Length of template descriptor
+#define TUD_CDC_NCM_DESC_LEN (8+9+5+5+13+6+7+9+9+7+7)
+
+// CDC-ECM Descriptor Template
+// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
+#define TUD_CDC_NCM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \
+ /* Interface Association */\
+ 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, 0,\
+ /* CDC Control Interface */\
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_NETWORK_CONTROL_MODEL, 0, _desc_stridx,\
+ /* CDC-NCM Header */\
+ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
+ /* CDC-NCM Union */\
+ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+ /* CDC-NCM Functional Descriptor */\
+ 13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0, \
+ /* CDC-NCM Functional Descriptor */\
+ 6, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_NCM, U16_TO_U8S_LE(0x0100), 0, \
+ /* Endpoint Notification */\
+ 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 50,\
+ /* CDC Data Interface (default inactive) */\
+ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 0, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\
+ /* CDC Data Interface (alternative active) */\
+ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 1, 2, TUSB_CLASS_CDC_DATA, 0, NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK, 0,\
+ /* Endpoint In */\
+ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+ /* Endpoint Out */\
+ 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
#ifdef __cplusplus
}
#endif
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index 6a4b30956..7607b9895 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -81,7 +81,7 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr);
// Release an endpoint without submitting a transfer
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr);
-// Check if endpoint transferring is complete
+// Check if endpoint is busy transferring
bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr);
// Stall endpoint
@@ -93,6 +93,7 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);
// Check if endpoint is stalled
bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr);
+// Check if endpoint is ready (not busy and not stalled)
TU_ATTR_ALWAYS_INLINE static inline
bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr)
{