Merge branch 'master' into port-ft90x

This commit is contained in:
Gordon McNab
2021-12-08 08:36:43 +00:00
318 changed files with 31702 additions and 3551 deletions

View File

@@ -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

View File

@@ -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(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(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(STM32F7)
#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(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(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

View File

@@ -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);
memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
usbd_control_reset();
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();
}
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;
// If using IAD, bind all interfaces to the same driver
if (desc_iad)
// 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)
{
// 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);
#if CFG_TUD_CDC
if ( driver->open == cdcd_open ) assoc_itf_count = 2;
#endif
for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
{
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
}
#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++)
{
uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
// 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;
}

View File

@@ -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

View File

@@ -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)
{