This is an automated email from the ASF dual-hosted git repository. kasjer pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 567628552c660aa3d5a4f07b24055440612c64cf Author: Jerzy Kasenberg <[email protected]> AuthorDate: Wed Oct 7 14:55:12 2026 +0200 tinyusb/std_descriptors: Add USB Audio Class 2.0 function Add UAC2 descriptors to the standard descriptor set, selected and shaped by syscfg: - USBD_AUDIO: NONE, IN (microphone), OUT (speaker) or IN_OUT (headset). Function category and default terminal types follow the selection, USBD_AUDIO_IN/OUT_TERMINAL_TYPE override them. - USBD_AUDIO_SAMPLE_RATE, USBD_AUDIO_SAMPLE_SIZE and USBD_AUDIO_BYTES_PER_SAMPLE describe the single Type I PCM format. - USBD_AUDIO_IN_CHANNELS and USBD_AUDIO_OUT_CHANNELS are independent, feature units expose mute and optionally volume per channel. - USBD_AUDIO_FEEDBACK switches speaker endpoint from adaptive to asynchronous with feedback endpoint. - Endpoint numbers, optional interrupt endpoint and FIFO depths are configurable; isochronous endpoints default to 8 on nRF5x. Descriptor pieces live in usbd_audio_desc.h so that std_descriptors.c only adds interface numbers, string index and total length. A static assert verifies the composed descriptor length. The audio function uses an IAD, so the device qualifier reports MISC/COMMON/IAD and applications should set USBD_COMPOSITE_DEVICE. TinyUSB's TUD_AUDIO_EP_SIZE cannot be used in #if before usbd.h is included, a local USBD_AUDIO_EP_SIZE provides the same formula. Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Jerzy Kasenberg <[email protected]> --- .../tinyusb/std_descriptors/include/tusb_config.h | 99 +++++ .../std_descriptors/include/usbd_audio_desc.h | 398 +++++++++++++++++++++ .../tinyusb/std_descriptors/src/std_descriptors.c | 34 +- hw/usb/tinyusb/std_descriptors/syscfg.yml | 115 ++++++ 4 files changed, 644 insertions(+), 2 deletions(-) diff --git a/hw/usb/tinyusb/std_descriptors/include/tusb_config.h b/hw/usb/tinyusb/std_descriptors/include/tusb_config.h index 8cbe04e54..e2dab3951 100755 --- a/hw/usb/tinyusb/std_descriptors/include/tusb_config.h +++ b/hw/usb/tinyusb/std_descriptors/include/tusb_config.h @@ -242,6 +242,105 @@ extern "C" { #define CFG_TUD_DFU_DETACH_TIMEOUT 1000 #endif +/* ------------- Audio (USB Audio Class 2.0) ------------- */ +#if MYNEWT_VAL_CHOICE(USBD_AUDIO, IN) +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 +#elif MYNEWT_VAL_CHOICE(USBD_AUDIO, OUT) +#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#elif MYNEWT_VAL_CHOICE(USBD_AUDIO, IN_OUT) +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#else +#define CFG_TUD_AUDIO_ENABLE_EP_IN 0 +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 0 +#endif +#define CFG_TUD_AUDIO \ + (CFG_TUD_AUDIO_ENABLE_EP_IN || CFG_TUD_AUDIO_ENABLE_EP_OUT) + +#if CFG_TUD_AUDIO +#define USBD_AUDIO_SAMPLE_RATE MYNEWT_VAL(USBD_AUDIO_SAMPLE_RATE) +/* Valid bits in sample (bit resolution) */ +#define USBD_AUDIO_SAMPLE_SIZE MYNEWT_VAL(USBD_AUDIO_SAMPLE_SIZE) +/* Bytes used by sample in USB packet (subslot size) */ +#if MYNEWT_VAL(USBD_AUDIO_BYTES_PER_SAMPLE) +#define USBD_AUDIO_BYTES_PER_SAMPLE MYNEWT_VAL(USBD_AUDIO_BYTES_PER_SAMPLE) +#else +#define USBD_AUDIO_BYTES_PER_SAMPLE ((USBD_AUDIO_SAMPLE_SIZE + 7) / 8) +#endif + +#define USBD_AUDIO_IN_CHANNELS MYNEWT_VAL(USBD_AUDIO_IN_CHANNELS) +#define USBD_AUDIO_OUT_CHANNELS MYNEWT_VAL(USBD_AUDIO_OUT_CHANNELS) + +/* Endpoint addresses, isochronous endpoints on nRF5x are fixed to 8 */ +#if MYNEWT_VAL(USBD_AUDIO_OUT_EP) +#define USBD_AUDIO_OUT_EP MYNEWT_VAL(USBD_AUDIO_OUT_EP) +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X +#define USBD_AUDIO_OUT_EP 8 +#else +#define USBD_AUDIO_OUT_EP 1 +#endif + +#if MYNEWT_VAL(USBD_AUDIO_IN_EP) +#define USBD_AUDIO_IN_EP (0x80 | MYNEWT_VAL(USBD_AUDIO_IN_EP)) +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X +#define USBD_AUDIO_IN_EP (0x80 | 8) +#else +#define USBD_AUDIO_IN_EP (0x80 | 1) +#endif + +#if MYNEWT_VAL(USBD_AUDIO_FEEDBACK_EP) +#define USBD_AUDIO_FEEDBACK_EP \ + (0x80 | MYNEWT_VAL(USBD_AUDIO_FEEDBACK_EP)) +#elif CFG_TUSB_MCU == OPT_MCU_NRF5X +#define USBD_AUDIO_FEEDBACK_EP (0x80 | 8) +#else +#define USBD_AUDIO_FEEDBACK_EP (0x80 | 2) +#endif + +#if MYNEWT_VAL(USBD_AUDIO_FEEDBACK) && CFG_TUD_AUDIO_ENABLE_EP_OUT +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 +#else +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 +#endif + +#if MYNEWT_VAL(USBD_AUDIO_INT_EP) +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 1 +#define USBD_AUDIO_INT_EP (0x80 | MYNEWT_VAL(USBD_AUDIO_INT_EP)) +#else +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 +#endif + +/* + * Endpoint sizes for 1 ms packets (one extra sample for rates that are not + * multiple of 1 kHz and for asynchronous streams). Same packet size is used + * for full and high speed, high speed endpoints use interval of 8 + * microframes. + * Same formula as TUD_AUDIO_EP_SIZE(false, ...), written out here because + * TinyUSB evaluates these values in #if before usbd.h is included. + */ +#define USBD_AUDIO_EP_SIZE(_rate, _bytes, _nch) \ + (((((_rate) + 999) / 1000) + 1) * (_bytes) * (_nch)) +#define USBD_AUDIO_EP_IN_SZ \ + USBD_AUDIO_EP_SIZE(USBD_AUDIO_SAMPLE_RATE, USBD_AUDIO_BYTES_PER_SAMPLE, \ + USBD_AUDIO_IN_CHANNELS) +#define USBD_AUDIO_EP_OUT_SZ \ + USBD_AUDIO_EP_SIZE(USBD_AUDIO_SAMPLE_RATE, USBD_AUDIO_BYTES_PER_SAMPLE, \ + USBD_AUDIO_OUT_CHANNELS) + +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX USBD_AUDIO_EP_IN_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ \ + (MYNEWT_VAL(USBD_AUDIO_IN_BUFFER_PACKETS) * USBD_AUDIO_EP_IN_SZ) +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX USBD_AUDIO_EP_OUT_SZ +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ \ + (MYNEWT_VAL(USBD_AUDIO_OUT_BUFFER_PACKETS) * USBD_AUDIO_EP_OUT_SZ) +#endif +#endif /* CFG_TUD_AUDIO */ + #ifdef __cplusplus } #endif diff --git a/hw/usb/tinyusb/std_descriptors/include/usbd_audio_desc.h b/hw/usb/tinyusb/std_descriptors/include/usbd_audio_desc.h new file mode 100644 index 000000000..72f412ee8 --- /dev/null +++ b/hw/usb/tinyusb/std_descriptors/include/usbd_audio_desc.h @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_USBD_AUDIO_DESC_ +#define H_USBD_AUDIO_DESC_ + +#include <syscfg/syscfg.h> +#include <tusb.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * USB Audio Class 2.0 function descriptors built from syscfg values: + * + * USBD_AUDIO IN (mic), OUT (speaker), IN_OUT (headset) + * USBD_AUDIO_SAMPLE_RATE sampling frequency in Hz + * USBD_AUDIO_SAMPLE_SIZE bits per sample + * USBD_AUDIO_BYTES_PER_SAMPLE bytes per sample (subslot size) + * USBD_AUDIO_IN_CHANNELS number of microphone channels + * USBD_AUDIO_OUT_CHANNELS number of speaker channels + * USBD_AUDIO_IN_TERMINAL_TYPE microphone input terminal type + * (AUDIO_TERM_TYPE_IN_*) + * USBD_AUDIO_OUT_TERMINAL_TYPE speaker output terminal type + * (AUDIO_TERM_TYPE_OUT_*) + * USBD_AUDIO_VOLUME_CONTROL feature unit with mute and volume controls + * USBD_AUDIO_FEEDBACK feedback endpoint for speaker path + * USBD_AUDIO_INT_EP interrupt endpoint for control changes + * + * Function has one clock source shared by all terminals, one alternate + * setting with audio data per streaming interface and PCM type I format. + * Layout of the function: + * + * Interface N Audio Control: + * Clock Source (4) + * Speaker path: + * Input Terminal (1) -> [Feature Unit (2)] -> + * Output Terminal (3) + * Microphone path: + * Input Terminal (0x11) -> [Feature Unit (0x12)] -> + * Output Terminal (0x13) + * [Interrupt endpoint] + * Interface N+1 Audio Streaming OUT (speaker), + * alternate 0 (idle) and 1 (streaming) + * Interface N+2 Audio Streaming IN (microphone), + * alternate 0 (idle) and 1 (streaming) + * + * Only descriptors are provided here, application has to implement TinyUSB + * audio class callbacks (tud_audio_*_cb). Entity IDs below are needed to + * handle requests passed to tud_audio_get_req_entity_cb() and + * tud_audio_set_req_entity_cb(). + */ +#define USBD_AUDIO_ENTITY_CLOCK 0x04 +/* Speaker path (host -> device) */ +#define USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL 0x01 +#define USBD_AUDIO_ENTITY_SPK_FEATURE_UNIT 0x02 +#define USBD_AUDIO_ENTITY_SPK_OUTPUT_TERMINAL 0x03 +/* Microphone path (device -> host) */ +#define USBD_AUDIO_ENTITY_MIC_INPUT_TERMINAL 0x11 +#define USBD_AUDIO_ENTITY_MIC_FEATURE_UNIT 0x12 +#define USBD_AUDIO_ENTITY_MIC_OUTPUT_TERMINAL 0x13 + +#if CFG_TUD_AUDIO + +#if MYNEWT_VAL(USBD_AUDIO_VOLUME_CONTROL) && \ + (CFG_TUD_AUDIO_ENABLE_EP_OUT && USBD_AUDIO_OUT_CHANNELS > 8 || \ + CFG_TUD_AUDIO_ENABLE_EP_IN && USBD_AUDIO_IN_CHANNELS > 8) +#error USBD_AUDIO_VOLUME_CONTROL supports up to 8 channels +#endif + +/* Number of USB interfaces used by audio function (AC + AS interfaces). */ +#define USBD_AUDIO_ITF_COUNT \ + (1 + CFG_TUD_AUDIO_ENABLE_EP_OUT + CFG_TUD_AUDIO_ENABLE_EP_IN) + +/* Endpoint interval resulting in 1 ms packets for full and high speed. */ +#define USBD_AUDIO_EP_INTERVAL \ + ((USBD_RHPORT_MODE & OPT_MODE_HIGH_SPEED) ? 4 : 1) + +/* Function category and default terminal types depend on direction(s). */ +#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_EP_IN +#define USBD_AUDIO_FUNCTION_CATEGORY AUDIO20_FUNC_HEADSET +#define USBD_AUDIO_SPK_TERMINAL_DEFAULT AUDIO_TERM_TYPE_OUT_HEADPHONES +/* Terminals of both paths are associated with each other. */ +#define USBD_AUDIO_SPK_IT_ASSOC USBD_AUDIO_ENTITY_MIC_OUTPUT_TERMINAL +#define USBD_AUDIO_MIC_OT_ASSOC USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL +#elif CFG_TUD_AUDIO_ENABLE_EP_OUT +#define USBD_AUDIO_FUNCTION_CATEGORY AUDIO20_FUNC_DESKTOP_SPEAKER +#define USBD_AUDIO_SPK_TERMINAL_DEFAULT AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER +#define USBD_AUDIO_SPK_IT_ASSOC 0x00 +#else +#define USBD_AUDIO_FUNCTION_CATEGORY AUDIO20_FUNC_MICROPHONE +#define USBD_AUDIO_MIC_OT_ASSOC 0x00 +#endif +#define USBD_AUDIO_MIC_TERMINAL_DEFAULT AUDIO_TERM_TYPE_IN_GENERIC_MIC + +/* Terminal types, from syscfg when set (AUDIO_TERM_TYPE_* name or number). */ +#if defined(MYNEWT_VAL_USBD_AUDIO_OUT_TERMINAL_TYPE) +#define USBD_AUDIO_SPK_TERMINAL_TYPE MYNEWT_VAL(USBD_AUDIO_OUT_TERMINAL_TYPE) +#else +#define USBD_AUDIO_SPK_TERMINAL_TYPE USBD_AUDIO_SPK_TERMINAL_DEFAULT +#endif +#if defined(MYNEWT_VAL_USBD_AUDIO_IN_TERMINAL_TYPE) +#define USBD_AUDIO_MIC_TERMINAL_TYPE MYNEWT_VAL(USBD_AUDIO_IN_TERMINAL_TYPE) +#else +#define USBD_AUDIO_MIC_TERMINAL_TYPE USBD_AUDIO_MIC_TERMINAL_DEFAULT +#endif + +/* + * Spatial location of channels: mono - front center, stereo - left and + * right, other - not specified. + */ +#define USBD_AUDIO_CHANNEL_CONFIG(_nch) \ + ((_nch) == 1 ? AUDIO20_CHANNEL_CONFIG_FRONT_CENTER : \ + (_nch) == 2 ? (AUDIO20_CHANNEL_CONFIG_FRONT_LEFT | AUDIO20_CHANNEL_CONFIG_FRONT_RIGHT) : \ + AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED) + +/* + * Feature unit controls: mute and volume, read/write, for master channel + * (first) and every logical channel. USBD_AUDIO_FU_CTRLS_n expands to + * n + 1 values. + * Channel counts come from syscfg as parenthesized values, so they can not be + * pasted into macro names and #if ladders are used to select the list. + */ +#define USBD_AUDIO_FU_CTRL \ + ((AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS) | \ + (AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS)) +#define USBD_AUDIO_FU_CTRLS_1 USBD_AUDIO_FU_CTRL, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_2 USBD_AUDIO_FU_CTRLS_1, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_3 USBD_AUDIO_FU_CTRLS_2, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_4 USBD_AUDIO_FU_CTRLS_3, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_5 USBD_AUDIO_FU_CTRLS_4, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_6 USBD_AUDIO_FU_CTRLS_5, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_7 USBD_AUDIO_FU_CTRLS_6, USBD_AUDIO_FU_CTRL +#define USBD_AUDIO_FU_CTRLS_8 USBD_AUDIO_FU_CTRLS_7, USBD_AUDIO_FU_CTRL + +#if USBD_AUDIO_OUT_CHANNELS == 1 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_1 +#elif USBD_AUDIO_OUT_CHANNELS == 2 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_2 +#elif USBD_AUDIO_OUT_CHANNELS == 3 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_3 +#elif USBD_AUDIO_OUT_CHANNELS == 4 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_4 +#elif USBD_AUDIO_OUT_CHANNELS == 5 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_5 +#elif USBD_AUDIO_OUT_CHANNELS == 6 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_6 +#elif USBD_AUDIO_OUT_CHANNELS == 7 +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_7 +#else +#define USBD_AUDIO_SPK_FU_CTRLS USBD_AUDIO_FU_CTRLS_8 +#endif + +#if USBD_AUDIO_IN_CHANNELS == 1 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_1 +#elif USBD_AUDIO_IN_CHANNELS == 2 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_2 +#elif USBD_AUDIO_IN_CHANNELS == 3 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_3 +#elif USBD_AUDIO_IN_CHANNELS == 4 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_4 +#elif USBD_AUDIO_IN_CHANNELS == 5 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_5 +#elif USBD_AUDIO_IN_CHANNELS == 6 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_6 +#elif USBD_AUDIO_IN_CHANNELS == 7 +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_7 +#else +#define USBD_AUDIO_MIC_FU_CTRLS USBD_AUDIO_FU_CTRLS_8 +#endif + +#if MYNEWT_VAL(USBD_AUDIO_VOLUME_CONTROL) +#define USBD_AUDIO_FU_LEN(_nch) TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(_nch) +#define USBD_AUDIO_FU_DESC(_unitid, _srcid, _ctrls) \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + , TUD_AUDIO20_DESC_FEATURE_UNIT(_unitid, _srcid, 0x00, _ctrls) +#define USBD_AUDIO_SPK_OT_SOURCE USBD_AUDIO_ENTITY_SPK_FEATURE_UNIT +#define USBD_AUDIO_MIC_OT_SOURCE USBD_AUDIO_ENTITY_MIC_FEATURE_UNIT +#else +#define USBD_AUDIO_FU_LEN(_nch) 0 +#define USBD_AUDIO_FU_DESC(_unitid, _srcid, _ctrls) +#define USBD_AUDIO_SPK_OT_SOURCE USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL +#define USBD_AUDIO_MIC_OT_SOURCE USBD_AUDIO_ENTITY_MIC_INPUT_TERMINAL +#endif + +/* + * Optional parts of the descriptor are defined as macros that expand to + * nothing when the part is not needed. Each part starts with a comma so + * it can follow the previous one. + */ + +/* Audio Control entities of speaker path */ +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#define USBD_AUDIO_AC_SPK_ENTITIES_LEN \ + (TUD_AUDIO20_DESC_INPUT_TERM_LEN + USBD_AUDIO_FU_LEN(USBD_AUDIO_OUT_CHANNELS) + \ + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN) +#define USBD_AUDIO_AC_SPK_ENTITIES \ + /* Input Terminal Descriptor(4.7.2.4) - USB stream from host */ \ + , TUD_AUDIO20_DESC_INPUT_TERM(USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL, AUDIO_TERM_TYPE_USB_STREAMING, \ + USBD_AUDIO_SPK_IT_ASSOC, USBD_AUDIO_ENTITY_CLOCK, USBD_AUDIO_OUT_CHANNELS, \ + USBD_AUDIO_CHANNEL_CONFIG(USBD_AUDIO_OUT_CHANNELS), 0x00, 0x0000, 0x00) \ + USBD_AUDIO_FU_DESC(USBD_AUDIO_ENTITY_SPK_FEATURE_UNIT, USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL, \ + USBD_AUDIO_SPK_FU_CTRLS) \ + /* Output Terminal Descriptor(4.7.2.5) - speaker */ \ + , TUD_AUDIO20_DESC_OUTPUT_TERM(USBD_AUDIO_ENTITY_SPK_OUTPUT_TERMINAL, USBD_AUDIO_SPK_TERMINAL_TYPE, 0x00, \ + USBD_AUDIO_SPK_OT_SOURCE, USBD_AUDIO_ENTITY_CLOCK, 0x0000, 0x00) +#else +#define USBD_AUDIO_AC_SPK_ENTITIES_LEN 0 +#define USBD_AUDIO_AC_SPK_ENTITIES +#endif + +/* Audio Control entities of microphone path */ +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#define USBD_AUDIO_AC_MIC_ENTITIES_LEN \ + (TUD_AUDIO20_DESC_INPUT_TERM_LEN + USBD_AUDIO_FU_LEN(USBD_AUDIO_IN_CHANNELS) + \ + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN) +#define USBD_AUDIO_AC_MIC_ENTITIES \ + /* Input Terminal Descriptor(4.7.2.4) - microphone */ \ + , TUD_AUDIO20_DESC_INPUT_TERM(USBD_AUDIO_ENTITY_MIC_INPUT_TERMINAL, USBD_AUDIO_MIC_TERMINAL_TYPE, \ + 0x00, USBD_AUDIO_ENTITY_CLOCK, USBD_AUDIO_IN_CHANNELS, \ + USBD_AUDIO_CHANNEL_CONFIG(USBD_AUDIO_IN_CHANNELS), 0x00, 0x0000, 0x00) \ + USBD_AUDIO_FU_DESC(USBD_AUDIO_ENTITY_MIC_FEATURE_UNIT, USBD_AUDIO_ENTITY_MIC_INPUT_TERMINAL, \ + USBD_AUDIO_MIC_FU_CTRLS) \ + /* Output Terminal Descriptor(4.7.2.5) - USB stream to host */ \ + , TUD_AUDIO20_DESC_OUTPUT_TERM(USBD_AUDIO_ENTITY_MIC_OUTPUT_TERMINAL, AUDIO_TERM_TYPE_USB_STREAMING, \ + USBD_AUDIO_MIC_OT_ASSOC, USBD_AUDIO_MIC_OT_SOURCE, USBD_AUDIO_ENTITY_CLOCK, \ + 0x0000, 0x00) +#else +#define USBD_AUDIO_AC_MIC_ENTITIES_LEN 0 +#define USBD_AUDIO_AC_MIC_ENTITIES +#endif + +#define USBD_AUDIO_AC_ENTITIES_LEN \ + (TUD_AUDIO20_DESC_CLK_SRC_LEN + USBD_AUDIO_AC_SPK_ENTITIES_LEN + USBD_AUDIO_AC_MIC_ENTITIES_LEN) + +/* Audio Control interrupt endpoint */ +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +#define USBD_AUDIO_AC_INT_EP_LEN TUD_AUDIO20_DESC_STD_AC_INT_EP_LEN +#define USBD_AUDIO_AC_INT_EP \ + /* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */ \ + , TUD_AUDIO20_DESC_STD_AC_INT_EP(USBD_AUDIO_INT_EP, USBD_AUDIO_EP_INTERVAL) +#else +#define USBD_AUDIO_AC_INT_EP_LEN 0 +#define USBD_AUDIO_AC_INT_EP +#endif + +/* Audio Streaming interface of speaker path */ +#if CFG_TUD_AUDIO_ENABLE_EP_OUT +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +/* Rate is driven by device clock, host adjusts to feedback. */ +#define USBD_AUDIO_EP_OUT_SYNC TUSB_ISO_EP_ATT_ASYNCHRONOUS +#define USBD_AUDIO_AS_OUT_FB_EP_LEN TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP_LEN +#define USBD_AUDIO_AS_OUT_FB_EP \ + /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ \ + , TUD_AUDIO20_DESC_STD_AS_ISO_FB_EP(USBD_AUDIO_FEEDBACK_EP, 4, USBD_AUDIO_EP_INTERVAL) +#else +/* Device adapts to the rate host sends data at. */ +#define USBD_AUDIO_EP_OUT_SYNC TUSB_ISO_EP_ATT_ADAPTIVE +#define USBD_AUDIO_AS_OUT_FB_EP_LEN 0 +#define USBD_AUDIO_AS_OUT_FB_EP +#endif +#define USBD_AUDIO_AS_OUT_DESC_LEN \ + (2 * 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 + USBD_AUDIO_AS_OUT_FB_EP_LEN) +#define USBD_AUDIO_AS_OUT_DESC(_itfnum) \ + /* Standard AS Interface Descriptor(4.9.1), alternate 0 - no bandwidth */ \ + , TUD_AUDIO20_DESC_STD_AS_INT(_itfnum, 0x00, 0x00, 0x00) \ + /* Standard AS Interface Descriptor(4.9.1), alternate 1 - streaming */ \ + , TUD_AUDIO20_DESC_STD_AS_INT(_itfnum, 0x01, 1 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP, 0x00) \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + , TUD_AUDIO20_DESC_CS_AS_INT(USBD_AUDIO_ENTITY_SPK_INPUT_TERMINAL, AUDIO20_CTRL_NONE, \ + AUDIO20_FORMAT_TYPE_I, AUDIO20_DATA_FORMAT_TYPE_I_PCM, USBD_AUDIO_OUT_CHANNELS, \ + USBD_AUDIO_CHANNEL_CONFIG(USBD_AUDIO_OUT_CHANNELS), 0x00) \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + , TUD_AUDIO20_DESC_TYPE_I_FORMAT(USBD_AUDIO_BYTES_PER_SAMPLE, USBD_AUDIO_SAMPLE_SIZE) \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + , TUD_AUDIO20_DESC_STD_AS_ISO_EP(USBD_AUDIO_OUT_EP, \ + (uint8_t)(TUSB_XFER_ISOCHRONOUS | USBD_AUDIO_EP_OUT_SYNC | TUSB_ISO_EP_ATT_DATA), \ + USBD_AUDIO_EP_OUT_SZ, USBD_AUDIO_EP_INTERVAL) \ + /* Class-Specific AS Isochronous Data Endpoint Descriptor(4.10.1.2) */ \ + , TUD_AUDIO20_DESC_CS_AS_ISO_EP(AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO20_CTRL_NONE, \ + AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, 0x0001) \ + USBD_AUDIO_AS_OUT_FB_EP +#else +#define USBD_AUDIO_AS_OUT_DESC_LEN 0 +#define USBD_AUDIO_AS_OUT_DESC(_itfnum) +#endif + +/* Audio Streaming interface of microphone path */ +#if CFG_TUD_AUDIO_ENABLE_EP_IN +#define USBD_AUDIO_AS_IN_DESC_LEN \ + (2 * 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 USBD_AUDIO_AS_IN_DESC(_itfnum) \ + /* Standard AS Interface Descriptor(4.9.1), alternate 0 - no bandwidth */ \ + , TUD_AUDIO20_DESC_STD_AS_INT(_itfnum, 0x00, 0x00, 0x00) \ + /* Standard AS Interface Descriptor(4.9.1), alternate 1 - streaming */ \ + , TUD_AUDIO20_DESC_STD_AS_INT(_itfnum, 0x01, 0x01, 0x00) \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + , TUD_AUDIO20_DESC_CS_AS_INT(USBD_AUDIO_ENTITY_MIC_OUTPUT_TERMINAL, AUDIO20_CTRL_NONE, \ + AUDIO20_FORMAT_TYPE_I, AUDIO20_DATA_FORMAT_TYPE_I_PCM, USBD_AUDIO_IN_CHANNELS, \ + USBD_AUDIO_CHANNEL_CONFIG(USBD_AUDIO_IN_CHANNELS), 0x00) \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + , TUD_AUDIO20_DESC_TYPE_I_FORMAT(USBD_AUDIO_BYTES_PER_SAMPLE, USBD_AUDIO_SAMPLE_SIZE) \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + , TUD_AUDIO20_DESC_STD_AS_ISO_EP(USBD_AUDIO_IN_EP, \ + (uint8_t)(TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), \ + USBD_AUDIO_EP_IN_SZ, USBD_AUDIO_EP_INTERVAL) \ + /* Class-Specific AS Isochronous Data Endpoint Descriptor(4.10.1.2) */ \ + , TUD_AUDIO20_DESC_CS_AS_ISO_EP(AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO20_CTRL_NONE, \ + AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, 0x0000) +#else +#define USBD_AUDIO_AS_IN_DESC_LEN 0 +#define USBD_AUDIO_AS_IN_DESC(_itfnum) +#endif + +/* Total length of audio function descriptors. */ +#define USBD_AUDIO_DESC_LEN \ + (TUD_AUDIO20_DESC_IAD_LEN + TUD_AUDIO20_DESC_STD_AC_LEN + TUD_AUDIO20_DESC_CS_AC_LEN + \ + USBD_AUDIO_AC_ENTITIES_LEN + USBD_AUDIO_AC_INT_EP_LEN + \ + USBD_AUDIO_AS_OUT_DESC_LEN + USBD_AUDIO_AS_IN_DESC_LEN) + +/* + * Audio function descriptors. + * _itfnum - number of Audio Control interface, streaming interfaces follow it + * (OUT first when both are present). + * _stridx - string descriptor index of Audio Control interface. + */ +#define USBD_AUDIO20_DESCRIPTOR(_itfnum, _stridx) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO20_DESC_IAD(_itfnum, USBD_AUDIO_ITF_COUNT, 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO20_DESC_STD_AC(_itfnum, CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP, _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO20_DESC_CS_AC(0x0200, USBD_AUDIO_FUNCTION_CATEGORY, USBD_AUDIO_AC_ENTITIES_LEN, AUDIO20_CTRL_NONE), \ + /* Clock Source Descriptor(4.7.2.1), fixed frequency readable by host */ \ + TUD_AUDIO20_DESC_CLK_SRC(USBD_AUDIO_ENTITY_CLOCK, AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, \ + (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), 0x00, 0x00) \ + USBD_AUDIO_AC_SPK_ENTITIES \ + USBD_AUDIO_AC_MIC_ENTITIES \ + USBD_AUDIO_AC_INT_EP \ + USBD_AUDIO_AS_OUT_DESC((_itfnum) + 1) \ + USBD_AUDIO_AS_IN_DESC((_itfnum) + 1 + CFG_TUD_AUDIO_ENABLE_EP_OUT) + +#else /* CFG_TUD_AUDIO */ + +#define USBD_AUDIO_ITF_COUNT 0 +#define USBD_AUDIO_DESC_LEN 0 + +#endif /* CFG_TUD_AUDIO */ + +// 5.2.2 Control Request Layout - was removed from TinyUSB +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 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; + +#ifdef __cplusplus +} +#endif + +#endif /* H_USBD_AUDIO_DESC_ */ diff --git a/hw/usb/tinyusb/std_descriptors/src/std_descriptors.c b/hw/usb/tinyusb/std_descriptors/src/std_descriptors.c index 79cdd57f7..0e37bff99 100755 --- a/hw/usb/tinyusb/std_descriptors/src/std_descriptors.c +++ b/hw/usb/tinyusb/std_descriptors/src/std_descriptors.c @@ -32,6 +32,7 @@ #include <os/util.h> #include <console/console.h> #include <hal/hal_gpio.h> +#include <usbd_audio_desc.h> #define USBD_PRODUCT_RELEASE_NUMBER MYNEWT_VAL(USBD_PRODUCT_RELEASE_NUMBER) @@ -73,6 +74,11 @@ enum usb_desc_ix { #else #define BTH_IF_STR_IX 0 #endif +#if defined MYNEWT_VAL_USBD_AUDIO_DESCRIPTOR_STRING + AUDIO_IF_STR_IX, +#else +#define AUDIO_IF_STR_IX 0 +#endif #if defined MYNEWT_VAL_USBD_DFU_SLOT_NAME DFU_SLOT_NAME_IF_STR_IX, #endif @@ -208,9 +214,9 @@ tusb_desc_device_qualifier_t const desc_device_qualifier = { .bDeviceClass = TUD_BT_APP_CLASS, .bDeviceSubClass = TUD_BT_APP_SUBCLASS, .bDeviceProtocol = TUD_BT_PROTOCOL_PRIMARY_CONTROLLER, -#elif CFG_TUD_CDC +#elif CFG_TUD_CDC || CFG_TUD_AUDIO /* - * Use Interface Association Descriptor (IAD) for CDC + * Use Interface Association Descriptor (IAD) for CDC and Audio * As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) */ .bDeviceClass = TUSB_CLASS_MISC, @@ -286,6 +292,16 @@ enum { ITF_NUM_HID, #endif +#if CFG_TUD_AUDIO + ITF_NUM_AUDIO_CONTROL, +#if CFG_TUD_AUDIO_ENABLE_EP_OUT + ITF_NUM_AUDIO_STREAMING_OUT, +#endif +#if CFG_TUD_AUDIO_ENABLE_EP_IN + ITF_NUM_AUDIO_STREAMING_IN, +#endif +#endif + #if CFG_TUD_DFU ITF_NUM_DFU, #endif @@ -304,6 +320,7 @@ enum { CFG_TUD_MSC * TUD_MSC_DESC_LEN + \ CFG_TUD_HID * TUD_HID_DESC_LEN + \ CFG_TUD_BTH * TUD_BTH_DESC_LEN + \ + USBD_AUDIO_DESC_LEN + \ CFG_TUD_DFU * TUD_DFU_DESC_LEN(1) + \ CFG_TUD_DFU_RUNTIME * TUD_DFU_RT_DESC_LEN + \ 0) @@ -348,6 +365,10 @@ const uint8_t desc_configuration[] = { USBD_HID_REPORT_EP, USBD_HID_REPORT_EP_SIZE, USBD_HID_REPORT_EP_INTERVAL), #endif +#if CFG_TUD_AUDIO + USBD_AUDIO20_DESCRIPTOR(ITF_NUM_AUDIO_CONTROL, AUDIO_IF_STR_IX), +#endif + #if CFG_TUD_DFU TUD_DFU_DESCRIPTOR(ITF_NUM_DFU, 1, DFU_SLOT_NAME_IF_STR_IX, DFU_ATTR_CAN_DOWNLOAD, CFG_TUD_DFU_DETACH_TIMEOUT, CFG_TUD_DFU_XFER_BUFSIZE), @@ -359,6 +380,12 @@ const uint8_t desc_configuration[] = { #endif }; +#if CFG_TUD_AUDIO +/* Audio descriptor has many parts, make sure declared length matches. */ +TU_VERIFY_STATIC(sizeof(desc_configuration) == CONFIG_TOTAL_LEN, + "Configuration descriptor length mismatch"); +#endif + /** * Invoked when received GET CONFIGURATION DESCRIPTOR * Application return pointer to descriptor @@ -393,6 +420,9 @@ const char *string_desc_arr[] = { #if defined MYNEWT_VAL_USBD_BTH_DESCRIPTOR_STRING MYNEWT_VAL(USBD_BTH_DESCRIPTOR_STRING), #endif +#if defined MYNEWT_VAL_USBD_AUDIO_DESCRIPTOR_STRING + MYNEWT_VAL(USBD_AUDIO_DESCRIPTOR_STRING), +#endif #if defined MYNEWT_VAL_USBD_DFU_SLOT_NAME MYNEWT_VAL(USBD_DFU_SLOT_NAME), #endif diff --git a/hw/usb/tinyusb/std_descriptors/syscfg.yml b/hw/usb/tinyusb/std_descriptors/syscfg.yml index 8e6ea2cb7..b0650215a 100644 --- a/hw/usb/tinyusb/std_descriptors/syscfg.yml +++ b/hw/usb/tinyusb/std_descriptors/syscfg.yml @@ -223,6 +223,121 @@ syscfg.defs: description: MSC data endpoint buffer size value: + USBD_AUDIO: + description: > + Enable USB Audio Class 2.0 function in TinyUSB stack. + IN - microphone (device sends audio to host), + OUT - speaker (host sends audio to device), + IN_OUT - headset (both directions, single clock source), + NONE - no audio function. + This adds descriptors to USB configuration, application has to + implement TinyUSB audio class callbacks (tud_audio_*_cb). + Entity IDs used in descriptors are defined in usbd_audio_desc.h. + value: NONE + choices: + - NONE + - IN + - OUT + - IN_OUT + USBD_AUDIO_DESCRIPTOR_STRING: + description: String for Audio Control interface + value: + USBD_AUDIO_SAMPLE_RATE: + description: > + Audio sampling frequency in Hz, same for microphone and speaker. + value: 48000 + USBD_AUDIO_SAMPLE_SIZE: + description: > + Number of valid bits in each audio sample (bit resolution). + value: 16 + range: 8..32 + USBD_AUDIO_BYTES_PER_SAMPLE: + description: > + Number of bytes each sample occupies in USB packet (subslot size, + 1-4). Leave empty to use smallest size that fits + USBD_AUDIO_SAMPLE_SIZE. Set to 4 for 24 bit samples in 32 bit + slots. + value: + USBD_AUDIO_IN_CHANNELS: + description: > + Number of microphone (IN) channels. Values 1 and 2 are reported + to host as mono and stereo, other values as channels without + spatial location. + value: 1 + range: 1..32 + USBD_AUDIO_OUT_CHANNELS: + description: > + Number of speaker (OUT) channels. Values 1 and 2 are reported + to host as mono and stereo, other values as channels without + spatial location. + value: 2 + range: 1..32 + USBD_AUDIO_IN_TERMINAL_TYPE: + description: > + Terminal type of microphone input terminal, as AUDIO_TERM_TYPE_IN_* + constant from TinyUSB audio.h or numeric value from USB Audio + Terminal Types specification (0x0201 - generic microphone, + 0x0202 - desktop, 0x0203 - personal, 0x0204 - omni-directional, + 0x0205 - microphone array). + Empty for AUDIO_TERM_TYPE_IN_GENERIC_MIC. + value: + USBD_AUDIO_OUT_TERMINAL_TYPE: + description: > + Terminal type of speaker output terminal, as AUDIO_TERM_TYPE_OUT_* + constant from TinyUSB audio.h or numeric value from USB Audio + Terminal Types specification (0x0301 - generic speaker, + 0x0302 - headphones, 0x0304 - desktop speaker, 0x0305 - room + speaker, 0x0306 - communication speaker, 0x0307 - LFE speaker). + Empty for AUDIO_TERM_TYPE_OUT_HEADPHONES when USBD_AUDIO is IN_OUT + and AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER otherwise. + value: + USBD_AUDIO_VOLUME_CONTROL: + description: > + Add feature unit with mute and volume controls (master and per + channel) to microphone and speaker path. Application has to + handle requests for USBD_AUDIO_ENTITY_SPK_FEATURE_UNIT and + USBD_AUDIO_ENTITY_MIC_FEATURE_UNIT. Supports up to 8 channels. + value: 1 + USBD_AUDIO_FEEDBACK: + description: > + Add feedback endpoint to speaker path. Speaker endpoint is then + asynchronous and device reports its actual sampling rate to host + (see tud_audio_feedback_params_cb()). Without feedback endpoint + speaker endpoint is adaptive and device has to follow host's rate. + value: 0 + USBD_AUDIO_OUT_EP: + description: > + Speaker (OUT) isochronous endpoint number. + Empty for default: 8 on nRF5x (only isochronous endpoint), + 1 otherwise. + value: + USBD_AUDIO_IN_EP: + description: > + Microphone (IN) isochronous endpoint number. + Empty for default: 8 on nRF5x (only isochronous endpoint), + 1 otherwise. + value: + USBD_AUDIO_FEEDBACK_EP: + description: > + Feedback (IN) isochronous endpoint number, must differ from + USBD_AUDIO_IN_EP when both are used. + Empty for default: 8 on nRF5x, 2 otherwise. + value: + USBD_AUDIO_INT_EP: + description: > + Audio Control interrupt (IN) endpoint number used to notify host + about control changes. Empty for no interrupt endpoint. + value: + USBD_AUDIO_IN_BUFFER_PACKETS: + description: > + Size of TinyUSB software FIFO for microphone data in 1 ms + packets. TinyUSB flow control for IN endpoint requires at least 4. + value: 4 + USBD_AUDIO_OUT_BUFFER_PACKETS: + description: > + Size of TinyUSB software FIFO for speaker data in 1 ms packets. + value: 4 + USBD_WINDOWS_COMP_ID: description: > Add Windows compatibility descriptor.
