summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorhathach <[email protected]>2021-09-18 13:35:26 +0700
committerhathach <[email protected]>2021-09-18 13:35:26 +0700
commit3333703d257b4b2a37f543a65ea4a6e2db777fdb (patch)
treefb37112e82f7f64857473d8346f32c763bd67ec9 /src/device
parent82618d2d5f15d0f8dd9631dec3807964a1281782 (diff)
parent90465299b42facff3c815d97950066706dbbd74a (diff)
Merge branch 'master' into zhangslice-master
Diffstat (limited to 'src/device')
-rw-r--r--src/device/dcd.h21
-rw-r--r--src/device/dcd_attr.h164
-rw-r--r--src/device/usbd.c322
-rw-r--r--src/device/usbd.h83
-rw-r--r--src/device/usbd_control.c1
-rw-r--r--src/device/usbd_pvt.h4
6 files changed, 428 insertions, 167 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 63e97df96..d43a0dd9a 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -30,11 +30,24 @@
#include "common/tusb_common.h"
#include "osal/osal.h"
#include "common/tusb_fifo.h"
+#include "dcd_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUD_ENDPPOINT_MAX
+ #define CFG_TUD_ENDPPOINT_MAX DCD_ATTR_ENDPOINT_MAX
+#endif
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
typedef enum
{
DCD_EVENT_INVALID = 0,
@@ -124,6 +137,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;
@@ -135,10 +153,11 @@ 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
+// This API never calls with control endpoints, since it is auto cleared when receiving setup packet
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
//--------------------------------------------------------------------+
diff --git a/src/device/dcd_attr.h b/src/device/dcd_attr.h
new file mode 100644
index 000000000..a35fc0ac5
--- /dev/null
+++ b/src/device/dcd_attr.h
@@ -0,0 +1,164 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_DCD_ATTR_H_
+#define TUSB_DCD_ATTR_H_
+
+#include "tusb_option.h"
+
+// Attribute includes
+// - ENDPOINT_MAX: max (logical) number of endpoint
+// - ENDPOINT_EXCLUSIVE_NUMBER: endpoint number with different direction IN and OUT aren't allowed,
+// e.g EP1 OUT & EP1 IN cannot exist together
+// - 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)
+ #define DCD_ATTR_ENDPOINT_MAX 5
+
+#elif TU_CHECK_MCU(LPC175X_6X) || TU_CHECK_MCU(LPC177X_8X) || TU_CHECK_MCU(LPC40XX)
+ #define DCD_ATTR_ENDPOINT_MAX 16
+
+#elif TU_CHECK_MCU(LPC18XX) || TU_CHECK_MCU(LPC43XX)
+ // TODO USB0 has 6, USB1 has 4
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(LPC51UXX)
+ #define DCD_ATTR_ENDPOINT_MAX 5
+
+#elif TU_CHECK_MCU(LPC54XXX)
+ // TODO USB0 has 5, USB1 has 6
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(LPC55XX)
+ // TODO USB0 has 5, USB1 has 6
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(MIMXRT10XX)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(MKL25ZXX) || TU_CHECK_MCU(K32L2BXX)
+ #define DCD_ATTR_ENDPOINT_MAX 16
+
+//------------- Nordic -------------//
+#elif TU_CHECK_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)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(SAMG)
+ #define DCD_ATTR_ENDPOINT_MAX 6
+ #define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
+
+#elif TU_CHECK_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
+ #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
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(STM32F7)
+ // FS has 6, HS has 9
+ #define DCD_ATTR_ENDPOINT_MAX 9
+
+#elif TU_CHECK_MCU(STM32H7)
+ #define DCD_ATTR_ENDPOINT_MAX 9
+
+//------------- Sony -------------//
+#elif TU_CHECK_MCU(CXD56)
+ #define DCD_ATTR_ENDPOINT_MAX 7
+ #define DCD_ATTR_ENDPOINT_EXCLUSIVE_NUMBER
+
+//------------- TI -------------//
+#elif TU_CHECK_MCU(MSP430x5xx)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+//------------- ValentyUSB -------------//
+#elif TU_CHECK_MCU(VALENTYUSB_EPTRI)
+ #define DCD_ATTR_ENDPOINT_MAX 16
+
+//------------- Nuvoton -------------//
+#elif TU_CHECK_MCU(NUC121) || TU_CHECK_MCU(NUC126)
+ #define DCD_ATTR_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(NUC120)
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+#elif TU_CHECK_MCU(NUC505)
+ #define DCD_ATTR_ENDPOINT_MAX 12
+
+//------------- Espressif -------------//
+#elif TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
+ #define DCD_ATTR_ENDPOINT_MAX 6
+
+//------------- Dialog -------------//
+#elif TU_CHECK_MCU(DA1469X)
+ #define DCD_ATTR_ENDPOINT_MAX 4
+
+//------------- Raspberry Pi -------------//
+#elif TU_CHECK_MCU(RP2040)
+ #define DCD_ATTR_ENDPOINT_MAX 16
+
+//------------- Silabs -------------//
+#elif TU_CHECK_MCU(EFM32GG) || TU_CHECK_MCU(EFM32GG11) || TU_CHECK_MCU(EFM32GG12)
+ #define DCD_ATTR_ENDPOINT_MAX 7
+
+//------------- Renesas -------------//
+#elif TU_CHECK_MCU(RX63X) || TU_CHECK_MCU(RX65X) || TU_CHECK_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)
+ #define DCD_ATTR_ENDPOINT_MAX 4
+
+#else
+ #warning "DCD_ATTR_ENDPOINT_MAX is not defined for this MCU, default to 8"
+ #define DCD_ATTR_ENDPOINT_MAX 8
+#endif
+
+// Default to fullspeed if not defined
+//#ifndef PORT_HIGHSPEED
+// #define DCD_ATTR_PORT_HIGHSPEED 0x00
+//#endif
+
+#endif
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 2935defd0..3043fc7bc 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -33,12 +33,15 @@
#include "device/usbd_pvt.h"
#include "device/dcd.h"
-#ifndef CFG_TUD_TASK_QUEUE_SZ
-#define CFG_TUD_TASK_QUEUE_SZ 16
-#endif
+//--------------------------------------------------------------------+
+// USBD Configuration
+//--------------------------------------------------------------------+
+
+// Debug level of USBD
+#define USBD_DBG 2
-#ifndef CFG_TUD_EP_MAX
-#define CFG_TUD_EP_MAX 9
+#ifndef CFG_TUD_TASK_QUEUE_SZ
+ #define CFG_TUD_TASK_QUEUE_SZ 16
#endif
//--------------------------------------------------------------------+
@@ -65,7 +68,7 @@ typedef struct
uint8_t speed;
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
- uint8_t ep2drv[CFG_TUD_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
+ uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid )
struct TU_ATTR_PACKED
{
@@ -74,7 +77,7 @@ typedef struct
volatile bool claimed : 1;
// TODO merge ep2drv here, 4-bit should be sufficient
- }ep_status[CFG_TUD_EP_MAX][2];
+ }ep_status[CFG_TUD_ENDPPOINT_MAX][2];
}usbd_device_t;
@@ -188,9 +191,9 @@ static usbd_class_driver_t const _usbd_driver[] =
},
#endif
- #if CFG_TUD_DFU_MODE
+ #if CFG_TUD_DFU
{
- DRIVER_NAME("DFU-MODE")
+ DRIVER_NAME("DFU")
.init = dfu_moded_init,
.reset = dfu_moded_reset,
.open = dfu_moded_open,
@@ -271,7 +274,6 @@ static osal_mutex_t _usbd_mutex;
//--------------------------------------------------------------------+
// Prototypes
//--------------------------------------------------------------------+
-static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
@@ -430,19 +432,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)
@@ -556,13 +561,28 @@ void tud_task (void)
break;
case DCD_EVENT_SUSPEND:
- TU_LOG2("\r\n");
- if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
+ // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
+ // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event
+ // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
+ if ( _usbd_dev.connected )
+ {
+ TU_LOG2(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
+ if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
+ }else
+ {
+ TU_LOG2(" Skipped\r\n");
+ }
break;
case DCD_EVENT_RESUME:
- TU_LOG2("\r\n");
- if (tud_resume_cb) tud_resume_cb();
+ if ( _usbd_dev.connected )
+ {
+ TU_LOG2("\r\n");
+ if (tud_resume_cb) tud_resume_cb();
+ }else
+ {
+ TU_LOG2(" Skipped\r\n");
+ }
break;
case DCD_EVENT_SOF:
@@ -669,9 +689,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;
@@ -684,6 +724,8 @@ 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, " Enable Remote Wakeup\r\n");
+
// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
tud_control_status(rhport, p_request);
@@ -693,6 +735,8 @@ 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, " Disable Remote Wakeup\r\n");
+
// Host may disable remote wake up after resuming
_usbd_dev.remote_wakeup_en = false;
tud_control_status(rhport, p_request);
@@ -730,16 +774,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;
}
}
}
@@ -822,7 +874,8 @@ 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
@@ -831,16 +884,16 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
// Parse interface descriptor
uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
- uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + desc_cfg->wTotalLength;
+ uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
while( p_desc < desc_end )
{
- tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
+ tusb_desc_interface_assoc_t const * desc_iad = NULL;
// Class will always starts with Interface Association (if any) and then Interface descriptor
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
- desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
+ desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
p_desc = tu_desc_next(p_desc); // next to Interface
}
@@ -849,6 +902,13 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
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
uint8_t drv_id;
for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++)
{
@@ -860,30 +920,30 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
// Open successfully, check if length is correct
TU_ASSERT( sizeof(tusb_desc_interface_t) <= drv_len && drv_len <= remaining_len);
- // Interface number must not be used already
- TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber]);
-
TU_LOG2(" %s opened\r\n", driver->name);
+
+ // bind interface to found driver
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
- // If IAD exist, assign all interfaces to the same driver
- if (desc_itf_assoc)
+ // If using IAD, bind all interfaces to the same driver
+ if (desc_iad)
{
// IAD's first interface number and class should match with opened interface
- TU_ASSERT(desc_itf_assoc->bFirstInterface == desc_itf->bInterfaceNumber &&
- desc_itf_assoc->bFunctionClass == desc_itf->bInterfaceClass);
+ TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
+ desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
- for(uint8_t i=1; i<desc_itf_assoc->bInterfaceCount; i++)
+ for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
{
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
}
}
- mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, drv_len, drv_id); // TODO refactor
+ // 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
- break;
+ break; // exit driver find loop
}
}
@@ -897,25 +957,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
return true;
}
-// Helper marking endpoint of interface belongs to class driver
-static void mark_interface_endpoint(uint8_t ep2drv[][2], uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
-{
- uint16_t len = 0;
-
- while( len < desc_len )
- {
- if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
- {
- uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
-
- ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
- }
-
- len = (uint16_t)(len + tu_desc_len(p_desc));
- p_desc = tu_desc_next(p_desc);
- }
-}
-
// return descriptor's buffer and update desc_len
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
{
@@ -953,24 +994,34 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
tusb_desc_bos_t const* desc_bos = (tusb_desc_bos_t const*) tud_descriptor_bos_cb();
- uint16_t total_len;
// Use offsetof to avoid pointer to the odd/misaligned address
- memcpy(&total_len, (uint8_t*) desc_bos + offsetof(tusb_desc_bos_t, wTotalLength), 2);
+ uint16_t const total_len = tu_le16toh( tu_unaligned_read16((uint8_t*) 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);
+ tusb_desc_configuration_t const* desc_config;
+
+ if ( desc_type == TUSB_DESC_CONFIGURATION )
+ {
+ TU_LOG2(" Configuration[%u]\r\n", desc_index);
+ desc_config = (tusb_desc_configuration_t const*) 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 = (tusb_desc_configuration_t const*) 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);
- uint16_t total_len;
// Use offsetof to avoid pointer to the odd/misaligned address
- memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2);
+ uint16_t const total_len = tu_le16toh( tu_unaligned_read16((uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength)) );
return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
}
@@ -990,29 +1041,17 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
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;
-
- case TUSB_DESC_OTHER_SPEED_CONFIG:
- TU_LOG2(" Other Speed Configuration\r\n");
+ uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
+ TU_VERIFY(desc_qualifier);
- // 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*) desc_qualifier, desc_qualifier[0]);
+ }
break;
default: return false;
@@ -1027,19 +1066,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);
- }
- break;
-
- case DCD_EVENT_SOF:
- return; // skip SOF event for now
+ _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:
@@ -1063,6 +1094,17 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
}
break;
+ case DCD_EVENT_SOF:
+ // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
+ // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
+ if ( _usbd_dev.suspended )
+ {
+ _usbd_dev.suspended = 0;
+ dcd_event_t const event_resume = { .rhport = event->rhport, .event_id = DCD_EVENT_RESUME };
+ osal_queue_send(_usbd_q, &event_resume, in_isr);
+ }
+ break;
+
default:
osal_queue_send(_usbd_q, event, in_isr);
break;
@@ -1150,38 +1192,8 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
{
- TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, desc_ep->wMaxPacketSize.size);
-
- switch (desc_ep->bmAttributes.xfer)
- {
- case TUSB_XFER_ISOCHRONOUS:
- {
- uint16_t const max_epsize = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 1023);
- TU_ASSERT(desc_ep->wMaxPacketSize.size <= max_epsize);
- }
- break;
-
- case TUSB_XFER_BULK:
- if (_usbd_dev.speed == TUSB_SPEED_HIGH)
- {
- // Bulk highspeed must be EXACTLY 512
- TU_ASSERT(desc_ep->wMaxPacketSize.size == 512);
- }else
- {
- // TODO Bulk fullspeed can only be 8, 16, 32, 64
- TU_ASSERT(desc_ep->wMaxPacketSize.size <= 64);
- }
- break;
-
- case TUSB_XFER_INTERRUPT:
- {
- uint16_t const max_epsize = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 64);
- TU_ASSERT(desc_ep->wMaxPacketSize.size <= max_epsize);
- }
- break;
-
- default: return false;
- }
+ TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
+ TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
return dcd_edpt_open(rhport, desc_ep);
}
@@ -1190,6 +1202,9 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
{
(void) rhport;
+ // TODO add this check later, also make sure we don't starve an out endpoint while suspending
+ // TU_VERIFY(tud_ready());
+
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
@@ -1243,7 +1258,10 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
+ // TODO skip ready() check for now since enumeration also use this API
+ // TU_VERIFY(tud_ready());
+
+ TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
// Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
@@ -1254,14 +1272,13 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )
{
- TU_LOG2("OK\r\n");
return true;
}else
{
// DCD error, mark endpoint as ready to allow next transfer
_usbd_dev.ep_status[epnum][dir].busy = false;
_usbd_dev.ep_status[epnum][dir].claimed = 0;
- TU_LOG2("failed\r\n");
+ TU_LOG2("FAILED\r\n");
TU_BREAKPOINT();
return false;
}
@@ -1312,12 +1329,18 @@ bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
void usbd_edpt_stall(uint8_t rhport, uint8_t 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)
@@ -1325,9 +1348,14 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t 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)
@@ -1351,7 +1379,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 3857295d7..638d93094 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -24,18 +24,15 @@
* This file is part of the TinyUSB stack.
*/
-/** \ingroup group_usbd
- * @{ */
-
#ifndef _TUSB_USBD_H_
#define _TUSB_USBD_H_
+#include "common/tusb_common.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "common/tusb_common.h"
-
//--------------------------------------------------------------------+
// Application API
//--------------------------------------------------------------------+
@@ -103,10 +100,6 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void);
-// Invoked when received GET BOS DESCRIPTOR request
-// Application return pointer to descriptor
-TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
-
// Invoked when received GET CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
@@ -115,10 +108,21 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid);
+// Invoked when received GET BOS DESCRIPTOR request
+// Application return pointer to descriptor
+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);
@@ -236,7 +240,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
/* Interface */\
- 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint In */\
@@ -249,7 +253,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
/* Interface */\
- 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint Out */\
@@ -542,6 +546,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\
TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\
+// Calculate wMaxPacketSize of Endpoints
+#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \
+ ((((_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 -------------//
#define TUD_USBTMC_APP_CLASS (TUSB_CLASS_APPLICATION_SPECIFIC)
#define TUD_USBTMC_APP_SUBCLASS 0x03u
@@ -600,17 +609,51 @@ 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)
-// Length of template descriptr: 18 bytes
-#define TUD_DFU_MODE_DESC_LEN (9 + 9)
+// Length of template descriptor: 9 bytes + number of alternatives * 9
+#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9)
-// DFU runtime descriptor
-// Interface number, string index, attributes, detach timeout, transfer size
-#define TUD_DFU_MODE_DESCRIPTOR(_itfnum, _stridx, _attr, _timeout, _xfer_size) \
- /* Interface */ \
- 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx, \
+// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size
+// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface
+#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \
+ TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \
/* Function */ \
9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+#define _TUD_DFU_ALT(_itfnum, _alt, _stridx) \
+ /* Interface */ \
+ 9, TUSB_DESC_INTERFACE, _itfnum, _alt, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_DFU, _stridx
+
+#define _TUD_DFU_ALT_1(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx)
+
+#define _TUD_DFU_ALT_2(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_1(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_3(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_2(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_4(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_3(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_5(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_4(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_6(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_5(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_7(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_6(_itfnum, _alt_count+1, _stridx+1)
+
+#define _TUD_DFU_ALT_8(_itfnum, _alt_count, _stridx) \
+ _TUD_DFU_ALT(_itfnum, _alt_count, _stridx), \
+ _TUD_DFU_ALT_7(_itfnum, _alt_count+1, _stridx+1)
+
//------------- CDC-ECM -------------//
@@ -698,7 +741,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
/* Primary Interface */
#define TUD_BTH_PRI_ITF(_itfnum, _stridx, _ep_evt, _ep_evt_size, _ep_evt_interval, _ep_in, _ep_out, _ep_size) \
- 9, TUSB_DESC_INTERFACE, _itfnum, _stridx, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, 0, \
+ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 3, TUD_BT_APP_CLASS, TUD_BT_APP_SUBCLASS, TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, _stridx, \
/* Endpoint In for events */ \
7, TUSB_DESC_ENDPOINT, _ep_evt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_evt_size), _ep_evt_interval, \
/* Endpoint In for ACL data */ \
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index 724c652e6..7a8244699 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -186,6 +186,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
{
TU_VERIFY(_ctrl_xfer.buffer);
memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
+ TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2);
}
_ctrl_xfer.total_xferred += xferred_bytes;
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index b8d34d7b6..7607b9895 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -56,7 +56,6 @@ typedef struct
// Note: The drivers array must be accessible at all time when stack is active
usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK;
-
typedef bool (*usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
//--------------------------------------------------------------------+
@@ -82,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
@@ -94,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)
{