Get and set requests work

This commit is contained in:
Reinhard Panhuber 2020-07-25 11:18:50 +02:00
parent 141db1278a
commit d91843bcd2
3 changed files with 309 additions and 217 deletions

View File

@ -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
{ {
@ -703,7 +710,7 @@ typedef struct TU_ATTR_PACKED
} sourceID[source_num] ; \ } sourceID[source_num] ; \
uint8_t bmControls ; \ uint8_t bmControls ; \
uint8_t iClockSource ; \ uint8_t iClockSource ; \
} }
/// AUDIO Clock Multiplier Descriptor (4.7.2.3) /// AUDIO Clock Multiplier Descriptor (4.7.2.3)
typedef struct TU_ATTR_PACKED typedef struct TU_ATTR_PACKED
@ -773,7 +780,7 @@ typedef struct TU_ATTR_PACKED
uint32_t bmaControls ; \ uint32_t bmaControls ; \
} controls[ch_num+1] ; \ } controls[ch_num+1] ; \
uint8_t iTerminal ; \ uint8_t iTerminal ; \
} }
/// AUDIO Class-Specific AS Interface Descriptor(4.9.2) /// AUDIO Class-Specific AS Interface Descriptor(4.9.2)
typedef struct TU_ATTR_PACKED typedef struct TU_ATTR_PACKED
@ -833,72 +840,76 @@ 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
} }
#endif #endif
#endif #endif
/** @} */ /** @} */

View File

@ -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);

View File

@ -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);