diff --git a/class/audio/usb_audio.h b/class/audio/usb_audio.h index a0c4544b..617bc3ca 100644 --- a/class/audio/usb_audio.h +++ b/class/audio/usb_audio.h @@ -22,8 +22,7 @@ #define AUDIO_SUBCLASS_MIDISTREAMING 0x03 #define AUDIO_PROTOCOL_UNDEFINED 0x00 -#define AUDIO_PROTOCOLv20 0x20 /* IP version 2.0 */ -#define AUDIO_PROTOCOLv20_BCD 0x0200 /* IP version 2.0 (BCD) */ +#define AUDIO_PROTOCOLv20 0x20 /* IP version 2.0 */ /** Audio Class-Specific Request Codes * Refer to Table A-9 from audio10.pdf @@ -41,6 +40,11 @@ #define AUDIO_REQUEST_GET_MEM 0x85 #define AUDIO_REQUEST_GET_STAT 0xFF +/** Audio Class-Specific Request Codes + * Refer from audio20_final.pdf + */ +#define AUDIO_REQUEST_CUR 0x01 +#define AUDIO_REQUEST_RANGE 0x02 /** Audio Class-Specific Control Interface Descriptor Subtypes * Refer to Table A-5 from audio10.pdf */ @@ -242,6 +246,23 @@ #define AUDIO_FU_CONTROL_OVERFLOW 0x0f #define AUDIO_FU_CONTROL_LATENCY 0x10 +#define AUDIO_V2_FU_CONTROL_UNDEF 0x00 +#define AUDIO_V2_FU_CONTROL_MUTE (0x03 << 0) +#define AUDIO_V2_FU_CONTROL_VOLUME (0x03 << 2) +#define AUDIO_V2_FU_CONTROL_BASS (0x03 << 4) +#define AUDIO_V2_FU_CONTROL_MID (0x03 << 6) +#define AUDIO_V2_FU_CONTROL_TREBLE (0x03 << 8) +#define AUDIO_V2_FU_CONTROL_EQUALIZER (0x03 << 10) +#define AUDIO_V2_FU_CONTROL_AGC (0x03 << 12) +#define AUDIO_V2_FU_CONTROL_DELAY (0x03 << 14) +#define AUDIO_V2_FU_CONTROL_BASS_BOOST (0x03 << 16) +#define AUDIO_V2_FU_CONTROL_LOUDNESS (0x03 << 18) +#define AUDIO_V2_FU_CONTROL_INP_GAIN (0x03 << 20) +#define AUDIO_V2_FU_CONTROL_INP_GAIN_PAD (0x03 << 22) +#define AUDIO_V2_FU_CONTROL_PHASE_INVERT (0x03 << 24) +#define AUDIO_V2_FU_CONTROL_UNDERFLOW (0x03 << 26) +#define AUDIO_V2_FU_CONTROL_OVERFLOW (0x03 << 28) + /* Parametric Equalizer Section Effect Unit Control Selectors */ #define AUDIO_PE_CONTROL_UNDEF 0x00 #define AUDIO_PE_CONTROL_ENABLE 0x01 @@ -390,11 +411,9 @@ #define AUDIO_DTSD_CONTROL_DECODE_ERR 0x03 /* Endpoint Control Selectors */ - -#define AUDIO_EP_CONTROL_UNDEF 0x00 -#define AUDIO_EP_CONTROL_PITCH 0x01 -#define AUDIO_EP_CONTROL_OVERRUN 0x02 -#define AUDIO_EP_CONTROL_UNDERRUN 0x03 +#define AUDIO_EP_CONTROL_UNDEF 0x00 +#define AUDIO_EP_CONTROL_SAMPLING_FEQ 0x01 +#define AUDIO_EP_CONTROL_PITCH 0x02 /* Encoder Error Codes */ @@ -581,7 +600,7 @@ struct audio_cs_if_ac_header_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubtype; - uint16_t bcdAUDIO; + uint16_t bcdADC; uint16_t wTotalLength; uint8_t bInCollection; uint8_t baInterfaceNr[]; @@ -624,11 +643,11 @@ struct audio_cs_if_ac_feature_unit_descriptor { uint8_t bUnitID; uint8_t bSourceID; uint8_t bControlSize; - // uint8_t bmaControls[]; + uint8_t bmaControls[1]; uint8_t iFeature; } __PACKED; -#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(n) (7 + n) +#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + ch * n) struct audio_cs_if_as_general_descriptor { uint8_t bLength; @@ -680,7 +699,7 @@ struct audio_cs_ep_ep_general_descriptor { #define AUDIO_SIZEOF_CS_EP_GENERAL_DESC (7) // clang-format off -#define AUDIO_AC_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, bcdADC, wTotalLength, stridx, bInCollection, ...) \ +#define AUDIO_AC_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, wTotalLength, stridx, ...) \ /* Interface Association Descriptor */ \ 0x08, \ USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \ @@ -703,9 +722,9 @@ struct audio_cs_ep_ep_general_descriptor { 0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ \ - WBVAL(bcdADC), /* bcdADC */ \ + WBVAL(0x0100), /* bcdADC */ \ WBVAL(wTotalLength), /* wTotalLength */ \ - bInCollection, /* bInCollection */ \ + PP_NARG(__VA_ARGS__), /* bInCollection */ \ __VA_ARGS__ /* baInterfaceNr */ #define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n) @@ -742,7 +761,7 @@ struct audio_cs_ep_ep_general_descriptor { __VA_ARGS__, /* bmaControls(0) Mute */ \ 0x00 /* iTerminal */ -#define AUDIO_AS_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bEndpointAddress, wMaxPacketSize, bInterval, bSamFreqType, ...) \ +#define AUDIO_AS_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bEndpointAddress, wMaxPacketSize, bInterval, ...) \ 0x09, /* bLength */ \ USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ bInterfaceNumber, /* bInterfaceNumber */ \ @@ -766,8 +785,7 @@ struct audio_cs_ep_ep_general_descriptor { AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \ bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \ 0x01, /* bDelay */ \ - 0x01, /* wFormatTag : AUDIO_FORMAT_PCM */ \ - 0x00, \ + WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag : AUDIO_FORMAT_PCM */ \ 0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \ AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \ @@ -775,24 +793,304 @@ struct audio_cs_ep_ep_general_descriptor { bNrChannels, /* bNrChannels */ \ 0x02, /* bSubFrameSize : 2 Bytes per audio subframe */ \ 0x10, /* bBitResolution : 16 bits per sample */ \ - bSamFreqType, /* bSamFreqType : only one frequency supported */ \ + (PP_NARG(__VA_ARGS__)/3), /* bSamFreqType : only one frequency supported */ \ __VA_ARGS__, /* tSamFreq : Audio sampling frequency coded on 3 bytes */ \ 0x09, /* bLength */ \ USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \ bEndpointAddress, /* bEndpointAddress : IN endpoint 1 */ \ 0x01, /* bmAttributes */ \ WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \ - 0x04, /* bInterval : one packet per frame */ \ + bInterval, /* bInterval : one packet per frame */ \ 0x00, /* bRefresh */ \ 0x00, /* bSynchAddress */ \ 0x07, /* bLength */ \ AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \ AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \ - 0x00, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \ + AUDIO_EP_CONTROL_SAMPLING_FEQ, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \ 0x00, /* bLockDelayUnits */ \ 0x00, /* wLockDelay */ \ 0x00 -// clang-format on + #define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07) +struct audio_v2_channel_cluster_descriptor { + uint8_t bNrChannels; + uint32_t bmChannelConfig; + uint8_t iChannelNames; +} __PACKED; + +#define AUDIO_V2_SIZEOF_CHANNEL_CLUSTER_DESC (6) + +struct audio_v2_cs_if_ac_header_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint16_t bcdADC; + uint8_t bCategory; + uint16_t wTotalLength; + uint8_t bmControls; +} __PACKED; + +#define AUDIO_V2_SIZEOF_AC_HEADER_DESC (9) + +struct audio_v2_cs_if_ac_clock_source_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bClockID; + uint8_t bmAttributes; + uint8_t bmControls; + uint8_t bAssocTerminal; + uint8_t iClockSource; +} __PACKED; + +#define AUDIO_SIZEOF_AC_CLOCK_SOURCE_DESC (8) + +struct audio_v2_cs_if_ac_clock_selector_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bClockID; + uint8_t bNrInPins; + uint8_t baCSourceID[1]; + uint8_t iClockSelector; +} __PACKED; + +#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(n) (7 + n) + +struct audio_v2_cs_if_ac_clock_multiplier_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bClockID; + uint8_t bCSourceID; + uint8_t bmControls; + uint8_t iClockMultiplier; +} __PACKED; + +#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC() (7) + +struct audio_v2_cs_if_ac_input_terminal_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bCSourceID; + uint8_t bNrChannels; + uint32_t wChannelConfig; + uint8_t iChannelNames; + uint16_t bmControls; + uint8_t iTerminal; +} __PACKED; + +#define AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC (17) + +struct audio_v2_cs_if_ac_output_terminal_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalID; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bSourceID; + uint8_t bCSourceID; + uint16_t bmControls; + uint8_t iTerminal; +} __PACKED; + +#define AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC (12) + +struct audio_v2_cs_if_ac_feature_unit_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bUnitID; + uint8_t bSourceID; + uint32_t bmaControls[1]; + uint8_t iFeature; +} __PACKED; + +#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(ch) (6 + ch * 4) + +struct audio_v2_cs_if_as_general_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bTerminalLink; + uint8_t bmControls; + uint8_t bFormatType; + uint32_t bmFormats; + uint8_t bNrChannels; + uint32_t bmChannelConfig; + uint8_t iChannelNames; +} __PACKED; + +#define AUDIO_V2_SIZEOF_AS_GENERAL_DESC (16) + +struct audio_v2_control_range1_param_block { + uint16_t wNumSubRanges; + struct + { + uint8_t bMin; + uint8_t bMax; + uint8_t bRes; + }subrange[]; +} __PACKED; + +struct audio_v2_control_range2_param_block { + uint16_t wNumSubRanges; + struct + { + uint16_t wMin; + uint16_t wMax; + uint16_t wRes; + }subrange[]; +} __PACKED; + +struct audio_v2_control_range3_param_block { + uint16_t wNumSubRanges; + struct + { + uint32_t dMin; + uint32_t dMax; + uint32_t dRes; + }subrange[]; +} __PACKED; + +#define AUDIO_V2_AC_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, wTotalLength, bCategory, bmControls, stridx) \ + /* Interface Association Descriptor */ \ + 0x08, \ + USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \ + bFirstInterface, \ + bInterfaceCount, \ + USB_DEVICE_CLASS_AUDIO, \ + AUDIO_SUBCLASS_AUDIOCONTROL, \ + AUDIO_PROTOCOLv20, \ + 0x00, \ + /* ------------------ AudioControl Interface ------------------ */\ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + bFirstInterface, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x00, /* bNumEndpoints */ \ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \ + AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ \ + AUDIO_PROTOCOLv20, /* bInterfaceProtocol */ \ + stridx, /* iInterface */ \ + 0x09, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ \ + WBVAL(0x0200), /* bcdADC */ \ + bCategory, /* bCategory */ \ + WBVAL(wTotalLength), /* wTotalLength */ \ + bmControls /* bmControls */ \ + +#define AUDIO_V2_AC_DESCRIPTOR_INIT_LEN (0x08 + 0x09 + 0x09) + +#define AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(bClockID, bmAttributes, bmControls) \ + 0x08, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_CONTROL_CLOCK_SOURCE, /* bDescriptorSubtype */ \ + bClockID, /* bClockID */ \ + bmAttributes, /* bmAttributes */ \ + bmControls, /* bmControls */ \ + 0x00, /* bAssocTerminal */ \ + 0x00 /* iClockSource */ + +#define AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bCSourceID, bNrChannels, wChannelConfig, bmControls) \ + 0x11, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ \ + bTerminalID, /* bTerminalID */ \ + WBVAL(wTerminalType), /* wTerminalType : Microphone 0x0201 */ \ + 0x00, /* bAssocTerminal */ \ + bCSourceID, /* bCSourceID */ \ + bNrChannels, /* bNrChannels */ \ + DBVAL(wChannelConfig), /* wChannelConfig : Mono sets no position bits */ \ + 0x00, /* iChannelNames */ \ + WBVAL(bmControls), /* bmControls */ \ + 0x00 /* iTerminal */ + +#define AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bSourceID, bCSourceID, bmControls) \ + 0x0c, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ \ + bTerminalID, /* bTerminalID */ \ + WBVAL(wTerminalType), /* wTerminalType : USB Streaming */ \ + 0x00, /* bAssocTerminal */ \ + bSourceID, /* bSourceID */ \ + bCSourceID, /* bCSourceID */ \ + WBVAL(bmControls), /* bmControls */ \ + 0x00 /* iTerminal */ + +#define AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(bUnitID, bSourceID, ...) \ + 0x06 + (PP_NARG(__VA_ARGS__)), /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */ \ + bUnitID, /* bUnitID */ \ + bSourceID, /* bSourceID */ \ + __VA_ARGS__, /* bmaControls(0) Mute */ \ + 0x00 /* iTerminal */ + +// clang-format on + +#define AUDIO_V2_AS_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bmChannelConfig, bSubslotSize, bBitResolution, bEndpointAddress, wMaxPacketSize, bInterval) \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + bInterfaceNumber, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x00, /* bNumEndpoints */ \ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \ + AUDIO_PROTOCOLv20, /* bInterfaceProtocol */ \ + 0x00, /* iInterface */ \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + bInterfaceNumber, /* bInterfaceNumber */ \ + 0x01, /* bAlternateSetting */ \ + 0x01, /* bNumEndpoints */ \ + USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \ + AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ \ + AUDIO_PROTOCOLv20, /* bInterfaceProtocol */ \ + 0x00, /* iInterface */ \ + 0x10, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \ + bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \ + 0x00, /* bmControls */ \ + AUDIO_FORMAT_TYPE_I, /* bFormatType : AUDIO_FORMAT_TYPE_I */ \ + DBVAL(AUDIO_FORMAT_PCM), /* bmFormats PCM */ \ + bNrChannels, /* bNrChannels */ \ + DBVAL(bmChannelConfig), /* bmChannelConfig */ \ + 0x00, /* iChannelNames */ \ + 0x06, /* bLength */ \ + AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \ + AUDIO_FORMAT_TYPE_I, /* bFormatType */ \ + bSubslotSize, /* bSubslotSize */ \ + bBitResolution, /* bBitResolution */ \ + 0x07, /* bLength */ \ + 0x05, /* bDescriptorType */ \ + bEndpointAddress, /* bEndpointAddress 3 out endpoint for Audio */ \ + 0x09, /* bmAttributes */ \ + WBVAL(wMaxPacketSize), /* XXXX wMaxPacketSize in Bytes (Freq(Samples)*2(Stereo)*2(HalfWord)) */ \ + bInterval, /* bInterval */ \ + 0x08, /* bLength */ \ + AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \ + AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \ + 0x00, /* bmAttributes */ \ + 0x00, /* bmControls */ \ + 0x00, /* bLockDelayUnits */ \ + 0x00, /* wLockDelay */ \ + 0x00 + +#define AUDIO_V2_AS_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08) + +#define AUDIO_SAMPLE_FREQ_NUM(num) (uint8_t)(num), (uint8_t)((num >> 8)) +#define AUDIO_SAMPLE_FREQ_3B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16)) +#define AUDIO_SAMPLE_FREQ_4B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), \ + (uint8_t)((frq >> 16)), (uint8_t)((frq >> 24)) + #endif /* _USB_AUDIO_H_ */ diff --git a/class/audio/usbd_audio.c b/class/audio/usbd_audio.c index a7a5817a..029ac4c7 100644 --- a/class/audio/usbd_audio.c +++ b/class/audio/usbd_audio.c @@ -23,13 +23,82 @@ #include "usbd_core.h" #include "usbd_audio.h" -struct usbd_audio_control_info { +struct usbd_audio_volume_info { uint16_t vol_min; uint16_t vol_max; uint16_t vol_res; uint16_t vol_current; - uint8_t mute; -} audio_control_info = { 0xdb00, 0x0000, 0x0100, 0xf600, 0 }; +}; + +struct usbd_audio_v1_feature_unit_control { + struct usbd_audio_volume_info volume[CONFIG_USBDEV_AUDIO_MAX_CHANNEL]; + uint8_t mute[CONFIG_USBDEV_AUDIO_MAX_CHANNEL]; + uint8_t automatic_gain[CONFIG_USBDEV_AUDIO_MAX_CHANNEL]; +}; + +struct audio_v2_control_range2_param_block_default { + uint16_t wNumSubRanges; + struct + { + uint16_t wMin; + uint16_t wMax; + uint16_t wRes; + } subrange[CONFIG_USBDEV_AUDIO_MAX_CHANNEL]; +} __PACKED; + +struct usbd_audio_v2_feature_unit_control { + uint32_t volume_bCUR; + uint32_t mute_bCUR; + struct audio_v2_control_range2_param_block_default volume; + uint8_t mute[CONFIG_USBDEV_AUDIO_MAX_CHANNEL]; +}; + +struct audio_entity_info { + usb_slist_t list; + uint8_t bDescriptorSubtype; + uint8_t bEntityId; + void *priv; +}; + +static usb_slist_t usbd_audio_entity_info_head = USB_SLIST_OBJECT_INIT(usbd_audio_entity_info_head); + +#if CONFIG_USBDEV_AUDIO_VERSION < 0x0200 +static int audio_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) +{ + uint8_t control_selector; + uint32_t sampling_freq; + uint8_t pitch_enable; + uint8_t ep; + + if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_ENDPOINT) { + control_selector = HI_BYTE(setup->wValue); + ep = LO_BYTE(setup->wIndex); + + switch (setup->bRequest) { + case AUDIO_REQUEST_SET_CUR: + switch (control_selector) { + case AUDIO_EP_CONTROL_SAMPLING_FEQ: + memcpy(&sampling_freq, *data, *len); + USB_LOG_INFO("Set ep %02x %d Hz\r\n", ep, (int)sampling_freq); + usbd_audio_set_sampling_freq(ep, sampling_freq); + return 0; + case AUDIO_EP_CONTROL_PITCH: + pitch_enable = (*data)[0]; + usbd_audio_set_pitch(ep, pitch_enable); + return 0; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); + break; + } + } + return -1; +} +#endif static int audio_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) { @@ -37,69 +106,236 @@ static int audio_class_request_handler(struct usb_setup_packet *setup, uint8_t * "bRequest 0x%02x\r\n", setup->bRequest); - switch (setup->bRequest) { - case AUDIO_REQUEST_SET_CUR: + struct audio_entity_info *current_entity_info = NULL; + usb_slist_t *i; + uint8_t entity_id; + uint8_t control_selector; + uint8_t ch; + uint8_t mute; + uint16_t volume; + const char *mute_string[2] = { "off", "on" }; - if (LO_BYTE(setup->wValue) == 0x01) { - if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) { - memcpy(&audio_control_info.mute, *data, *len); - usbd_audio_set_mute(audio_control_info.mute); - } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) { - memcpy(&audio_control_info.vol_current, *data, *len); - int vol; - if (audio_control_info.vol_current == 0) { - vol = 100; - } else { - vol = (audio_control_info.vol_current - 0xDB00 + 1) * 100 / (0xFFFF - 0xDB00); - } - usbd_audio_set_volume(vol); - USB_LOG_INFO("current audio volume:%d\r\n", vol); - } - } + entity_id = HI_BYTE(setup->wIndex); + control_selector = HI_BYTE(setup->wValue); + ch = LO_BYTE(setup->wValue); - break; - - case AUDIO_REQUEST_GET_CUR: - if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) { - *data = (uint8_t *)&audio_control_info.mute; - *len = 1; - } else if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_VOLUME) { - *data = (uint8_t *)&audio_control_info.vol_current; - *len = 2; - } - - break; - - case AUDIO_REQUEST_SET_RES: - break; - - case AUDIO_REQUEST_SET_MEM: - break; - - case AUDIO_REQUEST_GET_MIN: - *data = (uint8_t *)&audio_control_info.vol_min; - *len = 2; - break; - - case AUDIO_REQUEST_GET_MAX: - *data = (uint8_t *)&audio_control_info.vol_max; - *len = 2; - break; - - case AUDIO_REQUEST_GET_RES: - *data = (uint8_t *)&audio_control_info.vol_res; - *len = 2; - break; - case AUDIO_REQUEST_GET_MEM: - *data[0] = 0; - *len = 1; - break; - - default: - USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); - return -1; + if (ch > (CONFIG_USBDEV_AUDIO_MAX_CHANNEL - 1)) { + return -2; } + usb_slist_for_each(i, &usbd_audio_entity_info_head) + { + struct audio_entity_info *tmp_entity_info = usb_slist_entry(i, struct audio_entity_info, list); + if (tmp_entity_info->bEntityId == entity_id) { + current_entity_info = tmp_entity_info; + break; + } + } + + if (current_entity_info == NULL) { + return -2; + } + + if (current_entity_info->bDescriptorSubtype == AUDIO_CONTROL_FEATURE_UNIT) { +#if CONFIG_USBDEV_AUDIO_VERSION < 0x0200 + struct usbd_audio_v1_feature_unit_control *current_control = (struct usbd_audio_v1_feature_unit_control *)current_entity_info->priv; + + float volume2db = 0.0; + + switch (control_selector) { + case AUDIO_FU_CONTROL_MUTE: + switch (setup->bRequest) { + case AUDIO_REQUEST_SET_CUR: + mute = (*data)[0]; + current_control->mute[ch] = mute; + USB_LOG_INFO("Set ch[%d] mute %s\r\n", ch, mute_string[mute]); + usbd_audio_set_mute(ch, mute); + break; + case AUDIO_REQUEST_GET_CUR: + (*data)[0] = current_control->mute[ch]; + break; + default: + USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } + + break; + case AUDIO_FU_CONTROL_VOLUME: + switch (setup->bRequest) { + case AUDIO_REQUEST_SET_CUR: + volume = (((uint16_t)(*data)[1] << 8) | ((uint16_t)(*data)[0])); + current_control->volume[ch].vol_current = volume; + + if (volume < 0x8000) { + volume2db = 0.00390625 * volume; + } else if (volume > 0x8000) { + volume2db = -0.00390625 * (0xffff - volume + 1); + } + + USB_LOG_INFO("Set ch[%d] %0.4f dB\r\n", ch, volume2db); + usbd_audio_set_volume(ch, volume2db); + break; + case AUDIO_REQUEST_GET_CUR: + memcpy(*data, ¤t_control->volume[ch].vol_current, 2); + *len = 2; + break; + + case AUDIO_REQUEST_GET_MIN: + memcpy(*data, ¤t_control->volume[ch].vol_min, 2); + *len = 2; + break; + + case AUDIO_REQUEST_GET_MAX: + memcpy(*data, ¤t_control->volume[ch].vol_max, 2); + *len = 2; + break; + + case AUDIO_REQUEST_GET_RES: + memcpy(*data, ¤t_control->volume[ch].vol_res, 2); + *len = 2; + break; + default: + USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } +#else + struct usbd_audio_v2_feature_unit_control *control = (struct usbd_audio_v2_feature_unit_control *)current_entity_info->priv; + + switch (setup->bRequest) { + case AUDIO_REQUEST_CUR: + switch (control_selector) { + case AUDIO_FU_CONTROL_MUTE: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + (*data)[0] = control->mute_bCUR; + *len = 1; + } else { + mute = (*data)[0]; + USB_LOG_INFO("Set ch[%d] mute %s\r\n", ch, mute_string[mute]); + usbd_audio_set_mute(ch, mute); + } + break; + case AUDIO_FU_CONTROL_VOLUME: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + (*data)[0] = control->volume_bCUR & 0XFF; + (*data)[1] = (control->volume_bCUR >> 8) & 0xff; + *len = 2; + } else { + volume = (((uint16_t)(*data)[1] << 8) | ((uint16_t)(*data)[0])); + control->volume_bCUR = volume; + USB_LOG_INFO("Set ch[%d] %d dB\r\n", ch, volume); + usbd_audio_set_volume(ch, volume); + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } + break; + case AUDIO_REQUEST_RANGE: + switch (control_selector) { + case AUDIO_FU_CONTROL_VOLUME: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + *((uint16_t *)(*data + 0)) = control->volume.wNumSubRanges; + *((uint16_t *)(*data + 2)) = control->volume.subrange[ch].wMin; + *((uint16_t *)(*data + 4)) = control->volume.subrange[ch].wMax; + *((uint16_t *)(*data + 6)) = control->volume.subrange[ch].wRes; + *len = 8; + } else { + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } + + break; + default: + USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } +#endif + } +#if CONFIG_USBDEV_AUDIO_VERSION >= 0x0200 + else if (current_entity_info->bDescriptorSubtype == AUDIO_CONTROL_CLOCK_SOURCE) { + switch (setup->bRequest) { + case AUDIO_REQUEST_CUR: + switch (control_selector) { + case AUDIO_CS_CONTROL_SAM_FREQ: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + uint8_t param_block[] = { + 0x80, + 0xbb, + 0x00, + 0x00 + }; + memcpy(*data, param_block, sizeof(param_block)); + *len = 4; + } else { + uint32_t sampling_freq; + memcpy(&sampling_freq, *data, setup->wLength); + USB_LOG_INFO("Set ch[%d] %d Hz\r\n", ch, (int)sampling_freq); + usbd_audio_set_sampling_freq(ch, sampling_freq); + } + break; + case AUDIO_CS_CONTROL_CLOCK_VALID: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + (*data)[0] = 1; + *len = 1; + } else { + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } + break; + case AUDIO_REQUEST_RANGE: + switch (control_selector) { + case AUDIO_CS_CONTROL_SAM_FREQ: + if (setup->bmRequestType & USB_REQUEST_DIR_MASK) { + uint8_t param_block[] = { + AUDIO_SAMPLE_FREQ_NUM(6), + AUDIO_SAMPLE_FREQ_4B(16000), + AUDIO_SAMPLE_FREQ_4B(16000), + AUDIO_SAMPLE_FREQ_4B(0x00), + AUDIO_SAMPLE_FREQ_4B(48000), + AUDIO_SAMPLE_FREQ_4B(48000), + AUDIO_SAMPLE_FREQ_4B(0x00), + AUDIO_SAMPLE_FREQ_4B(96000), + AUDIO_SAMPLE_FREQ_4B(96000), + AUDIO_SAMPLE_FREQ_4B(0x00), + AUDIO_SAMPLE_FREQ_4B(44100), + AUDIO_SAMPLE_FREQ_4B(44100), + AUDIO_SAMPLE_FREQ_4B(0x00), + AUDIO_SAMPLE_FREQ_4B(8000), + AUDIO_SAMPLE_FREQ_4B(8000), + AUDIO_SAMPLE_FREQ_4B(0x00), + AUDIO_SAMPLE_FREQ_4B(32000), + AUDIO_SAMPLE_FREQ_4B(32000), + AUDIO_SAMPLE_FREQ_4B(0x00), + }; + memcpy(*data, param_block, sizeof(param_block)); + *len = sizeof(param_block); + } else { + } + break; + default: + USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector); + break; + } + + break; + default: + USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } + } +#endif return 0; } @@ -114,14 +350,16 @@ static void audio_notify_handler(uint8_t event, void *arg) usbd_audio_sof_callback(); break; - case USBD_EVENT_SET_INTERFACE: + case USBD_EVENT_SET_INTERFACE: { struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg; if (intf->bAlternateSetting == 1) { usbd_audio_open(intf->bInterfaceNumber); } else { usbd_audio_close(intf->bInterfaceNumber); } - break; + } + + break; default: break; @@ -138,17 +376,68 @@ void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf) } intf->class_handler = audio_class_request_handler; +#if CONFIG_USBDEV_AUDIO_VERSION < 0x0200 + intf->custom_handler = audio_custom_request_handler; +#else intf->custom_handler = NULL; +#endif intf->vendor_handler = NULL; intf->notify_handler = audio_notify_handler; usbd_class_add_interface(devclass, intf); } -__WEAK void usbd_audio_set_volume(uint8_t vol) +void usbd_audio_add_entity(uint8_t entity_id, uint16_t bDescriptorSubtype) +{ + struct audio_entity_info *entity_info = malloc(sizeof(struct audio_entity_info)); + memset(entity_info, 0, sizeof(struct audio_entity_info)); + entity_info->bEntityId = entity_id; + entity_info->bDescriptorSubtype = bDescriptorSubtype; + + if (bDescriptorSubtype == AUDIO_CONTROL_FEATURE_UNIT) { +#if CONFIG_USBDEV_AUDIO_VERSION < 0x0200 + struct usbd_audio_v1_feature_unit_control *control = malloc(sizeof(struct usbd_audio_v1_feature_unit_control)); + memset(control, 0, sizeof(struct usbd_audio_v1_feature_unit_control)); + for (uint8_t ch = 0; ch < CONFIG_USBDEV_AUDIO_MAX_CHANNEL; ch++) { + control->volume[ch].vol_min = 0xdb00; + control->volume[ch].vol_max = 0x0000; + control->volume[ch].vol_res = 0x0100; + control->volume[ch].vol_current = 0xf600; + control->mute[ch] = 0; + control->automatic_gain[ch] = 0; + } +#else + struct usbd_audio_v2_feature_unit_control *control = malloc(sizeof(struct usbd_audio_v2_feature_unit_control)); + memset(control, 0, sizeof(struct usbd_audio_v2_feature_unit_control)); + for (uint8_t ch = 0; ch < CONFIG_USBDEV_AUDIO_MAX_CHANNEL; ch++) { + control->volume.wNumSubRanges = 1; + control->volume.subrange[ch].wMin = 0; + control->volume.subrange[ch].wMax = 100; + control->volume.subrange[ch].wRes = 1; + control->mute[ch] = 0; + control->volume_bCUR = 50; + control->mute_bCUR = 0; + } +#endif + entity_info->priv = control; + } else if (bDescriptorSubtype == AUDIO_CONTROL_CLOCK_SOURCE) { + } + + usb_slist_add_tail(&usbd_audio_entity_info_head, &entity_info->list); +} + +__WEAK void usbd_audio_set_volume(uint8_t ch, float dB) { } -__WEAK void usbd_audio_set_mute(uint8_t mute) +__WEAK void usbd_audio_set_mute(uint8_t ch, uint8_t enable) +{ +} + +__WEAK void usbd_audio_set_sampling_freq(uint8_t ep_ch, uint32_t sampling_freq) +{ +} + +__WEAK void usbd_audio_set_pitch(uint8_t ep, bool enable) { } diff --git a/class/audio/usbd_audio.h b/class/audio/usbd_audio.h index 04cb27c7..387fe4c3 100644 --- a/class/audio/usbd_audio.h +++ b/class/audio/usbd_audio.h @@ -33,8 +33,12 @@ void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf); void usbd_audio_open(uint8_t intf); void usbd_audio_close(uint8_t intf); -void usbd_audio_set_mute(uint8_t mute); -void usbd_audio_set_volume(uint8_t vol); +void usbd_audio_add_entity(uint8_t entity_id, uint16_t bDescriptorSubtype); +void usbd_audio_set_volume(uint8_t ch, float dB); +void usbd_audio_set_mute(uint8_t ch, uint8_t enable); +void usbd_audio_set_sampling_freq(uint8_t ep_ch, uint32_t sampling_freq); +void usbd_audio_set_pitch(uint8_t ep, bool enable); +void usbd_audio_sof_callback(void); #ifdef __cplusplus } diff --git a/demo/audio_v2_speaker_dualchan_template.c b/demo/audio_v2_speaker_dualchan_template.c new file mode 100644 index 00000000..061f95b3 --- /dev/null +++ b/demo/audio_v2_speaker_dualchan_template.c @@ -0,0 +1,170 @@ +#include "usbd_core.h" +#include "usbd_audio.h" + +#define USBD_VID 0xffff +#define USBD_PID 0xffff +#define USBD_MAX_POWER 100 +#define USBD_LANGID_STRING 1033 + +#ifdef CONFIG_USB_HS +#define EP_INTERVAL 0x04 +#else +#define EP_INTERVAL 0x01 +#endif + +#define AUDIO_OUT_EP 0x01 + +#define AUDIO_FREQ 48000 +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +/* 16bit(2 Bytes) 双声道(Mono:2) */ + +#define AUDIO_OUT_PACKET ((uint32_t)((AUDIO_FREQ * 2 * 2) / 1000)) + +#define HALF_WORD_BYTES 2 //2 half word (one channel) +#define SAMPLE_BITS 16 //16 bit per channel + +#define CHANNEL_NUM 2 + +#define BMCONTROL (AUDIO_V2_FU_CONTROL_MUTE | AUDIO_V2_FU_CONTROL_VOLUME) + +#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \ + AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \ + AUDIO_SIZEOF_AC_CLOCK_SOURCE_DESC + \ + AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \ + AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(CHANNEL_NUM) + \ + AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \ + AUDIO_V2_AS_DESCRIPTOR_INIT_LEN) + +#define AUDIO_AC_SIZ (AUDIO_V2_SIZEOF_AC_HEADER_DESC + \ + AUDIO_SIZEOF_AC_CLOCK_SOURCE_DESC + \ + AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \ + AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(CHANNEL_NUM) + \ + AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC) + +const uint8_t audio_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00), + AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(0x01, 0x03, 0x07), + AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, 0x01, CHANNEL_NUM, 0x00000003, 0x0000), + AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x03, 0x02, DBVAL(BMCONTROL), DBVAL(BMCONTROL)), + AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, 0x03, 0x01, 0x0000), + AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, CHANNEL_NUM, 0x00000003, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL), + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x26, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + ' ', 0x00, /* wcChar9 */ + 'U', 0x00, /* wcChar10 */ + 'A', 0x00, /* wcChar11 */ + 'C', 0x00, /* wcChar12 */ + ' ', 0x00, /* wcChar13 */ + 'D', 0x00, /* wcChar14 */ + 'E', 0x00, /* wcChar15 */ + 'M', 0x00, /* wcChar16 */ + 'O', 0x00, /* wcChar17 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x16, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + '2', 0x00, /* wcChar0 */ + '0', 0x00, /* wcChar1 */ + '2', 0x00, /* wcChar2 */ + '1', 0x00, /* wcChar3 */ + '0', 0x00, /* wcChar4 */ + '3', 0x00, /* wcChar5 */ + '1', 0x00, /* wcChar6 */ + '0', 0x00, /* wcChar7 */ + '0', 0x00, /* wcChar8 */ + '3', 0x00, /* wcChar9 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x01, + 0x00, +#endif + 0x00 +}; +volatile bool tx_flag = 0; + +void usbd_audio_open(uint8_t intf) +{ + tx_flag = 1; + printf("OPEN\r\n"); +} +void usbd_audio_close(uint8_t intf) +{ + printf("CLOSE\r\n"); + tx_flag = 0; +} + +static usbd_class_t audio_class; +static usbd_interface_t audio_control_intf; +static usbd_interface_t audio_stream_intf; + +void usbd_audio_iso_callback(uint8_t ep) +{ +} + +static usbd_endpoint_t audio_in_ep = { + .ep_cb = usbd_audio_iso_callback, + .ep_addr = AUDIO_IN_EP +}; + +void audio_init() +{ + usbd_desc_register(audio_descriptor); + usbd_audio_add_interface(&audio_class, &audio_control_intf); + usbd_audio_add_interface(&audio_class, &audio_stream_intf); + usbd_interface_add_endpoint(&audio_stream_intf, &audio_in_ep); + usbd_audio_add_entity(0x01, AUDIO_CONTROL_CLOCK_SOURCE); + usbd_audio_add_entity(0x03, AUDIO_CONTROL_FEATURE_UNIT); + + usbd_initialize(); +} + +void audio_test() +{ + while (1) { + if (tx_flag) { + } + } +}