Reinhard Panhuber 5 лет назад
Родитель
Сommit
d91843bcd2
3 измененных файлов с 309 добавлено и 217 удалено
  1. 161 150
      src/class/audio/audio.h
  2. 137 64
      src/class/audio/audio_device.c
  3. 11 3
      src/class/audio/audio_device.h

+ 161 - 150
src/class/audio/audio.h

@@ -652,165 +652,172 @@ typedef enum
 	AUDIO_CHANNEL_CONFIG_RAW_DATA					= 0x80000000,
 } audio_channel_config_t;
 
+/// AUDIO Channel Cluster Descriptor (4.1)
+typedef struct TU_ATTR_PACKED {
+	uint8_t 				bNrChannels; 		///< Number of channels currently connected.
+	audio_channel_config_t 	bmChannelConfig; 	///< Bitmap according to 'audio_channel_config_t' with a 1 set if channel is connected and 0 else. In case channels are non-predefined ignore them here (see UAC2 specification 4.1 Audio Channel Cluster Descriptor.
+	uint8_t 				iChannelNames; 		///< Index of a string descriptor, describing the name of the first inserted channel with a non-predefined spatial location.
+} audio_desc_channel_cluster_t;
+
 /// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor in bytes: 9.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER.
-  uint16_t bcdADC            ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200).
-  uint8_t bCategory 		 ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t.
-  uint16_t wTotalLength      ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors.
-  uint8_t bmControls 		 ; ///< See: audio_cs_ac_interface_control_pos_t.
+	uint8_t bLength            ; ///< Size of this descriptor in bytes: 9.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER.
+	uint16_t bcdADC            ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200).
+	uint8_t bCategory 		 ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t.
+	uint16_t wTotalLength      ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors.
+	uint8_t bmControls 		 ; ///< See: audio_cs_ac_interface_control_pos_t.
 } audio_desc_cs_ac_interface_t;
 
 /// AUDIO Clock Source Descriptor (4.7.2.1)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor in bytes: 8.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE.
-  uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity.
-  uint8_t bmAttributes 		 ; ///< See: audio_clock_source_attribute_t.
-  uint8_t bmControls 		 ; ///< See: audio_clock_source_control_pos_t.
-  uint8_t bAssocTerminal	 ; ///< Terminal ID of the Terminal that is associated with this Clock Source.
-  uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Source Entity.
+	uint8_t bLength            ; ///< Size of this descriptor in bytes: 8.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE.
+	uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity.
+	uint8_t bmAttributes 		 ; ///< See: audio_clock_source_attribute_t.
+	uint8_t bmControls 		 ; ///< See: audio_clock_source_control_pos_t.
+	uint8_t bAssocTerminal	 ; ///< Terminal ID of the Terminal that is associated with this Clock Source.
+	uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Source Entity.
 } audio_desc_clock_source_t;
 
 /// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7+p.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR.
-  uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity.
-  uint8_t bNrInPins 		 ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1.
-  uint8_t baCSourceID 		 ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected..
-  uint8_t bmControls 		 ; ///< See: audio_clock_selector_control_pos_t.
-  uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Selector Entity.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7+p.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR.
+	uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity.
+	uint8_t bNrInPins 		 ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1.
+	uint8_t baCSourceID 		 ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected..
+	uint8_t bmControls 		 ; ///< See: audio_clock_selector_control_pos_t.
+	uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Selector Entity.
 } audio_desc_clock_selector_t;
 
 /// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins
 #define audio_desc_clock_selector_n_t(source_num) \
-  struct TU_ATTR_PACKED {         \
+		struct TU_ATTR_PACKED {         \
 	uint8_t bLength            	; \
 	uint8_t bDescriptorType    	; \
 	uint8_t bDescriptorSubType 	; \
 	uint8_t bClockID 		 	; \
 	uint8_t bNrInPins 		 	; \
-    struct TU_ATTR_PACKED {    	  \
-        uint8_t baSourceID		; \
-    } sourceID[source_num]		; \
-    uint8_t bmControls			; \
-    uint8_t iClockSource		; \
- }
+	struct TU_ATTR_PACKED {    	  \
+		uint8_t baSourceID		; \
+	} sourceID[source_num]		; \
+	uint8_t bmControls			; \
+	uint8_t iClockSource		; \
+}
 
 /// AUDIO Clock Multiplier Descriptor (4.7.2.3)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER.
-  uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity.
-  uint8_t bCSourceID 		 ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected.
-  uint8_t bmControls 		 ; ///< See: audio_clock_multiplier_control_pos_t.
-  uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Multiplier Entity.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 7.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER.
+	uint8_t bClockID 		 	 ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity.
+	uint8_t bCSourceID 		 ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected.
+	uint8_t bmControls 		 ; ///< See: audio_clock_multiplier_control_pos_t.
+	uint8_t iClockSource	 	 ; ///< Index of a string descriptor, describing the Clock Multiplier Entity.
 } audio_desc_clock_multiplier_t;
 
 /// AUDIO Input Terminal Descriptor(4.7.2.4)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 17.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL.
-  uint16_t wTerminalType 	 ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types.
-  uint8_t bAssocTerminal	 ; ///< ID of the Output Terminal to which this Input Terminal is associated.
-  uint8_t bCSourceID 		 ; ///< ID of the Clock Entity to which this Input Terminal is connected.
-  uint8_t bNrChannels	 	 ; ///< Number of logical output channels in the Terminal’s output audio channel cluster.
-  uint32_t bmChannelConfig	 ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t.
-  uint16_t bmControls	 	 ; ///< See: audio_terminal_input_control_pos_t.
-  uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing the Input Terminal.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 17.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL.
+	uint16_t wTerminalType 	 ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types.
+	uint8_t bAssocTerminal	 ; ///< ID of the Output Terminal to which this Input Terminal is associated.
+	uint8_t bCSourceID 		 ; ///< ID of the Clock Entity to which this Input Terminal is connected.
+	uint8_t bNrChannels	 	 ; ///< Number of logical output channels in the Terminal’s output audio channel cluster.
+	uint32_t bmChannelConfig	 ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t.
+	uint16_t bmControls	 	 ; ///< See: audio_terminal_input_control_pos_t.
+	uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing the Input Terminal.
 } audio_desc_input_terminal_t;
 
 /// AUDIO Output Terminal Descriptor(4.7.2.5)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 12.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL.
-  uint8_t bTerminalID 	 	 ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal.
-  uint16_t wTerminalType	 ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types.
-  uint8_t bAssocTerminal 	 ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated.
-  uint8_t bSourceID		 	 ; ///< ID of the Unit or Terminal to which this Terminal is connected.
-  uint8_t bCSourceID	 	 ; ///< ID of the Clock Entity to which this Output Terminal is connected.
-  uint16_t bmControls	 	 ; ///< See: audio_terminal_output_type_t.
-  uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing the Output Terminal.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 12.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL.
+	uint8_t bTerminalID 	 	 ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal.
+	uint16_t wTerminalType	 ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types.
+	uint8_t bAssocTerminal 	 ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated.
+	uint8_t bSourceID		 	 ; ///< ID of the Unit or Terminal to which this Terminal is connected.
+	uint8_t bCSourceID	 	 ; ///< ID of the Clock Entity to which this Output Terminal is connected.
+	uint16_t bmControls	 	 ; ///< See: audio_terminal_output_type_t.
+	uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing the Output Terminal.
 } audio_desc_output_terminal_t;
 
 /// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 14.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT.
-  uint8_t bUnitID    	 	 ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit.
-  uint8_t bSourceID	 		 ; ///< ID of the Unit or Terminal to which this Feature Unit is connected.
-  struct TU_ATTR_PACKED {
-	  uint32_t bmaControls	 ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1.
-  } controls[2] 		     ;
-  uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing this Feature Unit.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 14.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT.
+	uint8_t bUnitID    	 	 ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit.
+	uint8_t bSourceID	 		 ; ///< ID of the Unit or Terminal to which this Feature Unit is connected.
+	struct TU_ATTR_PACKED {
+		uint32_t bmaControls	 ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1.
+	} controls[2] 		     ;
+	uint8_t iTerminal	 	 	 ; ///< Index of a string descriptor, describing this Feature Unit.
 } audio_desc_feature_unit_t;
 
 /// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels
 #define audio_desc_feature_unit_n_t(ch_num) \
-  struct TU_ATTR_PACKED {         \
+		struct TU_ATTR_PACKED {         \
 	uint8_t bLength            	; /* 6+(ch_num+1)*4 */\
-	uint8_t bDescriptorType    	; \
-	uint8_t bDescriptorSubType 	; \
-	uint8_t bUnitID 		 	; \
-	uint8_t bSourceID 		 	; \
-    struct TU_ATTR_PACKED {    	  \
-        uint32_t bmaControls	; \
-    } controls[ch_num+1]		; \
-    uint8_t iTerminal			; \
- }
+		uint8_t bDescriptorType    	; \
+		uint8_t bDescriptorSubType 	; \
+		uint8_t bUnitID 		 	; \
+		uint8_t bSourceID 		 	; \
+		struct TU_ATTR_PACKED {    	  \
+			uint32_t bmaControls	; \
+		} controls[ch_num+1]		; \
+		uint8_t iTerminal			; \
+}
 
 /// AUDIO Class-Specific AS Interface Descriptor(4.9.2)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 16.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL.
-  uint8_t bTerminalLink	 	 ; ///< The Terminal ID of the Terminal to which this interface is connected.
-  uint8_t bmControls	 	 ; ///< See: audio_cs_as_interface_control_pos_t.
-  uint8_t bFormatType 	 	 ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t.
-  uint32_t bmFormats	 	 ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t.
-  uint8_t bNrChannels	 	 ; ///< Number of physical channels in the AS Interface audio channel cluster.
-  uint32_t bmChannelConfig	 ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t.
-  uint8_t iChannelNames	 	 ; ///< Index of a string descriptor, describing the name of the first physical channel.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 16.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL.
+	uint8_t bTerminalLink	 	 ; ///< The Terminal ID of the Terminal to which this interface is connected.
+	uint8_t bmControls	 	 ; ///< See: audio_cs_as_interface_control_pos_t.
+	uint8_t bFormatType 	 	 ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t.
+	uint32_t bmFormats	 	 ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t.
+	uint8_t bNrChannels	 	 ; ///< Number of physical channels in the AS Interface audio channel cluster.
+	uint32_t bmChannelConfig	 ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t.
+	uint8_t iChannelNames	 	 ; ///< Index of a string descriptor, describing the name of the first physical channel.
 } audio_desc_cs_as_interface_t;
 
 /// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 6.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE.
-  uint8_t bFormatType	 	 ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I.
-  uint8_t bSubslotSize	 	 ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4.
-  uint8_t bBitResolution 	 ; ///< The number of effectively used bits from the available bits in an audio subslot.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 6.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE.
+	uint8_t bFormatType	 	 ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I.
+	uint8_t bSubslotSize	 	 ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4.
+	uint8_t bBitResolution 	 ; ///< The number of effectively used bits from the available bits in an audio subslot.
 } audio_desc_type_I_format_t;
 
 /// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2)
 typedef struct TU_ATTR_PACKED
 {
-  uint8_t bLength            ; ///< Size of this descriptor, in bytes: 8.
-  uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT.
-  uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL.
-  uint8_t bmAttributes	 	 ; ///< See: audio_cs_as_iso_data_ep_attribute_t.
-  uint8_t bmControls	 	 ; ///< See: audio_cs_as_iso_data_ep_control_pos_t.
-  uint8_t bLockDelayUnits 	 ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t.
-  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.
+	uint8_t bLength            ; ///< Size of this descriptor, in bytes: 8.
+	uint8_t bDescriptorType    ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT.
+	uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL.
+	uint8_t bmAttributes	 	 ; ///< See: audio_cs_as_iso_data_ep_attribute_t.
+	uint8_t bmControls	 	 ; ///< See: audio_cs_as_iso_data_ep_control_pos_t.
+	uint8_t bLockDelayUnits 	 ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t.
+	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
@@ -818,87 +825,91 @@ typedef struct TU_ATTR_PACKED
 // 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
+	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
+	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
+	int32_t bCur            	;	///< The setting for the CUR attribute of the addressed Control
 } audio_control_cur_4_t;
 
+// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the one below for predefined lengths - or if you know what you are doing do what you like
 // 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[]				;
+	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*/
+	} subrange[]				;
 } 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[]				;
+	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*/
+	} subrange[]				;
 } 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[]				;
+	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*/
+	} subrange[]				;
 } audio_control_range_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*/\
+		} subrange[numSubRanges]	; \
+}
+
+		// 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*/\
+		} subrange[numSubRanges]		; \
+	}
+
+		// 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*/\
+		} subrange[numSubRanges]		; \
+	}
+
+		/** @} */
 
 #ifdef __cplusplus
-}
+	}
 #endif
 
 #endif
 
-/** @} */
+	/** @} */

+ 137 - 64
src/class/audio/audio_device.c

@@ -157,10 +157,10 @@ static bool audio_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* a
 static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request);
 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);
+static bool audiod_get_AS_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, uint8_t *idxDriver);
+static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver);
+static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver);
 
 bool tud_audio_n_mounted(uint8_t itf)
 {
@@ -691,7 +691,7 @@ static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *
 	uint8_t idxDriver, idxItf;
 	uint8_t const *dummy;
 
-	TU_VERIFY(audiod_get_interface_index(itf, &idxDriver, &idxItf, &dummy));
+	TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &dummy));
 	TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].altSetting[idxItf], 1));
 
 	return true;
@@ -724,7 +724,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
 	// Find index of audio streaming interface and index of interface
 	uint8_t idxDriver, idxItf;
 	uint8_t const *p_desc;
-	TU_VERIFY(audiod_get_interface_index(itf, &idxDriver, &idxItf, &p_desc));
+	TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc));
 
 	// Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
 #if CFG_TUD_AUDIO_EPSIZE_IN > 0
@@ -837,6 +837,8 @@ bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_re
 	// Handle audio class specific set requests
 	if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
 	{
+		uint8_t idxDriver;
+
 		switch (p_request->bmRequestType_bit.recipient)
 		{
 		case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
@@ -844,28 +846,35 @@ bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_re
 		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))
+			if (tud_audio_set_req_entity_cb)
 			{
-				tud_control_status(rhport, p_request);
+				// Check if entity is present and get corresponding driver index
+				TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &idxDriver));
+
+				// Invoke callback
+				return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf);
 			}
 			else
 			{
+				TU_LOG2("  No entity set request callback available!\r\n");
 				return false; 	// In case no callback function is present or request can not be conducted we stall it
 			}
 		}
 		else
 		{
-			// Invoke callback
-			if (tud_audio_set_req_itf_cb && tud_audio_set_req_itf_cb(rhport, p_request))
+			if (tud_audio_set_req_itf_cb)
 			{
-				tud_control_status(rhport, p_request);
+				// Find index of audio driver structure and verify interface really exists
+				TU_VERIFY(audiod_verify_itf_exists(itf, &idxDriver));
+
+				// Invoke callback
+				return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf);
 			}
 			else
 			{
+				TU_LOG2("  No interface set request callback available!\r\n");
 				return false; 	// In case no callback function is present or request can not be conducted we stall it
 			}
 		}
@@ -876,18 +885,20 @@ bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_re
 
 		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))
+		if (tud_audio_set_req_ep_cb)
 		{
-			tud_control_status(rhport, p_request);
+			// Check if entity is present and get corresponding driver index
+			TU_VERIFY(audiod_verify_ep_exists(ep, &idxDriver));
+
+			// Invoke callback
+			return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf);
 		}
 		else
 		{
+			TU_LOG2("  No EP set request callback available!\r\n");
 			return false; 	// In case no callback function is present or request can not be conducted we stall it
 		}
 
-		break;
-
 		// Unknown/Unsupported recipient
 		default: TU_BREAKPOINT(); return false;
 		}
@@ -920,82 +931,89 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 	// Handle class requests
 	if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
 	{
+		uint8_t itf = TU_U16_LOW(p_request->wIndex);
+		uint8_t idxDriver;
+
 		// 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
+		// Verify if entity is present
 		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;
+			// Find index of audio driver structure and verify entity really exists
+			TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &idxDriver));
 
-			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
-			if (tud_audio_get_req_entity_cb)
+			// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+			if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
 			{
-				return tud_audio_get_req_entity_cb(rhport, p_request);
-			}
-			else
-			{
-				TU_LOG2("  No entity get request callback available!\r\n");
+				if (tud_audio_get_req_entity_cb)
+				{
+					return tud_audio_get_req_entity_cb(rhport, p_request);
+				}
+				else
+				{
+					TU_LOG2("  No entity get request callback available!\r\n");
+					return false; 	// Stall
+				}
 			}
 		}
 		else
 		{
-			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;
+			// Find index of audio driver structure and verify interface really exists
+			TU_VERIFY(audiod_verify_itf_exists(itf, &idxDriver));
 
-			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
-			if (tud_audio_get_req_itf_cb)
+			// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+			if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
 			{
-				return tud_audio_get_req_itf_cb(rhport, p_request);
-			}
-			else
-			{
-				TU_LOG2("  No interface get request callback available!\r\n");
+				if (tud_audio_get_req_itf_cb)
+				{
+					return tud_audio_get_req_itf_cb(rhport, p_request);
+				}
+				else
+				{
+					TU_LOG2("  No interface get request callback available!\r\n");
+					return false; 	// Stall
+				}
 			}
 		}
-
 		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);
 
-		// 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));
+		// Find index of audio driver structure and verify EP really exists
+		TU_VERIFY(audiod_verify_ep_exists(ep, &idxDriver));
 
-		// 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
+		// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
+		if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
 		{
-			TU_LOG2("  No EP get request callback available!\r\n");
+			if (tud_audio_get_req_ep_cb)
+			{
+				return tud_audio_get_req_ep_cb(rhport, p_request);
+			}
+			else
+			{
+				TU_LOG2("  No EP get request callback available!\r\n");
+				return false; 	// Stall
+			}
 		}
-
 		break;
 
 		// Unknown/Unsupported recipient
 		default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
 		}
 
-		// Host expects an answer - in case no callback function is present we stall the request
-		return false;
+		// If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished
+		TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_itf[idxDriver].ctrl_buf, CFG_TUD_AUDIO_CTRL_BUF_SIZE));
+		return true;
 	}
 
-	// There went something wrong
+	// There went something wrong - unsupported control request type
 	TU_BREAKPOINT();
 	return false;
 }
@@ -1094,10 +1112,61 @@ 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
+bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
+{
+	// Handles only sending of data not receiving
+	if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
+
+	// Get corresponding driver index
+	uint8_t idxDriver;
+	uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+	// Conduct checks which depend on the recipient
+	switch (p_request->bmRequestType_bit.recipient)
+	{
+	case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
+
+	uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+	// Verify if entity is present
+	if (entityID != 0)
+	{
+		// Find index of audio driver structure and verify entity really exists
+		TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &idxDriver));
+	}
+	else
+	{
+		// Find index of audio driver structure and verify interface really exists
+		TU_VERIFY(audiod_verify_itf_exists(itf, &idxDriver));
+	}
+	break;
+
+	case TUSB_REQ_RCPT_ENDPOINT: ;		// The semicolon is there to enable a declaration right after the label
+
+	uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+	// Find index of audio driver structure and verify EP really exists
+	TU_VERIFY(audiod_verify_ep_exists(ep, &idxDriver));
+	break;
+
+	// Unknown/Unsupported recipient
+	default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
+	}
+
+	// Crop length
+	if (len > CFG_TUD_AUDIO_CTRL_BUF_SIZE) len = CFG_TUD_AUDIO_CTRL_BUF_SIZE;
+
+	// Copy into buffer
+	memcpy((void *)_audiod_itf[idxDriver].ctrl_buf, data, (size_t)len);
+
+	// Schedule transmit
+	return tud_control_xfer(rhport, p_request, (void*)_audiod_itf[idxDriver].ctrl_buf, len);
+}
+
+// This helper function finds for a given AS interface number the index of the attached driver structure, 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)
+// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
+static bool audiod_get_AS_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;
@@ -1134,7 +1203,8 @@ 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)
+// Verify an entity with the given ID exists and returns also the corresponding driver index
+static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *idxDriver)
 {
 	uint8_t i;
 	for (i = 0; i < CFG_TUD_AUDIO; i++)
@@ -1151,6 +1221,7 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID)
 			{
 				if (p_desc[3] == entityID) 	// Entity IDs are always at offset 3
 				{
+					*idxDriver = i;
 					return true;
 				}
 				p_desc = tu_desc_next(p_desc);
@@ -1160,7 +1231,7 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID)
 	return false;
 }
 
-static bool audiod_verify_itf_exists(uint8_t itf)
+static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver)
 {
 	uint8_t i;
 	for (i = 0; i < CFG_TUD_AUDIO; i++)
@@ -1175,6 +1246,7 @@ static bool audiod_verify_itf_exists(uint8_t itf)
 			{
 				if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_itf[i].p_desc)->bInterfaceNumber == itf)
 				{
+					*idxDriver = i;
 					return true;
 				}
 				p_desc = tu_desc_next(p_desc);
@@ -1184,7 +1256,7 @@ static bool audiod_verify_itf_exists(uint8_t itf)
 	return false;
 }
 
-static bool audiod_verify_ep_exists(uint8_t ep)
+static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver)
 {
 	uint8_t i;
 	for (i = 0; i < CFG_TUD_AUDIO; i++)
@@ -1202,6 +1274,7 @@ static bool audiod_verify_ep_exists(uint8_t ep)
 			{
 				if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
 				{
+					*idxDriver = i;
 					return true;
 				}
 				p_desc = tu_desc_next(p_desc);

+ 11 - 3
src/class/audio/audio_device.h

@@ -204,6 +204,14 @@ inline void 		tud_audio_int_ctr_read_flush 	(void);
 inline uint32_t 	tud_audio_int_ctr_write			(uint8_t const* buffer, uint32_t bufsize);
 #endif
 
+// Buffer control EP data and schedule a transmit
+// This function is intended to be used if you do not have a persistent buffer or memory location available (e.g. non-local variables) and need to answer onto a
+// get request. This function buffers your answer request frame into the control buffer of the corresponding audio driver and schedules a transmit for sending it.
+// Since transmission is triggered via interrupts, a persistent memory location is required onto which the buffer pointer in pointing. If you already have such
+// available you may directly use 'tud_control_xfer(...)'. In this case data does not need to be copied into an additional buffer and you save some time.
+// If the request's wLength is zero, a status packet is sent instead.
+bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len);
+
 //--------------------------------------------------------------------+
 // Application Callback API (weak is optional)
 //--------------------------------------------------------------------+
@@ -228,13 +236,13 @@ TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t * n_bytes_c
 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);
+TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
 
 // 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);
+TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
 
 // 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);
+TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff);
 
 // 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);