Просмотр исходного кода

Merge branch 'master' into dcd_same70

HiFiPhile 4 лет назад
Родитель
Сommit
b194aa240b
100 измененных файлов с 1984 добавлено и 856 удалено
  1. 0 35
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 74 0
      .github/ISSUE_TEMPLATE/bug_report.yml
  3. 1 1
      .github/workflows/build.yml
  4. 2 2
      .github/workflows/build_esp.yml
  5. 1 1
      .github/workflows/build_renesas.yml
  6. 3 2
      README.md
  7. 3 1
      docs/boards.md
  8. 1 1
      examples/device/CMakeLists.txt
  9. 1 1
      examples/device/audio_4_channel_mic/CMakeLists.txt
  10. 1 1
      examples/device/audio_test/CMakeLists.txt
  11. 1 2
      examples/device/board_test/CMakeLists.txt
  12. 1 1
      examples/device/cdc_dual_ports/CMakeLists.txt
  13. 1 1
      examples/device/cdc_msc/CMakeLists.txt
  14. 11 9
      examples/device/cdc_msc_freertos/CMakeLists.txt
  15. 1 1
      examples/device/cdc_msc_freertos/src/freertos_hook.c
  16. 1 1
      examples/device/dfu/CMakeLists.txt
  17. 1 1
      examples/device/dfu_runtime/CMakeLists.txt
  18. 1 1
      examples/device/dynamic_configuration/CMakeLists.txt
  19. 1 1
      examples/device/hid_composite/CMakeLists.txt
  20. 27 5
      examples/device/hid_composite/src/main.c
  21. 1 1
      examples/device/hid_composite_freertos/src/freertos_hook.c
  22. 24 5
      examples/device/hid_composite_freertos/src/main.c
  23. 1 1
      examples/device/hid_generic_inout/CMakeLists.txt
  24. 1 1
      examples/device/hid_multiple_interface/CMakeLists.txt
  25. 1 1
      examples/device/midi_test/CMakeLists.txt
  26. 1 1
      examples/device/msc_dual_lun/CMakeLists.txt
  27. 1 1
      examples/device/net_lwip_webserver/CMakeLists.txt
  28. 0 0
      examples/device/uac2_headset/.skip.MCU_LPC11UXX
  29. 0 0
      examples/device/uac2_headset/.skip.MCU_LPC13XX
  30. 0 0
      examples/device/uac2_headset/.skip.MCU_NUC121
  31. 1 1
      examples/device/uac2_headset/CMakeLists.txt
  32. 96 55
      examples/device/uac2_headset/src/main.c
  33. 32 16
      examples/device/uac2_headset/src/tusb_config.h
  34. 1 1
      examples/device/uac2_headset/src/usb_descriptors.c
  35. 47 12
      examples/device/uac2_headset/src/usb_descriptors.h
  36. 1 1
      examples/device/usbtmc/CMakeLists.txt
  37. 1 1
      examples/device/webusb_serial/CMakeLists.txt
  38. 1 1
      examples/host/CMakeLists.txt
  39. 1 1
      examples/host/cdc_msc_hid/CMakeLists.txt
  40. 105 61
      examples/host/cdc_msc_hid/src/hid_app.c
  41. 2 2
      examples/host/cdc_msc_hid/src/tusb_config.h
  42. 54 5
      hw/bsp/board.c
  43. 7 2
      hw/bsp/board.h
  44. 2 2
      hw/bsp/board_mcu.h
  45. 0 3
      hw/bsp/esp32s2/family.cmake
  46. 0 3
      hw/bsp/esp32s3/family.cmake
  47. 0 57
      hw/bsp/family_common.cmake
  48. 71 0
      hw/bsp/family_support.cmake
  49. 2 2
      hw/bsp/rp2040/family.cmake
  50. 24 0
      hw/bsp/rx/boards/gr_citrus/board.mk
  51. 35 15
      hw/bsp/rx/boards/gr_citrus/gr_citrus.c
  52. 0 0
      hw/bsp/rx/boards/gr_citrus/hwinit.c
  53. 2 2
      hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld
  54. 25 0
      hw/bsp/rx/boards/rx65n_target/board.mk
  55. 168 0
      hw/bsp/rx/boards/rx65n_target/r5f565ne.ld
  56. 320 0
      hw/bsp/rx/boards/rx65n_target/rx65n_target.c
  57. 32 0
      hw/bsp/rx/family.mk
  58. 0 61
      hw/bsp/rx63n/boards/gr_citrus/board.mk
  59. 0 1
      hw/bsp/rx63n/family.mk
  60. 0 50
      hw/bsp/saml22/family.mk
  61. 50 0
      hw/bsp/saml2x/boards/atsaml21_xpro/board.h
  62. 12 0
      hw/bsp/saml2x/boards/atsaml21_xpro/board.mk
  63. 153 0
      hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld
  64. 0 0
      hw/bsp/saml2x/boards/saml22_feather/board.h
  65. 2 0
      hw/bsp/saml2x/boards/saml22_feather/board.mk
  66. 0 0
      hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld
  67. 0 0
      hw/bsp/saml2x/boards/sensorwatch_m0/board.h
  68. 2 0
      hw/bsp/saml2x/boards/sensorwatch_m0/board.mk
  69. 0 0
      hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld
  70. 8 8
      hw/bsp/saml2x/family.c
  71. 48 0
      hw/bsp/saml2x/family.mk
  72. 1 1
      hw/mcu/microchip
  73. 1 1
      hw/mcu/renesas/rx
  74. 28 1
      src/class/audio/audio.h
  75. 210 184
      src/class/audio/audio_device.c
  76. 4 6
      src/class/cdc/cdc_device.c
  77. 30 32
      src/class/cdc/cdc_host.c
  78. 5 5
      src/class/cdc/cdc_host.h
  79. 3 1
      src/class/dfu/dfu_device.c
  80. 26 2
      src/class/hid/hid_device.c
  81. 38 37
      src/class/hid/hid_host.c
  82. 9 8
      src/class/hid/hid_host.h
  83. 16 20
      src/class/midi/midi_device.c
  84. 12 8
      src/class/msc/msc_device.c
  85. 8 5
      src/class/msc/msc_host.c
  86. 5 15
      src/class/msc/msc_host.h
  87. 16 8
      src/common/tusb_common.h
  88. 12 4
      src/common/tusb_compiler.h
  89. 2 2
      src/common/tusb_fifo.c
  90. 2 2
      src/common/tusb_fifo.h
  91. 1 1
      src/common/tusb_verify.h
  92. 2 3
      src/device/usbd.c
  93. 5 0
      src/device/usbd.h
  94. 1 0
      src/device/usbd_control.c
  95. 17 14
      src/host/hub.c
  96. 5 5
      src/host/hub.h
  97. 47 39
      src/host/usbh.c
  98. 5 5
      src/host/usbh_classdriver.h
  99. 3 3
      src/host/usbh_control.c
  100. 2 2
      src/portable/microchip/samd/dcd_samd.c

+ 0 - 35
.github/ISSUE_TEMPLATE/bug_report.md

@@ -1,35 +0,0 @@
----
-name: Bug Report
-about: Create a report to help us improve
-title: 'Please provide all details at least for Setup/Describe/Reproduce'
-labels: Bug 🐞
-assignees: ''
-
----
-
-**Set Up**
-
-- **PC OS** e.g Ubuntu 20.04 / Windows 10 / macOS 10.15
-- **Board** e.g Feather nRF52840 Express (if custom specify your MCUs)
-- **TinyUSB version** relase version or git hash (preferrably running with master for lastest code) 
-- **Firmware** e.g examples/device/cdc_msc
-
-**Describe The Bug**
-
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. See error
-
-**Screenshots**
-
-If applicable, add screenshots, bus capture to help explain your problem. 
-
-**Log**
-
-If applicable, provide the stack's log (uart/rtt/swo) where the issue occurred as attached txt file, best with comments to explain the actual events.
-Note: To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. More information can be found at [example's readme](/docs/getting_started.md)

+ 74 - 0
.github/ISSUE_TEMPLATE/bug_report.yml

@@ -0,0 +1,74 @@
+name: Bug Report
+description: Report a problem with TinyUSB
+labels: 'Bug 🐞'
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thanks for taking the time to fill out this bug report!
+        It's okay to leave some blank if it doesn't apply to your problem.
+
+  - type: dropdown
+    attributes:
+      label: Operating System
+      options:
+              - Linux
+              - MacOS
+              - RaspberryPi OS
+              - Windows 7
+              - Windows 10
+              - Windows 11
+              - Others
+    validations:
+      required: true
+
+  - type: input
+    attributes:
+      label: Board
+      placeholder: e.g Feather nRF52840 Express
+    validations:
+      required: true
+
+  - type: textarea
+    attributes:
+      label: Firmware
+      placeholder: |
+        e.g examples/device/cdc_msc.
+        If it is custom firmware, please provide links to your minimal sources or as attached files.
+    validations:
+      required: true
+
+  - type: textarea
+    attributes:
+      label: What happened ?
+      placeholder: A clear and concise description of what the bug is.
+    validations:
+      required: true
+
+  - type: textarea
+    attributes:
+      label: How to reproduce ?
+      placeholder: |
+        1. Go to '...'
+        2. Click on '....'
+        3. See error      
+    validations:
+      required: true
+
+  - type: textarea
+    attributes:
+      label: Debug Log
+      placeholder: |
+        TinyUSB debug log where the issue occurred as attached txt file, best with comments to explain the actual events.
+
+        Note: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h. 
+        More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md)
+    validations:
+      required: false
+
+  - type: textarea
+    attributes:
+      label: Screenshots
+      description: If applicable, add screenshots to help explain your problem.
+    validations:
+      required: false

+ 1 - 1
.github/workflows/build.yml

@@ -49,7 +49,7 @@ jobs:
         - 'samd11'
         - 'samd21'
         - 'samd51'
-        - 'saml22'
+        - 'saml2x'
         - 'stm32f0'
         - 'stm32f4'
         - 'stm32f7'

+ 2 - 2
.github/workflows/build_esp.yml

@@ -16,10 +16,10 @@ jobs:
         board:
         # Alphabetical order
         # ESP32-S2
-        - 'adafruit_metro_esp32s2'
         - 'espressif_saola_1'
         # ESP32-S3
-        - 'espressif_addax_1'
+        # latest IDF does not define USB0 in linker
+        #- 'espressif_addax_1'
 
     steps:
     - name: Setup Python

+ 1 - 1
.github/workflows/build_renesas.yml

@@ -15,7 +15,7 @@ jobs:
       matrix:
         family:
         # Alphabetical order
-        - 'rx63n'
+        - 'rx'
     steps:
     - name: Setup Python
       uses: actions/setup-python@v2

+ 3 - 2
README.md

@@ -32,7 +32,7 @@ The stack supports the following MCUs:
 
 - **Dialog:** DA1469x
 - **Espressif:** ESP32-S2, ESP32-S3
-- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55
+- **MicroChip:** SAMD11, SAMD21, SAMD51, SAME5x, SAMG55, SAML21, SAML22
 - **NordicSemi:** nRF52833, nRF52840
 - **Nuvoton:** NUC120, NUC121/NUC125, NUC126, NUC505
 - **NXP:**
@@ -40,7 +40,7 @@ The stack supports the following MCUs:
   - Kinetis: KL25
   - LPC Series: 11u, 13, 15, 17, 18, 40, 43, 51u, 54, 55
 - **Raspberry Pi:** RP2040
-- **Renesas:** RX63N
+- **Renesas:** RX63N, RX65N
 - **Silabs:** EFM32GG12
 - **Sony:** CXD56
 - **ST:** STM32 series: L0, F0, F1, F2, F3, F4, F7, H7 both FullSpeed and HighSpeed
@@ -106,6 +106,7 @@ TinyUSB is currently used by these other projects:
 - [Espressif IDF](https://github.com/espressif/esp-idf)
 - [MicroPython](https://github.com/micropython/micropython)
 - [mynewt](https://mynewt.apache.org)
+- [openinput](https://github.com/openinput-fw/openinput)
 - [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk)
 - [TinyUF2 Bootloader](https://github.com/adafruit/tinyuf2)
 - [TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino)

+ 3 - 1
docs/boards.md

@@ -47,8 +47,9 @@ This code base already had supported for a handful of following boards (sorted a
 
 - [Microchip SAMG55 Xplained Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/PartNO/ATSAMG55-XPRO)
 
-### MicroChip SAML22
+### MicroChip SAML2x
 
+- [SAML21 Xplaind Pro](https://www.microchip.com/DevelopmentTools/ProductDetails/ATSAML21-XPRO-B)
 - [SAML22 Feather](https://github.com/joeycastillo/Feather-Projects/tree/main/SAML22%20Feather)
 - [Sensor Watch](https://github.com/joeycastillo/Sensor-Watch)
 
@@ -126,6 +127,7 @@ This code base already had supported for a handful of following boards (sorted a
 ### Renesas RX
 
 - [GR-CITRUS](https://www.renesas.com/us/en/products/gadget-renesas/boards/gr-citrus)
+- [Renesas RX65N Target Board](https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/rtk5rx65n0c00000br-target-board-rx65n)
 
 ### Raspberry Pi RP2040
 

+ 1 - 1
examples/device/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
 
 project(tinyusb_device_examples)
 family_initialize_project(tinyusb_device_examples ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/audio_4_channel_mic/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/audio_test/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 2
examples/device/board_test/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # Check for -DFAMILY=
 if(FAMILY MATCHES "^esp32s[2-3]")
@@ -12,7 +12,6 @@ if(FAMILY MATCHES "^esp32s[2-3]")
   set(TOP "../../..")
   get_filename_component(TOP "${TOP}" REALPATH)
 
-  include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
   project(${PROJECT})
 
 else()

+ 1 - 1
examples/device/cdc_dual_ports/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/cdc_msc/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 11 - 9
examples/device/cdc_msc_freertos/CMakeLists.txt

@@ -1,20 +1,22 @@
 cmake_minimum_required(VERSION 3.5)
 
-# use BOARD-Directory name for project id
-get_filename_component(PROJECT ${CMAKE_CURRENT_SOURCE_DIR} NAME)
-set(PROJECT ${BOARD}-${PROJECT})
-
 # TOP is absolute path to root directory of TinyUSB git repo
+# needed for esp32sx build. TOOD could be removed later on
 set(TOP "../../..")
 get_filename_component(TOP "${TOP}" REALPATH)
 
-# Check for -DFAMILY=
-if(FAMILY MATCHES "^esp32s[2-3]")
-  cmake_minimum_required(VERSION 3.5)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
 
-  include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
-  project(${PROJECT})
+project(${PROJECT})
 
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+# Check for -DFAMILY=
+if(FAMILY MATCHES "^esp32s[2-3]")
 else()
   message(FATAL_ERROR "Invalid FAMILY specified: ${FAMILY}")
 endif()

+ 1 - 1
examples/device/cdc_msc_freertos/src/freertos_hook.c

@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
   *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
 }
 
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
 #include "iodefine.h"
 void vApplicationSetupTimerInterrupt(void)
 {

+ 1 - 1
examples/device/dfu/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/dfu_runtime/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/dynamic_configuration/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/hid_composite/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 27 - 5
examples/device/hid_composite/src/main.c

@@ -255,12 +255,31 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
 // received data on OUT endpoint ( Report ID = 0, Type = 0 )
 void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
 {
-  // TODO set LED based on CAPLOCK, NUMLOCK etc...
   (void) itf;
-  (void) report_id;
-  (void) report_type;
-  (void) buffer;
-  (void) bufsize;
+
+  if (report_type == HID_REPORT_TYPE_OUTPUT)
+  {
+    // Set keyboard LED e.g Capslock, Numlock etc...
+    if (report_id == REPORT_ID_KEYBOARD)
+    {
+      // bufsize should be (at least) 1
+      if ( bufsize < 1 ) return;
+
+      uint8_t const kbd_leds = buffer[0];
+
+      if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+      {
+        // Capslock On: disable blink, turn led on
+        blink_interval_ms = 0;
+        board_led_write(true);
+      }else
+      {
+        // Caplocks Off: back to normal blink
+        board_led_write(false);
+        blink_interval_ms = BLINK_MOUNTED;
+      }
+    }
+  }
 }
 
 //--------------------------------------------------------------------+
@@ -271,6 +290,9 @@ void led_blinking_task(void)
   static uint32_t start_ms = 0;
   static bool led_state = false;
 
+  // blink is disabled
+  if (!blink_interval_ms) return;
+
   // Blink every interval ms
   if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
   start_ms += blink_interval_ms;

+ 1 - 1
examples/device/hid_composite_freertos/src/freertos_hook.c

@@ -94,7 +94,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, Stack
   *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
 }
 
-#if CFG_TUSB_MCU == OPT_MCU_RX63X
+#if CFG_TUSB_MCU == OPT_MCU_RX63X | CFG_TUSB_MCU == OPT_MCU_RX65X
 #include "iodefine.h"
 void vApplicationSetupTimerInterrupt(void)
 {

+ 24 - 5
examples/device/hid_composite_freertos/src/main.c

@@ -315,12 +315,31 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
 // received data on OUT endpoint ( Report ID = 0, Type = 0 )
 void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
 {
-  // TODO set LED based on CAPLOCK, NUMLOCK etc...
   (void) itf;
-  (void) report_id;
-  (void) report_type;
-  (void) buffer;
-  (void) bufsize;
+
+  if (report_type == HID_REPORT_TYPE_OUTPUT)
+  {
+    // Set keyboard LED e.g Capslock, Numlock etc...
+    if (report_id == REPORT_ID_KEYBOARD)
+    {
+      // bufsize should be (at least) 1
+      if ( bufsize < 1 ) return;
+
+      uint8_t const kbd_leds = buffer[0];
+
+      if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
+      {
+        // Capslock On: disable blink, turn led on
+        xTimerStop(blinky_tm, portMAX_DELAY);
+        board_led_write(true);
+      }else
+      {
+        // Caplocks Off: back to normal blink
+        board_led_write(false);
+        xTimerStart(blinky_tm, portMAX_DELAY);
+      }
+    }
+  }
 }
 
 //--------------------------------------------------------------------+

+ 1 - 1
examples/device/hid_generic_inout/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/hid_multiple_interface/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/midi_test/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/msc_dual_lun/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/net_lwip_webserver/CMakeLists.txt

@@ -4,7 +4,7 @@ set(TOP "../../..")
 get_filename_component(TOP "${TOP}" REALPATH)
 
 if (EXISTS ${TOP}/lib/lwip/src)
-    include(${TOP}/hw/bsp/${FAMILY}/family.cmake)
+    include(${TOP}/hw/bsp/family_support.cmake)
 
     # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
     family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 0 - 0
examples/device/uac2_headset/.skip.MCU_LPC11UXX


+ 0 - 0
examples/device/uac2_headset/.skip.MCU_LPC13XX


+ 0 - 0
examples/device/uac2_headset/.skip.MCU_NUC121


+ 1 - 1
examples/device/uac2_headset/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 96 - 55
examples/device/uac2_headset/src/main.c

@@ -34,9 +34,11 @@
 // MACRO CONSTANT TYPEDEF PROTOTYPES
 //--------------------------------------------------------------------+
 
-#ifndef AUDIO_SAMPLE_RATE
-#define AUDIO_SAMPLE_RATE     48000
-#endif
+// List of supported sample rates
+const uint32_t sample_rates[]       = {44100, 48000, 88200, 96000};
+uint32_t       current_sample_rate  = 44100;
+
+#define N_SAMPLE_RATES  TU_ARRAY_SIZE(sample_rates)
 
 /* Blink pattern
  * - 25 ms   : streaming data
@@ -76,11 +78,16 @@ int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];       // +1 for master chan
 int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];    // +1 for master channel 0
 
 // Buffer for microphone data
-int16_t mic_buf[1000];
+int32_t mic_buf[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ / 4];
 // Buffer for speaker data
-int16_t spk_buf[1000];
+int32_t spk_buf[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ / 4];
 // Speaker data size received in the last frame
 int spk_data_size;
+// Resolution per format
+const uint8_t resolutions_per_format[CFG_TUD_AUDIO_FUNC_1_N_FORMATS] = {CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX,
+                                                                        CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX};
+// Current resolution, update on format change
+uint8_t current_resolution;
 
 void led_blinking_task(void);
 void audio_task(void);
@@ -135,55 +142,35 @@ void tud_resume_cb(void)
   blink_interval_ms = BLINK_MOUNTED;
 }
 
-typedef struct TU_ATTR_PACKED
-{
-  union
-  {
-    struct TU_ATTR_PACKED
-    {
-      uint8_t recipient :  5; ///< Recipient type tusb_request_recipient_t.
-      uint8_t type      :  2; ///< Request type tusb_request_type_t.
-      uint8_t direction :  1; ///< Direction type. tusb_dir_t
-    } bmRequestType_bit;
-
-    uint8_t bmRequestType;
-  };
-
-  uint8_t bRequest;  ///< Request type audio_cs_req_t
-  uint8_t bChannelNumber;
-  uint8_t bControlSelector;
-  union
-  {
-    uint8_t bInterface;
-    uint8_t bEndpoint;
-  };
-  uint8_t bEntityID;
-  uint16_t wLength;
-} audio_control_request_t;
-
 // Helper for clock get requests
 static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request)
 {
   TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
 
-  // Example supports only single frequency, same value will be used for current value and range
   if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
   {
     if (request->bRequest == AUDIO_CS_REQ_CUR)
     {
-      TU_LOG2("Clock get current freq %u\r\n", AUDIO_SAMPLE_RATE);
+      TU_LOG1("Clock get current freq %u\r\n", current_sample_rate);
 
-      audio_control_cur_4_t curf = { tu_htole32(AUDIO_SAMPLE_RATE) };
+      audio_control_cur_4_t curf = { tu_htole32(current_sample_rate) };
       return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf));
     }
     else if (request->bRequest == AUDIO_CS_REQ_RANGE)
     {
-      audio_control_range_4_n_t(1) rangef =
+      audio_control_range_4_n_t(N_SAMPLE_RATES) rangef =
       {
-        .wNumSubRanges = tu_htole16(1),
-        .subrange[0] = { tu_htole32(AUDIO_SAMPLE_RATE), tu_htole32(AUDIO_SAMPLE_RATE), 0}
+        .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)
       };
-      TU_LOG2("Clock get freq range (%d, %d, %d)\r\n", (int)rangef.subrange[0].bMin, (int)rangef.subrange[0].bMax, (int)rangef.subrange[0].bRes);
+      TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES);
+      for(uint8_t i = 0; i < N_SAMPLE_RATES; i++)
+      {
+        rangef.subrange[i].bMin = sample_rates[i];
+        rangef.subrange[i].bMax = sample_rates[i];
+        rangef.subrange[i].bRes = 0;
+        TU_LOG1("Range %d (%d, %d, %d)\r\n", i, (int)rangef.subrange[i].bMin, (int)rangef.subrange[i].bMax, (int)rangef.subrange[i].bRes);
+      }
+      
       return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef));
     }
   }
@@ -191,7 +178,7 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
            request->bRequest == AUDIO_CS_REQ_CUR)
   {
     audio_control_cur_1_t cur_valid = { .bCur = 1 };
-    TU_LOG2("Clock get is valid %u\r\n", cur_valid.bCur);
+    TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur);
     return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_valid, sizeof(cur_valid));
   }
   TU_LOG1("Clock get request not supported, entity = %u, selector = %u, request = %u\r\n",
@@ -199,6 +186,32 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t
   return false;
 }
 
+// Helper for clock set requests
+static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf)
+{
+  (void)rhport;
+
+  TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
+  TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR);
+
+  if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ)
+  {
+    TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t));
+
+    current_sample_rate = ((audio_control_cur_4_t *)buf)->bCur;
+
+    TU_LOG1("Clock set current freq: %d\r\n", current_sample_rate);
+
+    return true;
+  }
+  else
+  {
+    TU_LOG1("Clock set request not supported, entity = %u, selector = %u, request = %u\r\n",
+            request->bEntityID, request->bControlSelector, request->bRequest);
+    return false;
+  }
+}
+
 // Helper for feature unit get requests
 static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request)
 {
@@ -207,7 +220,7 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
   if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR)
   {
     audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] };
-    TU_LOG2("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
+    TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur);
     return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1));
   }
   else if (UAC2_ENTITY_SPK_FEATURE_UNIT && request->bControlSelector == AUDIO_FU_CTRL_VOLUME)
@@ -218,14 +231,14 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req
         .wNumSubRanges = tu_htole16(1),
         .subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) }
       };
-      TU_LOG2("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
+      TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber,
               range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256);
       return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &range_vol, sizeof(range_vol));
     }
     else if (request->bRequest == AUDIO_CS_REQ_CUR)
     {
       audio_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) };
-      TU_LOG2("Get channel %u volume %u dB\r\n", request->bChannelNumber, cur_vol.bCur);
+      TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256);
       return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_vol, sizeof(cur_vol));
     }
   }
@@ -249,7 +262,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
 
     mute[request->bChannelNumber] = ((audio_control_cur_1_t *)buf)->bCur;
 
-    TU_LOG2("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
+    TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]);
 
     return true;
   }
@@ -259,7 +272,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req
 
     volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur;
 
-    TU_LOG2("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
+    TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256);
 
     return true;
   }
@@ -299,7 +312,8 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p
 
   if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT)
     return tud_audio_feature_unit_set_request(rhport, request, buf);
-
+  if (request->bEntityID == UAC2_ENTITY_CLOCK)
+    return tud_audio_clock_set_request(rhport, request, buf);
   TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n",
           request->bEntityID, request->bControlSelector, request->bRequest);
 
@@ -329,6 +343,13 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_reque
   if (ITF_NUM_AUDIO_STREAMING_SPK == itf && alt != 0)
       blink_interval_ms = BLINK_STREAMING;
 
+  // Clear buffer when streaming format is changed
+  spk_data_size = 0;
+  if(alt != 0)
+  {
+    current_resolution = resolutions_per_format[alt-1];
+  }
+
   return true;
 }
 
@@ -362,20 +383,40 @@ void audio_task(void)
 {
   // When new data arrived, copy data from speaker buffer, to microphone buffer
   // and send it over
+  // Only support speaker & headphone both have the same resolution
+  // If one is 16bit another is 24bit be care of LOUD noise !
   if (spk_data_size)
   {
-    int16_t *src = spk_buf;
-    int16_t *limit = spk_buf + spk_data_size / 2;
-    int16_t *dst = mic_buf;
-    while (src < limit)
+    if (current_resolution == 16)
     {
-      // Combine two channels into one
-      int32_t left = *src++;
-      int32_t right = *src++;
-      *dst++ = (int16_t)((left + right) / 2);
+      int16_t *src = (int16_t*)spk_buf;
+      int16_t *limit = (int16_t*)spk_buf + spk_data_size / 2;
+      int16_t *dst = (int16_t*)mic_buf;
+      while (src < limit)
+      {
+        // Combine two channels into one
+        int32_t left = *src++;
+        int32_t right = *src++;
+        *dst++ = (left >> 1) + (right >> 1);
+      }
+      tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+      spk_data_size = 0;
+    }
+    else if (current_resolution == 24)
+    {
+      int32_t *src = spk_buf;
+      int32_t *limit = spk_buf + spk_data_size / 4;
+      int32_t *dst = mic_buf;
+      while (src < limit)
+      {
+        // Combine two channels into one
+        int32_t left = *src++;
+        int32_t right = *src++;
+        *dst++ = ((left >> 1) + (right >> 1)) & 0xffffff00;
+      }
+      tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
+      spk_data_size = 0;
     }
-    tud_audio_write((uint8_t *)mic_buf, spk_data_size / 2);
-    spk_data_size = 0;
   }
 }
 

+ 32 - 16
examples/device/uac2_headset/src/tusb_config.h

@@ -93,33 +93,49 @@ extern "C" {
 //--------------------------------------------------------------------
 // AUDIO CLASS DRIVER CONFIGURATION
 //--------------------------------------------------------------------
-#define CFG_TUD_AUDIO_IN_PATH                     (CFG_TUD_AUDIO)
-#define CFG_TUD_AUDIO_OUT_PATH                    (CFG_TUD_AUDIO)
 
-//#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                       220       // This equals TUD_AUDIO_HEADSET_STEREO_DESC_LEN, however, including it from usb_descriptors.h is not possible due to some strange include hassle
-#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                       TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                                TUD_AUDIO_HEADSET_STEREO_DESC_LEN
+
+// How many formats are used, need to adjust USB descriptor if changed
+#define CFG_TUD_AUDIO_FUNC_1_N_FORMATS                               2
 
 // Audio format type I specifications
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX                  1
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX          2
-#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX                  2
-#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX          2
-#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP                    0
+#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE                         96000     // 24bit/96kHz is the best quality for full-speed, high-speed is needed beyond this
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX                           1
+#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX                           2
+
+// 16bit in 16bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX          2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX                  16
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX          2
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX                  16
+
+// 24bit in 32bit slots
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX          4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX                  24
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX          4
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX                  24
 
 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
 #define CFG_TUD_AUDIO_ENABLE_EP_IN                1
-#define CFG_TUD_AUDIO_EP_SZ_IN                    (CFG_TUD_AUDIO_IN_PATH * (48 + 1) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)) // 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ      CFG_TUD_AUDIO_EP_SZ_IN
-#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX         CFG_TUD_AUDIO_EP_SZ_IN                  // Maximum EP IN size for all AS alternate settings used
+
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN    TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN    TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ      TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN)*2
+#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX         TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used
 
 // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
 #define CFG_TUD_AUDIO_ENABLE_EP_OUT               1
-#define CFG_TUD_AUDIO_EP_OUT_SZ                   (CFG_TUD_AUDIO_OUT_PATH * ((48 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * (CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX) * (CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX))) // N Samples (N kHz) x 2 Bytes/Sample x n Channels
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ     CFG_TUD_AUDIO_EP_OUT_SZ*3
-#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX        CFG_TUD_AUDIO_EP_OUT_SZ                 // Maximum EP IN size for all AS alternate settings used
+
+#define CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT    TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+#define CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT    TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX)
+
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ     TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT)*2
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX        TU_MAX(CFG_TUD_AUDIO_UNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_UNC_1_FORMAT_2_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used
 
 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
-#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 	          1
+#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 	          2
 
 // Size of control request buffer
 #define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ	64

+ 1 - 1
examples/device/uac2_headset/src/usb_descriptors.c

@@ -93,7 +93,7 @@ uint8_t const desc_configuration[] =
     TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
     // Interface number, string index, EP Out & EP In address, EP size
-    TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, 2, 16, EPNUM_AUDIO, CFG_TUD_AUDIO_EP_OUT_SZ, EPNUM_AUDIO | 0x80, CFG_TUD_AUDIO_EP_SZ_IN)
+    TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO, EPNUM_AUDIO | 0x80)
 };
 
 // Invoked when received GET CONFIGURATION DESCRIPTOR

+ 47 - 12
examples/device/uac2_headset/src/usb_descriptors.h

@@ -55,21 +55,36 @@ enum
     + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
     + TUD_AUDIO_DESC_INPUT_TERM_LEN\
     + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\
+    /* Interface 1, Alternate 0 */\
     + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+    /* Interface 1, Alternate 0 */\
     + TUD_AUDIO_DESC_STD_AS_INT_LEN\
     + TUD_AUDIO_DESC_CS_AS_INT_LEN\
     + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
     + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
     + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+    /* Interface 1, Alternate 2 */\
     + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+    + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+    + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+    + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+    + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+    /* Interface 2, Alternate 0 */\
+    + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+    /* Interface 2, Alternate 1 */\
+    + TUD_AUDIO_DESC_STD_AS_INT_LEN\
+    + TUD_AUDIO_DESC_CS_AS_INT_LEN\
+    + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
+    + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
+    + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\
+    /* Interface 2, Alternate 2 */\
     + TUD_AUDIO_DESC_STD_AS_INT_LEN\
     + TUD_AUDIO_DESC_CS_AS_INT_LEN\
     + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\
     + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\
     + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
 
-
-#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epin, _epinsize) \
+#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
     /* Standard Interface Association Descriptor (IAD) */\
     TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\
     /* Standard AC Interface Descriptor(4.7.1) */\
@@ -77,13 +92,13 @@ enum
     /* Class-Specific AC Interface Header Descriptor(4.7.2) */\
     TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\
     /* Clock Source Descriptor(4.7.2.1) */\
-    TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 5, /*_assocTerm*/ 0x00,  /*_stridx*/ 0x00),    \
+    TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00,  /*_stridx*/ 0x00),    \
     /* Input Terminal Descriptor(4.7.2.4) */\
     TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
     /* Feature Unit Descriptor(4.7.2.8) */\
     TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\
     /* Output Terminal Descriptor(4.7.2.5) */\
-    TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
+    TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\
     /* Input Terminal Descriptor(4.7.2.4) */\
     TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\
     /* Output Terminal Descriptor(4.7.2.5) */\
@@ -95,26 +110,46 @@ enum
     /* Interface 1, Alternate 1 - alternate interface for data streaming */\
     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
     /* Class-Specific AS Interface Descriptor(4.9.2) */\
-    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
     /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
-    TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
+    TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\
     /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
-    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
+    /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+    TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
+    /* Interface 1, Alternate 2 - alternate interface for data streaming */\
+    TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\
+    /* Class-Specific AS Interface Descriptor(4.9.2) */\
+    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+    /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+    TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\
+    /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\
     /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
     TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\
     /* Standard AS Interface Descriptor(4.9.1) */\
     /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\
     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\
     /* Standard AS Interface Descriptor(4.9.1) */\
-    /* Interface 1, Alternate 1 - alternate interface for data streaming */\
+    /* Interface 2, Alternate 1 - alternate interface for data streaming */\
     TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
     /* Class-Specific AS Interface Descriptor(4.9.2) */\
-    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
+    /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
+    TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\
+    /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
+    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
+    /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
+    TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\
+    /* Interface 2, Alternate 2 - alternate interface for data streaming */\
+    TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\
+    /* Class-Specific AS Interface Descriptor(4.9.2) */\
+    TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\
     /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
-    TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\
+    TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\
     /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
-    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epinsize, /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01),\
+    TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\
     /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
-    TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)\
+    TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
 
 #endif

+ 1 - 1
examples/device/usbtmc/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/device/webusb_serial/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/host/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake)
 
 project(tinyusb_host_examples)
 family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})

+ 1 - 1
examples/host/cdc_msc_hid/CMakeLists.txt

@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.5)
 
-include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/${FAMILY}/family.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
 
 # gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
 family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

+ 105 - 61
examples/host/cdc_msc_hid/src/hid_app.c

@@ -30,7 +30,8 @@
 // MACRO TYPEDEF CONSTANT ENUM DECLARATION
 //--------------------------------------------------------------------+
 
-// If your host terminal support ansi escape code, it can be use to simulate mouse cursor
+// If your host terminal support ansi escape code such as TeraTerm
+// it can be use to simulate mouse cursor movement within terminal
 #define USE_ANSI_ESCAPE   0
 
 #define MAX_REPORT  4
@@ -38,11 +39,15 @@
 static uint8_t const keycode2ascii[128][2] =  { HID_KEYCODE_TO_ASCII };
 
 // Each HID instance can has multiple reports
-static uint8_t _report_count[CFG_TUH_HID];
-static tuh_hid_report_info_t _report_info_arr[CFG_TUH_HID][MAX_REPORT];
+static struct
+{
+  uint8_t report_count;
+  tuh_hid_report_info_t report_info[MAX_REPORT];
+}hid_info[CFG_TUH_HID];
 
 static void process_kbd_report(hid_keyboard_report_t const *report);
 static void process_mouse_report(hid_mouse_report_t const * report);
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len);
 
 void hid_app_task(void)
 {
@@ -60,13 +65,19 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
 {
   printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
 
-  // Interface protocol
-  const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; // hid_protocol_type_t
-  uint8_t const interface_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+  // Interface protocol (hid_interface_protocol_enum_t)
+  const char* protocol_str[] = { "None", "Keyboard", "Mouse" };
+  uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
+
+  printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]);
 
-  // Parse report descriptor with built-in parser
-  _report_count[instance] = tuh_hid_parse_report_descriptor(_report_info_arr[instance], MAX_REPORT, desc_report, desc_len);
-  printf("HID has %u reports and interface protocol = %s\r\n", _report_count[instance], protocol_str[interface_protocol]);
+  // By default host stack will use activate boot protocol on supported interface.
+  // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser)
+  if ( itf_protocol == HID_ITF_PROTOCOL_NONE )
+  {
+    hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
+    printf("HID has %u reports \r\n", hid_info[instance].report_count);
+  }
 }
 
 // Invoked when device with hid interface is un-mounted
@@ -78,59 +89,24 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance)
 // Invoked when received report from device via interrupt endpoint
 void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
 {
-  (void) dev_addr;
-
-  uint8_t const rpt_count = _report_count[instance];
-  tuh_hid_report_info_t* rpt_info_arr = _report_info_arr[instance];
-  tuh_hid_report_info_t* rpt_info = NULL;
+  uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
 
-  if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
+  switch (itf_protocol)
   {
-    // Simple report without report ID as 1st byte
-    rpt_info = &rpt_info_arr[0];
-  }else
-  {
-    // Composite report, 1st byte is report ID, data starts from 2nd byte
-    uint8_t const rpt_id = report[0];
-
-    // Find report id in the arrray
-    for(uint8_t i=0; i<rpt_count; i++)
-    {
-      if (rpt_id == rpt_info_arr[i].report_id )
-      {
-        rpt_info = &rpt_info_arr[i];
-        break;
-      }
-    }
-
-    report++;
-    len--;
-  }
-
-  if (!rpt_info)
-  {
-    printf("Couldn't find the report info for this report !\r\n");
-    return;
-  }
-
-  if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
-  {
-    switch (rpt_info->usage)
-    {
-      case HID_USAGE_DESKTOP_KEYBOARD:
-        TU_LOG1("HID receive keyboard report\r\n");
-        // Assume keyboard follow boot report layout
-        process_kbd_report( (hid_keyboard_report_t const*) report );
-      break;
-
-      case HID_USAGE_DESKTOP_MOUSE:
-        TU_LOG1("HID receive mouse report\r\n");
-        // Assume mouse follow boot report layout
-        process_mouse_report( (hid_mouse_report_t const*) report );
-      break;
-
-      default: break;
-    }
+    case HID_ITF_PROTOCOL_KEYBOARD:
+      TU_LOG2("HID receive boot keyboard report\r\n");
+      process_kbd_report( (hid_keyboard_report_t const*) report );
+    break;
+
+    case HID_ITF_PROTOCOL_MOUSE:
+      TU_LOG2("HID receive boot mouse report\r\n");
+      process_mouse_report( (hid_mouse_report_t const*) report );
+    break;
+
+    default:
+      // Generic report requires matching ReportID and contents with previous parsed report info
+      process_generic_report(dev_addr, instance, report, len);
+    break;
   }
 }
 
@@ -164,7 +140,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report)
       }else
       {
         // not existed in previous report means the current key is pressed
-        bool const is_shift =  report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
+        bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT);
         uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0];
         putchar(ch);
         if ( ch == '\r' ) putchar('\n'); // added new line for enter key
@@ -235,3 +211,71 @@ static void process_mouse_report(hid_mouse_report_t const * report)
   //------------- cursor movement -------------//
   cursor_movement(report->x, report->y, report->wheel);
 }
+
+//--------------------------------------------------------------------+
+// Generic Report
+//--------------------------------------------------------------------+
+static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
+{
+  (void) dev_addr;
+
+  uint8_t const rpt_count = hid_info[instance].report_count;
+  tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info;
+  tuh_hid_report_info_t* rpt_info = NULL;
+
+  if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0)
+  {
+    // Simple report without report ID as 1st byte
+    rpt_info = &rpt_info_arr[0];
+  }else
+  {
+    // Composite report, 1st byte is report ID, data starts from 2nd byte
+    uint8_t const rpt_id = report[0];
+
+    // Find report id in the arrray
+    for(uint8_t i=0; i<rpt_count; i++)
+    {
+      if (rpt_id == rpt_info_arr[i].report_id )
+      {
+        rpt_info = &rpt_info_arr[i];
+        break;
+      }
+    }
+
+    report++;
+    len--;
+  }
+
+  if (!rpt_info)
+  {
+    printf("Couldn't find the report info for this report !\r\n");
+    return;
+  }
+
+  // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples:
+  // - Keyboard                     : Desktop, Keyboard
+  // - Mouse                        : Desktop, Mouse
+  // - Gamepad                      : Desktop, Gamepad
+  // - Consumer Control (Media Key) : Consumer, Consumer Control
+  // - System Control (Power key)   : Desktop, System Control
+  // - Generic (vendor)             : 0xFFxx, xx
+  if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP )
+  {
+    switch (rpt_info->usage)
+    {
+      case HID_USAGE_DESKTOP_KEYBOARD:
+        TU_LOG1("HID receive keyboard report\r\n");
+        // Assume keyboard follow boot report layout
+        process_kbd_report( (hid_keyboard_report_t const*) report );
+      break;
+
+      case HID_USAGE_DESKTOP_MOUSE:
+        TU_LOG1("HID receive mouse report\r\n");
+        // Assume mouse follow boot report layout
+        process_mouse_report( (hid_mouse_report_t const*) report );
+      break;
+
+      default: break;
+    }
+  }
+}

+ 2 - 2
examples/host/cdc_msc_hid/src/tusb_config.h

@@ -72,11 +72,11 @@
 //--------------------------------------------------------------------
 
 // Size of buffer to hold descriptors and other data used for enumeration
-#define CFG_TUH_ENUMERATION_BUFSZIE 256
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
 
 #define CFG_TUH_HUB                 1
 #define CFG_TUH_CDC                 1
-#define CFG_TUH_HID                 2
+#define CFG_TUH_HID                 4
 #define CFG_TUH_MSC                 1
 #define CFG_TUH_VENDOR              0
 

+ 54 - 5
hw/bsp/board.c

@@ -25,7 +25,60 @@
 
 #include "board.h"
 
-#if defined(__MSP430__)
+#if 0
+#define LED_PHASE_MAX   8
+
+static struct
+{
+  uint32_t phase[LED_PHASE_MAX];
+  uint8_t phase_count;
+
+  bool led_state;
+  uint8_t current_phase;
+  uint32_t current_ms;
+}led_pattern;
+
+void board_led_pattern(uint32_t const phase_ms[], uint8_t count)
+{
+  memcpy(led_pattern.phase, phase_ms, 4*count);
+  led_pattern.phase_count = count;
+
+  // reset with 1st phase is on
+  led_pattern.current_ms = board_millis();
+  led_pattern.current_phase = 0;
+  led_pattern.led_state = true;
+  board_led_on();
+}
+
+void board_led_task(void)
+{
+  if ( led_pattern.phase_count == 0 ) return;
+
+  uint32_t const duration = led_pattern.phase[led_pattern.current_phase];
+
+  // return if not enough time
+  if (board_millis() - led_pattern.current_ms < duration) return;
+
+  led_pattern.led_state = !led_pattern.led_state;
+  board_led_write(led_pattern.led_state);
+
+  led_pattern.current_ms += duration;
+  led_pattern.current_phase++;
+
+  if (led_pattern.current_phase == led_pattern.phase_count)
+  {
+    led_pattern.current_phase = 0;
+    led_pattern.led_state = true;
+    board_led_on();
+  }
+}
+#endif
+
+//--------------------------------------------------------------------+
+// newlib read()/write() retarget
+//--------------------------------------------------------------------+
+
+#if defined(__MSP430__) || defined(__RX__)
   #define sys_write   write
   #define sys_read    read
 #else
@@ -33,10 +86,6 @@
   #define sys_read    _read
 #endif
 
-//--------------------------------------------------------------------+
-// newlib read()/write() retarget
-//--------------------------------------------------------------------+
-
 #if defined(LOGGER_RTT)
 // Logging with RTT
 

+ 7 - 2
hw/bsp/board.h

@@ -54,6 +54,10 @@ void board_init(void);
 // Turn LED on or off
 void board_led_write(bool state);
 
+// Control led pattern using phase duration in ms.
+// For each phase, LED is toggle then repeated, board_led_task() is required to be called
+//void board_led_pattern(uint32_t const phase_ms[], uint8_t count);
+
 // Get the current state of button
 // a '1' means active (pressed), a '0' means inactive.
 uint32_t board_button_read(void);
@@ -81,11 +85,12 @@ int board_uart_write(void const * buf, int len);
   }
 
 #elif CFG_TUSB_OS == OPT_OS_PICO
-#include "pico/time.h"
-static inline uint32_t board_millis(void)
+  #include "pico/time.h"
+  static inline uint32_t board_millis(void)
   {
     return to_ms_since_boot(get_absolute_time());
   }
+
 #elif CFG_TUSB_OS == OPT_OS_RTTHREAD
   static inline uint32_t board_millis(void)
   {

+ 2 - 2
hw/bsp/board_mcu.h

@@ -54,7 +54,7 @@
 
 #elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
       CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
-      CFG_TUSB_MCU == OPT_MCU_SAML22
+      CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
   #include "sam.h"
 
 #elif CFG_TUSB_MCU == OPT_MCU_SAMG
@@ -127,7 +127,7 @@
 #elif CFG_TUSB_MCU == OPT_MCU_EFM32GG || CFG_TUSB_MCU == OPT_MCU_EFM32GG11 || CFG_TUSB_MCU == OPT_MCU_EFM32GG12
   #include "em_device.h"
 
-#elif CFG_TUSB_MCU == OPT_MCU_RX63X
+#elif CFG_TUSB_MCU == OPT_MCU_RX63X || CFG_TUSB_MCU == OPT_MCU_RX65X
   // no header needed
 
 #else

+ 0 - 3
hw/bsp/esp32s2/family.cmake

@@ -4,7 +4,4 @@ cmake_minimum_required(VERSION 3.5)
 set(EXTRA_COMPONENT_DIRS "src" "${TOP}/hw/bsp/esp32s2/boards" "${TOP}/hw/bsp/esp32s2/components")  
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 set(SUPPORTED_TARGETS esp32s2)
-
-# include basic family CMake functionality
 set(FAMILY_MCUS ESP32S2)
-include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)

+ 0 - 3
hw/bsp/esp32s3/family.cmake

@@ -4,7 +4,4 @@ cmake_minimum_required(VERSION 3.5)
 set(EXTRA_COMPONENT_DIRS "src" "${TOP}/hw/bsp/esp32s3/boards" "${TOP}/hw/bsp/esp32s3/components")  
 include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 set(SUPPORTED_TARGETS esp32s3)
-
-# include basic family CMake functionality
 set(FAMILY_MCUS ESP32S3)
-include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)

+ 0 - 57
hw/bsp/family_common.cmake

@@ -1,57 +0,0 @@
-if (NOT FAMILY_MCUS)
-    set(FAMILY_MCUS ${FAMILY})
-endif()
-
-# save it in case of re-inclusion
-set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "")
-
-function(family_filter RESULT DIR)
-    get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
-    file(GLOB ONLYS "${DIR}/.only.MCU_*")
-    if (ONLYS)
-        foreach(MCU IN LISTS FAMILY_MCUS)
-            if (EXISTS ${DIR}/.only.MCU_${MCU})
-                set(${RESULT} 1 PARENT_SCOPE)
-                return()
-            endif()
-        endforeach()
-    else()
-        foreach(MCU IN LISTS FAMILY_MCUS)
-            if (EXISTS ${DIR}/.skip.MCU_${MCU})
-                set(${RESULT} 0 PARENT_SCOPE)
-                return()
-            endif()
-        endforeach()
-    endif()
-    set(${RESULT} 1 PARENT_SCOPE)
-endfunction()
-
-function(family_add_subdirectory DIR)
-    family_filter(SHOULD_ADD "${DIR}")
-    if (SHOULD_ADD)
-        add_subdirectory(${DIR})
-    endif()
-endfunction()
-
-function(family_get_project_name OUTPUT_NAME DIR)
-    get_filename_component(SHORT_NAME ${DIR} NAME)
-    set(${OUTPUT_NAME} ${TINYUSB_FAMILY_PROJECT_NAME_PREFIX}${SHORT_NAME} PARENT_SCOPE)
-endfunction()
-
-function(family_initialize_project PROJECT DIR)
-    family_filter(ALLOWED "${DIR}")
-    if (NOT ALLOWED)
-        get_filename_component(SHORT_NAME ${DIR} NAME)
-        message(FATAL_ERROR "${SHORT_NAME} is not supported on FAMILY=${FAMILY}")
-    endif()
-endfunction()
-
-# configure an executable target to link to tinyusb in device mode, and add the board implementation
-function(family_configure_device_example TARGET)
-    # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
-endfunction()
-
-# configure an executable target to link to tinyusb in host mode, and add the board implementation
-function(family_configure_host_example TARGET)
-    # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
-endfunction()

+ 71 - 0
hw/bsp/family_support.cmake

@@ -0,0 +1,71 @@
+if (NOT TARGET _family_support_marker)
+    add_library(_family_support_marker INTERFACE)
+
+    if (NOT FAMILY)
+        message(FATAL_ERROR "You must set a FAMILY variable for the build (e.g. rp2040, eps32s2, esp32s3). You can do this via -DFAMILY=xxx on the camke command line")
+    endif()
+
+    if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
+        message(FATAL_ERROR "Family '${FAMILY}' is not known/supported")
+    endif()
+
+    function(family_filter RESULT DIR)
+        get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+        file(GLOB ONLYS "${DIR}/.only.MCU_*")
+        if (ONLYS)
+            foreach(MCU IN LISTS FAMILY_MCUS)
+                if (EXISTS ${DIR}/.only.MCU_${MCU})
+                    set(${RESULT} 1 PARENT_SCOPE)
+                    return()
+                endif()
+            endforeach()
+        else()
+            foreach(MCU IN LISTS FAMILY_MCUS)
+                if (EXISTS ${DIR}/.skip.MCU_${MCU})
+                    set(${RESULT} 0 PARENT_SCOPE)
+                    return()
+                endif()
+            endforeach()
+        endif()
+        set(${RESULT} 1 PARENT_SCOPE)
+    endfunction()
+
+    function(family_add_subdirectory DIR)
+        family_filter(SHOULD_ADD "${DIR}")
+        if (SHOULD_ADD)
+            add_subdirectory(${DIR})
+        endif()
+    endfunction()
+
+    function(family_get_project_name OUTPUT_NAME DIR)
+        get_filename_component(SHORT_NAME ${DIR} NAME)
+        set(${OUTPUT_NAME} ${TINYUSB_FAMILY_PROJECT_NAME_PREFIX}${SHORT_NAME} PARENT_SCOPE)
+    endfunction()
+
+    function(family_initialize_project PROJECT DIR)
+        family_filter(ALLOWED "${DIR}")
+        if (NOT ALLOWED)
+            get_filename_component(SHORT_NAME ${DIR} NAME)
+            message(FATAL_ERROR "${SHORT_NAME} is not supported on FAMILY=${FAMILY}")
+        endif()
+    endfunction()
+
+    # configure an executable target to link to tinyusb in device mode, and add the board implementation
+    function(family_configure_device_example TARGET)
+        # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
+    endfunction()
+
+    # configure an executable target to link to tinyusb in host mode, and add the board implementation
+    function(family_configure_host_example TARGET)
+        # default implentation is empty, the function should be redefined in the FAMILY/family.cmake
+    endfunction()
+
+    include(${CMAKE_CURRENT_LIST_DIR}/${FAMILY}/family.cmake)
+
+    if (NOT FAMILY_MCUS)
+        set(FAMILY_MCUS ${FAMILY})
+    endif()
+
+    # save it in case of re-inclusion
+    set(FAMILY_MCUS ${FAMILY_MCUS} CACHE INTERNAL "")
+endif()

+ 2 - 2
hw/bsp/rp2040/family.cmake

@@ -3,7 +3,8 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
 	add_library(_rp2040_family_inclusion_marker INTERFACE)
 
 	if (NOT BOARD)
-		message(FATAL_ERROR "BOARD must be specified")
+		message("BOARD not specified, defaulting to pico_sdk")
+		set(BOARD pico_sdk)
 	endif()
 
 	# add the SDK in case we are standalone tinyusb example (noop if already present)
@@ -11,7 +12,6 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
 
 	# include basic family CMake functionality
 	set(FAMILY_MCUS RP2040)
-	include(${CMAKE_CURRENT_LIST_DIR}/../family_common.cmake)
 
 	include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
 

+ 24 - 0
hw/bsp/rx/boards/gr_citrus/board.mk

@@ -0,0 +1,24 @@
+DEPS_SUBMODULES += hw/mcu/renesas/rx
+
+CFLAGS += \
+  -mcpu=rx610 \
+  -misa=v1 \
+  -DCFG_TUSB_MCU=OPT_MCU_RX63X
+
+MCU_DIR = hw/mcu/renesas/rx/rx63n
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/r5f5631fd.ld
+
+# For freeRTOS port source
+FREERTOS_PORT = RX600
+
+# For flash-jlink target
+JLINK_DEVICE = R5F5631F
+JLINK_IF     = JTAG
+
+# For flash-pyocd target
+PYOCD_TARGET =
+
+# flash using jlink
+flash: flash-jlink

+ 35 - 15
hw/bsp/rx63n/boards/gr_citrus/gr_citrus.c → hw/bsp/rx/boards/gr_citrus/gr_citrus.c

@@ -34,26 +34,22 @@
  *
  * The pads are [the back side of GR-CITRUS](https://www.slideshare.net/MinaoYamamoto/grcitrusrx631/2).
  * 
- * Connet the pins between GR-CITRUS and JLink as follows.
+ * Connect the pins between GR-CITRUS and JLink as follows.
  * 
- * | JTAG Function | GR-CITRUS pin name| JLink pin No.| note     |
- * |:-------------:|:-----------------:|:------------:|:--------:|
- * | VTref         |   3.3V            |   1          |          |
- * | TRST          |   5               |   3          |          |
- * | GND           |   GND             |   4          |          |
- * | TDI           |   3               |   5          |          |
- * | TMS           |   2               |   7          |          |
- * | TCK           |   14              |   9          | short J4 |
- * | TDO           |   9               |  13          | short J5 |
- * | nRES          |   RST             |  15          |          |
+ * | Function  | GR-CITRUS pin | JLink pin No.| note     |
+ * |:---------:|:-------------:|:------------:|:--------:|
+ * | VTref     |   3.3V        |   1          |          |
+ * | TRST      |   5           |   3          |          |
+ * | GND       |   GND         |   4          |          |
+ * | TDI       |   3           |   5          |          |
+ * | TMS       |   2           |   7          |          |
+ * | TCK/FINEC |   14          |   9          | short J4 |
+ * | TDO       |   9           |  13          | short J5 |
+ * | nRES      |   RST         |  15          |          |
  *
  * JLink firmware needs to update to V6.96 or newer version to avoid
  * [a bug](https://forum.segger.com/index.php/Thread/7758-SOLVED-Bug-in-JLink-from-V6-88b-regarding-RX65N)
  * regarding downloading.
- *
- * When using SEGGER RTT, `RX_NEWLIB=0` should be added to make command arguments.
- * The option is used to change the C runtime library to `optlib` from `newlib`.
- * RTT may not work with `newlib`.
  */
 
 #include "../board.h"
@@ -253,3 +249,27 @@ uint32_t board_millis(void)
 #else
 uint32_t SystemCoreClock = 96000000;
 #endif
+
+int close(int fd)
+{
+    (void)fd;
+    return -1;
+}
+int fstat(int fd, void *pstat)
+{
+    (void)fd;
+    (void)pstat;
+    return 0;
+}
+off_t lseek(int fd, off_t pos, int whence)
+{
+    (void)fd;
+    (void)pos;
+    (void)whence;
+    return 0;
+}
+int isatty(int fd)
+{
+    (void)fd;
+    return 1;
+}

+ 0 - 0
hw/bsp/rx63n/boards/gr_citrus/hwinit.c → hw/bsp/rx/boards/gr_citrus/hwinit.c


+ 2 - 2
hw/bsp/rx63n/boards/gr_citrus/r5f5631fd.ld → hw/bsp/rx/boards/gr_citrus/r5f5631fd.ld

@@ -1,5 +1,5 @@
-__USTACK_SIZE = 0x00000200;
-__ISTACK_SIZE = 0x00000200;
+__USTACK_SIZE = 0x00000400;
+__ISTACK_SIZE = 0x00000400;
 
 MEMORY
 {

+ 25 - 0
hw/bsp/rx/boards/rx65n_target/board.mk

@@ -0,0 +1,25 @@
+CFLAGS += \
+  -mcpu=rx64m \
+  -misa=v2 \
+  -DCFG_TUSB_MCU=OPT_MCU_RX65X \
+  -DIR_USB0_USBI0=IR_PERIB_INTB185 \
+  -DIER_USB0_USBI0=IER_PERIB_INTB185 \
+  -DIEN_USB0_USBI0=IEN_PERIB_INTB185
+
+MCU_DIR = hw/mcu/renesas/rx/rx65n
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/r5f565ne.ld
+
+# For freeRTOS port source
+FREERTOS_PORT = RX600
+
+# For flash-jlink target
+JLINK_DEVICE = R5F565NE
+JLINK_IF     = JTAG
+
+# For flash-pyocd target
+PYOCD_TARGET =
+
+# flash using rfp-cli
+flash: flash-rfp

+ 168 - 0
hw/bsp/rx/boards/rx65n_target/r5f565ne.ld

@@ -0,0 +1,168 @@
+__USTACK_SIZE = 0x00000400;
+__ISTACK_SIZE = 0x00000400;
+
+MEMORY
+{
+	RAM  : ORIGIN = 0x4,        LENGTH = 0x3fffc
+	RAM2 : ORIGIN = 0x00800000, LENGTH = 0x60000
+	OFS  : ORIGIN = 0xFE7F5D00, LENGTH = 128
+	ROM  : ORIGIN = 0xFFE00000, LENGTH = 0x200000
+}
+SECTIONS
+{
+	.exvectors 0xFFFFFF80: AT(0xFFFFFF80)
+	{
+		"_exvectors_start" = .;
+		KEEP(*(.exvectors))
+		"_exvectors_end" = .;
+	} >ROM
+	.fvectors 0xFFFFFFFC: AT(0xFFFFFFFC)
+	{
+		KEEP(*(.fvectors))
+	} > ROM
+	.text 0xFFE00000: AT(0xFFE00000)
+	{
+		*(.text)
+		*(.text.*)
+		*(P)
+		KEEP(*(.text.*_isr))
+		etext = .;
+	} > ROM
+	.rvectors ALIGN(4):
+	{
+		_rvectors_start = .;
+		KEEP(*(.rvectors))
+		_rvectors_end = .;
+	} > ROM
+	.init :
+	{
+		KEEP(*(.init))
+		__preinit_array_start = .;
+		KEEP(*(.preinit_array))
+		__preinit_array_end = .;
+		__init_array_start = (. + 3) & ~ 3;
+		KEEP(*(.init_array))
+		KEEP(*(SORT(.init_array.*)))
+		__init_array_end = .;
+		__fini_array_start = .;
+		KEEP(*(.fini_array))
+		KEEP(*(SORT(.fini_array.*)))
+		__fini_array_end = .;
+	} > ROM
+	.fini :
+	{
+		KEEP(*(.fini))
+	} > ROM
+	.got :
+	{
+		*(.got)
+		*(.got.plt)
+	} > ROM
+	.rodata :
+	{
+		*(.rodata)
+		*(.rodata.*)
+		*(C_1)
+		*(C_2)
+		*(C)
+		_erodata = .;
+	} > ROM
+	.eh_frame_hdr :
+	{
+		*(.eh_frame_hdr)
+	} > ROM
+	.eh_frame :
+	{
+		*(.eh_frame)
+	} > ROM
+	.jcr :
+	{
+		*(.jcr)
+	} > ROM
+	.tors :
+	{
+		__CTOR_LIST__ = .;
+		. = ALIGN(2);
+		___ctors = .;
+		*(.ctors)
+		___ctors_end = .;
+		__CTOR_END__ = .;
+		__DTOR_LIST__ = .;
+		___dtors = .;
+		*(.dtors)
+		___dtors_end = .;
+		__DTOR_END__ = .;
+		. = ALIGN(2);
+		_mdata = .;
+	} > ROM
+	.data : AT(_mdata)
+	{
+		_data = .;
+		*(.data)
+		*(.data.*)
+		*(D)
+		*(D_1)
+		*(D_2)
+		_edata = .;
+	} > RAM
+	.gcc_exc :
+	{
+		*(.gcc_exc)
+	} > RAM
+	.bss :
+	{
+		_bss = .;
+		*(.bss)
+		*(.bss.**)
+		*(COMMON)
+		*(B)
+		*(B_1)
+		*(B_2)
+		_ebss = .;
+		_end = .;
+	} > RAM
+	.ustack :
+	{
+		. = ALIGN(8);
+		. = . + __USTACK_SIZE;
+		PROVIDE(_ustack = .);
+	} > RAM
+	.istack :
+	{
+		. = ALIGN(8);
+		. = . + __ISTACK_SIZE;
+		PROVIDE(_istack = .);
+	} > RAM
+	.ofs1 0xFE7F5D00: AT(0xFE7F5D00)
+	{
+		KEEP(*(.ofs1))
+	} > OFS
+	.ofs2 0xFE7F5D10: AT(0xFE7F5D10)
+	{
+		KEEP(*(.ofs2))
+	} > OFS
+	.ofs3 0xFE7F5D20: AT(0xFE7F5D20)
+	{
+		KEEP(*(.ofs3))
+	} > OFS
+	.ofs4 0xFE7F5D40: AT(0xFE7F5D40)
+	{
+		KEEP(*(.ofs4))
+	} > OFS
+	.ofs5 0xFE7F5D48: AT(0xFE7F5D48)
+	{
+		KEEP(*(.ofs5))
+	} > OFS
+	.ofs6 0xFE7F5D50: AT(0xFE7F5D50)
+	{
+		KEEP(*(.ofs6))
+	} > OFS
+	.ofs7 0xFE7F5D64: AT(0xFE7F5D64)
+	{
+		KEEP(*(.ofs7))
+	} > OFS
+	.ofs8 0xFE7F5D70: AT(0xFE7F5D70)
+	{
+		KEEP(*(.ofs8))
+	} > OFS
+}

+ 320 - 0
hw/bsp/rx/boards/rx65n_target/rx65n_target.c

@@ -0,0 +1,320 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Koji Kitayama
+ *
+ * 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.
+ */
+
+/* How to connect JLink and RX65n Target and option board
+ * (For original comment https://github.com/hathach/tinyusb/pull/922#issuecomment-869786131)
+ *
+ * To enable JTAG, RX65N requires following connections on main board.
+ * - short EJ2 jumper header, to disable onboard E2L.
+ * - short EMLE(J1-2) and 3V3(J1-14 or J2-10), to enable In-Circuit Emulator.
+ *
+ * Note: For RX65N-Cloud-Kit, the option board's JTAG pins to some switches or floating.
+ * To use JLink with the option board, I think some further modifications will be necessary.
+ *
+ * | Function  | RX65N pin  | main board | option board | JLink connector |
+ * |:---------:|:----------:|:----------:|:------------:|:---------------:|
+ * | 3V3       | VCC        |   J1-14    | CN5-6        |    1            |
+ * | TRST      | P34        |   J1-16    | CN5-7        |    3            |
+ * | GND       | VSS        |   J1-12    | CN5-5        |    4            |
+ * | TDI       | P30        |   J1-20    | CN5-10       |    5            |
+ * | TMS       | P31        |   J1-19    | USER_SW      |    7            |
+ * | TCK/FINEC | P27        |   J1-21    | N/A          |    9            |
+ * | TDO       | P26        |   J1-22    | CN5-9        |   13            |
+ * | nRES      | RES#       |   J1-10    | RESET_SW     |   15            |
+ *
+ * JLink firmware needs to update to V6.96 or newer version to avoid
+ * [a bug](https://forum.segger.com/index.php/Thread/7758-SOLVED-Bug-in-JLink-from-V6-88b-regarding-RX65N)
+ * regarding downloading.
+ */
+
+#include "bsp/board.h"
+#include "iodefine.h"
+#include "interrupt_handlers.h"
+
+#define IRQ_PRIORITY_CMT0     5
+#define IRQ_PRIORITY_USBI0    6
+#define IRQ_PRIORITY_SCI5     5
+
+#define SYSTEM_PRCR_PRC1      (1<<1)
+#define SYSTEM_PRCR_PRKEY     (0xA5u<<8)
+
+#define CMT_PCLK              60000000
+#define CMT_CMCR_CKS_DIV_128  2
+#define CMT_CMCR_CMIE         (1<<6)
+#define MPC_PFS_ISEL          (1<<6)
+
+#define SCI_PCLK              60000000
+#define SCI_SSR_FER           (1<<4)
+#define SCI_SSR_ORER          (1<<5)
+
+#define SCI_SCR_TEIE          (1u<<2)
+#define SCI_SCR_RE            (1u<<4)
+#define SCI_SCR_TE            (1u<<5)
+#define SCI_SCR_RIE           (1u<<6)
+#define SCI_SCR_TIE           (1u<<7)
+#define INT_Excep_SCI5_TEI5   INT_Excep_ICU_GROUPBL0
+
+#define IRQ_USB0_USBI0        62
+#define SLIBR_USBI0           SLIBR185
+#define IPR_USB0_USBI0        IPR_PERIB_INTB185
+#define INT_Excep_USB0_USBI0  INT_Excep_PERIB_INTB185
+
+void HardwareSetup(void)
+{
+  FLASH.ROMCIV.WORD = 1;
+  while (FLASH.ROMCIV.WORD) ;
+  FLASH.ROMCE.WORD = 1;
+  while (!FLASH.ROMCE.WORD) ;
+
+  SYSTEM.PRCR.WORD = 0xA503u;
+  if (!SYSTEM.RSTSR1.BYTE) {
+    RTC.RCR4.BYTE = 0;
+    RTC.RCR3.BYTE = 12;
+    while (12 != RTC.RCR3.BYTE) ;
+  }
+  SYSTEM.SOSCCR.BYTE = 1;
+
+  if (SYSTEM.HOCOCR.BYTE) {
+    SYSTEM.HOCOCR.BYTE = 0;
+    while (!SYSTEM.OSCOVFSR.BIT.HCOVF) ;
+  }
+  SYSTEM.PLLCR.WORD  = 0x1D10u; /* HOCO x 15 */
+  SYSTEM.PLLCR2.BYTE = 0;
+  while (!SYSTEM.OSCOVFSR.BIT.PLOVF) ;
+
+  SYSTEM.SCKCR.LONG  = 0x21C11222u;
+  SYSTEM.SCKCR2.WORD = 0x0041u;
+  SYSTEM.ROMWT.BYTE  = 0x02u;
+  while (0x02u != SYSTEM.ROMWT.BYTE) ;
+  SYSTEM.SCKCR3.WORD = 0x400u;
+  SYSTEM.PRCR.WORD   = 0xA500u;
+}
+
+//--------------------------------------------------------------------+
+// SCI handling
+//--------------------------------------------------------------------+
+typedef struct {
+  uint8_t *buf;
+  uint32_t cnt;
+} sci_buf_t;
+static volatile sci_buf_t sci_buf[2];
+
+void INT_Excep_SCI5_TXI5(void)
+{
+  uint8_t *buf = sci_buf[0].buf;
+  uint32_t cnt = sci_buf[0].cnt;
+  
+  if (!buf || !cnt) {
+    SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE);
+    return;
+  }
+  SCI5.TDR = *buf;
+  if (--cnt) {
+    ++buf;
+  } else {
+    buf = NULL;
+    SCI5.SCR.BIT.TIE  = 0;
+    SCI5.SCR.BIT.TEIE = 1;
+  }
+  sci_buf[0].buf = buf;
+  sci_buf[0].cnt = cnt;
+}
+
+void INT_Excep_SCI5_TEI5(void)
+{
+  SCI5.SCR.BYTE &= ~(SCI_SCR_TEIE | SCI_SCR_TE | SCI_SCR_TIE);
+}
+
+void INT_Excep_SCI5_RXI5(void)
+{
+  uint8_t *buf = sci_buf[1].buf;
+  uint32_t cnt = sci_buf[1].cnt;
+
+  if (!buf || !cnt ||
+      (SCI5.SSR.BYTE & (SCI_SSR_FER | SCI_SSR_ORER))) {
+    sci_buf[1].buf = NULL;
+    SCI5.SSR.BYTE   = 0;
+    SCI5.SCR.BYTE  &= ~(SCI_SCR_RE | SCI_SCR_RIE);
+    return;
+  }
+  *buf = SCI5.RDR;
+  if (--cnt) {
+    ++buf;
+  } else {
+    buf = NULL;
+    SCI5.SCR.BYTE &= ~(SCI_SCR_RE | SCI_SCR_RIE);
+  }
+  sci_buf[1].buf = buf;
+  sci_buf[1].cnt = cnt;
+}
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void INT_Excep_USB0_USBI0(void)
+{
+  tud_int_handler(0);
+}
+
+void board_init(void)
+{
+  /* setup software configurable interrupts */
+  ICU.SLIBR_USBI0.BYTE = IRQ_USB0_USBI0;
+  ICU.SLIPRCR.BYTE     = 1;
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+  /* Enable CMT0 */
+  SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+  MSTP(CMT0)       = 0;
+  SYSTEM.PRCR.WORD = SYSTEM_PRCR_PRKEY;
+  /* Setup 1ms tick timer */
+  CMT0.CMCNT      = 0;
+  CMT0.CMCOR      = CMT_PCLK / 1000 / 128;
+  CMT0.CMCR.WORD  = CMT_CMCR_CMIE | CMT_CMCR_CKS_DIV_128;
+  IR(CMT0, CMI0)  = 0;
+  IPR(CMT0, CMI0) = IRQ_PRIORITY_CMT0;
+  IEN(CMT0, CMI0) = 1;
+  CMT.CMSTR0.BIT.STR0 = 1;
+#endif
+
+  /* Unlock MPC registers */
+  MPC.PWPR.BIT.B0WI  = 0;
+  MPC.PWPR.BIT.PFSWE = 1;
+  // SW PB1
+  PORTB.PMR.BIT.B1 = 0U;
+  PORTB.PDR.BIT.B1 = 0U;
+  // LED PD6
+  PORTD.PODR.BIT.B6 = 1U;
+  PORTD.ODR1.BIT.B4 = 1U;
+  PORTD.PMR.BIT.B6  = 0U;
+  PORTD.PDR.BIT.B6  = 1U;
+  /* UART TXD5 => PA4, RXD5 => PA3 */
+  PORTA.PMR.BIT.B4 = 1U;
+  PORTA.PCR.BIT.B4 = 1U;
+  MPC.PA4PFS.BYTE  = 0b01010;
+  PORTA.PMR.BIT.B3 = 1U;
+  MPC.PA5PFS.BYTE  = 0b01010;
+  /* USB VBUS -> P16 */
+  PORT1.PMR.BIT.B6 = 1U;
+  MPC.P16PFS.BYTE  = MPC_PFS_ISEL | 0b10001;
+  /* Lock MPC registers */
+  MPC.PWPR.BIT.PFSWE = 0;
+  MPC.PWPR.BIT.B0WI  = 1;
+
+  /* Enable SCI5 */
+  SYSTEM.PRCR.WORD   = SYSTEM_PRCR_PRKEY | SYSTEM_PRCR_PRC1;
+  MSTP(SCI5)         = 0;
+  SYSTEM.PRCR.WORD   = SYSTEM_PRCR_PRKEY;
+  SCI5.SEMR.BIT.ABCS = 1;
+  SCI5.SEMR.BIT.BGDM = 1;
+  SCI5.BRR           = (SCI_PCLK / (8 * 115200)) - 1;
+  IR(SCI5,  RXI5)    = 0;
+  IR(SCI5,  TXI5)    = 0;
+  IS(SCI5,  TEI5)    = 0;
+  IR(ICU, GROUPBL0)  = 0;
+  IPR(SCI5, RXI5)    = IRQ_PRIORITY_SCI5;
+  IPR(SCI5, TXI5)    = IRQ_PRIORITY_SCI5;
+  IPR(ICU,GROUPBL0)  = IRQ_PRIORITY_SCI5;
+  IEN(SCI5, RXI5)    = 1;
+  IEN(SCI5, TXI5)    = 1;
+  IEN(ICU,GROUPBL0)  = 1;
+  EN(SCI5, TEI5)     = 1;
+
+  /* setup USBI0 interrupt. */
+  IR(USB0, USBI0)  = 0;
+  IPR(USB0, USBI0) = IRQ_PRIORITY_USBI0;
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state)
+{
+  PORTD.PODR.BIT.B6 = state ? 0 : 1;
+}
+
+uint32_t board_button_read(void)
+{
+  return PORTB.PIDR.BIT.B1 ? 0 : 1;
+}
+
+int board_uart_read(uint8_t* buf, int len)
+{
+  sci_buf[1].buf = buf;
+  sci_buf[1].cnt = len;
+  SCI5.SCR.BYTE |= SCI_SCR_RE | SCI_SCR_RIE;
+  while (SCI5.SCR.BIT.RE) ;
+  return len - sci_buf[1].cnt;
+}
+
+int board_uart_write(void const *buf, int len)
+{
+  sci_buf[0].buf = (uint8_t*)buf;
+  sci_buf[0].cnt = len;
+  SCI5.SCR.BYTE |= SCI_SCR_TE | SCI_SCR_TIE;
+  while (SCI5.SCR.BIT.TE) ;
+  return len;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void INT_Excep_CMT0_CMI0(void)
+{
+  ++system_ticks;
+}
+
+uint32_t board_millis(void)
+{
+  return system_ticks;
+}
+#else
+uint32_t SystemCoreClock = 120000000;
+#endif
+
+int close(int fd)
+{
+    (void)fd;
+    return -1;
+}
+int fstat(int fd, void *pstat)
+{
+    (void)fd;
+    (void)pstat;
+    return 0;
+}
+off_t lseek(int fd, off_t pos, int whence)
+{
+    (void)fd;
+    (void)pos;
+    (void)whence;
+    return 0;
+}
+int isatty(int fd)
+{
+    (void)fd;
+    return 1;
+}

+ 32 - 0
hw/bsp/rx/family.mk

@@ -0,0 +1,32 @@
+DEPS_SUBMODULES += hw/mcu/renesas/rx
+
+# Cross Compiler for RX
+CROSS_COMPILE = rx-elf-
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CFLAGS += \
+  -nostartfiles \
+  -ffunction-sections \
+  -fdata-sections \
+  -fshort-enums \
+  -mlittle-endian-data \
+  -DSSIZE_MAX=__INT_MAX__
+
+SRC_C += \
+	src/portable/renesas/usba/dcd_usba.c \
+	$(MCU_DIR)/vects.c
+
+INC += \
+	$(TOP)/$(BOARD_PATH) \
+	$(TOP)/$(MCU_DIR)
+
+SRC_S += $(MCU_DIR)/start.S
+
+$(BUILD)/$(PROJECT).mot: $(BUILD)/$(PROJECT).elf
+	@echo CREATE $@
+	$(OBJCOPY) -O srec -I elf32-rx-be-ns $^ $@
+
+# flash using rfp-cli
+flash-rfp: $(BUILD)/$(PROJECT).mot
+	rfp-cli -device rx65x -tool e2l -if fine -fo id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auth id FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -auto $^

+ 0 - 61
hw/bsp/rx63n/boards/gr_citrus/board.mk

@@ -1,61 +0,0 @@
-DEPS_SUBMODULES += hw/mcu/renesas/rx
-
-CFLAGS += \
-  -nostartfiles \
-  -ffunction-sections \
-  -fdata-sections \
-  -fshort-enums \
-  -mcpu=rx610 \
-  -misa=v1 \
-  -mlittle-endian-data \
-  -DCFG_TUSB_MCU=OPT_MCU_RX63X
-
-# Cross Compiler for RX
-CROSS_COMPILE = rx-elf-
-
-RX_NEWLIB ?= 1
-
-ifeq ($(CMDEXE),1)
-OPTLIBINC="$(shell for /F "usebackq delims=" %%i in (`where rx-elf-gcc`) do echo %%~dpi..\rx-elf\optlibinc)"
-else
-OPTLIBINC=$(shell dirname `which rx-elf-gcc`)../rx-elf/optlibinc
-endif
-
-ifeq ($(RX_NEWLIB),1)
-CFLAGS += -DSSIZE_MAX=__INT_MAX__
-else
-# setup for optlib
-CFLAGS += -nostdinc \
-  -isystem $(OPTLIBINC) \
-  -DLWIP_NO_INTTYPES_H
-
-LIBS += -loptc -loptm
-endif
-
-MCU_DIR = hw/mcu/renesas/rx/rx63n
-
-# All source paths should be relative to the top level.
-LD_FILE = $(BOARD_PATH)/r5f5631fd.ld
-
-SRC_C += \
-	src/portable/renesas/usba/dcd_usba.c \
-	$(MCU_DIR)/vects.c
-
-INC += \
-	$(TOP)/$(BOARD_PATH) \
-	$(TOP)/$(MCU_DIR)
-
-SRC_S += $(MCU_DIR)/start.S
-
-# For freeRTOS port source
-FREERTOS_PORT = RX600
-
-# For flash-jlink target
-JLINK_DEVICE = R5F5631F
-JLINK_IF     = JTAG
-
-# For flash-pyocd target
-PYOCD_TARGET =
-
-# flash using jlink
-flash: flash-jlink

+ 0 - 1
hw/bsp/rx63n/family.mk

@@ -1 +0,0 @@
-include $(TOP)/$(BOARD_PATH)/board.mk

+ 0 - 50
hw/bsp/saml22/family.mk

@@ -1,50 +0,0 @@
-UF2_FAMILY_ID = 0x68ed2b88
-DEPS_SUBMODULES += hw/mcu/microchip
-
-include $(TOP)/$(BOARD_PATH)/board.mk
-
-CFLAGS += \
-  -mthumb \
-  -mabi=aapcs \
-  -mcpu=cortex-m0plus \
-  -nostdlib -nostartfiles \
-  -DCONF_OSC32K_CALIB_ENABLE=0 \
-  -DCFG_TUSB_MCU=OPT_MCU_SAML22
-
-SRC_C += \
-	src/portable/microchip/samd/dcd_samd.c \
-	hw/mcu/microchip/saml22/gcc/gcc/startup_saml22.c \
-	hw/mcu/microchip/saml22/gcc/system_saml22.c \
-	hw/mcu/microchip/saml22/hpl/gclk/hpl_gclk.c \
-	hw/mcu/microchip/saml22/hpl/mclk/hpl_mclk.c \
-	hw/mcu/microchip/saml22/hpl/pm/hpl_pm.c \
-	hw/mcu/microchip/saml22/hpl/osc32kctrl/hpl_osc32kctrl.c \
-	hw/mcu/microchip/saml22/hpl/oscctrl/hpl_oscctrl.c \
-	hw/mcu/microchip/saml22/hal/src/hal_atomic.c
-
-INC += \
-	$(TOP)/$(BOARD_PATH) \
-	$(TOP)/hw/mcu/microchip/saml22/ \
-	$(TOP)/hw/mcu/microchip/saml22/config \
-	$(TOP)/hw/mcu/microchip/saml22/include \
-	$(TOP)/hw/mcu/microchip/saml22/hal/include \
-	$(TOP)/hw/mcu/microchip/saml22/hal/utils/include \
-	$(TOP)/hw/mcu/microchip/saml22/hpl/port \
-	$(TOP)/hw/mcu/microchip/saml22/hri \
-	$(TOP)/hw/mcu/microchip/saml22/CMSIS/Core/Include
-
-# For TinyUSB port source 
-VENDOR = microchip
-CHIP_FAMILY = samd
-
-# For freeRTOS port source
-FREERTOS_PORT = ARM_CM0
-
-# flash using bossac at least version 1.8
-# can be found in arduino15/packages/arduino/tools/bossac/
-# Add it to your PATH or change BOSSAC variable to match your installation
-BOSSAC = bossac
-
-flash-bossac: $(BUILD)/$(PROJECT).bin
-	@:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
-	$(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R

+ 50 - 0
hw/bsp/saml2x/boards/atsaml21_xpro/board.h

@@ -0,0 +1,50 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, 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 BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// LED
+#define LED_PIN               (32 + 30) // PB30
+#define LED_STATE_ON          0
+
+// Button
+#define BUTTON_PIN            (0  + 15) // PA15
+#define BUTTON_STATE_ACTIVE   0
+
+// UART
+#define UART_RX_PIN           4
+#define UART_TX_PIN           5
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */

+ 12 - 0
hw/bsp/saml2x/boards/atsaml21_xpro/board.mk

@@ -0,0 +1,12 @@
+CFLAGS += -D__SAML21J18B__
+
+SAML_VARIANT = saml21
+
+# All source paths should be relative to the top level.
+LD_FILE = $(BOARD_PATH)/saml21j18b_flash.ld
+
+# For flash-jlink target
+JLINK_DEVICE = ATSAML21J18
+
+# flash using jlink
+flash: flash-jlink

+ 153 - 0
hw/bsp/saml2x/boards/atsaml21_xpro/saml21j18b_flash.ld

@@ -0,0 +1,153 @@
+/**
+ * \file
+ *
+ * \brief Linker script for running in internal FLASH on the SAML21J18B
+ *
+ * Copyright (c) 2016 Atmel Corporation,
+ *                    a wholly owned subsidiary of Microchip Technology Inc.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the Licence at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * \asf_license_stop
+ *
+ */
+
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+SEARCH_DIR(.)
+
+/* Memory Spaces Definitions */
+MEMORY
+{
+  rom      (rx)  : ORIGIN = 0x00000000, LENGTH = 0x00040000
+  ram      (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
+  lpram    (rwx) : ORIGIN = 0x30000000, LENGTH = 0x00002000
+}
+
+/* The stack size used by the application. NOTE: you need to adjust according to your application. */
+STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000;
+
+/* Section Definitions */
+SECTIONS
+{
+    .text :
+    {
+        . = ALIGN(4);
+        _sfixed = .;
+        KEEP(*(.vectors .vectors.*))
+        *(.text .text.* .gnu.linkonce.t.*)
+        *(.glue_7t) *(.glue_7)
+        *(.rodata .rodata* .gnu.linkonce.r.*)
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+
+        /* Support C constructors, and C destructors in both user code
+           and the C library. This also provides support for C++ code. */
+        . = ALIGN(4);
+        KEEP(*(.init))
+        . = ALIGN(4);
+        __preinit_array_start = .;
+        KEEP (*(.preinit_array))
+        __preinit_array_end = .;
+
+        . = ALIGN(4);
+        __init_array_start = .;
+        KEEP (*(SORT(.init_array.*)))
+        KEEP (*(.init_array))
+        __init_array_end = .;
+
+        . = ALIGN(4);
+        KEEP (*crtbegin.o(.ctors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+        KEEP (*(SORT(.ctors.*)))
+        KEEP (*crtend.o(.ctors))
+
+        . = ALIGN(4);
+        KEEP(*(.fini))
+
+        . = ALIGN(4);
+        __fini_array_start = .;
+        KEEP (*(.fini_array))
+        KEEP (*(SORT(.fini_array.*)))
+        __fini_array_end = .;
+
+        KEEP (*crtbegin.o(.dtors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+        KEEP (*(SORT(.dtors.*)))
+        KEEP (*crtend.o(.dtors))
+
+        . = ALIGN(4);
+        _efixed = .;            /* End of text section */
+    } > rom
+
+    /* .ARM.exidx is sorted, so has to go in its own output section.  */
+    PROVIDE_HIDDEN (__exidx_start = .);
+    .ARM.exidx :
+    {
+      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > rom
+    PROVIDE_HIDDEN (__exidx_end = .);
+
+    . = ALIGN(4);
+    _etext = .;
+
+    .relocate : AT (_etext)
+    {
+        . = ALIGN(4);
+        _srelocate = .;
+        *(.ramfunc .ramfunc.*);
+        *(.data .data.*);
+        . = ALIGN(4);
+        _erelocate = .;
+    } > ram
+
+    .lpram (NOLOAD):
+    {
+        . = ALIGN(8);
+        _slpram = .;
+        *(.lpram .lpram.*);
+        . = ALIGN(8);
+        _elpram = .;
+    } > lpram
+
+    /* .bss section which is used for uninitialized data */
+    .bss (NOLOAD) :
+    {
+        . = ALIGN(4);
+        _sbss = . ;
+        _szero = .;
+        *(.bss .bss.*)
+        *(COMMON)
+        . = ALIGN(4);
+        _ebss = . ;
+        _ezero = .;
+        end = .;
+    } > ram
+
+    /* stack section */
+    .stack (NOLOAD):
+    {
+        . = ALIGN(8);
+        _sstack = .;
+        . = . + STACK_SIZE;
+        . = ALIGN(8);
+        _estack = .;
+    } > ram
+
+    . = ALIGN(4);
+    _end = . ;
+}

+ 0 - 0
hw/bsp/saml22/boards/saml22_feather/board.h → hw/bsp/saml2x/boards/saml22_feather/board.h


+ 2 - 0
hw/bsp/saml22/boards/saml22_feather/board.mk → hw/bsp/saml2x/boards/saml22_feather/board.mk

@@ -1,5 +1,7 @@
 CFLAGS += -D__SAML22J18A__
 
+SAML_VARIANT = saml22
+
 # All source paths should be relative to the top level.
 LD_FILE = $(BOARD_PATH)/$(BOARD).ld
 

+ 0 - 0
hw/bsp/saml22/boards/saml22_feather/saml22_feather.ld → hw/bsp/saml2x/boards/saml22_feather/saml22_feather.ld


+ 0 - 0
hw/bsp/saml22/boards/sensorwatch_m0/board.h → hw/bsp/saml2x/boards/sensorwatch_m0/board.h


+ 2 - 0
hw/bsp/saml22/boards/sensorwatch_m0/board.mk → hw/bsp/saml2x/boards/sensorwatch_m0/board.mk

@@ -1,5 +1,7 @@
 CFLAGS += -D__SAML22J18A__
 
+SAML_VARIANT = saml22
+
 # All source paths should be relative to the top level.
 LD_FILE = $(BOARD_PATH)/$(BOARD).ld
 

+ 0 - 0
hw/bsp/saml22/boards/sensorwatch_m0/sensorwatch_m0.ld → hw/bsp/saml2x/boards/sensorwatch_m0/sensorwatch_m0.ld


+ 8 - 8
hw/bsp/saml22/family.c → hw/bsp/saml2x/family.c

@@ -108,13 +108,13 @@ void board_init(void)
   gpio_set_pin_function(PIN_PA25, PINMUX_PA25G_USB_DP);
 
   // Output 500hz PWM on PB23 (TCC0 WO[3]) so we can validate the GCLK1 clock speed
-  hri_mclk_set_APBCMASK_TCC0_bit(MCLK);
-  TCC0->PER.bit.PER = 48000000 / 1000;
-  TCC0->CC[3].bit.CC = 48000000 / 2000;
-  TCC0->CTRLA.bit.ENABLE = true;
-
-  gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3);
-  hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
+//  hri_mclk_set_APBCMASK_TCC0_bit(MCLK);
+//  TCC0->PER.bit.PER = 48000000 / 1000;
+//  TCC0->CC[3].bit.CC = 48000000 / 2000;
+//  TCC0->CTRLA.bit.ENABLE = true;
+//
+//  gpio_set_pin_function(PIN_PB23, PINMUX_PB23F_TCC0_WO3);
+//  hri_gclk_write_PCHCTRL_reg(GCLK, TCC0_GCLK_ID, GCLK_PCHCTRL_GEN_GCLK1_Val | GCLK_PCHCTRL_CHEN);
 }
 
 //--------------------------------------------------------------------+
@@ -160,4 +160,4 @@ uint32_t board_millis(void)
 void _init(void)
 {
 
-}
+}

+ 48 - 0
hw/bsp/saml2x/family.mk

@@ -0,0 +1,48 @@
+UF2_FAMILY_ID = 0x68ed2b88
+DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/microchip
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+MCU_DIR = hw/mcu/microchip/$(SAML_VARIANT)
+
+CFLAGS += \
+  -mthumb \
+  -mabi=aapcs \
+  -mcpu=cortex-m0plus \
+  -nostdlib -nostartfiles \
+  -DCONF_OSC32K_CALIB_ENABLE=0 \
+  -DCFG_TUSB_MCU=OPT_MCU_SAML22
+
+SRC_C += \
+	src/portable/microchip/samd/dcd_samd.c \
+	$(MCU_DIR)/gcc/gcc/startup_$(SAML_VARIANT).c \
+	$(MCU_DIR)/gcc/system_$(SAML_VARIANT).c \
+	$(MCU_DIR)/hpl/gclk/hpl_gclk.c \
+	$(MCU_DIR)/hpl/mclk/hpl_mclk.c \
+	$(MCU_DIR)/hpl/pm/hpl_pm.c \
+	$(MCU_DIR)/hpl/osc32kctrl/hpl_osc32kctrl.c \
+	$(MCU_DIR)/hpl/oscctrl/hpl_oscctrl.c \
+	$(MCU_DIR)/hal/src/hal_atomic.c
+
+INC += \
+	$(TOP)/$(BOARD_PATH) \
+	$(TOP)/$(MCU_DIR)/ \
+	$(TOP)/$(MCU_DIR)/config \
+	$(TOP)/$(MCU_DIR)/include \
+	$(TOP)/$(MCU_DIR)/hal/include \
+	$(TOP)/$(MCU_DIR)/hal/utils/include \
+	$(TOP)/$(MCU_DIR)/hpl/port \
+	$(TOP)/$(MCU_DIR)/hri \
+	$(TOP)/lib/CMSIS_5/CMSIS/Core/Include
+
+# For freeRTOS port source
+FREERTOS_PORT = ARM_CM0
+
+# flash using bossac at least version 1.8
+# can be found in arduino15/packages/arduino/tools/bossac/
+# Add it to your PATH or change BOSSAC variable to match your installation
+BOSSAC = bossac
+
+flash-bossac: $(BUILD)/$(PROJECT).bin
+	@:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
+	$(BOSSAC) --port=$(SERIAL) -U -i --offset=0x2000 -e -w $^ -R

+ 1 - 1
hw/mcu/microchip

@@ -1 +1 @@
-Subproject commit f7087f04783c896627061fc151fa3527b73733c7
+Subproject commit 58eb3763200ff51a998be5f537acf67299add227

+ 1 - 1
hw/mcu/renesas/rx

@@ -1 +1 @@
-Subproject commit 4a51dfe6ecdf936d2d89f223f069e24a2d109207
+Subproject commit 706b4e0cf485605c32351e2f90f5698267996023

+ 28 - 1
src/class/audio/audio.h

@@ -489,7 +489,7 @@ typedef enum
   AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT     = (uint32_t) (1 << 2),
   AUDIO_DATA_FORMAT_TYPE_I_ALAW           = (uint32_t) (1 << 3),
   AUDIO_DATA_FORMAT_TYPE_I_MULAW          = (uint32_t) (1 << 4),
-  AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA       = 0x100000000,
+  AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA       = 0x80000000,
 } audio_data_format_type_I_t;
 
 /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
@@ -823,6 +823,33 @@ typedef struct TU_ATTR_PACKED
   uint16_t wLockDelay        ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field.
 } audio_desc_cs_as_iso_data_ep_t;
 
+// 5.2.2 Control Request Layout
+typedef struct TU_ATTR_PACKED
+{
+    union
+    {
+        struct TU_ATTR_PACKED
+        {
+            uint8_t recipient :  5; ///< Recipient type tusb_request_recipient_t.
+            uint8_t type      :  2; ///< Request type tusb_request_type_t.
+            uint8_t direction :  1; ///< Direction type. tusb_dir_t
+        } bmRequestType_bit;
+        
+        uint8_t bmRequestType;
+    };
+    
+    uint8_t bRequest;  ///< Request type audio_cs_req_t
+    uint8_t bChannelNumber;
+    uint8_t bControlSelector;
+    union
+    {
+        uint8_t bInterface;
+        uint8_t bEndpoint;
+    };
+    uint8_t bEntityID;
+    uint16_t wLength;
+} audio_control_request_t;
+
 //// 5.2.3 Control Request Parameter Block Layout
 
 // 5.2.3.1 1-byte Control CUR Parameter Block

+ 210 - 184
src/class/audio/audio_device.c

@@ -102,19 +102,19 @@
 // EP IN software buffers and mutexes
 #if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
 #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_in_ff_mutex_wr_1;                                                             // No need for read mutex as only USB driver reads from FIFO
 #endif
 #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_in_ff_mutex_wr_2;                                                             // No need for read mutex as only USB driver reads from FIFO
 #endif
 #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_in_ff_mutex_wr_3;                                                             // No need for read mutex as only USB driver reads from FIFO
 #endif
@@ -126,32 +126,32 @@ osal_mutex_def_t ep_in_ff_mutex_wr_3;
 // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
 #if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
 #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
 #endif
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
 #endif
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
 #endif
 #endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
 
 // EP OUT software buffers and mutexes
 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
 #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_out_ff_mutex_rd_1;                                                            // No need for write mutex as only USB driver writes into FIFO
 #endif
 #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_out_ff_mutex_rd_2;                                                            // No need for write mutex as only USB driver writes into FIFO
 #endif
 #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t ep_out_ff_mutex_rd_3;                                                            // No need for write mutex as only USB driver writes into FIFO
 #endif
@@ -163,52 +163,52 @@ osal_mutex_def_t ep_out_ff_mutex_rd_3;
 // - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
 #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
 #endif
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
 #endif
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
-CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
 #endif
 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
 
 // Control buffers
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
 #if CFG_TUD_AUDIO > 1
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
 #endif
 #if CFG_TUD_AUDIO > 2
-CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
 #endif
 
 // Active alternate setting of interfaces
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
+uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
+uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
 #endif
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
-CFG_TUSB_MEM_ALIGN uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
+uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
 #endif
 
 // Software encoding/decoding support FIFOs
 #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
 #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
 tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
 #endif
 #endif
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
 tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
 #endif
 #endif
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
 tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];                   // No need for read mutex as only USB driver reads from FIFO
@@ -218,21 +218,21 @@ osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
 
 #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
 #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
 tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
 #endif
 #endif
 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
 tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
 #endif
 #endif
 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
-CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
 tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
 #if CFG_FIFO_MUTEX
 osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];                   // No need for write mutex as only USB driver writes into FIFO
@@ -294,7 +294,7 @@ typedef struct
 
   // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
 #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-  CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
+  CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
 #endif
 
   // Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -393,12 +393,12 @@ static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
 
 #if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
 static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
-#endif
 
 static inline uint8_t tu_desc_subtype(void const* desc)
 {
   return ((uint8_t const*) desc)[2];
 }
+#endif
 
 bool tud_audio_n_mounted(uint8_t func_id)
 {
@@ -643,7 +643,6 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
 
   // Determine amount of samples
   uint8_t const n_ff_used               = audio->n_ff_used_rx;
-  uint16_t const nBytesToCopy           = audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx;
   uint16_t const nBytesPerFFToRead      = n_bytes_received / n_ff_used;
   uint8_t cnt_ff;
 
@@ -662,14 +661,14 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
       info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
       src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
       dst_end = info.ptr_lin + info.len_lin;
-      src = audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_lin, dst_end, src, n_ff_used);
+      src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
 
       // Handle wrapped part of FIFO
       info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
       if (info.len_wrap != 0)
       {
         dst_end = info.ptr_wrap + info.len_wrap;
-        audiod_interleaved_copy_bytes_fast_decode(nBytesToCopy, info.ptr_wrap, dst_end, src, n_ff_used);
+        audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
       }
       tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
     }
@@ -885,7 +884,7 @@ range [-1, +1)
  * */
 
 // Helper function
-static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, void * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
+static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
 {
   // Optimize for fast half word copies
   typedef struct{
@@ -900,15 +899,15 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
   switch (nBytesToCopy)
   {
     case 1:
-      while((uint8_t *)src < src_end)
+      while(src < src_end)
       {
-        *dst = *(uint8_t *)src++;
+        *dst = *src++;
         dst += n_ff_used;
       }
       break;
 
     case 2:
-      while((uint8_t *)src < src_end)
+      while(src < src_end)
       {
         *(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
         src += 2;
@@ -917,23 +916,23 @@ static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const
       break;
 
     case 3:
-      while((uint8_t *)src < src_end)
+      while(src < src_end)
       {
         //        memcpy(dst, src, 3);
         //        src = (uint8_t *)src + 3;
         //        dst += 3 * n_ff_used;
 
         // TODO: Is there a faster way to copy 3 bytes?
-        *dst++ = *(uint8_t *)src++;
-        *dst++ = *(uint8_t *)src++;
-        *dst++ = *(uint8_t *)src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
 
         dst += 3 * (n_ff_used - 1);
       }
       break;
 
     case 4:
-      while((uint8_t *)src < src_end)
+      while(src < src_end)
       {
         *(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
         src += 4;
@@ -993,8 +992,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
     if (info.len_lin != 0)
     {
       info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin);       // Limit up to desired length
-      src_end = info.ptr_lin + info.len_lin;
-      dst = audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_lin, src_end, dst, n_ff_used);
+      src_end = (uint8_t *)info.ptr_lin + info.len_lin;
+      dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
 
       // Limit up to desired length
       info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
@@ -1002,8 +1001,8 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
       // Handle wrapped part of FIFO
       if (info.len_wrap != 0)
       {
-        src_end = info.ptr_wrap + info.len_wrap;
-        audiod_interleaved_copy_bytes_fast_encode(nBytesToCopy, info.ptr_wrap, src_end, dst, n_ff_used);
+        src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
+        audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
       }
 
       tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
@@ -1481,18 +1480,20 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
     audio->ep_in_as_intf_num = 0;
     usbd_edpt_close(rhport, audio->ep_in);
 
-    // Invoke callback - can be used to stop data sampling
-    if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
-
-    audio->ep_in = 0;                           // Necessary?
-
-    // Clear support FIFOs if used
-#if CFG_TUD_AUDIO_ENABLE_ENCODING
+    // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_ENCODING
+    tu_fifo_clear(&audio->ep_in_ff);
+#else
     for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
     {
       tu_fifo_clear(&audio->tx_supp_ff[cnt]);
     }
 #endif
+    
+    // Invoke callback - can be used to stop data sampling
+    if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+    audio->ep_in = 0;                           // Necessary?
 
   }
 #endif
@@ -1502,16 +1503,22 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
   {
     audio->ep_out_as_intf_num = 0;
     usbd_edpt_close(rhport, audio->ep_out);
-    audio->ep_out = 0;                          // Necessary?
 
-    // Clear support FIFOs if used
-#if CFG_TUD_AUDIO_ENABLE_DECODING
+    // Clear FIFOs, since data is no longer valid
+#if !CFG_TUD_AUDIO_ENABLE_DECODING
+    tu_fifo_clear(&audio->ep_out_ff);
+#else
     for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
     {
       tu_fifo_clear(&audio->rx_supp_ff[cnt]);
     }
 #endif
 
+    // Invoke callback - can be used to stop data sampling
+    if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
+
+    audio->ep_out = 0;                          // Necessary?
+
     // Close corresponding feedback EP
 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
     usbd_edpt_close(rhport, audio->ep_fb);
@@ -1605,9 +1612,17 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
             TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
 #endif
 #endif
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+            // In case of asynchronous EP, call Cb after ep_fb is set
+            if (!(((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.sync == 0x01 && audio->ep_fb == 0))
+            {
+              if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+            }
+#else
             // Invoke callback
             if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
-
+#endif
             // Prepare for incoming data
 #if USE_LINEAR_BUFFER_RX
             TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
@@ -1621,8 +1636,11 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
           {
             audio->ep_fb = ep_addr;
 
-            // Invoke callback
-            if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+            // Invoke callback after ep_out is set
+            if (audio->ep_out != 0)
+            {
+              if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+            }
           }
 #endif
 #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1658,64 +1676,65 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
 
     switch (p_request->bmRequestType_bit.recipient)
     {
-      case TUSB_REQ_RCPT_INTERFACE: ;       // The semicolon is there to enable a declaration right after the label
-
-      uint8_t itf = TU_U16_LOW(p_request->wIndex);
-      uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
-      if (entityID != 0)
+      case TUSB_REQ_RCPT_INTERFACE:
       {
-        if (tud_audio_set_req_entity_cb)
+        uint8_t itf = TU_U16_LOW(p_request->wIndex);
+        uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+        if (entityID != 0)
         {
-          // Check if entity is present and get corresponding driver index
-          TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+          if (tud_audio_set_req_entity_cb)
+          {
+            // Check if entity is present and get corresponding driver index
+            TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
 
-          // Invoke callback
-          return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+            // Invoke callback
+            return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+          }
+          else
+          {
+            TU_LOG2("  No entity set request callback available!\r\n");
+            return false;     // In case no callback function is present or request can not be conducted we stall it
+          }
         }
         else
         {
-          TU_LOG2("  No entity set request callback available!\r\n");
-          return false;     // In case no callback function is present or request can not be conducted we stall it
+          if (tud_audio_set_req_itf_cb)
+          {
+            // Find index of audio driver structure and verify interface really exists
+            TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+            // Invoke callback
+            return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+          }
+          else
+          {
+            TU_LOG2("  No interface set request callback available!\r\n");
+            return false;     // In case no callback function is present or request can not be conducted we stall it
+          }
         }
       }
-      else
+      break;
+
+      case TUSB_REQ_RCPT_ENDPOINT:
       {
-        if (tud_audio_set_req_itf_cb)
+        uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+        if (tud_audio_set_req_ep_cb)
         {
-          // Find index of audio driver structure and verify interface really exists
-          TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+          // Check if entity is present and get corresponding driver index
+          TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
 
           // Invoke callback
-          return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
+          return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
         }
         else
         {
-          TU_LOG2("  No interface set request callback available!\r\n");
-          return false;     // In case no callback function is present or request can not be conducted we stall it
+          TU_LOG2("  No EP set request callback available!\r\n");
+          return false;   // In case no callback function is present or request can not be conducted we stall it
         }
       }
-
       break;
-
-      case TUSB_REQ_RCPT_ENDPOINT: ;        // The semicolon is there to enable a declaration right after the label
-
-      uint8_t ep = TU_U16_LOW(p_request->wIndex);
-
-      if (tud_audio_set_req_ep_cb)
-      {
-        // Check if entity is present and get corresponding driver index
-        TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
-
-        // Invoke callback
-        return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
-      }
-      else
-      {
-        TU_LOG2("  No EP set request callback available!\r\n");
-        return false;   // In case no callback function is present or request can not be conducted we stall it
-      }
-
       // Unknown/Unsupported recipient
       default: TU_BREAKPOINT(); return false;
     }
@@ -1754,73 +1773,75 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
     // Conduct checks which depend on the recipient
     switch (p_request->bmRequestType_bit.recipient)
     {
-      case TUSB_REQ_RCPT_INTERFACE: ;       // The semicolon is there to enable a declaration right after the label
-
-      uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
-      // Verify if entity is present
-      if (entityID != 0)
+      case TUSB_REQ_RCPT_INTERFACE:
       {
-        // Find index of audio driver structure and verify entity really exists
-        TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+        uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
 
-        // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
-        if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
+        // Verify if entity is present
+        if (entityID != 0)
         {
-          if (tud_audio_get_req_entity_cb)
+          // Find index of audio driver structure and verify entity really exists
+          TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+
+          // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+          if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
           {
-            return tud_audio_get_req_entity_cb(rhport, p_request);
+            if (tud_audio_get_req_entity_cb)
+            {
+              return tud_audio_get_req_entity_cb(rhport, p_request);
+            }
+            else
+            {
+              TU_LOG2("  No entity get request callback available!\r\n");
+              return false;   // Stall
+            }
           }
-          else
+        }
+        else
+        {
+          // Find index of audio driver structure and verify interface really exists
+          TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+
+          // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+          if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
           {
-            TU_LOG2("  No entity get request callback available!\r\n");
-            return false;   // Stall
+            if (tud_audio_get_req_itf_cb)
+            {
+              return tud_audio_get_req_itf_cb(rhport, p_request);
+            }
+            else
+            {
+              TU_LOG2("  No interface get request callback available!\r\n");
+              return false;   // Stall
+            }
           }
         }
       }
-      else
+      break;
+
+      case TUSB_REQ_RCPT_ENDPOINT:
       {
-        // Find index of audio driver structure and verify interface really exists
-        TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+        uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+        // Find index of audio driver structure and verify EP really exists
+        TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
 
         // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
         if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
         {
-          if (tud_audio_get_req_itf_cb)
+          if (tud_audio_get_req_ep_cb)
           {
-            return tud_audio_get_req_itf_cb(rhport, p_request);
+            return tud_audio_get_req_ep_cb(rhport, p_request);
           }
           else
           {
-            TU_LOG2("  No interface get request callback available!\r\n");
-            return false;   // Stall
+            TU_LOG2("  No EP get request callback available!\r\n");
+            return false;     // Stall
           }
         }
       }
       break;
 
-      case TUSB_REQ_RCPT_ENDPOINT: ;        // The semicolon is there to enable a declaration right after the label
-
-      uint8_t ep = TU_U16_LOW(p_request->wIndex);
-
-      // Find index of audio driver structure and verify EP really exists
-      TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
-
-      // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
-      if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
-      {
-        if (tud_audio_get_req_ep_cb)
-        {
-          return tud_audio_get_req_ep_cb(rhport, p_request);
-        }
-        else
-        {
-          TU_LOG2("  No EP get request callback available!\r\n");
-          return false;     // Stall
-        }
-      }
-      break;
-
       // Unknown/Unsupported recipient
       default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
     }
@@ -1913,8 +1934,12 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
     {
       if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
 
-      // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
-      return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+      // Schedule a transmit with the new value if EP is not busy 
+      if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
+      {
+        // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
+        return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+      }
     }
 #endif
 #endif
@@ -1935,29 +1960,31 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
   // Conduct checks which depend on the recipient
   switch (p_request->bmRequestType_bit.recipient)
   {
-    case TUSB_REQ_RCPT_INTERFACE: ;     // The semicolon is there to enable a declaration right after the label
-
-    uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
-
-    // Verify if entity is present
-    if (entityID != 0)
-    {
-      // Find index of audio driver structure and verify entity really exists
-      TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
-    }
-    else
+    case TUSB_REQ_RCPT_INTERFACE:
     {
-      // Find index of audio driver structure and verify interface really exists
-      TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+      uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+      // Verify if entity is present
+      if (entityID != 0)
+      {
+        // Find index of audio driver structure and verify entity really exists
+        TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
+      }
+      else
+      {
+        // Find index of audio driver structure and verify interface really exists
+        TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
+      }
     }
     break;
 
-    case TUSB_REQ_RCPT_ENDPOINT: ;      // The semicolon is there to enable a declaration right after the label
-
-    uint8_t ep = TU_U16_LOW(p_request->wIndex);
+    case TUSB_REQ_RCPT_ENDPOINT:
+    {
+      uint8_t ep = TU_U16_LOW(p_request->wIndex);
 
-    // Find index of audio driver structure and verify EP really exists
-    TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+      // Find index of audio driver structure and verify EP really exists
+      TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
+    }
     break;
 
     // Unknown/Unsupported recipient
@@ -1992,15 +2019,17 @@ static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio
     while (p_desc < p_desc_end)
     {
       // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
-      if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
+      if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
       {
-        *idxItf = tmp;
-        *pp_desc_int = p_desc;
-        return true;
+        if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
+        {
+          *idxItf = tmp;
+          *pp_desc_int = p_desc;
+          return true;
+        }
+        // Increase index, bytes read, and pointer
+        tmp++;
       }
-
-      // Increase index, bytes read, and pointer
-      tmp++;
       p_desc = tu_desc_next(p_desc);
     }
   }
@@ -2137,10 +2166,10 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
       if (as_itf == audio->ep_in_as_intf_num)
       {
         audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
-        audio->format_type_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
+        audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
 
 #if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
-        audio->format_type_I_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
+        audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
 #endif
       }
 #endif
@@ -2202,22 +2231,19 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
   TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
 
   // Format the feedback value
-  if (_audiod_fct[func_id].rhport == 0)
-  {
-    uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
-
-    // For FS format is 10.14
-    *(fb++) = (feedback >> 2) & 0xFF;
-    *(fb++) = (feedback >> 10) & 0xFF;
-    *(fb++) = (feedback >> 18) & 0xFF;
-    // 4th byte is needed to work correctly with MS Windows
-    *fb = 0;
-  }
-  else
-  {
-    // For HS format is 16.16 as originally demanded
-    _audiod_fct[func_id].fb_val = feedback;
-  }
+#if !TUD_OPT_HIGH_SPEED
+  uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
+
+  // For FS format is 10.14
+  *(fb++) = (feedback >> 2) & 0xFF;
+  *(fb++) = (feedback >> 10) & 0xFF;
+  *(fb++) = (feedback >> 18) & 0xFF;
+  // 4th byte is needed to work correctly with MS Windows
+  *fb = 0;
+#else
+  // For HS format is 16.16 as originally demanded
+  _audiod_fct[func_id].fb_val = feedback;
+#endif
 
   // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
   if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))

+ 4 - 6
src/class/cdc/cdc_device.c

@@ -273,9 +273,6 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
   TU_VERIFY( TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass &&
              CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
 
-  // Note: 0xFF can be used with RNDIS
-  TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA), 0);
-
   // Find available interface
   cdcd_interface_t * p_cdc = NULL;
   for(uint8_t cdc_id=0; cdc_id<CFG_TUD_CDC; cdc_id++)
@@ -303,10 +300,11 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
 
   if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
   {
-    // notification endpoint if any
-    TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
+    // notification endpoint
+    tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
 
-    p_cdc->ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+    TU_ASSERT( usbd_edpt_open(rhport, desc_ep), 0 );
+    p_cdc->ep_notif = desc_ep->bEndpointAddress;
 
     drv_len += tu_desc_len(p_desc);
     p_desc   = tu_desc_next(p_desc);

+ 30 - 32
src/class/cdc/cdc_host.c

@@ -149,29 +149,27 @@ void cdch_init(void)
   tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
 }
 
-bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
+uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
 {
-  // Only support ACM
-  TU_VERIFY( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass);
+  (void) max_len;
 
-  // Only support AT commands, no protocol and vendor specific commands.
-  TU_VERIFY(tu_within(CDC_COMM_PROTOCOL_NONE, itf_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
-            0xff == itf_desc->bInterfaceProtocol);
+  // Only support ACM subclass
+  // Protocol 0xFF can be RNDIS device for windows XP
+  TU_VERIFY( TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass &&
+             CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
+             0xFF                                     != itf_desc->bInterfaceProtocol, 0);
 
-  uint8_t const * p_desc;
-  cdch_data_t * p_cdc;
-
-  p_desc = tu_desc_next(itf_desc);
-  p_cdc  = get_itf(dev_addr);
+  cdch_data_t * p_cdc = get_itf(dev_addr);
 
-  p_cdc->itf_num   = itf_desc->bInterfaceNumber;
-  p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com
+  p_cdc->itf_num      = itf_desc->bInterfaceNumber;
+  p_cdc->itf_protocol = itf_desc->bInterfaceProtocol;
 
   //------------- Communication Interface -------------//
-  (*p_length) = sizeof(tusb_desc_interface_t);
+  uint16_t drv_len = tu_desc_len(itf_desc);
+  uint8_t const * p_desc = tu_desc_next(itf_desc);
 
   // Communication Functional Descriptors
-  while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
+  while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
   {
     if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
     {
@@ -179,52 +177,52 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
       p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
     }
 
-    (*p_length) += p_desc[DESC_OFFSET_LEN];
+    drv_len += tu_desc_len(p_desc);
     p_desc = tu_desc_next(p_desc);
   }
 
-  if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
   {
     // notification endpoint
-    tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) p_desc;
+    tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
 
-    TU_ASSERT( usbh_edpt_open(rhport, dev_addr, ep_desc) );
-    p_cdc->ep_notif = ep_desc->bEndpointAddress;
+    TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
+    p_cdc->ep_notif = desc_ep->bEndpointAddress;
 
-    (*p_length) += p_desc[DESC_OFFSET_LEN];
+    drv_len += tu_desc_len(p_desc);
     p_desc = tu_desc_next(p_desc);
   }
 
   //------------- Data Interface (if any) -------------//
-  if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
+  if ( (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
        (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
   {
-    (*p_length) += p_desc[DESC_OFFSET_LEN];
+    // next to endpoint descriptor
+    drv_len += tu_desc_len(p_desc);
     p_desc = tu_desc_next(p_desc);
 
     // data endpoints expected to be in pairs
     for(uint32_t i=0; i<2; i++)
     {
-      tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *) p_desc;
-      TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
-      TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
+      tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
+      TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0);
 
-      TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+      TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep), 0);
 
-      if ( tu_edpt_dir(ep_desc->bEndpointAddress) ==  TUSB_DIR_IN )
+      if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
       {
-        p_cdc->ep_in = ep_desc->bEndpointAddress;
+        p_cdc->ep_in = desc_ep->bEndpointAddress;
       }else
       {
-        p_cdc->ep_out = ep_desc->bEndpointAddress;
+        p_cdc->ep_out = desc_ep->bEndpointAddress;
       }
 
-      (*p_length) += p_desc[DESC_OFFSET_LEN];
+      drv_len += tu_desc_len(p_desc);
       p_desc = tu_desc_next( p_desc );
     }
   }
 
-  return true;
+  return drv_len;
 }
 
 bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)

+ 5 - 5
src/class/cdc/cdc_host.h

@@ -121,11 +121,11 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void cdch_init(void);
-bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
-bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void cdch_close(uint8_t dev_addr);
+void     cdch_init       (void);
+uint16_t cdch_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool     cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool     cdch_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void     cdch_close      (uint8_t dev_addr);
 
 #ifdef __cplusplus
  }

+ 3 - 1
src/class/dfu/dfu_device.c

@@ -247,7 +247,7 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque
 
 static uint16_t dfu_req_upload(uint8_t rhport, tusb_control_request_t const * request, uint16_t block_num, uint16_t wLength)
 {
-  TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE);
+  TU_VERIFY( wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, 0);
   uint16_t retval = tud_dfu_req_upload_data_cb(block_num, (uint8_t *)_dfu_state_ctx.transfer_buf, wLength);
   tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, retval);
   return retval;
@@ -276,6 +276,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
   // if they wish, there still will be the internal control buffer copy to this buffer
   // but this mode would provide zero copy from the class driver to the application
 
+  TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
   // setup for data phase
   tud_control_xfer(rhport, request, _dfu_state_ctx.transfer_buf, request->wLength);
 }
@@ -283,6 +284,7 @@ static void dfu_req_dnload_setup(uint8_t rhport, tusb_control_request_t const *
 static void dfu_req_dnload_reply(uint8_t rhport, tusb_control_request_t const * request)
 {
   (void) rhport;
+  TU_VERIFY( request->wLength <= CFG_TUD_DFU_TRANSFER_BUFFER_SIZE, );
   tud_dfu_req_dnload_data_cb(request->wValue, (uint8_t *)_dfu_state_ctx.transfer_buf, request->wLength);
   _dfu_state_ctx.blk_transfer_in_proc = false;
 }

+ 26 - 2
src/class/hid/hid_device.c

@@ -280,7 +280,21 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
           uint8_t const report_type = tu_u16_high(request->wValue);
           uint8_t const report_id   = tu_u16_low(request->wValue);
 
-          uint16_t xferlen = tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epin_buf, request->wLength);
+          uint8_t* report_buf = p_hid->epin_buf;
+          uint16_t req_len = request->wLength;
+
+          uint16_t xferlen = 0;
+
+          // If host request a specific Report ID, add ID to as 1 byte of response
+          if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
+          {
+            *report_buf++ = report_id;
+            req_len--;
+
+            xferlen++;
+          }
+
+          xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
           TU_ASSERT( xferlen > 0 );
 
           tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen);
@@ -298,7 +312,17 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
           uint8_t const report_type = tu_u16_high(request->wValue);
           uint8_t const report_id   = tu_u16_low(request->wValue);
 
-          tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epout_buf, request->wLength);
+          uint8_t const* report_buf = p_hid->epout_buf;
+          uint16_t report_len = request->wLength;
+
+          // If host request a specific Report ID, extract report ID in buffer before invoking callback
+          if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
+          {
+            report_buf++;
+            report_len--;
+          }
+
+          tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
         }
       break;
 

+ 38 - 37
src/class/hid/hid_host.c

@@ -37,16 +37,6 @@
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
 
-/*
- "KEYBOARD"               : in_len=8 , out_len=1, usage_page=0x01, usage=0x06   # Generic Desktop, Keyboard
- "MOUSE"                  : in_len=4 , out_len=0, usage_page=0x01, usage=0x02   # Generic Desktop, Mouse
- "CONSUMER"               : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01   # Consumer, Consumer Control
- "SYS_CONTROL"            : in_len=1 , out_len=0, usage_page=0x01, usage=0x80   # Generic Desktop, Sys Control
- "GAMEPAD"                : in_len=6 , out_len=0, usage_page=0x01, usage=0x05   # Generic Desktop, Game Pad
- "DIGITIZER"              : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02   # Digitizers, Pen
- "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05   # Generic Desktop, Game Pad
- "RAW"                    : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF
- */
 typedef struct
 {
   uint8_t itf_num;
@@ -108,7 +98,7 @@ uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
   return hid_itf->itf_protocol;
 }
 
-bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
 {
   hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
   return hid_itf->protocol_mode;
@@ -253,33 +243,37 @@ void hidh_close(uint8_t dev_addr)
 // Enumeration
 //--------------------------------------------------------------------+
 
-static bool config_get_protocol             (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+static bool config_set_protocol             (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
 static bool config_get_report_desc          (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
 static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
 
-bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
+uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
 {
-  TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
+  (void) max_len;
+
+  TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
 
+  uint16_t drv_len = sizeof(tusb_desc_interface_t);
   uint8_t const *p_desc = (uint8_t const *) desc_itf;
 
   //------------- HID descriptor -------------//
   p_desc = tu_desc_next(p_desc);
   tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
-  TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
+  TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType, 0);
 
   // not enough interface, try to increase CFG_TUH_HID
   // TODO multiple devices
   hidh_device_t* hid_dev = get_dev(dev_addr);
-  TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID);
+  TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
 
   //------------- Endpoint Descriptor -------------//
+  drv_len += tu_desc_len(p_desc);
   p_desc = tu_desc_next(p_desc);
   tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
-  TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
+  TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType, 0);
 
   // TODO also open endpoint OUT
-  TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
+  TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
 
   hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
   hid_dev->inst_count++;
@@ -292,12 +286,13 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
   hid_itf->report_desc_type = desc_hid->bReportType;
   hid_itf->report_desc_len  = tu_unaligned_read16(&desc_hid->wReportLength);
 
-  hid_itf->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
+  // Per HID Specs: default is Report protocol, though we will force Boot protocol when set_config
+  hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
   if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
 
-  *p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+  drv_len += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
 
-  return true;
+  return drv_len;
 }
 
 bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
@@ -324,43 +319,49 @@ bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
     .wLength  = 0
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_get_protocol : config_get_report_desc) );
+  TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
 
   return true;
 }
 
-static bool config_get_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
+// Force device to work in BOOT protocol
+static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
 {
-  // Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
+  // Stall is a valid response for SET_IDLE, therefore we could ignore its result
   (void) result;
 
   uint8_t const itf_num     = (uint8_t) request->wIndex;
   uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
   hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
 
-  TU_LOG2("HID Get Protocol\r\n");
+  TU_LOG2("HID Set Protocol\r\n");
+  hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
   tusb_control_request_t const new_request =
   {
     .bmRequestType_bit =
     {
       .recipient = TUSB_REQ_RCPT_INTERFACE,
       .type      = TUSB_REQ_TYPE_CLASS,
-      .direction = TUSB_DIR_IN
+      .direction = TUSB_DIR_OUT
     },
-    .bRequest = HID_REQ_CONTROL_GET_PROTOCOL,
-    .wValue   = 0,
+    .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
+    .wValue   = HID_PROTOCOL_BOOT,
     .wIndex   = hid_itf->itf_num,
-    .wLength  = 1
+    .wLength  = 0
   };
 
-  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, &hid_itf->protocol_mode, config_get_report_desc) );
-  return false;
+  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
+  return true;
 }
 
 static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
 {
-  // Stall is a valid response for SET_IDLE GET_PROTOCOL, therefore we could ignore its result
-  (void) result;
+  // We can be here after SET_IDLE or SET_PROTOCOL (boot device)
+  // Trigger assert if result is not successful with set protocol
+  if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
+  {
+    TU_ASSERT(result == XFER_RESULT_SUCCESS);
+  }
 
   uint8_t const itf_num     = (uint8_t) request->wIndex;
   uint8_t const instance    = get_instance_id_by_itfnum(dev_addr, itf_num);
@@ -368,7 +369,7 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons
 
   // Get Report Descriptor
   // using usbh enumeration buffer since report descriptor can be very long
-  TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSZIE );
+  TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSIZE );
 
   TU_LOG2("HID Get Report Descriptor\r\n");
   tusb_control_request_t const new_request =
@@ -452,9 +453,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
 
     uint8_t const data8 = desc_report[0];
 
-    TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size);
-    for(uint32_t i=0; i<size; i++) TU_LOG2("%02X ", desc_report[i]);
-    TU_LOG2("\r\n");
+    TU_LOG(3, "tag = %d, type = %d, size = %d, data = ", tag, type, size);
+    for(uint32_t i=0; i<size; i++) TU_LOG(3, "%02X ", desc_report[i]);
+    TU_LOG(3, "\r\n");
 
     switch(type)
     {

+ 9 - 8
src/class/hid/hid_host.h

@@ -66,9 +66,10 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance);
 // Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
 uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance);
 
-// Get current active protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
-// Note: as HID spec, device will be initialized in Report mode
-bool tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
+// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
+// Note: Device will be initialized in Boot protocol for simplicity.
+//       Application can use set_protocol() to switch back to Report protocol.
+uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
 
 // Set protocol to HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
 // This function is only supported by Boot interface (tuh_n_hid_interface_protocol() != NONE)
@@ -118,11 +119,11 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t ins
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void hidh_init(void);
-bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
-bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
-void hidh_close(uint8_t dev_addr);
+void     hidh_init       (void);
+uint16_t hidh_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool     hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool     hidh_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+void     hidh_close      (uint8_t dev_addr);
 
 #ifdef __cplusplus
 }

+ 16 - 20
src/class/midi/midi_device.c

@@ -197,9 +197,11 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui
 
 bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
 {
-  midid_interface_t* p_midi = &_midid_itf[itf];
-  uint32_t num_read = tu_fifo_read_n(&p_midi->rx_ff, packet, 4);
-  _prep_out_transaction(p_midi);
+  midid_interface_t* midi = &_midid_itf[itf];
+  TU_VERIFY(midi->ep_out);
+
+  uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
+  _prep_out_transaction(midi);
   return (num_read == 4);
 }
 
@@ -234,19 +236,19 @@ static uint32_t write_flush(midid_interface_t* midi)
 uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
 {
   midid_interface_t* midi = &_midid_itf[itf];
-  TU_VERIFY(midi->itf_num, 0);
+  TU_VERIFY(midi->ep_in, 0);
 
   midid_stream_t* stream = &midi->stream_write;
 
-  uint32_t total_written = 0;
   uint32_t i = 0;
-  while ( i < bufsize )
+  while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) )
   {
     uint8_t const data = buffer[i];
+    i++;
 
     if ( stream->index == 0 )
     {
-      // new event packet
+      //------------- New event packet -------------//
 
       uint8_t const msg = data >> 4;
 
@@ -308,9 +310,9 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
     }
     else
     {
-      // On-going (buffering) packet
+      //------------- On-going (buffering) packet -------------//
 
-      TU_ASSERT(stream->index < 4, total_written);
+      TU_ASSERT(stream->index < 4, i);
       stream->buffer[stream->index] = data;
       stream->index++;
 
@@ -333,27 +335,20 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
       // complete current event packet, reset stream
       stream->index = stream->total = 0;
 
-      // fifo overflow, here we assume FIFO is multiple of 4 and didn't check remaining before writing
-      if ( count != 4 ) break;
-
-      // updated written if succeeded
-      total_written = i;
+      // FIFO overflown, since we already check fifo remaining. It is probably race condition
+      TU_ASSERT(count == 4, i);
     }
-
-    i++;
   }
 
   write_flush(midi);
 
-  return total_written;
+  return i;
 }
 
 bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
 {
   midid_interface_t* midi = &_midid_itf[itf];
-  if (midi->itf_num == 0) {
-    return 0;
-  }
+  TU_VERIFY(midi->ep_in);
 
   if (tu_fifo_remaining(&midi->tx_ff) < 4) return false;
 
@@ -435,6 +430,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
   }
 
   p_midi->itf_num = desc_midi->bInterfaceNumber;
+  (void) p_midi->itf_num;
 
   // next descriptor
   drv_len += tu_desc_len(p_desc);

+ 12 - 8
src/class/msc/msc_device.c

@@ -37,6 +37,10 @@
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
+
+// Can be selectively disabled to reduce logging when troubleshooting other driver
+#define MSC_DEBUG   2
+
 enum
 {
   MSC_STAGE_CMD  = 0,
@@ -99,7 +103,7 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
 //--------------------------------------------------------------------+
 #if CFG_TUSB_DEBUG >= 2
 
-static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
+TU_ATTR_UNUSED static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
 {
   { .key = SCSI_CMD_TEST_UNIT_READY              , .data = "Test Unit Ready" },
   { .key = SCSI_CMD_INQUIRY                      , .data = "Inquiry" },
@@ -114,7 +118,7 @@ static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
   { .key = SCSI_CMD_WRITE_10                     , .data = "Write10" }
 };
 
-static tu_lookup_table_t const _msc_scsi_cmd_table =
+TU_ATTR_UNUSED static tu_lookup_table_t const _msc_scsi_cmd_table =
 {
   .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
   .items = _msc_scsi_cmd_lookup
@@ -232,8 +236,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       TU_ASSERT( event == XFER_RESULT_SUCCESS &&
                  xferred_bytes == sizeof(msc_cbw_t) && p_cbw->signature == MSC_CBW_SIGNATURE );
 
-      TU_LOG2("  SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
-      // TU_LOG2_MEM(p_cbw, xferred_bytes, 2);
+      TU_LOG(MSC_DEBUG, "  SCSI Command: %s\r\n", tu_lookup_find(&_msc_scsi_cmd_table, p_cbw->command[0]));
+      // TU_LOG_MEM(MSC_DEBUG, p_cbw, xferred_bytes, 2);
 
       p_csw->signature    = MSC_CSW_SIGNATURE;
       p_csw->tag          = p_cbw->tag;
@@ -305,8 +309,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
     break;
 
     case MSC_STAGE_DATA:
-      TU_LOG2("  SCSI Data\r\n");
-      //TU_LOG2_MEM(_mscd_buf, xferred_bytes, 2);
+      TU_LOG(MSC_DEBUG, "  SCSI Data\r\n");
+      //TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2);
 
       // OUT transfer, invoke callback if needed
       if ( !tu_bit_test(p_cbw->dir, 7) )
@@ -402,8 +406,8 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       // Wait for the Status phase to complete
       if( (ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t)) )
       {
-        TU_LOG2("  SCSI Status: %u\r\n", p_csw->status);
-        // TU_LOG2_MEM(p_csw, xferred_bytes, 2);
+        TU_LOG(MSC_DEBUG, "  SCSI Status: %u\r\n", p_csw->status);
+        // TU_LOG_MEM(MSC_DEBUG, p_csw, xferred_bytes, 2);
 
         // Invoke complete callback if defined
         // Note: There is racing issue with samd51 + qspi flash testing with arduino

+ 8 - 5
src/class/msc/msc_host.c

@@ -360,18 +360,22 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
 static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 
-bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length)
+uint16_t msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
 {
   TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
              MSC_PROTOCOL_BOT  == desc_itf->bInterfaceProtocol);
 
+  // msc driver length is fixed
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+  TU_ASSERT(drv_len <= max_len, 0);
+
   msch_interface_t* p_msc = get_itf(dev_addr);
   tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
 
   for(uint32_t i=0; i<2; i++)
   {
-    TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
-    TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+    TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer, 0);
+    TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc), 0);
 
     if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
     {
@@ -385,9 +389,8 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
   }
 
   p_msc->itf_num = desc_itf->bInterfaceNumber;
-  (*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
 
-  return true;
+  return drv_len;
 }
 
 bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)

+ 5 - 15
src/class/msc/msc_host.h

@@ -41,13 +41,6 @@
 #define CFG_TUH_MSC_MAXLUN  4
 #endif
 
-
-/** \addtogroup ClassDriver_MSC
- *  @{
- * \defgroup MSC_Host Host
- *  The interface API includes status checking function, data transferring function and callback functions
- *  @{ */
-
 typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
 
 //--------------------------------------------------------------------+
@@ -113,17 +106,14 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
 // Internal Class Driver API
 //--------------------------------------------------------------------+
 
-void msch_init(void);
-bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t *p_length);
-bool msch_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void msch_close(uint8_t dev_addr);
+void     msch_init       (void);
+uint16_t msch_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
+bool     msch_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool     msch_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void     msch_close      (uint8_t dev_addr);
 
 #ifdef __cplusplus
  }
 #endif
 
 #endif /* _TUSB_MSC_HOST_H_ */
-
-/// @}
-/// @}

+ 16 - 8
src/common/tusb_common.h

@@ -123,7 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { retur
 TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
 
 //------------- Mathematics -------------//
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); }
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
 
 /// inclusive range checking TODO remove
 TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
@@ -305,11 +305,11 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
 }
 
 // Log with Level
-#define TU_LOG(n, ...)        TU_LOG##n(__VA_ARGS__)
-#define TU_LOG_MEM(n, ...)    TU_LOG##n##_MEM(__VA_ARGS__)
-#define TU_LOG_VAR(n, ...)    TU_LOG##n##_VAR(__VA_ARGS__)
-#define TU_LOG_INT(n, ...)    TU_LOG##n##_INT(__VA_ARGS__)
-#define TU_LOG_HEX(n, ...)    TU_LOG##n##_HEX(__VA_ARGS__)
+#define TU_LOG(n, ...)        TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
+#define TU_LOG_MEM(n, ...)    TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
+#define TU_LOG_VAR(n, ...)    TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
+#define TU_LOG_INT(n, ...)    TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
+#define TU_LOG_HEX(n, ...)    TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
 #define TU_LOG_LOCATION()     tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
 #define TU_LOG_FAILED()       tu_printf("%s: %d: Failed\r\n", __PRETTY_FUNCTION__, __LINE__)
 
@@ -317,8 +317,8 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize)
 #define TU_LOG1               tu_printf
 #define TU_LOG1_MEM           tu_print_mem
 #define TU_LOG1_VAR(_x)       tu_print_var((uint8_t const*)(_x), sizeof(*(_x)))
-#define TU_LOG1_INT(_x)       tu_printf(#_x " = %ld\n", (uint32_t) (_x) )
-#define TU_LOG1_HEX(_x)       tu_printf(#_x " = %lX\n", (uint32_t) (_x) )
+#define TU_LOG1_INT(_x)       tu_printf(#_x " = %ld\r\n", (uint32_t) (_x) )
+#define TU_LOG1_HEX(_x)       tu_printf(#_x " = %lX\r\n", (uint32_t) (_x) )
 
 // Log Level 2: Warn
 #if CFG_TUSB_DEBUG >= 2
@@ -373,6 +373,14 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
 #endif
 
 // TODO replace all TU_LOGn with TU_LOG(n)
+
+#define TU_LOG0(...)
+#define TU_LOG0_MEM(...)
+#define TU_LOG0_VAR(...)
+#define TU_LOG0_INT(...)
+#define TU_LOG0_HEX(...)
+
+
 #ifndef TU_LOG1
   #define TU_LOG1(...)
   #define TU_LOG1_MEM(...)

+ 12 - 4
src/common/tusb_compiler.h

@@ -32,10 +32,14 @@
 #ifndef _TUSB_COMPILER_H_
 #define _TUSB_COMPILER_H_
 
-#define TU_STRING(x)      #x              ///< stringify without expand
-#define TU_XSTRING(x)     TU_STRING(x)    ///< expand then stringify
-#define TU_STRCAT(a, b)   a##b            ///< concat without expand
-#define TU_XSTRCAT(a, b)  TU_STRCAT(a, b) ///< expand then concat
+#define TU_STRING(x)          #x                  ///< stringify without expand
+#define TU_XSTRING(x)         TU_STRING(x)        ///< expand then stringify
+
+#define TU_STRCAT(a, b)       a##b                ///< concat without expand
+#define TU_STRCAT3(a, b, c)   a##b##c             ///< concat without expand
+
+#define TU_XSTRCAT(a, b)      TU_STRCAT(a, b)     ///< expand then concat
+#define TU_XSTRCAT3(a, b, c)  TU_STRCAT3(a, b, c) ///< expand then concat 3 tokens
 
 #if defined __COUNTER__ && __COUNTER__ != __COUNTER__
   #define _TU_COUNTER_ __COUNTER__
@@ -83,6 +87,10 @@
   #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
   #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
 
+  // List of obsolete callback function that is renamed and should not be defined.
+  // Put it here since only gcc support this pragma
+  #pragma GCC poison tud_vendor_control_request_cb
+
 #elif defined(__TI_COMPILER_VERSION__)
   #define TU_ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))
   #define TU_ATTR_SECTION(sec_name)     __attribute__ ((section(#sec_name)))

+ 2 - 2
src/common/tusb_fifo.c

@@ -325,7 +325,7 @@ static uint16_t advance_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
   // We are exploiting the wrap around to the correct index
 
   // TODO warning: assuming signed overflow does not occur when assuming that (X + c) < X is always false [-Wstrict-overflow]
-  if ((p > p + offset) || (p + offset > f->max_pointer_idx))
+  if ((p > (uint16_t)(p + offset)) || ((uint16_t)(p + offset) > f->max_pointer_idx))
   {
     p = (p + offset) + f->non_used_index_space;
   }
@@ -342,7 +342,7 @@ static uint16_t backward_pointer(tu_fifo_t* f, uint16_t p, uint16_t offset)
   // We limit the index space of p such that a correct wrap around happens
   // Check for a wrap around or if we are in unused index space - This has to be checked first!!
   // We are exploiting the wrap around to the correct index
-  if ((p < p - offset) || (p - offset > f->max_pointer_idx))
+  if ((p < (uint16_t)(p - offset)) || ((uint16_t)(p - offset) > f->max_pointer_idx))
   {
     p = (p - offset) - f->non_used_index_space;
   }

+ 2 - 2
src/common/tusb_fifo.h

@@ -86,8 +86,8 @@ typedef struct
   .depth                = _depth,                           \
   .item_size            = sizeof(_type),                    \
   .overwritable         = _overwritable,                    \
-  .max_pointer_idx      = 2*(_depth)-1,                     \
   .non_used_index_space = UINT16_MAX - (2*(_depth)-1),      \
+  .max_pointer_idx      = 2*(_depth)-1,                     \
 }
 
 #define TU_FIFO_DEF(_name, _depth, _type, _overwritable)                      \
@@ -120,9 +120,9 @@ bool     tu_fifo_peek                   (tu_fifo_t* f, void * p_buffer);
 uint16_t tu_fifo_peek_n                 (tu_fifo_t* f, void * p_buffer, uint16_t n);
 
 uint16_t tu_fifo_count                  (tu_fifo_t* f);
+uint16_t tu_fifo_remaining              (tu_fifo_t* f);
 bool     tu_fifo_empty                  (tu_fifo_t* f);
 bool     tu_fifo_full                   (tu_fifo_t* f);
-uint16_t tu_fifo_remaining              (tu_fifo_t* f);
 bool     tu_fifo_overflowed             (tu_fifo_t* f);
 void     tu_fifo_correct_read_pointer   (tu_fifo_t* f);
 

+ 1 - 1
src/common/tusb_verify.h

@@ -75,7 +75,7 @@
 #if CFG_TUSB_DEBUG
   #include <stdio.h>
   #define _MESS_ERR(_err)   tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err])
-  #define _MESS_FAILED()    tu_printf("%s %d: assert failed\r\n", __func__, __LINE__)
+  #define _MESS_FAILED()    tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
 #else
   #define _MESS_ERR(_err) do {} while (0)
   #define _MESS_FAILED() do {} while (0)

+ 2 - 3
src/device/usbd.c

@@ -1243,7 +1243,7 @@ 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);
+  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 +1254,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;
   }

+ 5 - 0
src/device/usbd.h

@@ -542,6 +542,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

+ 1 - 0
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;

+ 17 - 14
src/host/hub.c

@@ -144,29 +144,32 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
 //--------------------------------------------------------------------+
 void hub_init(void)
 {
-  tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof( hub_interface_t));
+  tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(hub_interface_t));
 }
 
-bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length)
+uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
 {
-  // not support multiple TT yet
-  if ( itf_desc->bInterfaceProtocol > 1 ) return false;
+  // hub driver does not support multiple TT yet
+  TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
+            0              == itf_desc->bInterfaceSubClass &&
+            1              <= itf_desc->bInterfaceProtocol, 0);
 
-  //------------- Open Interrupt Status Pipe -------------//
-  tusb_desc_endpoint_t const *ep_desc;
-  ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+  // msc driver length is fixed
+  uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+  TU_ASSERT(drv_len <= max_len, 0);
 
-  TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType);
-  TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer);
+  //------------- Interrupt Status endpoint -------------//
+  tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
+
+  TU_ASSERT(TUSB_DESC_ENDPOINT  == desc_ep->bDescriptorType &&
+            TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
   
-  TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
+  TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
 
   hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
-  hub_data[dev_addr-1].ep_in   = ep_desc->bEndpointAddress;
-
-  (*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
+  hub_data[dev_addr-1].ep_in   = desc_ep->bEndpointAddress;
 
-  return true;
+  return drv_len;
 }
 
 void hub_close(uint8_t dev_addr)

+ 5 - 5
src/host/hub.h

@@ -181,11 +181,11 @@ bool hub_status_pipe_queue(uint8_t dev_addr);
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void hub_init(void);
-bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length);
-bool hub_set_config(uint8_t dev_addr, uint8_t itf_num);
-bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void hub_close(uint8_t dev_addr);
+void     hub_init       (void);
+uint16_t hub_open       (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
+bool     hub_set_config (uint8_t dev_addr, uint8_t itf_num);
+bool     hub_xfer_cb    (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+void     hub_close      (uint8_t dev_addr);
 
 #ifdef __cplusplus
  }

+ 47 - 39
src/host/usbh.c

@@ -130,7 +130,7 @@ CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1];
 OSAL_QUEUE_DEF(OPT_MODE_HOST, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
 static osal_queue_t _usbh_q;
 
-CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
 
 //------------- Helper Function Prototypes -------------//
 static bool enum_new_device(hcd_event_t* event);
@@ -795,6 +795,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
     return false;
   }
 
+  TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE);
+
   // Reset device again before Set Address
   TU_LOG2("Port reset \r\n");
 
@@ -907,7 +909,7 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
   // Use offsetof to avoid pointer to the odd/misaligned address
   memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2);
 
-  TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSZIE);
+  TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
 
   // Get full configuration descriptor
   TU_LOG2("Get Configuration Descriptor\r\n");
@@ -938,7 +940,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
 
   // Parse configuration & set up drivers
   // Driver open aren't allowed to make any usb transfer yet
-  parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf);
+  TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
 
   TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
   tusb_control_request_t const new_request =
@@ -982,55 +984,61 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
 static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
 {
   usbh_device_t* dev = &_usbh_devices[dev_addr];
-  uint8_t const* p_desc = (uint8_t const*) desc_cfg;
-  p_desc = tu_desc_next(p_desc);
+
+  uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
+  uint8_t const* p_desc   = tu_desc_next(desc_cfg);
 
   // parse each interfaces
-  while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength )
+  while( p_desc < desc_end )
   {
-    // skip until we see interface descriptor
-    if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) )
+    // TODO Do we need to use IAD
+    // tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
+
+    // Class will always starts with Interface Association (if any) and then Interface descriptor
+    if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
     {
-      p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length
-    }else
+      // desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
+      p_desc = tu_desc_next(p_desc);
+    }
+
+    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;
+
+    // Check if class is supported TODO drop class_code
+    uint8_t drv_id;
+    for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
     {
-      tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
+      if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
+    }
 
-      // Check if class is supported
-      uint8_t drv_id;
-      for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
-      {
-        if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
-      }
+    if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+    {
+      // skip unsupported class
+      p_desc = tu_desc_next(p_desc);
+    }
+    else
+    {
+      usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
 
-      if( drv_id >= USBH_CLASS_DRIVER_COUNT )
+      // Interface number must not be used already TODO alternate interface
+      TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
+      dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
+
+      if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
       {
-        // skip unsupported class
+        // TODO Attach hub to Hub is not currently supported
+        // skip this interface
         p_desc = tu_desc_next(p_desc);
       }
       else
       {
-        usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
-
-        // Interface number must not be used already TODO alternate interface
-        TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
-        dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
+        TU_LOG2("%s open\r\n", driver->name);
 
-        if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
-        {
-          // TODO Attach hub to Hub is not currently supported
-          // skip this interface
-          p_desc = tu_desc_next(p_desc);
-        }
-        else
-        {
-          TU_LOG2("%s open\r\n", driver->name);
-
-          uint16_t itf_len = 0;
-          TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) );
-          TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) );
-          p_desc += itf_len;
-        }
+        uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
+        TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
+        p_desc += itf_len;
       }
     }
   }

+ 5 - 5
src/host/usbh_classdriver.h

@@ -45,11 +45,11 @@ typedef struct {
 
   uint8_t class_code;
 
-  void (* const init       )(void);
-  bool (* const open       )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen);
-  bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
-  bool (* const xfer_cb    )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
-  void (* const close      )(uint8_t dev_addr);
+  void     (* const init       )(void);
+  uint16_t (* const open       )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
+  bool     (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
+  bool     (* const xfer_cb    )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+  void     (* const close      )(uint8_t dev_addr);
 } usbh_class_driver_t;
 
 // Call by class driver to tell USBH that it has complete the enumeration

+ 3 - 3
src/host/usbh_control.c

@@ -50,7 +50,7 @@ typedef struct
 static usbh_control_xfer_t _ctrl_xfer;
 
 //CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
-//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSZIE];
+//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
 
 //--------------------------------------------------------------------+
 // MACRO TYPEDEF CONSTANT ENUM DECLARATION
@@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request,
   _ctrl_xfer.stage       = STAGE_SETUP;
   _ctrl_xfer.complete_cb = complete_cb;
 
-  TU_LOG2("Control Setup: ");
+  TU_LOG2("Control Setup (addr = %u): ", dev_addr);
   TU_LOG2_VAR(request);
   TU_LOG2("\r\n");
 
@@ -119,7 +119,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu
 
         if (request->wLength)
         {
-          TU_LOG2("Control data:\r\n");
+          TU_LOG2("Control data (addr = %u):\r\n", dev_addr);
           TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2);
         }
 

+ 2 - 2
src/portable/microchip/samd/dcd_samd.c

@@ -29,7 +29,7 @@
 #if TUSB_OPT_DEVICE_ENABLED && \
     (CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
      CFG_TUSB_MCU == OPT_MCU_SAMD51 || CFG_TUSB_MCU == OPT_MCU_SAME5X || \
-     CFG_TUSB_MCU == OPT_MCU_SAML22)
+     CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21)
 
 #include "sam.h"
 #include "device/dcd.h"
@@ -125,7 +125,7 @@ void dcd_int_disable(uint8_t rhport)
 }
 
 #elif CFG_TUSB_MCU == OPT_MCU_SAMD11 || CFG_TUSB_MCU == OPT_MCU_SAMD21 || \
-      CFG_TUSB_MCU == OPT_MCU_SAML22
+      CFG_TUSB_MCU == OPT_MCU_SAML22 || CFG_TUSB_MCU == OPT_MCU_SAML21
 
 void dcd_int_enable(uint8_t rhport)
 {

Некоторые файлы не были показаны из-за большого количества измененных файлов