ソースを参照

improving midi support, adding midi exmaple

rename TUSB_DESC_CLASS_SPECIFIC to TUSB_DESC_CS_INTERFACE
hathach 6 年 前
コミット
6991b28532

+ 3 - 1
examples/device/cdc_msc_hid/src/usb_descriptors.c

@@ -32,7 +32,7 @@
  *   [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) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
 
 //------------- Device Descriptors -------------//
 tusb_desc_device_t const desc_device =
@@ -188,6 +188,8 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index)
     chr_count = 1;
   }else
   {
+    // Convert ASCII string into UTF-16
+
     if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
 
     const char* str = string_desc_arr[index];

+ 4 - 2
examples/device/cdc_msc_hid_freertos/src/usb_descriptors.c

@@ -32,7 +32,7 @@
  *   [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) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
 
 //------------- Device Descriptors -------------//
 tusb_desc_device_t const desc_device =
@@ -126,7 +126,7 @@ enum
 
 uint8_t const desc_configuration[] =
 {
-  // Inteface count, string index, total length, attribute, power in mA
+  // interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
 #if CFG_TUD_CDC
@@ -189,6 +189,8 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index)
     chr_count = 1;
   }else
   {
+    // Convert ASCII string into UTF-16
+
     if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
 
     const char* str = string_desc_arr[index];

+ 4 - 2
examples/device/hid_generic_inout/src/usb_descriptors.c

@@ -32,7 +32,7 @@
  *   [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) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
 
 //------------- Device Descriptors -------------//
 tusb_desc_device_t const desc_device =
@@ -81,7 +81,7 @@ enum
 
 uint8_t const desc_configuration[] =
 {
-  // Inteface count, string index, total length, attribute, power in mA
+  // interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
   // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
@@ -138,6 +138,8 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index)
     chr_count = 1;
   }else
   {
+    // Convert ASCII string into UTF-16
+
     if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
 
     const char* str = string_desc_arr[index];

+ 12 - 0
examples/device/midi/Makefile

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

+ 115 - 0
examples/device/midi/src/main.c

@@ -0,0 +1,115 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+/* Blink pattern
+ * - 250 ms  : device not mounted
+ * - 1000 ms : device mounted
+ * - 2500 ms : device is suspended
+ */
+enum  {
+  BLINK_NOT_MOUNTED = 250,
+  BLINK_MOUNTED = 1000,
+  BLINK_SUSPENDED = 2500,
+};
+
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+
+void led_blinking_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+  board_init();
+
+  tusb_init();
+
+  while (1)
+  {
+    // tinyusb device task
+    tud_task();
+
+    led_blinking_task();
+  }
+
+  return 0;
+}
+
+//--------------------------------------------------------------------+
+// Device callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void)
+{
+  blink_interval_ms = BLINK_NOT_MOUNTED;
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us  to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en)
+{
+  (void) remote_wakeup_en;
+  blink_interval_ms = BLINK_SUSPENDED;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+  static uint32_t start_ms = 0;
+  static bool led_state = false;
+
+  // Blink every 1000 ms
+  if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
+  start_ms += blink_interval_ms;
+
+  board_led_write(led_state);
+  led_state = 1 - led_state; // toggle
+}

+ 85 - 0
examples/device/midi/src/tusb_config.h

@@ -0,0 +1,85 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+  #error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
+#endif
+
+#define CFG_TUSB_OS                 OPT_OS_NONE
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          TU_ATTR_ALIGNED(4)
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#define CFG_TUD_ENDOINT0_SIZE       64
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC                 0
+#define CFG_TUD_MSC                 0
+#define CFG_TUD_HID                 0
+#define CFG_TUD_MIDI                1
+#define CFG_TUD_CUSTOM_CLASS        0
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 149 - 0
examples/device/midi/src/usb_descriptors.c

@@ -0,0 +1,149 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]       MIDI | HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
+
+//------------- Device Descriptors -------------//
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0200,
+    // Use Interface Association Descriptor (IAD) for Audio
+    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+    .bDeviceClass       = TUSB_CLASS_MISC,
+    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
+    .bMaxPacketSize0    = CFG_TUD_ENDOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+//------------- Configuration Descriptor -------------//
+enum
+{
+  ITF_NUM_MIDI = 0,
+  ITF_NUM_MIDI_STREAMING,
+  ITF_NUM_TOTAL
+};
+
+enum
+{
+  CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + TUD_MIDI_DESC_LEN
+};
+
+// Use Endpoint 2 instead of 1 due to NXP MCU
+// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
+// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+#define EPNUM_MIDI   0x02
+
+uint8_t const desc_configuration[] =
+{
+  // Interface count, string index, total length, attribute, power in mA
+  TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+  // Interface number, string index, EP Out & EP In address, EP size
+  TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 0, EPNUM_MIDI, 0x80 | EPNUM_MIDI, (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64)
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+  (void) index; // for multiple configurations
+  return desc_configuration;
+}
+
+//------------- String Descriptors -------------//
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+  (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
+  "TinyUSB",                     // 1: Manufacturer
+  "TinyUSB Device",              // 2: Product
+  "123456",                      // 3: Serials, should use chip ID
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index)
+{
+  uint8_t chr_count;
+
+  if ( index == 0)
+  {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  }else
+  {
+    // Convert ASCII string into UTF-16
+
+    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+    const char* str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = strlen(str);
+    if ( chr_count > 31 ) chr_count = 31;
+
+    for(uint8_t i=0; i<chr_count; i++)
+    {
+      _desc_str[1+i] = str[i];
+    }
+  }
+
+  // first byte is len, second byte is string type
+  _desc_str[0] = TUD_DESC_STR_HEADER(chr_count);
+
+  return _desc_str;
+}

+ 4 - 2
examples/device/msc_dual_lun/src/usb_descriptors.c

@@ -32,7 +32,7 @@
  *   [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) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | _PID_MAP(MIDI, 3) )
 
 //------------- Device Descriptors -------------//
 tusb_desc_device_t const desc_device =
@@ -75,7 +75,7 @@ enum
 
 uint8_t const desc_configuration[] =
 {
-  // Inteface count, string index, total length, attribute, power in mA
+  // interface count, string index, total length, attribute, power in mA
   TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
 
   // Interface number, string index, EP Out & EP In address, EP size
@@ -123,6 +123,8 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index)
     chr_count = 1;
   }else
   {
+    // Convert ASCII string into UTF-16
+
     if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
 
     const char* str = string_desc_arr[index];

+ 39 - 5
src/class/audio/audio.h

@@ -29,8 +29,8 @@
  *            Currently only MIDI subclass is supported
  *  @{ */
 
-#ifndef _TUSB_CDC_H__
-#define _TUSB_CDC_H__
+#ifndef _TUSB_AUDIO_H__
+#define _TUSB_AUDIO_H__
 
 #include "common/tusb_common.h"
 
@@ -41,9 +41,9 @@
 /// Audio Interface Subclass Codes
 typedef enum
 {
-  AUDIO_SUBCLASS_AUDIO_CONTROL = 0x01  , ///< Audio Control
-  AUDIO_SUBCLASS_AUDIO_STREAMING       , ///< Audio Streaming
-  AUDIO_SUBCLASS_MIDI_STREAMING       ,  ///< MIDI Streaming
+  AUDIO_SUBCLASS_CONTROL = 0x01  , ///< Audio Control
+  AUDIO_SUBCLASS_STREAMING       , ///< Audio Streaming
+  AUDIO_SUBCLASS_MIDI_STREAMING  ,  ///< MIDI Streaming
 } audio_subclass_type_t;
 
 /// Audio Protocol Codes
@@ -54,6 +54,40 @@ typedef enum
   AUDIO_PROTOCOL_V3                   = 0x30, ///< Version 3.0
 } audio_protocol_type_t;
 
+/// Audio Function Category Codes
+typedef enum
+{
+  AUDIO_FUNC_DESKTOP_SPEAKER    = 0x01,
+  AUDIO_FUNC_HOME_THEATER       = 0x02,
+  AUDIO_FUNC_MICROPHONE         = 0x03,
+  AUDIO_FUNC_HEADSET            = 0x04,
+  AUDIO_FUNC_TELEPHONE          = 0x05,
+  AUDIO_FUNC_CONVERTER          = 0x06,
+  AUDIO_FUNC_SOUND_RECODER      = 0x07,
+  AUDIO_FUNC_IO_BOX             = 0x08,
+  AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09,
+  AUDIO_FUNC_PRO_AUDIO          = 0x0A,
+  AUDIO_FUNC_AUDIO_VIDEO        = 0x0B,
+  AUDIO_FUNC_CONTROL_PANEL      = 0x0C
+} audio_function_t;
+
+/// Audio Class-Specific AC Interface Descriptor Subtypes
+typedef enum
+{
+  AUDIO_CS_INTERFACE_HEADER                = 0x01,
+  AUDIO_CS_INTERFACE_INPUT_TERMINAL        = 0x02,
+  AUDIO_CS_INTERFACE_OUTPUT_TERMINAL       = 0x03,
+  AUDIO_CS_INTERFACE_MIXER_UNIT            = 0x04,
+  AUDIO_CS_INTERFACE_SELECTOR_UNIT         = 0x05,
+  AUDIO_CS_INTERFACE_FEATURE_UNIT          = 0x06,
+  AUDIO_CS_INTERFACE_EFFECT_UNIT           = 0x07,
+  AUDIO_CS_INTERFACE_PROCESSING_UNIT       = 0x08,
+  AUDIO_CS_INTERFACE_EXTENSION_UNIT        = 0x09,
+  AUDIO_CS_INTERFACE_CLOCK_SOURCE          = 0x0A,
+  AUDIO_CS_INTERFACE_CLOCK_SELECTOR        = 0x0B,
+  AUDIO_CS_INTERFACE_CLOCK_MULTIPLIER      = 0x0C,
+  AUDIO_CS_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D,
+} audio_cs_interface_subtype_t;
 
 /** @} */
 

+ 12 - 8
src/class/cdc/cdc.h

@@ -41,7 +41,7 @@
 /** \defgroup ClassDriver_CDC_Common Common Definitions
  *  @{ */
 
-
+// TODO remove
 /// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In)
 typedef enum
 {
@@ -52,8 +52,9 @@ typedef enum
 }cdc_pipeid_t;
 
 //--------------------------------------------------------------------+
-// CDC COMMUNICATION INTERFACE CLASS
+// CDC Communication Interface Class
 //--------------------------------------------------------------------+
+
 /// Communication Interface Subclass Codes
 typedef enum
 {
@@ -117,7 +118,7 @@ typedef enum
 }cdc_func_desc_type_t;
 
 //--------------------------------------------------------------------+
-// CDC DATA INTERFACE CLASS
+// CDC Data Interface Class
 //--------------------------------------------------------------------+
 
 // SUBCLASS code of Data Interface is not used and should/must be zero
@@ -138,8 +139,9 @@ typedef enum{
 }cdc_data_protocol_type_t;
 
 //--------------------------------------------------------------------+
-// MANAGEMENT ELEMENT REQUEST (CONTROL ENDPOINT)
+// Management Element Request (Control Endpoint)
 //--------------------------------------------------------------------+
+
 /// Communication Interface Management Element Request Codes
 typedef enum
 {
@@ -189,8 +191,9 @@ typedef enum
 }cdc_management_request_t;
 
 //--------------------------------------------------------------------+
-// MANAGEMENT ELEMENENT NOTIFICATION (NOTIFICATION ENDPOINT)
+// Management Elemenent Notification (Notification Endpoint)
 //--------------------------------------------------------------------+
+
 /// Communication Interface Management Element Notification Codes
 typedef enum
 {
@@ -209,14 +212,15 @@ typedef enum
 }cdc_notification_request_t;
 
 //--------------------------------------------------------------------+
-// FUNCTIONAL DESCRIPTOR (COMMUNICATION INTERFACE)
+// Class Specific Functional Descriptor (Communication Interface)
 //--------------------------------------------------------------------+
+
 /// Header Functional Descriptor (Communication Interface)
 typedef struct TU_ATTR_PACKED
 {
   uint8_t bLength            ; ///< Size of this descriptor in bytes.
   uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_
   uint16_t bcdCDC            ; ///< CDC release number in Binary-Coded Decimal
 }cdc_desc_func_header_t;
 
@@ -246,7 +250,7 @@ typedef struct TU_ATTR_PACKED
   uint8_t bDescriptorType     ; ///< Descriptor Type, must be Class-Specific
   uint8_t bDescriptorSubType  ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
   uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes.
-  uint16_t wCountryCode[]     ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country.
+  uint16_t wCountryCode       ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country.
 }cdc_desc_func_country_selection_t;
 
 #define cdc_desc_func_country_selection_n_t(no_country) \

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

@@ -265,7 +265,7 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
   (*p_length) = sizeof(tusb_desc_interface_t);
 
   // Communication Functional Descriptors
-  while ( TUSB_DESC_CLASS_SPECIFIC == tu_desc_type(p_desc) )
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
   {
     (*p_length) += tu_desc_len(p_desc);
     p_desc = tu_desc_next(p_desc);

+ 1 - 1
src/class/cdc/cdc_host.c

@@ -142,7 +142,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
   (*p_length) = sizeof(tusb_desc_interface_t);
 
   // Communication Functional Descriptors
-  while( TUSB_DESC_CLASS_SPECIFIC == p_desc[DESC_OFFSET_TYPE] )
+  while( TUSB_DESC_CS_INTERFACE == p_desc[DESC_OFFSET_TYPE] )
   {
     if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
     {

+ 106 - 11
src/class/midi/midi.h

@@ -39,27 +39,122 @@
 #endif
 
 //--------------------------------------------------------------------+
-// FUNCTIONAL DESCRIPTOR (COMMUNICATION INTERFACE)
+// Class Specific Descriptor
 //--------------------------------------------------------------------+
-/// Header Functional Descriptor (Communication Interface)
+
+typedef enum
+{
+  MIDI_CS_INTERFACE_HEADER    = 0x01,
+  MIDI_CS_INTERFACE_IN_JACK   = 0x02,
+  MIDI_CS_INTERFACE_OUT_JACK  = 0x03,
+  MIDI_CS_INTERFACE_ELEMENT   = 0x04,
+} midi_cs_interface_subtype_t;
+
+typedef enum
+{
+  MIDI_CS_ENDPOINT_GENERAL = 0x01
+} midi_cs_endpoint_subtype_t;
+
+typedef enum
+{
+  MIDI_JACK_EMBEDDED = 0x01,
+  MIDI_JACK_EXTERNAL = 0x02
+} midi_jack_type_t;
+
+/// MIDI Interface Header Descriptor
 typedef struct TU_ATTR_PACKED
 {
   uint8_t bLength            ; ///< Size of this descriptor in bytes.
   uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above MIDI_FUCN_DESC_
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
   uint16_t bcdMSC            ; ///< MidiStreaming SubClass release number in Binary-Coded Decimal
   uint16_t wTotalLength      ;
-}midi_desc_func_header_t;
+} midi_desc_header_t;
+
+/// MIDI In Jack Descriptor
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bJackType          ; ///< Embedded or External
+  uint8_t bJackID            ; ///< Unique ID for MIDI IN Jack
+  uint8_t iJack              ; ///< string descriptor
+} midi_desc_in_jack_t;
+
+
+/// MIDI Out Jack Descriptor with single pin
+typedef struct TU_ATTR_PACKED
+{
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bJackType          ; ///< Embedded or External
+  uint8_t bJackID            ; ///< Unique ID for MIDI IN Jack
+  uint8_t bNrInputPins;
+
+  uint8_t baSourceID;
+  uint8_t baSourcePin;
+
+  uint8_t iJack              ; ///< string descriptor
+} midi_desc_out_jack_t ;
+
+/// MIDI Out Jack Descriptor with multiple pins
+#define midi_desc_out_jack_n_t(input_num) \
+  struct TU_ATTR_PACKED { \
+    uint8_t bLength            ; \
+    uint8_t bDescriptorType    ; \
+    uint8_t bDescriptorSubType ; \
+    uint8_t bJackType          ; \
+    uint8_t bJackID            ; \
+    uint8_t bNrInputPins       ; \
+    struct TU_ATTR_PACKED {      \
+        uint8_t baSourceID;      \
+        uint8_t baSourcePin;     \
+    } pins[input_num];           \
+   uint8_t iJack              ;  \
+  }
 
-/// Union Functional Descriptor (Communication Interface)
+/// MIDI Element Descriptor
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength                  ; ///< Size of this descriptor in bytes.
-  uint8_t bDescriptorType          ; ///< Descriptor Type, must be Class-Specific
-  uint8_t bDescriptorSubType       ; ///< Descriptor SubType one of above CDC_FUCN_DESC_
-  uint8_t bControlInterface        ; ///< Interface number of Communication Interface
-  uint8_t bSubordinateInterface    ; ///< Array of Interface number of Data Interface
-}cdc_desc_func_union_t;
+  uint8_t bLength            ; ///< Size of this descriptor in bytes.
+  uint8_t bDescriptorType    ; ///< Descriptor Type, must be Class-Specific
+  uint8_t bDescriptorSubType ; ///< Descriptor SubType
+  uint8_t bElementID;
+
+  uint8_t bNrInputPins;
+  uint8_t baSourceID;
+  uint8_t baSourcePin;
+
+  uint8_t bNrOutputPins;
+  uint8_t bInTerminalLink;
+  uint8_t bOutTerminalLink;
+  uint8_t bElCapsSize;
+
+  uint16_t bmElementCaps;
+  uint8_t  iElement;
+} midi_desc_element_t;
+
+/// MIDI Element Descriptor with multiple pins
+#define midi_desc_element_n_t(input_num) \
+  struct TU_ATTR_PACKED {       \
+    uint8_t bLength;            \
+    uint8_t bDescriptorType;    \
+    uint8_t bDescriptorSubType; \
+    uint8_t bElementID;         \
+    uint8_t bNrInputPins;       \
+    struct TU_ATTR_PACKED {     \
+        uint8_t baSourceID;     \
+        uint8_t baSourcePin;    \
+    } pins[input_num];          \
+    uint8_t bNrOutputPins;      \
+    uint8_t bInTerminalLink;    \
+    uint8_t bOutTerminalLink;   \
+    uint8_t bElCapsSize;        \
+    uint16_t bmElementCaps;     \
+    uint8_t  iElement;          \
+ }
 
 /** @} */
 

+ 20 - 14
src/common/tusb_types.h

@@ -72,18 +72,24 @@ typedef enum
 /// USB Descriptor Types (section 9.4 table 9-5)
 typedef enum
 {
-  TUSB_DESC_DEVICE                = 0x01 ,
-  TUSB_DESC_CONFIGURATION         = 0x02 ,
-  TUSB_DESC_STRING                = 0x03 ,
-  TUSB_DESC_INTERFACE             = 0x04 ,
-  TUSB_DESC_ENDPOINT              = 0x05 ,
-  TUSB_DESC_DEVICE_QUALIFIER      = 0x06 ,
-  TUSB_DESC_OTHER_SPEED_CONFIG    = 0x07 ,
-  TUSB_DESC_INTERFACE_POWER       = 0x08 ,
-  TUSB_DESC_OTG                   = 0x09 ,
-  TUSB_DESC_DEBUG                 = 0x0A ,
-  TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B ,
-  TUSB_DESC_CLASS_SPECIFIC        = 0x24
+  TUSB_DESC_DEVICE                = 0x01,
+  TUSB_DESC_CONFIGURATION         = 0x02,
+  TUSB_DESC_STRING                = 0x03,
+  TUSB_DESC_INTERFACE             = 0x04,
+  TUSB_DESC_ENDPOINT              = 0x05,
+  TUSB_DESC_DEVICE_QUALIFIER      = 0x06,
+  TUSB_DESC_OTHER_SPEED_CONFIG    = 0x07,
+  TUSB_DESC_INTERFACE_POWER       = 0x08,
+  TUSB_DESC_OTG                   = 0x09,
+  TUSB_DESC_DEBUG                 = 0x0A,
+  TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B,
+
+  // Class Specific Descriptor
+  TUSB_DESC_CS_DEVICE             = 0x21,
+  TUSB_DESC_CS_CONFIGURATION      = 0x22,
+  TUSB_DESC_CS_STRING             = 0x23,
+  TUSB_DESC_CS_INTERFACE          = 0x24,
+  TUSB_DESC_CS_ENDPOINT           = 0x25,
 }tusb_desc_type_t;
 
 typedef enum
@@ -105,9 +111,9 @@ typedef enum
 
 typedef enum
 {
-  TUSB_REQ_FEATURE_EDPT_HALT = 0,
+  TUSB_REQ_FEATURE_EDPT_HALT     = 0,
   TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
-  TUSB_REQ_FEATURE_TEST_MODE = 2
+  TUSB_REQ_FEATURE_TEST_MODE     = 2
 }tusb_request_feature_selector_t;
 
 typedef enum

+ 41 - 4
src/device/usbd.h

@@ -111,13 +111,13 @@ TU_ATTR_WEAK void tud_resume_cb(void);
   /* 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),\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
   /* CDC Call */\
-  5, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (_itfnum) + 1,\
+  5, TUSB_DESC_CS_INTERFACE, 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,\
+  4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
   /* CDC Union */\
-  5, TUSB_DESC_CLASS_SPECIFIC, CDC_FUNC_DESC_UNION, _itfnum, (_itfnum) + 1,\
+  5, TUSB_DESC_CS_INTERFACE, 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 */\
@@ -171,6 +171,43 @@ TU_ATTR_WEAK void tud_resume_cb(void);
   /* Endpoint Out */\
   7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval
 
+//------------- MIDI -------------//
+
+// Length of template descriptor (96 bytes)
+#define TUD_MIDI_DESC_LEN (8 + 9 + 9 + 9 + 7 + 6 + 6 + 9 + 9 + 7 + 5 + 7 + 5)
+
+// MIDI simple descriptor
+// - 1 Embedded Jack In connected to 1 External Jack Out
+// - 1 Embedded Jack out connected to 1 External Jack In
+#define TUD_MIDI_DESCRIPTOR(_itfnum, _stridx, _epin, _epout, _epsize) \
+  /* Interface Associate */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_AUDIO, 0x00, AUDIO_PROTOCOL_V1, 0,\
+  /* Audio Control (AC) Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_PROTOCOL_V1, _stridx,\
+  /* AC Header */\
+  9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, _itfnum+1,\
+  /* MIDI Streaming (MS) Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum+1, 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_PROTOCOL_V1, 0,\
+  /* MS Header */\
+  7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0025),\
+  /* MS In Jack (Embedded) */\
+  6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EMBEDDED, 1, 0,\
+  /* MS In Jack (External) */\
+  6, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_IN_JACK, MIDI_JACK_EXTERNAL, 2, 0,\
+  /* MS Out Jack (Embedded), connected to In Jack External */\
+  9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, 3, 1, 2, 1,\
+  /* MS Out Jack (External), connected to In Jack Embedded */\
+  9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, 4, 1, 1, 1,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* MS Endpoint (connected to embedded jack in) */\
+  5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 1,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* MS Endpoint (connected to embedded jack out) */\
+  5, TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL, 1, 3
+
+
 #ifdef __cplusplus
  }
 #endif