Intermediate commit.

This commit is contained in:
Reinhard Panhuber 2020-07-17 08:40:10 +02:00
parent 28505cf03e
commit d0f3d03933
5 changed files with 525 additions and 145 deletions

View File

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

View File

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

View File

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

View File

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

View File

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