Преглед изворни кода

Merge pull request #89 from hathach/develop

resolve #35 (vendor class), implement #86 (webusb)
hathach пре 6 година
родитељ
комит
1e7f1de4d7
53 измењених фајлова са 1675 додато и 578 уклоњено
  1. 3 0
      .gitignore
  2. 2 0
      changelog.md
  3. 3 10
      examples/device/cdc_msc_hid/src/main.c
  4. 11 11
      examples/device/cdc_msc_hid/src/tusb_config.h
  5. 25 20
      examples/device/cdc_msc_hid/src/usb_descriptors.c
  6. 34 0
      examples/device/cdc_msc_hid/src/usb_descriptors.h
  7. 2 7
      examples/device/cdc_msc_hid_freertos/src/main.c
  8. 11 11
      examples/device/cdc_msc_hid_freertos/src/tusb_config.h
  9. 25 20
      examples/device/cdc_msc_hid_freertos/src/usb_descriptors.c
  10. 34 0
      examples/device/cdc_msc_hid_freertos/src/usb_descriptors.h
  11. 1 3
      examples/device/hid_generic_inout/src/main.c
  12. 8 8
      examples/device/hid_generic_inout/src/tusb_config.h
  13. 34 26
      examples/device/hid_generic_inout/src/usb_descriptors.c
  14. 4 6
      examples/device/midi_test/src/main.c
  15. 9 9
      examples/device/midi_test/src/tusb_config.h
  16. 24 20
      examples/device/midi_test/src/usb_descriptors.c
  17. 1 3
      examples/device/msc_dual_lun/src/main.c
  18. 8 8
      examples/device/msc_dual_lun/src/tusb_config.h
  19. 20 15
      examples/device/msc_dual_lun/src/usb_descriptors.c
  20. 12 0
      examples/device/webusb_serial/Makefile
  21. 276 0
      examples/device/webusb_serial/src/main.c
  22. 95 0
      examples/device/webusb_serial/src/tusb_config.h
  23. 237 0
      examples/device/webusb_serial/src/usb_descriptors.c
  24. 36 0
      examples/device/webusb_serial/src/usb_descriptors.h
  25. 5 19
      examples/host/cdc_msc_hid/src/tusb_config.h
  26. 2 1
      examples/rules.mk
  27. 4 4
      src/class/cdc/cdc_device.c
  28. 6 6
      src/class/cdc/cdc_device.h
  29. 0 93
      src/class/custom/custom_device.c
  30. 0 58
      src/class/custom/custom_device.h
  31. 8 8
      src/class/hid/hid_device.c
  32. 6 6
      src/class/hid/hid_device.h
  33. 2 2
      src/class/hid/hid_host.h
  34. 11 7
      src/class/midi/midi_device.c
  35. 6 6
      src/class/midi/midi_device.h
  36. 5 5
      src/class/msc/msc_device.c
  37. 6 6
      src/class/msc/msc_device.h
  38. 214 0
      src/class/vendor/vendor_device.c
  39. 121 0
      src/class/vendor/vendor_device.h
  40. 2 2
      src/class/vendor/vendor_host.c
  41. 3 3
      src/class/vendor/vendor_host.h
  42. 3 2
      src/common/tusb_common.h
  43. 91 29
      src/common/tusb_types.h
  44. 21 21
      src/common/tusb_verify.h
  45. 132 84
      src/device/usbd.c
  46. 76 6
      src/device/usbd.h
  47. 4 4
      src/device/usbd_control.c
  48. 3 9
      src/device/usbd_pvt.h
  49. 1 1
      src/host/usbh.c
  50. 4 4
      src/tusb.h
  51. 2 2
      src/tusb_option.h
  52. 11 11
      test/test/support/tusb_config.h
  53. 11 2
      tools/build_all.py

+ 3 - 0
.gitignore

@@ -6,9 +6,12 @@ test/_build
 *.P
 *.map
 *.axf
+*.bin
 *.jlink
 *.emSession
 *.elf
 *.ind
 .env
 /examples/*/*/build-*
+test_old/
+tests_obsolete/

+ 2 - 0
changelog.md

@@ -1,5 +1,7 @@
 # TinyUSB changelog
 
+## New Release
+
 ## 0.5.0 (Initial Release) - 2019.07.10
 
 First release, device stack works great, host stack works but still need improvement. 

+ 3 - 10
examples/device/cdc_msc_hid/src/main.c

@@ -30,6 +30,8 @@
 #include "bsp/board.h"
 #include "tusb.h"
 
+#include "usb_descriptors.h"
+
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF PROTYPES
 //--------------------------------------------------------------------+
@@ -61,9 +63,7 @@ int main(void)
 
   while (1)
   {
-    // tinyusb device task
-    tud_task();
-
+    tud_task(); // tinyusb device task
     led_blinking_task();
 
 #if CFG_TUD_CDC
@@ -164,13 +164,6 @@ void tud_cdc_rx_cb(uint8_t itf)
 //--------------------------------------------------------------------+
 #if CFG_TUD_HID
 
-// Must match with ID declared by HID Report Descriptor, better to be in header file
-enum
-{
-  REPORT_ID_KEYBOARD = 1,
-  REPORT_ID_MOUSE
-};
-
 void hid_task(void)
 {
   // Poll every 10ms

+ 11 - 11
examples/device/cdc_msc_hid/src/tusb_config.h

@@ -62,32 +62,32 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE    64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 1
-#define CFG_TUD_MSC                 1
-#define CFG_TUD_HID                 1
+#define CFG_TUD_CDC              1
+#define CFG_TUD_MSC              1
+#define CFG_TUD_HID              1
 
-#define CFG_TUD_MIDI                0
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_MIDI             0
+#define CFG_TUD_VENDOR           0
 
 // CDC FIFO size of TX and RX
-#define CFG_TUD_CDC_RX_BUFSIZE      64
-#define CFG_TUD_CDC_TX_BUFSIZE      64
+#define CFG_TUD_CDC_RX_BUFSIZE   64
+#define CFG_TUD_CDC_TX_BUFSIZE   64
 
 // MSC Buffer size of Device Mass storage
-#define CFG_TUD_MSC_BUFSIZE         512
+#define CFG_TUD_MSC_BUFSIZE      512
 
 // HID buffer size Should be sufficient to hold ID (if any) + Data
-#define CFG_TUD_HID_BUFSIZE         16
+#define CFG_TUD_HID_BUFSIZE      16
 
 #ifdef __cplusplus
  }

+ 25 - 20
examples/device/cdc_msc_hid/src/usb_descriptors.c

@@ -24,6 +24,7 @@
  */
 
 #include "tusb.h"
+#include "usb_descriptors.h"
 
 /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
  * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
@@ -32,9 +33,12 @@
  *   [MSB]         HID | MSC | CDC          [LSB]
  */
 #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
-#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
 
-//------------- Device Descriptors -------------//
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
 tusb_desc_device_t const desc_device =
 {
     .bLength            = sizeof(tusb_desc_device_t),
@@ -66,13 +70,17 @@ tusb_desc_device_t const desc_device =
     .bNumConfigurations = 0x01
 };
 
-//------------- HID Report Descriptor -------------//
-#if CFG_TUD_HID
-enum
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
 {
-  REPORT_ID_KEYBOARD = 1,
-  REPORT_ID_MOUSE
-};
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// HID Report Descriptor
+//--------------------------------------------------------------------+
+#if CFG_TUD_HID
 
 uint8_t const desc_hid_report[] =
 {
@@ -90,7 +98,10 @@ uint8_t const * tud_hid_descriptor_report_cb(void)
 
 #endif
 
-//------------- Configuration Descriptor -------------//
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
 enum
 {
 #if CFG_TUD_CDC
@@ -109,10 +120,7 @@ enum
   ITF_NUM_TOTAL
 };
 
-enum
-{
-  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC*TUD_CDC_DESC_LEN + CFG_TUD_MSC*TUD_MSC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN
-};
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC*TUD_CDC_DESC_LEN + CFG_TUD_MSC*TUD_MSC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN)
 
 #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
   // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -145,12 +153,6 @@ uint8_t const desc_configuration[] =
 #endif
 };
 
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
-  return (uint8_t const *) &desc_device;
-}
 
 // Invoked when received GET CONFIGURATION DESCRIPTOR
 // Application return pointer to descriptor
@@ -160,7 +162,10 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
   (void) index; // for multiple configurations
   return desc_configuration;
 }
-//------------- String Descriptors -------------//
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
 
 // array of pointer to string descriptors
 char const* string_desc_arr [] =

+ 34 - 0
examples/device/cdc_msc_hid/src/usb_descriptors.h

@@ -0,0 +1,34 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+enum
+{
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE
+};
+
+#endif /* USB_DESCRIPTORS_H_ */

+ 2 - 7
examples/device/cdc_msc_hid_freertos/src/main.c

@@ -36,6 +36,8 @@
 #include "bsp/board.h"
 #include "tusb.h"
 
+#include "usb_descriptors.h"
+
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF PROTYPES
 //--------------------------------------------------------------------+
@@ -194,13 +196,6 @@ void tud_cdc_rx_cb(uint8_t itf)
 //--------------------------------------------------------------------+
 #if CFG_TUD_HID
 
-// Must match with ID declared by HID Report Descriptor, better to be in header file
-enum
-{
-  REPORT_ID_KEYBOARD = 1,
-  REPORT_ID_MOUSE
-};
-
 void hid_task(void* params)
 {
   (void) params;

+ 11 - 11
examples/device/cdc_msc_hid_freertos/src/tusb_config.h

@@ -62,32 +62,32 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE    64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 1
-#define CFG_TUD_MSC                 1
-#define CFG_TUD_HID                 1
+#define CFG_TUD_CDC              1
+#define CFG_TUD_MSC              1
+#define CFG_TUD_HID              1
 
-#define CFG_TUD_MIDI                0
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_MIDI             0
+#define CFG_TUD_VENDOR           0
 
 // CDC FIFO size of TX and RX
-#define CFG_TUD_CDC_RX_BUFSIZE      64
-#define CFG_TUD_CDC_TX_BUFSIZE      64
+#define CFG_TUD_CDC_RX_BUFSIZE   64
+#define CFG_TUD_CDC_TX_BUFSIZE   64
 
 // MSC Buffer size of Device Mass storage
-#define CFG_TUD_MSC_BUFSIZE         512
+#define CFG_TUD_MSC_BUFSIZE      512
 
 // HID buffer size Should be sufficient to hold ID (if any) + Data
-#define CFG_TUD_HID_BUFSIZE         16
+#define CFG_TUD_HID_BUFSIZE      16
 
 #ifdef __cplusplus
  }

+ 25 - 20
examples/device/cdc_msc_hid_freertos/src/usb_descriptors.c

@@ -24,6 +24,7 @@
  */
 
 #include "tusb.h"
+#include "usb_descriptors.h"
 
 /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
  * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
@@ -32,9 +33,12 @@
  *   [MSB]         HID | MSC | CDC          [LSB]
  */
 #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
-#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
 
-//------------- Device Descriptors -------------//
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
 tusb_desc_device_t const desc_device =
 {
     .bLength            = sizeof(tusb_desc_device_t),
@@ -66,13 +70,17 @@ tusb_desc_device_t const desc_device =
     .bNumConfigurations = 0x01
 };
 
-//------------- HID Report Descriptor -------------//
-#if CFG_TUD_HID
-enum
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
 {
-  REPORT_ID_KEYBOARD = 1,
-  REPORT_ID_MOUSE
-};
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// HID Report Descriptor
+//--------------------------------------------------------------------+
+#if CFG_TUD_HID
 
 uint8_t const desc_hid_report[] =
 {
@@ -90,7 +98,10 @@ uint8_t const * tud_hid_descriptor_report_cb(void)
 
 #endif
 
-//------------- Configuration Descriptor -------------//
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
 enum
 {
 #if CFG_TUD_CDC
@@ -109,10 +120,7 @@ enum
   ITF_NUM_TOTAL
 };
 
-enum
-{
-  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + CFG_TUD_CDC*TUD_CDC_DESC_LEN + CFG_TUD_MSC*TUD_MSC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN
-};
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC*TUD_CDC_DESC_LEN + CFG_TUD_MSC*TUD_MSC_DESC_LEN + CFG_TUD_HID*TUD_HID_DESC_LEN)
 
 #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
   // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -145,12 +153,7 @@ uint8_t const desc_configuration[] =
 #endif
 };
 
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
-  return (uint8_t const *) &desc_device;
-}
+
 
 // Invoked when received GET CONFIGURATION DESCRIPTOR
 // Application return pointer to descriptor
@@ -161,7 +164,9 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
   return desc_configuration;
 }
 
-//------------- String Descriptors -------------//
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
 
 // array of pointer to string descriptors
 char const* string_desc_arr [] =

+ 34 - 0
examples/device/cdc_msc_hid_freertos/src/usb_descriptors.h

@@ -0,0 +1,34 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+enum
+{
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE
+};
+
+#endif /* USB_DESCRIPTORS_H_ */

+ 1 - 3
examples/device/hid_generic_inout/src/main.c

@@ -76,9 +76,7 @@ int main(void)
 
   while (1)
   {
-    // tinyusb device task
-    tud_task();
-
+    tud_task(); // tinyusb device task
     led_blinking_task();
   }
 

+ 8 - 8
examples/device/hid_generic_inout/src/tusb_config.h

@@ -62,24 +62,24 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE   64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 0
-#define CFG_TUD_MSC                 0
-#define CFG_TUD_HID                 1
-#define CFG_TUD_MIDI                0
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_CDC             0
+#define CFG_TUD_MSC             0
+#define CFG_TUD_HID             1
+#define CFG_TUD_MIDI            0
+#define CFG_TUD_VENDOR          0
 
 // HID buffer size Should be sufficient to hold ID (if any) + Data
-#define CFG_TUD_HID_BUFSIZE         64
+#define CFG_TUD_HID_BUFSIZE     64
 
 #ifdef __cplusplus
  }

+ 34 - 26
examples/device/hid_generic_inout/src/usb_descriptors.c

@@ -32,9 +32,12 @@
  *   [MSB]         HID | MSC | CDC          [LSB]
  */
 #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
-#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
 
-//------------- Device Descriptors -------------//
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
 tusb_desc_device_t const desc_device =
 {
     .bLength            = sizeof(tusb_desc_device_t),
@@ -56,23 +59,42 @@ tusb_desc_device_t const desc_device =
     .bNumConfigurations = 0x01
 };
 
-//------------- HID Report Descriptor -------------//
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// HID Report Descriptor
+//--------------------------------------------------------------------+
+
 uint8_t const desc_hid_report[] =
 {
   TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_BUFSIZE)
 };
 
-//------------- Configuration Descriptor -------------//
+// Invoked when received GET HID REPORT DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_hid_descriptor_report_cb(void)
+{
+  return desc_hid_report;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
 enum
 {
   ITF_NUM_HID,
   ITF_NUM_TOTAL
 };
 
-enum
-{
-  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN
-};
+
+#define  CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
 
 // Use Endpoint 2 instead of 1 due to NXP MCU
 // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -85,17 +107,9 @@ uint8_t const desc_configuration[] =
   TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
   // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
-  TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), 0x80 | EPNUM_HID, EPNUM_HID, CFG_TUD_HID_BUFSIZE, 10)
+  TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_BUFSIZE, 10)
 };
 
-
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
-  return (uint8_t const *) &desc_device;
-}
-
 // Invoked when received GET CONFIGURATION DESCRIPTOR
 // Application return pointer to descriptor
 // Descriptor contents must exist long enough for transfer to complete
@@ -105,15 +119,9 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
   return desc_configuration;
 }
 
-// Invoked when received GET HID REPORT DESCRIPTOR
-// Application return pointer to descriptor
-// Descriptor contents must exist long enough for transfer to complete
-uint8_t const * tud_hid_descriptor_report_cb(void)
-{
-  return desc_hid_report;
-}
-
-//------------- String Descriptors -------------//
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
 
 // array of pointer to string descriptors
 char const* string_desc_arr [] =

+ 4 - 6
examples/device/midi_test/src/main.c

@@ -32,8 +32,9 @@
 
 /* This MIDI example send sequence of note (on/off) repeatedly. To test on PC, you need to install
  * synth software and midi connection management software. On
- * - Linux (Ubuntu) : install qsynth, qjackctl. Then connect TinyUSB output port to FLUID Synth input port
- *
+ * - Linux (Ubuntu): install qsynth, qjackctl. Then connect TinyUSB output port to FLUID Synth input port
+ * - Windows: install MIDI-OX
+ * - MacOS: SimpleSynth
  */
 
 //--------------------------------------------------------------------+
@@ -65,11 +66,8 @@ int main(void)
 
   while (1)
   {
-    // tinyusb device task
-    tud_task();
-
+    tud_task(); // tinyusb device task
     led_blinking_task();
-
     midi_task();
   }
 

+ 9 - 9
examples/device/midi_test/src/tusb_config.h

@@ -62,25 +62,25 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE     64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 0
-#define CFG_TUD_MSC                 0
-#define CFG_TUD_HID                 0
-#define CFG_TUD_MIDI                1
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_CDC               0
+#define CFG_TUD_MSC               0
+#define CFG_TUD_HID               0
+#define CFG_TUD_MIDI              1
+#define CFG_TUD_VENDOR            0
 
 // MIDI FIFO size of TX and RX
-#define CFG_TUD_MIDI_RX_BUFSIZE     64
-#define CFG_TUD_MIDI_TX_BUFSIZE     64
+#define CFG_TUD_MIDI_RX_BUFSIZE   64
+#define CFG_TUD_MIDI_TX_BUFSIZE   64
 
 #ifdef __cplusplus
  }

+ 24 - 20
examples/device/midi_test/src/usb_descriptors.c

@@ -32,19 +32,20 @@
  *   [MSB]       MIDI | HID | MSC | CDC          [LSB]
  */
 #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
-#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
 
-//------------- Device Descriptors -------------//
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
 tusb_desc_device_t const desc_device =
 {
     .bLength            = sizeof(tusb_desc_device_t),
     .bDescriptorType    = TUSB_DESC_DEVICE,
     .bcdUSB             = 0x0200,
-    // Use Interface Association Descriptor (IAD) for Audio
-    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
-    .bDeviceClass       = TUSB_CLASS_MISC,
-    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
-    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
+    .bDeviceClass       = 0x00,
+    .bDeviceSubClass    = 0x00,
+    .bDeviceProtocol    = 0x00,
     .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
 
     .idVendor           = 0xCafe,
@@ -58,7 +59,18 @@ tusb_desc_device_t const desc_device =
     .bNumConfigurations = 0x01
 };
 
-//------------- Configuration Descriptor -------------//
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
 enum
 {
   ITF_NUM_MIDI = 0,
@@ -66,10 +78,7 @@ enum
   ITF_NUM_TOTAL
 };
 
-enum
-{
-  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + TUD_MIDI_DESC_LEN
-};
+#define CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_MIDI_DESC_LEN)
 
 #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
   // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -88,13 +97,6 @@ uint8_t const desc_configuration[] =
   TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64)
 };
 
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
-  return (uint8_t const *) &desc_device;
-}
-
 // Invoked when received GET CONFIGURATION DESCRIPTOR
 // Application return pointer to descriptor
 // Descriptor contents must exist long enough for transfer to complete
@@ -104,7 +106,9 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
   return desc_configuration;
 }
 
-//------------- String Descriptors -------------//
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
 
 // array of pointer to string descriptors
 char const* string_desc_arr [] =

+ 1 - 3
examples/device/msc_dual_lun/src/main.c

@@ -58,9 +58,7 @@ int main(void)
 
   while (1)
   {
-    // tinyusb device task
-    tud_task();
-
+    tud_task(); // tinyusb device task
     led_blinking_task();
   }
 

+ 8 - 8
examples/device/msc_dual_lun/src/tusb_config.h

@@ -62,24 +62,24 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE   64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 0
-#define CFG_TUD_MSC                 1
-#define CFG_TUD_HID                 0
-#define CFG_TUD_MIDI                0
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_CDC             0
+#define CFG_TUD_MSC             1
+#define CFG_TUD_HID             0
+#define CFG_TUD_MIDI            0
+#define CFG_TUD_VENDOR          0
 
 // MSC Buffer size of Device Mass storage
-#define CFG_TUD_MSC_BUFSIZE         512
+#define CFG_TUD_MSC_BUFSIZE     512
 
 #ifdef __cplusplus
  }

+ 20 - 15
examples/device/msc_dual_lun/src/usb_descriptors.c

@@ -32,9 +32,12 @@
  *   [MSB]         HID | MSC | CDC          [LSB]
  */
 #define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
-#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
 
-//------------- Device Descriptors -------------//
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
 tusb_desc_device_t const desc_device =
 {
     .bLength            = sizeof(tusb_desc_device_t),
@@ -56,17 +59,24 @@ tusb_desc_device_t const desc_device =
     .bNumConfigurations = 0x01
 };
 
-//------------- Configuration Descriptor -------------//
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+
 enum
 {
   ITF_NUM_MSC,
   ITF_NUM_TOTAL
 };
 
-enum
-{
-  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN
-};
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)
 
 #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
   // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -85,13 +95,6 @@ uint8_t const desc_configuration[] =
   TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC, 0x80 | EPNUM_MSC, (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64),
 };
 
-// Invoked when received GET DEVICE DESCRIPTOR
-// Application return pointer to descriptor
-uint8_t const * tud_descriptor_device_cb(void)
-{
-  return (uint8_t const *) &desc_device;
-}
-
 // Invoked when received GET CONFIGURATION DESCRIPTOR
 // Application return pointer to descriptor
 // Descriptor contents must exist long enough for transfer to complete
@@ -101,7 +104,9 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
   return desc_configuration;
 }
 
-//------------- String Descriptors -------------//
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
 
 // array of pointer to string descriptors
 char const* string_desc_arr [] =

+ 12 - 0
examples/device/webusb_serial/Makefile

@@ -0,0 +1,12 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+  src \
+  $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += $(wildcard src/*.c)
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../rules.mk

+ 276 - 0
examples/device/webusb_serial/src/main.c

@@ -0,0 +1,276 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+#include "usb_descriptors.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+/* Blink pattern
+ * - 250 ms  : device not mounted
+ * - 1000 ms : device mounted
+ * - 2500 ms : device is suspended
+ */
+enum  {
+  BLINK_NOT_MOUNTED = 250,
+  BLINK_MOUNTED     = 1000,
+  BLINK_SUSPENDED   = 2500,
+
+  BLINK_ALWAYS_ON   = UINT32_MAX,
+  BLINK_ALWAYS_OFF  = 0
+};
+
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+
+#define URL  "www.tinyusb.org/examples/webusb-serial"
+
+const tusb_desc_webusb_url_t desc_url =
+{
+  .bLength         = 3 + sizeof(URL) - 1,
+  .bDescriptorType = 3, // WEBUSB URL type
+  .bScheme         = 1, // 0: http, 1: https
+  .url             = URL
+};
+
+static bool web_serial_connected = false;
+
+//------------- prototypes -------------//
+void led_blinking_task(void);
+void cdc_task(void);
+void webserial_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+  board_init();
+
+  tusb_init();
+
+  while (1)
+  {
+    tud_task(); // tinyusb device task
+    cdc_task();
+    webserial_task();
+    led_blinking_task();
+  }
+
+  return 0;
+}
+
+// send characters to both CDC and WebUSB
+void echo_all(uint8_t buf[], uint32_t count)
+{
+  // echo to web serial
+  if ( web_serial_connected )
+  {
+    tud_vendor_write(buf, count);
+  }
+
+  // echo to cdc
+  if ( tud_cdc_connected() )
+  {
+    for(uint32_t i=0; i<count; i++)
+    {
+      tud_cdc_write_char(buf[i]);
+
+      if ( buf[i] == '\r' ) tud_cdc_write_char('\n');
+    }
+    tud_cdc_write_flush();
+  }
+}
+
+//--------------------------------------------------------------------+
+// Device callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void)
+{
+  blink_interval_ms = BLINK_NOT_MOUNTED;
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us  to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en)
+{
+  (void) remote_wakeup_en;
+  blink_interval_ms = BLINK_SUSPENDED;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// WebUSB use vendor class
+//--------------------------------------------------------------------+
+
+// Invoked when received VENDOR control request
+bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request)
+{
+  switch (request->bRequest)
+  {
+    case VENDOR_REQUEST_WEBUSB:
+      // match vendor request in BOS descriptor
+      // Get landing page url
+      return tud_control_xfer(rhport, request, (void*) &desc_url, desc_url.bLength);
+
+    case VENDOR_REQUEST_MICROSOFT:
+      if ( request->wIndex == 7 )
+      {
+        // Get Microsoft OS 2.0 compatible descriptor
+        uint16_t total_len;
+        memcpy(&total_len, desc_ms_os_20+8, 2);
+
+        return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len);
+      }else
+      {
+        return false;
+      }
+
+    case 0x22:
+      // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to
+      // connect and disconnect.
+      web_serial_connected = (request->wValue != 0);
+
+      // Always lit LED if connected
+      if ( web_serial_connected )
+      {
+        board_led_write(true);
+        blink_interval_ms = BLINK_ALWAYS_ON;
+
+        tud_vendor_write_str("\r\nTinyUSB WebUSB device example\r\n");
+      }else
+      {
+        blink_interval_ms = BLINK_MOUNTED;
+      }
+
+      // response with status OK
+      return tud_control_status(rhport, request);
+
+    default:
+      // stall unknown request
+      return false;
+  }
+
+  return true;
+}
+
+// Invoked when DATA Stage of VENDOR's request is complete
+bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request)
+{
+  (void) rhport;
+  (void) request;
+
+  // nothing to do
+  return true;
+}
+
+void webserial_task(void)
+{
+  if ( web_serial_connected )
+  {
+    if ( tud_vendor_available() )
+    {
+      uint8_t buf[64];
+      uint32_t count = tud_vendor_read(buf, sizeof(buf));
+
+      // echo back to both web serial and cdc
+      echo_all(buf, count);
+    }
+  }
+}
+
+
+//--------------------------------------------------------------------+
+// USB CDC
+//--------------------------------------------------------------------+
+void cdc_task(void)
+{
+  if ( tud_cdc_connected() )
+  {
+    // connected and there are data available
+    if ( tud_cdc_available() )
+    {
+      uint8_t buf[64];
+
+      uint32_t count = tud_cdc_read(buf, sizeof(buf));
+
+      // echo back to both web serial and cdc
+      echo_all(buf, count);
+    }
+  }
+}
+
+// Invoked when cdc when line state changed e.g connected/disconnected
+void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
+{
+  (void) itf;
+
+  // connected
+  if ( dtr && rts )
+  {
+    // print initial message when connected
+    tud_cdc_write_str("\r\nTinyUSB WebUSB device example\r\n");
+  }
+}
+
+// Invoked when CDC interface received data from host
+void tud_cdc_rx_cb(uint8_t itf)
+{
+  (void) itf;
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+  static uint32_t start_ms = 0;
+  static bool led_state = false;
+
+  // Blink every interval ms
+  if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
+  start_ms += blink_interval_ms;
+
+  board_led_write(led_state);
+  led_state = 1 - led_state; // toggle
+}

+ 95 - 0
examples/device/webusb_serial/src/tusb_config.h

@@ -0,0 +1,95 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+  #error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
+#endif
+
+#define CFG_TUSB_OS                 OPT_OS_NONE
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#define CFG_TUD_ENDOINT0_SIZE     64
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC               1
+#define CFG_TUD_MSC               0
+#define CFG_TUD_HID               0
+#define CFG_TUD_MIDI              0
+#define CFG_TUD_VENDOR            1
+
+// CDC FIFO size of TX and RX
+#define CFG_TUD_CDC_RX_BUFSIZE    64
+#define CFG_TUD_CDC_TX_BUFSIZE    64
+
+// Vendor FIFO size of TX and RX
+// If not configured vendor endpoints will not be buffered
+#define CFG_TUD_VENDOR_RX_BUFSIZE 64
+#define CFG_TUD_VENDOR_TX_BUFSIZE 64
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 237 - 0
examples/device/webusb_serial/src/usb_descriptors.c

@@ -0,0 +1,237 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]       MIDI | HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0210, // at least 2.1 or 3.x for BOS & webUSB
+
+    // Use Interface Association Descriptor (IAD) for CDC
+    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+    .bDeviceClass       = TUSB_CLASS_MISC,
+    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
+    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+enum
+{
+  ITF_NUM_CDC = 0,
+  ITF_NUM_CDC_DATA,
+  ITF_NUM_VENDOR,
+  ITF_NUM_TOTAL
+};
+
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN)
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
+  // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
+  // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+  #define EPNUM_CDC     2
+  #define EPNUM_VENDOR  5
+#else
+  #define EPNUM_CDC     2
+  #define EPNUM_VENDOR  3
+#endif
+
+uint8_t const desc_configuration[] =
+{
+  // Interface count, string index, total length, attribute, power in mA
+  TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+  // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, 64),
+
+  // Interface number, string index, EP Out & IN address, EP size
+  TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR, 5, EPNUM_VENDOR, 0x80 | EPNUM_VENDOR, 64)
+};
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+  (void) index; // for multiple configurations
+  return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// BOS Descriptor
+//--------------------------------------------------------------------+
+
+/* Microsoft OS 2.0 registry property descriptor
+Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
+device should create DeviceInterfaceGUIDs. It can be done by driver and
+in case of real PnP solution device should expose MS "Microsoft OS 2.0
+registry property descriptor". Such descriptor can insert any record
+into Windows registry per device/configuration/interface. In our case it
+will insert "DeviceInterfaceGUIDs" multistring property.
+
+GUID is freshly generated and should be OK to use.
+
+https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
+(Section Microsoft OS compatibility descriptors)
+*/
+
+#define BOS_TOTAL_LEN      (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
+
+#define MS_OS_20_DESC_LEN  0xB2
+
+// BOS Descriptor is required for webUSB
+uint8_t const desc_bos[] =
+{
+  // total length, number of device caps
+  TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
+
+  // Vendor Code, iLandingPage
+  TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
+
+  // Microsoft OS 2.0 descriptor
+  TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
+};
+
+uint8_t const * tud_descriptor_bos_cb(void)
+{
+  return desc_bos;
+}
+
+
+uint8_t const desc_ms_os_20[] =
+{
+  // Set header: length, type, windows version, total length
+  U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
+
+  // Configuration subset header: length, type, configuration index, reserved, configuration total length
+  U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
+
+  // Function Subset header: length, type, first interface, reserved, subset length
+  U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), ITF_NUM_VENDOR, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
+
+  // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
+  U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
+
+  // MS OS 2.0 Registry property descriptor: length, type
+  U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
+  U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
+  'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
+  'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
+  U16_TO_U8S_LE(0x0050), // wPropertyDataLength
+	//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
+  '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
+  '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
+  '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
+  '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+  (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+  "TinyUSB",                     // 1: Manufacturer
+  "TinyUSB Device",              // 2: Product
+  "123456",                      // 3: Serials, should use chip ID
+  "TinyUSB CDC",                 // 4: CDC Interface
+  "TinyUSB WebUSB"               // 5: Vendor Interface
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index)
+{
+  uint8_t chr_count;
+
+  if ( index == 0)
+  {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  }else
+  {
+    // Convert ASCII string into UTF-16
+
+    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+    const char* str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = strlen(str);
+    if ( chr_count > 31 ) chr_count = 31;
+
+    for(uint8_t i=0; i<chr_count; i++)
+    {
+      _desc_str[1+i] = str[i];
+    }
+  }
+
+  // first byte is len, second byte is string type
+  _desc_str[0] = TUD_DESC_STR_HEADER(chr_count);
+
+  return _desc_str;
+}

+ 36 - 0
examples/device/webusb_serial/src/usb_descriptors.h

@@ -0,0 +1,36 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+enum
+{
+  VENDOR_REQUEST_WEBUSB = 1,
+  VENDOR_REQUEST_MICROSOFT = 2
+};
+
+extern uint8_t const desc_ms_os_20[];
+
+#endif /* USB_DESCRIPTORS_H_ */

+ 5 - 19
examples/host/cdc_msc_hid/src/tusb_config.h

@@ -63,11 +63,11 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
-// DEVICE CONFIGURATION
+// CONFIGURATION
 //--------------------------------------------------------------------
 
 #define CFG_TUH_HUB                 1
@@ -82,30 +82,16 @@
 //------------- CLASS -------------//
 #define CFG_TUD_CDC                 0
 #define CFG_TUD_MSC                 0
-#define CFG_TUD_CUSTOM_CLASS        0
-
 #define CFG_TUD_HID                 0
-#define CFG_TUD_HID_KEYBOARD        0
-#define CFG_TUD_HID_MOUSE           0
+#define CFG_TUD_VENDOR              0
 
-//--------------------------------------------------------------------
-// CDC
-//--------------------------------------------------------------------
-
-// FIFO size of CDC TX and RX
+// CDC FIFO size of TX and RX
 #define CFG_TUD_CDC_RX_BUFSIZE      64
 #define CFG_TUD_CDC_TX_BUFSIZE      64
 
-//--------------------------------------------------------------------
-// MSC
-//--------------------------------------------------------------------
-
-// Buffer size of Device Mass storage
+// MSC Buffer size of Device Mass storage
 #define CFG_TUD_MSC_BUFSIZE         512
 
-//--------------------------------------------------------------------
-// HID
-//--------------------------------------------------------------------
 
 #ifdef __cplusplus
  }

+ 2 - 1
examples/rules.mk

@@ -7,6 +7,7 @@ LIBS = -lgcc -lc -lm -lnosys
 
 # TinyUSB Stack source
 SRC_C += \
+	src/tusb.c \
 	src/common/tusb_fifo.c \
 	src/device/usbd.c \
 	src/device/usbd_control.c \
@@ -14,7 +15,7 @@ SRC_C += \
 	src/class/cdc/cdc_device.c \
 	src/class/hid/hid_device.c \
 	src/class/midi/midi_device.c \
-	src/tusb.c \
+	src/class/vendor/vendor_device.c \
 	src/portable/$(VENDOR)/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c
 
 # TinyUSB stack include

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

@@ -300,7 +300,7 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
 
 // Invoked when class request DATA stage is finished.
 // return false to stall control endpoint (e.g Host send non-sense DATA)
-bool cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * request)
+bool cdcd_control_complete(uint8_t rhport, tusb_control_request_t const * request)
 {
   (void) rhport;
 
@@ -334,11 +334,11 @@ bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request
   switch ( request->bRequest )
   {
     case CDC_REQUEST_SET_LINE_CODING:
-      usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
+      tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
     break;
 
     case CDC_REQUEST_GET_LINE_CODING:
-      usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
+      tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
     break;
 
     case CDC_REQUEST_SET_CONTROL_LINE_STATE:
@@ -349,7 +349,7 @@ bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request
       //        This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
       p_cdc->line_state = (uint8_t) request->wValue;
 
-      usbd_control_status(rhport, request);
+      tud_control_status(rhport, request);
 
       // Invoke callback
       if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, tu_bit_test(request->wValue, 0), tu_bit_test(request->wValue, 1));

+ 6 - 6
src/class/cdc/cdc_device.h

@@ -176,12 +176,12 @@ static inline bool tud_cdc_write_flush (void)
 //--------------------------------------------------------------------+
 // INTERNAL USBD-CLASS DRIVER API
 //--------------------------------------------------------------------+
-void cdcd_init               (void);
-bool cdcd_open               (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
-bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
-bool cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-bool cdcd_xfer_cb            (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
-void cdcd_reset              (uint8_t rhport);
+void cdcd_init             (void);
+void cdcd_reset            (uint8_t rhport);
+bool cdcd_open             (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool cdcd_control_request  (uint8_t rhport, tusb_control_request_t const * request);
+bool cdcd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
+bool cdcd_xfer_cb          (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
 
 #ifdef __cplusplus
  }

+ 0 - 93
src/class/custom/custom_device.c

@@ -1,93 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 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.
- */
-
-#include "tusb_option.h"
-
-#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_CUSTOM_CLASS)
-
-#include "common/tusb_common.h"
-#include "custom_device.h"
-#include "device/usbd_pvt.h"
-
-/*------------------------------------------------------------------*/
-/* MACRO TYPEDEF CONSTANT ENUM
- *------------------------------------------------------------------*/
-
-/*------------------------------------------------------------------*/
-/* VARIABLE DECLARATION
- *------------------------------------------------------------------*/
-typedef struct {
-  uint8_t itf_num;
-
-  uint8_t ep_in;
-  uint8_t ep_out;
-
-} cusd_interface_t;
-
-static cusd_interface_t _cusd_itf;
-
-/*------------------------------------------------------------------*/
-/* FUNCTION DECLARATION
- *------------------------------------------------------------------*/
-void cusd_init(void)
-{
-  tu_varclr(&_cusd_itf);
-}
-
-bool cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, uint16_t *p_len)
-{
-  cusd_interface_t* p_itf = &_cusd_itf;
-
-  // Open endpoint pair with usbd helper
-  tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(p_desc_itf);
-  TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_itf->ep_out, &p_itf->ep_in) );
-
-  p_itf->itf_num = p_desc_itf->bInterfaceNumber;
-
-  (*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
-
-  // TODO Prepare for incoming data
-//  TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
-
-  return true;
-}
-
-bool cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
-{
-  return false;
-}
-
-bool cusd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
-{
-  return true;
-}
-
-void cusd_reset(uint8_t rhport)
-{
-
-}
-
-#endif

+ 0 - 58
src/class/custom/custom_device.h

@@ -1,58 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * This file is part of the TinyUSB stack.
- */
-
-#ifndef _TUSB_CUSTOM_DEVICE_H_
-#define _TUSB_CUSTOM_DEVICE_H_
-
-#include "common/tusb_common.h"
-#include "device/usbd.h"
-
-//--------------------------------------------------------------------+
-// APPLICATION API (Multiple Root Ports)
-// Should be used only with MCU that support more than 1 ports
-//--------------------------------------------------------------------+
-
-//--------------------------------------------------------------------+
-// APPLICATION API (Single Port)
-// Should be used with MCU supporting only 1 USB port for code simplicity
-//--------------------------------------------------------------------+
-
-
-//--------------------------------------------------------------------+
-// APPLICATION CALLBACK API (WEAK is optional)
-//--------------------------------------------------------------------+
-
-//--------------------------------------------------------------------+
-// Internal Class Driver API
-//--------------------------------------------------------------------+
-void cusd_init(void);
-bool cusd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
-bool cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
-bool cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-bool cusd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void cusd_reset(uint8_t rhport);
-
-#endif /* _TUSB_CUSTOM_DEVICE_H_ */

+ 8 - 8
src/class/hid/hid_device.c

@@ -205,7 +205,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
     if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
     {
       uint8_t const * desc_report = tud_hid_descriptor_report_cb();
-      usbd_control_xfer(rhport, p_request, (void*) desc_report, p_hid->reprot_desc_len);
+      tud_control_xfer(rhport, p_request, (void*) desc_report, p_hid->reprot_desc_len);
     }else
     {
       return false; // stall unsupported request
@@ -225,12 +225,12 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
         uint16_t xferlen  = tud_hid_get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->epin_buf, p_request->wLength);
         TU_ASSERT( xferlen > 0 );
 
-        usbd_control_xfer(rhport, p_request, p_hid->epin_buf, xferlen);
+        tud_control_xfer(rhport, p_request, p_hid->epin_buf, xferlen);
       }
       break;
 
       case  HID_REQ_CONTROL_SET_REPORT:
-        usbd_control_xfer(rhport, p_request, p_hid->epout_buf, p_request->wLength);
+        tud_control_xfer(rhport, p_request, p_hid->epout_buf, p_request->wLength);
       break;
 
       case HID_REQ_CONTROL_SET_IDLE:
@@ -241,18 +241,18 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
           if ( !tud_hid_set_idle_cb(p_hid->idle_rate) ) return false;
         }
 
-        usbd_control_status(rhport, p_request);
+        tud_control_status(rhport, p_request);
       break;
 
       case HID_REQ_CONTROL_GET_IDLE:
         // TODO idle rate of report
-        usbd_control_xfer(rhport, p_request, &p_hid->idle_rate, 1);
+        tud_control_xfer(rhport, p_request, &p_hid->idle_rate, 1);
       break;
 
       case HID_REQ_CONTROL_GET_PROTOCOL:
       {
         uint8_t protocol = 1-p_hid->boot_mode;   // 0 is Boot, 1 is Report protocol
-        usbd_control_xfer(rhport, p_request, &protocol, 1);
+        tud_control_xfer(rhport, p_request, &protocol, 1);
       }
       break;
 
@@ -261,7 +261,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
 
         if (tud_hid_boot_mode_cb) tud_hid_boot_mode_cb(p_hid->boot_mode);
 
-        usbd_control_status(rhport, p_request);
+        tud_control_status(rhport, p_request);
       break;
 
       default: return false; // stall unsupported request
@@ -276,7 +276,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
 
 // Invoked when class request DATA stage is finished.
 // return false to stall control endpoint (e.g Host send non-sense DATA)
-bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
+bool hidd_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 {
   (void) rhport;
   hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );

+ 6 - 6
src/class/hid/hid_device.h

@@ -300,12 +300,12 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate);
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void hidd_init(void);
-bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
-bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
-bool hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void hidd_reset(uint8_t rhport);
+void hidd_init             (void);
+void hidd_reset            (uint8_t rhport);
+bool hidd_open             (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool hidd_control_request  (uint8_t rhport, tusb_control_request_t const * request);
+bool hidd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
+bool hidd_xfer_cb          (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
 
 #ifdef __cplusplus
  }

+ 2 - 2
src/class/hid/hid_host.h

@@ -55,7 +55,7 @@ extern uint8_t const hid_keycode_to_ascii_tbl[2][128]; // TODO used weak attr if
  * \retval      true if device supports Keyboard interface
  * \retval      false if device does not support Keyboard interface or is not mounted
  */
-bool          tuh_hid_keyboard_is_mounted(uint8_t dev_addr);
+bool tuh_hid_keyboard_is_mounted(uint8_t dev_addr);
 
 /** \brief      Check if the interface is currently busy or not
  * \param[in]   dev_addr device address
@@ -64,7 +64,7 @@ bool          tuh_hid_keyboard_is_mounted(uint8_t dev_addr);
  * \note        This function is primarily used for polling/waiting result after \ref tuh_hid_keyboard_get_report.
  *              Alternatively, asynchronous event API can be used
  */
-bool          tuh_hid_keyboard_is_busy(uint8_t dev_addr);
+bool tuh_hid_keyboard_is_busy(uint8_t dev_addr);
 
 /** \brief        Perform a get report from Keyboard interface
  * \param[in]		  dev_addr device address

+ 11 - 7
src/class/midi/midi_device.c

@@ -44,6 +44,7 @@ typedef struct
   uint8_t ep_in;
   uint8_t ep_out;
 
+  /*------------- From this point, data is not cleared by bus reset -------------*/
   // FIFO
   tu_fifo_t rx_ff;
   tu_fifo_t tx_ff;
@@ -77,7 +78,7 @@ CFG_TUSB_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
 bool tud_midi_n_mounted (uint8_t itf)
 {
   midid_interface_t* midi = &_midid_itf[itf];
-  return midi->itf_num != 0;
+  return midi->ep_in && midi->ep_out;
 }
 
 //--------------------------------------------------------------------+
@@ -127,7 +128,8 @@ void midi_rx_done_cb(midid_interface_t* midi, uint8_t const* buffer, uint32_t bu
 
 static bool maybe_transmit(midid_interface_t* midi, uint8_t itf_index)
 {
-  TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, midi->ep_in) ); // skip if previous transfer not complete
+  // skip if previous transfer not complete
+  TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, midi->ep_in) );
 
   uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EPSIZE);
   if (count > 0)
@@ -222,6 +224,7 @@ void midid_init(void)
     // config fifo
     tu_fifo_config(&midi->rx_ff, midi->rx_ff_buf, CFG_TUD_MIDI_RX_BUFSIZE, 1, true);
     tu_fifo_config(&midi->tx_ff, midi->tx_ff_buf, CFG_TUD_MIDI_TX_BUFSIZE, 1, true);
+
     #if CFG_FIFO_MUTEX
     tu_fifo_config_mutex(&midi->rx_ff, osal_mutex_create(&midi->rx_ff_mutex));
     tu_fifo_config_mutex(&midi->tx_ff, osal_mutex_create(&midi->tx_ff_mutex));
@@ -275,7 +278,8 @@ bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc,
   (*p_length) = sizeof(tusb_desc_interface_t);
 
   uint8_t found_endpoints = 0;
-  while (found_endpoints < p_interface_desc->bNumEndpoints) {
+  while (found_endpoints < p_interface_desc->bNumEndpoints)
+  {
     if ( TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
     {
         TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), false);
@@ -300,7 +304,7 @@ bool midid_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc,
   return true;
 }
 
-bool midid_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
+bool midid_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 {
   return false;
 }
@@ -313,20 +317,20 @@ bool midid_control_request(uint8_t rhport, tusb_control_request_t const * p_requ
   return false;
 }
 
-bool midid_xfer_cb(uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes)
+bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
 {
   // TODO Support multiple interfaces
   uint8_t const itf = 0;
   midid_interface_t* p_midi = &_midid_itf[itf];
 
   // receive new data
-  if ( edpt_addr == p_midi->ep_out )
+  if ( ep_addr == p_midi->ep_out )
   {
     midi_rx_done_cb(p_midi, p_midi->epout_buf, xferred_bytes);
 
     // prepare for next
     TU_ASSERT( usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, CFG_TUD_MIDI_EPSIZE), false );
-  } else if ( edpt_addr == p_midi->ep_in ) {
+  } else if ( ep_addr == p_midi->ep_in ) {
     maybe_transmit(p_midi, itf);
   }
 

+ 6 - 6
src/class/midi/midi_device.h

@@ -121,12 +121,12 @@ static inline uint32_t tudi_midi_write24 (uint8_t jack_id, uint8_t b1, uint8_t b
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void midid_init               (void);
-bool midid_open               (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
-bool midid_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
-bool midid_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-bool midid_xfer_cb            (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
-void midid_reset              (uint8_t rhport);
+void midid_init             (void);
+void midid_reset            (uint8_t rhport);
+bool midid_open             (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool midid_control_request  (uint8_t rhport, tusb_control_request_t const * request);
+bool midid_control_complete (uint8_t rhport, tusb_control_request_t const * request);
+bool midid_xfer_cb          (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
 
 #ifdef __cplusplus
  }

+ 5 - 5
src/class/msc/msc_device.c

@@ -111,7 +111,7 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
 }
 
 //--------------------------------------------------------------------+
-// USBD-CLASS API
+// USBD Driver API
 //--------------------------------------------------------------------+
 void mscd_init(void)
 {
@@ -154,7 +154,7 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
   {
     case MSC_REQ_RESET:
       // TODO: Actually reset interface.
-      usbd_control_status(rhport, p_request);
+      tud_control_status(rhport, p_request);
     break;
 
     case MSC_REQ_GET_MAX_LUN:
@@ -166,7 +166,7 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
       // MAX LUN is minus 1 by specs
       maxlun--;
 
-      usbd_control_xfer(rhport, p_request, &maxlun, 1);
+      tud_control_xfer(rhport, p_request, &maxlun, 1);
     }
     break;
 
@@ -178,10 +178,10 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
 
 // Invoked when class request DATA stage is finished.
 // return false to stall control endpoint (e.g Host send non-sense DATA)
-bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
+bool mscd_control_complete(uint8_t rhport, tusb_control_request_t const * request)
 {
   (void) rhport;
-  (void) p_request;
+  (void) request;
 
   // nothing to do
   return true;

+ 6 - 6
src/class/msc/msc_device.h

@@ -151,12 +151,12 @@ TU_ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
 //--------------------------------------------------------------------+
 // Internal Class Driver API
 //--------------------------------------------------------------------+
-void mscd_init(void);
-bool mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
-bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
-bool mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
-bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
-void mscd_reset(uint8_t rhport);
+void mscd_init             (void);
+void mscd_reset            (uint8_t rhport);
+bool mscd_open             (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool mscd_control_request  (uint8_t rhport, tusb_control_request_t const * p_request);
+bool mscd_control_complete (uint8_t rhport, tusb_control_request_t const * p_request);
+bool mscd_xfer_cb          (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
 
 #ifdef __cplusplus
  }

+ 214 - 0
src/class/vendor/vendor_device.c

@@ -0,0 +1,214 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ */
+
+#include "tusb_option.h"
+
+#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_VENDOR)
+
+#include "vendor_device.h"
+#include "device/usbd_pvt.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_in;
+  uint8_t ep_out;
+
+  /*------------- From this point, data is not cleared by bus reset -------------*/
+  tu_fifo_t rx_ff;
+  tu_fifo_t tx_ff;
+
+  uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+  uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
+
+#if CFG_FIFO_MUTEX
+  osal_mutex_def_t rx_ff_mutex;
+  osal_mutex_def_t tx_ff_mutex;
+#endif
+
+  // Endpoint Transfer buffer
+  CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE];
+  CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE];
+} vendord_interface_t;
+
+CFG_TUSB_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
+
+#define ITF_MEM_RESET_SIZE   offsetof(vendord_interface_t, rx_ff)
+
+
+
+bool tud_vendor_n_mounted (uint8_t itf)
+{
+  return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out;
+}
+
+uint32_t tud_vendor_n_available (uint8_t itf)
+{
+  return tu_fifo_count(&_vendord_itf[itf].rx_ff);
+}
+
+//--------------------------------------------------------------------+
+// Read API
+//--------------------------------------------------------------------+
+static void _prep_out_transaction (vendord_interface_t* p_itf)
+{
+  // skip if previous transfer not complete
+  if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_out) ) return;
+
+  // Prepare for incoming data but only allow what we can store in the ring buffer.
+  uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff);
+  if ( max_read >= CFG_TUD_VENDOR_EPSIZE )
+  {
+    usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
+  }
+}
+
+uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize)
+{
+  vendord_interface_t* p_itf = &_vendord_itf[itf];
+  uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, bufsize);
+  _prep_out_transaction(p_itf);
+  return num_read;
+}
+
+//--------------------------------------------------------------------+
+// Write API
+//--------------------------------------------------------------------+
+static bool maybe_transmit(vendord_interface_t* p_itf)
+{
+  // skip if previous transfer not complete
+  TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) );
+
+  uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE);
+  if (count > 0)
+  {
+    TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) );
+  }
+  return true;
+}
+
+uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
+{
+  vendord_interface_t* p_itf = &_vendord_itf[itf];
+  uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize);
+  maybe_transmit(p_itf);
+  return ret;
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void vendord_init(void)
+{
+  tu_memclr(_vendord_itf, sizeof(_vendord_itf));
+
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    vendord_interface_t* p_itf = &_vendord_itf[i];
+
+    // config fifo
+    tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false);
+    tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false);
+
+#if CFG_FIFO_MUTEX
+    tu_fifo_config_mutex(&p_itf->rx_ff, osal_mutex_create(&p_itf->rx_ff_mutex));
+    tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex));
+#endif
+  }
+}
+
+void vendord_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    vendord_interface_t* p_itf = &_vendord_itf[i];
+
+    tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
+    tu_fifo_clear(&p_itf->rx_ff);
+    tu_fifo_clear(&p_itf->tx_ff);
+  }
+}
+
+bool vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_len)
+{
+  // Find available interface
+  vendord_interface_t* p_vendor = NULL;
+  for(uint8_t i=0; i<CFG_TUD_VENDOR; i++)
+  {
+    if ( _vendord_itf[i].ep_in == 0 && _vendord_itf[i].ep_out == 0 )
+    {
+      p_vendor = &_vendord_itf[i];
+      break;
+    }
+  }
+  TU_VERIFY(p_vendor);
+
+  // Open endpoint pair with usbd helper
+  TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in));
+
+  p_vendor->itf_num = itf_desc->bInterfaceNumber;
+  (*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
+
+  // Prepare for incoming data
+  TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, sizeof(p_vendor->epout_buf)));
+
+  return true;
+}
+
+bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) rhport;
+  (void) result;
+
+  // TODO Support multiple interfaces
+  uint8_t const itf = 0;
+  vendord_interface_t* p_itf = &_vendord_itf[itf];
+
+  if ( ep_addr == p_itf->ep_out )
+  {
+    // Receive new data
+    tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, xferred_bytes);
+
+    // Invoked callback if any
+    if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf);
+
+    _prep_out_transaction(p_itf);
+  }
+  else if ( ep_addr == p_itf->ep_in )
+  {
+    // Send complete, try to send more if possible
+    maybe_transmit(p_itf);
+  }
+
+  return true;
+}
+
+#endif

+ 121 - 0
src/class/vendor/vendor_device.h

@@ -0,0 +1,121 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_VENDOR_DEVICE_H_
+#define _TUSB_VENDOR_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "device/usbd.h"
+
+#ifndef CFG_TUD_VENDOR_EPSIZE
+#define CFG_TUD_VENDOR_EPSIZE     64
+#endif
+
+#ifndef CFG_TUD_VENDOR_RX_BUFSIZE
+#define CFG_TUD_VENDOR_RX_BUFSIZE 0
+#endif
+
+#ifndef CFG_TUD_VENDOR_TX_BUFSIZE
+#define CFG_TUD_VENDOR_TX_BUFSIZE 0
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API (Multiple Interfaces)
+//--------------------------------------------------------------------+
+bool     tud_vendor_n_mounted    (uint8_t itf);
+uint32_t tud_vendor_n_available  (uint8_t itf);
+uint32_t tud_vendor_n_read       (uint8_t itf, void* buffer, uint32_t bufsize);
+uint32_t tud_vendor_n_write      (uint8_t itf, void const* buffer, uint32_t bufsize);
+
+static inline uint32_t tud_vendor_n_write_str  (uint8_t itf, char const* str);
+
+//--------------------------------------------------------------------+
+// Application API (Single Port)
+//--------------------------------------------------------------------+
+static inline bool     tud_vendor_mounted    (void);
+static inline uint32_t tud_vendor_available  (void);
+static inline uint32_t tud_vendor_read       (void* buffer, uint32_t bufsize);
+static inline uint32_t tud_vendor_write      (void const* buffer, uint32_t bufsize);
+static inline uint32_t tud_vendor_write_str  (char const* str);
+
+//--------------------------------------------------------------------+
+// Application Callback API (weak is optional)
+//--------------------------------------------------------------------+
+
+// Invoked when received new data
+TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf);
+
+//--------------------------------------------------------------------+
+// Inline Functions
+//--------------------------------------------------------------------+
+
+static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str)
+{
+  return tud_vendor_n_write(itf, str, strlen(str));
+}
+
+static inline bool tud_vendor_mounted (void)
+{
+  return tud_vendor_n_mounted(0);
+}
+
+static inline uint32_t tud_vendor_available (void)
+{
+  return tud_vendor_n_available(0);
+}
+
+static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize)
+{
+  return tud_vendor_n_read(0, buffer, bufsize);
+}
+
+static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize)
+{
+  return tud_vendor_n_write(0, buffer, bufsize);
+}
+
+static inline uint32_t tud_vendor_write_str (char const* str)
+{
+  return tud_vendor_n_write_str(0, str);
+}
+
+//--------------------------------------------------------------------+
+// Internal Class Driver API
+//--------------------------------------------------------------------+
+void vendord_init(void);
+void vendord_reset(uint8_t rhport);
+bool vendord_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_VENDOR_DEVICE_H_ */

+ 2 - 2
src/class/custom/custom_host.c → src/class/vendor/vendor_host.c

@@ -26,13 +26,13 @@
 
 #include "tusb_option.h"
 
-#if (TUSB_OPT_HOST_ENABLED && CFG_TUSB_HOST_CUSTOM_CLASS)
+#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_VENDOR)
 
 //--------------------------------------------------------------------+
 // INCLUDE
 //--------------------------------------------------------------------+
 #include "common/tusb_common.h"
-#include "custom_host.h"
+#include "vendor_host.h"
 
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF

+ 3 - 3
src/class/custom/custom_host.h → src/class/vendor/vendor_host.h

@@ -28,8 +28,8 @@
  *  \defgroup Group_Custom Custom Class (not supported yet)
  *  @{ */
 
-#ifndef _TUSB_CUSTOM_HOST_H_
-#define _TUSB_CUSTOM_HOST_H_
+#ifndef _TUSB_VENDOR_HOST_H_
+#define _TUSB_VENDOR_HOST_H_
 
 #include "common/tusb_common.h"
 #include "host/usbh.h"
@@ -69,6 +69,6 @@ void         cush_close(uint8_t dev_addr);
  }
 #endif
 
-#endif /* _TUSB_CUSTOM_HOST_H_ */
+#endif /* _TUSB_VENDOR_HOST_H_ */
 
 /** @} */

+ 3 - 2
src/common/tusb_common.h

@@ -146,9 +146,10 @@ static inline bool     tu_bit_test (uint32_t value, uint8_t n) { return (value &
  * Nth position is the same as the number of arguments
  * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
  *------------------------------------------------------------------*/
-#ifndef VA_ARGS_NUM_
+#ifndef TU_ARGS_NUM
+
+#define TU_ARGS_NUM(...) 	 NARG_(_0, ##__VA_ARGS__,_RSEQ_N())
 
-#define VA_ARGS_NUM_(...) 	 NARG_(_0, ##__VA_ARGS__,_RSEQ_N())
 #define NARG_(...)        _GET_NTH_ARG(__VA_ARGS__)
 #define _GET_NTH_ARG( \
           _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \

+ 91 - 29
src/common/tusb_types.h

@@ -69,7 +69,7 @@ typedef enum
 }tusb_dir_t;
 
 
-/// USB Descriptor Types (section 9.4 table 9-5)
+/// USB Descriptor Types
 typedef enum
 {
   TUSB_DESC_DEVICE                = 0x01,
@@ -84,29 +84,35 @@ typedef enum
   TUSB_DESC_DEBUG                 = 0x0A,
   TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
 
+  TUSB_DESC_BOS                   = 0x0F,
+  TUSB_DESC_DEVICE_CAPABILITY     = 0x10,
+
   // Class Specific Descriptor
   TUSB_DESC_CS_DEVICE             = 0x21,
   TUSB_DESC_CS_CONFIGURATION      = 0x22,
   TUSB_DESC_CS_STRING             = 0x23,
   TUSB_DESC_CS_INTERFACE          = 0x24,
   TUSB_DESC_CS_ENDPOINT           = 0x25,
+
+  TUSB_DESC_SUPERSPEED_ENDPOINT_COMPANION     = 0x30,
+  TUSB_DESC_SUPERSPEED_ISO_ENDPOINT_COMPANION = 0x31
 }tusb_desc_type_t;
 
 typedef enum
 {
-  TUSB_REQ_GET_STATUS =0     , ///< 0
-  TUSB_REQ_CLEAR_FEATURE     , ///< 1
-  TUSB_REQ_RESERVED          , ///< 2
-  TUSB_REQ_SET_FEATURE       , ///< 3
-  TUSB_REQ_RESERVED2         , ///< 4
-  TUSB_REQ_SET_ADDRESS       , ///< 5
-  TUSB_REQ_GET_DESCRIPTOR    , ///< 6
-  TUSB_REQ_SET_DESCRIPTOR    , ///< 7
-  TUSB_REQ_GET_CONFIGURATION , ///< 8
-  TUSB_REQ_SET_CONFIGURATION , ///< 9
-  TUSB_REQ_GET_INTERFACE     , ///< 10
-  TUSB_REQ_SET_INTERFACE     , ///< 11
-  TUSB_REQ_SYNCH_FRAME         ///< 12
+  TUSB_REQ_GET_STATUS        = 0  ,
+  TUSB_REQ_CLEAR_FEATURE     = 1  ,
+  TUSB_REQ_RESERVED          = 2  ,
+  TUSB_REQ_SET_FEATURE       = 3  ,
+  TUSB_REQ_RESERVED2         = 4  ,
+  TUSB_REQ_SET_ADDRESS       = 5  ,
+  TUSB_REQ_GET_DESCRIPTOR    = 6  ,
+  TUSB_REQ_SET_DESCRIPTOR    = 7  ,
+  TUSB_REQ_GET_CONFIGURATION = 8  ,
+  TUSB_REQ_SET_CONFIGURATION = 9  ,
+  TUSB_REQ_GET_INTERFACE     = 10 ,
+  TUSB_REQ_SET_INTERFACE     = 11 ,
+  TUSB_REQ_SYNCH_FRAME       = 12
 }tusb_request_code_t;
 
 typedef enum
@@ -168,6 +174,26 @@ typedef enum
   MISC_PROTOCOL_IAD = 1
 }misc_protocol_type_t;
 
+typedef enum
+{
+  DEVICE_CAPABILITY_WIRELESS_USB               = 0x01,
+  DEVICE_CAPABILITY_USB20_EXTENSION            = 0x02,
+  DEVICE_CAPABILITY_SUPERSPEED_USB             = 0x03,
+  DEVICE_CAPABILITY_CONTAINER_id               = 0x04,
+  DEVICE_CAPABILITY_PLATFORM                   = 0x05,
+  DEVICE_CAPABILITY_POWER_DELIVERY             = 0x06,
+  DEVICE_CAPABILITY_BATTERY_INFO               = 0x07,
+  DEVICE_CAPABILITY_PD_CONSUMER_PORT           = 0x08,
+  DEVICE_CAPABILITY_PD_PROVIDER_PORT           = 0x09,
+  DEVICE_CAPABILITY_SUPERSPEED_PLUS            = 0x0A,
+  DEVICE_CAPABILITY_PRECESION_TIME_MEASUREMENT = 0x0B,
+  DEVICE_CAPABILITY_WIRELESS_USB_EXT           = 0x0C,
+  DEVICE_CAPABILITY_BILLBOARD                  = 0x0D,
+  DEVICE_CAPABILITY_AUTHENTICATION             = 0x0E,
+  DEVICE_CAPABILITY_BILLBOARD_EX               = 0x0F,
+  DEVICE_CAPABILITY_CONFIGURATION_SUMMARY      = 0x10
+}device_capability_type_t;
+
 enum {
   TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
   TUSB_DESC_CONFIG_ATT_SELF_POWERED  = TU_BIT(6),
@@ -201,11 +227,25 @@ enum
   INTERFACE_INVALID_NUMBER = 0xff
 };
 
+
+enum
+{
+  MS_OS_20_SET_HEADER_DESCRIPTOR       = 0x00,
+  MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
+  MS_OS_20_SUBSET_HEADER_FUNCTION      = 0x02,
+  MS_OS_20_FEATURE_COMPATBLE_ID        = 0x03,
+  MS_OS_20_FEATURE_REG_PROPERTY        = 0x04,
+  MS_OS_20_FEATURE_MIN_RESUME_TIME     = 0x05,
+  MS_OS_20_FEATURE_MODEL_ID            = 0x06,
+  MS_OS_20_FEATURE_CCGP_DEVICE         = 0x07,
+  MS_OS_20_FEATURE_VENDOR_REVISION     = 0x08
+}microsoft_os_20_type_t;
+
 //--------------------------------------------------------------------+
-// STANDARD DESCRIPTORS
+// USB Descriptors
 //--------------------------------------------------------------------+
 
-/// USB Standard Device Descriptor (section 9.6.1, table 9-8)
+/// USB Device Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength            ; ///< Size of this descriptor in bytes.
@@ -227,7 +267,16 @@ typedef struct TU_ATTR_PACKED
   uint8_t  bNumConfigurations ; ///< Number of possible configurations.
 } tusb_desc_device_t;
 
-/// USB Standard Configuration Descriptor (section 9.6.1 table 9-10) */
+// USB Binary Device Object Store (BOS) Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t  bLength         ; ///< Size of this descriptor in bytes
+  uint8_t  bDescriptorType ; ///< CONFIGURATION Descriptor Type
+  uint16_t wTotalLength    ; ///< Total length of data returned for this descriptor
+  uint8_t  bNumDeviceCaps  ; ///< Number of device capability descriptors in the BOS
+} tusb_desc_bos_t;
+
+/// USB Configuration Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength             ; ///< Size of this descriptor in bytes
@@ -241,7 +290,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t  bMaxPower           ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
 } tusb_desc_configuration_t;
 
-/// USB Standard Interface Descriptor (section 9.6.1 table 9-12)
+/// USB Interface Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength            ; ///< Size of this descriptor in bytes
@@ -256,7 +305,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t  iInterface         ; ///< Index of string descriptor describing this interface
 } tusb_desc_interface_t;
 
-/// USB Standard Endpoint Descriptor (section 9.6.1 table 9-13)
+/// USB Endpoint Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength          ; ///< Size of this descriptor in bytes
@@ -280,7 +329,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t  bInterval        ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
 } tusb_desc_endpoint_t;
 
-/// USB Other Speed Configuration Descriptor (section 9.6.1 table 9-11)
+/// USB Other Speed Configuration Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength             ; ///< Size of descriptor
@@ -294,7 +343,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t  bMaxPower           ; ///< Same as Configuration descriptor
 } tusb_desc_other_speed_t;
 
-/// USB Device Qualifier Descriptor (section 9.6.1 table 9-9)
+/// USB Device Qualifier Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength            ; ///< Size of descriptor
@@ -325,13 +374,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t iFunction         ; ///< Index of the string descriptor describing the interface association.
 } tusb_desc_interface_assoc_t;
 
-/// USB Header Descriptor
-typedef struct TU_ATTR_PACKED
-{
-  uint8_t  bLength         ; ///< Size of this descriptor in bytes
-  uint8_t  bDescriptorType ; ///< Descriptor Type
-} tusb_desc_header_t;
-
+// USB String Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t  bLength         ; ///< Size of this descriptor in bytes
@@ -339,6 +382,25 @@ typedef struct TU_ATTR_PACKED
   uint16_t unicode_string[];
 } tusb_desc_string_t;
 
+// USB Binary Device Object Store (BOS)
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType ;
+  uint8_t bDevCapabilityType;
+  uint8_t bReserved;
+  uint8_t PlatformCapabilityUUID[16];
+  uint8_t CapabilityData[];
+} tusb_desc_bos_platform_t;
+
+// USB WebuSB URL Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength;
+  uint8_t bDescriptorType;
+  uint8_t bScheme;
+  char    url[];
+} tusb_desc_webusb_url_t;
 
 /*------------------------------------------------------------------*/
 /* Types
@@ -415,7 +477,7 @@ static inline uint8_t tu_desc_len(void const* desc)
 #define TUD_DESC_STR_HEADER(_chr_count)  ( (uint16_t) ( (TUSB_DESC_STRING << 8 ) | TUD_DESC_STRLEN(_chr_count)) )
 
 // Convert comma-separated string to descriptor unicode format
-#define TUD_DESC_STRCONV( ... )     (const uint16_t[]) { TUD_DESC_STR_HEADER(VA_ARGS_NUM_(__VA_ARGS__)), __VA_ARGS__ }
+#define TUD_DESC_STRCONV( ... )     (const uint16_t[]) { TUD_DESC_STR_HEADER(TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__ }
 
 #ifdef __cplusplus
  }

+ 21 - 21
src/common/tusb_verify.h

@@ -51,8 +51,8 @@
 //--------------------------------------------------------------------+
 #if CFG_TUSB_DEBUG
   #include <stdio.h>
-  #define _MESS_ERR(_err)         printf("%s: %d: failed, error = %s\n", __func__, __LINE__, tusb_strerr[_err])
-  #define _MESS_FAILED()          printf("%s: %d: failed\n", __func__, __LINE__)
+  #define _MESS_ERR(_err)   printf("%s: %d: failed, error = %s\n", __func__, __LINE__, tusb_strerr[_err])
+  #define _MESS_FAILED()    printf("%s: %d: failed\n", __func__, __LINE__)
 #else
   #define _MESS_ERR(_err)
   #define _MESS_FAILED()
@@ -61,11 +61,11 @@
 // Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
 #if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
 
-#define TU_BREAKPOINT() \
-  do {\
-    volatile uint32_t* ARM_CM_DHCSR =  ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
-    if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */\
-  } while(0)
+#define TU_BREAKPOINT() do                                                                                \
+{                                                                                                         \
+  volatile uint32_t* ARM_CM_DHCSR =  ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+  if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */            \
+} while(0)
 
 #else
 #define TU_BREAKPOINT()
@@ -80,22 +80,23 @@
 #define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...)  arg4
 
 /*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
-#define TU_VERIFY_DEFINE(_cond, _handler, _ret)  do { if ( !(_cond) ) { _handler; return _ret;  } } while(0)
+#define TU_VERIFY_DEFINE(_cond, _handler, _ret)  do            \
+{                                                              \
+  if ( !(_cond) ) { _handler; return _ret;  }                  \
+} while(0)
 
 /*------------- Generator for TU_VERIFY_ERR and TU_VERIFY_ERR_HDLR -------------*/
-#define TU_VERIFY_ERR_DEF2(_error, _handler)  \
-    do {                                              \
-      uint32_t _err = (uint32_t)(_error);             \
-      if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; }\
-    } while(0)
-
-#define TU_VERIFY_ERR_DEF3(_error, _handler, _ret)  \
-    do {                                              \
-      uint32_t _err = (uint32_t)(_error);             \
-      if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; }\
-    } while(0)
-
+#define TU_VERIFY_ERR_DEF2(_error, _handler)  do               \
+{                                                              \
+  uint32_t _err = (uint32_t)(_error);                          \
+  if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; } \
+} while(0)
 
+#define TU_VERIFY_ERR_DEF3(_error, _handler, _ret) do          \
+{                                                              \
+  uint32_t _err = (uint32_t)(_error);                          \
+  if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; } \
+} while(0)
 
 
 /*------------------------------------------------------------------*/
@@ -141,7 +142,6 @@
 #define TU_VERIFY_ERR_HDLR(...)       GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_ERR_HDLR_3ARGS, TU_VERIFY_ERR_HDLR_2ARGS)(__VA_ARGS__)
 
 
-
 /*------------------------------------------------------------------*/
 /* ASSERT
  * basically TU_VERIFY with TU_BREAKPOINT() as handler

+ 132 - 84
src/device/usbd.c

@@ -43,20 +43,20 @@
 typedef struct {
   struct TU_ATTR_PACKED
   {
-      volatile uint8_t connected    : 1;
-      volatile uint8_t configured   : 1;
-      volatile uint8_t suspended    : 1;
+    volatile uint8_t connected    : 1;
+    volatile uint8_t configured   : 1;
+    volatile uint8_t suspended    : 1;
 
-      uint8_t remote_wakeup_en      : 1; // enable/disable by host
-      uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute
-      uint8_t self_powered          : 1; // configuration descriptor's attribute
+    uint8_t remote_wakeup_en      : 1; // enable/disable by host
+    uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute
+    uint8_t self_powered          : 1; // configuration descriptor's attribute
   };
 
   uint8_t ep_busy_map[2];  // bit mask for busy endpoint
   uint8_t ep_stall_map[2]; // bit map for stalled endpoint
 
-  uint8_t itf2drv[16];      // map interface number to driver (0xff is invalid)
-  uint8_t ep2drv[8][2];     // map endpoint to driver ( 0xff is invalid )
+  uint8_t itf2drv[16];     // map interface number to driver (0xff is invalid)
+  uint8_t ep2drv[8][2];    // map endpoint to driver ( 0xff is invalid )
 }usbd_device_t;
 
 static usbd_device_t _usbd_dev = { 0 };
@@ -67,80 +67,80 @@ static usbd_device_t _usbd_dev = { 0 };
 typedef struct {
   uint8_t class_code;
 
-  void (* init           ) (void);
-  bool (* open           ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
-  bool (* control_request ) (uint8_t rhport, tusb_control_request_t const * request);
-  bool (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const * request);
-  bool (* xfer_cb        ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t, uint32_t);
-  void (* sof            ) (uint8_t rhport);
-  void (* reset          ) (uint8_t);
+  void (* init             ) (void);
+  void (* reset            ) (uint8_t rhport);
+  bool (* open             ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
+  bool (* control_request  ) (uint8_t rhport, tusb_control_request_t const * request);
+  bool (* control_complete ) (uint8_t rhport, tusb_control_request_t const * request);
+  bool (* xfer_cb          ) (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+  void (* sof              ) (uint8_t rhport);
 } usbd_class_driver_t;
 
 static usbd_class_driver_t const usbd_class_drivers[] =
 {
   #if CFG_TUD_CDC
-    {
-        .class_code      = TUSB_CLASS_CDC,
-        .init            = cdcd_init,
-        .open            = cdcd_open,
-        .control_request = cdcd_control_request,
-        .control_request_complete = cdcd_control_request_complete,
-        .xfer_cb         = cdcd_xfer_cb,
-        .sof             = NULL,
-        .reset           = cdcd_reset
-    },
+  {
+      .class_code       = TUSB_CLASS_CDC,
+      .init             = cdcd_init,
+      .reset            = cdcd_reset,
+      .open             = cdcd_open,
+      .control_request  = cdcd_control_request,
+      .control_complete = cdcd_control_complete,
+      .xfer_cb          = cdcd_xfer_cb,
+      .sof              = NULL
+  },
   #endif
 
   #if CFG_TUD_MSC
-    {
-        .class_code      = TUSB_CLASS_MSC,
-        .init            = mscd_init,
-        .open            = mscd_open,
-        .control_request = mscd_control_request,
-        .control_request_complete = mscd_control_request_complete,
-        .xfer_cb         = mscd_xfer_cb,
-        .sof             = NULL,
-        .reset           = mscd_reset
-    },
+  {
+      .class_code       = TUSB_CLASS_MSC,
+      .init             = mscd_init,
+      .reset            = mscd_reset,
+      .open             = mscd_open,
+      .control_request  = mscd_control_request,
+      .control_complete = mscd_control_complete,
+      .xfer_cb          = mscd_xfer_cb,
+      .sof              = NULL
+  },
   #endif
 
   #if CFG_TUD_HID
-    {
-        .class_code      = TUSB_CLASS_HID,
-        .init            = hidd_init,
-        .open            = hidd_open,
-        .control_request = hidd_control_request,
-        .control_request_complete = hidd_control_request_complete,
-        .xfer_cb         = hidd_xfer_cb,
-        .sof             = NULL,
-        .reset           = hidd_reset
-    },
+  {
+      .class_code       = TUSB_CLASS_HID,
+      .init             = hidd_init,
+      .reset            = hidd_reset,
+      .open             = hidd_open,
+      .control_request  = hidd_control_request,
+      .control_complete = hidd_control_complete,
+      .xfer_cb          = hidd_xfer_cb,
+      .sof              = NULL
+  },
   #endif
 
   #if CFG_TUD_MIDI
-    {
-        .class_code      = TUSB_CLASS_AUDIO,
-        .init            = midid_init,
-        .open            = midid_open,
-        .control_request = midid_control_request,
-        .control_request_complete = midid_control_request_complete,
-        .xfer_cb         = midid_xfer_cb,
-        .sof             = NULL,
-        .reset           = midid_reset
-    },
+  {
+      .class_code       = TUSB_CLASS_AUDIO,
+      .init             = midid_init,
+      .open             = midid_open,
+      .reset            = midid_reset,
+      .control_request  = midid_control_request,
+      .control_complete = midid_control_complete,
+      .xfer_cb          = midid_xfer_cb,
+      .sof              = NULL
+  },
   #endif
 
-  #if CFG_TUD_CUSTOM_CLASS
-    {
-        .class_code      = TUSB_CLASS_VENDOR_SPECIFIC,
-        .init            = cusd_init,
-        .open            = cusd_open,
-        .control_request = cusd_control_request,
-        .control_request_complete = cusd_control_request_complete,
-        .xfer_cb         = cusd_xfer_cb,
-        .sof             = NULL,
-        .reset           = cusd_reset
-    },
+  #if CFG_TUD_VENDOR
+  {
+      .class_code       = TUSB_CLASS_VENDOR_SPECIFIC,
+      .init             = vendord_init,
+      .reset            = vendord_reset,
+      .open             = vendord_open,
+      .control_request  = tud_vendor_control_request_cb,
+      .control_complete = tud_vendor_control_complete_cb,
+      .xfer_cb          = vendord_xfer_cb,
+      .sof              = NULL
+  },
   #endif
 };
 
@@ -237,7 +237,6 @@ static void usbd_reset(uint8_t rhport)
       while(1) // the mainloop
       {
         application_code();
-
         tud_task(); // tinyusb device task
       }
     }
@@ -347,6 +346,15 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 {
   usbd_control_set_complete_callback(NULL);
 
+  // Vendor request
+  if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR )
+  {
+    TU_VERIFY(tud_vendor_control_request_cb);
+
+    if (tud_vendor_control_complete_cb) usbd_control_set_complete_callback(tud_vendor_control_complete_cb);
+    return tud_vendor_control_request_cb(rhport, p_request);
+  }
+
   switch ( p_request->bmRequestType_bit.recipient )
   {
     //------------- Device Requests e.g in enumeration -------------//
@@ -370,7 +378,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
         case TUSB_REQ_GET_CONFIGURATION:
         {
           uint8_t cfgnum = _usbd_dev.configured ? 1 : 0;
-          usbd_control_xfer(rhport, p_request, &cfgnum, 1);
+          tud_control_xfer(rhport, p_request, &cfgnum, 1);
         }
         break;
 
@@ -382,7 +390,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
           _usbd_dev.configured = cfg_num ? 1 : 0;
 
           if ( cfg_num ) TU_ASSERT( process_set_config(rhport, cfg_num) );
-          usbd_control_status(rhport, p_request);
+          tud_control_status(rhport, p_request);
         }
         break;
 
@@ -396,7 +404,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 
           // Host may enable remote wake up before suspending especially HID device
           _usbd_dev.remote_wakeup_en = true;
-          usbd_control_status(rhport, p_request);
+          tud_control_status(rhport, p_request);
         break;
 
         case TUSB_REQ_CLEAR_FEATURE:
@@ -405,7 +413,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 
           // Host may disable remote wake up after resuming
           _usbd_dev.remote_wakeup_en = false;
-          usbd_control_status(rhport, p_request);
+          tud_control_status(rhport, p_request);
         break;
 
         case TUSB_REQ_GET_STATUS:
@@ -414,7 +422,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
           // - Bit 0: Self Powered
           // - Bit 1: Remote Wakeup enabled
           uint16_t status = (_usbd_dev.self_powered ? 1 : 0) | (_usbd_dev.remote_wakeup_en ? 2 : 0);
-          usbd_control_xfer(rhport, p_request, &status, 2);
+          tud_control_xfer(rhport, p_request, &status, 2);
         }
         break;
 
@@ -431,10 +439,34 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 
       TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
 
-      usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete );
+      switch ( p_request->bRequest )
+      {
+        case TUSB_REQ_GET_INTERFACE:
+        {
+          // TODO not support alternate interface yet
+          uint8_t alternate = 0;
+          tud_control_xfer(rhport, p_request, &alternate, 1);
+        }
+        break;
+
+        case TUSB_REQ_SET_INTERFACE:
+        {
+          uint8_t alternate = (uint8_t) p_request->wValue;
+
+          // TODO not support alternate interface yet
+          TU_ASSERT(alternate == 0);
 
-      // stall control endpoint if driver return false
-      return usbd_class_drivers[drvid].control_request(rhport, p_request);
+          tud_control_status(rhport, p_request);
+        }
+        break;
+
+        default:
+          // forward to class driver
+          // stall control endpoint if driver return false
+          usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_complete);
+          TU_ASSERT(usbd_class_drivers[drvid].control_request(rhport, p_request));
+        break;
+      }
     }
     break;
 
@@ -448,7 +480,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
         case TUSB_REQ_GET_STATUS:
         {
           uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
-          usbd_control_xfer(rhport, p_request, &status, 2);
+          tud_control_xfer(rhport, p_request, &status, 2);
         }
         break;
 
@@ -457,7 +489,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
           {
             usbd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
           }
-          usbd_control_status(rhport, p_request);
+          tud_control_status(rhport, p_request);
         break;
 
         case TUSB_REQ_SET_FEATURE:
@@ -465,7 +497,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
           {
             usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
           }
-          usbd_control_status(rhport, p_request);
+          tud_control_status(rhport, p_request);
         break;
 
         // Unknown/Unsupported request
@@ -520,7 +552,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
       _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
 
       uint16_t itf_len=0;
-      TU_ASSERT( usbd_class_drivers[drv_id].open( rhport, desc_itf, &itf_len ) );
+      TU_ASSERT( usbd_class_drivers[drv_id].open(rhport, desc_itf, &itf_len) );
       TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) );
 
       mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, itf_len, drv_id);
@@ -563,13 +595,29 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
   switch(desc_type)
   {
     case TUSB_DESC_DEVICE:
-      return usbd_control_xfer(rhport, p_request, (void*) tud_descriptor_device_cb(), sizeof(tusb_desc_device_t));
+      return tud_control_xfer(rhport, p_request, (void*) tud_descriptor_device_cb(), sizeof(tusb_desc_device_t));
+    break;
+
+    case TUSB_DESC_BOS:
+    {
+      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
+      if (!tud_descriptor_bos_cb) return false;
+
+      tusb_desc_bos_t const* desc_bos = (tusb_desc_bos_t const*) tud_descriptor_bos_cb();
+      uint16_t total_len;
+      memcpy(&total_len, &desc_bos->wTotalLength, 2); // possibly mis-aligned memory
+
+      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
+    }
     break;
 
     case TUSB_DESC_CONFIGURATION:
     {
       tusb_desc_configuration_t const* desc_config = (tusb_desc_configuration_t const*) tud_descriptor_configuration_cb(desc_index);
-      return usbd_control_xfer(rhport, p_request, (void*) desc_config, desc_config->wTotalLength);
+      uint16_t total_len;
+      memcpy(&total_len, &desc_config->wTotalLength, 2); // possibly mis-aligned memory
+
+      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
     }
     break;
 
@@ -577,8 +625,8 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
       // String Descriptor always uses the desc set from user
       if ( desc_index == 0xEE )
       {
-        // The 0xEE index string is a Microsoft USB extension.
-        // It can be used to tell Windows what driver it should use for the device !!!
+        // The 0xEE index string is a Microsoft OS Descriptors.
+        // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
         return false;
       }else
       {
@@ -586,7 +634,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
         TU_ASSERT(desc_str);
 
         // first byte of descriptor is its size
-        return usbd_control_xfer(rhport, p_request, (void*) desc_str, desc_str[0]);
+        return tud_control_xfer(rhport, p_request, (void*) desc_str, desc_str[0]);
       }
     break;
 

+ 76 - 6
src/device/usbd.h

@@ -59,6 +59,14 @@ static inline bool tud_ready(void)
 // Remote wake up host, only if suspended and enabled by host
 bool tud_remote_wakeup(void);
 
+// Carry out Data and Status stage of control transfer
+// - If len = 0, it is equivalent to sending status only
+// - If len > wLength : it will be truncated
+bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
+
+// Send STATUS (zero length) packet
+bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request);
+
 //--------------------------------------------------------------------+
 // Application Callbacks (WEAK is optional)
 //--------------------------------------------------------------------+
@@ -67,6 +75,10 @@ bool tud_remote_wakeup(void);
 // Application return pointer to descriptor
 uint8_t const * tud_descriptor_device_cb(void);
 
+// Invoked when received GET BOS DESCRIPTOR request
+// Application return pointer to descriptor
+TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void);
+
 // Invoked when received GET CONFIGURATION DESCRIPTOR request
 // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
 uint8_t const * tud_descriptor_configuration_cb(uint8_t index);
@@ -88,10 +100,56 @@ TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
 // Invoked when usb bus is resumed
 TU_ATTR_WEAK void tud_resume_cb(void);
 
+// Invoked when received control request with VENDOR TYPE
+TU_ATTR_WEAK bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request);
+TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request);
+
+
 //--------------------------------------------------------------------+
-// Interface Descriptor Template
+// Binary Device Object Store (BOS) Descriptor Templates
 //--------------------------------------------------------------------+
 
+#define TUD_BOS_DESC_LEN      5
+
+// total length, number of device caps
+#define TUD_BOS_DESCRIPTOR(_total_len, _caps_num) \
+  5, TUSB_DESC_BOS, U16_TO_U8S_LE(_total_len), _caps_num
+
+// Device Capability Platform 128-bit UUID + Data
+#define TUD_BOS_PLATFORM_DESCRIPTOR(...) \
+  4+TU_ARGS_NUM(__VA_ARGS__), TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_PLATFORM, 0x00, __VA_ARGS__
+
+//------------- WebUSB BOS Platform -------------//
+
+// Descriptor Length
+#define TUD_BOS_WEBUSB_DESC_LEN         24
+
+// Vendor Code, iLandingPage
+#define TUD_BOS_WEBUSB_DESCRIPTOR(_vendor_code, _ipage) \
+  TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_WEBUSB_UUID, U16_TO_U8S_LE(0x0100), _vendor_code, _ipage)
+
+#define TUD_BOS_WEBUSB_UUID   \
+  0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, \
+  0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65
+
+//------------- Microsoft OS 2.0 Platform -------------//
+
+#define TUD_BOS_MICROSOFT_OS_DESC_LEN   28
+
+// Total Length of descriptor set, vendor code
+#define TUD_BOS_MS_OS_20_DESCRIPTOR(_desc_set_len, _vendor_code) \
+  TUD_BOS_PLATFORM_DESCRIPTOR(TUD_BOS_MS_OS_20_UUID, U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(_desc_set_len), _vendor_code, 0)
+
+#define TUD_BOS_MS_OS_20_UUID \
+  0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, \
+  0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F
+
+
+//--------------------------------------------------------------------+
+// Configuration & Interface Descriptor Templates
+//--------------------------------------------------------------------+
+
+//------------- Configuration -------------//
 #define TUD_CONFIG_DESC_LEN   (9)
 
 // Interface count, string index, total length, attribute, power in mA
@@ -160,16 +218,16 @@ TU_ATTR_WEAK void tud_resume_cb(void);
 #define TUD_HID_INOUT_DESC_LEN    (9 + 9 + 7 + 7)
 
 // HID Input & Output descriptor
-// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
-#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epout, _epsize, _ep_interval) \
+// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
+#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epout, _epin, _epsize, _ep_interval) \
   /* Interface */\
   9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (_boot_protocol) ? HID_SUBCLASS_BOOT : 0, _boot_protocol, _stridx,\
   /* HID descriptor */\
   9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
-  /* Endpoint In */\
-  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval,\
   /* Endpoint Out */\
-  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval, \
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
 
 //------------- MIDI -------------//
 
@@ -205,6 +263,18 @@ TU_ATTR_WEAK void tud_resume_cb(void);
   /* MS Endpoint (connected to embedded jack out) */\
   5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 3
 
+//------------- Vendor -------------//
+#define TUD_VENDOR_DESC_LEN  (9+7+7)
+
+// Interface number, string index, EP Out & IN address, EP size
+#define TUD_VENDOR_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_VENDOR_SPECIFIC, 0x00, 0x00, _stridx,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
 
 #ifdef __cplusplus
  }

+ 4 - 4
src/device/usbd_control.c

@@ -59,7 +59,7 @@ void usbd_control_reset (uint8_t rhport)
   tu_varclr(&_control_state);
 }
 
-bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request)
+bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request)
 {
   // status direction is reversed to one in the setup packet
   return dcd_edpt_xfer(rhport, request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN, NULL, 0);
@@ -87,7 +87,7 @@ void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_reque
   _control_state.complete_cb = fp;
 }
 
-bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
+bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
 {
   _control_state.request = (*request);
   _control_state.buffer = buffer;
@@ -103,7 +103,7 @@ bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, v
   }else
   {
     // Status stage
-    TU_ASSERT( usbd_control_status(rhport, request) );
+    TU_ASSERT( tud_control_status(rhport, request) );
   }
 
   return true;
@@ -139,7 +139,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
     if ( is_ok )
     {
       // Send status
-      TU_ASSERT( usbd_control_status(rhport, &_control_state.request) );
+      TU_ASSERT( tud_control_status(rhport, &_control_state.request) );
     }else
     {
       // Stall both IN and OUT control endpoint

+ 3 - 9
src/device/usbd_pvt.h

@@ -39,19 +39,13 @@ bool usbd_init (void);
 // USBD Endpoint API
 //--------------------------------------------------------------------+
 
-// Carry out Data and Status stage of control transfer
-// - If len = 0, it is equivalent to sending status only
-// - If len > wLength : it will be truncated
-bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
-
-// Send STATUS (zero length) packet
-bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request);
+//bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
 
 // Submit a usb transfer
-bool usbd_edpt_xfer        (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
 
 // Check if endpoint transferring is complete
-bool usbd_edpt_busy        (uint8_t rhport, uint8_t ep_addr);
+bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr);
 
 void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr);
 void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);

+ 1 - 1
src/host/usbh.c

@@ -84,7 +84,7 @@ static host_class_driver_t const usbh_class_drivers[] =
     },
   #endif
 
-  #if CFG_TUSB_HOST_CUSTOM_CLASS
+  #if CFG_TUH_VENDOR
     {
       .class_code = TUSB_CLASS_VENDOR_SPECIFIC,
       .init       = cush_init,

+ 4 - 4
src/tusb.h

@@ -54,8 +54,8 @@
     #include "class/cdc/cdc_host.h"
   #endif
 
-  #if CFG_TUSB_HOST_CUSTOM_CLASS
-    #include "class/custom_host.h"
+  #if CFG_TUH_VENDOR
+    #include "class/vendor/vendor_host.h"
   #endif
 
 #endif
@@ -80,8 +80,8 @@
     #include "class/midi/midi_device.h"
   #endif
 
-  #if CFG_TUD_CUSTOM_CLASS
-    #include "class/custom/custom_device.h"
+  #if CFG_TUD_VENDOR
+    #include "class/vendor/vendor_device.h"
   #endif
 #endif
 

+ 2 - 2
src/tusb_option.h

@@ -161,8 +161,8 @@
   #define CFG_TUD_MIDI            0
 #endif
 
-#ifndef CFG_TUD_CUSTOM_CLASS
-  #define CFG_TUD_CUSTOM_CLASS    0
+#ifndef CFG_TUD_VENDOR
+  #define CFG_TUD_VENDOR          0
 #endif
 
 

+ 11 - 11
test/test/support/tusb_config.h

@@ -63,38 +63,38 @@
 #endif
 
 #ifndef CFG_TUSB_MEM_ALIGN
-#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
 #endif
 
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
 
-#define CFG_TUD_ENDOINT0_SIZE       64
+#define CFG_TUD_ENDOINT0_SIZE    64
 
 //------------- CLASS -------------//
-#define CFG_TUD_CDC                 1
-#define CFG_TUD_MSC                 1
-#define CFG_TUD_HID                 1
+#define CFG_TUD_CDC              1
+#define CFG_TUD_MSC              1
+#define CFG_TUD_HID              1
 
-#define CFG_TUD_MIDI                1
-#define CFG_TUD_CUSTOM_CLASS        0
+#define CFG_TUD_MIDI             1
+#define CFG_TUD_VENDOR           1
 
 //------------- CDC -------------//
 
 // FIFO size of CDC TX and RX
-#define CFG_TUD_CDC_RX_BUFSIZE      64
-#define CFG_TUD_CDC_TX_BUFSIZE      64
+#define CFG_TUD_CDC_RX_BUFSIZE   64
+#define CFG_TUD_CDC_TX_BUFSIZE   64
 
 //------------- MSC -------------//
 
 // Buffer size of Device Mass storage
-#define CFG_TUD_MSC_BUFSIZE         512
+#define CFG_TUD_MSC_BUFSIZE      512
 
 //------------- HID -------------//
 
 // Should be sufficient to hold ID (if any) + Data
-#define CFG_TUD_HID_BUFSIZE         16
+#define CFG_TUD_HID_BUFSIZE      16
 
 #ifdef __cplusplus
  }

+ 11 - 2
tools/build_all.py

@@ -12,7 +12,16 @@ success_count = 0
 fail_count = 0
 exit_status = 0
 
-all_device_example = ["cdc_msc_hid", "hid_generic_inout", "midi_test", "msc_dual_lun"]
+all_examples = [];
+for entry in os.scandir("examples/device"):
+    if entry.is_dir():
+        all_examples.append(entry.name)
+
+# mynewt has its own example repo
+all_examples.remove("cdc_msc_hid_mynewt")
+
+# TODO update freeRTOS example to work with all boards (only nrf52840 now)
+all_examples.remove("cdc_msc_hid_freertos")
 
 all_boards = []
 for entry in os.scandir("hw/bsp"):
@@ -25,7 +34,7 @@ def build_example(example, board):
 
 total_time = time.monotonic()
 
-for example in all_device_example:
+for example in all_examples:
     for board in all_boards:
         start_time = time.monotonic()
         build_result = build_example(example, board)