diff options
| author | HiFiPhile <[email protected]> | 2025-11-07 12:00:09 +0100 |
|---|---|---|
| committer | HiFiPhile <[email protected]> | 2025-11-07 12:00:09 +0100 |
| commit | f9bbad7576023d2ce90289b028fb0998dae1c307 (patch) | |
| tree | cc50a8d290505076f9ddf1890be627d917db30b6 | |
| parent | 53c155bf1b2105c8cbfa30b30eaf22a2826d1e0f (diff) | |
| parent | dfcab8747d48b18290a5f93ce893541644a9bac6 (diff) | |
Merge remote-tracking branch 'tinyusb/master' into audio_ep_in_target_fifo_size
59 files changed, 3560 insertions, 2254 deletions
diff --git a/README.rst b/README.rst index 3ea1bd018..38ebcc8da 100644 --- a/README.rst +++ b/README.rst @@ -160,7 +160,7 @@ Supported CPUs | +-----------------------------+--------+------+-----------+------------------------+-------------------+ | | NUC505 | ✔ | | ✔ | nuc505 | | +--------------+---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs | | +| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs, ehci | | | +---------+-------------------+--------+------+-----------+------------------------+-------------------+ | | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ @@ -168,15 +168,15 @@ Supported CPUs | +---------+-------------------+--------+------+-----------+------------------------+-------------------+ | | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40 | | +| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40, ohci | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs | | +| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs, ehci | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ | | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ | | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | | +---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs | | +| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs, ehci | | | | +-------------------+--------+------+-----------+------------------------+-------------------+ | | | A15 | ✔ | | | ci_fs | | +--------------+---------+-------------------+--------+------+-----------+------------------------+-------------------+ diff --git a/examples/device/audio_4_channel_mic/src/main.c b/examples/device/audio_4_channel_mic/src/main.c index 3e0f03a20..de9e8a06a 100644 --- a/examples/device/audio_4_channel_mic/src/main.c +++ b/examples/device/audio_4_channel_mic/src/main.c @@ -66,8 +66,8 @@ uint32_t sampFreq; uint8_t clkValid; // Range states -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state +audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state +audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3 uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX * CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000]; @@ -171,7 +171,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_req (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -191,7 +191,7 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_re (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -218,25 +218,25 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p (void) itf; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); return true; - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = (uint16_t) ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -297,13 +297,13 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Input terminal (Microphone input) if (entityID == 1) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; - ret.bmChannelConfig = (audio_channel_config_t) 0; + ret.bmChannelConfig = (audio20_channel_config_t) 0; ret.iChannelNames = 0; TU_LOG2(" Get terminal connector\r\n"); @@ -321,24 +321,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) - ret; + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; ret.subrange[0].bMin = -90;// -90 dB @@ -364,15 +363,15 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == 4) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); // Buffered control transfer is needed for IN flow control to work return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Sample Freq. range\r\n"); return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); @@ -383,7 +382,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG2(" Get Sample Freq. valid\r\n"); return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); diff --git a/examples/device/audio_4_channel_mic/src/tusb_config.h b/examples/device/audio_4_channel_mic/src/tusb_config.h index 8ead5c8b0..085f9d168 100644 --- a/examples/device/audio_4_channel_mic/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic/src/tusb_config.h @@ -105,14 +105,10 @@ extern "C" { // Have a look into audio_device.h for all configurations #define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN - -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 - #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 diff --git a/examples/device/audio_4_channel_mic/src/usb_descriptors.c b/examples/device/audio_4_channel_mic/src/usb_descriptors.c index 73f856fc8..2f5f67f66 100644 --- a/examples/device/audio_4_channel_mic/src/usb_descriptors.c +++ b/examples/device/audio_4_channel_mic/src/usb_descriptors.c @@ -80,7 +80,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_FOUR_CH_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_FOUR_CH_DESC_LEN) #if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -101,7 +101,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) + TUD_AUDIO20_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c index 96eca0be9..4572bbb3c 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/main.c +++ b/examples/device/audio_4_channel_mic_freertos/src/main.c @@ -102,8 +102,8 @@ uint32_t sampFreq; uint8_t clkValid; // Range states -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state +audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state +audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data, 4 channels muxed together, buffer[0] for CH0, buffer[1] for CH1, buffer[2] for CH2, buffer[3] for CH3 uint16_t i2s_dummy_buffer[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX * CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000]; @@ -245,7 +245,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_req (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -265,7 +265,7 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_re (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -292,25 +292,25 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p (void) itf; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; TU_LOG1(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); return true; - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG1(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -368,9 +368,9 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Input terminal (Microphone input) if (entityID == 1) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; @@ -392,23 +392,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG1(" Get Mute of channel: %u\r\n", channelNum); return tud_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG1(" Get Volume of channel: %u\r\n", channelNum); return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG1(" Get Volume range of channel: %u\r\n", channelNum); // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) ret; + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; ret.subrange[0].bMin = -90;// -90 dB @@ -434,15 +434,15 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == 4) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG1(" Get Sample Freq.\r\n"); // Buffered control transfer is needed for IN flow control to work return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG1(" Get Sample Freq. range\r\n"); return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); @@ -453,7 +453,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG1(" Get Sample Freq. valid\r\n"); return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h index dd7cc7eff..74729695f 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h @@ -111,14 +111,10 @@ extern "C" { // Have a look into audio_device.h for all configurations #define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_FOUR_CH_DESC_LEN - -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 - #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 4 // This value is not required by the driver, it parses this information from the descriptor once the alternate interface is set by the host - we use it for the setup -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 diff --git a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c b/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c index 73f856fc8..2f5f67f66 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c +++ b/examples/device/audio_4_channel_mic_freertos/src/usb_descriptors.c @@ -80,7 +80,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_FOUR_CH_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_FOUR_CH_DESC_LEN) #if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -101,7 +101,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) + TUD_AUDIO20_MIC_FOUR_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/audio_test/src/main.c b/examples/device/audio_test/src/main.c index 5b3beec24..875d0b7f0 100644 --- a/examples/device/audio_test/src/main.c +++ b/examples/device/audio_test/src/main.c @@ -63,8 +63,8 @@ uint32_t sampFreq; uint8_t clkValid; // Range states -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state +audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state +audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data uint16_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / 2]; @@ -157,7 +157,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_req (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -177,7 +177,7 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_re (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -204,25 +204,25 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p (void) itf; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); return true; - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = (uint16_t) ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -283,13 +283,13 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Input terminal (Microphone input) if (entityID == 1) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; - ret.bmChannelConfig = (audio_channel_config_t) 0; + ret.bmChannelConfig = (audio20_channel_config_t) 0; ret.iChannelNames = 0; TU_LOG2(" Get terminal connector\r\n"); @@ -307,23 +307,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; @@ -350,14 +350,14 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == 4) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Sample Freq. range\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); @@ -368,7 +368,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG2(" Get Sample Freq. valid\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); diff --git a/examples/device/audio_test/src/tusb_config.h b/examples/device/audio_test/src/tusb_config.h index 2efec5124..e311d892f 100644 --- a/examples/device/audio_test/src/tusb_config.h +++ b/examples/device/audio_test/src/tusb_config.h @@ -108,13 +108,10 @@ extern "C" { // Have a look into audio_device.h for all configurations #define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer - #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device diff --git a/examples/device/audio_test/src/usb_descriptors.c b/examples/device/audio_test/src/usb_descriptors.c index 5f0f587b3..b6c19deba 100644 --- a/examples/device/audio_test/src/usb_descriptors.c +++ b/examples/device/audio_test/src/usb_descriptors.c @@ -80,7 +80,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_ONE_CH_DESC_LEN) #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -101,7 +101,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) + TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c index 1eab5dab8..cf2fb74d1 100644 --- a/examples/device/audio_test_freertos/src/main.c +++ b/examples/device/audio_test_freertos/src/main.c @@ -100,8 +100,8 @@ uint32_t sampFreq; uint8_t clkValid; // Range states -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state -audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state +audio20_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state +audio20_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state // Audio test data uint16_t test_buffer_audio[CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX / 2]; @@ -231,7 +231,7 @@ bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_req (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -251,7 +251,7 @@ bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_re (void) pBuff; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // Page 91 in UAC2 specification uint8_t channelNum = TU_U16_LOW(p_request->wValue); @@ -278,25 +278,25 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p (void) itf; // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; TU_LOG1(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); return true; - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = (uint16_t) ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = (uint16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG1(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -354,13 +354,13 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Input terminal (Microphone input) if (entityID == 1) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; - ret.bmChannelConfig = (audio_channel_config_t) 0; + ret.bmChannelConfig = (audio20_channel_config_t) 0; ret.iChannelNames = 0; TU_LOG1(" Get terminal connector\r\n"); @@ -378,23 +378,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == 2) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG1(" Get Mute of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG1(" Get Volume of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG1(" Get Volume range of channel: %u\r\n", channelNum); // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; @@ -421,14 +421,14 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == 4) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG1(" Get Sample Freq.\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG1(" Get Sample Freq. range\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng)); @@ -439,7 +439,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG1(" Get Sample Freq. valid\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h index 4dad6c2b9..81f0c11f4 100644 --- a/examples/device/audio_test_freertos/src/tusb_config.h +++ b/examples/device/audio_test_freertos/src/tusb_config.h @@ -114,13 +114,10 @@ extern "C" { // Have a look into audio_device.h for all configurations #define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 48000 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer - #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! -#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device diff --git a/examples/device/audio_test_freertos/src/usb_descriptors.c b/examples/device/audio_test_freertos/src/usb_descriptors.c index 5f0f587b3..b6c19deba 100644 --- a/examples/device/audio_test_freertos/src/usb_descriptors.c +++ b/examples/device/audio_test_freertos/src/usb_descriptors.c @@ -80,7 +80,7 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN) +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO20_MIC_ONE_CH_DESC_LEN) #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number @@ -101,7 +101,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) + TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/audio_test_multi_rate/src/main.c b/examples/device/audio_test_multi_rate/src/main.c index 9d467991e..55a649613 100644 --- a/examples/device/audio_test_multi_rate/src/main.c +++ b/examples/device/audio_test_multi_rate/src/main.c @@ -60,7 +60,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0 -uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// +1 for master channel 0 +int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// +1 for master channel 0 uint32_t sampFreq; uint8_t bytesPerSample; uint8_t clkValid; @@ -80,9 +80,6 @@ static const uint8_t bytesPerSampleAltList[CFG_TUD_AUDIO_FUNC_1_N_FORMATS] = CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, }; -audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1];// Volume range state - - // Audio test data CFG_TUD_MEM_ALIGN uint8_t test_buffer_audio[(TUD_OPT_HIGH_SPEED ? 8 : 1) * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX]; uint16_t startVal = 0; @@ -111,9 +108,6 @@ int main(void) { led_blinking_task(); audio_task(); } - - - return 0; } //--------------------------------------------------------------------+ @@ -176,91 +170,204 @@ void audio_task(void) { // Application Callback API Implementations //--------------------------------------------------------------------+ -// Invoked when set interface is called, typically on start/stop streaming or format change -bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - //uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); - uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); +//--------------------------------------------------------------------+ +// UAC1 Helper Functions +//--------------------------------------------------------------------+ - // Clear buffer when streaming format is changed - if (alt != 0) { - bytesPerSample = bytesPerSampleAltList[alt - 1]; +static bool audio10_set_req_ep(tusb_control_request_t const *p_request, uint8_t *pBuff) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_SET_CUR) { + // Request uses 3 bytes + TU_VERIFY(p_request->wLength == 3); + + sampFreq = tu_unaligned_read32(pBuff) & 0x00FFFFFF; + + TU_LOG2("EP set current freq: %" PRIu32 "\r\n", sampFreq); + + return true; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; } - return true; + + return false; } -// Invoked when audio class specific set request received for an EP -bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; +static bool audio10_get_req_ep(uint8_t rhport, tusb_control_request_t const *p_request) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_GET_CUR) { + TU_LOG2("EP get current freq\r\n"); + + uint8_t freq[3]; + freq[0] = (uint8_t) (sampFreq & 0xFF); + freq[1] = (uint8_t) ((sampFreq >> 8) & 0xFF); + freq[2] = (uint8_t) ((sampFreq >> 16) & 0xFF); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, freq, sizeof(freq)); + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + + return false; +} - // Page 91 in UAC2 specification +static bool audio10_set_req_entity(tusb_control_request_t const *p_request, uint8_t *pBuff) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - (void) channelNum; - (void) ctrlSel; - (void) ep; + // If request is for our feature unit (ID defined in usbd.h) + if (entityID == 0x02) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength ==1); - return false;// Yet not implemented -} + mute[channelNum] = pBuff[0]; -// Invoked when audio class specific set request received for an interface -bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; - (void) pBuff; + TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); + return true; - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + default: + return false; // not supported + } - // Page 91 in UAC2 specification + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength == 2); + + volume[channelNum] = (int16_t)tu_unaligned_read16(pBuff) / 256; + + TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); + return true; + + default: + return false; // not supported + } + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; +} + +static bool audio10_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // If request is for our feature unit (ID defined in usbd.h) + if (entityID == 0x02) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + // Audio control mute cur parameter block consists of only one byte - we thus can send it right away + // There does not exist a range parameter block for mute + TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - (void) channelNum; - (void) ctrlSel; - (void) itf; + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_GET_CUR: + TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); + { + int16_t vol = (int16_t) volume[channelNum]; + vol = vol * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &vol, sizeof(vol)); + } - return false;// Yet not implemented + case AUDIO10_CS_REQ_GET_MIN: + TU_LOG2(" Get Volume min of channel: %u\r\n", channelNum); + { + int16_t min = -90; // -90 dB + min = min * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &min, sizeof(min)); + } + + case AUDIO10_CS_REQ_GET_MAX: + TU_LOG2(" Get Volume max of channel: %u\r\n", channelNum); + { + int16_t max = 30; // +30 dB + max = max * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &max, sizeof(max)); + } + + case AUDIO10_CS_REQ_GET_RES: + TU_LOG2(" Get Volume res of channel: %u\r\n", channelNum); + { + int16_t res = 1; // 1 dB + res = res * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &res, sizeof(res)); + } + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; } -// Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { - (void) rhport; +//--------------------------------------------------------------------+ +// UAC2 Helper Functions +//--------------------------------------------------------------------+ + +#if TUD_OPT_HIGH_SPEED - // Page 91 in UAC2 specification +static bool audio20_set_req_entity(tusb_control_request_t const *p_request, uint8_t *pBuff) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - (void) itf; - // We do not support any set range requests here, only current value requests - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // If request is for our feature unit if (entityID == UAC2_ENTITY_FEATURE_UNIT) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Request uses format layout 1 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); - mute[channelNum] = ((audio_control_cur_1_t *) pBuff)->bCur; + mute[channelNum] = ((audio20_control_cur_1_t *) pBuff)->bCur; TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); return true; - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: // Request uses format layout 2 - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); - volume[channelNum] = (uint16_t) ((audio_control_cur_2_t *) pBuff)->bCur; + volume[channelNum] = (int16_t) ((audio20_control_cur_2_t *) pBuff)->bCur; TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); return true; @@ -275,10 +382,10 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == UAC2_ENTITY_CLOCK) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_4_t)); + case AUDIO20_CS_CTRL_SAM_FREQ: + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_4_t)); - sampFreq = (uint32_t) ((audio_control_cur_4_t *) pBuff)->bCur; + sampFreq = (uint32_t) ((audio20_control_cur_4_t *) pBuff)->bCur; TU_LOG2("Clock set current freq: %" PRIu32 "\r\n", sampFreq); @@ -292,59 +399,20 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } } - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an EP -bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t ep = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) ep; - - // return tud_control_xfer(rhport, p_request, &tmp, 1); - - return false;// Yet not implemented -} - -// Invoked when audio class specific get request received for an interface -bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification - uint8_t channelNum = TU_U16_LOW(p_request->wValue); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - uint8_t itf = TU_U16_LOW(p_request->wIndex); - - (void) channelNum; - (void) ctrlSel; - (void) itf; - - return false;// Yet not implemented + return false; } -// Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; - - // Page 91 in UAC2 specification +static bool audio20_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { uint8_t channelNum = TU_U16_LOW(p_request->wValue); uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since we have only one audio function implemented, we do not need the itf value uint8_t entityID = TU_U16_HIGH(p_request->wIndex); // Input terminal (Microphone input) if (entityID == UAC2_ENTITY_INPUT_TERMINAL) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { + case AUDIO20_TE_CTRL_CONNECTOR: { // The terminal connector control only has a get request with only the CUR attribute. - audio_desc_channel_cluster_t ret; + audio20_desc_channel_cluster_t ret; // Those are dummy values for now ret.bNrChannels = 1; @@ -366,23 +434,23 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit if (entityID == UAC2_ENTITY_FEATURE_UNIT) { switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: // Audio control mute cur parameter block consists of only one byte - we thus can send it right away // There does not exist a range parameter block for mute TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum])); - case AUDIO_CS_REQ_RANGE: + case AUDIO20_CS_REQ_RANGE: TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum); // Copy values - only for testing - better is version below - audio_control_range_2_n_t(1) + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; @@ -409,16 +477,16 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock Source unit if (entityID == UAC2_ENTITY_CLOCK) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: // channelNum is always zero in this case switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: TU_LOG2(" Get Sample Freq.\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq)); - case AUDIO_CS_REQ_RANGE: { + case AUDIO20_CS_REQ_RANGE: { TU_LOG2(" Get Sample Freq. range\r\n"); - audio_control_range_4_n_t(N_sampleRates) rangef = + audio20_control_range_4_n_t(N_sampleRates) rangef = { .wNumSubRanges = tu_htole16(N_sampleRates)}; TU_LOG1("Clock get %d freq ranges\r\n", N_sampleRates); @@ -437,7 +505,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } break; - case AUDIO_CS_CTRL_CLK_VALID: + case AUDIO20_CS_CTRL_CLK_VALID: // Only cur attribute exists for this request TU_LOG2(" Get Sample Freq. valid\r\n"); return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid)); @@ -449,7 +517,82 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } } - TU_LOG2(" Unsupported entity: %d\r\n", entityID); + return false; +} + +#endif // TUD_OPT_HIGH_SPEED + +//--------------------------------------------------------------------+ +// Main Callback Functions +//--------------------------------------------------------------------+ + +// Invoked when set interface is called, typically on start/stop streaming or format change +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + //uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); + uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); + + // Clear buffer when streaming format is changed + if (alt != 0) { + bytesPerSample = bytesPerSampleAltList[alt - 1]; + } + return true; +} + +// Invoked when audio class specific set request received for an EP +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void) rhport; + (void) pBuff; + + if (tud_audio_version() == 1) { + return audio10_set_req_ep(p_request, pBuff); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific get request received for an EP +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_ep(rhport, p_request); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific set request received for an entity +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_set_req_entity(p_request, pBuff); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_set_req_entity(p_request, pBuff); +#endif + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific get request received for an entity +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_entity(rhport, p_request); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_get_req_entity(rhport, p_request); +#endif + } + return false;// Yet not implemented } diff --git a/examples/device/audio_test_multi_rate/src/tusb_config.h b/examples/device/audio_test_multi_rate/src/tusb_config.h index 7ce235df0..3587ae089 100644 --- a/examples/device/audio_test_multi_rate/src/tusb_config.h +++ b/examples/device/audio_test_multi_rate/src/tusb_config.h @@ -116,23 +116,28 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16 -// 24bit in 32bit slots +// 24bit in 32bit slots (UAC2 only) #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 4 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 24 // Have a look into audio_device.h for all configurations -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! -#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor! +// UAC1 (Full-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(false, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +// UAC2 (High-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX // Example write FIFO every 1ms, so it should be 8 times larger for HS device +// Maximum EP IN size for all AS alternate settings used +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, TU_MAX(CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN)) + +// Tx flow control needs buffer size >= 4* EP size to work correctly +// Example write FIFO every 1ms (8 HS frames), so buffer size should be 8 times larger for HS device +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ TU_MAX(4 * CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, TU_MAX(32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN, 32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN)) #ifdef __cplusplus } diff --git a/examples/device/audio_test_multi_rate/src/usb_descriptors.c b/examples/device/audio_test_multi_rate/src/usb_descriptors.c index 11e5d2127..1912a81e2 100644 --- a/examples/device/audio_test_multi_rate/src/usb_descriptors.c +++ b/examples/device/audio_test_multi_rate/src/usb_descriptors.c @@ -41,8 +41,7 @@ //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ -static tusb_desc_device_t const desc_device = -{ +static tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = 0x0200, @@ -67,23 +66,19 @@ static tusb_desc_device_t const desc_device = // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ +uint8_t const * tud_descriptor_device_cb(void) { return (uint8_t const *) &desc_device; } //--------------------------------------------------------------------+ // Configuration Descriptor //--------------------------------------------------------------------+ -enum -{ +enum { ITF_NUM_AUDIO_CONTROL = 0, ITF_NUM_AUDIO_STREAMING, ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN) - #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... @@ -97,24 +92,81 @@ enum #define EPNUM_AUDIO 0x01 #endif -uint8_t const desc_configuration[] = -{ +#define CONFIG_UAC1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO10_MIC_ONE_CH_DESC_LEN(3)) + +uint8_t const desc_uac1_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC1_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, EP Out & EP In address, EP size + TUD_AUDIO10_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ 2, /*_nBitsUsedPerSample*/ 16, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, 32000, 48000, 96000) +}; + +TU_VERIFY_STATIC(sizeof(desc_uac1_configuration) == CONFIG_UAC1_TOTAL_LEN, "Incorrect size"); + +#if TUD_OPT_HIGH_SPEED +#define CONFIG_UAC2_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO20_MIC_ONE_CH_2_FORMAT_DESC_LEN) + +uint8_t const desc2_uac2_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC2_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_epin*/ 0x80 | EPNUM_AUDIO) + TUD_AUDIO20_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_epin*/ 0x80 | EPNUM_AUDIO) +}; + +TU_VERIFY_STATIC(sizeof(desc2_uac2_configuration) == CONFIG_UAC2_TOTAL_LEN, "Incorrect size"); + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 }; -TU_VERIFY_STATIC(sizeof(desc_configuration) == CONFIG_TOTAL_LEN, "Incorrect size"); +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const *tud_descriptor_device_qualifier_cb(void) { + return (uint8_t const *) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index;// for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_uac1_configuration : desc2_uac2_configuration; +} + +#endif// highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations - return desc_configuration; +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + if(tud_speed_get() == TUSB_SPEED_FULL) { + return desc_uac1_configuration; + } else { + return desc2_uac2_configuration; + } +#else + return desc_uac1_configuration; +#endif } //--------------------------------------------------------------------+ @@ -130,8 +182,7 @@ enum { }; // array of pointer to string descriptors -char const* string_desc_arr [] = -{ +char const* string_desc_arr [] = { (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) "PaniRCorp", // 1: Manufacturer "MicNode", // 2: Product diff --git a/examples/device/audio_test_multi_rate/src/usb_descriptors.h b/examples/device/audio_test_multi_rate/src/usb_descriptors.h index 8381e31f5..c02f40cd9 100644 --- a/examples/device/audio_test_multi_rate/src/usb_descriptors.h +++ b/examples/device/audio_test_multi_rate/src/usb_descriptors.h @@ -35,68 +35,68 @@ #define UAC2_ENTITY_FEATURE_UNIT 0x02 -#define TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ +#define TUD_AUDIO20_MIC_ONE_CH_2_FORMAT_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1)\ /* Interface 1, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ /* Interface 1, Alternate 1 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 1, Alternate 2 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(_itfnum, _stridx, _epin) \ +#define TUD_AUDIO20_MIC_ONE_CH_2_FORMAT_DESCRIPTOR(_itfnum, _stridx, _epin) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS | AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS, /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ AUDIO20_CTRL_RW << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS | AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_VAL_POS, /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC2_ENTITY_INPUT_TERMINAL, /*_srcid*/ UAC2_ENTITY_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC2_ENTITY_INPUT_TERMINAL, /*_srcid*/ UAC2_ENTITY_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ UAC2_ENTITY_FEATURE_UNIT, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ UAC2_ENTITY_FEATURE_UNIT, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN, /*_interval*/ 0x01),\ /* 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),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Interface 1, Alternate 2 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN, /*_interval*/ 0x01),\ /* 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) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) #endif diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 69f2435ba..4fb209fd0 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -37,7 +37,7 @@ #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) #endif -#define CDC_STACK_SIZE configMINIMAL_STACK_SIZE +#define CDC_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE //--------------------------------------------------------------------+ diff --git a/examples/device/cdc_uac2/src/tusb_config.h b/examples/device/cdc_uac2/src/tusb_config.h index bd1dfc688..b7ece8b7c 100644 --- a/examples/device/cdc_uac2/src/tusb_config.h +++ b/examples/device/cdc_uac2/src/tusb_config.h @@ -105,8 +105,6 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN - // How many formats are used, need to adjust USB descriptor if changed #define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2 @@ -142,8 +140,8 @@ extern "C" { // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device @@ -151,15 +149,12 @@ extern "C" { // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device -// Size of control request buffer -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 - // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/examples/device/cdc_uac2/src/uac2_app.c b/examples/device/cdc_uac2/src/uac2_app.c index a1a0dd73d..cb7b716e8 100644 --- a/examples/device/cdc_uac2/src/uac2_app.c +++ b/examples/device/cdc_uac2/src/uac2_app.c @@ -80,22 +80,22 @@ void audio_task(void) { } // Helper for clock get requests -static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request) +static bool tud_audio_clock_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { - if (request->bRequest == AUDIO_CS_REQ_CUR) + if (request->bRequest == AUDIO20_CS_REQ_CUR) { TU_LOG1("Clock get current freq %" PRIu32 "\r\n", current_sample_rate); - audio_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) }; + audio20_control_cur_4_t curf = { (int32_t) tu_htole32(current_sample_rate) }; return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &curf, sizeof(curf)); } - else if (request->bRequest == AUDIO_CS_REQ_RANGE) + else if (request->bRequest == AUDIO20_CS_REQ_RANGE) { - audio_control_range_4_n_t(N_SAMPLE_RATES) rangef = + audio20_control_range_4_n_t(N_SAMPLE_RATES) rangef = { .wNumSubRanges = tu_htole16(N_SAMPLE_RATES) }; @@ -111,10 +111,10 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &rangef, sizeof(rangef)); } } - else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && - request->bRequest == AUDIO_CS_REQ_CUR) + else if (request->bControlSelector == AUDIO20_CS_CTRL_CLK_VALID && + request->bRequest == AUDIO20_CS_REQ_CUR) { - audio_control_cur_1_t cur_valid = { .bCur = 1 }; + audio20_control_cur_1_t cur_valid = { .bCur = 1 }; TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_valid, sizeof(cur_valid)); } @@ -124,18 +124,18 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t } // Helper for clock set requests -static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) +static bool tud_audio_clock_set_request(uint8_t rhport, audio20_control_request_t const *request, uint8_t const *buf) { (void)rhport; TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t)); + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_4_t)); - current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *)buf)->bCur; + current_sample_rate = (uint32_t) ((audio20_control_cur_4_t const *)buf)->bCur; TU_LOG1("Clock set current freq: %" PRIu32 "\r\n", current_sample_rate); @@ -150,21 +150,21 @@ static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t } // Helper for feature unit get requests -static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request) +static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR) + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE && request->bRequest == AUDIO20_CS_REQ_CUR) { - audio_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] }; + audio20_control_cur_1_t mute1 = { .bCur = mute[request->bChannelNumber] }; TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &mute1, sizeof(mute1)); } - else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { - if (request->bRequest == AUDIO_CS_REQ_RANGE) + if (request->bRequest == AUDIO20_CS_REQ_RANGE) { - audio_control_range_2_n_t(1) range_vol = { + audio20_control_range_2_n_t(1) range_vol = { .wNumSubRanges = tu_htole16(1), .subrange[0] = { .bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256) } }; @@ -172,9 +172,9 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &range_vol, sizeof(range_vol)); } - else if (request->bRequest == AUDIO_CS_REQ_CUR) + else if (request->bRequest == AUDIO20_CS_REQ_CUR) { - audio_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) }; + audio20_control_cur_2_t cur_vol = { .bCur = tu_htole16(volume[request->bChannelNumber]) }; TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *)request, &cur_vol, sizeof(cur_vol)); } @@ -186,28 +186,28 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req } // Helper for feature unit set requests -static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) +static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio20_control_request_t const *request, uint8_t const *buf) { (void)rhport; TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t)); + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_1_t)); - mute[request->bChannelNumber] = ((audio_control_cur_1_t const *)buf)->bCur; + mute[request->bChannelNumber] = ((audio20_control_cur_1_t const *)buf)->bCur; TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]); return true; } - else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) + else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t)); + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_2_t)); - volume[request->bChannelNumber] = ((audio_control_cur_2_t const *)buf)->bCur; + volume[request->bChannelNumber] = ((audio20_control_cur_2_t const *)buf)->bCur; TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256); @@ -228,7 +228,7 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req // Invoked when audio class specific get request received for an entity bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - audio_control_request_t const *request = (audio_control_request_t const *)p_request; + audio20_control_request_t const *request = (audio20_control_request_t const *)p_request; if (request->bEntityID == UAC2_ENTITY_CLOCK) return tud_audio_clock_get_request(rhport, request); @@ -245,7 +245,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Invoked when audio class specific set request received for an entity bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { - audio_control_request_t const *request = (audio_control_request_t const *)p_request; + audio20_control_request_t const *request = (audio20_control_request_t const *)p_request; if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) return tud_audio_feature_unit_set_request(rhport, request, buf); diff --git a/examples/device/cdc_uac2/src/usb_descriptors.h b/examples/device/cdc_uac2/src/usb_descriptors.h index 736feeefe..95d8da5c3 100644 --- a/examples/device/cdc_uac2/src/usb_descriptors.h +++ b/examples/device/cdc_uac2/src/usb_descriptors.h @@ -49,110 +49,110 @@ enum ITF_NUM_TOTAL }; -#define TUD_AUDIO_HEADSET_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ +#define TUD_AUDIO_HEADSET_STEREO_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2)\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ /* Interface 1, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ /* Interface 1, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 1, Alternate 2 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 2, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ /* Interface 2, Alternate 1 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 2, Alternate 2 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) #define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ 3, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ 3, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2)+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS)),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* 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_MILLISEC, /*_lockdelay*/ 0x0001),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Interface 1, Alternate 2 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* 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_MILLISEC, /*_lockdelay*/ 0x0001),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 2, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* 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),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Interface 2, Alternate 2 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* 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) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) #endif diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c index 0eb13add3..391e3c42a 100644 --- a/examples/device/hid_composite_freertos/src/main.c +++ b/examples/device/hid_composite_freertos/src/main.c @@ -53,7 +53,7 @@ #define USBD_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) #endif -#define HID_STACK_SZIE configMINIMAL_STACK_SIZE +#define HID_STACK_SZIE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c index 9dd66c526..f5267214e 100644 --- a/examples/device/midi_test_freertos/src/main.c +++ b/examples/device/midi_test_freertos/src/main.c @@ -48,7 +48,7 @@ #endif #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE -#define MIDI_STACK_SIZE configMINIMAL_STACK_SIZE +#define MIDI_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 2 : 1)) // static task #if configSUPPORT_STATIC_ALLOCATION diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index 102a6eef1..96fa66f1e 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -73,7 +73,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states -int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 +uint8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1];// +1 for master channel 0 // Buffer for microphone data @@ -141,18 +141,195 @@ void tud_resume_cb(void) { blink_interval_ms = tud_mounted() ? BLINK_MOUNTED : BLINK_NOT_MOUNTED; } +//--------------------------------------------------------------------+ +// Audio Callback Functions +//--------------------------------------------------------------------+ + +//--------------------------------------------------------------------+ +// UAC1 Helper Functions +//--------------------------------------------------------------------+ + +static bool audio10_set_req_ep(tusb_control_request_t const *p_request, uint8_t *pBuff) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_SET_CUR) { + // Request uses 3 bytes + TU_VERIFY(p_request->wLength == 3); + + current_sample_rate = tu_unaligned_read32(pBuff) & 0x00FFFFFF; + + TU_LOG2("EP set current freq: %" PRIu32 "\r\n", current_sample_rate); + + return true; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + + return false; +} + +static bool audio10_get_req_ep(uint8_t rhport, tusb_control_request_t const *p_request) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_GET_CUR) { + TU_LOG2("EP get current freq\r\n"); + + uint8_t freq[3]; + freq[0] = (uint8_t) (current_sample_rate & 0xFF); + freq[1] = (uint8_t) ((current_sample_rate >> 8) & 0xFF); + freq[2] = (uint8_t) ((current_sample_rate >> 16) & 0xFF); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, freq, sizeof(freq)); + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + + return false; +} + +static bool audio10_set_req_entity(tusb_control_request_t const *p_request, uint8_t *pBuff) { + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // If request is for our speaker feature unit + if (entityID == UAC1_ENTITY_SPK_FEATURE_UNIT) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength == 1); + + mute[channelNum] = pBuff[0]; + + TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); + return true; + + default: + return false; // not supported + } + + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength == 2); + + volume[channelNum] = (int16_t)tu_unaligned_read16(pBuff) / 256; + + TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); + return true; + + default: + return false; // not supported + } + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; +} + +static bool audio10_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // If request is for our speaker feature unit + if (entityID == UAC1_ENTITY_SPK_FEATURE_UNIT) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + // Audio control mute cur parameter block consists of only one byte - we thus can send it right away + // There does not exist a range parameter block for mute + TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); + + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_GET_CUR: + TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); + { + int16_t vol = (int16_t) volume[channelNum]; + vol = vol * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &vol, sizeof(vol)); + } + + case AUDIO10_CS_REQ_GET_MIN: + TU_LOG2(" Get Volume min of channel: %u\r\n", channelNum); + { + int16_t min = -90; // -90 dB + min = min * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &min, sizeof(min)); + } + + case AUDIO10_CS_REQ_GET_MAX: + TU_LOG2(" Get Volume max of channel: %u\r\n", channelNum); + { + int16_t max = 30; // +30 dB + max = max * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &max, sizeof(max)); + } + + case AUDIO10_CS_REQ_GET_RES: + TU_LOG2(" Get Volume res of channel: %u\r\n", channelNum); + { + int16_t res = 1; // 1 dB + res = res * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &res, sizeof(res)); + } + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; +} + +//--------------------------------------------------------------------+ +// UAC2 Helper Functions +//--------------------------------------------------------------------+ + +#if TUD_OPT_HIGH_SPEED + // Helper for clock get requests -static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request) { +static bool audio20_clock_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { - if (request->bRequest == AUDIO_CS_REQ_CUR) { + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { + if (request->bRequest == AUDIO20_CS_REQ_CUR) { TU_LOG1("Clock get current freq %" PRIu32 "\r\n", current_sample_rate); - audio_control_cur_4_t curf = {(int32_t) tu_htole32(current_sample_rate)}; + audio20_control_cur_4_t curf = {(int32_t) tu_htole32(current_sample_rate)}; return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &curf, sizeof(curf)); - } else if (request->bRequest == AUDIO_CS_REQ_RANGE) { - audio_control_range_4_n_t(N_SAMPLE_RATES) rangef = + } else if (request->bRequest == AUDIO20_CS_REQ_RANGE) { + audio20_control_range_4_n_t(N_SAMPLE_RATES) rangef = { .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)}; TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES); @@ -165,9 +342,9 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &rangef, sizeof(rangef)); } - } else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && - request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_1_t cur_valid = {.bCur = 1}; + } else if (request->bControlSelector == AUDIO20_CS_CTRL_CLK_VALID && + request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_1_t cur_valid = {.bCur = 1}; TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &cur_valid, sizeof(cur_valid)); } @@ -177,16 +354,16 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t } // Helper for clock set requests -static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) { +static bool audio20_clock_set_request(uint8_t rhport, audio20_control_request_t const *request, uint8_t const *buf) { (void) rhport; TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t)); + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_4_t)); - current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *) buf)->bCur; + current_sample_rate = (uint32_t) ((audio20_control_cur_4_t const *) buf)->bCur; TU_LOG1("Clock set current freq: %" PRIu32 "\r\n", current_sample_rate); @@ -199,23 +376,23 @@ static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t } // Helper for feature unit get requests -static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request) { +static bool audio20_feature_unit_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_1_t mute1 = {.bCur = mute[request->bChannelNumber]}; + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE && request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_1_t mute1 = {.bCur = mute[request->bChannelNumber]}; TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &mute1, sizeof(mute1)); - } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { - if (request->bRequest == AUDIO_CS_REQ_RANGE) { - audio_control_range_2_n_t(1) range_vol = { + } else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { + if (request->bRequest == AUDIO20_CS_REQ_RANGE) { + audio20_control_range_2_n_t(1) range_vol = { .wNumSubRanges = tu_htole16(1), .subrange[0] = {.bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256)}}; TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber, range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &range_vol, sizeof(range_vol)); - } else if (request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_2_t cur_vol = {.bCur = tu_htole16(volume[request->bChannelNumber])}; + } else if (request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_2_t cur_vol = {.bCur = tu_htole16(volume[request->bChannelNumber])}; TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &cur_vol, sizeof(cur_vol)); } @@ -227,24 +404,24 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req } // Helper for feature unit set requests -static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) { +static bool audio20_feature_unit_set_request(uint8_t rhport, audio20_control_request_t const *request, uint8_t const *buf) { (void) rhport; TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t)); + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_1_t)); - mute[request->bChannelNumber] = ((audio_control_cur_1_t const *) buf)->bCur; + mute[request->bChannelNumber] = ((audio20_control_cur_1_t const *) buf)->bCur; TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]); return true; - } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t)); + } else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_2_t)); - volume[request->bChannelNumber] = ((audio_control_cur_2_t const *) buf)->bCur; + volume[request->bChannelNumber] = ((audio20_control_cur_2_t const *) buf)->bCur; TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256); @@ -256,18 +433,13 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req } } -//--------------------------------------------------------------------+ -// Application Callback API Implementations -//--------------------------------------------------------------------+ - -// Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - audio_control_request_t const *request = (audio_control_request_t const *) p_request; +static bool audio20_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { + audio20_control_request_t const *request = (audio20_control_request_t const *) p_request; if (request->bEntityID == UAC2_ENTITY_CLOCK) - return tud_audio_clock_get_request(rhport, request); + return audio20_clock_get_request(rhport, request); if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) - return tud_audio_feature_unit_get_request(rhport, request); + return audio20_feature_unit_get_request(rhport, request); else { TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); @@ -275,20 +447,78 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } -// Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { - audio_control_request_t const *request = (audio_control_request_t const *) p_request; +static bool audio20_set_req_entity(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { + audio20_control_request_t const *request = (audio20_control_request_t const *) p_request; if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) - return tud_audio_feature_unit_set_request(rhport, request, buf); + return audio20_feature_unit_set_request(rhport, request, buf); if (request->bEntityID == UAC2_ENTITY_CLOCK) - return tud_audio_clock_set_request(rhport, request, buf); + return audio20_clock_set_request(rhport, request, buf); TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); return false; } +#endif // TUD_OPT_HIGH_SPEED + +// Invoked when audio class specific set request received for an EP +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void) rhport; + (void) pBuff; + + if (tud_audio_version() == 1) { + return audio10_set_req_ep(p_request, pBuff); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific get request received for an EP +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_ep(rhport, p_request); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific get request received for an entity +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_entity(rhport, p_request); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_get_req_entity(rhport, p_request); +#endif + } + + return false; +} + +// Invoked when audio class specific set request received for an entity +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_set_req_entity(p_request, buf); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_set_req_entity(rhport, p_request, buf); +#endif + } + + return false; +} + bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; @@ -380,6 +610,10 @@ void audio_control_task(void) { uint32_t btn = board_button_read(); + // Even UAC1 spec have status interrupt support like UAC2, most host do not support it + // So you have to either use UAC2 or use old day HID volume control + TU_VERIFY((tud_audio_version() == 1),); + if (!btn_prev && btn) { // Adjust volume between 0dB (100%) and -30dB (10%) for (int i = 0; i < CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1; i++) { @@ -387,14 +621,14 @@ void audio_control_task(void) { } // 6.1 Interrupt Data Message - const audio_interrupt_data_t data = { + const audio_interrupt_data_t data = {.v2 = { .bInfo = 0, // Class-specific interrupt, originated from an interface - .bAttribute = AUDIO_CS_REQ_CUR, // Caused by current settings + .bAttribute = AUDIO20_CS_REQ_CUR, // Caused by current settings .wValue_cn_or_mcn = 0, // CH0: master volume - .wValue_cs = AUDIO_FU_CTRL_VOLUME, // Volume change + .wValue_cs = AUDIO20_FU_CTRL_VOLUME, // Volume change .wIndex_ep_or_int = 0, // From the interface itself .wIndex_entity_id = UAC2_ENTITY_SPK_FEATURE_UNIT,// From feature unit - }; + }}; tud_audio_int_write(&data); } diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index 2678054e1..a43a4bd25 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -108,8 +108,6 @@ extern "C" { // Allow volume controlled by on-baord button #define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 1 -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN - // How many formats are used, need to adjust USB descriptor if changed #define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2 @@ -126,40 +124,45 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 2 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16 -#if defined(__RX__) -// 8bit in 8bit slots -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 8 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 8 -#else -// 24bit in 32bit slots +// 24bit in 32bit slots (UAC2 only) #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 4 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 24 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX 4 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX 24 -#endif // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +// UAC1 (Full-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(false, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) + +// UAC2 (High-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_IN) // Maximum EP IN size for all AS alternate settings used -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device +// Maximum EP IN size for all AS alternate settings used +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TU_MAX(CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, TU_MAX(CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN, CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN)) + +// Tx flow control needs buffer size >= 4* EP size to work correctly +// Example write FIFO every 1ms (8 HS frames), so buffer size should be 8 times larger for HS device +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ TU_MAX(4 * CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, TU_MAX(32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_IN, 32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_IN)) // EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +// UAC1 (Full-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(false, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) + +// UAC2 (High-Speed) Endpoint size calculation +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_OUT TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +#define CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_OUT TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_EP_SZ_OUT) // Maximum EP IN size for all AS alternate settings used -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device +// Maximum EP OUT size for all AS alternate settings used +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_OUT, TU_MAX(CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_OUT, CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_OUT)) -// Size of control request buffer -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 +// Rx flow control needs buffer size >= 4* EP size to work correctly +// Example read FIFO every 1ms (8 HS frames), so buffer size should be 8 times larger for HS device +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(4 * CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_OUT, TU_MAX(32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_1_EP_SZ_OUT, 32 * CFG_TUD_AUDIO20_FUNC_1_FORMAT_2_EP_SZ_OUT)) #ifdef __cplusplus } diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index 7b1a41161..e4fbbf8a5 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -110,22 +110,93 @@ uint8_t const * tud_descriptor_device_cb(void) #define EPNUM_AUDIO_INT 0x02 #endif -uint8_t const desc_configuration[] = +#define CONFIG_UAC1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO10_HEADSET_STEREO_DESC_LEN(2)) + +uint8_t const desc_uac1_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC1_TOTAL_LEN, 0x00, 100), + + // Interface number, string index, bytes per sample RX/TX, bits used per sample RX/TX, EP Out & EP In address, EP sizes, sample rate + TUD_AUDIO10_HEADSET_STEREO_DESCRIPTOR(ITF_NUM_AUDIO_CONTROL, 4, \ + CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX, \ + CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX, \ + EPNUM_AUDIO_OUT, CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_OUT, \ + EPNUM_AUDIO_IN | 0x80, CFG_TUD_AUDIO10_FUNC_1_FORMAT_1_EP_SZ_IN, \ + 44100, 48000) +}; + +TU_VERIFY_STATIC(sizeof(desc_uac1_configuration) == CONFIG_UAC1_TOTAL_LEN, "Incorrect size"); + +#if TUD_OPT_HIGH_SPEED + +#define CONFIG_UAC2_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO20_HEADSET_STEREO_DESC_LEN) + +uint8_t const desc_uac2_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC2_TOTAL_LEN, 0x00, 100), + + // String index, EP Out & EP In address, EP Interrupt address + TUD_AUDIO20_HEADSET_STEREO_DESCRIPTOR(5, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80, EPNUM_AUDIO_INT | 0x80) +}; + +TU_VERIFY_STATIC(sizeof(desc_uac2_configuration) == CONFIG_UAC2_TOTAL_LEN, "Incorrect size"); + + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = 0x0200, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, - // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80, EPNUM_AUDIO_INT | 0x80) + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 }; +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const *tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const *) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_uac1_configuration : desc_uac2_configuration; +} +#endif + // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void)index; // for multiple configurations - return desc_configuration; +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + if(tud_speed_get() == TUSB_SPEED_FULL) { + return desc_uac1_configuration; + } else { + return desc_uac2_configuration; + } +#else + return desc_uac1_configuration; +#endif } //--------------------------------------------------------------------+ @@ -145,10 +216,10 @@ static char const *string_desc_arr[] = { (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) "TinyUSB", // 1: Manufacturer - "TinyUSB headset", // 2: Product + "TinyUSB Headset", // 2: Product NULL, // 3: Serials will use unique ID if possible - "TinyUSB Speakers", // 4: Audio Interface - "TinyUSB Microphone", // 5: Audio Interface + "TinyUSB UAC1 Headset", // 4: Function + "TinyUSB UAC2 Headset", // 5: Function }; static uint16_t _desc_str[32 + 1]; diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h index da0da83e8..d673beace 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.h +++ b/examples/device/uac2_headset/src/usb_descriptors.h @@ -26,7 +26,17 @@ #ifndef _USB_DESCRIPTORS_H_ #define _USB_DESCRIPTORS_H_ -// #include "tusb.h" +enum +{ + ITF_NUM_AUDIO_CONTROL = 0, + ITF_NUM_AUDIO_STREAMING_SPK, + ITF_NUM_AUDIO_STREAMING_MIC, + ITF_NUM_TOTAL +}; + +//--------------------------------------------------------------------+ +// UAC2 DESCRIPTOR TEMPLATES +//--------------------------------------------------------------------+ // Unit numbers are arbitrary selected #define UAC2_ENTITY_CLOCK 0x04 @@ -38,121 +48,192 @@ #define UAC2_ENTITY_MIC_INPUT_TERMINAL 0x11 #define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x13 -enum -{ - ITF_NUM_AUDIO_CONTROL = 0, - ITF_NUM_AUDIO_STREAMING_SPK, - ITF_NUM_AUDIO_STREAMING_MIC, - ITF_NUM_TOTAL -}; - -#define TUD_AUDIO_HEADSET_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_STD_AC_INT_EP_LEN\ +#define TUD_AUDIO20_HEADSET_STEREO_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2)\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_STD_AC_INT_EP_LEN\ /* Interface 1, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ /* Interface 1, Alternate 1 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 1, Alternate 2 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 2, Alternate 0 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ /* Interface 2, Alternate 1 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ /* Interface 2, Alternate 2 */\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin, _epint) \ +#define TUD_AUDIO20_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin, _epint) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2)+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3, /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS)),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */\ - TUD_AUDIO_DESC_STD_AC_INT_EP(/*_ep*/ _epint, /*_interval*/ 0x01), \ + TUD_AUDIO20_DESC_STD_AC_INT_EP(/*_ep*/ _epint, /*_interval*/ 0x01), \ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* 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_MILLISEC, /*_lockdelay*/ 0x0001),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Interface 1, Alternate 2 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x05),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* 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_MILLISEC, /*_lockdelay*/ 0x0001),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 2, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* 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),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Interface 2, Alternate 2 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ 0x04),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x02, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* 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) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +//--------------------------------------------------------------------+ +// UAC1 DESCRIPTOR TEMPLATES +//--------------------------------------------------------------------+ + +// UAC1 entity IDs for speaker and microphone +// Speaker path +#define UAC1_ENTITY_SPK_INPUT_TERMINAL 0x01 +#define UAC1_ENTITY_SPK_FEATURE_UNIT 0x02 +#define UAC1_ENTITY_SPK_OUTPUT_TERMINAL 0x03 +// Microphone path +#define UAC1_ENTITY_MIC_INPUT_TERMINAL 0x11 +#define UAC1_ENTITY_MIC_OUTPUT_TERMINAL 0x13 + +#define TUD_AUDIO10_HEADSET_STEREO_DESC_LEN(_nfreqs) (\ + +TUD_AUDIO10_DESC_STD_AC_LEN\ + + TUD_AUDIO10_DESC_CS_AC_LEN(2)\ + + TUD_AUDIO10_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(2)\ + + TUD_AUDIO10_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_OUTPUT_TERM_LEN\ + /* Interface 1, Alternate 0 (speaker) */\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + /* Interface 1, Alternate 1 (speaker) */\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(_nfreqs)\ + + TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN\ + /* Interface 2, Alternate 0 (microphone) */\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + /* Interface 2, Alternate 1 (microphone) */\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(_nfreqs)\ + + TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN) + + +#define TUD_AUDIO10_HEADSET_STEREO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample_RX, _nBitsUsedPerSample_RX, _nBytesPerSample_TX, _nBitsUsedPerSample_TX, _epout, _epoutsize, _epin, _epinsize, ...) \ + /* Standard AC Interface Descriptor(4.3.1) */\ + TUD_AUDIO10_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.3.2) */\ + TUD_AUDIO10_DESC_CS_AC(/*_bcdADC*/ 0x0100, /*_totallen*/ (TUD_AUDIO10_DESC_INPUT_TERM_LEN+TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(2)+TUD_AUDIO10_DESC_OUTPUT_TERM_LEN+TUD_AUDIO10_DESC_INPUT_TERM_LEN+TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(1)+TUD_AUDIO10_DESC_OUTPUT_TERM_LEN), /*_itf*/ ((_itfnum)+1), ((_itfnum)+2)),\ + /* Speaker Input Terminal Descriptor(4.3.2.1) */\ + TUD_AUDIO10_DESC_INPUT_TERM(/*_termid*/ UAC1_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC1_ENTITY_MIC_OUTPUT_TERMINAL, /*_nchannels*/ 0x02, /*_channelcfg*/ AUDIO10_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_stridx*/ 0x00),\ + /* Speaker Feature Unit Descriptor(4.3.2.5) */\ + TUD_AUDIO10_DESC_FEATURE_UNIT(/*_unitid*/ UAC1_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC1_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlmaster*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME), /*_ctrlch1*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME), /*_ctrlch2*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME)),\ + /* Speaker Output Terminal Descriptor(4.3.2.2) */\ + TUD_AUDIO10_DESC_OUTPUT_TERM(/*_termid*/ UAC1_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00, /*_srcid*/ UAC1_ENTITY_SPK_FEATURE_UNIT, /*_stridx*/ 0x00),\ + /* Microphone Input Terminal Descriptor(4.3.2.1) */\ + TUD_AUDIO10_DESC_INPUT_TERM(/*_termid*/ UAC1_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_nchannels*/ 0x01, /*_channelcfg*/ AUDIO10_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_stridx*/ 0x00),\ + /* Microphone Output Terminal Descriptor(4.3.2.2) */\ + TUD_AUDIO10_DESC_OUTPUT_TERM(/*_termid*/ UAC1_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ UAC1_ENTITY_SPK_INPUT_TERMINAL, /*_srcid*/ UAC1_ENTITY_MIC_INPUT_TERMINAL, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.5.1) - Speaker Interface 1, Alternate 0 */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Standard AS Interface Descriptor(4.5.1) - Speaker Interface 1, Alternate 1 */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ + /* Class-Specific AS Interface Descriptor(4.5.2) */\ + TUD_AUDIO10_DESC_CS_AS_INT(/*_termid*/ UAC1_ENTITY_SPK_INPUT_TERMINAL, /*_delay*/ 0x01, /*_formattype*/ AUDIO10_DATA_FORMAT_TYPE_I_PCM),\ + /* Type I Format Type Descriptor(2.2.5) */\ + TUD_AUDIO10_DESC_TYPE_I_FORMAT(/*_nrchannels*/ 0x02, /*_subframesize*/ _nBytesPerSample_RX, /*_bitresolution*/ _nBitsUsedPerSample_RX, /*_freqs*/ __VA_ARGS__),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.6.1.1) */\ + TUD_AUDIO10_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01, /*_syncep*/ 0x00),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.6.1.2) */\ + 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),\ + /* Standard AS Interface Descriptor(4.5.1) - Microphone Interface 2, Alternate 0 */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+2), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Standard AS Interface Descriptor(4.5.1) - Microphone Interface 2, Alternate 1 */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ + /* Class-Specific AS Interface Descriptor(4.5.2) */\ + TUD_AUDIO10_DESC_CS_AS_INT(/*_termid*/ UAC1_ENTITY_MIC_OUTPUT_TERMINAL, /*_delay*/ 0x01, /*_formattype*/ AUDIO10_DATA_FORMAT_TYPE_I_PCM),\ + /* Type I Format Type Descriptor(2.2.5) */\ + TUD_AUDIO10_DESC_TYPE_I_FORMAT(/*_nrchannels*/ 0x01, /*_subframesize*/ _nBytesPerSample_TX, /*_bitresolution*/ _nBitsUsedPerSample_TX, /*_freqs*/ __VA_ARGS__),\ + /* 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*/ _epinsize, /*_interval*/ 0x01, /*_syncep*/ 0x00),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.6.1.2) */\ + 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) #endif diff --git a/examples/device/uac2_speaker_fb/CMakeLists.txt b/examples/device/uac2_speaker_fb/CMakeLists.txt index 0ed3db646..ced98a909 100644 --- a/examples/device/uac2_speaker_fb/CMakeLists.txt +++ b/examples/device/uac2_speaker_fb/CMakeLists.txt @@ -21,7 +21,6 @@ add_executable(${PROJECT}) target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/quirk_os_guessing.c ) # Example include diff --git a/examples/device/uac2_speaker_fb/src/common_types.h b/examples/device/uac2_speaker_fb/src/common_types.h index 174e26671..b79ae2fd0 100644 --- a/examples/device/uac2_speaker_fb/src/common_types.h +++ b/examples/device/uac2_speaker_fb/src/common_types.h @@ -41,7 +41,7 @@ typedef struct { uint32_t sample_rate; uint8_t alt_settings; - int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; + uint8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; uint16_t fifo_size; uint16_t fifo_count; diff --git a/examples/device/uac2_speaker_fb/src/main.c b/examples/device/uac2_speaker_fb/src/main.c index e742dc52a..f2cfb155e 100644 --- a/examples/device/uac2_speaker_fb/src/main.c +++ b/examples/device/uac2_speaker_fb/src/main.c @@ -31,25 +31,17 @@ #include "tusb.h" #include "usb_descriptors.h" -#ifdef CFG_QUIRK_OS_GUESSING - #include "quirk_os_guessing.h" -#endif - //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTOTYPES //--------------------------------------------------------------------+ -// List of supported sample rates -#if defined(__RX__) -const uint32_t sample_rates[] = {44100, 48000}; -#else +// List of supported sample rates for UAC2 const uint32_t sample_rates[] = {44100, 48000, 88200, 96000}; -#endif - -uint32_t current_sample_rate = 44100; #define N_SAMPLE_RATES TU_ARRAY_SIZE(sample_rates) +uint32_t current_sample_rate = 44100; + /* Blink pattern * - 25 ms : streaming data * - 250 ms : device not mounted @@ -82,7 +74,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; // Audio controls // Current states -int8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 +uint8_t mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1]; // +1 for master channel 0 int16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1];// +1 for master channel 0 // Buffer for speaker data @@ -153,18 +145,189 @@ void tud_resume_cb(void) { // Application Callback API Implementations //--------------------------------------------------------------------+ -// Helper for clock get requests -static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t const *request) { +//--------------------------------------------------------------------+ +// UAC1 Helper Functions +//--------------------------------------------------------------------+ + +static bool audio10_set_req_ep(tusb_control_request_t const *p_request, uint8_t *pBuff) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_SET_CUR) { + // Request uses 3 bytes + TU_VERIFY(p_request->wLength == 3); + + current_sample_rate = tu_unaligned_read32(pBuff) & 0x00FFFFFF; + + TU_LOG2("EP set current freq: %" PRIu32 "\r\n", current_sample_rate); + + return true; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + + return false; +} + +static bool audio10_get_req_ep(uint8_t rhport, tusb_control_request_t const *p_request) { + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + + switch (ctrlSel) { + case AUDIO10_EP_CTRL_SAMPLING_FREQ: + if (p_request->bRequest == AUDIO10_CS_REQ_GET_CUR) { + TU_LOG2("EP get current freq\r\n"); + + uint8_t freq[3]; + freq[0] = (uint8_t) (current_sample_rate & 0xFF); + freq[1] = (uint8_t) ((current_sample_rate >> 8) & 0xFF); + freq[2] = (uint8_t) ((current_sample_rate >> 16) & 0xFF); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, freq, sizeof(freq)); + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + + return false; +} + +static bool audio10_set_req_entity(tusb_control_request_t const *p_request, uint8_t *pBuff) { + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // If request is for our feature unit + if (entityID == UAC1_ENTITY_FEATURE_UNIT) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength == 1); + + mute[channelNum] = pBuff[0]; + + TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum); + return true; + + default: + return false; // not supported + } + + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_SET_CUR: + // Only 1st form is supported + TU_VERIFY(p_request->wLength == 2); + + volume[channelNum] = (int16_t)tu_unaligned_read16(pBuff) / 256; + + TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum); + return true; + + default: + return false; // not supported + } + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; +} + +static bool audio10_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { + uint8_t channelNum = TU_U16_LOW(p_request->wValue); + uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + + // If request is for our feature unit + if (entityID == UAC1_ENTITY_FEATURE_UNIT) { + switch (ctrlSel) { + case AUDIO10_FU_CTRL_MUTE: + // Audio control mute cur parameter block consists of only one byte - we thus can send it right away + // There does not exist a range parameter block for mute + TU_LOG2(" Get Mute of channel: %u\r\n", channelNum); + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute[channelNum], 1); + + case AUDIO10_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO10_CS_REQ_GET_CUR: + TU_LOG2(" Get Volume of channel: %u\r\n", channelNum); + { + int16_t vol = (int16_t) volume[channelNum]; + vol = vol * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &vol, sizeof(vol)); + } + + case AUDIO10_CS_REQ_GET_MIN: + TU_LOG2(" Get Volume min of channel: %u\r\n", channelNum); + { + int16_t min = -90; // -90 dB + min = min * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &min, sizeof(min)); + } + + case AUDIO10_CS_REQ_GET_MAX: + TU_LOG2(" Get Volume max of channel: %u\r\n", channelNum); + { + int16_t max = 30; // +30 dB + max = max * 256; // convert to 1/256 dB units + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &max, sizeof(max)); + } + + case AUDIO10_CS_REQ_GET_RES: + TU_LOG2(" Get Volume res of channel: %u\r\n", channelNum); + { + int16_t res = 128; // 0.5 dB + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &res, sizeof(res)); + } + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + break; + + // Unknown/Unsupported control + default: + TU_BREAKPOINT(); + return false; + } + } + + return false; +} + +//--------------------------------------------------------------------+ +// UAC2 Helper Functions +//--------------------------------------------------------------------+ + +#if TUD_OPT_HIGH_SPEED + +static bool audio20_clock_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { - if (request->bRequest == AUDIO_CS_REQ_CUR) { + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { + if (request->bRequest == AUDIO20_CS_REQ_CUR) { TU_LOG1("Clock get current freq %" PRIu32 "\r\n", current_sample_rate); - audio_control_cur_4_t curf = {(int32_t) tu_htole32(current_sample_rate)}; + audio20_control_cur_4_t curf = {(int32_t) tu_htole32(current_sample_rate)}; return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &curf, sizeof(curf)); - } else if (request->bRequest == AUDIO_CS_REQ_RANGE) { - audio_control_range_4_n_t(N_SAMPLE_RATES) rangef = + } else if (request->bRequest == AUDIO20_CS_REQ_RANGE) { + audio20_control_range_4_n_t(N_SAMPLE_RATES) rangef = { .wNumSubRanges = tu_htole16(N_SAMPLE_RATES)}; TU_LOG1("Clock get %d freq ranges\r\n", N_SAMPLE_RATES); @@ -177,9 +340,9 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &rangef, sizeof(rangef)); } - } else if (request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && - request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_1_t cur_valid = {.bCur = 1}; + } else if (request->bControlSelector == AUDIO20_CS_CTRL_CLK_VALID && + request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_1_t cur_valid = {.bCur = 1}; TU_LOG1("Clock get is valid %u\r\n", cur_valid.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &cur_valid, sizeof(cur_valid)); } @@ -188,17 +351,14 @@ static bool tud_audio_clock_get_request(uint8_t rhport, audio_control_request_t return false; } -// Helper for clock set requests -static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) { - (void) rhport; - +static bool audio20_clock_set_request(audio20_control_request_t const *request, uint8_t const *buf) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_4_t)); + if (request->bControlSelector == AUDIO20_CS_CTRL_SAM_FREQ) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_4_t)); - current_sample_rate = (uint32_t) ((audio_control_cur_4_t const *) buf)->bCur; + current_sample_rate = (uint32_t) ((audio20_control_cur_4_t const *) buf)->bCur; TU_LOG1("Clock set current freq: %" PRIu32 "\r\n", current_sample_rate); @@ -210,24 +370,23 @@ static bool tud_audio_clock_set_request(uint8_t rhport, audio_control_request_t } } -// Helper for feature unit get requests -static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_request_t const *request) { +static bool audio20_feature_unit_get_request(uint8_t rhport, audio20_control_request_t const *request) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_FEATURE_UNIT); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE && request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_1_t mute1 = {.bCur = mute[request->bChannelNumber]}; + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE && request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_1_t mute1 = {.bCur = mute[request->bChannelNumber]}; TU_LOG1("Get channel %u mute %d\r\n", request->bChannelNumber, mute1.bCur); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &mute1, sizeof(mute1)); - } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { - if (request->bRequest == AUDIO_CS_REQ_RANGE) { - audio_control_range_2_n_t(1) range_vol = { + } else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { + if (request->bRequest == AUDIO20_CS_REQ_RANGE) { + audio20_control_range_2_n_t(1) range_vol = { .wNumSubRanges = tu_htole16(1), .subrange[0] = {.bMin = tu_htole16(-VOLUME_CTRL_50_DB), tu_htole16(VOLUME_CTRL_0_DB), tu_htole16(256)}}; TU_LOG1("Get channel %u volume range (%d, %d, %u) dB\r\n", request->bChannelNumber, range_vol.subrange[0].bMin / 256, range_vol.subrange[0].bMax / 256, range_vol.subrange[0].bRes / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &range_vol, sizeof(range_vol)); - } else if (request->bRequest == AUDIO_CS_REQ_CUR) { - audio_control_cur_2_t cur_vol = {.bCur = tu_htole16(volume[request->bChannelNumber])}; + } else if (request->bRequest == AUDIO20_CS_REQ_CUR) { + audio20_control_cur_2_t cur_vol = {.bCur = tu_htole16(volume[request->bChannelNumber])}; TU_LOG1("Get channel %u volume %d dB\r\n", request->bChannelNumber, cur_vol.bCur / 256); return tud_audio_buffer_and_schedule_control_xfer(rhport, (tusb_control_request_t const *) request, &cur_vol, sizeof(cur_vol)); } @@ -238,25 +397,22 @@ static bool tud_audio_feature_unit_get_request(uint8_t rhport, audio_control_req return false; } -// Helper for feature unit set requests -static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_request_t const *request, uint8_t const *buf) { - (void) rhport; - +static bool audio20_feature_unit_set_request(audio20_control_request_t const *request, uint8_t const *buf) { TU_ASSERT(request->bEntityID == UAC2_ENTITY_FEATURE_UNIT); - TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(request->bRequest == AUDIO20_CS_REQ_CUR); - if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t)); + if (request->bControlSelector == AUDIO20_FU_CTRL_MUTE) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_1_t)); - mute[request->bChannelNumber] = ((audio_control_cur_1_t const *) buf)->bCur; + mute[request->bChannelNumber] = ((audio20_control_cur_1_t const *) buf)->bCur; TU_LOG1("Set channel %d Mute: %d\r\n", request->bChannelNumber, mute[request->bChannelNumber]); return true; - } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { - TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t)); + } else if (request->bControlSelector == AUDIO20_FU_CTRL_VOLUME) { + TU_VERIFY(request->wLength == sizeof(audio20_control_cur_2_t)); - volume[request->bChannelNumber] = ((audio_control_cur_2_t const *) buf)->bCur; + volume[request->bChannelNumber] = ((audio20_control_cur_2_t const *) buf)->bCur; TU_LOG1("Set channel %d volume: %d dB\r\n", request->bChannelNumber, volume[request->bChannelNumber] / 256); @@ -268,14 +424,13 @@ static bool tud_audio_feature_unit_set_request(uint8_t rhport, audio_control_req } } -// Invoked when audio class specific get request received for an entity -bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - audio_control_request_t const *request = (audio_control_request_t const *) p_request; +static bool audio20_get_req_entity(uint8_t rhport, tusb_control_request_t const *p_request) { + audio20_control_request_t const *request = (audio20_control_request_t const *) p_request; if (request->bEntityID == UAC2_ENTITY_CLOCK) - return tud_audio_clock_get_request(rhport, request); + return audio20_clock_get_request(rhport, request); if (request->bEntityID == UAC2_ENTITY_FEATURE_UNIT) - return tud_audio_feature_unit_get_request(rhport, request); + return audio20_feature_unit_get_request(rhport, request); else { TU_LOG1("Get request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); @@ -283,31 +438,24 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } -// Invoked when audio class specific set request received for an entity -bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { - audio_control_request_t const *request = (audio_control_request_t const *) p_request; +static bool audio20_set_req_entity(tusb_control_request_t const *p_request, uint8_t *buf) { + audio20_control_request_t const *request = (audio20_control_request_t const *) p_request; if (request->bEntityID == UAC2_ENTITY_FEATURE_UNIT) - return tud_audio_feature_unit_set_request(rhport, request, buf); + return audio20_feature_unit_set_request(request, buf); if (request->bEntityID == UAC2_ENTITY_CLOCK) - return tud_audio_clock_set_request(rhport, request, buf); + return audio20_clock_set_request(request, buf); TU_LOG1("Set request not handled, entity = %d, selector = %d, request = %d\r\n", request->bEntityID, request->bControlSelector, request->bRequest); return false; } -bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { - (void) rhport; +#endif // TUD_OPT_HIGH_SPEED - uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); - uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); - - if (ITF_NUM_AUDIO_STREAMING == itf && alt == 0) - blink_interval_ms = BLINK_MOUNTED; - - return true; -} +//--------------------------------------------------------------------+ +// Main Callback Functions +//--------------------------------------------------------------------+ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void) rhport; @@ -325,6 +473,75 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques return true; } +// Invoked when audio class specific set request received for an EP +bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void) rhport; + (void) pBuff; + + if (tud_audio_version() == 1) { + return audio10_set_req_ep(p_request, pBuff); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific get request received for an EP +bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_ep(rhport, p_request); + } else if (tud_audio_version() == 2) { + // We do not support any requests here + } + + return false;// Yet not implemented +} + +// Invoked when audio class specific set request received for an entity +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *buf) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_set_req_entity(p_request, buf); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_set_req_entity(p_request, buf); +#endif + } + + return false; +} + +// Invoked when audio class specific get request received for an entity +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + if (tud_audio_version() == 1) { + return audio10_get_req_entity(rhport, p_request); +#if TUD_OPT_HIGH_SPEED + } else if (tud_audio_version() == 2) { + return audio20_get_req_entity(rhport, p_request); +#endif + } + + return false; +} + +bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void) rhport; + + uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); + uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); + + if (ITF_NUM_AUDIO_STREAMING == itf && alt == 0) + blink_interval_ms = BLINK_MOUNTED; + + return true; +} + void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t *feedback_param) { (void) func_id; (void) alt_itf; @@ -349,16 +566,6 @@ bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t fu } #endif -#if CFG_QUIRK_OS_GUESSING -bool tud_audio_feedback_format_correction_cb(uint8_t func_id) { - (void) func_id; - if (tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) { - return true; - } else { - return false; - } -} -#endif //--------------------------------------------------------------------+ // AUDIO Task //--------------------------------------------------------------------+ diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c deleted file mode 100644 index 92b9ab6ee..000000000 --- a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include "quirk_os_guessing.h" - -static tusb_desc_type_t desc_req_buf[2]; -static int desc_req_idx = 0; - -// Place at the start of tud_descriptor_device_cb() -void quirk_os_guessing_desc_device_cb(void) { - desc_req_idx = 0; -} - -// Place at the start of tud_descriptor_configuration_cb() -void quirk_os_guessing_desc_configuration_cb(void) { - // Skip redundant request - if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) { - desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION; - } -} - -// Place at the start of tud_descriptor_bos_cb() -void quirk_os_guessing_desc_bos_cb(void) { - // Skip redundant request - if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) { - desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS; - } -} - -// Place at the start of tud_descriptor_string_cb() -void quirk_os_guessing_desc_string_cb(void) { - // Skip redundant request - if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) { - desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING; - } -} - -// Each OS request descriptors differently: -// Windows 10 - 11 -// Device Desc -// Config Desc -// BOS Desc -// String Desc -// Linux 3.16 - 6.8 -// Device Desc -// BOS Desc -// Config Desc -// String Desc -// OS X Ventura - Sonoma -// Device Desc -// String Desc -// Config Desc || BOS Desc -// BOS Desc || Config Desc -quirk_os_guessing_t quirk_os_guessing_get(void) { - if (desc_req_idx < 2) { - return QUIRK_OS_GUESSING_UNKNOWN; - } - - if (desc_req_buf[0] == TUSB_DESC_BOS && desc_req_buf[1] == TUSB_DESC_CONFIGURATION) { - return QUIRK_OS_GUESSING_LINUX; - } else if (desc_req_buf[0] == TUSB_DESC_CONFIGURATION && desc_req_buf[1] == TUSB_DESC_BOS) { - return QUIRK_OS_GUESSING_WINDOWS; - } else if (desc_req_buf[0] == TUSB_DESC_STRING && (desc_req_buf[1] == TUSB_DESC_BOS || desc_req_buf[1] == TUSB_DESC_CONFIGURATION)) { - return QUIRK_OS_GUESSING_OSX; - } - - return QUIRK_OS_GUESSING_UNKNOWN; -} diff --git a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h b/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h deleted file mode 100644 index 1120355c9..000000000 --- a/examples/device/uac2_speaker_fb/src/quirk_os_guessing.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2024 HiFiPhile - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#ifndef _QUIRK_OS_GUESSING_H_ -#define _QUIRK_OS_GUESSING_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -#include "tusb.h" - -//================================== !!! WARNING !!! ==================================== -// This quirk operate out of USB specification in order to workaround specific issues. -// It may not work on your platform. -//======================================================================================= -// -// Prerequisites: -// - Set USB version to at least 2.01 in Device Descriptor -// - Has a valid BOS Descriptor, refer to webusb_serial example -// -// Attention: -// Windows detection result comes out after Configuration Descriptor request, -// meaning it will be too late to do descriptor adjustment. It's advised to make -// Windows as default configuration and adjust to other OS accordingly. - -typedef enum { - QUIRK_OS_GUESSING_UNKNOWN, - QUIRK_OS_GUESSING_LINUX, - QUIRK_OS_GUESSING_OSX, - QUIRK_OS_GUESSING_WINDOWS, -} quirk_os_guessing_t; - -// Get Host OS type -quirk_os_guessing_t quirk_os_guessing_get(void); - -// Place at the start of tud_descriptor_device_cb() -void quirk_os_guessing_desc_device_cb(void); - -// Place at the start of tud_descriptor_configuration_cb() -void quirk_os_guessing_desc_configuration_cb(void); - -// Place at the start of tud_descriptor_bos_cb() -void quirk_os_guessing_desc_bos_cb(void); - -// Place at the start of tud_descriptor_string_cb() -void quirk_os_guessing_desc_string_cb(void); - -#ifdef __cplusplus - } -#endif - -#endif /* _QUIRK_OS_GUESSING_H_ */ diff --git a/examples/device/uac2_speaker_fb/src/tusb_config.h b/examples/device/uac2_speaker_fb/src/tusb_config.h index 153b056bf..46f5703c8 100644 --- a/examples/device/uac2_speaker_fb/src/tusb_config.h +++ b/examples/device/uac2_speaker_fb/src/tusb_config.h @@ -87,14 +87,6 @@ extern "C" { #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) #endif -/* (Needed for Full-Speed only) - * Enable host OS guessing to workaround UAC2 compatibility issues between Windows and OS X - * The default configuration only support Windows and Linux, enable this option for OS X - * support. Otherwise if you don't need Windows support you can make OS X's configuration as - * default. - */ -#define CFG_QUIRK_OS_GUESSING 1 - //-------------------------------------------------------------------- // DEVICE CONFIGURATION //-------------------------------------------------------------------- @@ -128,35 +120,30 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN - -// Can be enabled with Full-Speed device on OSX, which forces feedback EP size to 3, in this case CFG_QUIRK_OS_GUESSING can be disabled -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2 -// Audio format type I specifications -#if defined(__RX__) -#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000 -#else -#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000 -#endif +// 16bit data in 16bit slots +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2 +#define CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX 16 -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 2 +// UAC1 Full-Speed endpoint size +#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE_FS 48000 +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_FS TUD_AUDIO_EP_SIZE(false, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE_FS, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) +// UAC2 High-Speed endpoint size +#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE_HS 96000 +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_HS TUD_AUDIO_EP_SIZE(true, CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE_HS, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) -// 16bit in 16bit slots -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX 2 -#define CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX 16 +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TU_MAX(CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_FS, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_HS) -// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) -#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +// AUDIO_FEEDBACK_METHOD_FIFO_COUNT needs buffer size >= 4* EP size to work correctly +// Example read FIFO every 1ms (8 HS frames), so buffer size should be 8 times larger for HS device +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ TU_MAX(4 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_FS, 32 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_HS) -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (TUD_OPT_HIGH_SPEED ? 32 : 4) * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX // Example read FIFO every 1ms, so it should be 8 times larger for HS device +// Enable OUT EP +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 // Enable feedback EP -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 - -// Size of control request buffer -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 #ifdef __cplusplus } diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.c b/examples/device/uac2_speaker_fb/src/usb_descriptors.c index c74eb90dc..697e51483 100644 --- a/examples/device/uac2_speaker_fb/src/usb_descriptors.c +++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.c @@ -28,10 +28,6 @@ #include "usb_descriptors.h" #include "common_types.h" -#ifdef CFG_QUIRK_OS_GUESSING -#include "quirk_os_guessing.h" -#endif - /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. * @@ -49,7 +45,7 @@ static tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0201, + .bcdUSB = 0x0200, // Use Interface Association Descriptor (IAD) for Audio // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) @@ -71,12 +67,8 @@ static tusb_desc_device_t const desc_device = // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ -#if CFG_QUIRK_OS_GUESSING - quirk_os_guessing_desc_device_cb(); -#endif - return (uint8_t const *)&desc_device; +uint8_t const * tud_descriptor_device_cb(void) { + return (uint8_t const *) &desc_device; } #if CFG_AUDIO_DEBUG @@ -84,8 +76,7 @@ uint8_t const * tud_descriptor_device_cb(void) // HID Report Descriptor //--------------------------------------------------------------------+ -uint8_t const desc_hid_report[] = -{ +uint8_t const desc_hid_report[] = { HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ HID_USAGE ( 0x01 ),\ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ @@ -101,8 +92,7 @@ uint8_t const desc_hid_report[] = // Invoked when received GET HID REPORT DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) -{ +uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) { (void) itf; return desc_hid_report; } @@ -112,109 +102,126 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) // Configuration Descriptor //--------------------------------------------------------------------+ -#if CFG_AUDIO_DEBUG - #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN + TUD_HID_DESC_LEN) -#else - #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN) -#endif - #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... + #define EPNUM_AUDIO 0x03 #define EPNUM_AUDIO_FB 0x03 - #define EPNUM_AUDIO_OUT 0x03 #define EPNUM_DEBUG 0x04 -#elif CFG_TUSB_MCU == OPT_MCU_NRF5X - // ISO endpoints for NRF5x are fixed to 0x08 (0x88) +#elif TU_CHECK_MCU(OPT_MCU_NRF5X) + // nRF5x ISO can only be endpoint 8 + #define EPNUM_AUDIO 0x08 #define EPNUM_AUDIO_FB 0x08 - #define EPNUM_AUDIO_OUT 0x08 #define EPNUM_DEBUG 0x01 #elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY) // MCUs that don't support a same endpoint number with different direction IN and OUT defined in tusb_mcu.h // e.g EP1 OUT & EP1 IN cannot exist together + #define EPNUM_AUDIO 0x02 #define EPNUM_AUDIO_FB 0x01 - #define EPNUM_AUDIO_OUT 0x02 #define EPNUM_DEBUG 0x03 #else + #define EPNUM_AUDIO 0x01 #define EPNUM_AUDIO_FB 0x01 - #define EPNUM_AUDIO_OUT 0x01 #define EPNUM_DEBUG 0x02 #endif -uint8_t const desc_configuration_default[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), +#if CFG_AUDIO_DEBUG + #define CONFIG_UAC1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO10_SPEAKER_STEREO_FB_DESC_LEN(2) + TUD_HID_DESC_LEN) +#else + #define CONFIG_UAC1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO10_SPEAKER_STEREO_FB_DESC_LEN(2)) +#endif + +uint8_t const desc_uac1_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC1_TOTAL_LEN, 0x00, 100), - // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size, - TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 4), + // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, sample rates (44.1kHz, 48kHz) + TUD_AUDIO10_SPEAKER_STEREO_FB_DESCRIPTOR(ITF_NUM_AUDIO_CONTROL, 5, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_FS, EPNUM_AUDIO_FB | 0x80, 44100, 48000), #if CFG_AUDIO_DEBUG - // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval - TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) #endif }; -#if CFG_QUIRK_OS_GUESSING -// OS X needs 3 bytes feedback endpoint on FS -uint8_t const desc_configuration_osx_fs[] = -{ - // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), +TU_VERIFY_STATIC(sizeof(desc_uac1_configuration) == CONFIG_UAC1_TOTAL_LEN, "Incorrect size"); - // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size, - TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 3), +#if TUD_OPT_HIGH_SPEED #if CFG_AUDIO_DEBUG - // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval - TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) -#endif -}; + #define CONFIG_UAC2_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO20_SPEAKER_STEREO_FB_DESC_LEN + TUD_HID_DESC_LEN) +#else + #define CONFIG_UAC2_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO20_SPEAKER_STEREO_FB_DESC_LEN) #endif -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void)index; // for multiple configurations +uint8_t const desc_uac2_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_UAC2_TOTAL_LEN, 0x00, 100), -#if CFG_QUIRK_OS_GUESSING - quirk_os_guessing_desc_configuration_cb(); - if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) { - return desc_configuration_osx_fs; - } -#endif - return desc_configuration_default; -} + // Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size, + TUD_AUDIO20_SPEAKER_STEREO_FB_DESCRIPTOR(ITF_NUM_AUDIO_CONTROL, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_HS, EPNUM_AUDIO_FB | 0x80, 4), -//--------------------------------------------------------------------+ -// BOS Descriptor, required for OS guessing quirk -//--------------------------------------------------------------------+ +#if CFG_AUDIO_DEBUG + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7) +#endif +}; -#define TUD_BOS_USB20_EXT_DESC_LEN 7 +TU_VERIFY_STATIC(sizeof(desc_uac2_configuration) == CONFIG_UAC2_TOTAL_LEN, "Incorrect size"); -#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_USB20_EXT_DESC_LEN) +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, -// BOS Descriptor is required for webUSB -uint8_t const desc_bos[] = -{ - // total length, number of device caps - TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1), + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, - // USB 2.0 Extension Descriptor - 0x07, TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_USB20_EXTENSION, 0x00, 0x00, 0x00,0x00 + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 }; -uint8_t const * tud_descriptor_bos_cb(void) -{ -#if CFG_QUIRK_OS_GUESSING - quirk_os_guessing_desc_bos_cb(); +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const *tud_descriptor_device_qualifier_cb(void) { + return (uint8_t const *) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index;// for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_uac1_configuration : desc_uac2_configuration; +} + +#endif // highspeed + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { + (void) index; // for multiple configurations +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + if(tud_speed_get() == TUSB_SPEED_FULL) { + return desc_uac1_configuration; + } else { + return desc_uac2_configuration; + } +#else + return desc_uac1_configuration; #endif - return desc_bos; } //--------------------------------------------------------------------+ @@ -237,6 +244,7 @@ static char const *string_desc_arr[] = "TinyUSB Speaker", // 2: Product NULL, // 3: Serials will use unique ID if possible "UAC2 Speaker", // 4: Audio Interface + "UAC1 Speaker", // 5: UAC1 Audio Interface }; static uint16_t _desc_str[32 + 1]; @@ -247,10 +255,6 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { (void) langid; size_t chr_count; -#if CFG_QUIRK_OS_GUESSING - quirk_os_guessing_desc_string_cb(); -#endif - switch ( index ) { case STRID_LANGID: memcpy(&_desc_str[1], string_desc_arr[0], 2); diff --git a/examples/device/uac2_speaker_fb/src/usb_descriptors.h b/examples/device/uac2_speaker_fb/src/usb_descriptors.h index 9511bf797..b0ec60ea1 100644 --- a/examples/device/uac2_speaker_fb/src/usb_descriptors.h +++ b/examples/device/uac2_speaker_fb/src/usb_descriptors.h @@ -26,57 +26,145 @@ #ifndef _USB_DESCRIPTORS_H_ #define _USB_DESCRIPTORS_H_ -// Defined in TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR +//--------------------------------------------------------------------+ +// UAC2 DESCRIPTOR TEMPLATES +//--------------------------------------------------------------------+ + +// Defined in TUD_AUDIO20_SPEAKER_STEREO_FB_DESCRIPTOR #define UAC2_ENTITY_CLOCK 0x04 #define UAC2_ENTITY_INPUT_TERMINAL 0x01 #define UAC2_ENTITY_FEATURE_UNIT 0x02 #define UAC2_ENTITY_OUTPUT_TERMINAL 0x03 -#define TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) +#define TUD_AUDIO20_SPEAKER_STEREO_FB_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2)\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP_LEN) -#define TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ +#define TUD_AUDIO20_SPEAKER_STEREO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ (AUDIO20_CTRL_RW << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS,/*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ /* 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_MILLISEC, /*_lockdelay*/ 0x0001),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1)\ + TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1) + +//--------------------------------------------------------------------+ +// UAC1 DESCRIPTOR TEMPLATES +//--------------------------------------------------------------------+ + +// Defined in TUD_AUDIO10_SPEAKER_STEREO_FB_DESCRIPTOR +#define UAC1_ENTITY_INPUT_TERMINAL 0x01 +#define UAC1_ENTITY_FEATURE_UNIT 0x02 +#define UAC1_ENTITY_OUTPUT_TERMINAL 0x03 + +#define TUD_AUDIO10_SPEAKER_STEREO_FB_DESC_LEN(_nfreqs) (\ + + TUD_AUDIO10_DESC_STD_AC_LEN\ + + TUD_AUDIO10_DESC_CS_AC_LEN(1)\ + + TUD_AUDIO10_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(2)\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(_nfreqs)\ + + TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO10_DESC_STD_AS_ISO_SYNC_EP_LEN) + +#define TUD_AUDIO10_SPEAKER_STEREO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, ...) \ + /* Standard AC Interface Descriptor(4.3.1) */\ + TUD_AUDIO10_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.3.2) */\ + TUD_AUDIO10_DESC_CS_AC(/*_bcdADC*/ 0x0100, /*_totallen*/ (TUD_AUDIO10_DESC_INPUT_TERM_LEN+TUD_AUDIO10_DESC_OUTPUT_TERM_LEN+TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(2)), /*_itf*/ ((_itfnum)+1)),\ + /* Input Terminal Descriptor(4.3.2.1) */\ + TUD_AUDIO10_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_nchannels*/ 0x02, /*_channelcfg*/ AUDIO10_CHANNEL_CONFIG_LEFT_FRONT | AUDIO10_CHANNEL_CONFIG_RIGHT_FRONT, /*_idxchannelnames*/ 0x00, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.3.2.2) */\ + TUD_AUDIO10_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ 0x02, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.3.2.5) */\ + TUD_AUDIO10_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlmaster*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME), /*_ctrlch1*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME), /*_ctrlch2*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME)),\ + /* Standard AS Interface Descriptor(4.5.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.5.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.5.2) */\ + TUD_AUDIO10_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_delay*/ 0x00, /*_formattype*/ AUDIO10_DATA_FORMAT_TYPE_I_PCM),\ + /* Type I Format Type Descriptor(2.2.5) */\ + TUD_AUDIO10_DESC_TYPE_I_FORMAT(/*_nrchannels*/ 0x02, /*_subframesize*/ _nBytesPerSample, /*_bitresolution*/ _nBitsUsedPerSample, /*_freqs*/ __VA_ARGS__),\ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.6.1.1) */\ + TUD_AUDIO10_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01, /*_sync_ep*/ _epfb),\ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.6.1.2) */\ + 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_UNDEFINED, /*_lockdelay*/ 0x0000),\ + /* Standard AS Isochronous Synch Endpoint Descriptor (4.6.2.1) */\ + TUD_AUDIO10_DESC_STD_AS_ISO_SYNC_EP(/*_ep*/ _epfb, /*_bRefresh*/ 0) + +//---------------------------------------------------------------------------+ +// UAC1 Isochronous Synch Endpoint bRefresh Workaround +// +// bRefresh value is set to 0, while UAC1 spec requires it to be between +// 1 (2 ms) and 9 (512 ms) +// +// This value has been tested to work with Windows, macOS and Linux. +// +// Rationale: +// Some USB device controllers (e.g. Synopsys DWC2) require a known transfer +// interval to manually schedule isochronous IN transfers. For data isochronous +// endpoints, the bInterval field in the endpoint descriptor is used. However, +// for synch endpoint it's unclear which field the host uses to determine the +// transfer interval. Windows and macOS use bRefresh, while Linux uses bInterval. +// +// Since bInterval is fixed to 1, if bRefresh is set to 2 then Windows and macOS +// will schedule the feedback transfer every 4 ms, but Linux will schedule it +// every 1 ms. DWC2 controller cannot handle this discrepancy without knwowing +// the actual interval, therefore we set bRefresh to 0 to let the transfer +// execute every 1 ms, which is the same as bInterval. +// +// Rant: +// WTF USB-IF? Why have two fields that mean the same thing? Why not just use +// bInterval for both data and synch endpoints? Why is bRefresh even necessary? +// +// Note: +// For the moment DWC2 driver doesn't have proper support for bInterval > 1 +// for isochronous IN endpoints. The implementation would be complex and CPU +// intensive (cfr. +// https://github.com/torvalds/linux/blob/master/drivers/usb/dwc2/gadget.c) +// It MAY work in some cases if you are lucky, but it's not guaranteed. +//---------------------------------------------------------------------------+ #endif diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c index 5dab2bed0..a41de2769 100644 --- a/examples/host/cdc_msc_hid_freertos/src/main.c +++ b/examples/host/cdc_msc_hid_freertos/src/main.c @@ -35,7 +35,7 @@ #define USBH_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled - #define USBH_STACK_SIZE (3*configMINIMAL_STACK_SIZE/2) * (CFG_TUSB_DEBUG ? 2 : 1) + #define USBH_STACK_SIZE (configMINIMAL_STACK_SIZE * (CFG_TUSB_DEBUG ? 4 : 2)) #endif diff --git a/hw/bsp/lpc17/family.cmake b/hw/bsp/lpc17/family.cmake index 92bcbff21..919b8f3bc 100644 --- a/hw/bsp/lpc17/family.cmake +++ b/hw/bsp/lpc17/family.cmake @@ -69,7 +69,6 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/nxp/lpc17_40/dcd_lpc17_40.c - ${TOP}/src/portable/nxp/lpc17_40/hcd_lpc17_40.c ${TOP}/src/portable/ohci/ohci.c ) diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk index e8d707ea5..f1ed1a7d0 100644 --- a/hw/bsp/lpc17/family.mk +++ b/hw/bsp/lpc17/family.mk @@ -20,7 +20,6 @@ LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs SRC_C += \ src/portable/nxp/lpc17_40/dcd_lpc17_40.c \ - src/portable/nxp/lpc17_40/hcd_lpc17_40.c \ src/portable/ohci/ohci.c \ $(MCU_DIR)/../gcc/cr_startup_lpc175x_6x.c \ $(MCU_DIR)/src/chip_17xx_40xx.c \ diff --git a/hw/bsp/lpc40/family.cmake b/hw/bsp/lpc40/family.cmake index 211846444..01430bbb1 100644 --- a/hw/bsp/lpc40/family.cmake +++ b/hw/bsp/lpc40/family.cmake @@ -70,7 +70,6 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/nxp/lpc17_40/dcd_lpc17_40.c - ${TOP}/src/portable/nxp/lpc17_40/hcd_lpc17_40.c ${TOP}/src/portable/ohci/ohci.c ) diff --git a/hw/bsp/lpc40/family.mk b/hw/bsp/lpc40/family.mk index c72631235..c21923000 100644 --- a/hw/bsp/lpc40/family.mk +++ b/hw/bsp/lpc40/family.mk @@ -18,7 +18,6 @@ LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs # All source paths should be relative to the top level. SRC_C += \ src/portable/nxp/lpc17_40/dcd_lpc17_40.c \ - src/portable/nxp/lpc17_40/hcd_lpc17_40.c \ src/portable/ohci/ohci.c \ $(MCU_DIR)/../gcc/cr_startup_lpc40xx.c \ $(MCU_DIR)/src/chip_17xx_40xx.c \ diff --git a/hw/bsp/lpc55/boards/double_m33_express/board.cmake b/hw/bsp/lpc55/boards/double_m33_express/board.cmake index 3324ce888..186655b5a 100644 --- a/hw/bsp/lpc55/boards/double_m33_express/board.cmake +++ b/hw/bsp/lpc55/boards/double_m33_express/board.cmake @@ -7,11 +7,6 @@ set(NXPLINK_DEVICE LPC55S69:LPCXpresso55S69) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/LPC55S69_cm33_core0_uf2.ld) -# Device port default to PORT1 Highspeed -if (NOT DEFINED PORT) - set(PORT 1) -endif() - function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC CPU_LPC55S69JBD100_cm33_core0 diff --git a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake index b3d0c3349..d935b70e6 100644 --- a/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake +++ b/hw/bsp/lpc55/boards/lpcxpresso55s28/board.cmake @@ -5,11 +5,6 @@ set(JLINK_DEVICE LPC55S28) set(PYOCD_TARGET LPC55S28) set(NXPLINK_DEVICE LPC55S28:LPCXpresso55S28) -# Device port default to PORT1 Highspeed -if (NOT DEFINED PORT) - set(PORT 1) -endif() - function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC CPU_LPC55S28JBD100 diff --git a/hw/bsp/lpc55/boards/lpcxpresso55s69/board.cmake b/hw/bsp/lpc55/boards/lpcxpresso55s69/board.cmake index b52ec2f9d..f46775b27 100644 --- a/hw/bsp/lpc55/boards/lpcxpresso55s69/board.cmake +++ b/hw/bsp/lpc55/boards/lpcxpresso55s69/board.cmake @@ -5,11 +5,6 @@ set(JLINK_DEVICE LPC55S69_M33_0) set(PYOCD_TARGET LPC55S69) set(NXPLINK_DEVICE LPC55S69:LPCXpresso55S69) -# Device port default to PORT1 Highspeed -if (NOT DEFINED PORT) - set(PORT 1) -endif() - function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC CPU_LPC55S69JBD100_cm33_core0 diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c index f0ded96a7..f1ef58926 100644 --- a/hw/bsp/lpc55/family.c +++ b/hw/bsp/lpc55/family.c @@ -55,6 +55,7 @@ #define IOCON_PIO_MODE_INACT 0x00u // No addition pin function #define IOCON_PIO_OPENDRAIN_DI 0x00u // Open drain is disabled #define IOCON_PIO_SLEW_STANDARD 0x00u // Standard mode, output slew rate control is enabled +#define IOCON_PIO_MODE_PULLUP 0x20u /*!<@brief Selects pull-up function */ #define IOCON_PIO_DIG_FUNC0_EN (IOCON_PIO_DIGITAL_EN | IOCON_PIO_FUNC0) // Digital pin function 0 enabled #define IOCON_PIO_DIG_FUNC1_EN (IOCON_PIO_DIGITAL_EN | IOCON_PIO_FUNC1) // Digital pin function 1 enabled @@ -197,13 +198,14 @@ void board_init(void) { USART_Init(UART_DEV, &uart_config, 12000000); #endif - // USB VBUS +#if (CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 0) || (CFG_TUH_ENABLED && BOARD_TUH_RHPORT == 0) /* PORT0 PIN22 configured as USB0_VBUS */ IOCON_PinMuxSet(IOCON, 0U, 22U, IOCON_PIO_DIG_FUNC7_EN); - -#if defined(BOARD_TUD_RHPORT) && BOARD_TUD_RHPORT == 0 // Port0 is Full Speed + NVIC_ClearPendingIRQ(USB0_IRQn); + NVIC_ClearPendingIRQ(USB0_NEEDCLK_IRQn); + /* Turn on USB0 Phy */ POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); @@ -212,21 +214,55 @@ void board_init(void) { RESET_PeripheralReset(kUSB0HSL_RST_SHIFT_RSTn); RESET_PeripheralReset(kUSB0HMR_RST_SHIFT_RSTn); - // Enable USB Clock Adjustments to trim the FRO for the full speed controller - ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_USBCLKADJ_MASK; - CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false); - CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); + if (CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 0) { + // Enable USB Clock Adjustments to trim the FRO for the full speed controller + ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_USBCLKADJ_MASK; + CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1, false); + CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); + + /*According to reference manual, device mode setting has to be set by access usb host register */ + CLOCK_EnableClock(kCLOCK_Usbhsl0); // enable usb0 host clock + USBFSH->PORTMODE |= USBFSH_PORTMODE_DEV_ENABLE_MASK; + CLOCK_DisableClock(kCLOCK_Usbhsl0); // disable usb0 host clock + /* enable USB Device clock */ + CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbfsSrcFro, CLOCK_GetFreq(kCLOCK_FroHf)); + } else { + const uint32_t port1_pin12_config = (/* Pin is configured as USB0_PORTPWRN */ + IOCON_PIO_FUNC4 | + /* Selects pull-up function */ + IOCON_PIO_MODE_PULLUP | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT1 PIN12 (coords: 67) is configured as USB0_PORTPWRN */ + IOCON_PinMuxSet(IOCON, 1U, 12U, port1_pin12_config); - /*According to reference manual, device mode setting has to be set by access usb host register */ - CLOCK_EnableClock(kCLOCK_Usbhsl0); // enable usb0 host clock - USBFSH->PORTMODE |= USBFSH_PORTMODE_DEV_ENABLE_MASK; - CLOCK_DisableClock(kCLOCK_Usbhsl0); // disable usb0 host clock + const uint32_t port0_pin28_config = (/* Pin is configured as USB0_OVERCURRENTN */ + IOCON_PIO_FUNC7 | + /* Selects pull-up function */ + IOCON_PIO_MODE_PULLUP | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN28 (coords: 66) is configured as USB0_OVERCURRENTN */ + IOCON_PinMuxSet(IOCON, 0U, 28U, port0_pin28_config); - /* enable USB Device clock */ - CLOCK_EnableUsbfs0DeviceClock(kCLOCK_UsbfsSrcFro, CLOCK_GetFreq(kCLOCK_FroHf)); + CLOCK_EnableUsbfs0HostClock(kCLOCK_UsbfsSrcPll1, 48000000U); + USBFSH->PORTMODE &= ~USBFSH_PORTMODE_DEV_ENABLE_MASK; + } #endif -#if defined(BOARD_TUD_RHPORT) && BOARD_TUD_RHPORT == 1 +#if (CFG_TUD_ENABLED && BOARD_TUD_RHPORT == 1) || (CFG_TUH_ENABLED && BOARD_TUH_RHPORT == 1) // Port1 is High Speed /* Turn on USB1 Phy */ @@ -266,9 +302,9 @@ void board_init(void) { // phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06); // USBPHY->TX = phytx; - ARM_MPU_SetMemAttr(0, 0x44); // Normal memory, non-cacheable (inner and outer) - ARM_MPU_SetRegion(0, ARM_MPU_RBAR(0x40100000, ARM_MPU_SH_NON, 0, 1, 1), ARM_MPU_RLAR(0x40104000, 0)); - ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk); + ARM_MPU_SetMemAttr(0, 0x44); // Normal memory, non-cacheable (inner and outer) + ARM_MPU_SetRegion(0, ARM_MPU_RBAR(0x40100000, ARM_MPU_SH_NON, 0, 1, 1), ARM_MPU_RLAR(0x40104000, 0)); + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk); #endif } diff --git a/hw/bsp/lpc55/family.cmake b/hw/bsp/lpc55/family.cmake index 3477d9f10..1f18f9bad 100644 --- a/hw/bsp/lpc55/family.cmake +++ b/hw/bsp/lpc55/family.cmake @@ -12,22 +12,40 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOL set(FAMILY_MCUS LPC55 CACHE INTERNAL "") -if (NOT DEFINED PORT) - set(PORT 0) -endif() +# ---------------------- +# Port & Speed Selection +# ---------------------- -# Host port will be the other port if available -set(HOST_PORT $<NOT:${PORT}>) +# default device port to USB1 highspeed, host to USB0 fullspeed +if (NOT DEFINED RHPORT_DEVICE) + set(RHPORT_DEVICE 1) +endif () +if (NOT DEFINED RHPORT_HOST) + set(RHPORT_HOST 0) +endif () + +# port 0 is fullspeed, port 1 is highspeed +set(RHPORT_SPEED OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED) + +if (NOT DEFINED RHPORT_DEVICE_SPEED) + list(GET RHPORT_SPEED ${RHPORT_DEVICE} RHPORT_DEVICE_SPEED) +endif () +if (NOT DEFINED RHPORT_HOST_SPEED) + list(GET RHPORT_SPEED ${RHPORT_HOST} RHPORT_HOST_SPEED) +endif () + +cmake_print_variables(RHPORT_DEVICE RHPORT_DEVICE_SPEED RHPORT_HOST RHPORT_HOST_SPEED) #------------------------------------ # Startup & Linker script #------------------------------------ if (NOT DEFINED LD_FILE_GNU) -set(LD_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_CORE}_flash.ld) + set(LD_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/${MCU_CORE}_flash.ld) endif () set(LD_FILE_Clang ${LD_FILE_GNU}) + if (NOT DEFINED STARTUP_FILE_GNU) -set(STARTUP_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_CORE}.S) + set(STARTUP_FILE_GNU ${SDK_DIR}/devices/${MCU_VARIANT}/gcc/startup_${MCU_CORE}.S) endif () set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) @@ -63,22 +81,20 @@ function(family_add_board BOARD_TARGET) ) target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUSB_MEM_ALIGN=TU_ATTR_ALIGNED\(64\) - BOARD_TUD_RHPORT=${PORT} - BOARD_TUH_RHPORT=${HOST_PORT} + BOARD_TUD_RHPORT=${RHPORT_DEVICE} + BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} + BOARD_TUH_RHPORT=${RHPORT_HOST} + BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} __STARTUP_CLEAR_BSS ) # Port 0 is Fullspeed, Port 1 is Highspeed. Port1 controller can only access USB_SRAM - if (PORT EQUAL 1) + if (RHPORT_DEVICE EQUAL 1) target_compile_definitions(${BOARD_TARGET} PUBLIC - BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED - BOARD_TUH_MAX_SPEED=OPT_MODE_FULL_SPEED CFG_TUD_MEM_SECTION=__attribute__\(\(section\(\"m_usb_global\"\)\)\) ) - else () + elseif (RHPORT_HOST EQUAL 1) target_compile_definitions(${BOARD_TARGET} PUBLIC - BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED - BOARD_TUH_MAX_SPEED=OPT_MODE_HIGH_SPEED CFG_TUH_MEM_SECTION=__attribute__\(\(section\(\"m_usb_global\"\)\)\) ) endif () @@ -98,6 +114,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/lib/sct_neopixel/sct_neopixel.c ${TOP}/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c + ${TOP}/src/portable/ohci/ohci.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake index aae820aee..7b3456585 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake +++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake @@ -1,5 +1,5 @@ set(MCU_VARIANT stm32h7s3xx) -set(JLINK_DEVICE stm32h7s3xx) +set(JLINK_DEVICE stm32h7s3l8) set(LD_FILE_Clang ${LD_FILE_GNU}) diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk index 47055a108..40b15bc0e 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk +++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk @@ -2,7 +2,7 @@ MCU_VARIANT = stm32h7s3xx CFLAGS += -DSTM32H7S3xx # For flash-jlink target -JLINK_DEVICE = stm32h7s3xx +JLINK_DEVICE = stm32h7s3l8 # flash target using on-board stlink flash: flash-stlink diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index fc352a1af..47d25dd81 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -39,917 +39,1255 @@ extern "C" { #endif -/// Audio Device Class Codes +//--------------------------------------------------------------------+ +// GENERIC AUDIO CLASS CODES (COMMON TO UAC1 AND UAC2) +//--------------------------------------------------------------------+ /// A.2 - Audio Function Subclass Codes -typedef enum -{ +typedef enum { AUDIO_FUNCTION_SUBCLASS_UNDEFINED = 0x00, } audio_function_subclass_type_t; /// A.3 - Audio Function Protocol Codes -typedef enum -{ - AUDIO_FUNC_PROTOCOL_CODE_UNDEF = 0x00, - AUDIO_FUNC_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +typedef enum { + AUDIO_FUNC_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_FUNC_PROTOCOL_CODE_V1 = 0x00,///< Version 1.0 - same as undefined for backward compatibility + AUDIO_FUNC_PROTOCOL_CODE_V2 = 0x20,///< Version 2.0 } audio_function_protocol_code_t; /// A.5 - Audio Interface Subclass Codes -typedef enum -{ +typedef enum { AUDIO_SUBCLASS_UNDEFINED = 0x00, - AUDIO_SUBCLASS_CONTROL , ///< Audio Control - AUDIO_SUBCLASS_STREAMING , ///< Audio Streaming - AUDIO_SUBCLASS_MIDI_STREAMING , ///< MIDI Streaming + AUDIO_SUBCLASS_CONTROL, ///< Audio Control + AUDIO_SUBCLASS_STREAMING, ///< Audio Streaming + AUDIO_SUBCLASS_MIDI_STREAMING,///< MIDI Streaming } audio_subclass_type_t; /// A.6 - Audio Interface Protocol Codes -typedef enum -{ - AUDIO_INT_PROTOCOL_CODE_UNDEF = 0x00, - AUDIO_INT_PROTOCOL_CODE_V2 = 0x20, ///< Version 2.0 +typedef enum { + AUDIO_INT_PROTOCOL_CODE_UNDEF = 0x00, + AUDIO_INT_PROTOCOL_CODE_V1 = 0x00,///< Version 1.0 - same as undefined for backward compatibility + AUDIO_INT_PROTOCOL_CODE_V2 = 0x20,///< Version 2.0 } audio_interface_protocol_code_t; +/// Terminal Types + +/// 2.1 - Audio Class-Terminal Types +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 +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 +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 + +//--------------------------------------------------------------------+ +// USB AUDIO CLASS 1.0 (UAC1) DEFINITIONS +//--------------------------------------------------------------------+ + +/// A.5 - Audio Class-Specific AC Interface Descriptor Subtypes UAC1 +typedef enum { + AUDIO10_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, + AUDIO10_CS_AC_INTERFACE_HEADER = 0x01, + AUDIO10_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, + AUDIO10_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, + AUDIO10_CS_AC_INTERFACE_MIXER_UNIT = 0x04, + AUDIO10_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, + AUDIO10_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, + AUDIO10_CS_AC_INTERFACE_PROCESSING_UNIT = 0x07, + AUDIO10_CS_AC_INTERFACE_EXTENSION_UNIT = 0x08, +} audio10_cs_ac_interface_subtype_t; + +/// A.6 - Audio Class-Specific AS Interface Descriptor Subtypes UAC1 +typedef enum { + AUDIO10_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, + AUDIO10_CS_AS_INTERFACE_AS_GENERAL = 0x01, + AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, +} audio10_cs_as_interface_subtype_t; + +/// A.8 - Audio Class-Specific EP Descriptor Subtypes UAC1 +typedef enum { + AUDIO10_CS_EP_SUBTYPE_UNDEF = 0x00, + AUDIO10_CS_EP_SUBTYPE_GENERAL = 0x01, +} audio10_cs_ep_subtype_t; + +/// A.9 - Audio Class-Specific Request Codes UAC1 +typedef enum { + AUDIO10_CS_REQ_UNDEF = 0x00, + AUDIO10_CS_REQ_SET_CUR = 0x01, + AUDIO10_CS_REQ_GET_CUR = 0x81, + AUDIO10_CS_REQ_SET_MIN = 0x02, + AUDIO10_CS_REQ_GET_MIN = 0x82, + AUDIO10_CS_REQ_SET_MAX = 0x03, + AUDIO10_CS_REQ_GET_MAX = 0x83, + AUDIO10_CS_REQ_SET_RES = 0x04, + AUDIO10_CS_REQ_GET_RES = 0x84, + AUDIO10_CS_REQ_SET_MEM = 0x05, + AUDIO10_CS_REQ_GET_MEM = 0x85, + AUDIO10_CS_REQ_GET_STAT = 0xFF, +} audio10_cs_req_t; + +/// A.10.1 - Terminal Control Selectors UAC1 +typedef enum { + AUDIO10_TE_CTRL_UNDEF = 0x00, + AUDIO10_TE_CTRL_COPY_PROTECT = 0x01, +} audio10_terminal_control_selector_t; + +/// A.10.2 - Feature Unit Control Selectors UAC1 +typedef enum { + AUDIO10_FU_CTRL_UNDEF = 0x00, + AUDIO10_FU_CTRL_MUTE = 0x01, + AUDIO10_FU_CTRL_VOLUME = 0x02, + AUDIO10_FU_CTRL_BASS = 0x03, + AUDIO10_FU_CTRL_MID = 0x04, + AUDIO10_FU_CTRL_TREBLE = 0x05, + AUDIO10_FU_CTRL_GRAPHIC_EQUALIZER = 0x06, + AUDIO10_FU_CTRL_AGC = 0x07, + AUDIO10_FU_CTRL_DELAY = 0x08, + AUDIO10_FU_CTRL_BASS_BOOST = 0x09, + AUDIO10_FU_CTRL_LOUDNESS = 0x0A, +} audio10_feature_unit_control_selector_t; + +/// A.10.3.1 - Up/Down-mix Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_UD_CTRL_UNDEF = 0x00, + AUDIO10_UD_CTRL_ENABLE = 0x01, + AUDIO10_UD_CTRL_MODE_SELECT = 0x02, +} audio10_up_down_mix_control_selector_t; + +/// A.10.3.2 - Dolby Prologic Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_DP_CTRL_UNDEF = 0x00, + AUDIO10_DP_CTRL_ENABLE = 0x01, + AUDIO10_DP_CTRL_MODE_SELECT = 0x02, +} audio10_dolby_prologic_control_selector_t; + +/// A.10.3.3 - 3D Stereo Extender Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_3D_CTRL_UNDEF = 0x00, + AUDIO10_3D_CTRL_ENABLE = 0x01, + AUDIO10_3D_CTRL_SPACIOUSNESS = 0x02, +} audio10_3d_stereo_extender_control_selector_t; + +/// A.10.3.4 - Reverberation Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_RV_CTRL_UNDEF = 0x00, + AUDIO10_RV_CTRL_ENABLE = 0x01, + AUDIO10_RV_CTRL_REVERB_LEVEL = 0x02, + AUDIO10_RV_CTRL_REVERB_TIME = 0x03, + AUDIO10_RV_CTRL_REVERB_FEEDBACK = 0x04, +} audio10_reverberation_control_selector_t; + +/// A.10.3.5 - Chorus Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_CH_CTRL_UNDEF = 0x00, + AUDIO10_CH_CTRL_ENABLE = 0x01, + AUDIO10_CH_CTRL_CHORUS_LEVEL = 0x02, + AUDIO10_CH_CTRL_CHORUS_RATE = 0x03, + AUDIO10_CH_CTRL_CHORUS_DEPTH = 0x04, +} audio10_chorus_control_selector_t; + +/// A.10.3.6 - Dynamic Range Compressor Processing Unit Control Selectors UAC1 +typedef enum { + AUDIO10_DR_CTRL_UNDEF = 0x00, + AUDIO10_DR_CTRL_ENABLE = 0x01, + AUDIO10_DR_CTRL_COMPRESSION_RATE = 0x02, + AUDIO10_DR_CTRL_MAXAMPL = 0x03, + AUDIO10_DR_CTRL_THRESHOLD = 0x04, + AUDIO10_DR_CTRL_ATTACK_TIME = 0x05, + AUDIO10_DR_CTRL_RELEASE_TIME = 0x06, +} audio10_dynamic_range_compression_control_selector_t; + +/// A.10.4 - Extension Unit Control Selectors UAC1 +typedef enum { + AUDIO10_XU_CTRL_UNDEF = 0x00, + AUDIO10_XU_CTRL_ENABLE = 0x01, +} audio10_extension_unit_control_selector_t; + +/// A.10.5 - Endpoint Control Selectors UAC1 +typedef enum { + AUDIO10_EP_CTRL_UNDEF = 0x00, + AUDIO10_EP_CTRL_SAMPLING_FREQ = 0x01, + AUDIO10_EP_CTRL_PITCH = 0x02, +} audio10_ep_control_selector_t; + +/// Audio Class-Specific AS Isochronous Data EP Attributes UAC1 +typedef enum { + AUDIO10_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, + AUDIO10_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, + AUDIO10_CS_AS_ISO_DATA_EP_ATT_SAMPLING_FRQ = 0x01, + AUDIO10_CS_AS_ISO_DATA_EP_ATT_PITCH = 0x02, +} audio10_cs_as_iso_data_ep_attribute_t; + +/// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC1 +typedef enum { + AUDIO10_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, + AUDIO10_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, + AUDIO10_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, +} audio10_cs_as_iso_data_ep_lock_delay_unit_t; + +/// Audio Class-Feature Unit Controls UAC1 +typedef enum { + AUDIO10_FU_CONTROL_BM_MUTE = 1 << 0, + AUDIO10_FU_CONTROL_BM_VOLUME = 1 << 1, + AUDIO10_FU_CONTROL_BM_BASS = 1 << 2, + AUDIO10_FU_CONTROL_BM_MID = 1 << 3, + AUDIO10_FU_CONTROL_BM_TREBLE = 1 << 4, + AUDIO10_FU_CONTROL_BM_GRAPHIC_EQUALIZER = 1 << 5, + AUDIO10_FU_CONTROL_BM_AGC = 1 << 6, + AUDIO10_FU_CONTROL_BM_DELAY = 1 << 7, + AUDIO10_FU_CONTROL_BM_BASS_BOOST = 1 << 8, + AUDIO10_FU_CONTROL_BM_LOUDNESS = 1 << 9, +} audio10_feature_unit_control_bitmap_t; + +/// A.1 - Audio Class-Format Type Codes UAC1 +typedef enum { + AUDIO10_FORMAT_TYPE_UNDEFINED = 0x00, + AUDIO10_FORMAT_TYPE_I = 0x01, + AUDIO10_FORMAT_TYPE_II = 0x02, + AUDIO10_FORMAT_TYPE_III = 0x03, +} audio10_format_type_t; + +// A.1.1 - Audio Class-Audio Data Format Type I UAC1 +typedef enum { + AUDIO10_DATA_FORMAT_TYPE_I_PCM = 0x0001, + AUDIO10_DATA_FORMAT_TYPE_I_PCM8 = 0x0002, + AUDIO10_DATA_FORMAT_TYPE_I_IEEE_FLOAT = 0x0003, + AUDIO10_DATA_FORMAT_TYPE_I_ALAW = 0x0004, + AUDIO10_DATA_FORMAT_TYPE_I_MULAW = 0x0005, +} audio10_data_format_type_I_t; + +// A.1.2 - Audio Class-Audio Data Format Type II UAC1 +typedef enum { + AUDIO10_DATA_FORMAT_TYPE_II_MPEG = 0x1001, + AUDIO10_DATA_FORMAT_TYPE_II_AC3 = 0x1002, +} audio10_data_format_type_II_t; + +// A.1.3 - Audio Class-Audio Data Format Type III UAC1 +typedef enum { + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_AC3_1 = 0x2001, + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_MPEG1_L1_1 = 0x2002, + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_MPEG1_L23_1 = 0x2003, + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_MPEG2_EXT_1 = 0x2004, + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_MPEG2_L1_LS_1 = 0x2005, + AUDIO10_DATA_FORMAT_TYPE_III_IEC1937_MPEG2_L23_LS_1 = 0x2006, +} audio10_data_format_type_III_t; + +/// Audio Class-Audio Channel Configuration UAC1 (Table A-7) +typedef enum { + AUDIO10_CHANNEL_CONFIG_NON_PREDEFINED = 0x0000, + AUDIO10_CHANNEL_CONFIG_LEFT_FRONT = 0x0001, + AUDIO10_CHANNEL_CONFIG_RIGHT_FRONT = 0x0002, + AUDIO10_CHANNEL_CONFIG_CENTER_FRONT = 0x0004, + AUDIO10_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x0008, + AUDIO10_CHANNEL_CONFIG_LEFT_SURROUND = 0x0010, + AUDIO10_CHANNEL_CONFIG_RIGHT_SURROUND = 0x0020, + AUDIO10_CHANNEL_CONFIG_LEFT_OF_CENTER = 0x0040, + AUDIO10_CHANNEL_CONFIG_RIGHT_OF_CENTER = 0x0080, + AUDIO10_CHANNEL_CONFIG_SURROUND = 0x0100, + AUDIO10_CHANNEL_CONFIG_SIDE_LEFT = 0x0200, + AUDIO10_CHANNEL_CONFIG_SIDE_RIGHT = 0x0400, + AUDIO10_CHANNEL_CONFIG_TOP = 0x0800, +} audio10_channel_config_t; + + +//--------------------------------------------------------------------+ +// USB AUDIO CLASS 1.0 (UAC1) DESCRIPTORS +//--------------------------------------------------------------------+ + +/// AUDIO Class-Specific AC Interface Header Descriptor UAC1 (4.3.2) +#define audio10_desc_cs_ac_interface_n_t(numInterfaces) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 8+n. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_HEADER. */ \ + uint16_t bcdADC; /* Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: 0x0100 for UAC1. */ \ + uint16_t wTotalLength; /* Total number of bytes returned for the class-specific AudioControl interface descriptor. */ \ + uint8_t bInCollection; /* The number of AudioStreaming and MIDIStreaming interfaces in the Audio Interface Collection. */ \ + uint8_t baInterfaceNr[numInterfaces]; /* Interface number of the AudioStreaming or MIDIStreaming interface in the Collection. */ \ + } + +/// AUDIO Input Terminal Descriptor UAC1 (4.3.2.1) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 12. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_INPUT_TERMINAL. + uint8_t bTerminalID; ///< Constant uniquely identifying the Terminal within the audio function. + uint16_t wTerminalType; ///< Constant characterizing the type of Terminal. + uint8_t bAssocTerminal; ///< ID of the Output Terminal to which this Input Terminal is associated. + uint8_t bNrChannels; ///< Number of logical output channels in the Terminal's output audio channel cluster. + uint16_t wChannelConfig; ///< Describes the spatial location of the logical channels. + uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first logical channel. + uint8_t iTerminal; ///< Index of a string descriptor, describing the Input Terminal. +} audio10_desc_input_terminal_t; + +/// AUDIO Output Terminal Descriptor UAC1 (4.3.2.2) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 9. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_OUTPUT_TERMINAL. + uint8_t bTerminalID; ///< Constant uniquely identifying the Terminal within the audio function. + uint16_t wTerminalType; ///< Constant characterizing the type of Terminal. + uint8_t bAssocTerminal; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. + uint8_t bSourceID; ///< ID of the Unit or Terminal to which this Terminal is connected. + uint8_t iTerminal; ///< Index of a string descriptor, describing the Output Terminal. +} audio10_desc_output_terminal_t; + +/// AUDIO Mixer Unit Descriptor UAC1 (4.3.2.3) +#define audio10_desc_mixer_unit_n_t(numInputPins, numControlBytes) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 10+p+n. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_MIXER_UNIT. */ \ + uint8_t bUnitID; /* Constant uniquely identifying the Unit within the audio function. */ \ + uint8_t bNrInPins; /* Number of Input Pins of this Unit: p. */ \ + uint8_t baSourceID[numInputPins]; /* ID of the Unit or Terminal to which Input Pins of this Mixer Unit are connected. */ \ + uint8_t bNrChannels; /* Number of logical output channels in the Mixer Unit's output audio channel cluster. */ \ + uint16_t wChannelConfig; /* Describes the spatial location of the logical channels. */ \ + uint8_t iChannelNames; /* Index of a string descriptor, describing the name of the first logical channel. */ \ + uint8_t bmControls[numControlBytes]; /* Mixer Unit Controls bitmap. */ \ + uint8_t iMixer; /* Index of a string descriptor, describing the Mixer Unit. */ \ + } + +/// AUDIO Selector Unit Descriptor UAC1 (4.3.2.4) +#define audio10_desc_selector_unit_n_t(numInputPins) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 6+p. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_SELECTOR_UNIT. */ \ + uint8_t bUnitID; /* Constant uniquely identifying the Unit within the audio function. */ \ + uint8_t bNrInPins; /* Number of Input Pins of this Unit: p. */ \ + uint8_t baSourceID[numInputPins]; /* ID of the Unit or Terminal to which Input Pins of this Selector Unit are connected. */ \ + uint8_t iSelector; /* Index of a string descriptor, describing the Selector Unit. */ \ + } + +/// AUDIO Feature Unit Descriptor UAC1 (4.3.2.5) +#define audio10_desc_feature_unit_n_t(numChannels, controlSize) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 7+(ch+1)*n. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_FEATURE_UNIT. */ \ + uint8_t bUnitID; /* Constant uniquely identifying the Unit within the audio function. */ \ + uint8_t bSourceID; /* ID of the Unit or Terminal to which this Feature Unit is connected. */ \ + uint8_t bControlSize; /* Size in bytes of an element of the bmaControls() array. */ \ + uint8_t bmaControls[(numChannels + 1) * controlSize]; /* Control bitmaps for master + logical channels. */ \ + uint8_t iFeature; /* Index of a string descriptor, describing this Feature Unit. */ \ + } + +/// AUDIO Processing Unit Descriptor UAC1 (4.3.2.6) +#define audio10_desc_processing_unit_n_t(numInputPins, numControlBytes) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 13+p+n. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_PROCESSING_UNIT. */ \ + uint8_t bUnitID; /* Constant uniquely identifying the Unit within the audio function. */ \ + uint16_t wProcessType; /* Constant identifying the type of processing this Unit is performing. */ \ + uint8_t bNrInPins; /* Number of Input Pins of this Unit: p. */ \ + uint8_t baSourceID[numInputPins]; /* ID of the Unit or Terminal to which Input Pins of this Processing Unit are connected. */ \ + uint8_t bNrChannels; /* Number of logical output channels in the Processing Unit's output audio channel cluster. */ \ + uint16_t wChannelConfig; /* Describes the spatial location of the logical channels. */ \ + uint8_t iChannelNames; /* Index of a string descriptor, describing the name of the first logical channel. */ \ + uint8_t bControlSize; /* Size in bytes of the bmControls field. */ \ + uint8_t bmControls[numControlBytes]; /* Processing Unit Controls bitmap. */ \ + uint8_t iProcessing; /* Index of a string descriptor, describing the Processing Unit. */ \ + } + +/// AUDIO Extension Unit Descriptor UAC1 (4.3.2.7) +#define audio10_desc_extension_unit_n_t(numInputPins, numControlBytes) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 13+p+n. */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AC_INTERFACE_EXTENSION_UNIT. */ \ + uint8_t bUnitID; /* Constant uniquely identifying the Unit within the audio function. */ \ + uint16_t wExtensionCode; /* Vendor-specific code identifying the Extension Unit. */ \ + uint8_t bNrInPins; /* Number of Input Pins of this Unit: p. */ \ + uint8_t baSourceID[numInputPins]; /* ID of the Unit or Terminal to which Input Pins of this Extension Unit are connected. */ \ + uint8_t bNrChannels; /* Number of logical output channels in the Extension Unit's output audio channel cluster. */ \ + uint16_t wChannelConfig; /* Describes the spatial location of the logical channels. */ \ + uint8_t iChannelNames; /* Index of a string descriptor, describing the name of the first logical channel. */ \ + uint8_t bControlSize; /* Size in bytes of the bmControls field. */ \ + uint8_t bmControls[numControlBytes]; /* Extension Unit Controls bitmap. */ \ + uint8_t iExtension; /* Index of a string descriptor, describing the Extension Unit. */ \ + } + +/// AUDIO Class-Specific AS Interface Descriptor UAC1 (4.5.2) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 7. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO10_CS_AS_INTERFACE_AS_GENERAL. + uint8_t bTerminalLink; ///< The Terminal ID of the Terminal to which the endpoint of this interface is connected. + uint8_t bDelay; ///< Expressed in number of frames. + uint16_t wFormatTag; ///< The Audio Data Format that has to be used to communicate with this interface. +} audio10_desc_cs_as_interface_t; + +/// AUDIO Type I Format Type Descriptor UAC1 (2.2.5) +#define audio10_desc_type_I_format_n_t(numSamFreq) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 8+(ns*3). */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE. */ \ + uint8_t bFormatType; /* Constant identifying the Format Type the AudioStreaming interface is using. */ \ + uint8_t bNrChannels; /* Indicates the number of physical channels in the audio data stream. */ \ + uint8_t bSubFrameSize; /* The number of bytes occupied by one audio subframe. */ \ + uint8_t bBitResolution; /* The number of effectively used bits from the available bits in an audio subframe. */ \ + uint8_t bSamFreqType; /* Indicates how the sampling frequency can be programmed. */ \ + uint8_t tSamFreq[numSamFreq * 3]; /* Sampling frequency or lower/upper bounds in Hz for the sampling frequency range. */ \ + } + +/// AUDIO Type II Format Type Descriptor UAC1 (2.3.5) +#define audio10_desc_type_II_format_n_t(numSamFreq) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 9+(ns*3). */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE. */ \ + uint8_t bFormatType; /* Constant identifying the Format Type the AudioStreaming interface is using. */ \ + uint16_t wMaxBitRate; /* Indicates the maximum number of bits per second this interface can handle. */ \ + uint16_t wSamplesPerFrame; /* Indicates the number of PCM audio samples contained in one encoded audio frame. */ \ + uint8_t bSamFreqType; /* Indicates how the sampling frequency can be programmed. */ \ + uint8_t tSamFreq[numSamFreq * 3]; /* Sampling frequency or lower/upper bounds in Hz for the sampling frequency range. */ \ + } + +/// AUDIO Type III Format Type Descriptor UAC1 (2.4.5) +#define audio10_desc_type_III_format_n_t(numSamFreq) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* Size of this descriptor in bytes: 8+(ns*3). */ \ + uint8_t bDescriptorType; /* Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. */ \ + uint8_t bDescriptorSubType; /* Descriptor SubType. Value: AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE. */ \ + uint8_t bFormatType; /* Constant identifying the Format Type the AudioStreaming interface is using. */ \ + uint8_t bNrChannels; /* Indicates the number of physical channels in the audio data stream. */ \ + uint8_t bSubFrameSize; /* The number of bytes occupied by one audio subframe. */ \ + uint8_t bBitResolution; /* The number of effectively used bits from the available bits in an audio subframe. */ \ + uint8_t bSamFreqType; /* Indicates how the sampling frequency can be programmed. */ \ + uint8_t tSamFreq[numSamFreq * 3]; /* Sampling frequency or lower/upper bounds in Hz for the sampling frequency range. */ \ + } + +/// Standard AS Isochronous Audio Data Endpoint Descriptor UAC1 (4.6.1.1) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 9. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_ENDPOINT. + uint8_t bEndpointAddress;///< The address of the endpoint on the USB device described by this descriptor. + struct TU_ATTR_PACKED { + uint8_t xfer : 2; // Control, ISO, Bulk, Interrupt + uint8_t sync : 2; // None, Asynchronous, Adaptive, Synchronous + uint8_t usage : 2; // Data, Feedback, Implicit feedback + uint8_t : 2; + } bmAttributes; + uint16_t wMaxPacketSize; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. + uint8_t bInterval; ///< Interval for polling endpoint for data transfers. + uint8_t bRefresh; ///< The rate at which the endpoint is refreshed. + uint8_t bSynchAddress; ///< The address of the endpoint used to send synchronization information for the data endpoint. +} audio10_desc_as_iso_data_ep_t; + +/// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor UAC1 (4.6.1.2) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 7. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO10_CS_EP_SUBTYPE_GENERAL. + uint8_t bmAttributes; ///< Bit 0: Sampling Frequency, Bit 1: Pitch, Bit 7: MaxPacketsOnly. + uint8_t bLockDelayUnits; ///< Indicates the units used for the wLockDelay field. + uint16_t wLockDelay; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. +} audio10_desc_cs_as_iso_data_ep_t; + +/// AUDIO Interrupt Data Message Format UAC1 (3.7.1.2) +typedef struct TU_ATTR_PACKED { + uint8_t bStatusType;///< Indicates the type of status information being reported. + uint8_t bOriginator;///< Indicates the entity that originated this status information. +} audio10_interrupt_data_t; + +//--------------------------------------------------------------------+ +// USB AUDIO CLASS 2.0 (UAC2) DEFINITIONS +//--------------------------------------------------------------------+ + /// 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, - AUDIO_FUNC_HEADSET = 0x04, - AUDIO_FUNC_TELEPHONE = 0x05, - AUDIO_FUNC_CONVERTER = 0x06, - AUDIO_FUNC_SOUND_RECODER = 0x07, - AUDIO_FUNC_IO_BOX = 0x08, - AUDIO_FUNC_MUSICAL_INSTRUMENT = 0x09, - AUDIO_FUNC_PRO_AUDIO = 0x0A, - AUDIO_FUNC_AUDIO_VIDEO = 0x0B, - AUDIO_FUNC_CONTROL_PANEL = 0x0C, - AUDIO_FUNC_OTHER = 0xFF, -} audio_function_code_t; +typedef enum { + AUDIO20_FUNC_UNDEF = 0x00, + AUDIO20_FUNC_DESKTOP_SPEAKER = 0x01, + AUDIO20_FUNC_HOME_THEATER = 0x02, + AUDIO20_FUNC_MICROPHONE = 0x03, + AUDIO20_FUNC_HEADSET = 0x04, + AUDIO20_FUNC_TELEPHONE = 0x05, + AUDIO20_FUNC_CONVERTER = 0x06, + AUDIO20_FUNC_SOUND_RECODER = 0x07, + AUDIO20_FUNC_IO_BOX = 0x08, + AUDIO20_FUNC_MUSICAL_INSTRUMENT = 0x09, + AUDIO20_FUNC_PRO_AUDIO = 0x0A, + AUDIO20_FUNC_AUDIO_VIDEO = 0x0B, + AUDIO20_FUNC_CONTROL_PANEL = 0x0C, + AUDIO20_FUNC_OTHER = 0xFF, +} audio20_function_code_t; /// A.9 - Audio Class-Specific AC Interface Descriptor Subtypes UAC2 -typedef enum -{ - AUDIO_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, - AUDIO_CS_AC_INTERFACE_HEADER = 0x01, - AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, - AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, - AUDIO_CS_AC_INTERFACE_MIXER_UNIT = 0x04, - AUDIO_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, - AUDIO_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, - AUDIO_CS_AC_INTERFACE_EFFECT_UNIT = 0x07, - AUDIO_CS_AC_INTERFACE_PROCESSING_UNIT = 0x08, - AUDIO_CS_AC_INTERFACE_EXTENSION_UNIT = 0x09, - AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE = 0x0A, - AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR = 0x0B, - AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER = 0x0C, - AUDIO_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D, -} audio_cs_ac_interface_subtype_t; +typedef enum { + AUDIO20_CS_AC_INTERFACE_AC_DESCRIPTOR_UNDEF = 0x00, + AUDIO20_CS_AC_INTERFACE_HEADER = 0x01, + AUDIO20_CS_AC_INTERFACE_INPUT_TERMINAL = 0x02, + AUDIO20_CS_AC_INTERFACE_OUTPUT_TERMINAL = 0x03, + AUDIO20_CS_AC_INTERFACE_MIXER_UNIT = 0x04, + AUDIO20_CS_AC_INTERFACE_SELECTOR_UNIT = 0x05, + AUDIO20_CS_AC_INTERFACE_FEATURE_UNIT = 0x06, + AUDIO20_CS_AC_INTERFACE_EFFECT_UNIT = 0x07, + AUDIO20_CS_AC_INTERFACE_PROCESSING_UNIT = 0x08, + AUDIO20_CS_AC_INTERFACE_EXTENSION_UNIT = 0x09, + AUDIO20_CS_AC_INTERFACE_CLOCK_SOURCE = 0x0A, + AUDIO20_CS_AC_INTERFACE_CLOCK_SELECTOR = 0x0B, + AUDIO20_CS_AC_INTERFACE_CLOCK_MULTIPLIER = 0x0C, + AUDIO20_CS_AC_INTERFACE_SAMPLE_RATE_CONVERTER = 0x0D, +} audio20_cs_ac_interface_subtype_t; /// A.10 - Audio Class-Specific AS Interface Descriptor Subtypes UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, - AUDIO_CS_AS_INTERFACE_AS_GENERAL = 0x01, - AUDIO_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, - AUDIO_CS_AS_INTERFACE_ENCODER = 0x03, - AUDIO_CS_AS_INTERFACE_DECODER = 0x04, -} audio_cs_as_interface_subtype_t; +typedef enum { + AUDIO20_CS_AS_INTERFACE_AS_DESCRIPTOR_UNDEF = 0x00, + AUDIO20_CS_AS_INTERFACE_AS_GENERAL = 0x01, + AUDIO20_CS_AS_INTERFACE_FORMAT_TYPE = 0x02, + AUDIO20_CS_AS_INTERFACE_ENCODER = 0x03, + AUDIO20_CS_AS_INTERFACE_DECODER = 0x04, +} audio20_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; +typedef enum { + AUDIO20_EFFECT_TYPE_UNDEF = 0x00, + AUDIO20_EFFECT_TYPE_PARAM_EQ_SECTION = 0x01, + AUDIO20_EFFECT_TYPE_REVERBERATION = 0x02, + AUDIO20_EFFECT_TYPE_MOD_DELAY = 0x03, + AUDIO20_EFFECT_TYPE_DYN_RANGE_COMP = 0x04, +} audio20_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; +typedef enum { + AUDIO20_PROCESS_TYPE_UNDEF = 0x00, + AUDIO20_PROCESS_TYPE_UP_DOWN_MIX = 0x01, + AUDIO20_PROCESS_TYPE_DOLBY_PROLOGIC = 0x02, + AUDIO20_PROCESS_TYPE_STEREO_EXTENDER = 0x03, +} audio20_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; +typedef enum { + AUDIO20_CS_EP_SUBTYPE_UNDEF = 0x00, + AUDIO20_CS_EP_SUBTYPE_GENERAL = 0x01, +} audio20_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.14 - Audio Class-Specific Request Codes UAC2 +typedef enum { + AUDIO20_CS_REQ_UNDEF = 0x00, + AUDIO20_CS_REQ_CUR = 0x01, + AUDIO20_CS_REQ_RANGE = 0x02, + AUDIO20_CS_REQ_MEM = 0x03, +} audio20_cs_req_t; -/// A.17 - Control Selector Codes +/// A.17 - Control Selector Codes UAC2 /// A.17.1 - Clock Source Control Selectors -typedef enum -{ - AUDIO_CS_CTRL_UNDEF = 0x00, - AUDIO_CS_CTRL_SAM_FREQ = 0x01, - AUDIO_CS_CTRL_CLK_VALID = 0x02, -} audio_clock_src_control_selector_t; +typedef enum { + AUDIO20_CS_CTRL_UNDEF = 0x00, + AUDIO20_CS_CTRL_SAM_FREQ = 0x01, + AUDIO20_CS_CTRL_CLK_VALID = 0x02, +} audio20_clock_src_control_selector_t; /// A.17.2 - Clock Selector Control Selectors -typedef enum -{ - AUDIO_CX_CTRL_UNDEF = 0x00, - AUDIO_CX_CTRL_CONTROL = 0x01, -} audio_clock_sel_control_selector_t; +typedef enum { + AUDIO20_CX_CTRL_UNDEF = 0x00, + AUDIO20_CX_CTRL_CONTROL = 0x01, +} audio20_clock_sel_control_selector_t; /// A.17.3 - Clock Multiplier Control Selectors -typedef enum -{ - AUDIO_CM_CTRL_UNDEF = 0x00, - AUDIO_CM_CTRL_NUMERATOR_CONTROL = 0x01, - AUDIO_CM_CTRL_DENOMINATOR_CONTROL = 0x02, -} audio_clock_mul_control_selector_t; +typedef enum { + AUDIO20_CM_CTRL_UNDEF = 0x00, + AUDIO20_CM_CTRL_NUMERATOR_CONTROL = 0x01, + AUDIO20_CM_CTRL_DENOMINATOR_CONTROL = 0x02, +} audio20_clock_mul_control_selector_t; -/// A.17.4 - Terminal Control Selectors -typedef enum -{ - AUDIO_TE_CTRL_UNDEF = 0x00, - AUDIO_TE_CTRL_COPY_PROTECT = 0x01, - AUDIO_TE_CTRL_CONNECTOR = 0x02, - AUDIO_TE_CTRL_OVERLOAD = 0x03, - AUDIO_TE_CTRL_CLUSTER = 0x04, - AUDIO_TE_CTRL_UNDERFLOW = 0x05, - AUDIO_TE_CTRL_OVERFLOW = 0x06, - AUDIO_TE_CTRL_LATENCY = 0x07, -} audio_terminal_control_selector_t; +/// A.17.4 - Terminal Control Selectors UAC2 +typedef enum { + AUDIO20_TE_CTRL_UNDEF = 0x00, + AUDIO20_TE_CTRL_COPY_PROTECT = 0x01, + AUDIO20_TE_CTRL_CONNECTOR = 0x02, + AUDIO20_TE_CTRL_OVERLOAD = 0x03, + AUDIO20_TE_CTRL_CLUSTER = 0x04, + AUDIO20_TE_CTRL_UNDERFLOW = 0x05, + AUDIO20_TE_CTRL_OVERFLOW = 0x06, + AUDIO20_TE_CTRL_LATENCY = 0x07, +} audio20_terminal_control_selector_t; /// A.17.5 - Mixer Control Selectors -typedef enum -{ - AUDIO_MU_CTRL_UNDEF = 0x00, - AUDIO_MU_CTRL_MIXER = 0x01, - AUDIO_MU_CTRL_CLUSTER = 0x02, - AUDIO_MU_CTRL_UNDERFLOW = 0x03, - AUDIO_MU_CTRL_OVERFLOW = 0x04, - AUDIO_MU_CTRL_LATENCY = 0x05, -} audio_mixer_control_selector_t; +typedef enum { + AUDIO20_MU_CTRL_UNDEF = 0x00, + AUDIO20_MU_CTRL_MIXER = 0x01, + AUDIO20_MU_CTRL_CLUSTER = 0x02, + AUDIO20_MU_CTRL_UNDERFLOW = 0x03, + AUDIO20_MU_CTRL_OVERFLOW = 0x04, + AUDIO20_MU_CTRL_LATENCY = 0x05, +} audio20_mixer_control_selector_t; /// A.17.6 - Selector Control Selectors -typedef enum -{ - AUDIO_SU_CTRL_UNDEF = 0x00, - AUDIO_SU_CTRL_SELECTOR = 0x01, - AUDIO_SU_CTRL_LATENCY = 0x02, -} audio_sel_control_selector_t; +typedef enum { + AUDIO20_SU_CTRL_UNDEF = 0x00, + AUDIO20_SU_CTRL_SELECTOR = 0x01, + AUDIO20_SU_CTRL_LATENCY = 0x02, +} audio20_sel_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; +/// A.17.7 - Feature Unit Control Selectors UAC2 +typedef enum { + AUDIO20_FU_CTRL_UNDEF = 0x00, + AUDIO20_FU_CTRL_MUTE = 0x01, + AUDIO20_FU_CTRL_VOLUME = 0x02, + AUDIO20_FU_CTRL_BASS = 0x03, + AUDIO20_FU_CTRL_MID = 0x04, + AUDIO20_FU_CTRL_TREBLE = 0x05, + AUDIO20_FU_CTRL_GRAPHIC_EQUALIZER = 0x06, + AUDIO20_FU_CTRL_AGC = 0x07, + AUDIO20_FU_CTRL_DELAY = 0x08, + AUDIO20_FU_CTRL_BASS_BOOST = 0x09, + AUDIO20_FU_CTRL_LOUDNESS = 0x0A, + AUDIO20_FU_CTRL_INPUT_GAIN = 0x0B, + AUDIO20_FU_CTRL_GAIN_PAD = 0x0C, + AUDIO20_FU_CTRL_INVERTER = 0x0D, + AUDIO20_FU_CTRL_UNDERFLOW = 0x0E, + AUDIO20_FU_CTRL_OVERVLOW = 0x0F, + AUDIO20_FU_CTRL_LATENCY = 0x10, +} audio20_feature_unit_control_selector_t; /// A.17.8 Effect Unit Control Selectors /// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors -typedef enum -{ - AUDIO_PE_CTRL_UNDEF = 0x00, - AUDIO_PE_CTRL_ENABLE = 0x01, - AUDIO_PE_CTRL_CENTERFREQ = 0x02, - AUDIO_PE_CTRL_QFACTOR = 0x03, - AUDIO_PE_CTRL_GAIN = 0x04, - AUDIO_PE_CTRL_UNDERFLOW = 0x05, - AUDIO_PE_CTRL_OVERFLOW = 0x06, - AUDIO_PE_CTRL_LATENCY = 0x07, -} audio_parametric_equalizer_control_selector_t; +typedef enum { + AUDIO20_PE_CTRL_UNDEF = 0x00, + AUDIO20_PE_CTRL_ENABLE = 0x01, + AUDIO20_PE_CTRL_CENTERFREQ = 0x02, + AUDIO20_PE_CTRL_QFACTOR = 0x03, + AUDIO20_PE_CTRL_GAIN = 0x04, + AUDIO20_PE_CTRL_UNDERFLOW = 0x05, + AUDIO20_PE_CTRL_OVERFLOW = 0x06, + AUDIO20_PE_CTRL_LATENCY = 0x07, +} audio20_parametric_equalizer_control_selector_t; /// A.17.8.2 Reverberation Effect Unit Control Selectors -typedef enum -{ - AUDIO_RV_CTRL_UNDEF = 0x00, - AUDIO_RV_CTRL_ENABLE = 0x01, - AUDIO_RV_CTRL_TYPE = 0x02, - AUDIO_RV_CTRL_LEVEL = 0x03, - AUDIO_RV_CTRL_TIME = 0x04, - AUDIO_RV_CTRL_FEEDBACK = 0x05, - AUDIO_RV_CTRL_PREDELAY = 0x06, - AUDIO_RV_CTRL_DENSITY = 0x07, - AUDIO_RV_CTRL_HIFREQ_ROLLOFF = 0x08, - AUDIO_RV_CTRL_UNDERFLOW = 0x09, - AUDIO_RV_CTRL_OVERFLOW = 0x0A, - AUDIO_RV_CTRL_LATENCY = 0x0B, -} audio_reverberation_effect_control_selector_t; +typedef enum { + AUDIO20_RV_CTRL_UNDEF = 0x00, + AUDIO20_RV_CTRL_ENABLE = 0x01, + AUDIO20_RV_CTRL_TYPE = 0x02, + AUDIO20_RV_CTRL_LEVEL = 0x03, + AUDIO20_RV_CTRL_TIME = 0x04, + AUDIO20_RV_CTRL_FEEDBACK = 0x05, + AUDIO20_RV_CTRL_PREDELAY = 0x06, + AUDIO20_RV_CTRL_DENSITY = 0x07, + AUDIO20_RV_CTRL_HIFREQ_ROLLOFF = 0x08, + AUDIO20_RV_CTRL_UNDERFLOW = 0x09, + AUDIO20_RV_CTRL_OVERFLOW = 0x0A, + AUDIO20_RV_CTRL_LATENCY = 0x0B, +} audio20_reverberation_effect_control_selector_t; /// A.17.8.3 Modulation Delay Effect Unit Control Selectors -typedef enum -{ - AUDIO_MD_CTRL_UNDEF = 0x00, - AUDIO_MD_CTRL_ENABLE = 0x01, - AUDIO_MD_CTRL_BALANCE = 0x02, - AUDIO_MD_CTRL_RATE = 0x03, - AUDIO_MD_CTRL_DEPTH = 0x04, - AUDIO_MD_CTRL_TIME = 0x05, - AUDIO_MD_CTRL_FEEDBACK = 0x06, - AUDIO_MD_CTRL_UNDERFLOW = 0x07, - AUDIO_MD_CTRL_OVERFLOW = 0x08, - AUDIO_MD_CTRL_LATENCY = 0x09, -} audio_modulation_delay_control_selector_t; +typedef enum { + AUDIO20_MD_CTRL_UNDEF = 0x00, + AUDIO20_MD_CTRL_ENABLE = 0x01, + AUDIO20_MD_CTRL_BALANCE = 0x02, + AUDIO20_MD_CTRL_RATE = 0x03, + AUDIO20_MD_CTRL_DEPTH = 0x04, + AUDIO20_MD_CTRL_TIME = 0x05, + AUDIO20_MD_CTRL_FEEDBACK = 0x06, + AUDIO20_MD_CTRL_UNDERFLOW = 0x07, + AUDIO20_MD_CTRL_OVERFLOW = 0x08, + AUDIO20_MD_CTRL_LATENCY = 0x09, +} audio20_modulation_delay_control_selector_t; /// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors -typedef enum -{ - AUDIO_DR_CTRL_UNDEF = 0x00, - AUDIO_DR_CTRL_ENABLE = 0x01, - AUDIO_DR_CTRL_COMPRESSION_RATE = 0x02, - AUDIO_DR_CTRL_MAXAMPL = 0x03, - AUDIO_DR_CTRL_THRESHOLD = 0x04, - AUDIO_DR_CTRL_ATTACK_TIME = 0x05, - AUDIO_DR_CTRL_RELEASE_TIME = 0x06, - AUDIO_DR_CTRL_UNDERFLOW = 0x07, - AUDIO_DR_CTRL_OVERFLOW = 0x08, - AUDIO_DR_CTRL_LATENCY = 0x09, -} audio_dynamic_range_compression_control_selector_t; +typedef enum { + AUDIO20_DR_CTRL_UNDEF = 0x00, + AUDIO20_DR_CTRL_ENABLE = 0x01, + AUDIO20_DR_CTRL_COMPRESSION_RATE = 0x02, + AUDIO20_DR_CTRL_MAXAMPL = 0x03, + AUDIO20_DR_CTRL_THRESHOLD = 0x04, + AUDIO20_DR_CTRL_ATTACK_TIME = 0x05, + AUDIO20_DR_CTRL_RELEASE_TIME = 0x06, + AUDIO20_DR_CTRL_UNDERFLOW = 0x07, + AUDIO20_DR_CTRL_OVERFLOW = 0x08, + AUDIO20_DR_CTRL_LATENCY = 0x09, +} audio20_dynamic_range_compression_control_selector_t; /// A.17.9 Processing Unit Control Selectors /// A.17.9.1 Up/Down-mix Processing Unit Control Selectors -typedef enum -{ - AUDIO_UD_CTRL_UNDEF = 0x00, - AUDIO_UD_CTRL_ENABLE = 0x01, - AUDIO_UD_CTRL_MODE_SELECT = 0x02, - AUDIO_UD_CTRL_CLUSTER = 0x03, - AUDIO_UD_CTRL_UNDERFLOW = 0x04, - AUDIO_UD_CTRL_OVERFLOW = 0x05, - AUDIO_UD_CTRL_LATENCY = 0x06, -} audio_up_down_mix_control_selector_t; +typedef enum { + AUDIO20_UD_CTRL_UNDEF = 0x00, + AUDIO20_UD_CTRL_ENABLE = 0x01, + AUDIO20_UD_CTRL_MODE_SELECT = 0x02, + AUDIO20_UD_CTRL_CLUSTER = 0x03, + AUDIO20_UD_CTRL_UNDERFLOW = 0x04, + AUDIO20_UD_CTRL_OVERFLOW = 0x05, + AUDIO20_UD_CTRL_LATENCY = 0x06, +} audio20_up_down_mix_control_selector_t; /// A.17.9.2 Dolby Prologic ™ Processing Unit Control Selectors -typedef enum -{ - AUDIO_DP_CTRL_UNDEF = 0x00, - AUDIO_DP_CTRL_ENABLE = 0x01, - AUDIO_DP_CTRL_MODE_SELECT = 0x02, - AUDIO_DP_CTRL_CLUSTER = 0x03, - AUDIO_DP_CTRL_UNDERFLOW = 0x04, - AUDIO_DP_CTRL_OVERFLOW = 0x05, - AUDIO_DP_CTRL_LATENCY = 0x06, -} audio_dolby_prologic_control_selector_t; +typedef enum { + AUDIO20_DP_CTRL_UNDEF = 0x00, + AUDIO20_DP_CTRL_ENABLE = 0x01, + AUDIO20_DP_CTRL_MODE_SELECT = 0x02, + AUDIO20_DP_CTRL_CLUSTER = 0x03, + AUDIO20_DP_CTRL_UNDERFLOW = 0x04, + AUDIO20_DP_CTRL_OVERFLOW = 0x05, + AUDIO20_DP_CTRL_LATENCY = 0x06, +} audio20_dolby_prologic_control_selector_t; /// A.17.9.3 Stereo Extender Processing Unit Control Selectors -typedef enum -{ - AUDIO_ST_EXT_CTRL_UNDEF = 0x00, - AUDIO_ST_EXT_CTRL_ENABLE = 0x01, - AUDIO_ST_EXT_CTRL_WIDTH = 0x02, - AUDIO_ST_EXT_CTRL_UNDERFLOW = 0x03, - AUDIO_ST_EXT_CTRL_OVERFLOW = 0x04, - AUDIO_ST_EXT_CTRL_LATENCY = 0x05, -} audio_stereo_extender_control_selector_t; +typedef enum { + AUDIO20_ST_EXT_CTRL_UNDEF = 0x00, + AUDIO20_ST_EXT_CTRL_ENABLE = 0x01, + AUDIO20_ST_EXT_CTRL_WIDTH = 0x02, + AUDIO20_ST_EXT_CTRL_UNDERFLOW = 0x03, + AUDIO20_ST_EXT_CTRL_OVERFLOW = 0x04, + AUDIO20_ST_EXT_CTRL_LATENCY = 0x05, +} audio20_stereo_extender_control_selector_t; /// A.17.10 Extension Unit Control Selectors -typedef enum -{ - AUDIO_XU_CTRL_UNDEF = 0x00, - AUDIO_XU_CTRL_ENABLE = 0x01, - AUDIO_XU_CTRL_CLUSTER = 0x02, - AUDIO_XU_CTRL_UNDERFLOW = 0x03, - AUDIO_XU_CTRL_OVERFLOW = 0x04, - AUDIO_XU_CTRL_LATENCY = 0x05, -} audio_extension_unit_control_selector_t; +typedef enum { + AUDIO20_XU_CTRL_UNDEF = 0x00, + AUDIO20_XU_CTRL_ENABLE = 0x01, + AUDIO20_XU_CTRL_CLUSTER = 0x02, + AUDIO20_XU_CTRL_UNDERFLOW = 0x03, + AUDIO20_XU_CTRL_OVERFLOW = 0x04, + AUDIO20_XU_CTRL_LATENCY = 0x05, +} audio20_extension_unit_control_selector_t; /// A.17.11 AudioStreaming Interface Control Selectors -typedef enum -{ - AUDIO_AS_CTRL_UNDEF = 0x00, - AUDIO_AS_CTRL_ACT_ALT_SETTING = 0x01, - AUDIO_AS_CTRL_VAL_ALT_SETTINGS = 0x02, - AUDIO_AS_CTRL_AUDIO_DATA_FORMAT = 0x03, -} audio_audiostreaming_interface_control_selector_t; +typedef enum { + AUDIO20_AS_CTRL_UNDEF = 0x00, + AUDIO20_AS_CTRL_ACT_ALT_SETTING = 0x01, + AUDIO20_AS_CTRL_VAL_ALT_SETTINGS = 0x02, + AUDIO20_AS_CTRL_AUDIO_DATA_FORMAT = 0x03, +} audio20_audiostreaming_interface_control_selector_t; /// A.17.12 Encoder Control Selectors -typedef enum -{ - AUDIO_EN_CTRL_UNDEF = 0x00, - AUDIO_EN_CTRL_BIT_RATE = 0x01, - AUDIO_EN_CTRL_QUALITY = 0x02, - AUDIO_EN_CTRL_VBR = 0x03, - AUDIO_EN_CTRL_TYPE = 0x04, - AUDIO_EN_CTRL_UNDERFLOW = 0x05, - AUDIO_EN_CTRL_OVERFLOW = 0x06, - AUDIO_EN_CTRL_ENCODER_ERROR = 0x07, - AUDIO_EN_CTRL_PARAM1 = 0x08, - AUDIO_EN_CTRL_PARAM2 = 0x09, - AUDIO_EN_CTRL_PARAM3 = 0x0A, - AUDIO_EN_CTRL_PARAM4 = 0x0B, - AUDIO_EN_CTRL_PARAM5 = 0x0C, - AUDIO_EN_CTRL_PARAM6 = 0x0D, - AUDIO_EN_CTRL_PARAM7 = 0x0E, - AUDIO_EN_CTRL_PARAM8 = 0x0F, -} audio_encoder_control_selector_t; +typedef enum { + AUDIO20_EN_CTRL_UNDEF = 0x00, + AUDIO20_EN_CTRL_BIT_RATE = 0x01, + AUDIO20_EN_CTRL_QUALITY = 0x02, + AUDIO20_EN_CTRL_VBR = 0x03, + AUDIO20_EN_CTRL_TYPE = 0x04, + AUDIO20_EN_CTRL_UNDERFLOW = 0x05, + AUDIO20_EN_CTRL_OVERFLOW = 0x06, + AUDIO20_EN_CTRL_ENCODER_ERROR = 0x07, + AUDIO20_EN_CTRL_PARAM1 = 0x08, + AUDIO20_EN_CTRL_PARAM2 = 0x09, + AUDIO20_EN_CTRL_PARAM3 = 0x0A, + AUDIO20_EN_CTRL_PARAM4 = 0x0B, + AUDIO20_EN_CTRL_PARAM5 = 0x0C, + AUDIO20_EN_CTRL_PARAM6 = 0x0D, + AUDIO20_EN_CTRL_PARAM7 = 0x0E, + AUDIO20_EN_CTRL_PARAM8 = 0x0F, +} audio20_encoder_control_selector_t; /// A.17.13 Decoder Control Selectors /// A.17.13.1 MPEG Decoder Control Selectors -typedef enum -{ - AUDIO_MPD_CTRL_UNDEF = 0x00, - AUDIO_MPD_CTRL_DUAL_CHANNEL = 0x01, - AUDIO_MPD_CTRL_SECOND_STEREO = 0x02, - AUDIO_MPD_CTRL_MULTILINGUAL = 0x03, - AUDIO_MPD_CTRL_DYN_RANGE = 0x04, - AUDIO_MPD_CTRL_SCALING = 0x05, - AUDIO_MPD_CTRL_HILO_SCALING = 0x06, - AUDIO_MPD_CTRL_UNDERFLOW = 0x07, - AUDIO_MPD_CTRL_OVERFLOW = 0x08, - AUDIO_MPD_CTRL_DECODER_ERROR = 0x09, -} audio_MPEG_decoder_control_selector_t; +typedef enum { + AUDIO20_MPD_CTRL_UNDEF = 0x00, + AUDIO20_MPD_CTRL_DUAL_CHANNEL = 0x01, + AUDIO20_MPD_CTRL_SECOND_STEREO = 0x02, + AUDIO20_MPD_CTRL_MULTILINGUAL = 0x03, + AUDIO20_MPD_CTRL_DYN_RANGE = 0x04, + AUDIO20_MPD_CTRL_SCALING = 0x05, + AUDIO20_MPD_CTRL_HILO_SCALING = 0x06, + AUDIO20_MPD_CTRL_UNDERFLOW = 0x07, + AUDIO20_MPD_CTRL_OVERFLOW = 0x08, + AUDIO20_MPD_CTRL_DECODER_ERROR = 0x09, +} audio20_MPEG_decoder_control_selector_t; /// A.17.13.2 AC-3 Decoder Control Selectors -typedef enum -{ - AUDIO_AD_CTRL_UNDEF = 0x00, - AUDIO_AD_CTRL_MODE = 0x01, - AUDIO_AD_CTRL_DYN_RANGE = 0x02, - AUDIO_AD_CTRL_SCALING = 0x03, - AUDIO_AD_CTRL_HILO_SCALING = 0x04, - AUDIO_AD_CTRL_UNDERFLOW = 0x05, - AUDIO_AD_CTRL_OVERFLOW = 0x06, - AUDIO_AD_CTRL_DECODER_ERROR = 0x07, -} audio_AC3_decoder_control_selector_t; +typedef enum { + AUDIO20_AD_CTRL_UNDEF = 0x00, + AUDIO20_AD_CTRL_MODE = 0x01, + AUDIO20_AD_CTRL_DYN_RANGE = 0x02, + AUDIO20_AD_CTRL_SCALING = 0x03, + AUDIO20_AD_CTRL_HILO_SCALING = 0x04, + AUDIO20_AD_CTRL_UNDERFLOW = 0x05, + AUDIO20_AD_CTRL_OVERFLOW = 0x06, + AUDIO20_AD_CTRL_DECODER_ERROR = 0x07, +} audio20_AC3_decoder_control_selector_t; /// A.17.13.3 WMA Decoder Control Selectors -typedef enum -{ - AUDIO_WD_CTRL_UNDEF = 0x00, - AUDIO_WD_CTRL_UNDERFLOW = 0x01, - AUDIO_WD_CTRL_OVERFLOW = 0x02, - AUDIO_WD_CTRL_DECODER_ERROR = 0x03, -} audio_WMA_decoder_control_selector_t; +typedef enum { + AUDIO20_WD_CTRL_UNDEF = 0x00, + AUDIO20_WD_CTRL_UNDERFLOW = 0x01, + AUDIO20_WD_CTRL_OVERFLOW = 0x02, + AUDIO20_WD_CTRL_DECODER_ERROR = 0x03, +} audio20_WMA_decoder_control_selector_t; /// A.17.13.4 DTS Decoder Control Selectors -typedef enum -{ - AUDIO_DD_CTRL_UNDEF = 0x00, - AUDIO_DD_CTRL_UNDERFLOW = 0x01, - AUDIO_DD_CTRL_OVERFLOW = 0x02, - AUDIO_DD_CTRL_DECODER_ERROR = 0x03, -} audio_DTS_decoder_control_selector_t; +typedef enum { + AUDIO20_DD_CTRL_UNDEF = 0x00, + AUDIO20_DD_CTRL_UNDERFLOW = 0x01, + AUDIO20_DD_CTRL_OVERFLOW = 0x02, + AUDIO20_DD_CTRL_DECODER_ERROR = 0x03, +} audio20_DTS_decoder_control_selector_t; /// A.17.14 Endpoint Control Selectors -typedef enum -{ - AUDIO_EP_CTRL_UNDEF = 0x00, - AUDIO_EP_CTRL_PITCH = 0x01, - AUDIO_EP_CTRL_DATA_OVERRUN = 0x02, - AUDIO_EP_CTRL_DATA_UNDERRUN = 0x03, -} audio_EP_control_selector_t; - -/// 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 +typedef enum { + AUDIO20_EP_CTRL_UNDEF = 0x00, + AUDIO20_EP_CTRL_PITCH = 0x01, + AUDIO20_EP_CTRL_DATA_OVERRUN = 0x02, + AUDIO20_EP_CTRL_DATA_UNDERRUN = 0x03, +} audio20_EP_control_selector_t; /// 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; +typedef enum { + AUDIO20_FORMAT_TYPE_UNDEFINED = 0x00, + AUDIO20_FORMAT_TYPE_I = 0x01, + AUDIO20_FORMAT_TYPE_II = 0x02, + AUDIO20_FORMAT_TYPE_III = 0x03, + AUDIO20_FORMAT_TYPE_IV = 0x04, + AUDIO20_EXT_FORMAT_TYPE_I = 0x81, + AUDIO20_EXT_FORMAT_TYPE_II = 0x82, + AUDIO20_EXT_FORMAT_TYPE_III = 0x83, +} audio20_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 = 0x80000000u, -} audio_data_format_type_I_t; +typedef enum { + AUDIO20_DATA_FORMAT_TYPE_I_PCM = (uint32_t) (1 << 0), + AUDIO20_DATA_FORMAT_TYPE_I_PCM8 = (uint32_t) (1 << 1), + AUDIO20_DATA_FORMAT_TYPE_I_IEEE_FLOAT = (uint32_t) (1 << 2), + AUDIO20_DATA_FORMAT_TYPE_I_ALAW = (uint32_t) (1 << 3), + AUDIO20_DATA_FORMAT_TYPE_I_MULAW = (uint32_t) (1 << 4), + AUDIO20_DATA_FORMAT_TYPE_I_RAW_DATA = 0x80000000u, +} audio20_data_format_type_I_t; + +/// Audio Class-Audio Channel Configuration UAC2 (Table A-11) +typedef enum { + AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED = 0x00000000, + AUDIO20_CHANNEL_CONFIG_FRONT_LEFT = 0x00000001, + AUDIO20_CHANNEL_CONFIG_FRONT_RIGHT = 0x00000002, + AUDIO20_CHANNEL_CONFIG_FRONT_CENTER = 0x00000004, + AUDIO20_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x00000008, + AUDIO20_CHANNEL_CONFIG_BACK_LEFT = 0x00000010, + AUDIO20_CHANNEL_CONFIG_BACK_RIGHT = 0x00000020, + AUDIO20_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER = 0x00000040, + AUDIO20_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER = 0x00000080, + AUDIO20_CHANNEL_CONFIG_BACK_CENTER = 0x00000100, + AUDIO20_CHANNEL_CONFIG_SIDE_LEFT = 0x00000200, + AUDIO20_CHANNEL_CONFIG_SIDE_RIGHT = 0x00000400, + AUDIO20_CHANNEL_CONFIG_TOP_CENTER = 0x00000800, + AUDIO20_CHANNEL_CONFIG_TOP_FRONT_LEFT = 0x00001000, + AUDIO20_CHANNEL_CONFIG_TOP_FRONT_CENTER = 0x00002000, + AUDIO20_CHANNEL_CONFIG_TOP_FRONT_RIGHT = 0x00004000, + AUDIO20_CHANNEL_CONFIG_TOP_BACK_LEFT = 0x00008000, + AUDIO20_CHANNEL_CONFIG_TOP_BACK_CENTER = 0x00010000, + AUDIO20_CHANNEL_CONFIG_TOP_BACK_RIGHT = 0x00020000, + AUDIO20_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER = 0x00040000, + AUDIO20_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER = 0x00080000, + AUDIO20_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS = 0x00100000, + AUDIO20_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS = 0x00200000, + AUDIO20_CHANNEL_CONFIG_TOP_SIDE_LEFT = 0x00400000, + AUDIO20_CHANNEL_CONFIG_TOP_SIDE_RIGHT = 0x00800000, + AUDIO20_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, + AUDIO20_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, + AUDIO20_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, + AUDIO20_CHANNEL_CONFIG_RAW_DATA = 0x80000000, +} audio20_channel_config_t; /// All remaining definitions are taken from the descriptor descriptions in the UAC2 main specification /// Audio Class-Control Values UAC2 -typedef enum -{ - AUDIO_CTRL_NONE = 0x00, ///< No Host access - AUDIO_CTRL_R = 0x01, ///< Host read access only - AUDIO_CTRL_RW = 0x03, ///< Host read write access -} audio_control_t; +typedef enum { + AUDIO20_CTRL_NONE = 0x00,///< No Host access + AUDIO20_CTRL_R = 0x01, ///< Host read access only + AUDIO20_CTRL_RW = 0x03, ///< Host read write access +} audio20_control_t; /// Audio Class-Specific AC Interface Descriptor Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS = 0, -} audio_cs_ac_interface_control_pos_t; +typedef enum { + AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS = 0, +} audio20_cs_ac_interface_control_pos_t; /// Audio Class-Specific AS Interface Descriptor Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS = 0, - AUDIO_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS = 2, -} audio_cs_as_interface_control_pos_t; +typedef enum { + AUDIO20_CS_AS_INTERFACE_CTRL_ACTIVE_ALT_SET_POS = 0, + AUDIO20_CS_AS_INTERFACE_CTRL_VALID_ALT_SET_POS = 2, +} audio20_cs_as_interface_control_pos_t; /// Audio Class-Specific AS Isochronous Data EP Attributes UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, - AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, -} audio_cs_as_iso_data_ep_attribute_t; +typedef enum { + AUDIO20_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY = 0x80, + AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK = 0x00, +} audio20_cs_as_iso_data_ep_attribute_t; /// Audio Class-Specific AS Isochronous Data EP Controls UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS = 0, - AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS = 2, - AUDIO_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS = 4, -} audio_cs_as_iso_data_ep_control_pos_t; +typedef enum { + AUDIO20_CS_AS_ISO_DATA_EP_CTRL_PITCH_POS = 0, + AUDIO20_CS_AS_ISO_DATA_EP_CTRL_DATA_OVERRUN_POS = 2, + AUDIO20_CS_AS_ISO_DATA_EP_CTRL_DATA_UNDERRUN_POS = 4, +} audio20_cs_as_iso_data_ep_control_pos_t; /// Audio Class-Specific AS Isochronous Data EP Lock Delay Units UAC2 -typedef enum -{ - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, - AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, -} audio_cs_as_iso_data_ep_lock_delay_unit_t; +typedef enum { + AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED = 0x00, + AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC = 0x01, + AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_PCM_SAMPLES = 0x02, +} audio20_cs_as_iso_data_ep_lock_delay_unit_t; /// Audio Class-Clock Source Attributes UAC2 -typedef enum -{ - AUDIO_CLOCK_SOURCE_ATT_EXT_CLK = 0x00, - AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK = 0x01, - AUDIO_CLOCK_SOURCE_ATT_INT_VAR_CLK = 0x02, - AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK = 0x03, - AUDIO_CLOCK_SOURCE_ATT_CLK_SYC_SOF = 0x04, -} audio_clock_source_attribute_t; +typedef enum { + AUDIO20_CLOCK_SOURCE_ATT_EXT_CLK = 0x00, + AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK = 0x01, + AUDIO20_CLOCK_SOURCE_ATT_INT_VAR_CLK = 0x02, + AUDIO20_CLOCK_SOURCE_ATT_INT_PRO_CLK = 0x03, + AUDIO20_CLOCK_SOURCE_ATT_CLK_SYC_SOF = 0x04, +} audio20_clock_source_attribute_t; /// Audio Class-Clock Source Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS = 0, - AUDIO_CLOCK_SOURCE_CTRL_CLK_VAL_POS = 2, -} audio_clock_source_control_pos_t; +typedef enum { + AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS = 0, + AUDIO20_CLOCK_SOURCE_CTRL_CLK_VAL_POS = 2, +} audio20_clock_source_control_pos_t; /// Audio Class-Clock Selector Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_SELECTOR_CTRL_POS = 0, -} audio_clock_selector_control_pos_t; +typedef enum { + AUDIO20_CLOCK_SELECTOR_CTRL_POS = 0, +} audio20_clock_selector_control_pos_t; /// Audio Class-Clock Multiplier Controls UAC2 -typedef enum -{ - AUDIO_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS = 0, - AUDIO_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS = 2, -} audio_clock_multiplier_control_pos_t; +typedef enum { + AUDIO20_CLOCK_MULTIPLIER_CTRL_NUMERATOR_POS = 0, + AUDIO20_CLOCK_MULTIPLIER_CTRL_DENOMINATOR_POS = 2, +} audio20_clock_multiplier_control_pos_t; /// Audio Class-Input Terminal Controls UAC2 -typedef enum -{ - AUDIO_IN_TERM_CTRL_CPY_PROT_POS = 0, - AUDIO_IN_TERM_CTRL_CONNECTOR_POS = 2, - AUDIO_IN_TERM_CTRL_OVERLOAD_POS = 4, - AUDIO_IN_TERM_CTRL_CLUSTER_POS = 6, - AUDIO_IN_TERM_CTRL_UNDERFLOW_POS = 8, - AUDIO_IN_TERM_CTRL_OVERFLOW_POS = 10, -} audio_terminal_input_control_pos_t; +typedef enum { + AUDIO20_IN_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO20_IN_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO20_IN_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO20_IN_TERM_CTRL_CLUSTER_POS = 6, + AUDIO20_IN_TERM_CTRL_UNDERFLOW_POS = 8, + AUDIO20_IN_TERM_CTRL_OVERFLOW_POS = 10, +} audio20_terminal_input_control_pos_t; /// Audio Class-Output Terminal Controls UAC2 -typedef enum -{ - AUDIO_OUT_TERM_CTRL_CPY_PROT_POS = 0, - AUDIO_OUT_TERM_CTRL_CONNECTOR_POS = 2, - AUDIO_OUT_TERM_CTRL_OVERLOAD_POS = 4, - AUDIO_OUT_TERM_CTRL_UNDERFLOW_POS = 6, - AUDIO_OUT_TERM_CTRL_OVERFLOW_POS = 8, -} audio_terminal_output_control_pos_t; +typedef enum { + AUDIO20_OUT_TERM_CTRL_CPY_PROT_POS = 0, + AUDIO20_OUT_TERM_CTRL_CONNECTOR_POS = 2, + AUDIO20_OUT_TERM_CTRL_OVERLOAD_POS = 4, + AUDIO20_OUT_TERM_CTRL_UNDERFLOW_POS = 6, + AUDIO20_OUT_TERM_CTRL_OVERFLOW_POS = 8, +} audio20_terminal_output_control_pos_t; /// Audio Class-Feature Unit Controls UAC2 -typedef enum -{ - AUDIO_FEATURE_UNIT_CTRL_MUTE_POS = 0, - AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS = 2, - AUDIO_FEATURE_UNIT_CTRL_BASS_POS = 4, - AUDIO_FEATURE_UNIT_CTRL_MID_POS = 6, - AUDIO_FEATURE_UNIT_CTRL_TREBLE_POS = 8, - AUDIO_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS = 10, - AUDIO_FEATURE_UNIT_CTRL_AGC_POS = 12, - AUDIO_FEATURE_UNIT_CTRL_DELAY_POS = 14, - AUDIO_FEATURE_UNIT_CTRL_BASS_BOOST_POS = 16, - AUDIO_FEATURE_UNIT_CTRL_LOUDNESS_POS = 18, - AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_POS = 20, - AUDIO_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS = 22, - AUDIO_FEATURE_UNIT_CTRL_PHASE_INV_POS = 24, - AUDIO_FEATURE_UNIT_CTRL_UNDERFLOW_POS = 26, - AUDIO_FEATURE_UNIT_CTRL_OVERFLOW_POS = 28, -} audio_feature_unit_control_pos_t; +typedef enum { + AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS = 0, + AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS = 2, + AUDIO20_FEATURE_UNIT_CTRL_BASS_POS = 4, + AUDIO20_FEATURE_UNIT_CTRL_MID_POS = 6, + AUDIO20_FEATURE_UNIT_CTRL_TREBLE_POS = 8, + AUDIO20_FEATURE_UNIT_CTRL_GRAPHIC_EQU_POS = 10, + AUDIO20_FEATURE_UNIT_CTRL_AGC_POS = 12, + AUDIO20_FEATURE_UNIT_CTRL_DELAY_POS = 14, + AUDIO20_FEATURE_UNIT_CTRL_BASS_BOOST_POS = 16, + AUDIO20_FEATURE_UNIT_CTRL_LOUDNESS_POS = 18, + AUDIO20_FEATURE_UNIT_CTRL_INPUT_GAIN_POS = 20, + AUDIO20_FEATURE_UNIT_CTRL_INPUT_GAIN_PAD_POS = 22, + AUDIO20_FEATURE_UNIT_CTRL_PHASE_INV_POS = 24, + AUDIO20_FEATURE_UNIT_CTRL_UNDERFLOW_POS = 26, + AUDIO20_FEATURE_UNIT_CTRL_OVERFLOW_POS = 28, +} audio20_feature_unit_control_pos_t; -/// Audio Class-Audio Channel Configuration UAC2 -typedef enum -{ - AUDIO_CHANNEL_CONFIG_NON_PREDEFINED = 0x00000000, - AUDIO_CHANNEL_CONFIG_FRONT_LEFT = 0x00000001, - AUDIO_CHANNEL_CONFIG_FRONT_RIGHT = 0x00000002, - AUDIO_CHANNEL_CONFIG_FRONT_CENTER = 0x00000004, - AUDIO_CHANNEL_CONFIG_LOW_FRQ_EFFECTS = 0x00000008, - AUDIO_CHANNEL_CONFIG_BACK_LEFT = 0x00000010, - AUDIO_CHANNEL_CONFIG_BACK_RIGHT = 0x00000020, - AUDIO_CHANNEL_CONFIG_FRONT_LEFT_OF_CENTER = 0x00000040, - AUDIO_CHANNEL_CONFIG_FRONT_RIGHT_OF_CENTER = 0x00000080, - AUDIO_CHANNEL_CONFIG_BACK_CENTER = 0x00000100, - AUDIO_CHANNEL_CONFIG_SIDE_LEFT = 0x00000200, - AUDIO_CHANNEL_CONFIG_SIDE_RIGHT = 0x00000400, - AUDIO_CHANNEL_CONFIG_TOP_CENTER = 0x00000800, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT = 0x00001000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_CENTER = 0x00002000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT = 0x00004000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_LEFT = 0x00008000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_CENTER = 0x00010000, - AUDIO_CHANNEL_CONFIG_TOP_BACK_RIGHT = 0x00020000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_LEFT_OF_CENTER = 0x00040000, - AUDIO_CHANNEL_CONFIG_TOP_FRONT_RIGHT_OF_CENTER = 0x00080000, - AUDIO_CHANNEL_CONFIG_LEFT_LOW_FRQ_EFFECTS = 0x00100000, - AUDIO_CHANNEL_CONFIG_RIGHT_LOW_FRQ_EFFECTS = 0x00200000, - AUDIO_CHANNEL_CONFIG_TOP_SIDE_LEFT = 0x00400000, - AUDIO_CHANNEL_CONFIG_TOP_SIDE_RIGHT = 0x00800000, - AUDIO_CHANNEL_CONFIG_BOTTOM_CENTER = 0x01000000, - AUDIO_CHANNEL_CONFIG_BACK_LEFT_OF_CENTER = 0x02000000, - AUDIO_CHANNEL_CONFIG_BACK_RIGHT_OF_CENTER = 0x04000000, - AUDIO_CHANNEL_CONFIG_RAW_DATA = 0x80000000u, -} audio_channel_config_t; +//--------------------------------------------------------------------+ +// USB AUDIO CLASS 2.0 (UAC2) DESCRIPTORS +//--------------------------------------------------------------------+ -/// AUDIO Channel Cluster Descriptor (4.1) +/// AUDIO Channel Cluster Descriptor UAC2 (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; + uint8_t bNrChannels; ///< Number of channels currently connected. + uint32_t bmChannelConfig;///< Bitmap according to 'audio20_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. +} audio20_desc_channel_cluster_t; -/// AUDIO Class-Specific AC Interface Header Descriptor (4.7.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes: 9. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_HEADER. - uint16_t bcdADC ; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200). - uint8_t bCategory ; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio_function_t. - uint16_t wTotalLength ; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. - uint8_t bmControls ; ///< See: audio_cs_ac_interface_control_pos_t. -} audio_desc_cs_ac_interface_t; -TU_VERIFY_STATIC(sizeof(audio_desc_cs_ac_interface_t) == 9, "size is not correct"); +/// AUDIO Class-Specific AC Interface Header Descriptor UAC2 (4.7.2) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 9. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_HEADER. + uint16_t bcdADC; ///< Audio Device Class Specification Release Number in Binary-Coded Decimal. Value: U16_TO_U8S_LE(0x0200). + uint8_t bCategory; ///< Constant, indicating the primary use of this audio function, as intended by the manufacturer. See: audio20_function_code_t. + uint16_t wTotalLength; ///< Total number of bytes returned for the class-specific AudioControl interface descriptor. Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors. + uint8_t bmControls; ///< See: audio20_cs_ac_interface_control_pos_t. +} audio20_desc_cs_ac_interface_t; +TU_VERIFY_STATIC(sizeof(audio20_desc_cs_ac_interface_t) == 9, "size is not correct"); -/// AUDIO Clock Source Descriptor (4.7.2.1) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor in bytes: 8. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bmAttributes ; ///< See: audio_clock_source_attribute_t. - uint8_t bmControls ; ///< See: audio_clock_source_control_pos_t. - uint8_t bAssocTerminal ; ///< Terminal ID of the Terminal that is associated with this Clock Source. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Source Entity. -} audio_desc_clock_source_t; +/// AUDIO Clock Source Descriptor UAC2 (4.7.2.1) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor in bytes: 8. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_CLOCK_SOURCE. + uint8_t bClockID; ///< Constant uniquely identifying the Clock Source Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bmAttributes; ///< See: audio20_clock_source_attribute_t. + uint8_t bmControls; ///< See: audio20_clock_source_control_pos_t. + uint8_t bAssocTerminal; ///< Terminal ID of the Terminal that is associated with this Clock Source. + uint8_t iClockSource; ///< Index of a string descriptor, describing the Clock Source Entity. +} audio20_desc_clock_source_t; -/// AUDIO Clock Selector Descriptor (4.7.2.2) for ONE pin -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 7+p. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_SELECTOR. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bNrInPins ; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1. - uint8_t baCSourceID ; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected.. - uint8_t bmControls ; ///< See: audio_clock_selector_control_pos_t. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Selector Entity. -} audio_desc_clock_selector_t; +/// AUDIO Clock Selector Descriptor UAC2 (4.7.2.2) for ONE pin +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 7+p. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_CLOCK_SELECTOR. + uint8_t bClockID; ///< Constant uniquely identifying the Clock Selector Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bNrInPins; ///< Number of Input Pins of this Unit: p = 1 thus bNrInPins = 1. + uint8_t baCSourceID; ///< ID of the Clock Entity to which the first Clock Input Pin of this Clock Selector Entity is connected.. + uint8_t bmControls; ///< See: audio20_clock_selector_control_pos_t. + uint8_t iClockSource; ///< Index of a string descriptor, describing the Clock Selector Entity. +} audio20_desc_clock_selector_t; /// AUDIO Clock Selector Descriptor (4.7.2.2) for multiple pins -#define audio_desc_clock_selector_n_t(source_num) \ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; \ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bClockID ; \ - uint8_t bNrInPins ; \ - struct TU_ATTR_PACKED { \ - uint8_t baSourceID ; \ - } sourceID[source_num] ; \ - uint8_t bmControls ; \ - uint8_t iClockSource ; \ -} +#define audio20_desc_clock_selector_n_t(source_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bClockID; \ + uint8_t bNrInPins; \ + struct TU_ATTR_PACKED { \ + uint8_t baSourceID; \ + } sourceID[source_num]; \ + uint8_t bmControls; \ + uint8_t iClockSource; \ + } -/// AUDIO Clock Multiplier Descriptor (4.7.2.3) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 7. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_CLOCK_MULTIPLIER. - uint8_t bClockID ; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected. - uint8_t bmControls ; ///< See: audio_clock_multiplier_control_pos_t. - uint8_t iClockSource ; ///< Index of a string descriptor, describing the Clock Multiplier Entity. -} audio_desc_clock_multiplier_t; +/// AUDIO Clock Multiplier Descriptor UAC2 (4.7.2.3) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 7. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_CLOCK_MULTIPLIER. + uint8_t bClockID; ///< Constant uniquely identifying the Clock Multiplier Entity within the audio function. This value is used in all requests to address this Entity. + uint8_t bCSourceID; ///< ID of the Clock Entity to which the last Clock Input Pin of this Clock Selector Entity is connected. + uint8_t bmControls; ///< See: audio20_clock_multiplier_control_pos_t. + uint8_t iClockSource; ///< Index of a string descriptor, describing the Clock Multiplier Entity. +} audio20_desc_clock_multiplier_t; /// AUDIO Input Terminal Descriptor(4.7.2.4) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 17. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. - uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this terminal. - uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. - uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected. - uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster. - uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t. - uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first logical channel. - uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t. - uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal. -} audio_desc_input_terminal_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 17. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL. + uint8_t bTerminalID; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this terminal. + uint16_t wTerminalType; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types. + uint8_t bAssocTerminal; ///< ID of the Output Terminal to which this Input Terminal is associated. + uint8_t bCSourceID; ///< ID of the Clock Entity to which this Input Terminal is connected. + uint8_t bNrChannels; ///< Number of logical output channels in the Terminal’s output audio channel cluster. + uint32_t bmChannelConfig; ///< Describes the spatial location of the logical channels. See:audio20_channel_config_t. + uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first logical channel. + uint16_t bmControls; ///< See: audio_terminal_input_control_pos_t. + uint8_t iTerminal; ///< Index of a string descriptor, describing the Input Terminal. +} audio20_desc_input_terminal_t; -/// AUDIO Output Terminal Descriptor(4.7.2.5) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 12. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL. - uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal. - uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_output_type_t for other output types. - uint8_t bAssocTerminal ; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. - uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Terminal is connected. - uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Output Terminal is connected. - uint16_t bmControls ; ///< See: audio_terminal_output_type_t. - uint8_t iTerminal ; ///< Index of a string descriptor, describing the Output Terminal. -} audio_desc_output_terminal_t; +/// AUDIO Output Terminal Descriptor UAC2 (4.7.2.5) +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 12. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_OUTPUT_TERMINAL. + uint8_t bTerminalID; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this Terminal. + uint16_t wTerminalType; ///< Constant characterizing the type of Terminal. See: audio20_terminal_type_t for USB streaming and audio20_terminal_output_type_t for other output types. + uint8_t bAssocTerminal; ///< Constant, identifying the Input Terminal to which this Output Terminal is associated. + uint8_t bSourceID; ///< ID of the Unit or Terminal to which this Terminal is connected. + uint8_t bCSourceID; ///< ID of the Clock Entity to which this Output Terminal is connected. + uint16_t bmControls; ///< See: audio20_terminal_output_control_pos_t. + uint8_t iTerminal; ///< Index of a string descriptor, describing the Output Terminal. +} audio20_desc_output_terminal_t; -/// AUDIO Feature Unit Descriptor(4.7.2.8) for ONE channel -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 14. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_FEATURE_UNIT. - uint8_t bUnitID ; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit. - uint8_t bSourceID ; ///< ID of the Unit or Terminal to which this Feature Unit is connected. +/// AUDIO Feature Unit Descriptor UAC2 (4.7.2.8) for ONE channel +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 14. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AC_INTERFACE_FEATURE_UNIT. + uint8_t bUnitID; ///< Constant uniquely identifying the Unit within the audio function. This value is used in all requests to address this Unit. + uint8_t bSourceID; ///< ID of the Unit or Terminal to which this Feature Unit is connected. struct TU_ATTR_PACKED { - uint32_t bmaControls ; ///< See: audio_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1. - } controls[2] ; - uint8_t iTerminal ; ///< Index of a string descriptor, describing this Feature Unit. -} audio_desc_feature_unit_t; + uint32_t bmaControls;///< See: audio20_feature_unit_control_pos_t. Controls0 is master channel 0 (always present) and Controls1 is logical channel 1. + } controls[2]; + uint8_t iTerminal;///< Index of a string descriptor, describing this Feature Unit. +} audio20_desc_feature_unit_t; /// AUDIO Feature Unit Descriptor(4.7.2.8) for multiple channels -#define audio_desc_feature_unit_n_t(ch_num)\ - struct TU_ATTR_PACKED { \ - uint8_t bLength ; /* 6+(ch_num+1)*4 */\ - uint8_t bDescriptorType ; \ - uint8_t bDescriptorSubType ; \ - uint8_t bUnitID ; \ - uint8_t bSourceID ; \ - struct TU_ATTR_PACKED { \ - uint32_t bmaControls ; \ - } controls[ch_num+1] ; \ - uint8_t iTerminal ; \ -} +#define audio20_desc_feature_unit_n_t(ch_num) \ + struct TU_ATTR_PACKED { \ + uint8_t bLength; /* 6+(ch_num+1)*4 */ \ + uint8_t bDescriptorType; \ + uint8_t bDescriptorSubType; \ + uint8_t bUnitID; \ + uint8_t bSourceID; \ + struct TU_ATTR_PACKED { \ + uint32_t bmaControls; \ + } controls[ch_num + 1]; \ + uint8_t iTerminal; \ + } /// AUDIO Class-Specific AS Interface Descriptor(4.9.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 16. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_AS_GENERAL. - uint8_t bTerminalLink ; ///< The Terminal ID of the Terminal to which this interface is connected. - uint8_t bmControls ; ///< See: audio_cs_as_interface_control_pos_t. - uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio_format_type_t. - uint32_t bmFormats ; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio_data_format_type_I_t. - uint8_t bNrChannels ; ///< Number of physical channels in the AS Interface audio channel cluster. - uint32_t bmChannelConfig ; ///< Describes the spatial location of the physical channels. See: audio_channel_config_t. - uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first physical channel. -} audio_desc_cs_as_interface_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 16. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AS_INTERFACE_AS_GENERAL. + uint8_t bTerminalLink; ///< The Terminal ID of the Terminal to which this interface is connected. + uint8_t bmControls; ///< See: audio20_cs_as_interface_control_pos_t. + uint8_t bFormatType; ///< Constant identifying the Format Type the AudioStreaming interface is using. See: audio20_format_type_t. + uint32_t bmFormats; ///< The Audio Data Format(s) that can be used to communicate with this interface.See: audio20_data_format_type_I_t. + uint8_t bNrChannels; ///< Number of physical channels in the AS Interface audio channel cluster. + uint32_t bmChannelConfig; ///< Describes the spatial location of the physical channels. See: audio20_channel_config_t. + uint8_t iChannelNames; ///< Index of a string descriptor, describing the name of the first physical channel. +} audio20_desc_cs_as_interface_t; /// AUDIO Type I Format Type Descriptor(2.3.1.6 - Audio Formats) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 6. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AS_INTERFACE_FORMAT_TYPE. - uint8_t bFormatType ; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO_FORMAT_TYPE_I. - uint8_t bSubslotSize ; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. - uint8_t bBitResolution ; ///< The number of effectively used bits from the available bits in an audio subslot. -} audio_desc_type_I_format_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 6. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_AS_INTERFACE_FORMAT_TYPE. + uint8_t bFormatType; ///< Constant identifying the Format Type the AudioStreaming interface is using. Value: AUDIO20_FORMAT_TYPE_I. + uint8_t bSubslotSize; ///< The number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. + uint8_t bBitResolution; ///< The number of effectively used bits from the available bits in an audio subslot. +} audio20_desc_type_I_format_t; /// AUDIO Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) -typedef struct TU_ATTR_PACKED -{ - uint8_t bLength ; ///< Size of this descriptor, in bytes: 8. - uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. - uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_EP_SUBTYPE_GENERAL. - uint8_t bmAttributes ; ///< See: audio_cs_as_iso_data_ep_attribute_t. - uint8_t bmControls ; ///< See: audio_cs_as_iso_data_ep_control_pos_t. - uint8_t bLockDelayUnits ; ///< Indicates the units used for the wLockDelay field. See: audio_cs_as_iso_data_ep_lock_delay_unit_t. - uint16_t wLockDelay ; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field. -} audio_desc_cs_as_iso_data_ep_t; +typedef struct TU_ATTR_PACKED { + uint8_t bLength; ///< Size of this descriptor, in bytes: 8. + uint8_t bDescriptorType; ///< Descriptor Type. Value: TUSB_DESC_CS_ENDPOINT. + uint8_t bDescriptorSubType;///< Descriptor SubType. Value: AUDIO20_CS_EP_SUBTYPE_GENERAL. + uint8_t bmAttributes; ///< See: audio20_cs_as_iso_data_ep_attribute_t. + uint8_t bmControls; ///< See: audio20_cs_as_iso_data_ep_control_pos_t. + uint8_t bLockDelayUnits; ///< Indicates the units used for the wLockDelay field. See: audio20_cs_as_iso_data_ep_lock_delay_unit_t. + uint16_t wLockDelay; ///< Indicates the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units used depend on the value of the bLockDelayUnits field. +} audio20_desc_cs_as_iso_data_ep_t; // 5.2.2 Control Request Layout -typedef struct TU_ATTR_PACKED -{ - union - { - struct TU_ATTR_PACKED - { - uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. - uint8_t type : 2; ///< Request type tusb_request_type_t. - uint8_t direction : 1; ///< Direction type. tusb_dir_t - } bmRequestType_bit; +typedef struct TU_ATTR_PACKED { + union { + struct TU_ATTR_PACKED { + uint8_t recipient : 5;///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1;///< Direction type. tusb_dir_t + } bmRequestType_bit; - uint8_t bmRequestType; - }; + uint8_t bmRequestType; + }; - uint8_t bRequest; ///< Request type audio_cs_req_t - uint8_t bChannelNumber; - uint8_t bControlSelector; - union - { - uint8_t bInterface; - uint8_t bEndpoint; - }; - uint8_t bEntityID; - uint16_t wLength; -} audio_control_request_t; + uint8_t bRequest;///< Request type audio_cs_req_t + uint8_t bChannelNumber; + uint8_t bControlSelector; + union { + uint8_t bInterface; + uint8_t bEndpoint; + }; + uint8_t bEntityID; + uint16_t wLength; +} audio20_control_request_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; +typedef struct TU_ATTR_PACKED { + int8_t bCur;///< The setting for the CUR attribute of the addressed Control +} audio20_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; - -// 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 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*/ - } subrange[] ; -} audio_control_range_1_t; + int16_t bCur;///< The setting for the CUR attribute of the addressed Control +} audio20_control_cur_2_t; -// 5.2.3.2 2-byte Control RANGE Parameter Block +// 5.2.3.3 4-byte Control CUR Parameter Block 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*/ - } subrange[] ; -} audio_control_range_2_t; + int32_t bCur;///< The setting for the CUR attribute of the addressed Control +} audio20_control_cur_4_t; -// 5.2.3.3 4-byte Control RANGE Parameter Block -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*/ - } subrange[] ; -} audio_control_range_4_t; +// Use the following ONLY for RECEIVED data - compiler does not know how many subranges are defined! Use the #define macros below for predefined lengths. // 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; \ - 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] ; \ -} +#define audio20_control_range_1_n_t(numSubRanges) \ + 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*/ \ + } 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; \ - 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]; \ -} +#define audio20_control_range_2_n_t(numSubRanges) \ + 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*/ \ + } 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; \ - 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]; \ -} +#define audio20_control_range_4_n_t(numSubRanges) \ + 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*/ \ + } subrange[numSubRanges]; \ + } // 6.1 Interrupt Data Message Format -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bInfo; uint8_t bAttribute; - union - { + union { uint16_t wValue; - struct - { + struct { uint8_t wValue_cn_or_mcn; uint8_t wValue_cs; }; }; - union - { + union { uint16_t wIndex; - struct - { + struct { uint8_t wIndex_ep_or_int; uint8_t wIndex_entity_id; }; }; +} audio20_interrupt_data_t; + +//--------------------------------------------------------------------+ +// APPLICATION HELPER DEFINITIONS +//--------------------------------------------------------------------+ + +// Combined Interrupt Data Message Format for both UAC1 and UAC2 +typedef union { + audio10_interrupt_data_t v1; + audio20_interrupt_data_t v2; } audio_interrupt_data_t; +// MIDI1.0 use the same CS AC Interface Descriptor as UAC1 +typedef audio10_desc_cs_ac_interface_n_t(1) midi10_desc_cs_ac_interface_t; + +// UAC1.0 AC Interface Descriptor with 1 interface, used to read fields other than baInterfaceNr +typedef audio10_desc_cs_ac_interface_n_t(1) audio10_desc_cs_ac_interface_1_t; + /** @} */ #ifdef __cplusplus diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 7b78b39b8..983faf8ec 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -180,16 +180,8 @@ tu_static CFG_TUD_MEM_SECTION struct { } lin_buf_out; #endif// CFG_TUD_AUDIO_ENABLE_EP_OUT && USE_LINEAR_BUFFER -// Control buffers -tu_static CFG_TUD_MEM_SECTION struct { - TUD_EPBUF_DEF(buf1, CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ); - #if CFG_TUD_AUDIO > 1 - TUD_EPBUF_DEF(buf2, CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ); - #endif - #if CFG_TUD_AUDIO > 2 - TUD_EPBUF_DEF(buf3, CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ); - #endif -} ctrl_buf; +// Control buffer +CFG_TUD_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_AUDIO_CTRL_BUF_SZ]; // Aligned buffer for feedback EP #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -217,6 +209,8 @@ typedef struct { uint8_t rhport; uint8_t const *p_desc;// Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function + uint8_t const *p_desc_as;// Pointer pointing to 1st Standard AS Interface Descriptor(4.9.1) - Audio Streaming descriptor defining audio function + uint16_t desc_length;// Length of audio function descriptor #if CFG_TUD_AUDIO_ENABLE_EP_IN uint8_t ep_in; // TX audio data EP. @@ -243,8 +237,6 @@ typedef struct bool mounted;// Device opened - uint16_t desc_length;// Length of audio function descriptor - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP struct { uint32_t value; // Feedback value for asynchronous mode (in 16.16 format). @@ -253,7 +245,6 @@ typedef struct uint8_t frame_shift;// bInterval-1 in unit of frame (FS), micro-frame (HS) uint8_t compute_method; - bool format_correction; union { uint8_t power_of_2;// pre-computed power of 2 shift float float_const; // pre-computed float constant @@ -283,17 +274,13 @@ typedef struct // Encoding parameters - parameters are set when alternate AS interface is set by host #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - audio_format_type_t format_type_tx; + uint8_t format_type_tx; uint8_t n_channels_tx; uint8_t n_bytes_per_sample_tx; #endif /*------------- From this point, data is not cleared by bus reset -------------*/ - // Buffer for control requests - uint8_t *ctrl_buf; - uint8_t ctrl_buf_sz; - // EP Transfer buffers and FIFOs #if CFG_TUD_AUDIO_ENABLE_EP_OUT tu_fifo_t ep_out_ff; @@ -327,7 +314,11 @@ typedef struct #define USE_LINEAR_BUFFER_RX 0 #endif -#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf) +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ep_out_ff) +#else +#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ep_in_ff) +#endif //--------------------------------------------------------------------+ // WEAK FUNCTION STUBS @@ -363,11 +354,6 @@ TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED; } -TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) { - (void) func_id; - return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION; -} - TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) { (void) func_id; (void) frame_number; @@ -376,7 +362,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 @@ -465,7 +451,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id); static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id); static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id); -static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio); +static inline uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio); #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t const *p_desc); @@ -474,7 +460,7 @@ static uint16_t audiod_tx_packet_size(const uint16_t *norminal_size, uint16_t da #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq, uint32_t mclk_freq); +static bool audiod_fb_params_prepare(uint8_t func_id, uint8_t alt); static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_new); #endif @@ -606,6 +592,10 @@ static bool audiod_tx_xfer_isr(uint8_t rhport, audiod_function_t * audio, uint16 #endif +//--------------------------------------------------------------------+ +// OTHER API +//--------------------------------------------------------------------+ + #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP // If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) { @@ -616,10 +606,15 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) // We write directly into the EP's buffer - abort if previous transfer not complete TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); + uint8_t size = tud_audio_n_version(func_id) == 2 ? sizeof(audio20_interrupt_data_t) : sizeof(audio10_interrupt_data_t); + + // INT EP buffer must be large enough + TU_ASSERT(size <= sizeof(int_ep_buf[func_id].buf)); + // Check length - if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf), data, sizeof(audio_interrupt_data_t)) == 0) { + if (tu_memcpy_s(int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf), data, size) == 0) { // Schedule transmit - TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, int_ep_buf[func_id].buf, sizeof(int_ep_buf[func_id].buf)), 0); + TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, int_ep_buf[func_id].buf, size), 0); } else { // Release endpoint since we don't make any transfer usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int); @@ -631,10 +626,11 @@ bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data) #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent -static inline bool audiod_fb_send(audiod_function_t *audio) { - bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction; +static inline bool audiod_fb_send(uint8_t func_id) { + audiod_function_t *audio = &_audiod_fct[func_id]; + uint8_t uac_version = tud_audio_n_version(func_id); // Format the feedback value - if (apply_correction) { + if (uac_version == 1) { uint8_t *fb = (uint8_t *) audio->fb_buf; // For FS format is 10.14 @@ -659,10 +655,66 @@ static inline bool audiod_fb_send(audiod_function_t *audio) { // 10.14 3 3 Linux, OSX // // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly - return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) audio->fb_buf, apply_correction ? 3 : 4); + return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) audio->fb_buf, uac_version == 1 ? 3 : 4); +} + +uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { + audiod_function_t *audio = &_audiod_fct[func_id]; + uint32_t feedback; + + switch (audio->feedback.compute_method) { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: + feedback = (cycles << audio->feedback.compute.power_of_2); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); + break; + + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: { + uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1)); + feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); + } break; + + default: + return 0; + } + + // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers + // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. + // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot + // (audio slot = channel count samples). + if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; + if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; + + tud_audio_n_fb_set(func_id, feedback); + + return feedback; +} + +bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) { + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + _audiod_fct[func_id].feedback.value = feedback; + + return true; } #endif +uint8_t tud_audio_n_version(uint8_t func_id) { + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + + uint8_t bIntfProtocol = ((tusb_desc_interface_t const *)_audiod_fct[func_id].p_desc)->bInterfaceProtocol; + + if (bIntfProtocol == AUDIO_INT_PROTOCOL_CODE_V1) { + return 1; + } else if (bIntfProtocol == AUDIO_INT_PROTOCOL_CODE_V2) { + return 2; + } else { + return 0; // Unknown version + } +} + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -672,26 +724,6 @@ void audiod_init(void) { for (uint8_t i = 0; i < CFG_TUD_AUDIO; i++) { audiod_function_t *audio = &_audiod_fct[i]; - // Initialize control buffers - switch (i) { - case 0: - audio->ctrl_buf = ctrl_buf.buf1; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ; - break; -#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0 - case 1: - audio->ctrl_buf = ctrl_buf.buf2; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ; - break; -#endif -#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0 - case 2: - audio->ctrl_buf = ctrl_buf.buf3; - audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ; - break; -#endif - } - // Initialize IN EP FIFO if required #if CFG_TUD_AUDIO_ENABLE_EP_IN @@ -828,7 +860,8 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass); // Verify version is correct - this check can be omitted - TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); + TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V1 || + itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); // Verify interrupt control EP is enabled if demanded by descriptor TU_ASSERT(itf_desc->bNumEndpoints <= 1);// 0 or 1 EPs are allowed @@ -846,21 +879,30 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint _audiod_fct[i].p_desc = (uint8_t const *) itf_desc;// Save pointer to AC descriptor which is by specification always the first one _audiod_fct[i].rhport = rhport; - // Setup descriptor lengths - switch (i) { - case 0: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN; - break; -#if CFG_TUD_AUDIO > 1 - case 1: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN; - break; -#endif -#if CFG_TUD_AUDIO > 2 - case 2: - _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN; - break; -#endif + // Calculate descriptor length + { + uint8_t const *p_desc = (uint8_t const *) itf_desc; + uint8_t const *p_desc_end = p_desc + max_len; + uint16_t total_len = sizeof(tusb_desc_interface_t); + // Skip Standard AC interface descriptor + p_desc = tu_desc_next(p_desc); + while (p_desc_end - p_desc > 0) { + // Stop if: + // - Non audio streaming interface descriptor found + // - IAD found + if ((tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && + !(((tusb_desc_interface_t const *) p_desc)->bInterfaceClass == TUSB_CLASS_AUDIO && ((tusb_desc_interface_t const *) p_desc)->bInterfaceSubClass == AUDIO_SUBCLASS_STREAMING)) + || tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) { + break; + } else if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *) p_desc)->bInterfaceSubClass == AUDIO_SUBCLASS_STREAMING) { + if (_audiod_fct[i].p_desc_as == 0) { + _audiod_fct[i].p_desc_as = p_desc; + } + } + total_len += p_desc[0]; + p_desc = tu_desc_next(p_desc); + } + _audiod_fct[i].desc_length = total_len; } #ifdef TUP_DCD_EDPT_ISO_ALLOC @@ -879,35 +921,48 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint uint8_t ep_fb = 0; #endif uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length; // 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) { + // Unified UAC1/UAC2 endpoint processing tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; - if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { - #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Explicit feedback EP - if (desc_ep->bmAttributes.usage == 1) { - 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->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); - } - #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 + bool is_feedback_ep = false; + bool is_data_ep = false; + + if (tud_audio_n_version(i) == 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_data_ep = (desc_ep_uac1->bmAttributes.sync != TUSB_ISO_EP_ATT_NO_SYNC); + is_feedback_ep = (desc_ep_uac1->bmAttributes.sync == TUSB_ISO_EP_ATT_NO_SYNC); + } else { + // UAC2: Use bmAttributes.usage to distinguish endpoint types + is_data_ep = (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2); + is_feedback_ep = (desc_ep->bmAttributes.usage == 1); + } + + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + // 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 && 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 && 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); @@ -936,19 +991,22 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL { uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length; // 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) { tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { // For data or data with implicit feedback IN EP + // For UAC1 this is always the case since there is no usage field if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { _audiod_fct[i].interval_tx = desc_ep->bInterval; } } - } else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) { + } else if (tud_audio_n_version(i) == 2 && + tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO20_CS_AC_INTERFACE_OUTPUT_TERMINAL) { + // For UAC2 only, UAC1 doesn't have a clock source if (tu_unaligned_read16(p_desc + 4) == AUDIO_TERM_TYPE_USB_STREAMING) { _audiod_fct[i].bclock_id_tx = p_desc[8]; } @@ -961,7 +1019,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP { uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length; // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning while (p_desc_end - p_desc > 0) { // For each endpoint @@ -989,7 +1047,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint TU_ASSERT(i < CFG_TUD_AUDIO); // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) - uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;// - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor + uint16_t drv_len = _audiod_fct[i].desc_length; return drv_len; } @@ -1099,11 +1157,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p #endif// CFG_TUD_AUDIO_ENABLE_EP_OUT // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface - uint8_t const *p_desc = tu_desc_next(audio->p_desc); - // Skip entire AC descriptor block - p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; + + uint8_t const *p_desc = audio->p_desc_as; // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length; // p_desc starts at required interface with alternate setting zero // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning @@ -1126,12 +1183,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_data_ep = (desc_ep_uac1->bmAttributes.sync != TUSB_ISO_EP_ATT_NO_SYNC); + is_feedback_ep = (desc_ep_uac1->bmAttributes.sync == TUSB_ISO_EP_ATT_NO_SYNC); + } else { + // UAC2: Use bmAttributes.usage to distinguish endpoint types + is_data_ep = (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2); + is_feedback_ep = (desc_ep->bmAttributes.usage == 1); + } + //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; @@ -1157,7 +1228,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; @@ -1174,13 +1245,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); + audiod_fb_send(func_id); } + #else + (void) is_feedback_ep; #endif +#else + (void) is_feedback_ep; #endif// CFG_TUD_AUDIO_ENABLE_EP_OUT foundEPs += 1; @@ -1194,50 +1269,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - // Prepare feedback computation if endpoint is available - if (audio->ep_fb != 0) { - audio_feedback_params_t fb_param; - - tud_audio_feedback_params_cb(func_id, alt, &fb_param); - audio->feedback.compute_method = fb_param.method; - - if (TUSB_SPEED_FULL == tud_speed_get()) - audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id); - - // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) - uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; - audio->feedback.min_value = ((fb_param.sample_freq - 1) / frame_div) << 16; - audio->feedback.max_value = (fb_param.sample_freq / frame_div + 1) << 16; - - switch (fb_param.method) { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq); - break; - - case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { - // Initialize the threshold level to half filled - uint16_t fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; - audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; - audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t) fifo_lvl_thr) << 16; - // Avoid 64bit division - uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100); - audio->feedback.compute.fifo_count.nom_value = nominal; - audio->feedback.compute.fifo_count.rate_const[0] = (uint16_t) ((audio->feedback.max_value - nominal) / fifo_lvl_thr); - audio->feedback.compute.fifo_count.rate_const[1] = (uint16_t) ((nominal - audio->feedback.min_value) / fifo_lvl_thr); - // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability - if (tud_speed_get() == TUSB_SPEED_HIGH) { - audio->feedback.compute.fifo_count.rate_const[0] /= 8; - audio->feedback.compute.fifo_count.rate_const[1] /= 8; - } - } break; - - // nothing to do - default: - break; - } - } + // Prepare feedback computation parameters + TU_VERIFY(audiod_fb_params_prepare(func_id, alt)); #endif// CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // We are done - abort loop @@ -1289,20 +1322,23 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id)); #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR) { - _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf); + if (tud_audio_n_version(func_id) == 2) { + 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(ctrl_buf); + audiod_calc_tx_packet_sz(&_audiod_fct[func_id]); + } } #endif // Invoke callback - return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + return tud_audio_set_req_entity_cb(rhport, p_request, ctrl_buf); } else { // Find index of audio driver structure and verify interface really exists TU_VERIFY(audiod_verify_itf_exists(itf, &func_id)); // Invoke callback - return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); + return tud_audio_set_req_itf_cb(rhport, p_request, ctrl_buf); } } break; @@ -1312,8 +1348,32 @@ 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)); - // Invoke callback - return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf); +#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(ctrl_buf) & 0x00FFFFFF; + audiod_calc_tx_packet_sz(&_audiod_fct[func_id]); + } + } + } +#endif + + // Invoke callback + bool ret = tud_audio_set_req_ep_cb(rhport, p_request, ctrl_buf); + +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + if (ret && tud_audio_n_version(func_id) == 1) { + if (_audiod_fct[func_id].ep_out == 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_fb_params_prepare(func_id, _audiod_fct[func_id].ep_out_alt); + } + } + } +#endif + return ret; } break; // Unknown/Unsupported recipient default: @@ -1398,7 +1458,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const } // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished - TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz)); + TU_VERIFY(tud_control_xfer(rhport, p_request, ctrl_buf, sizeof(ctrl_buf))); return true; } @@ -1435,7 +1495,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; } @@ -1486,7 +1546,7 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint if (audio->ep_fb == ep_addr) { // Schedule a transmit with the new value if EP is not busy // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent - audiod_fb_send(audio); + audiod_fb_send(func_id); return true; } #endif @@ -1498,30 +1558,72 @@ bool audiod_xfer_isr(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -static bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq, uint32_t mclk_freq) { - // Check if frame interval is within sane limits - // The interval value n_frames was taken from the descriptors within audiod_set_interface() +static bool audiod_fb_params_prepare(uint8_t func_id, uint8_t alt) { + audiod_function_t *audio = &_audiod_fct[func_id]; - // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed - // this lower limit ensures the measures feedback value has sufficient precision - uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; - uint32_t const n_frame = (1UL << audio->feedback.frame_shift); + // Prepare feedback computation if endpoint is available + if (audio->ep_fb != 0) { + audio_feedback_params_t fb_param; - if ((((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame) { - TU_LOG1(" UAC2 feedback interval too small\r\n"); - TU_BREAKPOINT(); - return false; - } + tud_audio_feedback_params_cb(func_id, alt, &fb_param); + audio->feedback.compute_method = fb_param.method; - // Check if parameters really allow for a power of two division - if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq)) { - audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; - audio->feedback.compute.power_of_2 = (uint8_t) (16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq)); - } else if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) { - audio->feedback.compute.float_const = (float) sample_freq / (float) mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); - } else { - audio->feedback.compute.fixed.sample_freq = sample_freq; - audio->feedback.compute.fixed.mclk_freq = mclk_freq; + // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame) + uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000; + audio->feedback.min_value = ((fb_param.sample_freq - 1) / frame_div) << 16; + audio->feedback.max_value = (fb_param.sample_freq / frame_div + 1) << 16; + + switch (fb_param.method) { + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: + case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: { + // Check if frame interval is within sane limits + // The interval value n_frames was taken from the descriptors within audiod_set_interface() + + // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed + // this lower limit ensures the measures feedback value has sufficient precision + uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13; + uint32_t const n_frame = (1UL << audio->feedback.frame_shift); + + if ((((1UL << k) * fb_param.sample_freq / fb_param.frequency.mclk_freq) + 1) > n_frame) { + TU_LOG1(" UAC2 feedback interval too small\r\n"); + TU_BREAKPOINT(); + return false; + } + + // Check if parameters really allow for a power of two division + if ((fb_param.frequency.mclk_freq % fb_param.sample_freq) == 0 && tu_is_power_of_two(fb_param.frequency.mclk_freq / fb_param.sample_freq)) { + audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2; + audio->feedback.compute.power_of_2 = (uint8_t) (16 - (audio->feedback.frame_shift - 1) - tu_log2(fb_param.frequency.mclk_freq / fb_param.sample_freq)); + } else if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT) { + audio->feedback.compute.float_const = (float) fb_param.sample_freq / (float) fb_param.frequency.mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1))); + } else { + audio->feedback.compute.fixed.sample_freq = fb_param.sample_freq; + audio->feedback.compute.fixed.mclk_freq = fb_param.frequency.mclk_freq; + } + } break; + + case AUDIO_FEEDBACK_METHOD_FIFO_COUNT: { + // Initialize the threshold level to half filled + uint16_t fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2; + audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr; + audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t) fifo_lvl_thr) << 16; + // Avoid 64bit division + uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100); + audio->feedback.compute.fifo_count.nom_value = nominal; + audio->feedback.compute.fifo_count.rate_const[0] = (uint16_t) ((audio->feedback.max_value - nominal) / fifo_lvl_thr); + audio->feedback.compute.fifo_count.rate_const[1] = (uint16_t) ((nominal - audio->feedback.min_value) / fifo_lvl_thr); + // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability + if (tud_speed_get() == TUSB_SPEED_HIGH) { + audio->feedback.compute.fifo_count.rate_const[0] /= 8; + audio->feedback.compute.fifo_count.rate_const[1] /= 8; + } + } break; + + // nothing to do + default: + break; + } } return true; @@ -1550,47 +1652,6 @@ static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_n audio->feedback.value = feedback; } -uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles) { - audiod_function_t *audio = &_audiod_fct[func_id]; - uint32_t feedback; - - switch (audio->feedback.compute_method) { - case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2: - feedback = (cycles << audio->feedback.compute.power_of_2); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT: - feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const); - break; - - case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED: { - uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1)); - feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq); - } break; - - default: - return 0; - } - - // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers - // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1. - // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot - // (audio slot = channel count samples). - if (feedback > audio->feedback.max_value) feedback = audio->feedback.max_value; - if (feedback < audio->feedback.min_value) feedback = audio->feedback.min_value; - - tud_audio_n_fb_set(func_id, feedback); - - return feedback; -} - -bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback) { - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); - - _audiod_fct[func_id].feedback.value = feedback; - - return true; -} #endif TU_ATTR_FAST_FUNC void audiod_sof_isr(uint8_t rhport, uint32_t frame_count) { @@ -1658,24 +1719,27 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req } // Crop length - if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz; + if (len > sizeof(ctrl_buf)) len = sizeof(ctrl_buf); // Copy into buffer - TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t) len)); + TU_VERIFY(0 == tu_memcpy_s(ctrl_buf, sizeof(ctrl_buf), data, (size_t) len)); #if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL - // Find data for sampling_frequency_control - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { - uint8_t entityID = TU_U16_HIGH(p_request->wIndex); - uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue); - if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR) { - _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf); + if (tud_audio_n_version(func_id) == 2) { + // Find data for sampling_frequency_control + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE) { + uint8_t entityID = TU_U16_HIGH(p_request->wIndex); + 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(ctrl_buf); + audiod_calc_tx_packet_sz(&_audiod_fct[func_id]); + } } } #endif // Schedule transmit - return tud_control_xfer(rhport, p_request, (void *) _audiod_fct[func_id].ctrl_buf, len); + return tud_control_xfer(rhport, p_request, ctrl_buf, len); } // Verify an entity with the given ID exists and returns also the corresponding driver index @@ -1686,11 +1750,9 @@ static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t * if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *) _audiod_fct[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_fct[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 - // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning - while (p_desc_end - p_desc > 0) { + while (_audiod_fct[i].p_desc_as - p_desc > 0) { // Entity IDs are always at offset 3 if (p_desc[3] == entityID) { *func_id = i; @@ -1709,7 +1771,7 @@ static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id) { if (_audiod_fct[i].p_desc) { // Get pointer at beginning and end uint8_t const *p_desc = _audiod_fct[i].p_desc; - uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; // 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_INTERFACE && ((tusb_desc_interface_t const *)p_desc)->bInterfaceNumber == itf) { @@ -1731,8 +1793,7 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id) { uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length; // Advance past AC descriptors - EP we look for are streaming EPs - uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); - p_desc += ((audio_desc_cs_ac_interface_t const *) p_desc)->wTotalLength; + uint8_t const *p_desc = _audiod_fct[i].p_desc_as; // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning while (p_desc_end - p_desc > 0) { @@ -1752,20 +1813,34 @@ static void audiod_parse_flow_control_params(audiod_function_t *audio, uint8_t c p_desc = tu_desc_next(p_desc);// Exclude standard AS interface descriptor of current alternate interface descriptor - // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL) { - audio->n_channels_tx = ((audio_desc_cs_as_interface_t const *) p_desc)->bNrChannels; - audio->format_type_tx = (audio_format_type_t) (((audio_desc_cs_as_interface_t const *) p_desc)->bFormatType); - // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) - p_desc = tu_desc_next(p_desc); - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const *) p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I) { - audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const *) p_desc)->bSubslotSize; + if (tud_audio_n_version(audiod_get_audio_fct_idx(audio)) == 1) { + p_desc = tu_desc_next(p_desc);// Exclude Class-Specific AS Interface Descriptor(4.5.2) to get to format type descriptor + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE) { + audio->format_type_tx = ((audio10_desc_type_I_format_n_t(1) const *) p_desc)->bFormatType; + 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 { + // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO20_CS_AS_INTERFACE_AS_GENERAL) { + audio->n_channels_tx = ((audio20_desc_cs_as_interface_t const *) p_desc)->bNrChannels; + audio->format_type_tx = ((audio20_desc_cs_as_interface_t const *) p_desc)->bFormatType; + // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats) + p_desc = tu_desc_next(p_desc); + if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO20_CS_AS_INTERFACE_FORMAT_TYPE && ((audio20_desc_type_I_format_t const *) p_desc)->bFormatType == AUDIO20_FORMAT_TYPE_I) { + audio->n_bytes_per_sample_tx = ((audio20_desc_type_I_format_t const *) p_desc)->bSubslotSize; + } } } } static bool audiod_calc_tx_packet_sz(audiod_function_t *audio) { - TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I); + // AUDIO20_FORMAT_TYPE_I = AUDIO10_FORMAT_TYPE_I + TU_VERIFY(audio->format_type_tx == AUDIO20_FORMAT_TYPE_I); TU_VERIFY(audio->n_channels_tx); TU_VERIFY(audio->n_bytes_per_sample_tx); TU_VERIFY(audio->interval_tx); @@ -1838,11 +1913,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t *norminal_size, uint16_t da #endif // No security checks here - internal function only which should always succeed -static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio) { - for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO; cnt++) { - if (&_audiod_fct[cnt] == audio) return cnt; - } - return 0; +static inline uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio) { + return (uint8_t) (audio - _audiod_fct); } #endif // (CFG_TUD_ENABLED && CFG_TUD_AUDIO) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index a501c5a19..69d9fb7bb 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -37,35 +37,10 @@ // All sizes are in bytes! -#ifndef CFG_TUD_AUDIO_FUNC_1_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_DESC_LEN -#error You must tell the driver the length of the audio function descriptor including IAD descriptor -#endif -#endif - -// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors -#ifndef CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif - -#if CFG_TUD_AUDIO > 1 -#ifndef CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif -#endif - -#if CFG_TUD_AUDIO > 2 -#ifndef CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ -#error You must define an audio class control request buffer size! -#endif +// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your +// biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors +#ifndef CFG_TUD_AUDIO_CTRL_BUF_SZ +#define CFG_TUD_AUDIO_CTRL_BUF_SZ 64 #endif // End point sizes IN BYTES - Limits: Full Speed <= 1023, High Speed <= 1024 @@ -167,7 +142,8 @@ #endif #endif -// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a virtual device where data is perfectly synchronized to USB clock. +// (For TYPE-I format only) Flow control is necessary to allow IN ep send correct amount of data, unless it's a +// virtual device where data is perfectly synchronized to USB clock. #ifndef CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL #define CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL 1 #endif @@ -177,12 +153,6 @@ #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1 #endif -// Enable/disable conversion from 16.16 to 10.14 format on full-speed devices. See tud_audio_n_fb_set(). -// Can be override by tud_audio_feedback_format_correction_cb() -#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION -#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 -#endif - // Enable/disable interrupt EP (required for notifying host of control changes) #ifndef CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP #define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 @@ -205,6 +175,7 @@ extern "C" { // CFG_TUD_AUDIO > 1 //--------------------------------------------------------------------+ bool tud_audio_n_mounted(uint8_t func_id); +uint8_t tud_audio_n_version(uint8_t func_id); #if CFG_TUD_AUDIO_ENABLE_EP_OUT uint16_t tud_audio_n_available (uint8_t func_id); @@ -229,6 +200,7 @@ bool tud_audio_int_n_write (uint8_t func_id, const audio_ // Application API (Interface0) //--------------------------------------------------------------------+ static inline bool tud_audio_mounted (void); +static inline uint8_t tud_audio_version (void); #if CFG_TUD_AUDIO_ENABLE_EP_OUT static inline uint16_t tud_audio_available (void); @@ -250,12 +222,15 @@ static inline bool tud_audio_int_write (const audio_interru #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. +// 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); +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 @@ -263,14 +238,18 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req #if CFG_TUD_AUDIO_ENABLE_EP_IN // Invoked in ISR context once an audio packet was sent successfully. -// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), call tud_audio_write() in I2S receive callback. -bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting); +// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), +// call tud_audio_write() in I2S receive callback. +bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, uint8_t ep_in, + uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT // Invoked in ISR context once an audio packet was received successfully. -// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), call tud_audio_read() in I2S transmit callback. -bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting); +// Normally this function is not needed, since the data transfer should be driven by audio clock (i.e. I2S clock), +// call tud_audio_read() in I2S transmit callback. +bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, + uint8_t cur_alt_setting); #endif #if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -279,42 +258,55 @@ bool tud_audio_rx_done_isr(uint8_t rhport, uint16_t n_bytes_received, uint8_t fu // // Option 1 - AUDIO_FEEDBACK_METHOD_FIFO_COUNT // Feedback value is calculated within the audio driver by regulating the FIFO level to half fill. -// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, well tested -// (Windows, Linux, OSX) with a reliable result so far. -// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is introduced. +// Advantage: No SOF interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus +// less CPU load, well tested (Windows, Linux, OSX) with a reliable result so far. +// Disadvantage: A FIFO of minimal 4 frames is needed to compensate for jitter, an average delay of 2 frames is +// introduced. // // Option 2 - AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED / AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT -// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from -// which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter). +// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information +// about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle +// count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter). // See tud_audio_set_fb_params() and tud_audio_feedback_update() -// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a smaller delay is possible. -// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point is the reading of the cycle counter value of f_m. -// It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced). -// Long-term drift could occur since error is accumulated. +// Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller and thus a +// smaller delay is possible. +// Disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. (The most critical point +// is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, +// hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is +// introduced). Long-term drift will cause the FIFO under/overflow, you still needs to correct it somehow. // // Option 3 - manual -// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. -// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load. -// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay is introduced. +// Determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined +// e.g. from some fill status of some FIFO buffer. +// Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus +// less CPU load. +// Disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 6 frames), i.e. a larger delay +// is introduced. -// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed. +// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at +// FB endpoint interval till it's changed. // -// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus Specification Revision 2.0 5.12.4.2). By default, -// the choice of format is left to the caller and feedback argument is sent as-is. If CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION is set or tud_audio_feedback_format_correction_cb() -// return true, then tinyusb expects 16.16 format and handles the conversion to 10.14 on FS. +// The feedback format is specified to be 16.16 for HS and 10.14 for FS devices (see Universal Serial Bus +// Specification Revision 2.0 5.12.4.2). For simplicity, this function always uses 16.16 format. For FS devices, +// the driver will automatically convert the value to 10.14 format. // -// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and it seems the -// driver can work with either format. +// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 +// devices. On Linux and it seems the driver can work with either format. // -// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value. +// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the +// feature is used, the user can not set the feedback value. // // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec // Boiled down, the feedback value Ff = n_samples / (micro)frame. -// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 -// for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s) -// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K) -// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames +// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames +// need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency +// e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is +// available and locked to f_s) +// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where +// P = min( ceil(log2(f_m / f_s)), K) +// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles +// within fb_n_frames bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback); // Update feedback value with passed MCLK cycles since last time this update function is called. @@ -354,15 +346,11 @@ void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedba // frame_number : current SOF count // interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift); - -// (Full-Speed only) Callback to set feedback format correction is applied or not, -// default to CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION if not implemented. -bool tud_audio_feedback_format_correction_cb(uint8_t func_id); #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +// Invoked when an interrupt notification transfer is complete void tud_audio_int_done_cb(uint8_t rhport); -void tud_audio_int_xfer_cb(uint8_t rhport); #endif // Invoked when audio set interface request received @@ -400,6 +388,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_audio_mounted(void) { return tud_audio_n_mounted(0); } +TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_audio_version(void) { + return tud_audio_n_version(0); +} + #if CFG_TUD_AUDIO_ENABLE_EP_OUT TU_ATTR_ALWAYS_INLINE static inline uint16_t tud_audio_available(void) { diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index e6ace316c..8b78fe945 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -220,11 +220,11 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d // driver after parsing the audio control interface and then resume parsing // the streaming audio interface. if (AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) { - TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(audio_desc_cs_ac_interface_t)); + TU_VERIFY(max_len > 2*sizeof(tusb_desc_interface_t) + sizeof(midi10_desc_cs_ac_interface_t)); p_desc = tu_desc_next(p_desc); TU_VERIFY(tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && - tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_HEADER); + tu_desc_subtype(p_desc) == AUDIO10_CS_AC_INTERFACE_HEADER); desc_cb.desc_audio_control = desc_itf; p_desc = tu_desc_next(p_desc); diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 04149da71..6aa7e0bfc 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -41,12 +41,19 @@ #define TU_DIV_CEIL(n, d) (((n) + (d) - 1) / (d)) #define TU_DIV_ROUND_NEAREST(v, d) (((v) + (d)/2) / (d) ) // round to nearest integer -#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low))) -#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) -#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) +#define TU_U16(_high, _low) ((uint16_t) ((((uint16_t) (_high)) << 8) | ((uint16_t) (_low)))) +#define TU_U16_HIGH(_u16) ((uint8_t) (((uint16_t) (_u16) >> 8) & 0x00ffu)) +#define TU_U16_LOW(_u16) ((uint8_t) ((uint16_t) (_u16) & 0x00ffu)) #define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16) #define U16_TO_U8S_LE(_u16) TU_U16_LOW(_u16), TU_U16_HIGH(_u16) +#define TU_U24(_high, _mid, _low) ((uint32_t) ((((uint32_t) (_high)) << 16) | (((uint32_t) (_mid)) << 8) | ((uint32_t) (_low)))) +#define TU_U24_HIGH(_u24) ((uint8_t) (((uint32_t) (_u24) >> 16) & 0x0000ffu)) +#define TU_U24_MID(_u24) ((uint8_t) (((uint32_t) (_u24) >> 8) & 0x0000ffu)) +#define TU_U24_LOW(_u24) ((uint8_t) ((uint32_t) (_u24) & 0x0000ffu)) +#define U24_TO_U8S_BE(_u24) TU_U24_HIGH(_u24), TU_U24_MID(_u24), TU_U24_LOW(_u24) +#define U24_TO_U8S_LE(_u24) TU_U24_LOW(_u24), TU_U24_MID(_u24), TU_U24_HIGH(_u24) + #define TU_U32_BYTE3(_u32) ((uint8_t) ((((uint32_t) _u32) >> 24) & 0x000000ff)) // MSB #define TU_U32_BYTE2(_u32) ((uint8_t) ((((uint32_t) _u32) >> 16) & 0x000000ff)) #define TU_U32_BYTE1(_u32) ((uint8_t) ((((uint32_t) _u32) >> 8) & 0x000000ff)) diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h index 55950fb45..1ce16f060 100644 --- a/src/common/tusb_compiler.h +++ b/src/common/tusb_compiler.h @@ -118,6 +118,18 @@ #define _TU_ARGS_APPLY_7(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1) _s _TU_ARGS_APPLY_6(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7) #define _TU_ARGS_APPLY_8(_X, _s, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1) _s _TU_ARGS_APPLY_7(_X, _s, _a2, _a3, _a4, _a5, _a6, _a7, _a8) +// Apply an macro X to each of the arguments and expand the result with comma +#define TU_ARGS_APPLY_EXPAND(_X, ...) TU_XSTRCAT(_TU_ARGS_APPLY_EXPAND_, TU_ARGS_NUM(__VA_ARGS__))(_X, __VA_ARGS__) + +#define _TU_ARGS_APPLY_EXPAND_1(_X, _a1) _X(_a1) +#define _TU_ARGS_APPLY_EXPAND_2(_X, _a1, _a2) _X(_a1), _X(_a2) +#define _TU_ARGS_APPLY_EXPAND_3(_X, _a1, _a2, _a3) _X(_a1), _TU_ARGS_APPLY_EXPAND_2(_X, _a2, _a3) +#define _TU_ARGS_APPLY_EXPAND_4(_X, _a1, _a2, _a3, _a4) _X(_a1), _TU_ARGS_APPLY_EXPAND_3(_X, _a2, _a3, _a4) +#define _TU_ARGS_APPLY_EXPAND_5(_X, _a1, _a2, _a3, _a4, _a5) _X(_a1), _TU_ARGS_APPLY_EXPAND_4(_X, _a2, _a3, _a4, _a5) +#define _TU_ARGS_APPLY_EXPAND_6(_X, _a1, _a2, _a3, _a4, _a5, _a6) _X(_a1), _TU_ARGS_APPLY_EXPAND_5(_X, _a2, _a3, _a4, _a5, _a6) +#define _TU_ARGS_APPLY_EXPAND_7(_X, _a1, _a2, _a3, _a4, _a5, _a6, _a7) _X(_a1), _TU_ARGS_APPLY_EXPAND_6(_X, _a2, _a3, _a4, _a5, _a6, _a7) +#define _TU_ARGS_APPLY_EXPAND_8(_X, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8) _X(_a1), _TU_ARGS_APPLY_EXPAND_7(_X, _a2, _a3, _a4, _a5, _a6, _a7, _a8) + //--------------------------------------------------------------------+ // Macro for function default arguments //--------------------------------------------------------------------+ diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 0b8ed1059..2ca14838b 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -64,6 +64,7 @@ #elif TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #define TUP_DCD_ENDPOINT_MAX 16 #define TUP_USBIP_OHCI + #define TUP_USBIP_OHCI_NXP #define TUP_OHCI_RHPORTS 2 #elif TU_CHECK_MCU(OPT_MCU_LPC51UXX) @@ -78,6 +79,10 @@ #elif TU_CHECK_MCU(OPT_MCU_LPC55) // TODO USB0 has 5, USB1 has 6 #define TUP_USBIP_IP3511 + #define TUP_USBIP_OHCI + #define TUP_USBIP_OHCI_NXP + #define TUP_OHCI_RHPORTS 1 // 1 downstream port + #define TUP_DCD_ENDPOINT_MAX 6 #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) diff --git a/src/device/usbd.c b/src/device/usbd.c index 339ccf4b4..05fc752af 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1101,6 +1101,28 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num) #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT if ( driver->open == btd_open ) assoc_itf_count = 2; #endif + + #if CFG_TUD_AUDIO + if (driver->open == audiod_open) { + // UAC1 device doesn't have IAD, needs to read AS interface count from CS AC descriptor + if (TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass && + AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass && + AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol) { + uint8_t const* p = tu_desc_next(p_desc); + uint8_t const* const itf_end = p_desc + remaining_len; + while (p < itf_end) { + if (TUSB_DESC_CS_INTERFACE == tu_desc_type(p) && + AUDIO10_CS_AC_INTERFACE_HEADER == ((audio10_desc_cs_ac_interface_1_t const *) p)->bDescriptorSubType) { + audio10_desc_cs_ac_interface_1_t const * p_header = (audio10_desc_cs_ac_interface_1_t const *) p; + // AC + AS interfaces + assoc_itf_count = p_header->bInCollection + 1; + break; + } + p = tu_desc_next(p); + } + } + } + #endif } // bind (associated) interfaces to found driver diff --git a/src/device/usbd.h b/src/device/usbd.h index f75803b14..bfff23399 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -330,7 +330,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ /* Audio Control (AC) Interface */\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\ /* AC Header */\ - 9, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\ + 9, TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(0x0009), 1, (uint8_t)((_itfnum) + 1),\ /* MIDI Streaming (MS) Interface */\ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ /* MS Header */\ @@ -383,242 +383,352 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ TUD_MIDI_JACKID_OUT_EMB(1) //--------------------------------------------------------------------+ -// Audio v2.0 Descriptor Templates +// Audio Descriptor Templates //--------------------------------------------------------------------+ + +/* Audio v1.0 Descriptor Templates */ + +/* Standard AC Interface Descriptor UAC1 (4.3.1) */ +#define TUD_AUDIO10_DESC_STD_AC_LEN 9 +#define TUD_AUDIO10_DESC_STD_AC(_itfnum, _nEPs, _stridx) \ + TUD_AUDIO10_DESC_STD_AC_LEN, TUSB_DESC_INTERFACE, _itfnum, 0x00, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_CONTROL, AUDIO_INT_PROTOCOL_CODE_V1, _stridx + +/* Class-Specific AC Interface Header Descriptor UAC1 (4.3.2) */ +#define TUD_AUDIO10_DESC_CS_AC_LEN(_nintfs) (8 + (_nintfs)) +// Class-Specific AC Interface Header descriptor, take list of streaming interface numbers as variable arguments +#define TUD_AUDIO10_DESC_CS_AC(_bcdADC, _totallen, ...) \ + TUD_AUDIO10_DESC_CS_AC_LEN(TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), U16_TO_U8S_LE(_totallen + TUD_AUDIO10_DESC_CS_AC_LEN(TU_ARGS_NUM(__VA_ARGS__))), TU_ARGS_NUM(__VA_ARGS__), __VA_ARGS__ + +/* Input Terminal Descriptor UAC1 (4.3.2.1) */ +#define TUD_AUDIO10_DESC_INPUT_TERM_LEN 12 +#define TUD_AUDIO10_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _nchannels, _channelcfg, _idxchannelnames, _stridx) \ + TUD_AUDIO10_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _nchannels, U16_TO_U8S_LE(_channelcfg), _idxchannelnames, _stridx + +/* Output Terminal Descriptor UAC1 (4.3.2.2) */ +#define TUD_AUDIO10_DESC_OUTPUT_TERM_LEN 9 +#define TUD_AUDIO10_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _stridx) \ + TUD_AUDIO10_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _stridx + +/* Mixer Unit Descriptor UAC1 (4.3.2.3) - One Input Pin */ +#define TUD_AUDIO10_DESC_MIXER_UNIT_ONE_PIN_LEN(_ctrlsize) (11 + (_ctrlsize)) +#define TUD_AUDIO10_DESC_MIXER_UNIT_ONE_PIN(_unitid, _srcid, _nrchannels, _channelcfg, _idxchannelnames, _ctrlsize, _stridx, ...) \ + TUD_AUDIO10_DESC_MIXER_UNIT_ONE_PIN_LEN(_ctrlsize), TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_MIXER_UNIT, _unitid, 1, _srcid, _nrchannels, U16_TO_U8S_LE(_channelcfg), _idxchannelnames, __VA_ARGS__, _stridx + +/* Selector Unit Descriptor UAC1 (4.3.2.4) - One Input Pin */ +#define TUD_AUDIO10_DESC_SELECTOR_UNIT_ONE_PIN_LEN 7 +#define TUD_AUDIO10_DESC_SELECTOR_UNIT_ONE_PIN(_unitid, _srcid, _stridx) \ + TUD_AUDIO10_DESC_SELECTOR_UNIT_ONE_PIN_LEN, TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_SELECTOR_UNIT, _unitid, 1, _srcid, _stridx + +/* Feature Unit Descriptor UAC1 (4.3.2.5) - Variable Channels */ +#define TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(_nchannels) (7 + (_nchannels + 1) * 2) +// Feature Unit descriptor, take list of control bitmaps for master channel + each channel as variable arguments +#define TUD_AUDIO10_DESC_FEATURE_UNIT(_unitid, _srcid, _stridx, ...) \ + TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(TU_ARGS_NUM(__VA_ARGS__) - 1), TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, 2, TU_ARGS_APPLY_EXPAND(U16_TO_U8S_LE, __VA_ARGS__), _stridx + +/* Standard AS Interface Descriptor UAC1 (4.5.1) */ +#define TUD_AUDIO10_DESC_STD_AS_LEN 9 +#define TUD_AUDIO10_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ + TUD_AUDIO10_DESC_STD_AS_LEN, TUSB_DESC_INTERFACE, _itfnum, _altset, _nEPs, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_STREAMING, AUDIO_INT_PROTOCOL_CODE_V1, _stridx + +/* Class-Specific AS Interface Descriptor UAC1 (4.5.2) */ +#define TUD_AUDIO10_DESC_CS_AS_INT_LEN 7 +#define TUD_AUDIO10_DESC_CS_AS_INT(_termid, _delay, _formattype) \ + TUD_AUDIO10_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AS_INTERFACE_AS_GENERAL, _termid, _delay, U16_TO_U8S_LE(_formattype) + +/* Type I Format Type Descriptor UAC1 (2.2.5) */ +#define TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(_nfreqs) (8 + (_nfreqs)*3) +// Type I Format descriptor, take list of sample rates in Hz as variable arguments +#define TUD_AUDIO10_DESC_TYPE_I_FORMAT(_nrchannels, _subframesize, _bitresolution, ...) \ + TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(TU_ARGS_NUM(__VA_ARGS__)), TUSB_DESC_CS_INTERFACE, AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO10_FORMAT_TYPE_I, _nrchannels, _subframesize, _bitresolution, TU_ARGS_NUM(__VA_ARGS__), TU_ARGS_APPLY_EXPAND(U24_TO_U8S_LE, __VA_ARGS__) + +/* Standard AS Isochronous Audio Data Endpoint Descriptor UAC1 (4.6.1.1) */ +#define TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN 9 +#define TUD_AUDIO10_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval, _sync_ep) \ + TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval, 0x00, _sync_ep + +/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor UAC1 (4.6.1.2) */ +#define TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN 7 +#define TUD_AUDIO10_DESC_CS_AS_ISO_EP(_attr, _lockdelayunits, _lockdelay) \ + TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO10_CS_EP_SUBTYPE_GENERAL, _attr, _lockdelayunits, U16_TO_U8S_LE(_lockdelay) + +/* Standard AS Isochronous Synch Endpoint Descriptor UAC1 (4.6.2.1) */ +#define TUD_AUDIO10_DESC_STD_AS_ISO_SYNC_EP_LEN 9 +#define TUD_AUDIO10_DESC_STD_AS_ISO_SYNC_EP(_ep, _bRefresh) \ + TUD_AUDIO10_DESC_STD_AS_ISO_SYNC_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS, U16_TO_U8S_LE(3), 1, _bRefresh, 0x00 + +/* Standard AC Interrupt Endpoint Descriptor UAC1 (4.4.2) */ +#define TUD_AUDIO10_DESC_STD_AC_INT_EP_LEN 9 +#define TUD_AUDIO10_DESC_STD_AC_INT_EP(_ep, _interval) \ + TUD_AUDIO10_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(2), _interval, 0x00, 0x00 + +// AUDIO simple descriptor templates for UAC1 + +// AUDIO simple descriptor (UAC1) for 1 microphone input +// - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal + +#define TUD_AUDIO10_MIC_ONE_CH_DESC_LEN(_nfreqs) (\ + + TUD_AUDIO10_DESC_STD_AC_LEN\ + + TUD_AUDIO10_DESC_CS_AC_LEN(1)\ + + TUD_AUDIO10_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(1)\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_STD_AS_LEN\ + + TUD_AUDIO10_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO10_DESC_TYPE_I_FORMAT_LEN(_nfreqs)\ + + TUD_AUDIO10_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO10_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO10_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize, ...) \ + /* Standard AC Interface Descriptor(4.3.1) */\ + TUD_AUDIO10_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + /* Class-Specific AC Interface Header Descriptor(4.3.2) */\ + TUD_AUDIO10_DESC_CS_AC(/*_bcdADC*/ 0x0100, /*_totallen*/ (TUD_AUDIO10_DESC_INPUT_TERM_LEN+TUD_AUDIO10_DESC_OUTPUT_TERM_LEN+TUD_AUDIO10_DESC_FEATURE_UNIT_LEN(1)), /*_itf*/ ((_itfnum)+1)),\ + /* Input Terminal Descriptor(4.3.2.1) */\ + TUD_AUDIO10_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_nchannels*/ 0x01, /*_channelcfg*/ AUDIO10_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_stridx*/ 0x00),\ + /* Output Terminal Descriptor(4.3.2.2) */\ + TUD_AUDIO10_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_stridx*/ 0x00),\ + /* Feature Unit Descriptor(4.3.2.5) */\ + TUD_AUDIO10_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlmaster*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME), /*_ctrlch1*/ (AUDIO10_FU_CONTROL_BM_MUTE | AUDIO10_FU_CONTROL_BM_VOLUME)),\ + /* Standard AS Interface Descriptor(4.5.1) */\ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.5.1) */\ + /* Interface 1, Alternate 1 - alternate interface for data streaming */\ + TUD_AUDIO10_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.5.2) */\ + TUD_AUDIO10_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_delay*/ 0x01, /*_formattype*/ AUDIO10_DATA_FORMAT_TYPE_I_PCM),\ + /* Type I Format Type Descriptor(2.2.5) */\ + TUD_AUDIO10_DESC_TYPE_I_FORMAT(/*_nrchannels*/ 0x01, /*_subframesize*/ _nBytesPerSample, /*_bitresolution*/ _nBitsUsedPerSample, /*_freq*/ __VA_ARGS__),\ + /* 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*/ 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 */ + /* Standard Interface Association Descriptor (IAD) */ -#define TUD_AUDIO_DESC_IAD_LEN 8 -#define TUD_AUDIO_DESC_IAD(_firstitf, _nitfs, _stridx) \ - TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx +#define TUD_AUDIO20_DESC_IAD_LEN 8 +#define TUD_AUDIO20_DESC_IAD(_firstitf, _nitfs, _stridx) \ + TUD_AUDIO20_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _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_INT_PROTOCOL_CODE_V2, _stridx +#define TUD_AUDIO20_DESC_STD_AC_LEN 9 +#define TUD_AUDIO20_DESC_STD_AC(_itfnum, _nEPs, _stridx) /* _nEPs is 0 or 1 */\ + TUD_AUDIO20_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 -#define TUD_AUDIO_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO_DESC_CS_AC_LEN, we already do this here*/ \ - TUD_AUDIO_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO_DESC_CS_AC_LEN), _ctrl +#define TUD_AUDIO20_DESC_CS_AC_LEN 9 +#define TUD_AUDIO20_DESC_CS_AC(_bcdADC, _category, _totallen, _ctrl) /* _bcdADC : Audio Device Class Specification Release Number in Binary-Coded Decimal, _category : see audio20_function_t, _totallen : Total number of bytes returned for the class-specific AudioControl interface i.e. Clock Source, Unit and Terminal descriptors - Do not include TUD_AUDIO20_DESC_CS_AC_LEN, we already do this here*/ \ + TUD_AUDIO20_DESC_CS_AC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AC_INTERFACE_HEADER, U16_TO_U8S_LE(_bcdADC), _category, U16_TO_U8S_LE(_totallen + TUD_AUDIO20_DESC_CS_AC_LEN), _ctrl /* Clock Source Descriptor(4.7.2.1) */ -#define TUD_AUDIO_DESC_CLK_SRC_LEN 8 -#define TUD_AUDIO_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \ - TUD_AUDIO_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx +#define TUD_AUDIO20_DESC_CLK_SRC_LEN 8 +#define TUD_AUDIO20_DESC_CLK_SRC(_clkid, _attr, _ctrl, _assocTerm, _stridx) \ + TUD_AUDIO20_DESC_CLK_SRC_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AC_INTERFACE_CLOCK_SOURCE, _clkid, _attr, _ctrl, _assocTerm, _stridx /* Input Terminal Descriptor(4.7.2.4) */ -#define TUD_AUDIO_DESC_INPUT_TERM_LEN 17 -#define TUD_AUDIO_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \ - TUD_AUDIO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx +#define TUD_AUDIO20_DESC_INPUT_TERM_LEN 17 +#define TUD_AUDIO20_DESC_INPUT_TERM(_termid, _termtype, _assocTerm, _clkid, _nchannelslogical, _channelcfg, _idxchannelnames, _ctrl, _stridx) \ + TUD_AUDIO20_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AC_INTERFACE_INPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _clkid, _nchannelslogical, U32_TO_U8S_LE(_channelcfg), _idxchannelnames, U16_TO_U8S_LE(_ctrl), _stridx /* Output Terminal Descriptor(4.7.2.5) */ -#define TUD_AUDIO_DESC_OUTPUT_TERM_LEN 12 -#define TUD_AUDIO_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \ - TUD_AUDIO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx +#define TUD_AUDIO20_DESC_OUTPUT_TERM_LEN 12 +#define TUD_AUDIO20_DESC_OUTPUT_TERM(_termid, _termtype, _assocTerm, _srcid, _clkid, _ctrl, _stridx) \ + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AC_INTERFACE_OUTPUT_TERMINAL, _termid, U16_TO_U8S_LE(_termtype), _assocTerm, _srcid, _clkid, U16_TO_U8S_LE(_ctrl), _stridx /* Feature Unit Descriptor(4.7.2.8) */ -// 1 - Channel -#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN 6+(1+1)*4 -#define TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _stridx) \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), _stridx - -// 2 - Channels -#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN (6+(2+1)*4) -#define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _stridx) \ - TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), _stridx -// 4 - Channels -#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN (6+(4+1)*4) -#define TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(_unitid, _srcid, _ctrlch0master, _ctrlch1, _ctrlch2, _ctrlch3, _ctrlch4, _stridx) \ - TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1), U32_TO_U8S_LE(_ctrlch2), U32_TO_U8S_LE(_ctrlch3), U32_TO_U8S_LE(_ctrlch4), _stridx - -// For more channels, add definitions here +#define TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(_nchannels) (6 + (_nchannels + 1) * 4) +#define TUD_AUDIO20_DESC_FEATURE_UNIT(_unitid, _srcid, _stridx, ...) \ + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(TU_ARGS_NUM(__VA_ARGS__) - 1), TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid, TU_ARGS_APPLY_EXPAND(U32_TO_U8S_LE, __VA_ARGS__), _stridx /* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */ -#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval +#define TUD_AUDIO20_DESC_STD_AC_INT_EP_LEN 7 +#define TUD_AUDIO20_DESC_STD_AC_INT_EP(_ep, _interval) \ + TUD_AUDIO20_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval /* 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_INT_PROTOCOL_CODE_V2, _stridx +#define TUD_AUDIO20_DESC_STD_AS_LEN 9 +#define TUD_AUDIO20_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ + TUD_AUDIO20_DESC_STD_AS_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 -#define TUD_AUDIO_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \ - TUD_AUDIO_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx +#define TUD_AUDIO20_DESC_CS_AS_INT_LEN 16 +#define TUD_AUDIO20_DESC_CS_AS_INT(_termid, _ctrl, _formattype, _formats, _nchannelsphysical, _channelcfg, _stridx) \ + TUD_AUDIO20_DESC_CS_AS_INT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AS_INTERFACE_AS_GENERAL, _termid, _ctrl, _formattype, U32_TO_U8S_LE(_formats), _nchannelsphysical, U32_TO_U8S_LE(_channelcfg), _stridx /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ -#define TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN 6 -#define TUD_AUDIO_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO_FORMAT_TYPE_I, _subslotsize, _bitresolution +#define TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN 6 +#define TUD_AUDIO20_DESC_TYPE_I_FORMAT(_subslotsize, _bitresolution) /* _subslotsize is number of bytes per sample (i.e. subslot) and can be 1,2,3, or 4 */\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN, TUSB_DESC_CS_INTERFACE, AUDIO20_CS_AS_INTERFACE_FORMAT_TYPE, AUDIO20_FORMAT_TYPE_I, _subslotsize, _bitresolution /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ -#define TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval +#define TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN 7 +#define TUD_AUDIO20_DESC_STD_AS_ISO_EP(_ep, _attr, _maxEPsize, _interval) \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN, TUSB_DESC_ENDPOINT, _ep, _attr, U16_TO_U8S_LE(_maxEPsize), _interval /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ -#define TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN 8 -#define TUD_AUDIO_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \ - TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay) +#define TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN 8 +#define TUD_AUDIO20_DESC_CS_AS_ISO_EP(_attr, _ctrl, _lockdelayunit, _lockdelay) \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN, TUSB_DESC_CS_ENDPOINT, AUDIO20_CS_EP_SUBTYPE_GENERAL, _attr, _ctrl, _lockdelayunit, U16_TO_U8S_LE(_lockdelay) /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ -#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _epsize, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(_epsize), _interval +#define TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP_LEN 7 +#define TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP(_ep, _epsize, _interval) \ + TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(_epsize), _interval // 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_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) +#define TUD_AUDIO20_MIC_ONE_CH_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1)\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_MIC_ONE_CH_DESC_N_AS_INT 1 // Number of AS interfaces +#define TUD_AUDIO20_MIC_ONE_CH_DESC_N_AS_INT 1 // Number of AS interfaces -#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ +#define TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* 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) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // AUDIO simple descriptor (UAC2) for 4 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source -#define TUD_AUDIO_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) +#define TUD_AUDIO20_MIC_FOUR_CH_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(4)\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_MIC_FOUR_CH_DESC_N_AS_INT 1 // Number of AS interfaces +#define TUD_AUDIO20_MIC_FOUR_CH_DESC_N_AS_INT 1 // Number of AS interfaces -#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ +#define TUD_AUDIO20_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(4), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x04, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_FOUR_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch3*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch4*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x04, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* 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) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // AUDIO simple descriptor (UAC2) for mono speaker // - 1 Input Terminal, 2 Feature Unit (Mute and Volume Control), 3 Output Terminal, 4 Clock Source -#define TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN\ - + TUD_AUDIO_DESC_STD_AC_LEN\ - + TUD_AUDIO_DESC_CS_AC_LEN\ - + TUD_AUDIO_DESC_CLK_SRC_LEN\ - + TUD_AUDIO_DESC_INPUT_TERM_LEN\ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_STD_AS_INT_LEN\ - + TUD_AUDIO_DESC_CS_AS_INT_LEN\ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ - + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) +#define TUD_AUDIO20_SPEAKER_MONO_FB_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN\ + + TUD_AUDIO20_DESC_STD_AC_LEN\ + + TUD_AUDIO20_DESC_CS_AC_LEN\ + + TUD_AUDIO20_DESC_CLK_SRC_LEN\ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1)\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_STD_AS_LEN\ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN\ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN\ + + TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP_LEN) -#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ +#define TUD_AUDIO20_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ /* Standard Interface Association Descriptor (IAD) */\ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN+TUD_AUDIO20_DESC_INPUT_TERM_LEN+TUD_AUDIO20_DESC_OUTPUT_TERM_LEN+TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/ 0x00),\ /* Input Terminal Descriptor(4.7.2.4) */\ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 1 - alternate interface for data streaming */\ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ /* 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),\ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ 1) + TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ 1) // Calculate wMaxPacketSize of Endpoints -#define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ - ((((_maxFrequency + (TUD_OPT_HIGH_SPEED ? 7999 : 999)) / (TUD_OPT_HIGH_SPEED ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels) +#define TUD_AUDIO_EP_SIZE(_is_highspeed, _maxFrequency, _nBytesPerSample, _nChannels) \ + ((((_maxFrequency + (_is_highspeed ? 7999 : 999)) / (_is_highspeed ? 8000 : 1000)) + 1) * _nBytesPerSample * _nChannels) //--------------------------------------------------------------------+ diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index f1689b5b4..a12f7d6ed 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -41,13 +41,16 @@ #include "host/usbh.h" #include "ohci.h" -// TODO remove -#include "chip.h" +#if defined(TUP_USBIP_OHCI_NXP) + #include "ohci_nxp.h" +#else + #error Unsupported OHCI IP +#endif //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#define OHCI_REG ((ohci_registers_t *) LPC_USB_BASE) + enum { OHCI_CONTROL_FUNCSTATE_RESET = 0, @@ -181,6 +184,8 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rhport; (void) rh_init; + ohci_phy_init(rhport); + //------------- Data Structure init -------------// tu_memclr(&ohci_data, sizeof(ohci_data_t)); for(uint8_t i=0; i<32; i++) diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index 3366f15f7..38cc84858 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -192,10 +192,10 @@ typedef struct TU_ATTR_ALIGNED(256) { //--------------------------------------------------------------------+ typedef volatile struct { - uint32_t revision; + uint32_t revision; // 0x00 union { - uint32_t control; + uint32_t control; // 0x04 struct { uint32_t control_bulk_service_ratio : 2; uint32_t periodic_list_enable : 1; @@ -211,7 +211,7 @@ typedef volatile struct }; union { - uint32_t command_status; + uint32_t command_status; // 0x08 struct { uint32_t controller_reset : 1; uint32_t control_list_filled : 1; @@ -222,26 +222,24 @@ typedef volatile struct }command_status_bit; }; - uint32_t interrupt_status; - uint32_t interrupt_enable; - uint32_t interrupt_disable; - - uint32_t hcca; - uint32_t period_current_ed; - uint32_t control_head_ed; - uint32_t control_current_ed; - uint32_t bulk_head_ed; - uint32_t bulk_current_ed; - uint32_t done_head; - - uint32_t frame_interval; - uint32_t frame_remaining; - uint32_t frame_number; - uint32_t periodic_start; - uint32_t lowspeed_threshold; + uint32_t interrupt_status; // 0x0C + uint32_t interrupt_enable; // 0x10 + uint32_t interrupt_disable; // 0x14 + uint32_t hcca; // 0x18 + uint32_t period_current_ed; // 0x1C + uint32_t control_head_ed; // 0x20 + uint32_t control_current_ed; // 0x24 + uint32_t bulk_head_ed; // 0x28 + uint32_t bulk_current_ed; // 0x2C + uint32_t done_head; // 0x30 + uint32_t frame_interval; // 0x34 + uint32_t frame_remaining; // 0x38 + uint32_t frame_number; // 0x3C + uint32_t periodic_start; // 0x40 + uint32_t lowspeed_threshold; // 0x44 union { - uint32_t rh_descriptorA; + uint32_t rh_descriptorA; // 0x48 struct { uint32_t number_downstream_ports : 8; uint32_t power_switching_mode : 1; @@ -255,7 +253,7 @@ typedef volatile struct }; union { - uint32_t rh_descriptorB; + uint32_t rh_descriptorB; // 0x4C struct { uint32_t device_removable : 16; uint32_t port_power_control_mask : 16; @@ -263,9 +261,9 @@ typedef volatile struct }; union { - uint32_t rh_status; + uint32_t rh_status; // 0x50 struct { - uint32_t local_power_status : 1; // read Local Power Status; write: Clear Global Power + uint32_t local_power_status : 1; // read Local Power Status; write: Clear Global Power uint32_t over_current_indicator : 1; uint32_t : 13; uint32_t device_remote_wakeup_enable : 1; @@ -277,7 +275,8 @@ typedef volatile struct }; union { - uint32_t rhport_status[TUP_OHCI_RHPORTS]; + uint32_t rhport_status[TUP_OHCI_RHPORTS]; // 0x54 + struct { uint32_t current_connect_status : 1; uint32_t port_enable_status : 1; diff --git a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c b/src/portable/ohci/ohci_nxp.h index fea3e2a66..9cba05e95 100644 --- a/src/portable/nxp/lpc17_40/hcd_lpc17_40.c +++ b/src/portable/ohci/ohci_nxp.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2019, Ha Thach (tinyusb.org) + * Copyright (c) 2025 Ha Thach (tinyusb.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,26 +23,48 @@ * * This file is part of the TinyUSB stack. */ +#ifndef TUSB_OHCI_NXP_H +#define TUSB_OHCI_NXP_H -#include "tusb_option.h" - -#if CFG_TUH_ENABLED && \ - (CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX) +#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX) #include "chip.h" -#include "host/hcd.h" -#include "host/usbh.h" +#define OHCI_REG ((ohci_registers_t *) LPC_USB_BASE) -void hcd_int_enable(uint8_t rhport) -{ - (void) rhport; +void hcd_int_enable(uint8_t rhport) { + (void)rhport; NVIC_EnableIRQ(USB_IRQn); } -void hcd_int_disable(uint8_t rhport) -{ - (void) rhport; +void hcd_int_disable(uint8_t rhport) { + (void)rhport; NVIC_DisableIRQ(USB_IRQn); } +static void ohci_phy_init(uint8_t rhport) { + (void) rhport; +} + +#else + +#include "fsl_device_registers.h" + +// for LPC55 USB0 controller +#define OHCI_REG ((ohci_registers_t *) USBFSH_BASE) + +static void ohci_phy_init(uint8_t rhport) { + (void) rhport; +} + +void hcd_int_enable(uint8_t rhport) { + (void)rhport; + NVIC_EnableIRQ(USB0_IRQn); +} + +void hcd_int_disable(uint8_t rhport) { + (void)rhport; + NVIC_DisableIRQ(USB0_IRQn); +} +#endif + #endif |
