mirror of
https://github.com/hathach/tinyusb.git
synced 2026-02-05 08:55:41 +00:00
Implement UAC1 IN flow control
Signed-off-by: HiFiPhile <admin@hifiphile.com>
This commit is contained in:
@ -376,7 +376,7 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
|
||||
TU_ATTR_WEAK void tud_audio_int_xfer_cb(uint8_t rhport) {
|
||||
TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
}
|
||||
#endif
|
||||
@ -942,55 +942,44 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint
|
||||
// Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
|
||||
while (p_desc_end - p_desc > 0) {
|
||||
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
|
||||
// UAC1
|
||||
// Unified UAC1/UAC2 endpoint processing
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
bool is_feedback_ep = false;
|
||||
bool is_data_ep = false;
|
||||
|
||||
if (tud_audio_n_version(i) == 1) {
|
||||
audio10_desc_as_iso_data_ep_t const *desc_ep = (audio10_desc_as_iso_data_ep_t const *) p_desc;
|
||||
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
// Explicit feedback EP
|
||||
if (desc_ep->bRefresh > 0) {
|
||||
ep_fb = desc_ep->bEndpointAddress;
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
// Data or data with implicit feedback IN EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN && desc_ep->bRefresh == 0) {
|
||||
ep_in = desc_ep->bEndpointAddress;
|
||||
ep_in_size = TU_MAX(tu_edpt_packet_size((tusb_desc_endpoint_t*)desc_ep), ep_in_size);
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
// Data OUT EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT && desc_ep->bRefresh == 0) {
|
||||
ep_out = desc_ep->bEndpointAddress;
|
||||
ep_out_size = TU_MAX(tu_edpt_packet_size((tusb_desc_endpoint_t*)desc_ep), ep_out_size);
|
||||
}
|
||||
#endif
|
||||
// UAC1: Use bRefresh field to distinguish endpoint types
|
||||
audio10_desc_as_iso_data_ep_t const *desc_ep_uac1 = (audio10_desc_as_iso_data_ep_t const *) p_desc;
|
||||
is_feedback_ep = (desc_ep_uac1->bRefresh > 0);
|
||||
is_data_ep = (desc_ep_uac1->bRefresh == 0);
|
||||
} else {
|
||||
// UAC2
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
// UAC2: Use bmAttributes.usage to distinguish endpoint types
|
||||
is_feedback_ep = (desc_ep->bmAttributes.usage == 1);
|
||||
is_data_ep = (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2);
|
||||
}
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
// Explicit feedback EP
|
||||
if (desc_ep->bmAttributes.usage == 1) {
|
||||
ep_fb = desc_ep->bEndpointAddress;
|
||||
}
|
||||
// Explicit feedback EP
|
||||
if (is_feedback_ep) {
|
||||
ep_fb = desc_ep->bEndpointAddress;
|
||||
}
|
||||
#else
|
||||
(void) is_feedback_ep;
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
// Data or data with implicit feedback IN EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN
|
||||
&& (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) {
|
||||
ep_in = desc_ep->bEndpointAddress;
|
||||
ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
|
||||
}
|
||||
// Data or data with implicit feedback IN EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN && is_data_ep) {
|
||||
ep_in = desc_ep->bEndpointAddress;
|
||||
ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
// Data OUT EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT
|
||||
&& desc_ep->bmAttributes.usage == 0) {
|
||||
ep_out = desc_ep->bEndpointAddress;
|
||||
ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
|
||||
}
|
||||
#endif
|
||||
// Data OUT EP
|
||||
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT && is_data_ep) {
|
||||
ep_out = desc_ep->bEndpointAddress;
|
||||
ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
@ -1216,12 +1205,26 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
|
||||
#endif
|
||||
uint8_t const ep_addr = desc_ep->bEndpointAddress;
|
||||
|
||||
bool is_feedback_ep = false;
|
||||
bool is_data_ep = false;
|
||||
|
||||
if (tud_audio_n_version(func_id) == 1) {
|
||||
// UAC1: Use bRefresh field to distinguish endpoint types
|
||||
audio10_desc_as_iso_data_ep_t const *desc_ep_uac1 = (audio10_desc_as_iso_data_ep_t const *) p_desc;
|
||||
is_feedback_ep = (desc_ep_uac1->bRefresh > 0);
|
||||
is_data_ep = (desc_ep_uac1->bRefresh == 0);
|
||||
} else {
|
||||
// UAC2: Use bmAttributes.usage to distinguish endpoint types
|
||||
is_feedback_ep = (desc_ep->bmAttributes.usage == 1);
|
||||
is_data_ep = (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2);
|
||||
}
|
||||
|
||||
//TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND!
|
||||
usbd_edpt_clear_stall(rhport, ep_addr);
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
||||
// For data or data with implicit feedback IN EP
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2))
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && is_data_ep)
|
||||
{
|
||||
// Save address
|
||||
audio->ep_in = ep_addr;
|
||||
@ -1245,7 +1248,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
// Checking usage not necessary
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT && is_data_ep) {
|
||||
// Save address
|
||||
audio->ep_out = ep_addr;
|
||||
audio->ep_out_as_intf_num = itf;
|
||||
@ -1262,13 +1265,17 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
||||
// Check if usage is explicit data feedback
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) {
|
||||
if (is_feedback_ep) {
|
||||
audio->ep_fb = ep_addr;
|
||||
audio->feedback.frame_shift = desc_ep->bInterval - 1;
|
||||
// Schedule first feedback transmit
|
||||
audiod_fb_send(audio);
|
||||
}
|
||||
#else
|
||||
(void) is_feedback_ep;
|
||||
#endif
|
||||
#else
|
||||
(void) is_feedback_ep;
|
||||
#endif// CFG_TUD_AUDIO_ENABLE_EP_OUT
|
||||
|
||||
foundEPs += 1;
|
||||
@ -1381,6 +1388,7 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO20_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO20_CS_REQ_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1402,6 +1410,17 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
||||
// Check if entity is present and get corresponding driver index
|
||||
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
|
||||
|
||||
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
|
||||
if (tud_audio_n_version(func_id) == 1) {
|
||||
if (_audiod_fct[func_id].ep_in == ep) {
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (ctrlSel == AUDIO10_EP_CTRL_SAMPLING_FREQ && p_request->bRequest == AUDIO10_CS_REQ_SET_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf) & 0x00FFFFFF;
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Invoke callback
|
||||
return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
||||
} break;
|
||||
@ -1525,7 +1544,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
||||
// I assume here, that things above are handled by PHY
|
||||
// All transmission is done - what remains to do is to inform job was completed
|
||||
|
||||
tud_audio_int_xfer_cb(rhport);
|
||||
tud_audio_int_done_cb(rhport);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1720,6 +1739,7 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
|
||||
uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||
if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO20_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO20_CS_REQ_CUR) {
|
||||
_audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
|
||||
audiod_calc_tx_packet_sz(&_audiod_fct[func_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1819,6 +1839,8 @@ static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t c
|
||||
if (audio->format_type_tx == AUDIO10_FORMAT_TYPE_I) {
|
||||
audio->n_channels_tx = ((audio10_desc_type_I_format_n_t(1) const *) p_desc)->bNrChannels;
|
||||
audio->n_bytes_per_sample_tx = ((audio10_desc_type_I_format_n_t(1) const *) p_desc)->bSubFrameSize;
|
||||
// Save sample rate - needed when EP doesn't support setting sample rate
|
||||
audio->sample_rate_tx = tu_unaligned_read32(((audio10_desc_type_I_format_n_t(1) const *) p_desc)->tSamFreq) & 0x00FFFFFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -480,7 +480,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
|
||||
/* Standard AS Isochronous Audio Data Endpoint Descriptor(4.6.1.1) */\
|
||||
TUD_AUDIO10_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01, /* _sync_ep */ 0x00),\
|
||||
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.6.1.2) */\
|
||||
TUD_AUDIO10_DESC_CS_AS_ISO_EP(/*_attr*/ 0x00, /*_lockdelayunits*/ AUDIO10_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001)
|
||||
TUD_AUDIO10_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO10_CS_AS_ISO_DATA_EP_ATT_SAMPLING_FRQ, /*_lockdelayunits*/ AUDIO10_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001)
|
||||
|
||||
/* Audio v2.0 Descriptor Templates */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user