From 2e21557842d25a132620306ce8f44e944ba93cab Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Thu, 8 Feb 2024 00:04:45 +0100 Subject: [PATCH] feat(esp_tinyusb): Added qualifier descritpor handling, implmented other speed and qualifier callbacks --- device/esp_tinyusb/descriptors_control.c | 104 ++++++++++++++++-- device/esp_tinyusb/include/tinyusb.h | 4 +- .../include_private/descriptors_control.h | 10 +- device/esp_tinyusb/test/CMakeLists.txt | 2 +- device/esp_tinyusb/test/test_bvalid_sig.c | 9 -- 5 files changed, 105 insertions(+), 24 deletions(-) diff --git a/device/esp_tinyusb/descriptors_control.c b/device/esp_tinyusb/descriptors_control.c index 2b30fab8..5af2c19c 100644 --- a/device/esp_tinyusb/descriptors_control.c +++ b/device/esp_tinyusb/descriptors_control.c @@ -47,15 +47,53 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index) assert(s_desc_cfg->cfg); #if (TUD_OPT_HIGH_SPEED) + // HINT: cfg and hs_cfg are the same, no need to assert(hs_cfg) assert(s_desc_cfg->fs_cfg); // Return configuration descriptor based on Host speed - return (tud_speed_get() == TUSB_SPEED_HIGH) - ? s_desc_cfg->cfg + return (TUSB_SPEED_HIGH == tud_speed_get()) + ? s_desc_cfg->hs_cfg : s_desc_cfg->fs_cfg; #else return s_desc_cfg->cfg; -#endif // +#endif // TUD_OPT_HIGH_SPEED +} + +#if (TUD_OPT_HIGH_SPEED) +/** + * @brief Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request + * Descriptor contents must exist long enough for transfer to complete + * If not highspeed capable stall this request + */ +uint8_t const *tud_descriptor_device_qualifier_cb(void) +{ + assert(s_desc_cfg); + assert(s_desc_cfg->qualifier); + return (uint8_t const *)s_desc_cfg->qualifier; +} + + +/** + * @brief Invoked when received GET OTHER SPEED CONFIGURATION DESCRIPTOR request + * Descriptor 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 + */ +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + assert(s_desc_cfg); + assert(s_desc_cfg->other_speed); + + const uint8_t *other_speed = (TUSB_SPEED_HIGH == tud_speed_get()) + ? s_desc_cfg->fs_cfg + : s_desc_cfg->hs_cfg; + + memcpy(s_desc_cfg->other_speed, + other_speed, + ((tusb_desc_configuration_t *)other_speed)->wTotalLength); + + ((tusb_desc_configuration_t *)s_desc_cfg->other_speed)->bDescriptorType = TUSB_DESC_OTHER_SPEED_CONFIG; + return s_desc_cfg->other_speed; } +#endif // TUD_OPT_HIGH_SPEED /** * @brief Invoked when received GET STRING DESCRIPTOR request @@ -106,8 +144,9 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) // ============================================================================= esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) { + esp_err_t ret = ESP_FAIL; assert(config); - const char **string_descriptor; + const char **pstr_desc; // Create descriptor struct s_desc_cfg = calloc(1, sizeof(tinyusb_descriptor_config_t)); assert(s_desc_cfg); @@ -126,7 +165,7 @@ esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) if (NULL == config->hs_cfg_desc) { // Default configuration descriptor is provided only for CDC, MSC and NCM classes #if (CFG_TUD_HID > 0 || CFG_TUD_MIDI > 0 || CFG_TUD_CUSTOM_CLASS > 0 || CFG_TUD_ECM_RNDIS > 0 || CFG_TUD_DFU > 0 || CFG_TUD_DFU_RUNTIME > 0 || CFG_TUD_BTH > 0) - ESP_RETURN_ON_FALSE(config->hs_cfg_desc, ESP_ERR_INVALID_ARG, TAG, "Configuration descriptor must be provided for this device"); + ESP_GOTO_ON_FALSE(config->hs_cfg_desc, ESP_ERR_INVALID_ARG, fail, TAG, "Configuration descriptor must be provided for this device"); #else ESP_LOGW(TAG, "The device's HS configuration descriptor is not provided by user, using default."); #endif @@ -139,7 +178,7 @@ esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) if (NULL == config->fs_cfg_desc) { // Default configuration descriptor is provided only for CDC, MSC and NCM classes #if (CFG_TUD_HID > 0 || CFG_TUD_MIDI > 0 || CFG_TUD_CUSTOM_CLASS > 0 || CFG_TUD_ECM_RNDIS > 0 || CFG_TUD_DFU > 0 || CFG_TUD_DFU_RUNTIME > 0 || CFG_TUD_BTH > 0) - ESP_RETURN_ON_FALSE(config->fs_cfg_desc, ESP_ERR_INVALID_ARG, TAG, "Configuration descriptor must be provided for this device"); + ESP_GOTO_ON_FALSE(config->fs_cfg_desc, ESP_ERR_INVALID_ARG, fail, TAG, "Configuration descriptor must be provided for this device"); #else ESP_LOGW(TAG, "The device's FS configuration descriptor is not provided by user, using default."); #endif @@ -147,11 +186,42 @@ esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) s_desc_cfg->fs_cfg = config->fs_cfg_desc ? config->fs_cfg_desc : descriptor_fs_cfg_kconfig; + + // HS and FS cfg desc should be equal length + ESP_GOTO_ON_FALSE(((tusb_desc_configuration_t *)s_desc_cfg->hs_cfg)->wTotalLength == + ((tusb_desc_configuration_t *)s_desc_cfg->fs_cfg)->wTotalLength, + ESP_ERR_INVALID_ARG, fail, TAG, "HS and FS Configuration descriptors must be same length"); + + // Qualifier Descriptor + if (NULL == config->qualifier_desc) { + ESP_LOGW(TAG, "Qualifier descriptor must be provided for HighSpeed device. Create one with current Device Descriptor."); + s_desc_cfg->qualifier = calloc(1, sizeof (tusb_desc_device_qualifier_t)); + + // Fill up with values from Device descriptor + s_desc_cfg->qualifier->bLength = s_desc_cfg->dev->bLength; + s_desc_cfg->qualifier->bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER; + s_desc_cfg->qualifier->bcdUSB = s_desc_cfg->dev->bcdUSB; + s_desc_cfg->qualifier->bDeviceClass = s_desc_cfg->dev->bDeviceClass; + s_desc_cfg->qualifier->bDeviceSubClass = s_desc_cfg->dev->bDeviceSubClass; + s_desc_cfg->qualifier->bDeviceProtocol = s_desc_cfg->dev->bDeviceProtocol; + s_desc_cfg->qualifier->bMaxPacketSize0 = s_desc_cfg->dev->bMaxPacketSize0; + s_desc_cfg->qualifier->bNumConfigurations = s_desc_cfg->dev->bNumConfigurations; + s_desc_cfg->qualifier->bReserved = 0; + + s_desc_cfg->qualifier_alloc_internally = true; + } else { + s_desc_cfg->qualifier = config->qualifier_desc; + s_desc_cfg->qualifier_alloc_internally = false; + } + + // Other Speed buffer allocate + s_desc_cfg->other_speed = calloc(1, ((tusb_desc_configuration_t *)s_desc_cfg->hs_cfg)->wTotalLength); + ESP_GOTO_ON_FALSE(s_desc_cfg->other_speed, ESP_ERR_NO_MEM, fail, TAG, "Other speed memory allocation error"); #else if (NULL == config->configuration_descriptor) { // Default configuration descriptor is provided only for CDC, MSC and NCM classes #if (CFG_TUD_HID > 0 || CFG_TUD_MIDI > 0 || CFG_TUD_CUSTOM_CLASS > 0 || CFG_TUD_ECM_RNDIS > 0 || CFG_TUD_DFU > 0 || CFG_TUD_DFU_RUNTIME > 0 || CFG_TUD_BTH > 0) - ESP_RETURN_ON_FALSE(config->configuration_descriptor, ESP_ERR_INVALID_ARG, TAG, "Configuration descriptor must be provided for this device"); + ESP_GOTO_ON_FALSE(config->configuration_descriptor, ESP_ERR_INVALID_ARG, fail, TAG, "Configuration descriptor must be provided for this device"); #else ESP_LOGW(TAG, "The device's configuration descriptor is not provided by user, using default."); #endif @@ -163,18 +233,18 @@ esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) // Select String Descriptors and count them if (config->string_descriptor) { - string_descriptor = config->string_descriptor; + pstr_desc = config->string_descriptor; s_desc_cfg->str_count = (config->string_descriptor_count != 0) ? config->string_descriptor_count : 8; // '8' is for backward compatibility with esp_tinyusb v1.0.0. Do NOT remove! } else { - string_descriptor = descriptor_str_kconfig; + pstr_desc = descriptor_str_kconfig; while (descriptor_str_kconfig[++s_desc_cfg->str_count] != NULL); ESP_LOGW(TAG, "The device's string descriptor is not provided by user, using default."); } - assert(s_desc_cfg->str_count <= USB_STRING_DESCRIPTOR_ARRAY_SIZE); - memcpy(s_desc_cfg->str, string_descriptor, s_desc_cfg->str_count * sizeof(string_descriptor[0])); + ESP_GOTO_ON_FALSE(s_desc_cfg->str_count <= USB_STRING_DESCRIPTOR_ARRAY_SIZE, ESP_ERR_NOT_SUPPORTED, fail, TAG, "String descriptors exceed limit"); + memcpy(s_desc_cfg->str, pstr_desc, s_desc_cfg->str_count * sizeof(pstr_desc[0])); ESP_LOGI(TAG, "\n" "┌─────────────────────────────────┐\n" @@ -207,7 +277,12 @@ esp_err_t tinyusb_set_descriptors(const tinyusb_config_t *config) s_desc_cfg->dev->idVendor, s_desc_cfg->dev->idProduct, s_desc_cfg->dev->bcdDevice, s_desc_cfg->dev->iManufacturer, s_desc_cfg->dev->iProduct, s_desc_cfg->dev->iSerialNumber, s_desc_cfg->dev->bNumConfigurations); + return ESP_OK; + +fail: + free(s_desc_cfg); + return ret; } void tinyusb_set_str_descriptor(const char *str, int str_idx) @@ -220,5 +295,12 @@ void tinyusb_set_str_descriptor(const char *str, int str_idx) void tinyusb_free_desctiptors(void) { assert(s_desc_cfg); +#if (TUD_OPT_HIGH_SPEED) + assert(s_desc_cfg->other_speed); + free(s_desc_cfg->other_speed); + if (s_desc_cfg->qualifier_alloc_internally) { + free(s_desc_cfg->qualifier); + } +#endif // TUD_OPT_HIGH_SPEED free(s_desc_cfg); } diff --git a/device/esp_tinyusb/include/tinyusb.h b/device/esp_tinyusb/include/tinyusb.h index 01f19516..8fe07016 100644 --- a/device/esp_tinyusb/include/tinyusb.h +++ b/device/esp_tinyusb/include/tinyusb.h @@ -34,12 +34,14 @@ typedef struct { union { struct { const uint8_t *configuration_descriptor; /*!< Pointer to a configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */ - const uint8_t *reserved; /*!< For backward compatibility */ + const uint8_t *reserved1; /*!< For backward compatibility */ + const uint8_t *reserved2; /*!< For backward compatibility */ }; #if (TUD_OPT_HIGH_SPEED) struct { const uint8_t *hs_cfg_desc; /*!< Pointer to a HS configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */ const uint8_t *fs_cfg_desc; /*!< Pointer to a FS configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */ + tusb_desc_device_qualifier_t *qualifier_desc; /*!< Pointer to a qualifier descriptor */ }; #endif // TUD_OPT_HIGH_SPEED }; diff --git a/device/esp_tinyusb/include_private/descriptors_control.h b/device/esp_tinyusb/include_private/descriptors_control.h index 92a7bfb0..5f474c6c 100644 --- a/device/esp_tinyusb/include_private/descriptors_control.h +++ b/device/esp_tinyusb/include_private/descriptors_control.h @@ -21,9 +21,15 @@ extern "C" { */ typedef struct { const tusb_desc_device_t *dev; /*!< Pointer to device descriptor */ - const uint8_t *cfg; /*!< Pointer to HS configuration descriptor */ + union { + const uint8_t *cfg; /*!< Pointer to FS configuration descriptor when device one-speed only */ + const uint8_t *hs_cfg; /*!< Pointer to HS configuration descriptor when device one-speed only */ + }; #if (TUD_OPT_HIGH_SPEED) - const uint8_t *fs_cfg; /*!< Pointer to FS configuration descriptor */ + const uint8_t *fs_cfg; /*!< Pointer to FS configuration descriptor when device support HS */ + tusb_desc_device_qualifier_t *qualifier; /*!< Pointer to Qualifier descriptor */ + bool qualifier_alloc_internally; /*!< Qualifier descriptor was allocated internally */ + uint8_t *other_speed; /*!< Pointer for other speed configuration descriptor */ #endif // TUD_OPT_HIGH_SPEED const char *str[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; /*!< Pointer to array of UTF-8 strings */ int str_count; /*!< Number of descriptors in str */ diff --git a/device/esp_tinyusb/test/CMakeLists.txt b/device/esp_tinyusb/test/CMakeLists.txt index fc89d7e0..00435e85 100644 --- a/device/esp_tinyusb/test/CMakeLists.txt +++ b/device/esp_tinyusb/test/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "test_esp_tinyusb.c" +idf_component_register(SRCS "test_esp_tinyusb.c" "test_bvalid_sig.c" INCLUDE_DIRS "." REQUIRES unity esp_tinyusb ) diff --git a/device/esp_tinyusb/test/test_bvalid_sig.c b/device/esp_tinyusb/test/test_bvalid_sig.c index 2ecfaad5..7be595f6 100644 --- a/device/esp_tinyusb/test/test_bvalid_sig.c +++ b/device/esp_tinyusb/test/test_bvalid_sig.c @@ -37,11 +37,7 @@ static uint8_t const test_configuration_descriptor[] = { TUD_CONFIG_DESCRIPTOR(1, 0, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), }; -<<<<<<< HEAD static const tusb_desc_device_t test_device_descriptor = { -======= -static tusb_desc_device_t test_device_descriptor = { ->>>>>>> 288fb6e (ref(esp_tinyusb): Update CHANGELOG.md) .bLength = sizeof(test_device_descriptor), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = 0x0200, @@ -92,13 +88,8 @@ TEST_CASE("bvalid_signal", "[esp_tinyusb]") } // Verify -<<<<<<< HEAD TEST_ASSERT_EQUAL(dev_umounted, dev_mounted); TEST_ASSERT_EQUAL(DEVICE_DETACH_TEST_ROUNDS, dev_mounted); -======= - TEST_ASSERT_EQUAL(dev_mounted, dev_umounted); - TEST_ASSERT_EQUAL(dev_mounted, DEVICE_DETACH_TEST_ROUNDS); ->>>>>>> 288fb6e (ref(esp_tinyusb): Update CHANGELOG.md) tinyusb_driver_uninstall(); }