// SPDX-License-Identifier: GPL-2.0+/* * f_uac2.c -- USB Audio Class 2.0 Function * * Copyright (C) 2011 * Yadwinder Singh (yadi.brar01@gmail.com) * Jaswinder Singh (jaswinder.singh@linaro.org) * * Copyright (C) 2020 * Ruslan Bilovol (ruslan.bilovol@gmail.com) */ #include <linux/usb/audio.h>#include <linux/usb/audio-v2.h>#include <linux/module.h> #include "u_audio.h" #include "u_uac2.h" /* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */#define UAC2_CHANNEL_MASK 0x07FFFFFF /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN * Capture and Playback sampling rates are independently * controlled by two clock sources : * CLK_5 := c_srate, and CLK_6 := p_srate */#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID)#define USB_IN_CLK_ID (in_clk_src_desc.bClockID)#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID)#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) #define CONTROL_ABSENT 0#define CONTROL_RDONLY 1#define CONTROL_RDWR 3 #define CLK_FREQ_CTRL 0#define CLK_VLD_CTRL 2#define FU_MUTE_CTRL 0#define FU_VOL_CTRL 2 #define COPY_CTRL 0#define CONN_CTRL 2#define OVRLD_CTRL 4#define CLSTR_CTRL 6#define UNFLW_CTRL 8#define OVFLW_CTRL 10 #define EPIN_EN(_opts) ((_opts)->p_chmask != 0)#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)#define FUIN_EN(_opts) (EPIN_EN(_opts) \ && ((_opts)->p_mute_present \ || (_opts)->p_volume_present))#define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ && ((_opts)->c_mute_present \ || (_opts)->c_volume_present))#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) struct f_uac2 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ struct usb_ctrlrequest setup_cr; /* will be used in data stage */ /* Interrupt IN endpoint of AC interface */ struct usb_ep *int_ep; atomic_t int_count; /* transient state, only valid during handling of a single control request */ int clock_id;}; static inline struct f_uac2 *func_to_uac2(struct usb_function *f){ return container_of(f, struct f_uac2, g_audio.func);} static inlinestruct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev){ return container_of(agdev->func.fi, struct f_uac2_opts, func_inst);} static int afunc_notify(struct g_audio *agdev, int unit_id, int cs); /* --------- USB Function Interface ------------- */ enum { STR_ASSOC, STR_IF_CTRL, STR_CLKSRC_IN, STR_CLKSRC_OUT, STR_USB_IT, STR_USB_IT_CH, STR_IO_IT, STR_IO_IT_CH, STR_USB_OT, STR_IO_OT, STR_FU_IN, STR_FU_OUT, STR_AS_OUT_ALT0, STR_AS_OUT_ALT1, STR_AS_IN_ALT0, STR_AS_IN_ALT1, NUM_STR_DESCRIPTORS,}; static struct usb_string strings_fn[NUM_STR_DESCRIPTORS + 1] = {}; static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", [USB_SPEED_LOW] = "LS", [USB_SPEED_FULL] = "FS", [USB_SPEED_HIGH] = "HS", [USB_SPEED_WIRELESS] = "W", [USB_SPEED_SUPER] = "SS", [USB_SPEED_SUPER_PLUS] = "SS+",}; static struct usb_gadget_strings str_fn = { .language = 0x0409, /* en-us */ .strings = strings_fn,}; static struct usb_gadget_strings *fn_strings[] = { &str_fn, NULL,}; static struct usb_interface_assoc_descriptor iad_desc = { .bLength = sizeof iad_desc, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bFirstInterface = 0, .bInterfaceCount = 3, .bFunctionClass = USB_CLASS_AUDIO, .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED, .bFunctionProtocol = UAC_VERSION_2,}; /* Audio Control Interface */static struct usb_interface_descriptor std_ac_if_desc = { .bLength = sizeof std_ac_if_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, /* .bNumEndpoints = DYNAMIC */ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, .bInterfaceProtocol = UAC_VERSION_2,}; /* Clock source for IN traffic */static struct uac_clock_source_descriptor in_clk_src_desc = { .bLength = sizeof in_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0,}; /* Clock source for OUT traffic */static struct uac_clock_source_descriptor out_clk_src_desc = { .bLength = sizeof out_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0,}; /* Input Terminal for USB_OUT */static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bLength = sizeof usb_out_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),}; /* Input Terminal for I/O-In */static struct uac2_input_terminal_descriptor io_in_it_desc = { .bLength = sizeof io_in_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ /* .wTerminalType = DYNAMIC */ .bAssocTerminal = 0, /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),}; /* Ouput Terminal for USB_IN */static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bLength = sizeof usb_in_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, /* .bSourceID = DYNAMIC */ /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),}; /* Ouput Terminal for I/O-Out */static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bLength = sizeof io_out_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ /* .wTerminalType = DYNAMIC */ .bAssocTerminal = 0, /* .bSourceID = DYNAMIC */ /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),}; static struct uac2_feature_unit_descriptor *in_feature_unit_desc;static struct uac2_feature_unit_descriptor *out_feature_unit_desc; static struct uac2_ac_header_descriptor ac_hdr_desc = { .bLength = sizeof ac_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_MS_HEADER, .bcdADC = cpu_to_le16(0x200), .bCategory = UAC2_FUNCTION_IO_BOX, /* .wTotalLength = DYNAMIC */ .bmControls = 0,}; /* AC IN Interrupt Endpoint */static struct usb_endpoint_descriptor fs_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 1,}; static struct usb_endpoint_descriptor hs_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 4,}; static struct usb_endpoint_descriptor ss_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 4,}; static struct usb_ss_ep_comp_descriptor ss_ep_int_desc_comp = { .bLength = sizeof(ss_ep_int_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .wBytesPerInterval = cpu_to_le16(6),}; /* Audio Streaming OUT Interface - Alt0 */static struct usb_interface_descriptor std_as_out_if0_desc = { .bLength = sizeof std_as_out_if0_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2,}; /* Audio Streaming OUT Interface - Alt1 */static struct usb_interface_descriptor std_as_out_if1_desc = { .bLength = sizeof std_as_out_if1_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2,}; /* Audio Stream OUT Intface Desc */static struct uac2_as_header_descriptor as_out_hdr_desc = { .bLength = sizeof as_out_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), .iChannelNames = 0,}; /* Audio USB_OUT Format */static struct uac2_format_type_i_descriptor as_out_fmt1_desc = { .bLength = sizeof as_out_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I,}; /* STD AS ISO OUT Endpoint */static struct usb_endpoint_descriptor fs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ .bInterval = 1,}; static struct usb_endpoint_descriptor hs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */}; static struct usb_endpoint_descriptor ss_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */}; static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { .bLength = sizeof(ss_epout_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, /* wBytesPerInterval = DYNAMIC */}; /* CS AS ISO OUT Endpoint */static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { .bLength = sizeof as_iso_out_desc, .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = UAC_EP_GENERAL, .bmAttributes = 0, .bmControls = 0, .bLockDelayUnits = 0, .wLockDelay = 0,}; /* STD AS ISO IN Feedback Endpoint */static struct usb_endpoint_descriptor fs_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(3), .bInterval = 1,}; static struct usb_endpoint_descriptor hs_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(4), .bInterval = 4,}; static struct usb_endpoint_descriptor ss_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(4), .bInterval = 4,}; static struct usb_ss_ep_comp_descriptor ss_epin_fback_desc_comp = { .bLength = sizeof(ss_epin_fback_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = cpu_to_le16(4),}; /* Audio Streaming IN Interface - Alt0 */static struct usb_interface_descriptor std_as_in_if0_desc = { .bLength = sizeof std_as_in_if0_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2,}; /* Audio Streaming IN Interface - Alt1 */static struct usb_interface_descriptor std_as_in_if1_desc = { .bLength = sizeof std_as_in_if1_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2,}; /* Audio Stream IN Intface Desc */static struct uac2_as_header_descriptor as_in_hdr_desc = { .bLength = sizeof as_in_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), .iChannelNames = 0,}; /* Audio USB_IN Format */static struct uac2_format_type_i_descriptor as_in_fmt1_desc = { .bLength = sizeof as_in_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I,}; /* STD AS ISO IN Endpoint */static struct usb_endpoint_descriptor fs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ .bInterval = 1,}; static struct usb_endpoint_descriptor hs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */}; static struct usb_endpoint_descriptor ss_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */}; static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { .bLength = sizeof(ss_epin_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0,Lines 1–500 of 2313. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * f_uac2.c -- USB Audio Class 2.0 Function * * Copyright (C) 2011 * Yadwinder Singh (yadi.brar01@gmail.com) * Jaswinder Singh (jaswinder.singh@linaro.org) * * Copyright (C) 2020 * Ruslan Bilovol (ruslan.bilovol@gmail.com) */ #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> #include <linux/module.h> #include "u_audio.h" #include "u_uac2.h" /* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ #define UAC2_CHANNEL_MASK 0x07FFFFFF /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN * Capture and Playback sampling rates are independently * controlled by two clock sources : * CLK_5 := c_srate, and CLK_6 := p_srate */ #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) #define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) #define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) #define CONTROL_ABSENT 0 #define CONTROL_RDONLY 1 #define CONTROL_RDWR 3 #define CLK_FREQ_CTRL 0 #define CLK_VLD_CTRL 2 #define FU_MUTE_CTRL 0 #define FU_VOL_CTRL 2 #define COPY_CTRL 0 #define CONN_CTRL 2 #define OVRLD_CTRL 4 #define CLSTR_CTRL 6 #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) #define FUIN_EN(_opts) (EPIN_EN(_opts) \ && ((_opts)->p_mute_present \ || (_opts)->p_volume_present)) #define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ && ((_opts)->c_mute_present \ || (_opts)->c_volume_present)) #define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) struct f_uac2 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ struct usb_ctrlrequest setup_cr; /* will be used in data stage */ /* Interrupt IN endpoint of AC interface */ struct usb_ep *int_ep; atomic_t int_count; /* transient state, only valid during handling of a single control request */ int clock_id; }; static inline struct f_uac2 *func_to_uac2(struct usb_function *f) { return container_of(f, struct f_uac2, g_audio.func); } static inline struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); } static int afunc_notify(struct g_audio *agdev, int unit_id, int cs); /* --------- USB Function Interface ------------- */ enum { STR_ASSOC, STR_IF_CTRL, STR_CLKSRC_IN, STR_CLKSRC_OUT, STR_USB_IT, STR_USB_IT_CH, STR_IO_IT, STR_IO_IT_CH, STR_USB_OT, STR_IO_OT, STR_FU_IN, STR_FU_OUT, STR_AS_OUT_ALT0, STR_AS_OUT_ALT1, STR_AS_IN_ALT0, STR_AS_IN_ALT1, NUM_STR_DESCRIPTORS, }; static struct usb_string strings_fn[NUM_STR_DESCRIPTORS + 1] = {}; static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", [USB_SPEED_LOW] = "LS", [USB_SPEED_FULL] = "FS", [USB_SPEED_HIGH] = "HS", [USB_SPEED_WIRELESS] = "W", [USB_SPEED_SUPER] = "SS", [USB_SPEED_SUPER_PLUS] = "SS+", }; static struct usb_gadget_strings str_fn = { .language = 0x0409, /* en-us */ .strings = strings_fn, }; static struct usb_gadget_strings *fn_strings[] = { &str_fn, NULL, }; static struct usb_interface_assoc_descriptor iad_desc = { .bLength = sizeof iad_desc, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bFirstInterface = 0, .bInterfaceCount = 3, .bFunctionClass = USB_CLASS_AUDIO, .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED, .bFunctionProtocol = UAC_VERSION_2, }; /* Audio Control Interface */ static struct usb_interface_descriptor std_ac_if_desc = { .bLength = sizeof std_ac_if_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, /* .bNumEndpoints = DYNAMIC */ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, .bInterfaceProtocol = UAC_VERSION_2, }; /* Clock source for IN traffic */ static struct uac_clock_source_descriptor in_clk_src_desc = { .bLength = sizeof in_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0, }; /* Clock source for OUT traffic */ static struct uac_clock_source_descriptor out_clk_src_desc = { .bLength = sizeof out_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0, }; /* Input Terminal for USB_OUT */ static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bLength = sizeof usb_out_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Input Terminal for I/O-In */ static struct uac2_input_terminal_descriptor io_in_it_desc = { .bLength = sizeof io_in_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ /* .wTerminalType = DYNAMIC */ .bAssocTerminal = 0, /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Ouput Terminal for USB_IN */ static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bLength = sizeof usb_in_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, /* .bSourceID = DYNAMIC */ /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Ouput Terminal for I/O-Out */ static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bLength = sizeof io_out_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, /* .bTerminalID = DYNAMIC */ /* .wTerminalType = DYNAMIC */ .bAssocTerminal = 0, /* .bSourceID = DYNAMIC */ /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; static struct uac2_feature_unit_descriptor *in_feature_unit_desc; static struct uac2_feature_unit_descriptor *out_feature_unit_desc; static struct uac2_ac_header_descriptor ac_hdr_desc = { .bLength = sizeof ac_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_MS_HEADER, .bcdADC = cpu_to_le16(0x200), .bCategory = UAC2_FUNCTION_IO_BOX, /* .wTotalLength = DYNAMIC */ .bmControls = 0, }; /* AC IN Interrupt Endpoint */ static struct usb_endpoint_descriptor fs_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 1, }; static struct usb_endpoint_descriptor hs_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 4, }; static struct usb_endpoint_descriptor ss_ep_int_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = cpu_to_le16(6), .bInterval = 4, }; static struct usb_ss_ep_comp_descriptor ss_ep_int_desc_comp = { .bLength = sizeof(ss_ep_int_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .wBytesPerInterval = cpu_to_le16(6), }; /* Audio Streaming OUT Interface - Alt0 */ static struct usb_interface_descriptor std_as_out_if0_desc = { .bLength = sizeof std_as_out_if0_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2, }; /* Audio Streaming OUT Interface - Alt1 */ static struct usb_interface_descriptor std_as_out_if1_desc = { .bLength = sizeof std_as_out_if1_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2, }; /* Audio Stream OUT Intface Desc */ static struct uac2_as_header_descriptor as_out_hdr_desc = { .bLength = sizeof as_out_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), .iChannelNames = 0, }; /* Audio USB_OUT Format */ static struct uac2_format_type_i_descriptor as_out_fmt1_desc = { .bLength = sizeof as_out_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I, }; /* STD AS ISO OUT Endpoint */ static struct usb_endpoint_descriptor fs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ .bInterval = 1, }; static struct usb_endpoint_descriptor hs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */ }; static struct usb_endpoint_descriptor ss_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, /* .bmAttributes = DYNAMIC */ /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */ }; static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { .bLength = sizeof(ss_epout_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, /* wBytesPerInterval = DYNAMIC */ }; /* CS AS ISO OUT Endpoint */ static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { .bLength = sizeof as_iso_out_desc, .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubtype = UAC_EP_GENERAL, .bmAttributes = 0, .bmControls = 0, .bLockDelayUnits = 0, .wLockDelay = 0, }; /* STD AS ISO IN Feedback Endpoint */ static struct usb_endpoint_descriptor fs_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(3), .bInterval = 1, }; static struct usb_endpoint_descriptor hs_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(4), .bInterval = 4, }; static struct usb_endpoint_descriptor ss_epin_fback_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, .wMaxPacketSize = cpu_to_le16(4), .bInterval = 4, }; static struct usb_ss_ep_comp_descriptor ss_epin_fback_desc_comp = { .bLength = sizeof(ss_epin_fback_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = cpu_to_le16(4), }; /* Audio Streaming IN Interface - Alt0 */ static struct usb_interface_descriptor std_as_in_if0_desc = { .bLength = sizeof std_as_in_if0_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, .bNumEndpoints = 0, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2, }; /* Audio Streaming IN Interface - Alt1 */ static struct usb_interface_descriptor std_as_in_if1_desc = { .bLength = sizeof std_as_in_if1_desc, .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 1, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, .bInterfaceProtocol = UAC_VERSION_2, }; /* Audio Stream IN Intface Desc */ static struct uac2_as_header_descriptor as_in_hdr_desc = { .bLength = sizeof as_in_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), .iChannelNames = 0, }; /* Audio USB_IN Format */ static struct uac2_format_type_i_descriptor as_in_fmt1_desc = { .bLength = sizeof as_in_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I, }; /* STD AS ISO IN Endpoint */ static struct usb_endpoint_descriptor fs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ .bInterval = 1, }; static struct usb_endpoint_descriptor hs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */ }; static struct usb_endpoint_descriptor ss_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, /* .wMaxPacketSize = DYNAMIC */ /* .bInterval = DYNAMIC */ }; static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { .bLength = sizeof(ss_epin_desc_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0,