Kaynağa Gözat

Intermediate commit.

Reinhard Panhuber 5 yıl önce
ebeveyn
işleme
d0f3d03933

+ 246 - 86
src/class/audio/audio.h

@@ -38,17 +38,22 @@
 extern "C" {
 #endif
 
-/// Isochronous End Point Attributes
+/// Audio Device Class Codes
+
+/// A.2 - Audio Function Subclass Codes
 typedef enum
 {
-	TUSB_ISO_EP_ATT_ASYNCHRONOUS 	= 0x04,
-	TUSB_ISO_EP_ATT_ADAPTIVE 		= 0x08,
-	TUSB_ISO_EP_ATT_SYNCHRONOUS 	= 0x0C,
-	TUSB_ISO_EP_ATT_DATA 			= 0x00,	///< Data End Point
-	TUSB_ISO_EP_ATT_FB 				= 0x20, ///< Feedback End Point
-} tusb_iso_ep_attribute_t;
+	AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00,
+} audio_function_subclass_type_t;
 
-/// Audio Interface Subclass Codes
+/// A.3 - Audio Function Protocol Codes
+typedef enum
+{
+	AUDIO_FUNC_PROTOCOL_CODE_UNDEF       = 0x00,
+	AUDIO_FUNC_PROTOCOL_CODE_V2          = 0x20, ///< Version 2.0
+} audio_function_protocol_code_t;
+
+/// A.5 - Audio Interface Subclass Codes
 typedef enum
 {
 	AUDIO_SUBCLASS_UNDEFINED = 0x00,
@@ -57,23 +62,17 @@ typedef enum
 	AUDIO_SUBCLASS_MIDI_STREAMING  , ///< MIDI Streaming
 } audio_subclass_type_t;
 
-/// Audio Function Subclass Codes
-typedef enum
-{
-	AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00,
-} audio_function_subclass_type_t;
-
-/// Audio Protocol Codes
+/// A.6 - Audio Interface Protocol Codes
 typedef enum
 {
-	AUDIO_PROTOCOL_V1                   = 0x00, ///< Version 1.0
-	AUDIO_PROTOCOL_V2                   = 0x20, ///< Version 2.0
-	AUDIO_PROTOCOL_V3                   = 0x30, ///< Version 3.0
-} audio_protocol_type_t;
+	AUDIO_INT_PROTOCOL_CODE_UNDEF 		= 0x00,
+	AUDIO_INT_PROTOCOL_CODE_V2   		= 0x20, ///< Version 2.0
+} audio_interface_protocol_code_t;
 
-/// Audio Function Category Codes
+/// A.7 - Audio Function Category Codes
 typedef enum
 {
+	AUDIO_FUNC_UNDEF 			  = 0x00,
 	AUDIO_FUNC_DESKTOP_SPEAKER    = 0x01,
 	AUDIO_FUNC_HOME_THEATER       = 0x02,
 	AUDIO_FUNC_MICROPHONE         = 0x03,
@@ -86,9 +85,10 @@ typedef enum
 	AUDIO_FUNC_PRO_AUDIO          = 0x0A,
 	AUDIO_FUNC_AUDIO_VIDEO        = 0x0B,
 	AUDIO_FUNC_CONTROL_PANEL      = 0x0C,
-} audio_function_t;
+	AUDIO_FUNC_OTHER      		  = 0xFF,
+} audio_function_code_t;
 
-/// Audio Class-Specific AC Interface Descriptor Subtypes UAC2
+/// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2
 typedef enum
 {
 	AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF   = 0x00,
@@ -107,7 +107,7 @@ typedef enum
 	AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D,
 } audio_cs_ac_interface_subtype_t;
 
-/// Audio Class-Specific AS Interface Descriptor Subtypes UAC2
+/// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2
 typedef enum
 {
 	AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF 	= 0x00,
@@ -117,6 +117,150 @@ typedef enum
 	AUDIO_CS_AS_INTERFACE_DECODER       		= 0x04,
 } audio_cs_as_interface_subtype_t;
 
+/// A.11 - Effect Unit Effect Types
+typedef enum
+{
+	AUDIO_EFFECT_TYPE_UNDEF 					= 0x00,
+	AUDIO_EFFECT_TYPE_PARAM_EQ_SECTION			= 0x01,
+	AUDIO_EFFECT_TYPE_REVERBERATION				= 0x02,
+	AUDIO_EFFECT_TYPE_MOD_DELAY 				= 0x03,
+	AUDIO_EFFECT_TYPE_DYN_RANGE_COMP			= 0x04,
+} audio_effect_unit_effect_type_t;
+
+/// A.12 - Processing Unit Process Types
+typedef enum
+{
+	AUDIO_PROCESS_TYPE_UNDEF 					= 0x00,
+	AUDIO_PROCESS_TYPE_UP_DOWN_MIX 				= 0x01,
+	AUDIO_PROCESS_TYPE_DOLBY_PROLOGIC			= 0x02,
+	AUDIO_PROCESS_TYPE_STEREO_EXTENDER			= 0x03,
+} audio_processing_unit_process_type_t;
+
+/// A.13 - Audio Class-Specific EP Descriptor Subtypes UAC2
+typedef enum
+{
+	AUDIO_CS_EP_SUBTYPE_UNDEF 					= 0x00,
+	AUDIO_CS_EP_SUBTYPE_GENERAL 				= 0x01,
+} audio_cs_ep_subtype_t;
+
+/// A.14 - Audio Class-Specific Request Codes
+typedef enum
+{
+	AUDIO_CS_REQ_UNDEF 							= 0x00,
+	AUDIO_CS_REQ_CUR 	 						= 0x01,
+	AUDIO_CS_REQ_RANGE 							= 0x02,
+	AUDIO_CS_REQ_MEM 							= 0x03,
+} audio_cs_req_t;
+
+/// A.17 - Control Selector Codes
+
+/// A.17.1 - Clock Source Control Selectors
+typedef enum
+{
+	AUDIO_CLK_SRC_CTRL_UNDEF 					= 0x00,
+	AUDIO_CLK_SRC_CTRL_SAM_FREQ					= 0x01,
+	AUDIO_CLK_SRC_CTRL_CLK_VALID				= 0x02,
+} audio_clock_src_control_selector_t;
+
+/// A.17.7 - Feature Unit Control Selectors
+typedef enum
+{
+	AUDIO_FU_CTRL_UNDEF 						= 0x00,
+	AUDIO_FU_CTRL_MUTE  						= 0x01,
+	AUDIO_FU_CTRL_VOLUME						= 0x02,
+	AUDIO_FU_CTRL_BASS							= 0x03,
+	AUDIO_FU_CTRL_MID							= 0x04,
+	AUDIO_FU_CTRL_TREBLE						= 0x05,
+	AUDIO_FU_CTRL_GRAPHIC_EQUALIZER				= 0x06,
+	AUDIO_FU_CTRL_AGC							= 0x07,
+	AUDIO_FU_CTRL_DELAY							= 0x08,
+	AUDIO_FU_CTRL_BASS_BOOST					= 0x09,
+	AUDIO_FU_CTRL_LOUDNESS						= 0x0A,
+	AUDIO_FU_CTRL_INPUT_GAIN					= 0x0B,
+	AUDIO_FU_CTRL_GAIN_PAD						= 0x0C,
+	AUDIO_FU_CTRL_INVERTER						= 0x0D,
+	AUDIO_FU_CTRL_UNDERFLOW						= 0x0E,
+	AUDIO_FU_CTRL_OVERVLOW						= 0x0F,
+	AUDIO_FU_CTRL_LATENCY						= 0x10,
+} audio_feature_unit_control_selector_t;
+
+// Rest is yet to be implemented!
+
+/// Terminal Types
+
+/// 2.1 - Audio Class-Terminal Types UAC2
+typedef enum
+{
+	AUDIO_TERM_TYPE_USB_UNDEFINED 		= 0x0100,
+	AUDIO_TERM_TYPE_USB_STREAMING 		= 0x0101,
+	AUDIO_TERM_TYPE_USB_VENDOR_SPEC		= 0x01FF,
+} audio_terminal_type_t;
+
+/// 2.2 - Audio Class-Input Terminal Types UAC2
+typedef enum
+{
+	AUDIO_TERM_TYPE_IN_UNDEFINED 		= 0x0200,
+	AUDIO_TERM_TYPE_IN_GENERIC_MIC 		= 0x0201,
+	AUDIO_TERM_TYPE_IN_DESKTOP_MIC 		= 0x0202,
+	AUDIO_TERM_TYPE_IN_PERSONAL_MIC 	= 0x0203,
+	AUDIO_TERM_TYPE_IN_OMNI_MIC 		= 0x0204,
+	AUDIO_TERM_TYPE_IN_ARRAY_MIC 		= 0x0205,
+	AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC 	= 0x0206,
+} audio_terminal_input_type_t;
+
+/// 2.3 - Audio Class-Output Terminal Types UAC2
+typedef enum
+{
+	AUDIO_TERM_TYPE_OUT_UNDEFINED 				= 0x0300,
+	AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER 		= 0x0301,
+	AUDIO_TERM_TYPE_OUT_HEADPHONES 				= 0x0302,
+	AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO 	= 0x0303,
+	AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER 		= 0x0304,
+	AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER	 		= 0x0305,
+	AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER 	= 0x0306,
+	AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307,
+} audio_terminal_output_type_t;
+
+/// Rest is yet to be implemented
+
+/// Additional Audio Device Class Codes - Source: Audio Data Formats
+
+/// A.1 - Audio Class-Format Type Codes UAC2
+typedef enum
+{
+	AUDIO_FORMAT_TYPE_UNDEFINED 	= 0x00,
+	AUDIO_FORMAT_TYPE_I 			= 0x01,
+	AUDIO_FORMAT_TYPE_II 			= 0x02,
+	AUDIO_FORMAT_TYPE_III 			= 0x03,
+	AUDIO_FORMAT_TYPE_IV 			= 0x04,
+	AUDIO_EXT_FORMAT_TYPE_I 		= 0x81,
+	AUDIO_EXT_FORMAT_TYPE_II 		= 0x82,
+	AUDIO_EXT_FORMAT_TYPE_III 		= 0x83,
+} audio_format_type_t;
+
+/// A.2.1 - Audio Class-Audio Data Format Type I UAC2
+typedef enum
+{
+	AUDIO_DATA_FORMAT_TYPE_I_PCM 			= (uint32_t) (1 << 0),
+	AUDIO_DATA_FORMAT_TYPE_I_PCM8 			= (uint32_t) (1 << 1),
+	AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT 	= (uint32_t) (1 << 2),
+	AUDIO_DATA_FORMAT_TYPE_I_ALAW 			= (uint32_t) (1 << 3),
+	AUDIO_DATA_FORMAT_TYPE_I_MULAW 			= (uint32_t) (1 << 4),
+	AUDIO_DATA_FORMAT_TYPE_I_RAW_DATA		= (uint32_t) (1 << 31),
+} audio_data_format_type_I_t;
+
+/// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification
+
+/// Isochronous End Point Attributes
+typedef enum
+{
+	TUSB_ISO_EP_ATT_ASYNCHRONOUS 	= 0x04,
+	TUSB_ISO_EP_ATT_ADAPTIVE 		= 0x08,
+	TUSB_ISO_EP_ATT_SYNCHRONOUS 	= 0x0C,
+	TUSB_ISO_EP_ATT_DATA 			= 0x00,	///< Data End Point
+	TUSB_ISO_EP_ATT_FB 				= 0x20, ///< Feedback End Point
+} tusb_iso_ep_attribute_t;
+
 /// Audio Class-Control Values UAC2
 typedef enum
 {
@@ -138,13 +282,6 @@ typedef enum
 	AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS	= 2,
 } audio_cs_as_interface_control_pos_t;
 
-/// Audio Class-Specific EP Descriptor Subtypes UAC2
-typedef enum
-{
-	AUDIO_CS_EP_SUBTYPE_DESCRIPTOR_UNDEFINED 	= 0x00,
-	AUDIO_CS_EP_SUBTYPE_GENERAL 				= 0x01,
-} audio_cs_ep_subtype_t;
-
 /// Audio Class-Specific AS Isochronous Data EP Attributes UAC2
 typedef enum
 {
@@ -198,26 +335,6 @@ typedef enum
 	AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS 	= 2,
 } audio_clock_multiplier_control_pos_t;
 
-/// Audio Class-Terminal Types UAC2
-typedef enum
-{
-	AUDIO_TERM_TYPE_USB_UNDEFINED 		= 0x0100,
-	AUDIO_TERM_TYPE_USB_STREAMING 		= 0x0101,
-	AUDIO_TERM_TYPE_USB_VENDOR_SPEC		= 0x01FF,
-} audio_terminal_type_t;
-
-/// Audio Class-Input Terminal Types UAC2
-typedef enum
-{
-	AUDIO_TERM_TYPE_IN_UNDEFINED 		= 0x0200,
-	AUDIO_TERM_TYPE_IN_GENERIC_MIC 		= 0x0201,
-	AUDIO_TERM_TYPE_IN_DESKTOP_MIC 		= 0x0202,
-	AUDIO_TERM_TYPE_IN_PERSONAL_MIC 	= 0x0203,
-	AUDIO_TERM_TYPE_IN_OMNI_MIC 		= 0x0204,
-	AUDIO_TERM_TYPE_IN_ARRAY_MIC 		= 0x0205,
-	AUDIO_TERM_TYPE_IN_PROC_ARRAY_MIC 	= 0x0206,
-} audio_terminal_input_type_t;
-
 /// Audio Class-Input Terminal Controls UAC2
 typedef enum
 {
@@ -229,19 +346,6 @@ typedef enum
 	AUDIO_IN_TERM_CTRL_OVERFLOW_POS 	= 10,
 } audio_terminal_input_control_pos_t;
 
-/// Audio Class-Output Terminal Types UAC2
-typedef enum
-{
-	AUDIO_TERM_TYPE_OUT_UNDEFINED 				= 0x0300,
-	AUDIO_TERM_TYPE_OUT_GENERIC_SPEAKER 		= 0x0301,
-	AUDIO_TERM_TYPE_OUT_HEADPHONES 				= 0x0302,
-	AUDIO_TERM_TYPE_OUT_HEAD_MNT_DISP_AUIDO 	= 0x0303,
-	AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER 		= 0x0304,
-	AUDIO_TERM_TYPE_OUT_ROOM_SPEAKER	 		= 0x0305,
-	AUDIO_TERM_TYPE_OUT_COMMUNICATION_SPEAKER 	= 0x0306,
-	AUDIO_TERM_TYPE_OUT_LOW_FRQ_EFFECTS_SPEAKER = 0x0307,
-} audio_terminal_output_type_t;
-
 /// Audio Class-Output Terminal Controls UAC2
 typedef enum
 {
@@ -272,29 +376,6 @@ typedef enum
 	AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS		= 28,
 } audio_feature_unit_control_pos_t;
 
-/// Audio Class-Format Type Codes UAC2
-typedef enum
-{
-	AUDIO_FORMAT_TYPE_UNDEFINED 	= 0x00,
-	AUDIO_FORMAT_TYPE_I 			= 0x01,
-	AUDIO_FORMAT_TYPE_II 			= 0x02,
-	AUDIO_FORMAT_TYPE_III 			= 0x03,
-	AUDIO_FORMAT_TYPE_IV 			= 0x04,
-	AUDIO_EXT_FORMAT_TYPE_I 		= 0x81,
-	AUDIO_EXT_FORMAT_TYPE_II 		= 0x82,
-	AUDIO_EXT_FORMAT_TYPE_III 		= 0x83,
-} audio_format_type_t;
-
-/// Audio Class-Audio Data Format Type I UAC2
-typedef enum
-{
-	AUDIO_DATA_FORMAT_TYPE_I_PCM 			= 0x00000000,
-	AUDIO_DATA_FORMAT_TYPE_I_PCM8 			= 0x00000001,
-	AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT 	= 0x00000002,
-	AUDIO_DATA_FORMAT_TYPE_I_ALAW 			= 0x00000003,
-	AUDIO_DATA_FORMAT_TYPE_I_MULAW 			= 0x00000004,
-} audio_data_format_type_I_t;
-
 /// Audio Class-Audio Channel Configuration UAC2
 typedef enum
 {
@@ -490,6 +571,85 @@ typedef struct TU_ATTR_PACKED
   uint16_t wLockDelay 		 ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field.
 } audio_desc_cs_as_iso_data_ep_t;
 
+//// 5.2.3 Control Request Parameter Block Layout
+
+// 5.2.3.1 1-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int8_t bCur            	; 	///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_1_t;
+
+// 5.2.3.2 2-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int16_t bCur            	;	///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_2_t;
+
+// 5.2.3.3 4-byte Control CUR Parameter Block
+typedef struct TU_ATTR_PACKED
+{
+  int32_t bCur            	;	///< The setting for the CUR attribute of the addressed Control
+} audio_control_cur_4_t;
+
+// 5.2.3.1 1-byte Control RANGE Parameter Block
+//#define audio_control_range_1_n_t(numSubRanges) \
+//  struct TU_ATTR_PACKED {         				\
+//	uint16_t wNumSubRanges = numSubRanges; 		\
+//    struct TU_ATTR_PACKED {    	  				\
+//        int8_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+//        int8_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+//        uint8_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+//    } setting[numSubRanges]		; \
+// }
+
+typedef struct TU_ATTR_PACKED {
+	uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+      int8_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+      int8_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+      uint8_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } setting[]				;
+} audio_control_range_1_t;
+
+// 5.2.3.2 2-byte Control RANGE Parameter Block
+//#define audio_control_range_2_n_t(numSubRanges) \
+//  struct TU_ATTR_PACKED {         				\
+//	uint16_t wNumSubRanges = numSubRanges; 		\
+//    struct TU_ATTR_PACKED {    	  				\
+//        int16_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+//        int16_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+//        uint16_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+//    } setting[numSubRanges]		; \
+// }
+
+typedef struct TU_ATTR_PACKED {
+	uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+      int16_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+      int16_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+      uint16_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } setting[]				;
+} audio_control_range_2_t;
+
+// 5.2.3.3 4-byte Control RANGE Parameter Block
+//#define audio_control_range_4_n_t(numSubRanges) \
+//  struct TU_ATTR_PACKED {         				\
+//	uint16_t wNumSubRanges = numSubRanges; 		\
+//    struct TU_ATTR_PACKED {    	  				\
+//        int32_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/\
+//        int32_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/\
+//        uint32_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/\
+//    } setting[numSubRanges]		; \
+// }
+
+typedef struct TU_ATTR_PACKED {
+	uint16_t wNumSubRanges;
+  struct TU_ATTR_PACKED {
+      int32_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
+      int32_t bMax			; /*The setting for the MAX attribute of the nth subrange of the addressed Control*/
+      uint32_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
+  } setting[]				;
+} audio_control_range_4_t;
 
 /** @} */
 

+ 250 - 18
src/class/audio/audio_device.c

@@ -152,6 +152,9 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *
 static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request);
 
 static bool audiod_get_interface_index(uint8_t itf, uint8_t *idxDriver, uint8_t *idxItf, uint8_t const **pp_desc_int);
+static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID);
+static bool audiod_verify_itf_exists(uint8_t itf);
+static bool audiod_verify_ep_exists(uint8_t ep);
 
 bool tud_audio_n_mounted(uint8_t itf)
 {
@@ -638,7 +641,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
 			AUDIO_SUBCLASS_CONTROL	== itf_desc->bInterfaceSubClass);
 
 	// Verify version is correct - this check can be omitted
-	TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_PROTOCOL_V2);
+	TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
 
 	// Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted
 	if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed
@@ -666,7 +669,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
 	// This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification)
 
 	// Notify caller we read complete descriptor
-//	(*p_length) += tud_audio_desc_lengths[i];
+	//	(*p_length) += tud_audio_desc_lengths[i];
 	// TODO: Find a way to find end of current audio function and avoid necessity of tud_audio_desc_lengths - since now max_length is available we could do this surely somehow
 	uint16_t drv_len = tud_audio_desc_lengths[i] - TUD_AUDIO_DESC_IAD_LEN; 	// - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor
 
@@ -675,8 +678,6 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
 
 static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request)
 {
-	(void) rhport;
-
 #if CFG_TUD_AUDIO_N_AS_INT > 0
 	uint8_t const itf = tu_u16_low(p_request->wIndex);
 
@@ -690,6 +691,7 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *
 	return true;
 
 #else
+	(void) rhport;
 	(void) p_request;
 	return false;
 #endif
@@ -805,21 +807,85 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
 	// Check for nothing found - we can rely on this since EP descriptors are never the last descriptors, there are always also class specific EP descriptors following!
 	TU_VERIFY(p_desc < p_desc_end);
 
-	// Conduct audio driver function specific stuff
-
-	// HERE DO WHAT YOU HAVE TO DO - E.G. START ADC OR SO
-	//#error Implementation specific setInterface code required here!
+	// Invoke callback
+	if (tud_audio_set_itf_cb)
+	{
+		if (!tud_audio_set_itf_cb(rhport, p_request))
+		{
+			return false;
+		}
+	}
 
 	// Save current alternative interface setting
 	_audiod_itf[idxDriver].altSetting[idxItf] = alt;
 
+	tud_control_status(rhport, p_request);
+
 	return true;
 }
 
+// Invoked when class request DATA stage is finished.
+// return false to stall control EP (e.g Host send non-sense DATA)
 bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 {
-	(void) rhport;
-	(void) p_request;
+	// Handle audio class specific set requests
+	if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
+	{
+		switch (p_request->bmRequestType_bit.recipient)
+		{
+		case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
+
+		uint8_t itf = TU_U16_LOW(p_request->wIndex);
+		uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+		// Verify if entity is present - This check may be omitted if we trust the host not to send rubbish
+		if (entityID != 0)
+		{
+			// Invoke callback
+			if (tud_audio_set_req_entity_cb && tud_audio_set_req_entity_cb(rhport, p_request))
+			{
+				tud_control_status(rhport, p_request);
+			}
+			else
+			{
+				return false; 	// In case no callback function is present or request can not be conducted we stall it
+			}
+		}
+		else
+		{
+			// Invoke callback
+			if (tud_audio_set_req_itf_cb && tud_audio_set_req_itf_cb(rhport, p_request))
+			{
+				tud_control_status(rhport, p_request);
+			}
+			else
+			{
+				return false; 	// In case no callback function is present or request can not be conducted we stall it
+			}
+		}
+
+		break;
+
+		case TUSB_REQ_RCPT_ENDPOINT: ;		// The semicolon is there to enable a declaration right after the label
+
+		uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+		// Invoke callback
+		if (tud_audio_set_req_ep_cb && tud_audio_set_req_ep_cb(rhport, p_request))
+		{
+			tud_control_status(rhport, p_request);
+		}
+		else
+		{
+			return false; 	// In case no callback function is present or request can not be conducted we stall it
+		}
+
+		break;
+
+		// Unknown/Unsupported recipient
+		default: TU_BREAKPOINT(); return false;
+		}
+	}
 	return true;
 }
 
@@ -829,17 +895,103 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 {
 	(void) rhport;
 
-	switch (p_request->bRequest)
+	// Handle standard requests - standard set requests usually have no data stage so we also handle set requests here
+	if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
+	{
+		switch (p_request->bRequest)
+		{
+		case TUSB_REQ_GET_INTERFACE:
+			return audiod_get_interface(rhport, p_request);
+
+		case TUSB_REQ_SET_INTERFACE:
+			return audiod_set_interface(rhport, p_request);
+
+			// Unknown/Unsupported request
+		default: TU_BREAKPOINT(); return false;
+		}
+	}
+
+	// Handle class requests
+	if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
 	{
-	case TUSB_REQ_GET_INTERFACE:
-		return audiod_get_interface(rhport, p_request);
+		// Conduct checks which depend on the recipient
+		switch (p_request->bmRequestType_bit.recipient)
+		{
+		case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
+
+		uint8_t itf = TU_U16_LOW(p_request->wIndex);
+		uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+		// Verify if entity is present - This check may be omitted if we trust the host not to send rubbish
+		if (entityID != 0)
+		{
+			TU_VERIFY(audiod_verify_entity_exists(itf, entityID));
+
+			// If request is a set request we return true here and handle the rest later in audiod_control_complete() once the data stage was finished
+			if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return true;
+
+			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+			if (tud_audio_get_req_entity_cb)
+			{
+				return tud_audio_get_req_entity_cb(rhport, p_request);
+			}
+			else
+			{
+				TU_LOG2("  No entity get request callback available!\r\n");
+			}
+		}
+		else
+		{
+			TU_VERIFY(audiod_verify_itf_exists(itf));
+
+			// If request is a set request we return true here and handle the rest later in audiod_control_complete() once the data stage was finished
+			if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return true;
+
+			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+			if (tud_audio_get_req_itf_cb)
+			{
+				return tud_audio_get_req_itf_cb(rhport, p_request);
+			}
+			else
+			{
+				TU_LOG2("  No interface get request callback available!\r\n");
+			}
+		}
+
+		break;
+
+		case TUSB_REQ_RCPT_ENDPOINT: ;		// The semicolon is there to enable a declaration right after the label
+
+		uint8_t ep = TU_U16_LOW(p_request->wIndex);
 
-	case TUSB_REQ_SET_INTERFACE:
-		return audiod_set_interface(rhport, p_request);
+		// Verify if EP is present - This check may be omitted if we trust the host not to send rubbish
+		TU_VERIFY(audiod_verify_ep_exists(ep));
 
-	default:
+		// If request is a set request we return true here and handle the rest later in audiod_control_complete() once the data stage was finished
+		if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return true;
+
+		if (tud_audio_get_req_ep_cb)
+		{
+			return tud_audio_get_req_ep_cb(rhport, p_request);
+		}
+		else
+		{
+			TU_LOG2("  No EP get request callback available!\r\n");
+		}
+
+		break;
+
+		// Unknown/Unsupported recipient
+		default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
+		}
+
+		// Host expects an answer - in case no callback function is present we stall the request
 		return false;
 	}
+
+	// There went something wrong
+	TU_BREAKPOINT();
+	return false;
 }
 
 bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -936,19 +1088,22 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
 
 }
 
+// This helper function finds for a given interface number the index of the attached driver interface, the index of the interface in the audio function
+// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
+// finally a pointer to the std. AS interface, where the pointer always points to the start i.e. alternate interface zero.
 static bool audiod_get_interface_index(uint8_t itf, uint8_t *idxDriver, uint8_t *idxItf, uint8_t const **pp_desc_int)
 {
 	// Loop over audio driver interfaces
 	uint8_t i;
 	for (i = 0; i < CFG_TUD_AUDIO; i++)
 	{
-		if (!_audiod_itf[i].p_desc)
+		if (_audiod_itf[i].p_desc)
 		{
 			// Get pointer at end
 			uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i];
 
 			// Advance past AC descriptors
-			uint8_t const * p_desc = tu_desc_next(_audiod_itf[i].p_desc);
+			uint8_t const *p_desc = tu_desc_next(_audiod_itf[i].p_desc);
 			p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
 
 			uint8_t tmp = 0;
@@ -973,6 +1128,83 @@ static bool audiod_get_interface_index(uint8_t itf, uint8_t *idxDriver, uint8_t
 	return false;
 }
 
+static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID)
+{
+	uint8_t i;
+	for (i = 0; i < CFG_TUD_AUDIO; i++)
+	{
+		// Look for the correct driver by checking if the unique standard AC interface number fits
+		if (_audiod_itf[i].p_desc && ((tusb_desc_interface_t const *)_audiod_itf[i].p_desc)->bInterfaceNumber == itf)
+		{
+			// Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between
+			uint8_t const *p_desc = tu_desc_next(_audiod_itf[i].p_desc); 											// Points to CS AC descriptor
+			uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
+			p_desc = tu_desc_next(p_desc); 																			// Get past CS AC descriptor
+
+			while (p_desc < p_desc_end)
+			{
+				if (p_desc[3] == entityID) 	// Entity IDs are always at offset 3
+				{
+					return true;
+				}
+				p_desc = tu_desc_next(p_desc);
+			}
+		}
+	}
+	return false;
+}
+
+static bool audiod_verify_itf_exists(uint8_t itf)
+{
+	uint8_t i;
+	for (i = 0; i < CFG_TUD_AUDIO; i++)
+	{
+		if (_audiod_itf[i].p_desc)
+		{
+			// Get pointer at beginning and end
+			uint8_t const *p_desc = _audiod_itf[i].p_desc;
+			uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i];
+
+			while (p_desc < p_desc_end)
+			{
+				if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_itf[i].p_desc)->bInterfaceNumber == itf)
+				{
+					return true;
+				}
+				p_desc = tu_desc_next(p_desc);
+			}
+		}
+	}
+	return false;
+}
+
+static bool audiod_verify_ep_exists(uint8_t ep)
+{
+	uint8_t i;
+	for (i = 0; i < CFG_TUD_AUDIO; i++)
+	{
+		if (_audiod_itf[i].p_desc)
+		{
+			// Get pointer at end
+			uint8_t const *p_desc_end = _audiod_itf[i].p_desc + tud_audio_desc_lengths[i];
+
+			// Advance past AC descriptors - EP we look for are streaming EPs
+			uint8_t const *p_desc = tu_desc_next(_audiod_itf[i].p_desc);
+			p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
+
+			while (p_desc < p_desc_end)
+			{
+				if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
+				{
+					return true;
+				}
+				p_desc = tu_desc_next(p_desc);
+			}
+		}
+	}
+	return false;
+}
+
 #endif //TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO
 
 // OLD

+ 21 - 0
src/class/audio/audio_device.h

@@ -229,6 +229,27 @@ bool tud_audio_fb_done_cb(uint8_t rhport);
 TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t * n_bytes_copied);
 #endif
 
+// Invoked when audio set interface request received
+TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific set request received for an EP
+TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific set request received for an interface
+TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific set request received for an entity
+TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific get request received for an EP
+TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific get request received for an interface
+TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
+// Invoked when audio class specific get request received for an entity
+TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request);
+
 //--------------------------------------------------------------------+
 // Inline Functions
 //--------------------------------------------------------------------+

+ 3 - 40
src/device/usbd.h

@@ -322,12 +322,12 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
 /* Standard Interface Association Descriptor (IAD) */
 #define TUD_AUDIO_DESC_IAD_LEN 8
 #define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
-		TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_PROTOCOL_V2, _stridx
+		TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
 
 /* Standard AC Interface Descriptor(4.7.1) */
 #define TUD_AUDIO_DESC_STD_AC_LEN 9
 #define TUD_AUDIO_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\
-		TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_PROTOCOL_V2, _stridx
+		TUD_AUDIO_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, /* fixed to zero */ 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
 
 /* Class-Specific AC Interface Header Descriptor(4.7.2) */
 #define TUD_AUDIO_DESC_CS_AC_LEN 9
@@ -360,7 +360,7 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
 /* Standard AS Interface Descriptor(4.9.1) */
 #define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
 #define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
-		TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_PROTOCOL_V2, _stridx
+		TUD_AUDIO_DESC_STD_AS_INT_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V2, _stridx
 
 /* Class-Specific AS Interface Descriptor(4.9.2) */
 #define TUD_AUDIO_DESC_CS_AS_INT_LEN 16
@@ -431,43 +431,6 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
 		/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
 		TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000)
 
-// Length of template descriptor (132 bytes)
-//#define TUD_AUDIO_MIC_DESC_LEN (8 + 9 + 9 + 8 + 17 + 12 + 14 + 9 + 9 + 16 + 6 + 7 + 8)
-//#define TUD_AUDIO_MIC_DESC_N_AS_INT 1
-//
-//		// AUDIO simple descriptor (UAC2) for 1 microphone input
-//		// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source
-//		#define TUD_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
-//		/* Standard Interface Association Descriptor (IAD) */\
-//		8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 0x02, TUSB_CLASS_AUDIO, 0x00, AUDIO_PROTOCOL_V2, 0x00,\
-//		/* Standard AC Interface Descriptor(4.7.1) */\
-//		9, TUSB_DESC_INTERFACE, _itfnum, 0x00, 0x00, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_PROTOCOL_V2, _stridx,\
-//		/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
-//		9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0200), AUDIO_FUNC_MICROPHONE, U16_TO_U8S_LE(9+8+17+12+6+(1+1)*4), AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS,\
-//		/* Clock Source Descriptor(4.7.2.1) */\
-//		8, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, 0x04, AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), 0x00, \
-//		/* Input Terminal Descriptor(4.7.2.4) */\
-//		17, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, 0x01, U16_TO_U8S_LE(AUDIO_TERM_TYPE_IN_GENERIC_MIC), 0x00, 0x04, 0x01, U32_TO_U8S_LE(AUDIO_CHANNEL_CONFIG_NON_PREDEFINED), 0x00, U16_TO_U8S_LE(AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), 0x00, \
-//		/* Output Terminal Descriptor(4.7.2.5) */\
-//		12, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, 0x03, U16_TO_U8S_LE(AUDIO_TERM_TYPE_USB_STREAMING), 0x00, 0x02, 0x04, U16_TO_U8S_LE(0x0000), 0x00, \
-//		/* Feature Unit Descriptor(4.7.2.8) */\
-//		6+(1+1)*4, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, 0x02, 0x01, U32_TO_U8S_LE(AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), U32_TO_U8S_LE(AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), 0x00, \
-//		/* Standard AS Interface Descriptor(4.9.1) */\
-//		/* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\
-//		9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), /* alternate setting */ 0x00, /* number of EPs */ 0x00, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_PROTOCOL_V2, 0x00,\
-//		/* Standard AS Interface Descriptor(4.9.1) */\
-//		/* Interface 1, Alternate 1 - alternate interface for data streaming */\
-//		9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), /* alternate setting */ 0x01, /* number of EPs */ 0x01, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_PROTOCOL_V2, 0x00,\
-//		/* Class-Specific AS Interface Descriptor(4.9.2) */\
-//		16, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, 0x03, AUDIO_CTRL_NONE, AUDIO_FORMAT_TYPE_I, U32_TO_U8S_LE(AUDIO_DATA_FORMAT_TYPE_I_PCM), 0x01, U32_TO_U8S_LE(AUDIO_CHANNEL_CONFIG_NON_PREDEFINED), 0x00,\
-//		/* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\
-//		6, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _nBytesPerSample, _nBitsUsedPerSample,\
-//		/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\
-//		7, TUSB_DESC_ENDPOINT, _epin, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), U16_TO_U8S_LE(_epsize), (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01,\
-//		/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\
-//		8, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO_CTRL_NONE, AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, U16_TO_U8S_LE(0x0000)
-
-
 //------------- TUD_USBTMC/USB488 -------------//
 #define TUD_USBTMC_APP_CLASS    (TUSB_CLASS_APPLICATION_SPECIFIC)
 #define TUD_USBTMC_APP_SUBCLASS 0x03u

+ 5 - 1
src/tusb_option.h

@@ -163,7 +163,7 @@
 
 // Debug enable to print out error message
 #ifndef CFG_TUSB_DEBUG
-  #define CFG_TUSB_DEBUG 0
+  #define CFG_TUSB_DEBUG 2
 #endif
 
 // place data in accessible RAM for usb controller
@@ -199,6 +199,10 @@
   #define CFG_TUD_HID             0
 #endif
 
+#ifndef CFG_TUD_AUDIO
+  #define CFG_TUD_AUDIO           0
+#endif
+
 #ifndef CFG_TUD_MIDI
   #define CFG_TUD_MIDI            0
 #endif