Get and set requests work
This commit is contained in:
		@@ -652,6 +652,13 @@ typedef enum
 | 
				
			|||||||
	AUDIO_CHANNEL_CONFIG_RAW_DATA					= 0x80000000,
 | 
						AUDIO_CHANNEL_CONFIG_RAW_DATA					= 0x80000000,
 | 
				
			||||||
} audio_channel_config_t;
 | 
					} 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)
 | 
					/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2)
 | 
				
			||||||
typedef struct TU_ATTR_PACKED
 | 
					typedef struct TU_ATTR_PACKED
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -833,66 +840,70 @@ 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;
 | 
					} 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
 | 
					// 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 {
 | 
					typedef struct TU_ATTR_PACKED {
 | 
				
			||||||
	uint16_t wNumSubRanges;
 | 
						uint16_t wNumSubRanges;
 | 
				
			||||||
	struct TU_ATTR_PACKED {
 | 
						struct TU_ATTR_PACKED {
 | 
				
			||||||
		int8_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
 | 
							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*/
 | 
							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*/
 | 
							uint8_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
 | 
				
			||||||
  } setting[]				;
 | 
						} subrange[]				;
 | 
				
			||||||
} audio_control_range_1_t;
 | 
					} audio_control_range_1_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 5.2.3.2 2-byte Control RANGE Parameter Block
 | 
					// 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 {
 | 
					typedef struct TU_ATTR_PACKED {
 | 
				
			||||||
	uint16_t wNumSubRanges;
 | 
						uint16_t wNumSubRanges;
 | 
				
			||||||
	struct TU_ATTR_PACKED {
 | 
						struct TU_ATTR_PACKED {
 | 
				
			||||||
		int16_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
 | 
							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*/
 | 
							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*/
 | 
							uint16_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
 | 
				
			||||||
  } setting[]				;
 | 
						} subrange[]				;
 | 
				
			||||||
} audio_control_range_2_t;
 | 
					} audio_control_range_2_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 5.2.3.3 4-byte Control RANGE Parameter Block
 | 
					// 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 {
 | 
					typedef struct TU_ATTR_PACKED {
 | 
				
			||||||
	uint16_t wNumSubRanges;
 | 
						uint16_t wNumSubRanges;
 | 
				
			||||||
	struct TU_ATTR_PACKED {
 | 
						struct TU_ATTR_PACKED {
 | 
				
			||||||
		int32_t bMin			; /*The setting for the MIN attribute of the nth subrange of the addressed Control*/
 | 
							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*/
 | 
							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*/
 | 
							uint32_t bRes			; /*The setting for the RES attribute of the nth subrange of the addressed Control*/
 | 
				
			||||||
  } setting[]				;
 | 
						} subrange[]				;
 | 
				
			||||||
} audio_control_range_4_t;
 | 
					} 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
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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_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_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_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);
 | 
					static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *idxDriver);
 | 
				
			||||||
static bool audiod_verify_itf_exists(uint8_t itf);
 | 
					static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *idxDriver);
 | 
				
			||||||
static bool audiod_verify_ep_exists(uint8_t ep);
 | 
					static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool tud_audio_n_mounted(uint8_t itf)
 | 
					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 idxDriver, idxItf;
 | 
				
			||||||
	uint8_t const *dummy;
 | 
						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));
 | 
						TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_itf[idxDriver].altSetting[idxItf], 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						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
 | 
						// Find index of audio streaming interface and index of interface
 | 
				
			||||||
	uint8_t idxDriver, idxItf;
 | 
						uint8_t idxDriver, idxItf;
 | 
				
			||||||
	uint8_t const *p_desc;
 | 
						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)
 | 
						// 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
 | 
					#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
 | 
						// Handle audio class specific set requests
 | 
				
			||||||
	if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
 | 
						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)
 | 
							switch (p_request->bmRequestType_bit.recipient)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
 | 
							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 itf = TU_U16_LOW(p_request->wIndex);
 | 
				
			||||||
		uint8_t entityID = TU_U16_HIGH(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)
 | 
							if (entityID != 0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// Invoke callback
 | 
								if (tud_audio_set_req_entity_cb)
 | 
				
			||||||
			if (tud_audio_set_req_entity_cb && tud_audio_set_req_entity_cb(rhport, p_request))
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				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
 | 
								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
 | 
									return false; 	// In case no callback function is present or request can not be conducted we stall it
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			// Invoke callback
 | 
								if (tud_audio_set_req_itf_cb)
 | 
				
			||||||
			if (tud_audio_set_req_itf_cb && tud_audio_set_req_itf_cb(rhport, p_request))
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				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
 | 
								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
 | 
									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);
 | 
							uint8_t ep = TU_U16_LOW(p_request->wIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Invoke callback
 | 
							if (tud_audio_set_req_ep_cb)
 | 
				
			||||||
		if (tud_audio_set_req_ep_cb && tud_audio_set_req_ep_cb(rhport, p_request))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			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
 | 
							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
 | 
								return false; 	// In case no callback function is present or request can not be conducted we stall it
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Unknown/Unsupported recipient
 | 
							// Unknown/Unsupported recipient
 | 
				
			||||||
		default: TU_BREAKPOINT(); return false;
 | 
							default: TU_BREAKPOINT(); return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -920,23 +931,25 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 | 
				
			|||||||
	// Handle class requests
 | 
						// Handle class requests
 | 
				
			||||||
	if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
 | 
						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
 | 
							// Conduct checks which depend on the recipient
 | 
				
			||||||
		switch (p_request->bmRequestType_bit.recipient)
 | 
							switch (p_request->bmRequestType_bit.recipient)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		case TUSB_REQ_RCPT_INTERFACE: ;		// The semicolon is there to enable a declaration right after the label
 | 
							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);
 | 
							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)
 | 
							if (entityID != 0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			TU_VERIFY(audiod_verify_entity_exists(itf, entityID));
 | 
								// Find index of audio driver structure and verify entity really exists
 | 
				
			||||||
 | 
								TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &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
 | 
								// 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_OUT) return true;
 | 
								if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
 | 
					 | 
				
			||||||
				if (tud_audio_get_req_entity_cb)
 | 
									if (tud_audio_get_req_entity_cb)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					return tud_audio_get_req_entity_cb(rhport, p_request);
 | 
										return tud_audio_get_req_entity_cb(rhport, p_request);
 | 
				
			||||||
@@ -944,16 +957,18 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 | 
				
			|||||||
				else
 | 
									else
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					TU_LOG2("  No entity get request callback available!\r\n");
 | 
										TU_LOG2("  No entity get request callback available!\r\n");
 | 
				
			||||||
 | 
										return false; 	// Stall
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			TU_VERIFY(audiod_verify_itf_exists(itf));
 | 
								// Find index of audio driver structure and verify interface really exists
 | 
				
			||||||
 | 
								TU_VERIFY(audiod_verify_itf_exists(itf, &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
 | 
								// 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_OUT) return true;
 | 
								if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
			// Invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
 | 
					 | 
				
			||||||
				if (tud_audio_get_req_itf_cb)
 | 
									if (tud_audio_get_req_itf_cb)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					return tud_audio_get_req_itf_cb(rhport, p_request);
 | 
										return tud_audio_get_req_itf_cb(rhport, p_request);
 | 
				
			||||||
@@ -961,21 +976,22 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 | 
				
			|||||||
				else
 | 
									else
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					TU_LOG2("  No interface get request callback available!\r\n");
 | 
										TU_LOG2("  No interface get request callback available!\r\n");
 | 
				
			||||||
 | 
										return false; 	// Stall
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case TUSB_REQ_RCPT_ENDPOINT: ;		// The semicolon is there to enable a declaration right after the label
 | 
							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);
 | 
							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
 | 
							// Find index of audio driver structure and verify EP really exists
 | 
				
			||||||
		TU_VERIFY(audiod_verify_ep_exists(ep));
 | 
							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;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 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)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
			if (tud_audio_get_req_ep_cb)
 | 
								if (tud_audio_get_req_ep_cb)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				return tud_audio_get_req_ep_cb(rhport, p_request);
 | 
									return tud_audio_get_req_ep_cb(rhport, p_request);
 | 
				
			||||||
@@ -983,19 +999,21 @@ bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_req
 | 
				
			|||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				TU_LOG2("  No EP get request callback available!\r\n");
 | 
									TU_LOG2("  No EP get request callback available!\r\n");
 | 
				
			||||||
 | 
									return false; 	// Stall
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Unknown/Unsupported recipient
 | 
							// Unknown/Unsupported recipient
 | 
				
			||||||
		default: TU_LOG2("  Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
 | 
							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
 | 
							// 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
 | 
				
			||||||
		return false;
 | 
							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();
 | 
						TU_BREAKPOINT();
 | 
				
			||||||
	return false;
 | 
						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
 | 
					// (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.
 | 
					// 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_interface_index(uint8_t itf, uint8_t *idxDriver, uint8_t *idxItf, uint8_t const **pp_desc_int)
 | 
					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
 | 
						// Loop over audio driver interfaces
 | 
				
			||||||
	uint8_t i;
 | 
						uint8_t i;
 | 
				
			||||||
@@ -1134,7 +1203,8 @@ static bool audiod_get_interface_index(uint8_t itf, uint8_t *idxDriver, uint8_t
 | 
				
			|||||||
	return false;
 | 
						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;
 | 
						uint8_t i;
 | 
				
			||||||
	for (i = 0; i < CFG_TUD_AUDIO; 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
 | 
									if (p_desc[3] == entityID) 	// Entity IDs are always at offset 3
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
										*idxDriver = i;
 | 
				
			||||||
					return true;
 | 
										return true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				p_desc = tu_desc_next(p_desc);
 | 
									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;
 | 
						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;
 | 
						uint8_t i;
 | 
				
			||||||
	for (i = 0; i < CFG_TUD_AUDIO; 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)
 | 
									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;
 | 
										return true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				p_desc = tu_desc_next(p_desc);
 | 
									p_desc = tu_desc_next(p_desc);
 | 
				
			||||||
@@ -1184,7 +1256,7 @@ static bool audiod_verify_itf_exists(uint8_t itf)
 | 
				
			|||||||
	return false;
 | 
						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;
 | 
						uint8_t i;
 | 
				
			||||||
	for (i = 0; i < CFG_TUD_AUDIO; 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)
 | 
									if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
										*idxDriver = i;
 | 
				
			||||||
					return true;
 | 
										return true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				p_desc = tu_desc_next(p_desc);
 | 
									p_desc = tu_desc_next(p_desc);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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);
 | 
					inline uint32_t 	tud_audio_int_ctr_write			(uint8_t const* buffer, uint32_t bufsize);
 | 
				
			||||||
#endif
 | 
					#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)
 | 
					// 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);
 | 
					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
 | 
					// 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
 | 
					// 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
 | 
					// 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
 | 
					// 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);
 | 
					TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user