Browse Source

Merge pull request #56 from hathach/develop

refactor hid device, remove auto descriptor, update example
hathach 7 years ago
parent
commit
ee3504fdb0

+ 1 - 1
README.md

@@ -24,7 +24,7 @@ TinyUSB is an open-source cross-platform USB Host/Device stack for embedded syst
 Support multiple device configurations by dynamically changing usb descriptors. Low power functions such as suspend, resume and remote wakeup. Following device classes are supported:
 
 - Communication Class (CDC)
-- Human Interface Device (HID): Keyboard, Mouse, Generic
+- Human Interface Device (HID): Keyboard, Mouse, Gamepad etc ...
 - Mass Storage Class (MSC)
 - Musical Instrument Digital Interface (MIDI)
 

+ 2 - 4
examples/device/cdc_msc_hid/Makefile

@@ -85,9 +85,8 @@ LIBS = -lgcc -lc -lm -lnosys
 
 EXAMPLE_SOURCE += \
 	src/main.c \
-	src/msc_app.c \
-	src/msc_disk_ram.c \
-	src/tusb_descriptors.c
+	src/msc_disk.c \
+	src/usb_descriptors.c
 
 SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
 
@@ -95,7 +94,6 @@ LIB_SOURCE += \
 	hw/bsp/$(BOARD)/board_$(BOARD).c \
 	src/common/tusb_fifo.c \
 	src/device/usbd.c \
-	src/device/usbd_auto_desc.c \
 	src/device/usbd_control.c \
 	src/class/msc/msc_device.c \
 	src/class/cdc/cdc_device.c \

+ 51 - 36
examples/device/cdc_msc_hid/src/main.c

@@ -40,12 +40,18 @@
  * - 1000 ms : device mounted
  * - 2500 ms : device is suspended
  */
-static uint32_t blink_interval_ms = 250;
+enum  {
+  BLINK_NOT_MOUNTED = 250,
+  BLINK_MOUNTED = 1000,
+  BLINK_SUSPENDED = 2500,
+};
+
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
 
 void led_blinking_task(void);
 
-extern void virtual_com_task(void);
-extern void usb_hid_task(void);
+extern void cdc_task(void);
+extern void hid_task(void);
 
 /*------------- MAIN -------------*/
 int main(void)
@@ -62,11 +68,11 @@ int main(void)
     led_blinking_task();
 
 #if CFG_TUD_CDC
-    virtual_com_task();
+    cdc_task();
 #endif
 
 #if CFG_TUD_HID
-    usb_hid_task();
+    hid_task();
 #endif
   }
 
@@ -77,7 +83,7 @@ int main(void)
 // USB CDC
 //--------------------------------------------------------------------+
 #if CFG_TUD_CDC
-void virtual_com_task(void)
+void cdc_task(void)
 {
   if ( tud_cdc_connected() )
   {
@@ -126,7 +132,15 @@ void tud_cdc_rx_cb(uint8_t itf)
 // USB HID
 //--------------------------------------------------------------------+
 #if CFG_TUD_HID
-void usb_hid_task(void)
+
+// 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
   const uint32_t interval_ms = 10;
@@ -137,6 +151,7 @@ void usb_hid_task(void)
 
   uint32_t const btn = board_button_read();
 
+  // Remote wakeup
   if ( tud_suspended() && btn )
   {
     // Wake up host if we are in suspend mode
@@ -144,43 +159,43 @@ void usb_hid_task(void)
     tud_remote_wakeup();
   }
 
-#if 0
+  /*------------- Mouse -------------*/
+  if ( tud_hid_ready() )
+  {
+    if ( btn )
+    {
+      int8_t const delta = 5;
+      tud_hid_mouse_move(REPORT_ID_MOUSE, delta, delta); // right + down
+
+      // delay a bit before attempt to send keyboard report
+      board_delay(2);
+    }
+  }
+
   /*------------- Keyboard -------------*/
-  if ( tud_hid_keyboard_ready() )
+  if ( tud_hid_ready() )
   {
+    // use to avoid send multiple consecutive zero report for keyboard
+    static bool has_key = false;
+
     if ( btn )
     {
       uint8_t keycode[6] = { 0 };
+      keycode[0] = HID_KEY_A;
 
-      for(uint8_t i=0; i < 6; i++)
-      {
-        if ( btn & (1 << i) ) keycode[i] = HID_KEY_A + i;
-      }
+      tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
 
-      tud_hid_keyboard_keycode(0, keycode);
+      has_key = true;
     }else
     {
-      // Null means all zeroes keycodes
-      tud_hid_keyboard_keycode(0, NULL);
+      // send empty key report if previously has key pressed
+      if (has_key) tud_hid_keyboard_key_release(REPORT_ID_KEYBOARD);
+      has_key = false;
     }
   }
-#endif
-
-#if 0
-  /*------------- Mouse -------------*/
-  if ( tud_hid_mouse_ready() )
-  {
-    enum { DELTA  = 5 };
-
-    if ( btn & 0x01 ) tud_hid_mouse_move(-DELTA,      0); // left
-    if ( btn & 0x02 ) tud_hid_mouse_move( DELTA,      0); // right
-    if ( btn & 0x04 ) tud_hid_mouse_move(  0   , -DELTA); // up
-    if ( btn & 0x08 ) tud_hid_mouse_move(  0   ,  DELTA); // down
-  }
-#endif
 }
 
-uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
 {
   // TODO not Implemented
   (void) report_id;
@@ -191,7 +206,7 @@ uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t repo
   return 0;
 }
 
-void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
 {
   // TODO not Implemented
   (void) report_id;
@@ -209,13 +224,13 @@ void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_t
 // Invoked when device is mounted
 void tud_mount_cb(void)
 {
-  blink_interval_ms = 1000;
+  blink_interval_ms = BLINK_MOUNTED;
 }
 
 // Invoked when device is unmounted
 void tud_umount_cb(void)
 {
-  blink_interval_ms = 250;
+  blink_interval_ms = BLINK_NOT_MOUNTED;
 }
 
 // Invoked when usb bus is suspended
@@ -224,13 +239,13 @@ void tud_umount_cb(void)
 void tud_suspend_cb(bool remote_wakeup_en)
 {
   (void) remote_wakeup_en;
-  blink_interval_ms = 2500;
+  blink_interval_ms = BLINK_SUSPENDED;
 }
 
 // Invoked when usb bus is resumed
 void tud_resume_cb(void)
 {
-  blink_interval_ms = 1000;
+  blink_interval_ms = BLINK_MOUNTED;
 }
 
 //--------------------------------------------------------------------+

+ 0 - 104
examples/device/cdc_msc_hid/src/msc_app.c

@@ -1,104 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2018, hathach (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 "bsp/board.h"
-#include "tusb.h"
-
-#if CFG_TUD_MSC
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-
-//--------------------------------------------------------------------+
-// tinyusb callbacks
-//--------------------------------------------------------------------+
-
-// Callback invoked when received an SCSI command not in built-in list below
-// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
-// - READ10 and WRITE10 has their own callbacks
-int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
-{
-  // read10 & write10 has their own callback and MUST not be handled here
-
-  void const* response = NULL;
-  uint16_t resplen = 0;
-
-  // most scsi handled is input
-  bool in_xfer = true;
-
-  switch (scsi_cmd[0])
-  {
-    case SCSI_CMD_TEST_UNIT_READY:
-      // Command that host uses to check our readiness before sending other commands
-      resplen = 0;
-    break;
-
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
-    case SCSI_CMD_START_STOP_UNIT:
-      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
-      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
-        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
-        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
-        start_stop->start;
-        start_stop->load_eject;
-       */
-       resplen = 0;
-    break;
-
-
-    default:
-      // Set Sense = Invalid Command Operation
-      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
-
-      // negative means error -> tinyusb could stall and/or response with failed status
-      resplen = -1;
-    break;
-  }
-
-  // return resplen must not larger than bufsize
-  if ( resplen > bufsize ) resplen = bufsize;
-
-  if ( response && (resplen > 0) )
-  {
-    if(in_xfer)
-    {
-      memcpy(buffer, response, resplen);
-    }else
-    {
-      // SCSI output
-    }
-  }
-
-  return resplen;
-}
-
-
-#endif

+ 63 - 0
examples/device/cdc_msc_hid/src/msc_disk_ram.c → examples/device/cdc_msc_hid/src/msc_disk.c

@@ -126,4 +126,67 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
   *block_size  = DISK_BLOCK_SIZE;
 }
 
+// Callback invoked when received an SCSI command not in built-in list below
+// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
+// - READ10 and WRITE10 has their own callbacks
+int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
+{
+  // read10 & write10 has their own callback and MUST not be handled here
+
+  void const* response = NULL;
+  uint16_t resplen = 0;
+
+  // most scsi handled is input
+  bool in_xfer = true;
+
+  switch (scsi_cmd[0])
+  {
+    case SCSI_CMD_TEST_UNIT_READY:
+      // Command that host uses to check our readiness before sending other commands
+      resplen = 0;
+    break;
+
+    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+      // Host is about to read/write etc ... better not to disconnect disk
+      resplen = 0;
+    break;
+
+    case SCSI_CMD_START_STOP_UNIT:
+      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
+      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
+        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
+        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
+        start_stop->start;
+        start_stop->load_eject;
+       */
+       resplen = 0;
+    break;
+
+
+    default:
+      // Set Sense = Invalid Command Operation
+      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+      // negative means error -> tinyusb could stall and/or response with failed status
+      resplen = -1;
+    break;
+  }
+
+  // return resplen must not larger than bufsize
+  if ( resplen > bufsize ) resplen = bufsize;
+
+  if ( response && (resplen > 0) )
+  {
+    if(in_xfer)
+    {
+      memcpy(buffer, response, resplen);
+    }else
+    {
+      // SCSI output
+    }
+  }
+
+  return resplen;
+}
+
 #endif

+ 7 - 40
examples/device/cdc_msc_hid/src/tusb_config.h

@@ -46,8 +46,8 @@
 #define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
 #endif
 
-#define CFG_TUSB_DEBUG              2
 #define CFG_TUSB_OS                 OPT_OS_NONE
+#define CFG_TUSB_DEBUG              2
 
 /* 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
@@ -67,49 +67,17 @@
 //--------------------------------------------------------------------
 // DEVICE CONFIGURATION
 //--------------------------------------------------------------------
-#define CFG_TUD_ENDOINT0_SIZE       64
-
-/*------------- Descriptors -------------*/
 
-/* Enable auto generated descriptor, tinyusb will try its best to create
- * descriptor ( device, configuration, hid ) that matches enabled CFG_* in this file
- *
- * Note: All CFG_TUD_DESC_* are relevant only if CFG_TUD_DESC_AUTO is enabled
- */
-#define CFG_TUD_DESC_AUTO           1
-
-/* If USB VID/PID is not defined, tinyusb will use default value
- * Note: different class combination e.g CDC and (CDC + MSC) should have different
- * PID since Host OS will "remembered" device driver after the first plug */
-// #define CFG_TUD_DESC_VID          0xCAFE
-// #define CFG_TUD_DESC_PID          0x0001
-
-// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
-// Therefore we need to force endpoint number to correct type on lpc17xx
-#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
-#define CFG_TUD_DESC_CDC_EPNUM_NOTIF      1
-#define CFG_TUD_DESC_CDC_EPNUM            2
-#define CFG_TUD_DESC_MSC_EPNUM            5
-#define CFG_TUD_DESC_HID_KEYBOARD_EPNUM   4
-#define CFG_TUD_DESC_HID_MOUSE_EPNUM      7
-#endif
+#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_MIDI                0
 #define CFG_TUD_CUSTOM_CLASS        0
 
-#define CFG_TUD_HID                 0
-#define CFG_TUD_HID_KEYBOARD        0
-#define CFG_TUD_HID_MOUSE           0
-
-/* Use Boot Protocol for Keyboard, Mouse. Enable this will create separated HID interface
- * require more IN endpoints. If disabled, they they are all packed into a single
- * multiple report interface called "Generic". */
-#define CFG_TUD_HID_KEYBOARD_BOOT   1
-#define CFG_TUD_HID_MOUSE_BOOT      1
-
 //--------------------------------------------------------------------
 // CDC
 //--------------------------------------------------------------------
@@ -121,6 +89,7 @@
 //--------------------------------------------------------------------
 // MSC
 //--------------------------------------------------------------------
+
 // Number of supported Logical Unit Number (At least 1)
 #define CFG_TUD_MSC_MAXLUN          1
 
@@ -140,14 +109,12 @@
 // HID
 //--------------------------------------------------------------------
 
-/* Use the HID_ASCII_TO_KEYCODE lookup if CFG_TUD_HID_KEYBOARD is enabled.
- * This will occupies 256 bytes of ROM. It will also enable the use of 2 extra APIs
+/* Use the HID_ASCII_TO_KEYCODE lookup
+ * This will occupies 256 bytes of ROM. It will also enable the use of extra APIs
  * - tud_hid_keyboard_send_char()
- * - tud_hid_keyboard_send_string()
  */
 #define CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP 1
 
-
 #ifdef __cplusplus
  }
 #endif

+ 0 - 86
examples/device/cdc_msc_hid/src/tusb_descriptors.c

@@ -1,86 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2018, hathach (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.h"
-
-//--------------------------------------------------------------------+
-// STRING DESCRIPTORS
-//--------------------------------------------------------------------+
-
-// array of pointer to string descriptors
-uint16_t const * const string_desc_arr [] =
-{
-    // 0: is supported language = English
-    TUD_DESC_STRCONV(0x0409),
-
-    // 1: Manufacturer
-    TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g'),
-
-    // 2: Product
-    TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'd', 'e', 'v', 'i', 'c', 'e'),
-
-    // 3: Serials TODO use chip ID
-    TUD_DESC_STRCONV('1', '2', '3', '4', '5', '6'),
-
-#if CFG_TUD_CDC
-    // 4: CDC Interface
-    TUD_DESC_STRCONV('t','u','s','b',' ','c','d','c'),
-#endif
-
-#if CFG_TUD_MSC
-    // 5: MSC Interface
-    TUD_DESC_STRCONV('t','u','s','b',' ','m','s','c'),
-#endif
-
-#if CFG_TUD_HID_KEYBOARD
-    // 6: Keyboard
-    TUD_DESC_STRCONV('t','u','s','b',' ','k','e','y','b','o','a','r','d'),
-#endif
-
-#if CFG_TUD_HID_MOUSE
-    // 7: Mouse
-    TUD_DESC_STRCONV('t','u','s','b',' ','m', 'o','u','s','e'),
-#endif
-
-};
-
-// tud_desc_set is required by tinyusb stack
-// since CFG_TUD_DESC_AUTO is enabled, we only need to set string_arr 
-tud_desc_set_t tud_desc_set =
-{
-    .device     = NULL,
-    .config     = NULL,
-
-    .string_arr   = (uint8_t const **) string_desc_arr,
-    .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
-
-    .hid_report =
-    {
-        .generic       = NULL,
-        .boot_keyboard = NULL,
-        .boot_mouse    = NULL
-    }
-};

+ 171 - 0
examples/device/cdc_msc_hid/src/usb_descriptors.c

@@ -0,0 +1,171 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (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.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]         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) )
+
+//------------- Device Descriptors -------------//
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0200,
+
+  #if CFG_TUD_CDC
+    // 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,
+  #else
+    .bDeviceClass       = 0x00,
+    .bDeviceSubClass    = 0x00,
+    .bDeviceProtocol    = 0x00,
+  #endif
+
+    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+//------------- HID Report Descriptor -------------//
+enum
+{
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE
+};
+
+uint8_t const desc_hid_report[] =
+{
+  HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD), ),
+  HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(REPORT_ID_MOUSE), )
+};
+
+//------------- Configuration Descriptor -------------//
+enum
+{
+  #if CFG_TUD_CDC
+    ITF_NUM_CDC = 0,
+    ITF_NUM_CDC_DATA,
+  #endif
+
+  #if CFG_TUD_MSC
+    ITF_NUM_MSC,
+  #endif
+
+  #if CFG_TUD_HID
+    ITF_NUM_HID,
+  #endif
+
+    ITF_NUM_TOTAL
+};
+
+enum
+{
+  CONFIG_DESC_LEN = sizeof(tusb_desc_configuration_t) + 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
+  // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+  // Note: since CDC EP ( 1 & 2), HID (4) are spot-on, thus we only need to force
+  // endpoint number for MSC to 5
+  #define EPNUM_MSC   0x05
+#else
+  #define EPNUM_MSC   0x03
+#endif
+
+uint8_t const desc_configuration[] =
+{
+  // Config: self-powered with remote wakeup support, max power up to 100 mA
+  TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+#if CFG_TUD_CDC
+  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, 0x02, 0x82, 64),
+#endif
+
+#if CFG_TUD_MSC
+  TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC, 0x80 | EPNUM_MSC, 64), // highspeed 512
+#endif
+
+#if CFG_TUD_HID
+  TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_PROTOCOL_KEYBOARD, sizeof(desc_hid_report), 0x84, 16, 10)
+#endif
+};
+
+//------------- String Descriptors -------------//
+// array of pointer to string descriptors
+uint16_t const * const string_desc_arr [] =
+{
+  // 0: is supported language = English
+  TUD_DESC_STRCONV(0x0409),
+
+  // 1: Manufacturer
+  TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g'),
+
+  // 2: Product
+  TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'd', 'e', 'v', 'i', 'c', 'e'),
+
+  // 3: Serials, should use chip ID
+  TUD_DESC_STRCONV('1', '2', '3', '4', '5', '6'),
+
+  // 4: CDC Interface
+  TUD_DESC_STRCONV('t','u','s','b',' ','c','d','c'),
+
+  // 5: MSC Interface
+  TUD_DESC_STRCONV('t','u','s','b',' ','m','s','c'),
+
+  // 6: HID
+  TUD_DESC_STRCONV('t','u','s','b',' ','h','i','d')
+};
+
+// tud_desc_set is required by tinyusb stack
+tud_desc_set_t tud_desc_set =
+{
+    .device     = &desc_device,
+    .config     = desc_configuration,
+
+    .string_arr   = (uint8_t const **) string_desc_arr,
+    .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
+
+    .hid_report = desc_hid_report,
+};

+ 1 - 1
examples/device/cdc_msc_hid_freertos/ses/nrf5x/nrf5x.emProject

@@ -20,7 +20,7 @@
       arm_target_interface_type="SWD"
       build_treat_warnings_as_errors="No"
       c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;CFG_TUSB_MCU=OPT_MCU_NRF5X"
-      c_user_include_directories="./;../../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include;$(freertosDir)/Source/include;$(freertosDir)/Source/portable/GCC/ARM_CM4F"
+      c_user_include_directories="./;../../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include;$(nrfxDir)/drivers/src;$(freertosDir)/Source/include;$(freertosDir)/Source/portable/GCC/ARM_CM4F"
       debug_register_definition_file="nrf52840_Registers.xml"
       debug_target_connection="J-Link"
       gcc_enable_all_warnings="Yes"

+ 103 - 45
examples/device/cdc_msc_hid_freertos/src/main.c

@@ -24,9 +24,6 @@
  * This file is part of the TinyUSB stack.
  */
 
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -41,12 +38,22 @@
 #include "tusb.h"
 
 //--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
+// MACRO CONSTANT TYPEDEF PROTYPES
 //--------------------------------------------------------------------+
 
-//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
-//--------------------------------------------------------------------+
+/* 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,
+};
+
+TimerHandle_t blink_tm;
+
 void led_blinky_cb(TimerHandle_t xTimer);
 void usb_device_task(void* param);
 
@@ -56,8 +63,8 @@ int main(void)
   board_init();
 
   // soft timer for blinky
-  TimerHandle_t tm_hdl = xTimerCreate(NULL, pdMS_TO_TICKS(1000), true, NULL, led_blinky_cb);
-  xTimerStart(tm_hdl, 0);
+  blink_tm = xTimerCreate(NULL, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), true, NULL, led_blinky_cb);
+  xTimerStart(blink_tm, 0);
 
   tusb_init();
 
@@ -71,7 +78,8 @@ int main(void)
 #endif
 
 #if CFG_TUD_HID
-  extern void usb_hid_task(void* params);
+  extern void hid_task(void* params);
+  xTaskCreate( hid_task, "hid", 256, NULL, configMAX_PRIORITIES-2, NULL);
 #endif
 
   vTaskStartScheduler();
@@ -130,6 +138,7 @@ void cdc_task(void* params)
   }
 }
 
+// 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;
@@ -141,85 +150,134 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
     tud_cdc_write_str("\r\nTinyUSB CDC MSC HID device with FreeRTOS example\r\n");
   }
 }
+
+// Invoked when CDC interface received data from host
+void tud_cdc_rx_cb(uint8_t itf)
+{
+  (void) itf;
+}
+
 #endif
 
 //--------------------------------------------------------------------+
 // USB HID
 //--------------------------------------------------------------------+
 #if CFG_TUD_HID
-void usb_hid_task(void* params)
+
+// Must match with ID declared by HID Report Descriptor, better to be in header file
+enum
 {
-  (void) params;
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE
+};
 
-  // Poll every 10ms
-  const uint32_t interval_ms = 10;
-  static uint32_t start_ms = 0;
+void hid_task(void* params)
+{
+  (void) params;
 
-  if ( board_millis() < start_ms + interval_ms) return; // not enough time
-  start_ms += interval_ms;
+  while (1)
+  {
+    // Poll every 10ms
+    vTaskDelay(pdMS_TO_TICKS(10));
 
-  uint32_t const btn = board_button_read();
+    uint32_t const btn = board_button_read();
 
-  /*------------- Keyboard -------------*/
-  if ( tud_hid_keyboard_ready() )
-  {
-    if ( btn )
+    // Remote wakeup
+    if ( tud_suspended() && btn )
     {
-      uint8_t keycode[6] = { 0 };
+      // Wake up host if we are in suspend mode
+      // and REMOTE_WAKEUP feature is enabled by host
+      tud_remote_wakeup();
+    }
 
-      for(uint8_t i=0; i < 6; i++)
+    /*------------- Mouse -------------*/
+    if ( tud_hid_ready() )
+    {
+      if ( btn )
       {
-        if ( btn & (1 << i) ) keycode[i] = HID_KEY_A + i;
+        int8_t const delta = 5;
+        tud_hid_mouse_move(REPORT_ID_MOUSE, delta, delta); // right + down
+
+        // delay a bit before attempt to send keyboard report
+        vTaskDelay(pdMS_TO_TICKS(2));
       }
+    }
 
-      tud_hid_keyboard_keycode(0, keycode);
-    }else
+    /*------------- Keyboard -------------*/
+    if ( tud_hid_ready() )
     {
-      // Null means all zeroes keycodes
-      tud_hid_keyboard_keycode(0, NULL);
-    }
-  }
+      // use to avoid send multiple consecutive zero report for keyboard
+      static bool has_key = false;
 
+      if ( btn )
+      {
+        uint8_t keycode[6] = { 0 };
+        keycode[0] = HID_KEY_A;
 
-  /*------------- Mouse -------------*/
-  if ( tud_hid_mouse_ready() )
-  {
-    enum { DELTA  = 5 };
+        tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode);
 
-    if ( btn & 0x01 ) tud_hid_mouse_move(-DELTA,      0); // left
-    if ( btn & 0x02 ) tud_hid_mouse_move( DELTA,      0); // right
-    if ( btn & 0x04 ) tud_hid_mouse_move(  0   , -DELTA); // up
-    if ( btn & 0x08 ) tud_hid_mouse_move(  0   ,  DELTA); // down
+        has_key = true;
+      }else
+      {
+        // send empty key report if previously has key pressed
+        if (has_key) tud_hid_keyboard_key_release(REPORT_ID_KEYBOARD);
+        has_key = false;
+      }
+    }
   }
 }
 
-uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
 {
   // TODO not Implemented
+  (void) report_id;
+  (void) report_type;
+  (void) buffer;
+  (void) reqlen;
+
   return 0;
 }
 
-void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
 {
   // TODO not Implemented
+  (void) report_id;
+  (void) report_type;
+  (void) buffer;
+  (void) bufsize;
 }
+
 #endif
 
 //--------------------------------------------------------------------+
-// tinyusb callbacks
+// Device callbacks
 //--------------------------------------------------------------------+
+
+// Invoked when device is mounted
 void tud_mount_cb(void)
 {
-
+  xTimerChangePeriod(blink_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
 }
 
+// Invoked when device is unmounted
 void tud_umount_cb(void)
 {
+  xTimerChangePeriod(blink_tm, pdMS_TO_TICKS(BLINK_NOT_MOUNTED), 0);
 }
 
-void tud_cdc_rx_cb(uint8_t itf)
+// 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) itf;
+  (void) remote_wakeup_en;
+  xTimerChangePeriod(blink_tm, pdMS_TO_TICKS(BLINK_SUSPENDED), 0);
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+  xTimerChangePeriod(blink_tm, pdMS_TO_TICKS(BLINK_MOUNTED), 0);
 }
 
 //--------------------------------------------------------------------+

+ 0 - 104
examples/device/cdc_msc_hid_freertos/src/msc_app.c

@@ -1,104 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2018, hathach (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 "bsp/board.h"
-#include "tusb.h"
-
-#if CFG_TUD_MSC
-
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
-
-//--------------------------------------------------------------------+
-// tinyusb callbacks
-//--------------------------------------------------------------------+
-
-// Callback invoked when received an SCSI command not in built-in list below
-// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
-// - READ10 and WRITE10 has their own callbacks
-int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
-{
-  // read10 & write10 has their own callback and MUST not be handled here
-
-  void const* response = NULL;
-  uint16_t resplen = 0;
-
-  // most scsi handled is input
-  bool in_xfer = true;
-
-  switch (scsi_cmd[0])
-  {
-    case SCSI_CMD_TEST_UNIT_READY:
-      // Command that host uses to check our readiness before sending other commands
-      resplen = 0;
-    break;
-
-    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-      // Host is about to read/write etc ... better not to disconnect disk
-      resplen = 0;
-    break;
-
-    case SCSI_CMD_START_STOP_UNIT:
-      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
-      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
-        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
-        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
-        start_stop->start;
-        start_stop->load_eject;
-       */
-       resplen = 0;
-    break;
-
-
-    default:
-      // Set Sense = Invalid Command Operation
-      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
-
-      // negative means error -> tinyusb could stall and/or response with failed status
-      resplen = -1;
-    break;
-  }
-
-  // return resplen must not larger than bufsize
-  if ( resplen > bufsize ) resplen = bufsize;
-
-  if ( response && (resplen > 0) )
-  {
-    if(in_xfer)
-    {
-      memcpy(buffer, response, resplen);
-    }else
-    {
-      // SCSI output
-    }
-  }
-
-  return resplen;
-}
-
-
-#endif

+ 68 - 3
examples/device/cdc_msc_hid_freertos/src/msc_disk_ram.c → examples/device/cdc_msc_hid_freertos/src/msc_disk.c

@@ -49,7 +49,7 @@ enum
 #ifdef DISK_READONLY
 const
 #endif
-static uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
+uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
 {
   //------------- Boot Sector -------------//
   // byte_per_sector    = DISK_BLOCK_SIZE; fat12_sector_num_16  = DISK_BLOCK_NUM;
@@ -82,7 +82,7 @@ static uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
       // second entry is readme file
       'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
       0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
-      sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's filesize (4 Bytes)
+      sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files ize (4 Bytes)
   },
 
   //------------- Readme Content -------------//
@@ -96,7 +96,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff
 {
   (void) lun;
 
-  uint8_t* addr = msc_disk[lba] + offset;
+  uint8_t const* addr = msc_disk[lba] + offset;
   memcpy(buffer, addr, bufsize);
 
   return bufsize;
@@ -111,6 +111,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
 #ifndef DISK_READONLY
   uint8_t* addr = msc_disk[lba] + offset;
   memcpy(addr, buffer, bufsize);
+#else
+  (void) lba; (void) offset; (void) buffer;
 #endif
 
   return bufsize;
@@ -124,4 +126,67 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
   *block_size  = DISK_BLOCK_SIZE;
 }
 
+// Callback invoked when received an SCSI command not in built-in list below
+// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
+// - READ10 and WRITE10 has their own callbacks
+int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
+{
+  // read10 & write10 has their own callback and MUST not be handled here
+
+  void const* response = NULL;
+  uint16_t resplen = 0;
+
+  // most scsi handled is input
+  bool in_xfer = true;
+
+  switch (scsi_cmd[0])
+  {
+    case SCSI_CMD_TEST_UNIT_READY:
+      // Command that host uses to check our readiness before sending other commands
+      resplen = 0;
+    break;
+
+    case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+      // Host is about to read/write etc ... better not to disconnect disk
+      resplen = 0;
+    break;
+
+    case SCSI_CMD_START_STOP_UNIT:
+      // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
+      /* scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
+        // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well
+        // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage
+        start_stop->start;
+        start_stop->load_eject;
+       */
+       resplen = 0;
+    break;
+
+
+    default:
+      // Set Sense = Invalid Command Operation
+      tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
+
+      // negative means error -> tinyusb could stall and/or response with failed status
+      resplen = -1;
+    break;
+  }
+
+  // return resplen must not larger than bufsize
+  if ( resplen > bufsize ) resplen = bufsize;
+
+  if ( response && (resplen > 0) )
+  {
+    if(in_xfer)
+    {
+      memcpy(buffer, response, resplen);
+    }else
+    {
+      // SCSI output
+    }
+  }
+
+  return resplen;
+}
+
 #endif

+ 10 - 39
examples/device/cdc_msc_hid_freertos/src/tusb_config.h

@@ -40,7 +40,12 @@
   #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_FREERTOS
 #define CFG_TUSB_DEBUG              2
 
@@ -65,46 +70,13 @@
 
 #define CFG_TUD_ENDOINT0_SIZE       64
 
-/*------------- Descriptors -------------*/
-
-/* Enable auto generated descriptor, tinyusb will try its best to create
- * descriptor ( device, configuration, hid ) that matches enabled CFG_* in this file
- *
- * Note: All CFG_TUD_DESC_* are relevant only if CFG_TUD_DESC_AUTO is enabled
- */
-#define CFG_TUD_DESC_AUTO           1
-
-/* If USB VID/PID is not defined, tinyusb will use default value
- * Note: different class combination e.g CDC and (CDC + MSC) should have different
- * PID since Host OS will "remembered" device driver after the first plug */
-// #define CFG_TUD_DESC_VID          0xCAFE
-// #define CFG_TUD_DESC_PID          0x0001
-
-// LPC175x_6x's endpoint type (bulk/interrupt/iso) are fixed by its number
-// Therefor we need to force endpoint number to correct type on lpc17xx
-#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X
-#define CFG_TUD_DESC_CDC_EPNUM_NOTIF      1
-#define CFG_TUD_DESC_CDC_EPNUM            2
-#define CFG_TUD_DESC_MSC_EPNUM            5
-#define CFG_TUD_DESC_HID_KEYBOARD_EPNUM   4
-#define CFG_TUD_DESC_HID_MOUSE_EPNUM      7
-#endif
-
-
 //------------- CLASS -------------//
 #define CFG_TUD_CDC                 1
 #define CFG_TUD_MSC                 1
+#define CFG_TUD_HID                 1
 
-#define CFG_TUD_HID                 0
-#define CFG_TUD_HID_KEYBOARD        0
-#define CFG_TUD_HID_MOUSE           0
-
-/* Use Boot Protocol for Keyboard, Mouse. Enable this will create separated HID interface
- * require more IN endpoints. If disabled, they they are all packed into a single
- * multiple report interface called "Generic". */
-#define CFG_TUD_HID_KEYBOARD_BOOT   1
-#define CFG_TUD_HID_MOUSE_BOOT      1
-
+#define CFG_TUD_MIDI                0
+#define CFG_TUD_CUSTOM_CLASS        0
 
 //--------------------------------------------------------------------
 // CDC
@@ -137,10 +109,9 @@
 // HID
 //--------------------------------------------------------------------
 
-/* Use the HID_ASCII_TO_KEYCODE lookup if CFG_TUD_HID_KEYBOARD is enabled.
- * This will occupies 256 bytes of ROM. It will also enable the use of 2 extra APIs
+/* Use the HID_ASCII_TO_KEYCODE lookup
+ * This will occupies 256 bytes of ROM. It will also enable the use of extra APIs
  * - tud_hid_keyboard_send_char()
- * - tud_hid_keyboard_send_string()
  */
 #define CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP 1
 

+ 0 - 86
examples/device/cdc_msc_hid_freertos/src/tusb_descriptors.c

@@ -1,86 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2018, hathach (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.h"
-
-//--------------------------------------------------------------------+
-// STRING DESCRIPTORS
-//--------------------------------------------------------------------+
-
-// array of pointer to string descriptors
-uint16_t const * const string_desc_arr [] =
-{
-    // 0: is supported language = English
-    TUD_DESC_STRCONV(0x0409),
-
-    // 1: Manufacturer
-    TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g'),
-
-    // 2: Product
-    TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'd', 'e', 'v', 'i', 'c', 'e'),
-
-    // 3: Serials TODO use chip ID
-    TUD_DESC_STRCONV('1', '2', '3', '4', '5', '6'),
-
-#if CFG_TUD_CDC
-    // 4: CDC Interface
-    TUD_DESC_STRCONV('t','u','s','b',' ','c','d','c'),
-#endif
-
-#if CFG_TUD_MSC
-    // 5: MSC Interface
-    TUD_DESC_STRCONV('t','u','s','b',' ','m','s','c'),
-#endif
-
-#if CFG_TUD_HID_KEYBOARD
-    // 6: Keyboard
-    TUD_DESC_STRCONV('t','u','s','b',' ','k','e','y','b','o','a','r','d'),
-#endif
-
-#if CFG_TUD_HID_MOUSE
-    // 7: Mouse
-    TUD_DESC_STRCONV('t','u','s','b',' ','m', 'o','u','s','e'),
-#endif
-
-};
-
-// tud_desc_set is required by tinyusb stack
-// since CFG_TUD_DESC_AUTO is enabled, we only need to set string_arr 
-tud_desc_set_t tud_desc_set =
-{
-    .device     = NULL,
-    .config     = NULL,
-
-    .string_arr   = (uint8_t const **) string_desc_arr,
-    .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
-
-    .hid_report =
-    {
-        .generic       = NULL,
-        .boot_keyboard = NULL,
-        .boot_mouse    = NULL
-    }
-};

+ 171 - 0
examples/device/cdc_msc_hid_freertos/src/usb_descriptors.c

@@ -0,0 +1,171 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018, hathach (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.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]         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) )
+
+//------------- Device Descriptors -------------//
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0200,
+
+  #if CFG_TUD_CDC
+    // 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,
+  #else
+    .bDeviceClass       = 0x00,
+    .bDeviceSubClass    = 0x00,
+    .bDeviceProtocol    = 0x00,
+  #endif
+
+    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+//------------- HID Report Descriptor -------------//
+enum
+{
+  REPORT_ID_KEYBOARD = 1,
+  REPORT_ID_MOUSE
+};
+
+uint8_t const desc_hid_report[] =
+{
+  HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD), ),
+  HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(REPORT_ID_MOUSE), )
+};
+
+//------------- Configuration Descriptor -------------//
+enum
+{
+  #if CFG_TUD_CDC
+    ITF_NUM_CDC = 0,
+    ITF_NUM_CDC_DATA,
+  #endif
+
+  #if CFG_TUD_MSC
+    ITF_NUM_MSC,
+  #endif
+
+  #if CFG_TUD_HID
+    ITF_NUM_HID,
+  #endif
+
+    ITF_NUM_TOTAL
+};
+
+enum
+{
+  CONFIG_DESC_LEN = sizeof(tusb_desc_configuration_t) + 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
+  // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+  // Note: since CDC EP ( 1 & 2), HID (4) are spot-on, thus we only need to force
+  // endpoint number for MSC to 5
+  #define EPNUM_MSC   0x05
+#else
+  #define EPNUM_MSC   0x03
+#endif
+
+uint8_t const desc_configuration[] =
+{
+  // Config: self-powered with remote wakeup support, max power up to 100 mA
+  TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_DESC_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+#if CFG_TUD_CDC
+  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, 0x02, 0x82, 64),
+#endif
+
+#if CFG_TUD_MSC
+  TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC, 0x80 | EPNUM_MSC, 64), // highspeed 512
+#endif
+
+#if CFG_TUD_HID
+  TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_PROTOCOL_KEYBOARD, sizeof(desc_hid_report), 0x84, 16, 10)
+#endif
+};
+
+//------------- String Descriptors -------------//
+// array of pointer to string descriptors
+uint16_t const * const string_desc_arr [] =
+{
+  // 0: is supported language = English
+  TUD_DESC_STRCONV(0x0409),
+
+  // 1: Manufacturer
+  TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g'),
+
+  // 2: Product
+  TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'd', 'e', 'v', 'i', 'c', 'e'),
+
+  // 3: Serials, should use chip ID
+  TUD_DESC_STRCONV('1', '2', '3', '4', '5', '6'),
+
+  // 4: CDC Interface
+  TUD_DESC_STRCONV('t','u','s','b',' ','c','d','c'),
+
+  // 5: MSC Interface
+  TUD_DESC_STRCONV('t','u','s','b',' ','m','s','c'),
+
+  // 6: HID
+  TUD_DESC_STRCONV('t','u','s','b',' ','h','i','d')
+};
+
+// tud_desc_set is required by tinyusb stack
+tud_desc_set_t tud_desc_set =
+{
+    .device     = &desc_device,
+    .config     = desc_configuration,
+
+    .string_arr   = (uint8_t const **) string_desc_arr,
+    .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]),
+
+    .hid_report = desc_hid_report,
+};

+ 6 - 6
examples/host/cdc_msc_hid/src/main.c

@@ -37,8 +37,8 @@
 void print_greeting(void);
 void led_blinking_task(void);
 
-extern void virtual_com_task(void);
-extern void usb_hid_task(void);
+extern void cdc_task(void);
+extern void hid_task(void);
 
 /*------------- MAIN -------------*/
 int main(void)
@@ -56,11 +56,11 @@ int main(void)
     led_blinking_task();
 
 #if CFG_TUH_CDC
-    virtual_com_task();
+    cdc_task();
 #endif
 
 #if CFG_TUD_HID
-    usb_hid_task();
+    hid_task();
 #endif
   }
 
@@ -100,7 +100,7 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
   tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // waiting for next data
 }
 
-void virtual_com_task(void)
+void cdc_task(void)
 {
 
 }
@@ -111,7 +111,7 @@ void virtual_com_task(void)
 // USB HID
 //--------------------------------------------------------------------+
 #if CFG_TUH_HID_KEYBOARD
-void usb_hid_task(void)
+void hid_task(void)
 {
 
 }

+ 6 - 0
hw/bsp/board.h

@@ -95,6 +95,12 @@ static inline void board_led_off(void)
   board_led_write(false);
 }
 
+static inline void board_delay(uint32_t ms)
+{
+  uint32_t start_ms = board_millis();
+  while( board_millis() < start_ms + ms) {}
+}
+
 static inline int8_t board_uart_getchar(void)
 {
   uint8_t c;

+ 35 - 3
src/class/cdc/cdc_device.h

@@ -94,6 +94,41 @@ ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
 ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
 ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
 
+//--------------------------------------------------------------------+
+// Interface Descriptor Template
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 66 bytes
+#define TUD_CDC_DESC_LEN  (8+9+5+5+4+5+7+9+7+7)
+
+// CDC Descriptor Template
+// interface number, string index, EP notification address and size, EP data address (out,in) and size.
+#define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
+  /* Interface Associate */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, _stridx,\
+  /* CDC Header */\
+  5, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
+  /* CDC Call */\
+  5, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (_itfnum) + 1,\
+  /* CDC ACM: support line request */\
+  4, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
+  /* CDC Union */\
+  5, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_UNION, _itfnum, (_itfnum) + 1,\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\
+  /* CDC Data Interface */\
+  9, TUSB_DESC_INTERFACE, (_itfnum)+1, 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* 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
+
+
+/** @} */
+/** @} */
+
 //--------------------------------------------------------------------+
 // INTERNAL USBD-CLASS DRIVER API
 //--------------------------------------------------------------------+
@@ -109,6 +144,3 @@ void cdcd_reset              (uint8_t rhport);
 #endif
 
 #endif /* _TUSB_CDC_DEVICE_H_ */
-
-/** @} */
-/** @} */

+ 1 - 1
src/class/hid/hid.h

@@ -179,7 +179,7 @@ typedef enum
 /// Standard HID Boot Protocol Keyboard Report.
 typedef struct ATTR_PACKED
 {
-  uint8_t modifier;   /**< Keyboard modifier byte, indicating pressed modifier keys (a combination of HID_KEYBOARD_MODIFER_* masks). */
+  uint8_t modifier;   /**< Keyboard modifier (KEYBOARD_MODIFER_* masks). */
   uint8_t reserved;   /**< Reserved for OEM use, always set to 0. */
   uint8_t keycode[6]; /**< Key codes of the currently pressed keys. */
 } hid_keyboard_report_t;

+ 73 - 219
src/class/hid/hid_device.c

@@ -39,61 +39,31 @@
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
 
-// Max report len is keyboard's one with 8 byte + 1 byte report id
-#define REPORT_BUFSIZE      12
-
-#define ITF_IDX_BOOT_KBD   0
-#define ITF_IDX_BOOT_MSE   ( ITF_IDX_BOOT_KBD + (CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT) )
-#define ITF_IDX_GENERIC    ( ITF_IDX_BOOT_MSE + (CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT) )
-#define ITF_COUNT          ( ITF_IDX_GENERIC + 1 )
+#ifndef CFG_TUD_HID_BUFSIZE
+#define CFG_TUD_HID_BUFSIZE     16
+#endif
 
 typedef struct
 {
   uint8_t itf_num;
   uint8_t ep_in;
+  uint8_t boot_protocol; // Boot mouse or keyboard
+  bool    boot_mode;
 
-  uint8_t idle_rate; // in unit of 4 ms TODO removed
-  bool    boot_protocol;
-
-  uint16_t desc_len;
-  uint8_t const * desc_report;
-
-  CFG_TUSB_MEM_ALIGN uint8_t report_buf[REPORT_BUFSIZE];
-
-  // callbacks
-  uint16_t (*get_report_cb) (uint8_t report_id, hid_report_type_t type, uint8_t* buffer, uint16_t reqlen);
-  void     (*set_report_cb) (uint8_t report_id, hid_report_type_t type, uint8_t const* buffer, uint16_t bufsize);
+  uint16_t reprot_desc_len;
+  uint8_t idle_rate;     // Idle Rate = 0 : only send report if there is changes, i.e skip duplication
+                         // Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
+  uint8_t mouse_button;  // caching button for using with tud_hid_mouse_ API
 
+  CFG_TUSB_MEM_ALIGN uint8_t report_buf[CFG_TUD_HID_BUFSIZE];
 }hidd_interface_t;
 
-typedef struct
-{
-  uint8_t usage;      // HID_USAGE_*
-  uint8_t idle_rate;  // Idle Rate = 0 : only send report if there is changes, i.e skip duplication
-                      // Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
-                      //                 If idle time is less than interrupt polling then use the polling.
-
-  uint8_t report_id;
-  uint8_t report_len;
-
-  hidd_interface_t* itf;
-} hidd_report_t ;
-
-CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[ITF_COUNT] = { { 0 } };
-
-
-#if CFG_TUD_HID_KEYBOARD
-static hidd_report_t _kbd_rpt;
-#endif
-
-#if CFG_TUD_HID_MOUSE
-static hidd_report_t _mse_rpt;
-#endif
+CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID];
 
 /*------------- Helpers -------------*/
 static inline hidd_interface_t* get_interface_by_itfnum(uint8_t itf_num)
 {
-  for (uint8_t i=0; i < ITF_COUNT; i++ )
+  for (uint8_t i=0; i < CFG_TUD_HID; i++ )
   {
     if ( itf_num == _hidd_itf[i].itf_num ) return &_hidd_itf[i];
   }
@@ -101,20 +71,22 @@ static inline hidd_interface_t* get_interface_by_itfnum(uint8_t itf_num)
   return NULL;
 }
 
-
 //--------------------------------------------------------------------+
-// HID GENERIC API
+// APPLICATION API
 //--------------------------------------------------------------------+
-bool tud_hid_generic_ready(void)
+bool tud_hid_ready(void)
 {
-  return tud_ready() && (_hidd_itf[ITF_IDX_GENERIC].ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, _hidd_itf[ITF_IDX_GENERIC].ep_in);
+  uint8_t itf = 0;
+  uint8_t const ep_in = _hidd_itf[itf].ep_in;
+  return tud_ready() && (ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, ep_in);
 }
 
-bool tud_hid_generic_report(uint8_t report_id, void const* report, uint8_t len)
+bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
 {
-  TU_VERIFY( tud_hid_generic_ready() && (len < REPORT_BUFSIZE) );
+  TU_VERIFY( tud_hid_ready() && (len < CFG_TUD_HID_BUFSIZE) );
 
-  hidd_interface_t * p_hid = &_hidd_itf[ITF_IDX_GENERIC];
+  uint8_t itf = 0;
+  hidd_interface_t * p_hid = &_hidd_itf[itf];
 
   // If report id = 0, skip ID field
   if (report_id)
@@ -126,44 +98,24 @@ bool tud_hid_generic_report(uint8_t report_id, void const* report, uint8_t len)
     memcpy(p_hid->report_buf, report, len);
   }
 
-  // TODO idle rate
-  return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->report_buf, len + ( report_id ? 1 : 0) );
-}
-
-//--------------------------------------------------------------------+
-// KEYBOARD APPLICATION API
-//--------------------------------------------------------------------+
-#if CFG_TUD_HID_KEYBOARD
-bool tud_hid_keyboard_ready(void)
-{
-  return (_kbd_rpt.itf != NULL) && !dcd_edpt_busy(TUD_OPT_RHPORT, _kbd_rpt.itf->ep_in);
+  // TODO skip duplication ? and or idle rate
+  return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->report_buf, len + (report_id ? 1 : 0) );
 }
 
-bool tud_hid_keyboard_is_boot_protocol(void)
+bool tud_hid_boot_mode(void)
 {
-  return (_kbd_rpt.itf != NULL) && _kbd_rpt.itf->boot_protocol;
+  uint8_t itf = 0;
+  return _hidd_itf[itf].boot_mode;
 }
 
-static bool hidd_kbd_report(hid_keyboard_report_t const *p_report)
+//--------------------------------------------------------------------+
+// KEYBOARD API
+//--------------------------------------------------------------------+
+bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
 {
-  TU_VERIFY( tud_hid_keyboard_ready() );
-
-  hidd_interface_t * p_hid = _kbd_rpt.itf;
+  hid_keyboard_report_t report;
 
-  // only send report if there is changes, i.e skip duplication
-//  if ( _kbd_rpt.idle_rate == 0 )
-//  {
-//    if ( 0 == memcmp(p_hid->report_buf, p_report, sizeof(hid_keyboard_report_t)) ) return true;
-//  }
-
-  memcpy(p_hid->report_buf, p_report, sizeof(hid_keyboard_report_t));
-
-  return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->report_buf, sizeof(hid_keyboard_report_t));
-}
-
-bool tud_hid_keyboard_keycode(uint8_t modifier, uint8_t keycode[6])
-{
-  hid_keyboard_report_t report = { .modifier = modifier };
+  report.modifier = modifier;
 
   if ( keycode )
   {
@@ -173,12 +125,12 @@ bool tud_hid_keyboard_keycode(uint8_t modifier, uint8_t keycode[6])
     tu_memclr(report.keycode, 6);
   }
 
-  return hidd_kbd_report(&report);
+  // TODO skip duplication ? and or idle rate
+  return tud_hid_report(report_id, &report, sizeof(report));
 }
 
 #if CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP
-
-bool tud_hid_keyboard_key_press(char ch)
+bool tud_hid_keyboard_key_press(uint8_t report_id, char ch)
 {
   uint8_t keycode[6] = { 0 };
   uint8_t modifier   = 0;
@@ -186,75 +138,47 @@ bool tud_hid_keyboard_key_press(char ch)
   if ( HID_ASCII_TO_KEYCODE[(uint8_t)ch].shift ) modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
   keycode[0] = HID_ASCII_TO_KEYCODE[(uint8_t)ch].keycode;
 
-  return tud_hid_keyboard_keycode(modifier, keycode);
+  return tud_hid_keyboard_report(report_id, modifier, keycode);
 }
-
 #endif // CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP
 
-#endif // CFG_TUD_HID_KEYBOARD
-
 //--------------------------------------------------------------------+
 // MOUSE APPLICATION API
 //--------------------------------------------------------------------+
-#if CFG_TUD_HID_MOUSE
-
-bool tud_hid_mouse_ready(void)
-{
-  return (_mse_rpt.itf != NULL) && !dcd_edpt_busy(TUD_OPT_RHPORT, _mse_rpt.itf->ep_in);
-}
-
-bool tud_hid_mouse_is_boot_protocol(void)
-{
-  return (_mse_rpt.itf != NULL) && _mse_rpt.itf->boot_protocol;
-}
-
-static bool hidd_mouse_report(hid_mouse_report_t const *p_report)
-{
-  TU_VERIFY( tud_hid_mouse_ready() );
-
-  hidd_interface_t * p_hid = _mse_rpt.itf;
-// only send report if there is changes, i.e skip duplication
-  memcpy(p_hid->report_buf, p_report, sizeof(hid_mouse_report_t));
-
-  return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->report_buf, sizeof(hid_mouse_report_t));
-}
-
-bool tud_hid_mouse_data(uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan)
+bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan)
 {
+  (void) pan;
   hid_mouse_report_t report =
   {
-      .buttons = buttons,
-      .x       = x,
-      .y       = y,
-      .wheel   = scroll,
-//      .pan     = pan
+    .buttons = buttons,
+    .x       = x,
+    .y       = y,
+    .wheel   = scroll,
+    //.pan     = pan
   };
 
-  return hidd_mouse_report( &report );
+  uint8_t itf = 0;
+  _hidd_itf[itf].mouse_button = buttons;
+
+  return tud_hid_report(report_id, &report, sizeof(report));
 }
 
-bool tud_hid_mouse_move(int8_t x, int8_t y)
+bool tud_hid_mouse_move(uint8_t report_id, int8_t x, int8_t y)
 {
-  TU_VERIFY( tud_hid_mouse_ready() );
-
-  hidd_interface_t * p_hid = _mse_rpt.itf;
-  uint8_t prev_buttons = p_hid->report_buf[0];
+  uint8_t itf = 0;
+  uint8_t const button = _hidd_itf[itf].mouse_button;
 
-  return tud_hid_mouse_data(prev_buttons, x, y, 0, 0);
+  return tud_hid_mouse_report(report_id, button, x, y, 0, 0);
 }
 
-bool tud_hid_mouse_scroll(int8_t vertical, int8_t horizontal)
+bool tud_hid_mouse_scroll(uint8_t report_id, int8_t scroll, int8_t pan)
 {
-  TU_VERIFY( tud_hid_mouse_ready() );
+  uint8_t itf = 0;
+  uint8_t const button = _hidd_itf[itf].mouse_button;
 
-  hidd_interface_t * p_hid =  _mse_rpt.itf;
-  uint8_t prev_buttons = p_hid->report_buf[0];
-
-  return tud_hid_mouse_data(prev_buttons, 0, 0, vertical, horizontal);
+  return tud_hid_mouse_report(report_id, button, 0, 0, scroll, pan);
 }
 
-#endif // CFG_TUD_HID_MOUSE
-
 //--------------------------------------------------------------------+
 // USBD-CLASS API
 //--------------------------------------------------------------------+
@@ -267,23 +191,12 @@ void hidd_reset(uint8_t rhport)
 {
   (void) rhport;
   tu_memclr(_hidd_itf, sizeof(_hidd_itf));
-
-  #if CFG_TUD_HID_KEYBOARD
-  tu_varclr(&_kbd_rpt);
-  #endif
-
-  #if CFG_TUD_HID_MOUSE
-  tu_varclr(&_mse_rpt);
-  #endif
 }
 
 bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t *p_len)
 {
   uint8_t const *p_desc = (uint8_t const *) desc_itf;
 
-  // TODO support HID OUT Endpoint
-  TU_ASSERT(desc_itf->bNumEndpoints == 1);
-
   //------------- HID descriptor -------------//
   p_desc = tu_desc_next(p_desc);
   tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
@@ -294,65 +207,18 @@ bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t
   tusb_desc_endpoint_t const *desc_edpt = (tusb_desc_endpoint_t const *) p_desc;
   TU_ASSERT(TUSB_DESC_ENDPOINT == desc_edpt->bDescriptorType);
 
-  hidd_interface_t * p_hid = NULL;
-
-  /*------------- Boot protocol only keyboard & mouse -------------*/
-  if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT)
-  {
-    TU_ASSERT(desc_itf->bInterfaceProtocol == HID_PROTOCOL_KEYBOARD || desc_itf->bInterfaceProtocol == HID_PROTOCOL_MOUSE);
-
-    #if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-    if (desc_itf->bInterfaceProtocol == HID_PROTOCOL_KEYBOARD)
-    {
-      p_hid = &_hidd_itf[ITF_IDX_BOOT_KBD];
-      p_hid->desc_report   = usbd_desc_set->hid_report.boot_keyboard;
-      p_hid->get_report_cb = tud_hid_keyboard_get_report_cb;
-      p_hid->set_report_cb = tud_hid_keyboard_set_report_cb;
-
-      hidd_report_t* report = &_kbd_rpt;
-      report->usage = HID_USAGE_DESKTOP_KEYBOARD;
-      report->report_id = 0;
-      report->report_len = 8;
-      report->itf = p_hid;
-    }
-    #endif
-
-    #if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-    if (desc_itf->bInterfaceProtocol == HID_PROTOCOL_MOUSE)
-    {
-      p_hid = &_hidd_itf[ITF_IDX_BOOT_MSE];
-      p_hid->desc_report   = usbd_desc_set->hid_report.boot_mouse;
-      p_hid->get_report_cb = tud_hid_mouse_get_report_cb;
-      p_hid->set_report_cb = tud_hid_mouse_set_report_cb;
-
-      hidd_report_t* report = &_mse_rpt;
-      report->usage = HID_USAGE_DESKTOP_MOUSE;
-      report->report_id = 0;
-      report->report_len = 4;
-      report->itf = p_hid;
-    }
-    #endif
-
-    TU_ASSERT(p_hid);
-    p_hid->boot_protocol = true; // default mode is BOOT
-  }
-  /*------------- Generic (multiple report) -------------*/
-  else
-  {
-    // TODO parse report ID for keyboard, mouse
-    p_hid = &_hidd_itf[ITF_IDX_GENERIC];
+  TU_ASSERT(dcd_edpt_open(rhport, desc_edpt));
 
-    p_hid->desc_report   = usbd_desc_set->hid_report.generic;
-    p_hid->get_report_cb = tud_hid_generic_get_report_cb;
-    p_hid->set_report_cb = tud_hid_generic_set_report_cb;
-  }
+  // TODO support multiple HID interface
+  uint8_t itf = 0;
+  hidd_interface_t * p_hid = &_hidd_itf[itf];
 
-  TU_ASSERT(p_hid->desc_report);
-  TU_ASSERT(dcd_edpt_open(rhport, desc_edpt));
+  if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->boot_protocol = desc_itf->bInterfaceProtocol;
 
+  p_hid->boot_mode = false; // default mode is REPORT
   p_hid->itf_num   = desc_itf->bInterfaceNumber;
   p_hid->ep_in     = desc_edpt->bEndpointAddress;
-  p_hid->desc_len  = desc_hid->wReportLength;
+  p_hid->reprot_desc_len  = desc_hid->wReportLength;
 
   *p_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
 
@@ -375,7 +241,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)
     {
-      usbd_control_xfer(rhport, p_request, (void *)p_hid->desc_report, p_hid->desc_len);
+      usbd_control_xfer(rhport, p_request, (void*) tud_desc_set.hid_report, p_hid->reprot_desc_len);
     }else
     {
       return false; // stall unsupported request
@@ -392,17 +258,9 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
         uint8_t const report_type = tu_u16_high(p_request->wValue);
         uint8_t const report_id   = tu_u16_low(p_request->wValue);
 
-        uint16_t xferlen;
-        if ( p_hid->get_report_cb )
-        {
-          xferlen = p_hid->get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
-        }else
-        {
-          // For boot Interface only: re-use report_buf -> report has no change
-          xferlen = p_request->wLength;
-        }
-
+        uint16_t xferlen  = tud_hid_get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
         TU_ASSERT( xferlen > 0 );
+
         usbd_control_xfer(rhport, p_request, p_hid->report_buf, xferlen);
       }
       break;
@@ -424,13 +282,16 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
 
       case HID_REQ_CONTROL_GET_PROTOCOL:
       {
-        uint8_t protocol = 1-p_hid->boot_protocol;   // 0 is Boot, 1 is Report protocol
+        uint8_t protocol = 1-p_hid->boot_mode;   // 0 is Boot, 1 is Report protocol
         usbd_control_xfer(rhport, p_request, &protocol, 1);
       }
       break;
 
       case HID_REQ_CONTROL_SET_PROTOCOL:
-        p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
+        p_hid->boot_mode = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
+
+        if (tud_hid_mode_changed_cb) tud_hid_mode_changed_cb(p_hid->boot_mode);
+
         usbd_control_status(rhport, p_request);
       break;
 
@@ -459,10 +320,7 @@ bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const
     uint8_t const report_type = tu_u16_high(p_request->wValue);
     uint8_t const report_id   = tu_u16_low(p_request->wValue);
 
-    if ( p_hid->set_report_cb )
-    {
-      p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
-    }
+    tud_hid_set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
   }
 
   return true;
@@ -480,11 +338,8 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
 }
 
 
-/*------------------------------------------------------------------*/
-/* Ascii to Keycode
- *------------------------------------------------------------------*/
+//------------- Ascii to Keycode Lookup -------------//
 #if CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP
-
 const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128] =
 {
     {0, 0                     }, // 0x00 Null
@@ -619,7 +474,6 @@ const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128] =
     {1, HID_KEY_GRAVE         }, // 0x7E ~
     {0, HID_KEY_DELETE        }  // 0x7F Delete
 };
-
-#endif
+#endif // CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP
 
 #endif

+ 70 - 130
src/class/hid/hid_device.h

@@ -42,47 +42,47 @@
 #define CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP 0
 #endif
 
-#if !CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-#error CFG_TUD_HID_KEYBOARD must be enabled
-#endif
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
 
-#if !CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-#error CFG_TUD_HID_MOUSE must be enabled
-#endif
+// Check if the interface is ready to use
+bool tud_hid_ready(void);
 
+// Check if current mode is Boot (true) or Report (false)
+bool tud_hid_boot_mode(void);
 
-//--------------------------------------------------------------------+
-// HID GENERIC API
-//--------------------------------------------------------------------+
-bool tud_hid_generic_ready(void);
-bool tud_hid_generic_report(uint8_t report_id, void const* report, uint8_t len);
+// Send report to host
+bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
 
 /*------------- Callbacks (Weak is optional) -------------*/
-uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
-void     tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
+
+// Invoked when receiving GET_REPORT control request
+// Application must fill buffer report's content and return its length.
+// Return zero will cause the stack to STALL request
+uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
+
+// Invoked when receiving SET_REPORT control request
+void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
+
+// Invoked when host switch mode Boot <-> Report via SET_PROTOCOL request
+void tud_hid_mode_changed_cb(uint8_t boot_mode) ATTR_WEAK;
 
 //--------------------------------------------------------------------+
 // KEYBOARD API
+// Convenient helper to send keyboard report if application use standard/boot
+// layout report as defined by hid_keyboard_report_t
 //--------------------------------------------------------------------+
-#if CFG_TUD_HID_KEYBOARD
-/** \addtogroup ClassDriver_HID_Keyboard Keyboard
- *  @{ */
-/** \defgroup Keyboard_Device Device
- *  @{ */
-
-/** Check if the interface is ready to use
- * \returns true if ready, otherwise interface may not be mounted or still busy transferring data
- * \note    Application must not perform any action if the interface is not ready
- */
-bool tud_hid_keyboard_ready(void);
-bool tud_hid_keyboard_is_boot_protocol(void);
 
-bool tud_hid_keyboard_keycode(uint8_t modifier, uint8_t keycode[6]);
+bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
 
-static inline bool tud_hid_keyboard_key_release(void) { return tud_hid_keyboard_keycode(0, NULL); }
+static inline bool tud_hid_keyboard_key_release(uint8_t report_id)
+{
+  return tud_hid_keyboard_report(report_id, 0, NULL);
+}
 
 #if CFG_TUD_HID_ASCII_TO_KEYCODE_LOOKUP
-bool tud_hid_keyboard_key_press(char ch);
+bool tud_hid_keyboard_key_press(uint8_t report_id, char ch);
 
 typedef struct{
   uint8_t shift;
@@ -91,115 +91,59 @@ typedef struct{
 extern const hid_ascii_to_keycode_entry_t HID_ASCII_TO_KEYCODE[128];
 #endif
 
-#endif
-
-/*------------- Callbacks (Weak is optional) -------------*/
-
-/** Callback invoked when USB host request \ref HID_REQ_CONTROL_GET_REPORT.
- * \param[in]   report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
- * \param[out]  buffer data that application need to update, value must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
- * \param[in]   reqlen  number of bytes that host requested
- * \retval      non-zero Actual number of bytes in the response's buffer.
- * \retval      zero  indicates the current request is not supported. Tinyusb device stack will reject the request by
- *              sending STALL in the data phase.
- * \note        After this callback, the request is silently executed by the tinyusb stack, thus
- *              the completion of this control request will not be reported to application.
- *              For Keyboard, USB host often uses this to turn on/off the LED for CAPLOCKS, NUMLOCK (\ref hid_keyboard_led_bm_t)
- */
-ATTR_WEAK uint16_t tud_hid_keyboard_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
-
-/** Callback invoked when USB host request \ref HID_REQ_CONTROL_SET_REPORT.
- * \param[in]   report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
- * \param[in]   buffer  containing the report's data
- * \param[in]   bufsize  number of bytes in the \a buffer
- * \note        By the time this callback is invoked, the USB control transfer is already completed in the hardware side.
- *              Application are free to handle data at its own will.
- */
-ATTR_WEAK void tud_hid_keyboard_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
-
-
-//ATTR_WEAK void tud_hid_keyboard_set_protocol_cb(bool boot_protocol);
-
-/** @} */
-/** @} */
-
 //--------------------------------------------------------------------+
 // MOUSE API
+// Convenient helper to send mouse report if application use standard/boot
+// layout report as defined by hid_mouse_report_t
 //--------------------------------------------------------------------+
-#if CFG_TUD_HID_MOUSE
-/** \addtogroup ClassDriver_HID_Mouse Mouse
- *  @{ */
-/** \defgroup Mouse_Device Device
- *  @{ */
-
-/** \brief      Check if the interface is currently busy or not
- * \retval      true if the interface is busy meaning the stack is still transferring/waiting data from/to host
- * \retval      false if the interface is not busy meaning the stack successfully transferred data from/to host
- * \note        This function is primarily used for polling/waiting result after \ref tusbd_hid_mouse_send.
- */
-bool tud_hid_mouse_ready(void);
-bool tud_hid_mouse_is_boot_protocol(void);
 
-bool tud_hid_mouse_data(uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan);
+bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan);
+bool tud_hid_mouse_move(uint8_t report_id, int8_t x, int8_t y);
+bool tud_hid_mouse_scroll(uint8_t report_id, int8_t scroll, int8_t pan);
 
-bool tud_hid_mouse_move(int8_t x, int8_t y);
-bool tud_hid_mouse_scroll(int8_t vertical, int8_t horizontal);
-
-static inline bool tud_hid_mouse_button_press(uint8_t buttons)
+static inline bool tud_hid_mouse_button_press(uint8_t report_id, uint8_t buttons)
 {
-  return tud_hid_mouse_data(buttons, 0, 0, 0, 0);
+  return tud_hid_mouse_report(report_id, buttons, 0, 0, 0, 0);
 }
 
-static inline bool tud_hid_mouse_button_release(void)
+static inline bool tud_hid_mouse_button_release(uint8_t report_id)
 {
-  return tud_hid_mouse_data(0, 0, 0, 0, 0);
+  return tud_hid_mouse_report(report_id, 0, 0, 0, 0, 0);
 }
 
-/*------------- Callbacks (Weak is optional) -------------*/
-
-/**
- * Callback function that is invoked when USB host request \ref HID_REQ_CONTROL_GET_REPORT.
- * \param[in]   report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
- * \param[out]  buffer  buffer that application need to update, value must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
- * \param[in]   reqlen  number of bytes that host requested
- * \retval      non-zero Actual number of bytes in the response's buffer.
- * \retval      zero  indicates the current request is not supported. Tinyusb device stack will reject the request by
- *              sending STALL in the data phase.
- * \note        After this callback, the request is silently executed by the tinyusb stack, thus
- *              the completion of this control request will not be reported to application
- */
-ATTR_WEAK uint16_t tud_hid_mouse_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
-
-/**
- * Callback function that is invoked when USB host request \ref HID_REQ_CONTROL_SET_REPORT.
- * \param[in]   report_type specify which report (INPUT, OUTPUT, FEATURE) that host requests
- * \param[in]   buffer buffer containing the report's data
- * \param[in]   bufsize  number of bytes in the \a p_report_data
- * \note        By the time this callback is invoked, the USB control transfer is already completed in the hardware side.
- *              Application are free to handle data at its own will.
- */
-ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
+//--------------------------------------------------------------------+
+// Interface Descriptor Template
+//--------------------------------------------------------------------+
 
-//ATTR_WEAK void tud_hid_mouse_set_protocol_cb(bool boot_protocol);
+#define TUD_HID_DESC_LEN    (9 + 9 + 7)
 
-#endif
+#define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (_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 descriptor */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
 
-
-//--------------------------------------------------------------------+
-// HID Report Descriptor Template
-//--------------------------------------------------------------------+
-/* These template should be used as follow
- * - Only 1 report : no parameter
- *      uint8_t report_desc[] = { ID_REPORT_DESC_KEYBOARD() };
+/* --------------------------------------------------------------------+
+ * HID Report Descriptor Template
+ *
+ * Convenient for declaring popular HID device (keyboard, mouse, consumer,
+ * gamepad etc...). Templates take "HID_REPORT_ID(n)," as input, leave
+ * empty if multiple reports is not used
+ *
+ * - Only 1 report: no parameter
+ *      uint8_t const report_desc[] = { HID_REPORT_DESC_KEYBOARD() };
  *
  * - Multiple Reports: "HID_REPORT_ID(ID)," must be passed to template
- *      uint8_t report_desc[] = {
- *          ID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1) ,) ,
- *          HID_REPORT_DESC_MOUSE  ( HID_REPORT_ID(2) ,)
+ *      uint8_t const report_desc[] =
+ *      {
+ *          HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ) ,
+ *          HID_REPORT_DESC_MOUSE   ( HID_REPORT_ID(2), )
  *      };
- */
+ *--------------------------------------------------------------------*/
 
-/*------------- Keyboard Descriptor Template -------------*/
+// Keyboard Report Descriptor Template
 #define HID_REPORT_DESC_KEYBOARD(...) \
   HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP     )                    ,\
   HID_USAGE      ( HID_USAGE_DESKTOP_KEYBOARD )                    ,\
@@ -240,7 +184,7 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
       HID_OUTPUT       ( HID_CONSTANT                            ) ,\
   HID_COLLECTION_END \
 
-/*------------- Mouse Descriptor Template -------------*/
+// Mouse Report Descriptor Template
 #define HID_REPORT_DESC_MOUSE(...) \
   HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP      )                    ,\
   HID_USAGE      ( HID_USAGE_DESKTOP_MOUSE     )                    ,\
@@ -280,7 +224,7 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
     HID_COLLECTION_END                                              ,\
   HID_COLLECTION_END \
 
-//------------- Consumer Control Report Template -------------//
+// Consumer Control Report Descriptor Template
 #define HID_REPORT_DESC_CONSUMER(...) \
   HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER    )              ,\
   HID_USAGE      ( HID_USAGE_CONSUMER_CONTROL )              ,\
@@ -295,8 +239,8 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
     HID_INPUT        ( HID_DATA | HID_ARRAY | HID_ABSOLUTE ) ,\
   HID_COLLECTION_END \
 
-//------------- System Control Report Template -------------//
-/* 0x00 - do nothing
+/* System Control Report Descriptor Template
+ * 0x00 - do nothing
  * 0x01 - Power Off
  * 0x02 - Standby
  * 0x04 - Wake Host
@@ -321,8 +265,8 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
     HID_INPUT        ( HID_CONSTANT                        ) ,\
   HID_COLLECTION_END \
 
-//------------- Gamepad Report Template -------------//
-// Gamepad with 16 buttons and 2 joysticks
+// Gamepad Report Descriptor Template
+// with 16 buttons and 2 joysticks with following layout
 // | Button Map (2 bytes) |  X | Y | Z | Rz
 #define HID_REPORT_DESC_GAMEPAD(...) \
   HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP     )        ,\
@@ -351,15 +295,11 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
     HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
   HID_COLLECTION_END \
 
-
-
 /** @} */
 /** @} */
 
-
-
 //--------------------------------------------------------------------+
-// INTERNAL API
+// 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);

+ 0 - 1
src/class/msc/msc_device.c

@@ -113,7 +113,6 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u
   return true;
 }
 
-
 //--------------------------------------------------------------------+
 // USBD-CLASS API
 //--------------------------------------------------------------------+

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

@@ -31,6 +31,9 @@
 #include "device/usbd.h"
 #include "msc.h"
 
+#ifdef __cplusplus
+ extern "C" {
+#endif
 
 //--------------------------------------------------------------------+
 // Class Driver Configuration
@@ -44,7 +47,7 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
 #endif
 
 #ifndef CFG_TUD_MSC_BUFSIZE
-  #error CFG_TUD_MSC_BUFSIZE must be defined, value of CFG_TUD_MSC_BLOCK_SZ should work well, the more the better
+  #error CFG_TUD_MSC_BUFSIZE must be defined, value of a block size should work well, the more the better
 #endif
 
 #ifndef CFG_TUD_MSC_VENDOR
@@ -59,10 +62,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
   #error CFG_TUD_MSC_PRODUCT_REV 4-byte string must be defined
 #endif
 
-#ifdef __cplusplus
- extern "C" {
-#endif
-
 /** \addtogroup ClassDriver_MSC
  *  @{
  * \defgroup MSC_Device Device
@@ -133,7 +132,7 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
  */
 int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize);
 
-/*------------- Optional callbacks : Could be used by application to free up resources -------------*/
+/*------------- Optional callbacks -------------*/
 
 // Invoked when Read10 command is complete
 ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
@@ -147,6 +146,23 @@ ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16])
 // Hook to make a mass storage device read-only. TODO remove
 ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
 
+//--------------------------------------------------------------------+
+// Interface Descriptor Template
+//--------------------------------------------------------------------+
+
+// Length of template descriptor: 23 bytes
+#define TUD_MSC_DESC_LEN    (9 + 7 + 7)
+
+// Interface Number, EP Out & EP In address
+#define TUD_MSC_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  /* Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_MSC, MSC_SUBCLASS_SCSI, MSC_PROTOCOL_BOT, _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
+
+
 /** @} */
 /** @} */
 

+ 7 - 16
src/common/compiler/tusb_compiler_gcc.h

@@ -35,34 +35,25 @@
  extern "C" {
 #endif
 
-#define ALIGN_OF(x) __alignof__(x)
+#define ALIGN_OF(x)                __alignof__(x)
 
-/// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes
+// Specifies a minimum alignment for the variable or structure field, measured in bytes
 #define ATTR_ALIGNED(Bytes)        __attribute__ ((aligned(Bytes)))
 
-/// Place variable in a specific section
+// Place variable in a specific section
 #define ATTR_SECTION(sec_name)      __attribute__ (( section(#sec_name) ))
 
-/// The packed attribute specifies that a variable or structure field should have
-/// the smallest possible alignment—one byte for a variable, and one bit for a field.
+// Packed struct/variable into smallest possible size
 #define ATTR_PACKED                __attribute__ ((packed))
 #define ATTR_PREPACKED
 
-/// This attribute inlines the function even if no optimization level is specified
-#define ATTR_ALWAYS_INLINE         __attribute__ ((always_inline))
-
-/// The deprecated attribute results in a warning if the function is used anywhere in the source file.
-/// This is useful when identifying functions that are expected to be removed in a future version of a program.
+// The deprecated attribute results in a warning if the function is used.
 #define ATTR_DEPRECATED(mess)      __attribute__ ((deprecated(mess)))
 
-/// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global.
-/// This is primarily useful in defining library functions that can be overridden in user code
+// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global.
 #define ATTR_WEAK                  __attribute__ ((weak))
 
-/// Warn if a caller of the function with this attribute does not use its return value.
-#define ATTR_WARN_UNUSED_RESULT    __attribute__ ((warn_unused_result))
-
-/// Function is meant to be possibly unused. GCC does not produce a warning for this function.
+// Function/Variable is meant to be possibly unused (thus no warning)
 #define ATTR_UNUSED                __attribute__ ((unused))
 
 // TODO mcu specific

+ 2 - 4
src/common/compiler/tusb_compiler_iar.h

@@ -36,12 +36,8 @@
 //#define ATTR_SECTION(section)      _Pragma((#section))
 #define ATTR_PREPACKED            __packed
 #define ATTR_PACKED
-
-#define ATTR_ALWAYS_INLINE
 #define ATTR_DEPRECATED(mess)
 #define ATTR_WEAK                 __weak
-
-#define ATTR_WARN_UNUSED_RESULT
 #define ATTR_UNUSED
 
 // built-in function to convert 32-bit Big-Endian to Little-Endian
@@ -52,6 +48,8 @@
 #define __n2be_16(u16)  ((uint16_t) __REV16(u16))
 #define __be2n_16(u16)  __n2be_16(u16)
 
+#error "IAR won't work due to '__packed' placement before struct"
+
 #ifdef __cplusplus
  }
 #endif

+ 0 - 1
src/common/tusb_common.h

@@ -113,7 +113,6 @@
 #include "tusb_option.h"
 #include "tusb_compiler.h"
 #include "tusb_verify.h"
-//#include "binary.h"
 #include "tusb_error.h"
 #include "tusb_timeout.h"
 #include "tusb_types.h"

+ 17 - 19
src/common/tusb_types.h

@@ -127,25 +127,23 @@ typedef enum
 
 typedef enum
 {
-  TUSB_CLASS_UNSPECIFIED          = 0    , ///< 0
-  TUSB_CLASS_AUDIO                = 1    , ///< 1
-  TUSB_CLASS_CDC                  = 2    , ///< 2
-  TUSB_CLASS_HID                  = 3    , ///< 3
-  TUSB_CLASS_RESERVED_4           = 4    , ///< 4
-  TUSB_CLASS_PHYSICAL             = 5    , ///< 5
-  TUSB_CLASS_IMAGE                = 6    , ///< 6
-  TUSB_CLASS_PRINTER              = 7    , ///< 7
-  TUSB_CLASS_MSC                  = 8    , ///< 8
-  TUSB_CLASS_HUB                  = 9    , ///< 9
-  TUSB_CLASS_CDC_DATA             = 10   , ///< 10
-  TUSB_CLASS_SMART_CARD           = 11   , ///< 11
-  TUSB_CLASS_RESERVED_12          = 12   , ///< 12
-  TUSB_CLASS_CONTENT_SECURITY     = 13   , ///< 13
-  TUSB_CLASS_VIDEO                = 14   , ///< 14
-  TUSB_CLASS_PERSONAL_HEALTHCARE  = 15   , ///< 15
-  TUSB_CLASS_AUDIO_VIDEO          = 16   , ///< 16
-
-  TUSB_CLASS_MAPPED_INDEX_START   = 17   , // TODO Map DIAGNOSTIC, WIRELESS_CONTROLLER, MISC, VENDOR_SPECIFIC to this to minimize the array
+  TUSB_CLASS_UNSPECIFIED          = 0    ,
+  TUSB_CLASS_AUDIO                = 1    ,
+  TUSB_CLASS_CDC                  = 2    ,
+  TUSB_CLASS_HID                  = 3    ,
+  TUSB_CLASS_RESERVED_4           = 4    ,
+  TUSB_CLASS_PHYSICAL             = 5    ,
+  TUSB_CLASS_IMAGE                = 6    ,
+  TUSB_CLASS_PRINTER              = 7    ,
+  TUSB_CLASS_MSC                  = 8    ,
+  TUSB_CLASS_HUB                  = 9    ,
+  TUSB_CLASS_CDC_DATA             = 10   ,
+  TUSB_CLASS_SMART_CARD           = 11   ,
+  TUSB_CLASS_RESERVED_12          = 12   ,
+  TUSB_CLASS_CONTENT_SECURITY     = 13   ,
+  TUSB_CLASS_VIDEO                = 14   ,
+  TUSB_CLASS_PERSONAL_HEALTHCARE  = 15   ,
+  TUSB_CLASS_AUDIO_VIDEO          = 16   ,
 
   TUSB_CLASS_DIAGNOSTIC           = 0xDC ,
   TUSB_CLASS_WIRELESS_CONTROLLER  = 0xE0 ,

+ 3 - 11
src/device/usbd.c

@@ -60,14 +60,6 @@ typedef struct {
 
 static usbd_device_t _usbd_dev = { 0 };
 
-// Auto descriptor is enabled, descriptor set point to auto generated one
-#if CFG_TUD_DESC_AUTO
-extern tud_desc_set_t const _usbd_auto_desc_set;
-tud_desc_set_t const* usbd_desc_set = &_usbd_auto_desc_set;
-#else
-tud_desc_set_t const* usbd_desc_set = &tud_desc_set;
-#endif
-
 //--------------------------------------------------------------------+
 // Class Driver
 //--------------------------------------------------------------------+
@@ -493,7 +485,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
 // This function parse configuration descriptor & open drivers accordingly
 static bool process_set_config(uint8_t rhport)
 {
-  tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) usbd_desc_set->config;
+  tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) tud_desc_set.config;
   TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
 
   // Parse configuration descriptor
@@ -577,12 +569,12 @@ static void const* get_descriptor(tusb_control_request_t const * p_request, uint
   switch(desc_type)
   {
     case TUSB_DESC_DEVICE:
-      desc_data = (uint8_t const *) usbd_desc_set->device;
+      desc_data = (uint8_t const *) tud_desc_set.device;
       len       = sizeof(tusb_desc_device_t);
     break;
 
     case TUSB_DESC_CONFIGURATION:
-      desc_data = (uint8_t const *) usbd_desc_set->config;
+      desc_data = (uint8_t const *) tud_desc_set.config;
       len       = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength;
     break;
 

+ 9 - 6
src/device/usbd.h

@@ -45,15 +45,11 @@ typedef struct {
   uint8_t const** string_arr;     ///< a array of pointers to string descriptors
   uint16_t        string_count;
 
-  struct {
-    uint8_t const* generic;
-    uint8_t const* boot_keyboard;
-    uint8_t const* boot_mouse;
-  } hid_report;
+  uint8_t const*  hid_report;
 
 }tud_desc_set_t;
 
-// Must be defined by application
+// Descriptor collection set, must be defined by application
 extern tud_desc_set_t tud_desc_set;
 
 //--------------------------------------------------------------------+
@@ -95,6 +91,13 @@ ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
 // Invoked when usb bus is resumed
 ATTR_WEAK void tud_resume_cb(void);
 
+//--------------------------------------------------------------------+
+// Interface Descriptor Template
+//--------------------------------------------------------------------+
+
+#define TUD_CONFIG_DESCRIPTOR(_itfcount, _stridx, _total_len, _attribute, _power_ma) \
+  9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(_total_len), _itfcount, 1, _stridx, TU_BIT(7) | _attribute, (_power_ma)/2
+
 #ifdef __cplusplus
  }
 #endif

+ 0 - 648
src/device/usbd_auto_desc.c

@@ -1,648 +0,0 @@
-/* 
- * The MIT License (MIT)
- *
- * Copyright (c) 2018, hathach (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_DESC_AUTO
-
-#include "tusb.h"
-
-//--------------------------------------------------------------------+
-// Auto Description Default Configure & Validation
-//--------------------------------------------------------------------+
-
-// If HID Generic interface is generated
-#define AUTO_DESC_HID_GENERIC    (CFG_TUD_HID && ((CFG_TUD_HID_KEYBOARD && !CFG_TUD_HID_KEYBOARD_BOOT) || \
-                                                (CFG_TUD_HID_MOUSE && !CFG_TUD_HID_MOUSE_BOOT)) )
-/*------------- VID/PID -------------*/
-#ifndef CFG_TUD_DESC_VID
-#define CFG_TUD_DESC_VID       0xCAFE
-#endif
-
-#ifndef CFG_TUD_DESC_PID
-
-/* 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]         HID Generic | Boot Mouse | Boot Keyboard | MSC | CDC          [LSB]
- */
-#define _PID_MAP(itf, n)      ( (CFG_TUD_##itf) << (n) )
-#define CFG_TUD_DESC_PID      (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
-                               _PID_MAP(HID_KEYBOARD, 2) | _PID_MAP(HID_MOUSE, 3) | (AUTO_DESC_HID_GENERIC << 4) )
-#endif
-
-//--------------------------------------------------------------------+
-// Interface & Endpoint mapping
-//--------------------------------------------------------------------+
-
-/*------------- Interface Numbering -------------*/
-/* The order as follows: CDC, MSC, Boot Keyboard, Boot Mouse, HID Generic
- * If an interface is not enabled, the later will take its place */
-
-enum
-{
-#if CFG_TUD_CDC
-  ITF_NUM_CDC,
-  ITF_NUM_CDC_DATA,
-#endif
-
-#if CFG_TUD_MSC
-  ITF_NUM_MSC,
-#endif
-
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-  ITF_NUM_HID_BOOT_KBD,
-#endif
-
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-  ITF_NUM_HID_BOOT_MSE,
-#endif
-
-#if AUTO_DESC_HID_GENERIC
-  ITF_NUM_HID_GEN,
-#endif
-
-  ITF_NUM_TOTAL
-};
-
-enum
-{
-  ITF_STR_LANGUAGE = 0 ,
-  ITF_STR_MANUFACTURER ,
-  ITF_STR_PRODUCT      ,
-  ITF_STR_SERIAL       ,
-
-#if CFG_TUD_CDC
-  ITF_STR_CDC          ,
-#endif
-
-#if CFG_TUD_MSC
-  ITF_STR_MSC          ,
-#endif
-
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-  ITF_STR_HID_BOOT_KBD,
-#endif
-
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-  ITF_STR_HID_BOOT_MSE,
-#endif
-
-#if AUTO_DESC_HID_GENERIC
-  ITF_STR_HID_GEN,
-#endif
-};
-
-/*------------- Endpoint Numbering & Size -------------*/
-#define _EP_IN(x)               (0x80 | (x))
-#define _EP_OUT(x)              (x)
-
-// CDC
-#ifdef CFG_TUD_DESC_CDC_EPNUM_NOTIF
-  #define EP_CDC_NOTIF            _EP_IN (CFG_TUD_DESC_CDC_EPNUM_NOTIF)
-#else
-  #define EP_CDC_NOTIF            _EP_IN ( ITF_NUM_CDC+1 )
-#endif
-#define EP_CDC_NOTIF_SIZE       8
-
-#ifdef CFG_TUD_DESC_CDC_EPNUM
-  #define EP_CDC_OUT              _EP_OUT( CFG_TUD_DESC_CDC_EPNUM )
-  #define EP_CDC_IN               _EP_IN ( CFG_TUD_DESC_CDC_EPNUM )
-#else
-  #define EP_CDC_OUT              _EP_OUT( ITF_NUM_CDC+2 )
-  #define EP_CDC_IN               _EP_IN ( ITF_NUM_CDC+2 )
-#endif
-
-// Mass Storage
-#ifdef CFG_TUD_DESC_MSC_EPNUM
-  #define EP_MSC_OUT              _EP_OUT( CFG_TUD_DESC_MSC_EPNUM )
-  #define EP_MSC_IN               _EP_IN ( CFG_TUD_DESC_MSC_EPNUM )
-#else
-  #define EP_MSC_OUT              _EP_OUT( ITF_NUM_MSC+1 )
-  #define EP_MSC_IN               _EP_IN ( ITF_NUM_MSC+1 )
-#endif
-
-#if TUD_OPT_HIGH_SPEED
-#define EP_MSC_SIZE 512
-#else
-#define EP_MSC_SIZE 64
-#endif
-
-
-// HID Keyboard with boot protocol
-#ifdef CFG_TUD_DESC_HID_KEYBOARD_EPNUM
-  #define EP_HID_KBD_BOOT         _EP_IN ( CFG_TUD_DESC_HID_KEYBOARD_EPNUM )
-#else
-  #define EP_HID_KBD_BOOT         _EP_IN ( ITF_NUM_HID_BOOT_KBD+1 )
-#endif
-#define EP_HID_KBD_BOOT_SZ      8
-
-// HID Mouse with boot protocol
-#ifdef CFG_TUD_DESC_HID_MOUSE_EPNUM
-  #define EP_HID_MSE_BOOT         _EP_IN ( CFG_TUD_DESC_HID_MOUSE_EPNUM )
-#else
-  #define EP_HID_MSE_BOOT         _EP_IN ( ITF_NUM_HID_BOOT_MSE+1 )
-#endif
-#define EP_HID_MSE_BOOT_SZ      8
-
-// HID composite = keyboard + mouse + gamepad + etc ...
-#define EP_HID_GEN              _EP_IN ( ITF_NUM_HID_GEN+1 )
-#define EP_HID_GEN_SIZE         16
-
-
-//--------------------------------------------------------------------+
-// Auto generated HID Report Descriptors
-//--------------------------------------------------------------------+
-
-
-/*------------- Boot Protocol Report Descriptor -------------*/
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-uint8_t const _desc_auto_hid_boot_kbd_report[] = { HID_REPORT_DESC_KEYBOARD() };
-#endif
-
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-uint8_t const _desc_auto_hid_boot_mse_report[] = { HID_REPORT_DESC_MOUSE() };
-#endif
-
-
-/*------------- Generic (composite) Descriptor -------------*/
-#if AUTO_DESC_HID_GENERIC
-
-// Report ID: 0 if there is only 1 report
-// starting from 1 if there is multiple reports
-#define _REPORT_ID_KBD
-
-// TODO report ID
-uint8_t const _desc_auto_hid_generic_report[] =
-{
-#if CFG_TUD_HID_KEYBOARD && !CFG_TUD_HID_KEYBOARD_BOOT
-    HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ),
-#endif
-
-#if CFG_TUD_HID_MOUSE && !CFG_TUD_HID_MOUSE_BOOT
-    HID_REPORT_DESC_MOUSE( HID_REPORT_ID(2), )
-#endif
-
-};
-
-#endif // hid generic
-
-
-/*------------------------------------------------------------------*/
-/* Auto generated Device & Configuration descriptor
- *------------------------------------------------------------------*/
-
-// For highspeed device but currently in full speed mode
-//tusb_desc_device_qualifier_t _device_qual =
-//{
-//    .bLength = sizeof(tusb_desc_device_qualifier_t),
-//    .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
-//    .bcdUSB = 0x0200,
-//    .bDeviceClass =
-//};
-
-/*------------- Device Descriptor -------------*/
-tusb_desc_device_t const _desc_auto_device =
-{
-    .bLength            = sizeof(tusb_desc_device_t),
-    .bDescriptorType    = TUSB_DESC_DEVICE,
-    .bcdUSB             = 0x0200,
-
-  #if CFG_TUD_CDC
-    // 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,
-  #else
-    .bDeviceClass       = 0x00,
-    .bDeviceSubClass    = 0x00,
-    .bDeviceProtocol    = 0x00,
-  #endif
-
-    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
-
-    .idVendor           = CFG_TUD_DESC_VID,
-    .idProduct          = CFG_TUD_DESC_PID,
-    .bcdDevice          = 0x0100,
-
-    .iManufacturer      = 0x01,
-    .iProduct           = 0x02,
-    .iSerialNumber      = 0x03,
-
-    .bNumConfigurations = 0x01
-};
-
-
-/*------------- Configuration Descriptor -------------*/
-typedef struct ATTR_PACKED
-{
-  tusb_desc_configuration_t           config;
-
-  //------------- CDC -------------//
-#if CFG_TUD_CDC
-  struct ATTR_PACKED
-  {
-    tusb_desc_interface_assoc_t       iad;
-
-    //CDC Control Interface
-    tusb_desc_interface_t             comm_itf;
-    cdc_desc_func_header_t            header;
-    cdc_desc_func_call_management_t   call;
-    cdc_desc_func_acm_t               acm;
-    cdc_desc_func_union_t             union_func;
-    tusb_desc_endpoint_t              ep_notif;
-
-    //CDC Data Interface
-    tusb_desc_interface_t             data_itf;
-    tusb_desc_endpoint_t              ep_out;
-    tusb_desc_endpoint_t              ep_in;
-  }cdc;
-#endif
-
-  //------------- Mass Storage -------------//
-#if CFG_TUD_MSC
-  struct ATTR_PACKED
-  {
-    tusb_desc_interface_t             itf;
-    tusb_desc_endpoint_t              ep_out;
-    tusb_desc_endpoint_t              ep_in;
-  } msc;
-#endif
-
-  //------------- HID -------------//
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-  struct ATTR_PACKED
-  {
-    tusb_desc_interface_t             itf;
-    tusb_hid_descriptor_hid_t         hid_desc;
-    tusb_desc_endpoint_t              ep_in;
-  } hid_kbd_boot;
-#endif
-
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-  struct ATTR_PACKED
-  {
-    tusb_desc_interface_t             itf;
-    tusb_hid_descriptor_hid_t         hid_desc;
-    tusb_desc_endpoint_t              ep_in;
-  } hid_mse_boot;
-#endif
-
-#if AUTO_DESC_HID_GENERIC
-
-  struct ATTR_PACKED
-  {
-    tusb_desc_interface_t             itf;
-    tusb_hid_descriptor_hid_t         hid_desc;
-    tusb_desc_endpoint_t              ep_in;
-
-    #if 0 //  CFG_TUD_HID_KEYBOARD
-    tusb_desc_endpoint_t              ep_out;
-    #endif
-  } hid_generic;
-
-#endif
-
-} desc_auto_cfg_t;
-
-desc_auto_cfg_t const _desc_auto_config_struct =
-{
-    .config =
-    {
-        .bLength             = sizeof(tusb_desc_configuration_t),
-        .bDescriptorType     = TUSB_DESC_CONFIGURATION,
-
-        .wTotalLength        = sizeof(desc_auto_cfg_t),
-        .bNumInterfaces      = ITF_NUM_TOTAL,
-
-        .bConfigurationValue = 1,
-        .iConfiguration      = 0x00,
-        .bmAttributes        = TU_BIT(7) | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
-        .bMaxPower           = TUSB_DESC_CONFIG_POWER_MA(100)
-    },
-
-#if CFG_TUD_CDC
-    // IAD points to CDC Interfaces
-    .cdc =
-    {
-      .iad =
-      {
-          .bLength           = sizeof(tusb_desc_interface_assoc_t),
-          .bDescriptorType   = TUSB_DESC_INTERFACE_ASSOCIATION,
-
-          .bFirstInterface   = ITF_NUM_CDC,
-          .bInterfaceCount   = 2,
-
-          .bFunctionClass    = TUSB_CLASS_CDC,
-          .bFunctionSubClass = CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
-          .bFunctionProtocol = CDC_COMM_PROTOCOL_ATCOMMAND,
-          .iFunction         = 0
-      },
-
-      //------------- CDC Communication Interface -------------//
-      .comm_itf =
-      {
-          .bLength            = sizeof(tusb_desc_interface_t),
-          .bDescriptorType    = TUSB_DESC_INTERFACE,
-          .bInterfaceNumber   = ITF_NUM_CDC,
-          .bAlternateSetting  = 0,
-          .bNumEndpoints      = 1,
-          .bInterfaceClass    = TUSB_CLASS_CDC,
-          .bInterfaceSubClass = CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL,
-          .bInterfaceProtocol = CDC_COMM_PROTOCOL_ATCOMMAND,
-          .iInterface         = 4
-      },
-
-      .header =
-      {
-          .bLength            = sizeof(cdc_desc_func_header_t),
-          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
-          .bDescriptorSubType = CDC_FUNC_DESC_HEADER,
-          .bcdCDC             = 0x0120
-      },
-
-      .call =
-      {
-          .bLength            = sizeof(cdc_desc_func_call_management_t),
-          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
-          .bDescriptorSubType = CDC_FUNC_DESC_CALL_MANAGEMENT,
-          .bmCapabilities     = { 0 },
-          .bDataInterface     = ITF_NUM_CDC+1,
-      },
-
-      .acm =
-      {
-          .bLength            = sizeof(cdc_desc_func_acm_t),
-          .bDescriptorType    = TUSB_DESC_CLASS_SPECIFIC,
-          .bDescriptorSubType = CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT,
-          .bmCapabilities     = { // 0x02
-              .support_line_request = 1,
-          }
-      },
-
-      .union_func =
-      {
-          .bLength                  = sizeof(cdc_desc_func_union_t), // plus number of
-          .bDescriptorType          = TUSB_DESC_CLASS_SPECIFIC,
-          .bDescriptorSubType       = CDC_FUNC_DESC_UNION,
-          .bControlInterface        = ITF_NUM_CDC,
-          .bSubordinateInterface    = ITF_NUM_CDC+1,
-      },
-
-      .ep_notif =
-      {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_CDC_NOTIF,
-          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
-          .wMaxPacketSize   = { .size = EP_CDC_NOTIF_SIZE },
-          .bInterval        = 0x10
-      },
-
-      //------------- CDC Data Interface -------------//
-      .data_itf =
-      {
-          .bLength            = sizeof(tusb_desc_interface_t),
-          .bDescriptorType    = TUSB_DESC_INTERFACE,
-          .bInterfaceNumber   = ITF_NUM_CDC+1,
-          .bAlternateSetting  = 0x00,
-          .bNumEndpoints      = 2,
-          .bInterfaceClass    = TUSB_CLASS_CDC_DATA,
-          .bInterfaceSubClass = 0,
-          .bInterfaceProtocol = 0,
-          .iInterface         = 0x00
-      },
-
-      .ep_out =
-      {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_CDC_OUT,
-          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
-          .wMaxPacketSize   = { .size = CFG_TUD_CDC_EPSIZE },
-          .bInterval        = 0
-      },
-
-      .ep_in =
-      {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_CDC_IN,
-          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
-          .wMaxPacketSize   = { .size = CFG_TUD_CDC_EPSIZE },
-          .bInterval        = 0
-      },
-    },
-#endif // cdc
-
-#if CFG_TUD_MSC
-    //------------- Mass Storage-------------//
-    .msc =
-    {
-      .itf =
-      {
-          .bLength            = sizeof(tusb_desc_interface_t),
-          .bDescriptorType    = TUSB_DESC_INTERFACE,
-          .bInterfaceNumber   = ITF_NUM_MSC,
-          .bAlternateSetting  = 0x00,
-          .bNumEndpoints      = 2,
-          .bInterfaceClass    = TUSB_CLASS_MSC,
-          .bInterfaceSubClass = MSC_SUBCLASS_SCSI,
-          .bInterfaceProtocol = MSC_PROTOCOL_BOT,
-          .iInterface         = 4 + CFG_TUD_CDC
-      },
-
-      .ep_out =
-      {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_MSC_OUT,
-          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
-          .wMaxPacketSize   = { .size = EP_MSC_SIZE},
-          .bInterval        = 1
-      },
-
-      .ep_in =
-      {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_MSC_IN,
-          .bmAttributes     = { .xfer = TUSB_XFER_BULK },
-          .wMaxPacketSize   = { .size = EP_MSC_SIZE},
-          .bInterval        = 1
-      }
-    },
-#endif // msc
-
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-    .hid_kbd_boot =
-    {
-        .itf =
-        {
-          .bLength            = sizeof(tusb_desc_interface_t),
-          .bDescriptorType    = TUSB_DESC_INTERFACE,
-          .bInterfaceNumber   = ITF_NUM_HID_BOOT_KBD,
-          .bAlternateSetting  = 0x00,
-          .bNumEndpoints      = 1,
-          .bInterfaceClass    = TUSB_CLASS_HID,
-          .bInterfaceSubClass = HID_SUBCLASS_BOOT,
-          .bInterfaceProtocol = HID_PROTOCOL_KEYBOARD,
-          .iInterface         = 0 //4 + CFG_TUD_CDC + CFG_TUD_MSC
-        },
-
-        .hid_desc =
-        {
-          .bLength         = sizeof(tusb_hid_descriptor_hid_t),
-          .bDescriptorType = HID_DESC_TYPE_HID,
-          .bcdHID          = 0x0111,
-          .bCountryCode    = HID_Local_NotSupported,
-          .bNumDescriptors = 1,
-          .bReportType     = HID_DESC_TYPE_REPORT,
-          .wReportLength   = sizeof(_desc_auto_hid_boot_kbd_report)
-        },
-
-        .ep_in =
-        {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_HID_KBD_BOOT,
-          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
-          .wMaxPacketSize   = { .size = EP_HID_KBD_BOOT_SZ },
-          .bInterval        = 0x0A
-        }
-    },
-#endif // boot keyboard
-
-  //------------- HID Mouse -------------//
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-    .hid_mse_boot =
-    {
-        .itf =
-        {
-          .bLength            = sizeof(tusb_desc_interface_t),
-          .bDescriptorType    = TUSB_DESC_INTERFACE,
-          .bInterfaceNumber   = ITF_NUM_HID_BOOT_MSE,
-          .bAlternateSetting  = 0x00,
-          .bNumEndpoints      = 1,
-          .bInterfaceClass    = TUSB_CLASS_HID,
-          .bInterfaceSubClass = HID_SUBCLASS_BOOT,
-          .bInterfaceProtocol = HID_PROTOCOL_MOUSE,
-          .iInterface         = 0 // 4 + CFG_TUD_CDC + CFG_TUD_MSC + CFG_TUD_HID_KEYBOARD
-        },
-
-        .hid_desc =
-        {
-          .bLength         = sizeof(tusb_hid_descriptor_hid_t),
-          .bDescriptorType = HID_DESC_TYPE_HID,
-          .bcdHID          = 0x0111,
-          .bCountryCode    = HID_Local_NotSupported,
-          .bNumDescriptors = 1,
-          .bReportType     = HID_DESC_TYPE_REPORT,
-          .wReportLength   = sizeof(_desc_auto_hid_boot_mse_report)
-        },
-
-        .ep_in =
-        {
-          .bLength          = sizeof(tusb_desc_endpoint_t),
-          .bDescriptorType  = TUSB_DESC_ENDPOINT,
-          .bEndpointAddress = EP_HID_MSE_BOOT,
-          .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
-          .wMaxPacketSize   = { .size = EP_HID_MSE_BOOT_SZ },
-          .bInterval        = 0x0A
-        },
-    },
-
-#endif // boot mouse
-
-#if AUTO_DESC_HID_GENERIC
-    //------------- HID Generic Multiple report -------------//
-    .hid_generic =
-    {
-        .itf =
-        {
-            .bLength            = sizeof(tusb_desc_interface_t),
-            .bDescriptorType    = TUSB_DESC_INTERFACE,
-            .bInterfaceNumber   = ITF_NUM_HID_GEN,
-            .bAlternateSetting  = 0x00,
-            .bNumEndpoints      = 1,
-            .bInterfaceClass    = TUSB_CLASS_HID,
-            .bInterfaceSubClass = 0,
-            .bInterfaceProtocol = 0,
-            .iInterface         = 0, // 4 + CFG_TUD_CDC + CFG_TUD_MSC,
-        },
-
-        .hid_desc =
-        {
-            .bLength           = sizeof(tusb_hid_descriptor_hid_t),
-            .bDescriptorType   = HID_DESC_TYPE_HID,
-            .bcdHID            = 0x0111,
-            .bCountryCode      = HID_Local_NotSupported,
-            .bNumDescriptors   = 1,
-            .bReportType       = HID_DESC_TYPE_REPORT,
-            .wReportLength     = sizeof(_desc_auto_hid_generic_report)
-        },
-
-        .ep_in =
-        {
-            .bLength          = sizeof(tusb_desc_endpoint_t),
-            .bDescriptorType  = TUSB_DESC_ENDPOINT,
-            .bEndpointAddress = EP_HID_GEN,
-            .bmAttributes     = { .xfer = TUSB_XFER_INTERRUPT },
-            .wMaxPacketSize   = { .size = EP_HID_GEN_SIZE },
-            .bInterval        = 0x0A
-        }
-    }
-#endif // hid generic
-};
-
-uint8_t const * const _desc_auto_config = (uint8_t const*) &_desc_auto_config_struct;
-
-tud_desc_set_t const _usbd_auto_desc_set =
-{
-    .device = &_desc_auto_device,
-    .config = &_desc_auto_config_struct,
-
-    .hid_report =
-    {
-#if AUTO_DESC_HID_GENERIC
-        .generic = _desc_auto_hid_generic_report,
-#else
-        .generic = NULL,
-#endif
-
-#if CFG_TUD_HID_KEYBOARD && CFG_TUD_HID_KEYBOARD_BOOT
-        .boot_keyboard = _desc_auto_hid_boot_kbd_report,
-#endif
-
-#if CFG_TUD_HID_MOUSE && CFG_TUD_HID_MOUSE_BOOT
-        .boot_mouse = _desc_auto_hid_boot_mse_report
-#endif
-    }
-};
-
-#endif

+ 0 - 3
src/device/usbd_pvt.h

@@ -33,9 +33,6 @@
  extern "C" {
 #endif
 
-// Either point to tud_desc_set or usbd_auto_desc_set depending on CFG_TUD_DESC_AUTO
-extern tud_desc_set_t const* usbd_desc_set;
-
 //--------------------------------------------------------------------+
 // INTERNAL API for stack management
 //--------------------------------------------------------------------+

+ 0 - 20
src/tusb_option.h

@@ -157,10 +157,6 @@
     #define CFG_TUD_CTRL_BUFSIZE 256
   #endif
 
-  #ifndef CFG_TUD_DESC_AUTO
-    #define CFG_TUD_DESC_AUTO 0
-  #endif
-
   #ifndef CFG_TUD_CDC
     #define CFG_TUD_CDC            0
   #endif
@@ -169,22 +165,6 @@
     #define CFG_TUD_MSC          0
   #endif
 
-  #ifndef CFG_TUD_HID_KEYBOARD
-  #define CFG_TUD_HID_KEYBOARD        0
-  #endif
-
-  #ifndef CFG_TUD_HID_MOUSE
-  #define CFG_TUD_HID_MOUSE           0
-  #endif
-
-  #ifndef CFG_TUD_HID_KEYBOARD_BOOT
-    #define CFG_TUD_HID_KEYBOARD_BOOT 0
-  #endif
-
-  #ifndef CFG_TUD_HID_MOUSE_BOOT
-    #define CFG_TUD_HID_MOUSE_BOOT 0
-  #endif
-
 #endif // TUSB_OPT_DEVICE_ENABLED
 
 //--------------------------------------------------------------------