add audio2.0 support and template
This commit is contained in:
@@ -22,8 +22,7 @@
|
|||||||
#define AUDIO_SUBCLASS_MIDISTREAMING 0x03
|
#define AUDIO_SUBCLASS_MIDISTREAMING 0x03
|
||||||
|
|
||||||
#define AUDIO_PROTOCOL_UNDEFINED 0x00
|
#define AUDIO_PROTOCOL_UNDEFINED 0x00
|
||||||
#define AUDIO_PROTOCOLv20 0x20 /* IP version 2.0 */
|
#define AUDIO_PROTOCOLv20 0x20 /* IP version 2.0 */
|
||||||
#define AUDIO_PROTOCOLv20_BCD 0x0200 /* IP version 2.0 (BCD) */
|
|
||||||
|
|
||||||
/** Audio Class-Specific Request Codes
|
/** Audio Class-Specific Request Codes
|
||||||
* Refer to Table A-9 from audio10.pdf
|
* Refer to Table A-9 from audio10.pdf
|
||||||
@@ -41,6 +40,11 @@
|
|||||||
#define AUDIO_REQUEST_GET_MEM 0x85
|
#define AUDIO_REQUEST_GET_MEM 0x85
|
||||||
#define AUDIO_REQUEST_GET_STAT 0xFF
|
#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
|
/** Audio Class-Specific Control Interface Descriptor Subtypes
|
||||||
* Refer to Table A-5 from audio10.pdf
|
* Refer to Table A-5 from audio10.pdf
|
||||||
*/
|
*/
|
||||||
@@ -242,6 +246,23 @@
|
|||||||
#define AUDIO_FU_CONTROL_OVERFLOW 0x0f
|
#define AUDIO_FU_CONTROL_OVERFLOW 0x0f
|
||||||
#define AUDIO_FU_CONTROL_LATENCY 0x10
|
#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 */
|
/* Parametric Equalizer Section Effect Unit Control Selectors */
|
||||||
#define AUDIO_PE_CONTROL_UNDEF 0x00
|
#define AUDIO_PE_CONTROL_UNDEF 0x00
|
||||||
#define AUDIO_PE_CONTROL_ENABLE 0x01
|
#define AUDIO_PE_CONTROL_ENABLE 0x01
|
||||||
@@ -390,11 +411,9 @@
|
|||||||
#define AUDIO_DTSD_CONTROL_DECODE_ERR 0x03
|
#define AUDIO_DTSD_CONTROL_DECODE_ERR 0x03
|
||||||
|
|
||||||
/* Endpoint Control Selectors */
|
/* Endpoint Control Selectors */
|
||||||
|
#define AUDIO_EP_CONTROL_UNDEF 0x00
|
||||||
#define AUDIO_EP_CONTROL_UNDEF 0x00
|
#define AUDIO_EP_CONTROL_SAMPLING_FEQ 0x01
|
||||||
#define AUDIO_EP_CONTROL_PITCH 0x01
|
#define AUDIO_EP_CONTROL_PITCH 0x02
|
||||||
#define AUDIO_EP_CONTROL_OVERRUN 0x02
|
|
||||||
#define AUDIO_EP_CONTROL_UNDERRUN 0x03
|
|
||||||
|
|
||||||
/* Encoder Error Codes */
|
/* Encoder Error Codes */
|
||||||
|
|
||||||
@@ -581,7 +600,7 @@ struct audio_cs_if_ac_header_descriptor {
|
|||||||
uint8_t bLength;
|
uint8_t bLength;
|
||||||
uint8_t bDescriptorType;
|
uint8_t bDescriptorType;
|
||||||
uint8_t bDescriptorSubtype;
|
uint8_t bDescriptorSubtype;
|
||||||
uint16_t bcdAUDIO;
|
uint16_t bcdADC;
|
||||||
uint16_t wTotalLength;
|
uint16_t wTotalLength;
|
||||||
uint8_t bInCollection;
|
uint8_t bInCollection;
|
||||||
uint8_t baInterfaceNr[];
|
uint8_t baInterfaceNr[];
|
||||||
@@ -624,11 +643,11 @@ struct audio_cs_if_ac_feature_unit_descriptor {
|
|||||||
uint8_t bUnitID;
|
uint8_t bUnitID;
|
||||||
uint8_t bSourceID;
|
uint8_t bSourceID;
|
||||||
uint8_t bControlSize;
|
uint8_t bControlSize;
|
||||||
// uint8_t bmaControls[];
|
uint8_t bmaControls[1];
|
||||||
uint8_t iFeature;
|
uint8_t iFeature;
|
||||||
} __PACKED;
|
} __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 {
|
struct audio_cs_if_as_general_descriptor {
|
||||||
uint8_t bLength;
|
uint8_t bLength;
|
||||||
@@ -680,7 +699,7 @@ struct audio_cs_ep_ep_general_descriptor {
|
|||||||
#define AUDIO_SIZEOF_CS_EP_GENERAL_DESC (7)
|
#define AUDIO_SIZEOF_CS_EP_GENERAL_DESC (7)
|
||||||
|
|
||||||
// clang-format off
|
// 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 */ \
|
/* Interface Association Descriptor */ \
|
||||||
0x08, \
|
0x08, \
|
||||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \
|
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \
|
||||||
@@ -703,9 +722,9 @@ struct audio_cs_ep_ep_general_descriptor {
|
|||||||
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
|
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
|
||||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
||||||
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ \
|
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ \
|
||||||
WBVAL(bcdADC), /* bcdADC */ \
|
WBVAL(0x0100), /* bcdADC */ \
|
||||||
WBVAL(wTotalLength), /* wTotalLength */ \
|
WBVAL(wTotalLength), /* wTotalLength */ \
|
||||||
bInCollection, /* bInCollection */ \
|
PP_NARG(__VA_ARGS__), /* bInCollection */ \
|
||||||
__VA_ARGS__ /* baInterfaceNr */
|
__VA_ARGS__ /* baInterfaceNr */
|
||||||
|
|
||||||
#define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n)
|
#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 */ \
|
__VA_ARGS__, /* bmaControls(0) Mute */ \
|
||||||
0x00 /* iTerminal */
|
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 */ \
|
0x09, /* bLength */ \
|
||||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||||
@@ -766,8 +785,7 @@ struct audio_cs_ep_ep_general_descriptor {
|
|||||||
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \
|
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ \
|
||||||
bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \
|
bTerminalLink, /* bTerminalLink : Unit ID of the Output Terminal*/ \
|
||||||
0x01, /* bDelay */ \
|
0x01, /* bDelay */ \
|
||||||
0x01, /* wFormatTag : AUDIO_FORMAT_PCM */ \
|
WBVAL(AUDIO_FORMAT_PCM), /* wFormatTag : AUDIO_FORMAT_PCM */ \
|
||||||
0x00, \
|
|
||||||
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
|
0x08 + PP_NARG(__VA_ARGS__), /* bLength */ \
|
||||||
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
||||||
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \
|
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */ \
|
||||||
@@ -775,24 +793,304 @@ struct audio_cs_ep_ep_general_descriptor {
|
|||||||
bNrChannels, /* bNrChannels */ \
|
bNrChannels, /* bNrChannels */ \
|
||||||
0x02, /* bSubFrameSize : 2 Bytes per audio subframe */ \
|
0x02, /* bSubFrameSize : 2 Bytes per audio subframe */ \
|
||||||
0x10, /* bBitResolution : 16 bits per sample */ \
|
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 */ \
|
__VA_ARGS__, /* tSamFreq : Audio sampling frequency coded on 3 bytes */ \
|
||||||
0x09, /* bLength */ \
|
0x09, /* bLength */ \
|
||||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||||
bEndpointAddress, /* bEndpointAddress : IN endpoint 1 */ \
|
bEndpointAddress, /* bEndpointAddress : IN endpoint 1 */ \
|
||||||
0x01, /* bmAttributes */ \
|
0x01, /* bmAttributes */ \
|
||||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
|
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
|
||||||
0x04, /* bInterval : one packet per frame */ \
|
bInterval, /* bInterval : one packet per frame */ \
|
||||||
0x00, /* bRefresh */ \
|
0x00, /* bRefresh */ \
|
||||||
0x00, /* bSynchAddress */ \
|
0x00, /* bSynchAddress */ \
|
||||||
0x07, /* bLength */ \
|
0x07, /* bLength */ \
|
||||||
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */ \
|
||||||
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \
|
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */ \
|
||||||
0x00, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \
|
AUDIO_EP_CONTROL_SAMPLING_FEQ, /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */ \
|
||||||
0x00, /* bLockDelayUnits */ \
|
0x00, /* bLockDelayUnits */ \
|
||||||
0x00, /* wLockDelay */ \
|
0x00, /* wLockDelay */ \
|
||||||
0x00
|
0x00
|
||||||
// clang-format on
|
|
||||||
#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
|
#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_ */
|
#endif /* _USB_AUDIO_H_ */
|
||||||
|
|||||||
@@ -23,13 +23,82 @@
|
|||||||
#include "usbd_core.h"
|
#include "usbd_core.h"
|
||||||
#include "usbd_audio.h"
|
#include "usbd_audio.h"
|
||||||
|
|
||||||
struct usbd_audio_control_info {
|
struct usbd_audio_volume_info {
|
||||||
uint16_t vol_min;
|
uint16_t vol_min;
|
||||||
uint16_t vol_max;
|
uint16_t vol_max;
|
||||||
uint16_t vol_res;
|
uint16_t vol_res;
|
||||||
uint16_t vol_current;
|
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)
|
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",
|
"bRequest 0x%02x\r\n",
|
||||||
setup->bRequest);
|
setup->bRequest);
|
||||||
|
|
||||||
switch (setup->bRequest) {
|
struct audio_entity_info *current_entity_info = NULL;
|
||||||
case AUDIO_REQUEST_SET_CUR:
|
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) {
|
entity_id = HI_BYTE(setup->wIndex);
|
||||||
if (HI_BYTE(setup->wValue) == AUDIO_FU_CONTROL_MUTE) {
|
control_selector = HI_BYTE(setup->wValue);
|
||||||
memcpy(&audio_control_info.mute, *data, *len);
|
ch = LO_BYTE(setup->wValue);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
if (ch > (CONFIG_USBDEV_AUDIO_MAX_CHANNEL - 1)) {
|
||||||
|
return -2;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,14 +350,16 @@ static void audio_notify_handler(uint8_t event, void *arg)
|
|||||||
usbd_audio_sof_callback();
|
usbd_audio_sof_callback();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USBD_EVENT_SET_INTERFACE:
|
case USBD_EVENT_SET_INTERFACE: {
|
||||||
struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
|
struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
|
||||||
if (intf->bAlternateSetting == 1) {
|
if (intf->bAlternateSetting == 1) {
|
||||||
usbd_audio_open(intf->bInterfaceNumber);
|
usbd_audio_open(intf->bInterfaceNumber);
|
||||||
} else {
|
} else {
|
||||||
usbd_audio_close(intf->bInterfaceNumber);
|
usbd_audio_close(intf->bInterfaceNumber);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
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;
|
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;
|
intf->custom_handler = NULL;
|
||||||
|
#endif
|
||||||
intf->vendor_handler = NULL;
|
intf->vendor_handler = NULL;
|
||||||
intf->notify_handler = audio_notify_handler;
|
intf->notify_handler = audio_notify_handler;
|
||||||
usbd_class_add_interface(devclass, intf);
|
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_open(uint8_t intf);
|
||||||
void usbd_audio_close(uint8_t intf);
|
void usbd_audio_close(uint8_t intf);
|
||||||
void usbd_audio_set_mute(uint8_t mute);
|
void usbd_audio_add_entity(uint8_t entity_id, uint16_t bDescriptorSubtype);
|
||||||
void usbd_audio_set_volume(uint8_t vol);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
170
demo/audio_v2_speaker_dualchan_template.c
Normal file
170
demo/audio_v2_speaker_dualchan_template.c
Normal file
@@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user