162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * f_uac2.c -- USB Audio Class 2.0 Function 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 662306a36Sopenharmony_ci * Yadwinder Singh (yadi.brar01@gmail.com) 762306a36Sopenharmony_ci * Jaswinder Singh (jaswinder.singh@linaro.org) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2020 1062306a36Sopenharmony_ci * Ruslan Bilovol (ruslan.bilovol@gmail.com) 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/usb/audio.h> 1462306a36Sopenharmony_ci#include <linux/usb/audio-v2.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "u_audio.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "u_uac2.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ 2262306a36Sopenharmony_ci#define UAC2_CHANNEL_MASK 0x07FFFFFF 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * The driver implements a simple UAC_2 topology. 2662306a36Sopenharmony_ci * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture 2762306a36Sopenharmony_ci * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN 2862306a36Sopenharmony_ci * Capture and Playback sampling rates are independently 2962306a36Sopenharmony_ci * controlled by two clock sources : 3062306a36Sopenharmony_ci * CLK_5 := c_srate, and CLK_6 := p_srate 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) 3362306a36Sopenharmony_ci#define USB_IN_CLK_ID (in_clk_src_desc.bClockID) 3462306a36Sopenharmony_ci#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) 3562306a36Sopenharmony_ci#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define CONTROL_ABSENT 0 3862306a36Sopenharmony_ci#define CONTROL_RDONLY 1 3962306a36Sopenharmony_ci#define CONTROL_RDWR 3 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define CLK_FREQ_CTRL 0 4262306a36Sopenharmony_ci#define CLK_VLD_CTRL 2 4362306a36Sopenharmony_ci#define FU_MUTE_CTRL 0 4462306a36Sopenharmony_ci#define FU_VOL_CTRL 2 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define COPY_CTRL 0 4762306a36Sopenharmony_ci#define CONN_CTRL 2 4862306a36Sopenharmony_ci#define OVRLD_CTRL 4 4962306a36Sopenharmony_ci#define CLSTR_CTRL 6 5062306a36Sopenharmony_ci#define UNFLW_CTRL 8 5162306a36Sopenharmony_ci#define OVFLW_CTRL 10 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) 5462306a36Sopenharmony_ci#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) 5562306a36Sopenharmony_ci#define FUIN_EN(_opts) (EPIN_EN(_opts) \ 5662306a36Sopenharmony_ci && ((_opts)->p_mute_present \ 5762306a36Sopenharmony_ci || (_opts)->p_volume_present)) 5862306a36Sopenharmony_ci#define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ 5962306a36Sopenharmony_ci && ((_opts)->c_mute_present \ 6062306a36Sopenharmony_ci || (_opts)->c_volume_present)) 6162306a36Sopenharmony_ci#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct f_uac2 { 6462306a36Sopenharmony_ci struct g_audio g_audio; 6562306a36Sopenharmony_ci u8 ac_intf, as_in_intf, as_out_intf; 6662306a36Sopenharmony_ci u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci struct usb_ctrlrequest setup_cr; /* will be used in data stage */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Interrupt IN endpoint of AC interface */ 7162306a36Sopenharmony_ci struct usb_ep *int_ep; 7262306a36Sopenharmony_ci atomic_t int_count; 7362306a36Sopenharmony_ci /* transient state, only valid during handling of a single control request */ 7462306a36Sopenharmony_ci int clock_id; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline struct f_uac2 *func_to_uac2(struct usb_function *f) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return container_of(f, struct f_uac2, g_audio.func); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline 8362306a36Sopenharmony_cistruct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int afunc_notify(struct g_audio *agdev, int unit_id, int cs); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* --------- USB Function Interface ------------- */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cienum { 9362306a36Sopenharmony_ci STR_ASSOC, 9462306a36Sopenharmony_ci STR_IF_CTRL, 9562306a36Sopenharmony_ci STR_CLKSRC_IN, 9662306a36Sopenharmony_ci STR_CLKSRC_OUT, 9762306a36Sopenharmony_ci STR_USB_IT, 9862306a36Sopenharmony_ci STR_IO_IT, 9962306a36Sopenharmony_ci STR_USB_OT, 10062306a36Sopenharmony_ci STR_IO_OT, 10162306a36Sopenharmony_ci STR_FU_IN, 10262306a36Sopenharmony_ci STR_FU_OUT, 10362306a36Sopenharmony_ci STR_AS_OUT_ALT0, 10462306a36Sopenharmony_ci STR_AS_OUT_ALT1, 10562306a36Sopenharmony_ci STR_AS_IN_ALT0, 10662306a36Sopenharmony_ci STR_AS_IN_ALT1, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct usb_string strings_fn[] = { 11062306a36Sopenharmony_ci /* [STR_ASSOC].s = DYNAMIC, */ 11162306a36Sopenharmony_ci [STR_IF_CTRL].s = "Topology Control", 11262306a36Sopenharmony_ci [STR_CLKSRC_IN].s = "Input Clock", 11362306a36Sopenharmony_ci [STR_CLKSRC_OUT].s = "Output Clock", 11462306a36Sopenharmony_ci [STR_USB_IT].s = "USBH Out", 11562306a36Sopenharmony_ci [STR_IO_IT].s = "USBD Out", 11662306a36Sopenharmony_ci [STR_USB_OT].s = "USBH In", 11762306a36Sopenharmony_ci [STR_IO_OT].s = "USBD In", 11862306a36Sopenharmony_ci [STR_FU_IN].s = "Capture Volume", 11962306a36Sopenharmony_ci [STR_FU_OUT].s = "Playback Volume", 12062306a36Sopenharmony_ci [STR_AS_OUT_ALT0].s = "Playback Inactive", 12162306a36Sopenharmony_ci [STR_AS_OUT_ALT1].s = "Playback Active", 12262306a36Sopenharmony_ci [STR_AS_IN_ALT0].s = "Capture Inactive", 12362306a36Sopenharmony_ci [STR_AS_IN_ALT1].s = "Capture Active", 12462306a36Sopenharmony_ci { }, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const char *const speed_names[] = { 12862306a36Sopenharmony_ci [USB_SPEED_UNKNOWN] = "UNKNOWN", 12962306a36Sopenharmony_ci [USB_SPEED_LOW] = "LS", 13062306a36Sopenharmony_ci [USB_SPEED_FULL] = "FS", 13162306a36Sopenharmony_ci [USB_SPEED_HIGH] = "HS", 13262306a36Sopenharmony_ci [USB_SPEED_WIRELESS] = "W", 13362306a36Sopenharmony_ci [USB_SPEED_SUPER] = "SS", 13462306a36Sopenharmony_ci [USB_SPEED_SUPER_PLUS] = "SS+", 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic struct usb_gadget_strings str_fn = { 13862306a36Sopenharmony_ci .language = 0x0409, /* en-us */ 13962306a36Sopenharmony_ci .strings = strings_fn, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic struct usb_gadget_strings *fn_strings[] = { 14362306a36Sopenharmony_ci &str_fn, 14462306a36Sopenharmony_ci NULL, 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct usb_interface_assoc_descriptor iad_desc = { 14862306a36Sopenharmony_ci .bLength = sizeof iad_desc, 14962306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci .bFirstInterface = 0, 15262306a36Sopenharmony_ci .bInterfaceCount = 3, 15362306a36Sopenharmony_ci .bFunctionClass = USB_CLASS_AUDIO, 15462306a36Sopenharmony_ci .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED, 15562306a36Sopenharmony_ci .bFunctionProtocol = UAC_VERSION_2, 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* Audio Control Interface */ 15962306a36Sopenharmony_cistatic struct usb_interface_descriptor std_ac_if_desc = { 16062306a36Sopenharmony_ci .bLength = sizeof std_ac_if_desc, 16162306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci .bAlternateSetting = 0, 16462306a36Sopenharmony_ci /* .bNumEndpoints = DYNAMIC */ 16562306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 16662306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, 16762306a36Sopenharmony_ci .bInterfaceProtocol = UAC_VERSION_2, 16862306a36Sopenharmony_ci}; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Clock source for IN traffic */ 17162306a36Sopenharmony_cistatic struct uac_clock_source_descriptor in_clk_src_desc = { 17262306a36Sopenharmony_ci .bLength = sizeof in_clk_src_desc, 17362306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci .bDescriptorSubtype = UAC2_CLOCK_SOURCE, 17662306a36Sopenharmony_ci /* .bClockID = DYNAMIC */ 17762306a36Sopenharmony_ci .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, 17862306a36Sopenharmony_ci .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), 17962306a36Sopenharmony_ci .bAssocTerminal = 0, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* Clock source for OUT traffic */ 18362306a36Sopenharmony_cistatic struct uac_clock_source_descriptor out_clk_src_desc = { 18462306a36Sopenharmony_ci .bLength = sizeof out_clk_src_desc, 18562306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci .bDescriptorSubtype = UAC2_CLOCK_SOURCE, 18862306a36Sopenharmony_ci /* .bClockID = DYNAMIC */ 18962306a36Sopenharmony_ci .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, 19062306a36Sopenharmony_ci .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), 19162306a36Sopenharmony_ci .bAssocTerminal = 0, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* Input Terminal for USB_OUT */ 19562306a36Sopenharmony_cistatic struct uac2_input_terminal_descriptor usb_out_it_desc = { 19662306a36Sopenharmony_ci .bLength = sizeof usb_out_it_desc, 19762306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci .bDescriptorSubtype = UAC_INPUT_TERMINAL, 20062306a36Sopenharmony_ci /* .bTerminalID = DYNAMIC */ 20162306a36Sopenharmony_ci .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 20262306a36Sopenharmony_ci .bAssocTerminal = 0, 20362306a36Sopenharmony_ci /* .bCSourceID = DYNAMIC */ 20462306a36Sopenharmony_ci .iChannelNames = 0, 20562306a36Sopenharmony_ci .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* Input Terminal for I/O-In */ 20962306a36Sopenharmony_cistatic struct uac2_input_terminal_descriptor io_in_it_desc = { 21062306a36Sopenharmony_ci .bLength = sizeof io_in_it_desc, 21162306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci .bDescriptorSubtype = UAC_INPUT_TERMINAL, 21462306a36Sopenharmony_ci /* .bTerminalID = DYNAMIC */ 21562306a36Sopenharmony_ci .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), 21662306a36Sopenharmony_ci .bAssocTerminal = 0, 21762306a36Sopenharmony_ci /* .bCSourceID = DYNAMIC */ 21862306a36Sopenharmony_ci .iChannelNames = 0, 21962306a36Sopenharmony_ci .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 22062306a36Sopenharmony_ci}; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* Ouput Terminal for USB_IN */ 22362306a36Sopenharmony_cistatic struct uac2_output_terminal_descriptor usb_in_ot_desc = { 22462306a36Sopenharmony_ci .bLength = sizeof usb_in_ot_desc, 22562306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 22862306a36Sopenharmony_ci /* .bTerminalID = DYNAMIC */ 22962306a36Sopenharmony_ci .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 23062306a36Sopenharmony_ci .bAssocTerminal = 0, 23162306a36Sopenharmony_ci /* .bSourceID = DYNAMIC */ 23262306a36Sopenharmony_ci /* .bCSourceID = DYNAMIC */ 23362306a36Sopenharmony_ci .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* Ouput Terminal for I/O-Out */ 23762306a36Sopenharmony_cistatic struct uac2_output_terminal_descriptor io_out_ot_desc = { 23862306a36Sopenharmony_ci .bLength = sizeof io_out_ot_desc, 23962306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 24262306a36Sopenharmony_ci /* .bTerminalID = DYNAMIC */ 24362306a36Sopenharmony_ci .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), 24462306a36Sopenharmony_ci .bAssocTerminal = 0, 24562306a36Sopenharmony_ci /* .bSourceID = DYNAMIC */ 24662306a36Sopenharmony_ci /* .bCSourceID = DYNAMIC */ 24762306a36Sopenharmony_ci .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic struct uac2_feature_unit_descriptor *in_feature_unit_desc; 25162306a36Sopenharmony_cistatic struct uac2_feature_unit_descriptor *out_feature_unit_desc; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic struct uac2_ac_header_descriptor ac_hdr_desc = { 25462306a36Sopenharmony_ci .bLength = sizeof ac_hdr_desc, 25562306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci .bDescriptorSubtype = UAC_MS_HEADER, 25862306a36Sopenharmony_ci .bcdADC = cpu_to_le16(0x200), 25962306a36Sopenharmony_ci .bCategory = UAC2_FUNCTION_IO_BOX, 26062306a36Sopenharmony_ci /* .wTotalLength = DYNAMIC */ 26162306a36Sopenharmony_ci .bmControls = 0, 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* AC IN Interrupt Endpoint */ 26562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor fs_ep_int_desc = { 26662306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 26762306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 27062306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 27162306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(6), 27262306a36Sopenharmony_ci .bInterval = 1, 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor hs_ep_int_desc = { 27662306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 27762306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 28062306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(6), 28162306a36Sopenharmony_ci .bInterval = 4, 28262306a36Sopenharmony_ci}; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic struct usb_endpoint_descriptor ss_ep_int_desc = { 28562306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 28662306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 28962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 29062306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(6), 29162306a36Sopenharmony_ci .bInterval = 4, 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor ss_ep_int_desc_comp = { 29562306a36Sopenharmony_ci .bLength = sizeof(ss_ep_int_desc_comp), 29662306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 29762306a36Sopenharmony_ci .wBytesPerInterval = cpu_to_le16(6), 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Audio Streaming OUT Interface - Alt0 */ 30162306a36Sopenharmony_cistatic struct usb_interface_descriptor std_as_out_if0_desc = { 30262306a36Sopenharmony_ci .bLength = sizeof std_as_out_if0_desc, 30362306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci .bAlternateSetting = 0, 30662306a36Sopenharmony_ci .bNumEndpoints = 0, 30762306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 30862306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, 30962306a36Sopenharmony_ci .bInterfaceProtocol = UAC_VERSION_2, 31062306a36Sopenharmony_ci}; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* Audio Streaming OUT Interface - Alt1 */ 31362306a36Sopenharmony_cistatic struct usb_interface_descriptor std_as_out_if1_desc = { 31462306a36Sopenharmony_ci .bLength = sizeof std_as_out_if1_desc, 31562306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci .bAlternateSetting = 1, 31862306a36Sopenharmony_ci .bNumEndpoints = 1, 31962306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 32062306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, 32162306a36Sopenharmony_ci .bInterfaceProtocol = UAC_VERSION_2, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* Audio Stream OUT Intface Desc */ 32562306a36Sopenharmony_cistatic struct uac2_as_header_descriptor as_out_hdr_desc = { 32662306a36Sopenharmony_ci .bLength = sizeof as_out_hdr_desc, 32762306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci .bDescriptorSubtype = UAC_AS_GENERAL, 33062306a36Sopenharmony_ci /* .bTerminalLink = DYNAMIC */ 33162306a36Sopenharmony_ci .bmControls = 0, 33262306a36Sopenharmony_ci .bFormatType = UAC_FORMAT_TYPE_I, 33362306a36Sopenharmony_ci .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), 33462306a36Sopenharmony_ci .iChannelNames = 0, 33562306a36Sopenharmony_ci}; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/* Audio USB_OUT Format */ 33862306a36Sopenharmony_cistatic struct uac2_format_type_i_descriptor as_out_fmt1_desc = { 33962306a36Sopenharmony_ci .bLength = sizeof as_out_fmt1_desc, 34062306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 34162306a36Sopenharmony_ci .bDescriptorSubtype = UAC_FORMAT_TYPE, 34262306a36Sopenharmony_ci .bFormatType = UAC_FORMAT_TYPE_I, 34362306a36Sopenharmony_ci}; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci/* STD AS ISO OUT Endpoint */ 34662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor fs_epout_desc = { 34762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 34862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_OUT, 35162306a36Sopenharmony_ci /* .bmAttributes = DYNAMIC */ 35262306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 35362306a36Sopenharmony_ci .bInterval = 1, 35462306a36Sopenharmony_ci}; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor hs_epout_desc = { 35762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 35862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* .bmAttributes = DYNAMIC */ 36162306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 36262306a36Sopenharmony_ci /* .bInterval = DYNAMIC */ 36362306a36Sopenharmony_ci}; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor ss_epout_desc = { 36662306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 36762306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_OUT, 37062306a36Sopenharmony_ci /* .bmAttributes = DYNAMIC */ 37162306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 37262306a36Sopenharmony_ci /* .bInterval = DYNAMIC */ 37362306a36Sopenharmony_ci}; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { 37662306a36Sopenharmony_ci .bLength = sizeof(ss_epout_desc_comp), 37762306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 37862306a36Sopenharmony_ci .bMaxBurst = 0, 37962306a36Sopenharmony_ci .bmAttributes = 0, 38062306a36Sopenharmony_ci /* wBytesPerInterval = DYNAMIC */ 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* CS AS ISO OUT Endpoint */ 38462306a36Sopenharmony_cistatic struct uac2_iso_endpoint_descriptor as_iso_out_desc = { 38562306a36Sopenharmony_ci .bLength = sizeof as_iso_out_desc, 38662306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_ENDPOINT, 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci .bDescriptorSubtype = UAC_EP_GENERAL, 38962306a36Sopenharmony_ci .bmAttributes = 0, 39062306a36Sopenharmony_ci .bmControls = 0, 39162306a36Sopenharmony_ci .bLockDelayUnits = 0, 39262306a36Sopenharmony_ci .wLockDelay = 0, 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* STD AS ISO IN Feedback Endpoint */ 39662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor fs_epin_fback_desc = { 39762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 39862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 40162306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, 40262306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(3), 40362306a36Sopenharmony_ci .bInterval = 1, 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor hs_epin_fback_desc = { 40762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 40862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, 41162306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(4), 41262306a36Sopenharmony_ci .bInterval = 4, 41362306a36Sopenharmony_ci}; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor ss_epin_fback_desc = { 41662306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 41762306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 42062306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, 42162306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(4), 42262306a36Sopenharmony_ci .bInterval = 4, 42362306a36Sopenharmony_ci}; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor ss_epin_fback_desc_comp = { 42662306a36Sopenharmony_ci .bLength = sizeof(ss_epin_fback_desc_comp), 42762306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 42862306a36Sopenharmony_ci .bMaxBurst = 0, 42962306a36Sopenharmony_ci .bmAttributes = 0, 43062306a36Sopenharmony_ci .wBytesPerInterval = cpu_to_le16(4), 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci/* Audio Streaming IN Interface - Alt0 */ 43562306a36Sopenharmony_cistatic struct usb_interface_descriptor std_as_in_if0_desc = { 43662306a36Sopenharmony_ci .bLength = sizeof std_as_in_if0_desc, 43762306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci .bAlternateSetting = 0, 44062306a36Sopenharmony_ci .bNumEndpoints = 0, 44162306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 44262306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, 44362306a36Sopenharmony_ci .bInterfaceProtocol = UAC_VERSION_2, 44462306a36Sopenharmony_ci}; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* Audio Streaming IN Interface - Alt1 */ 44762306a36Sopenharmony_cistatic struct usb_interface_descriptor std_as_in_if1_desc = { 44862306a36Sopenharmony_ci .bLength = sizeof std_as_in_if1_desc, 44962306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci .bAlternateSetting = 1, 45262306a36Sopenharmony_ci .bNumEndpoints = 1, 45362306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 45462306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, 45562306a36Sopenharmony_ci .bInterfaceProtocol = UAC_VERSION_2, 45662306a36Sopenharmony_ci}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* Audio Stream IN Intface Desc */ 45962306a36Sopenharmony_cistatic struct uac2_as_header_descriptor as_in_hdr_desc = { 46062306a36Sopenharmony_ci .bLength = sizeof as_in_hdr_desc, 46162306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci .bDescriptorSubtype = UAC_AS_GENERAL, 46462306a36Sopenharmony_ci /* .bTerminalLink = DYNAMIC */ 46562306a36Sopenharmony_ci .bmControls = 0, 46662306a36Sopenharmony_ci .bFormatType = UAC_FORMAT_TYPE_I, 46762306a36Sopenharmony_ci .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), 46862306a36Sopenharmony_ci .iChannelNames = 0, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/* Audio USB_IN Format */ 47262306a36Sopenharmony_cistatic struct uac2_format_type_i_descriptor as_in_fmt1_desc = { 47362306a36Sopenharmony_ci .bLength = sizeof as_in_fmt1_desc, 47462306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_INTERFACE, 47562306a36Sopenharmony_ci .bDescriptorSubtype = UAC_FORMAT_TYPE, 47662306a36Sopenharmony_ci .bFormatType = UAC_FORMAT_TYPE_I, 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/* STD AS ISO IN Endpoint */ 48062306a36Sopenharmony_cistatic struct usb_endpoint_descriptor fs_epin_desc = { 48162306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 48262306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 48562306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, 48662306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 48762306a36Sopenharmony_ci .bInterval = 1, 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic struct usb_endpoint_descriptor hs_epin_desc = { 49162306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 49262306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, 49562306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 49662306a36Sopenharmony_ci /* .bInterval = DYNAMIC */ 49762306a36Sopenharmony_ci}; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic struct usb_endpoint_descriptor ss_epin_desc = { 50062306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 50162306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 50462306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, 50562306a36Sopenharmony_ci /* .wMaxPacketSize = DYNAMIC */ 50662306a36Sopenharmony_ci /* .bInterval = DYNAMIC */ 50762306a36Sopenharmony_ci}; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { 51062306a36Sopenharmony_ci .bLength = sizeof(ss_epin_desc_comp), 51162306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 51262306a36Sopenharmony_ci .bMaxBurst = 0, 51362306a36Sopenharmony_ci .bmAttributes = 0, 51462306a36Sopenharmony_ci /* wBytesPerInterval = DYNAMIC */ 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* CS AS ISO IN Endpoint */ 51862306a36Sopenharmony_cistatic struct uac2_iso_endpoint_descriptor as_iso_in_desc = { 51962306a36Sopenharmony_ci .bLength = sizeof as_iso_in_desc, 52062306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_ENDPOINT, 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci .bDescriptorSubtype = UAC_EP_GENERAL, 52362306a36Sopenharmony_ci .bmAttributes = 0, 52462306a36Sopenharmony_ci .bmControls = 0, 52562306a36Sopenharmony_ci .bLockDelayUnits = 0, 52662306a36Sopenharmony_ci .wLockDelay = 0, 52762306a36Sopenharmony_ci}; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic struct usb_descriptor_header *fs_audio_desc[] = { 53062306a36Sopenharmony_ci (struct usb_descriptor_header *)&iad_desc, 53162306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_ac_if_desc, 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci (struct usb_descriptor_header *)&ac_hdr_desc, 53462306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_clk_src_desc, 53562306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_clk_src_desc, 53662306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_out_it_desc, 53762306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_feature_unit_desc, 53862306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_in_it_desc, 53962306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_in_ot_desc, 54062306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_feature_unit_desc, 54162306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_out_ot_desc, 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci (struct usb_descriptor_header *)&fs_ep_int_desc, 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if0_desc, 54662306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if1_desc, 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_hdr_desc, 54962306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_fmt1_desc, 55062306a36Sopenharmony_ci (struct usb_descriptor_header *)&fs_epout_desc, 55162306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_out_desc, 55262306a36Sopenharmony_ci (struct usb_descriptor_header *)&fs_epin_fback_desc, 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if0_desc, 55562306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if1_desc, 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_hdr_desc, 55862306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_fmt1_desc, 55962306a36Sopenharmony_ci (struct usb_descriptor_header *)&fs_epin_desc, 56062306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_in_desc, 56162306a36Sopenharmony_ci NULL, 56262306a36Sopenharmony_ci}; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic struct usb_descriptor_header *hs_audio_desc[] = { 56562306a36Sopenharmony_ci (struct usb_descriptor_header *)&iad_desc, 56662306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_ac_if_desc, 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci (struct usb_descriptor_header *)&ac_hdr_desc, 56962306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_clk_src_desc, 57062306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_clk_src_desc, 57162306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_out_it_desc, 57262306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_feature_unit_desc, 57362306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_in_it_desc, 57462306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_in_ot_desc, 57562306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_feature_unit_desc, 57662306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_out_ot_desc, 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci (struct usb_descriptor_header *)&hs_ep_int_desc, 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if0_desc, 58162306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if1_desc, 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_hdr_desc, 58462306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_fmt1_desc, 58562306a36Sopenharmony_ci (struct usb_descriptor_header *)&hs_epout_desc, 58662306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_out_desc, 58762306a36Sopenharmony_ci (struct usb_descriptor_header *)&hs_epin_fback_desc, 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if0_desc, 59062306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if1_desc, 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_hdr_desc, 59362306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_fmt1_desc, 59462306a36Sopenharmony_ci (struct usb_descriptor_header *)&hs_epin_desc, 59562306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_in_desc, 59662306a36Sopenharmony_ci NULL, 59762306a36Sopenharmony_ci}; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic struct usb_descriptor_header *ss_audio_desc[] = { 60062306a36Sopenharmony_ci (struct usb_descriptor_header *)&iad_desc, 60162306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_ac_if_desc, 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci (struct usb_descriptor_header *)&ac_hdr_desc, 60462306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_clk_src_desc, 60562306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_clk_src_desc, 60662306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_out_it_desc, 60762306a36Sopenharmony_ci (struct usb_descriptor_header *)&out_feature_unit_desc, 60862306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_in_it_desc, 60962306a36Sopenharmony_ci (struct usb_descriptor_header *)&usb_in_ot_desc, 61062306a36Sopenharmony_ci (struct usb_descriptor_header *)&in_feature_unit_desc, 61162306a36Sopenharmony_ci (struct usb_descriptor_header *)&io_out_ot_desc, 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_ep_int_desc, 61462306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_ep_int_desc_comp, 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if0_desc, 61762306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_out_if1_desc, 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_hdr_desc, 62062306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_out_fmt1_desc, 62162306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epout_desc, 62262306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epout_desc_comp, 62362306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_out_desc, 62462306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epin_fback_desc, 62562306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epin_fback_desc_comp, 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if0_desc, 62862306a36Sopenharmony_ci (struct usb_descriptor_header *)&std_as_in_if1_desc, 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_hdr_desc, 63162306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_in_fmt1_desc, 63262306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epin_desc, 63362306a36Sopenharmony_ci (struct usb_descriptor_header *)&ss_epin_desc_comp, 63462306a36Sopenharmony_ci (struct usb_descriptor_header *)&as_iso_in_desc, 63562306a36Sopenharmony_ci NULL, 63662306a36Sopenharmony_ci}; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistruct cntrl_cur_lay2 { 63962306a36Sopenharmony_ci __le16 wCUR; 64062306a36Sopenharmony_ci}; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistruct cntrl_range_lay2 { 64362306a36Sopenharmony_ci __le16 wNumSubRanges; 64462306a36Sopenharmony_ci __le16 wMIN; 64562306a36Sopenharmony_ci __le16 wMAX; 64662306a36Sopenharmony_ci __le16 wRES; 64762306a36Sopenharmony_ci} __packed; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistruct cntrl_cur_lay3 { 65062306a36Sopenharmony_ci __le32 dCUR; 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistruct cntrl_subrange_lay3 { 65462306a36Sopenharmony_ci __le32 dMIN; 65562306a36Sopenharmony_ci __le32 dMAX; 65662306a36Sopenharmony_ci __le32 dRES; 65762306a36Sopenharmony_ci} __packed; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci#define ranges_lay3_size(c) (sizeof(c.wNumSubRanges) \ 66062306a36Sopenharmony_ci + le16_to_cpu(c.wNumSubRanges) \ 66162306a36Sopenharmony_ci * sizeof(struct cntrl_subrange_lay3)) 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci#define DECLARE_UAC2_CNTRL_RANGES_LAY3(k, n) \ 66462306a36Sopenharmony_ci struct cntrl_ranges_lay3_##k { \ 66562306a36Sopenharmony_ci __le16 wNumSubRanges; \ 66662306a36Sopenharmony_ci struct cntrl_subrange_lay3 r[n]; \ 66762306a36Sopenharmony_ci} __packed 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciDECLARE_UAC2_CNTRL_RANGES_LAY3(srates, UAC_MAX_RATES); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int get_max_srate(const int *srates) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci int i, max_srate = 0; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci for (i = 0; i < UAC_MAX_RATES; i++) { 67662306a36Sopenharmony_ci if (srates[i] == 0) 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci if (srates[i] > max_srate) 67962306a36Sopenharmony_ci max_srate = srates[i]; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci return max_srate; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int get_max_bw_for_bint(const struct f_uac2_opts *uac2_opts, 68562306a36Sopenharmony_ci u8 bint, unsigned int factor, bool is_playback) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci int chmask, srate, ssize; 68862306a36Sopenharmony_ci u16 max_size_bw; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (is_playback) { 69162306a36Sopenharmony_ci chmask = uac2_opts->p_chmask; 69262306a36Sopenharmony_ci srate = get_max_srate(uac2_opts->p_srates); 69362306a36Sopenharmony_ci ssize = uac2_opts->p_ssize; 69462306a36Sopenharmony_ci } else { 69562306a36Sopenharmony_ci chmask = uac2_opts->c_chmask; 69662306a36Sopenharmony_ci srate = get_max_srate(uac2_opts->c_srates); 69762306a36Sopenharmony_ci ssize = uac2_opts->c_ssize; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (is_playback || (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { 70162306a36Sopenharmony_ci // playback is always async, capture only when configured 70262306a36Sopenharmony_ci // Win10 requires max packet size + 1 frame 70362306a36Sopenharmony_ci srate = srate * (1000 + uac2_opts->fb_max) / 1000; 70462306a36Sopenharmony_ci // updated srate is always bigger, therefore DIV_ROUND_UP always yields +1 70562306a36Sopenharmony_ci max_size_bw = num_channels(chmask) * ssize * 70662306a36Sopenharmony_ci (DIV_ROUND_UP(srate, factor / (1 << (bint - 1)))); 70762306a36Sopenharmony_ci } else { 70862306a36Sopenharmony_ci // adding 1 frame provision for Win10 70962306a36Sopenharmony_ci max_size_bw = num_channels(chmask) * ssize * 71062306a36Sopenharmony_ci (DIV_ROUND_UP(srate, factor / (1 << (bint - 1))) + 1); 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci return max_size_bw; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int set_ep_max_packet_size_bint(struct device *dev, const struct f_uac2_opts *uac2_opts, 71662306a36Sopenharmony_ci struct usb_endpoint_descriptor *ep_desc, 71762306a36Sopenharmony_ci enum usb_device_speed speed, bool is_playback) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci u16 max_size_bw, max_size_ep; 72062306a36Sopenharmony_ci u8 bint, opts_bint; 72162306a36Sopenharmony_ci char *dir; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci switch (speed) { 72462306a36Sopenharmony_ci case USB_SPEED_FULL: 72562306a36Sopenharmony_ci max_size_ep = 1023; 72662306a36Sopenharmony_ci // fixed 72762306a36Sopenharmony_ci bint = ep_desc->bInterval; 72862306a36Sopenharmony_ci max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 1000, is_playback); 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci case USB_SPEED_HIGH: 73262306a36Sopenharmony_ci case USB_SPEED_SUPER: 73362306a36Sopenharmony_ci max_size_ep = 1024; 73462306a36Sopenharmony_ci if (is_playback) 73562306a36Sopenharmony_ci opts_bint = uac2_opts->p_hs_bint; 73662306a36Sopenharmony_ci else 73762306a36Sopenharmony_ci opts_bint = uac2_opts->c_hs_bint; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (opts_bint > 0) { 74062306a36Sopenharmony_ci /* fixed bint */ 74162306a36Sopenharmony_ci bint = opts_bint; 74262306a36Sopenharmony_ci max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 8000, is_playback); 74362306a36Sopenharmony_ci } else { 74462306a36Sopenharmony_ci /* checking bInterval from 4 to 1 whether the required bandwidth fits */ 74562306a36Sopenharmony_ci for (bint = 4; bint > 0; --bint) { 74662306a36Sopenharmony_ci max_size_bw = get_max_bw_for_bint( 74762306a36Sopenharmony_ci uac2_opts, bint, 8000, is_playback); 74862306a36Sopenharmony_ci if (max_size_bw <= max_size_ep) 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci break; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci default: 75562306a36Sopenharmony_ci return -EINVAL; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (is_playback) 75962306a36Sopenharmony_ci dir = "Playback"; 76062306a36Sopenharmony_ci else 76162306a36Sopenharmony_ci dir = "Capture"; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (max_size_bw <= max_size_ep) 76462306a36Sopenharmony_ci dev_dbg(dev, 76562306a36Sopenharmony_ci "%s %s: Would use wMaxPacketSize %d and bInterval %d\n", 76662306a36Sopenharmony_ci speed_names[speed], dir, max_size_bw, bint); 76762306a36Sopenharmony_ci else { 76862306a36Sopenharmony_ci dev_warn(dev, 76962306a36Sopenharmony_ci "%s %s: Req. wMaxPacketSize %d at bInterval %d > max ISOC %d, may drop data!\n", 77062306a36Sopenharmony_ci speed_names[speed], dir, max_size_bw, bint, max_size_ep); 77162306a36Sopenharmony_ci max_size_bw = max_size_ep; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci ep_desc->wMaxPacketSize = cpu_to_le16(max_size_bw); 77562306a36Sopenharmony_ci ep_desc->bInterval = bint; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic struct uac2_feature_unit_descriptor *build_fu_desc(int chmask) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct uac2_feature_unit_descriptor *fu_desc; 78362306a36Sopenharmony_ci int channels = num_channels(chmask); 78462306a36Sopenharmony_ci int fu_desc_size = UAC2_DT_FEATURE_UNIT_SIZE(channels); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); 78762306a36Sopenharmony_ci if (!fu_desc) 78862306a36Sopenharmony_ci return NULL; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci fu_desc->bLength = fu_desc_size; 79162306a36Sopenharmony_ci fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci /* bUnitID, bSourceID and bmaControls will be defined later */ 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci return fu_desc; 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci/* Use macro to overcome line length limitation */ 80162306a36Sopenharmony_ci#define USBDHDR(p) (struct usb_descriptor_header *)(p) 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic void setup_headers(struct f_uac2_opts *opts, 80462306a36Sopenharmony_ci struct usb_descriptor_header **headers, 80562306a36Sopenharmony_ci enum usb_device_speed speed) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL; 80862306a36Sopenharmony_ci struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL; 80962306a36Sopenharmony_ci struct usb_ss_ep_comp_descriptor *epin_fback_desc_comp = NULL; 81062306a36Sopenharmony_ci struct usb_ss_ep_comp_descriptor *ep_int_desc_comp = NULL; 81162306a36Sopenharmony_ci struct usb_endpoint_descriptor *epout_desc; 81262306a36Sopenharmony_ci struct usb_endpoint_descriptor *epin_desc; 81362306a36Sopenharmony_ci struct usb_endpoint_descriptor *epin_fback_desc; 81462306a36Sopenharmony_ci struct usb_endpoint_descriptor *ep_int_desc; 81562306a36Sopenharmony_ci int i; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci switch (speed) { 81862306a36Sopenharmony_ci case USB_SPEED_FULL: 81962306a36Sopenharmony_ci epout_desc = &fs_epout_desc; 82062306a36Sopenharmony_ci epin_desc = &fs_epin_desc; 82162306a36Sopenharmony_ci epin_fback_desc = &fs_epin_fback_desc; 82262306a36Sopenharmony_ci ep_int_desc = &fs_ep_int_desc; 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci case USB_SPEED_HIGH: 82562306a36Sopenharmony_ci epout_desc = &hs_epout_desc; 82662306a36Sopenharmony_ci epin_desc = &hs_epin_desc; 82762306a36Sopenharmony_ci epin_fback_desc = &hs_epin_fback_desc; 82862306a36Sopenharmony_ci ep_int_desc = &hs_ep_int_desc; 82962306a36Sopenharmony_ci break; 83062306a36Sopenharmony_ci default: 83162306a36Sopenharmony_ci epout_desc = &ss_epout_desc; 83262306a36Sopenharmony_ci epin_desc = &ss_epin_desc; 83362306a36Sopenharmony_ci epout_desc_comp = &ss_epout_desc_comp; 83462306a36Sopenharmony_ci epin_desc_comp = &ss_epin_desc_comp; 83562306a36Sopenharmony_ci epin_fback_desc = &ss_epin_fback_desc; 83662306a36Sopenharmony_ci epin_fback_desc_comp = &ss_epin_fback_desc_comp; 83762306a36Sopenharmony_ci ep_int_desc = &ss_ep_int_desc; 83862306a36Sopenharmony_ci ep_int_desc_comp = &ss_ep_int_desc_comp; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci i = 0; 84262306a36Sopenharmony_ci headers[i++] = USBDHDR(&iad_desc); 84362306a36Sopenharmony_ci headers[i++] = USBDHDR(&std_ac_if_desc); 84462306a36Sopenharmony_ci headers[i++] = USBDHDR(&ac_hdr_desc); 84562306a36Sopenharmony_ci if (EPIN_EN(opts)) 84662306a36Sopenharmony_ci headers[i++] = USBDHDR(&in_clk_src_desc); 84762306a36Sopenharmony_ci if (EPOUT_EN(opts)) { 84862306a36Sopenharmony_ci headers[i++] = USBDHDR(&out_clk_src_desc); 84962306a36Sopenharmony_ci headers[i++] = USBDHDR(&usb_out_it_desc); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (FUOUT_EN(opts)) 85262306a36Sopenharmony_ci headers[i++] = USBDHDR(out_feature_unit_desc); 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (EPIN_EN(opts)) { 85662306a36Sopenharmony_ci headers[i++] = USBDHDR(&io_in_it_desc); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (FUIN_EN(opts)) 85962306a36Sopenharmony_ci headers[i++] = USBDHDR(in_feature_unit_desc); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci headers[i++] = USBDHDR(&usb_in_ot_desc); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (EPOUT_EN(opts)) 86562306a36Sopenharmony_ci headers[i++] = USBDHDR(&io_out_ot_desc); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (FUOUT_EN(opts) || FUIN_EN(opts)) { 86862306a36Sopenharmony_ci headers[i++] = USBDHDR(ep_int_desc); 86962306a36Sopenharmony_ci if (ep_int_desc_comp) 87062306a36Sopenharmony_ci headers[i++] = USBDHDR(ep_int_desc_comp); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (EPOUT_EN(opts)) { 87462306a36Sopenharmony_ci headers[i++] = USBDHDR(&std_as_out_if0_desc); 87562306a36Sopenharmony_ci headers[i++] = USBDHDR(&std_as_out_if1_desc); 87662306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_out_hdr_desc); 87762306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_out_fmt1_desc); 87862306a36Sopenharmony_ci headers[i++] = USBDHDR(epout_desc); 87962306a36Sopenharmony_ci if (epout_desc_comp) 88062306a36Sopenharmony_ci headers[i++] = USBDHDR(epout_desc_comp); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_iso_out_desc); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (EPOUT_FBACK_IN_EN(opts)) { 88562306a36Sopenharmony_ci headers[i++] = USBDHDR(epin_fback_desc); 88662306a36Sopenharmony_ci if (epin_fback_desc_comp) 88762306a36Sopenharmony_ci headers[i++] = USBDHDR(epin_fback_desc_comp); 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (EPIN_EN(opts)) { 89262306a36Sopenharmony_ci headers[i++] = USBDHDR(&std_as_in_if0_desc); 89362306a36Sopenharmony_ci headers[i++] = USBDHDR(&std_as_in_if1_desc); 89462306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_in_hdr_desc); 89562306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_in_fmt1_desc); 89662306a36Sopenharmony_ci headers[i++] = USBDHDR(epin_desc); 89762306a36Sopenharmony_ci if (epin_desc_comp) 89862306a36Sopenharmony_ci headers[i++] = USBDHDR(epin_desc_comp); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci headers[i++] = USBDHDR(&as_iso_in_desc); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci headers[i] = NULL; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic void setup_descriptor(struct f_uac2_opts *opts) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci /* patch descriptors */ 90862306a36Sopenharmony_ci int i = 1; /* ID's start with 1 */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (EPOUT_EN(opts)) 91162306a36Sopenharmony_ci usb_out_it_desc.bTerminalID = i++; 91262306a36Sopenharmony_ci if (EPIN_EN(opts)) 91362306a36Sopenharmony_ci io_in_it_desc.bTerminalID = i++; 91462306a36Sopenharmony_ci if (EPOUT_EN(opts)) 91562306a36Sopenharmony_ci io_out_ot_desc.bTerminalID = i++; 91662306a36Sopenharmony_ci if (EPIN_EN(opts)) 91762306a36Sopenharmony_ci usb_in_ot_desc.bTerminalID = i++; 91862306a36Sopenharmony_ci if (FUOUT_EN(opts)) 91962306a36Sopenharmony_ci out_feature_unit_desc->bUnitID = i++; 92062306a36Sopenharmony_ci if (FUIN_EN(opts)) 92162306a36Sopenharmony_ci in_feature_unit_desc->bUnitID = i++; 92262306a36Sopenharmony_ci if (EPOUT_EN(opts)) 92362306a36Sopenharmony_ci out_clk_src_desc.bClockID = i++; 92462306a36Sopenharmony_ci if (EPIN_EN(opts)) 92562306a36Sopenharmony_ci in_clk_src_desc.bClockID = i++; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (FUIN_EN(opts)) { 93062306a36Sopenharmony_ci usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; 93162306a36Sopenharmony_ci in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; 93262306a36Sopenharmony_ci } else { 93362306a36Sopenharmony_ci usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; 93762306a36Sopenharmony_ci io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; 93862306a36Sopenharmony_ci io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (FUOUT_EN(opts)) { 94162306a36Sopenharmony_ci io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; 94262306a36Sopenharmony_ci out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; 94362306a36Sopenharmony_ci } else { 94462306a36Sopenharmony_ci io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; 94862306a36Sopenharmony_ci as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci iad_desc.bInterfaceCount = 1; 95162306a36Sopenharmony_ci ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc)); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (EPIN_EN(opts)) { 95462306a36Sopenharmony_ci u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci len += sizeof(in_clk_src_desc); 95762306a36Sopenharmony_ci len += sizeof(usb_in_ot_desc); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (FUIN_EN(opts)) 96062306a36Sopenharmony_ci len += in_feature_unit_desc->bLength; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci len += sizeof(io_in_it_desc); 96362306a36Sopenharmony_ci ac_hdr_desc.wTotalLength = cpu_to_le16(len); 96462306a36Sopenharmony_ci iad_desc.bInterfaceCount++; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci if (EPOUT_EN(opts)) { 96762306a36Sopenharmony_ci u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci len += sizeof(out_clk_src_desc); 97062306a36Sopenharmony_ci len += sizeof(usb_out_it_desc); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (FUOUT_EN(opts)) 97362306a36Sopenharmony_ci len += out_feature_unit_desc->bLength; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci len += sizeof(io_out_ot_desc); 97662306a36Sopenharmony_ci ac_hdr_desc.wTotalLength = cpu_to_le16(len); 97762306a36Sopenharmony_ci iad_desc.bInterfaceCount++; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci setup_headers(opts, fs_audio_desc, USB_SPEED_FULL); 98162306a36Sopenharmony_ci setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH); 98262306a36Sopenharmony_ci setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER); 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic int afunc_validate_opts(struct g_audio *agdev, struct device *dev) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); 98862306a36Sopenharmony_ci const char *msg = NULL; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (!opts->p_chmask && !opts->c_chmask) 99162306a36Sopenharmony_ci msg = "no playback and capture channels"; 99262306a36Sopenharmony_ci else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) 99362306a36Sopenharmony_ci msg = "unsupported playback channels mask"; 99462306a36Sopenharmony_ci else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) 99562306a36Sopenharmony_ci msg = "unsupported capture channels mask"; 99662306a36Sopenharmony_ci else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) 99762306a36Sopenharmony_ci msg = "incorrect playback sample size"; 99862306a36Sopenharmony_ci else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) 99962306a36Sopenharmony_ci msg = "incorrect capture sample size"; 100062306a36Sopenharmony_ci else if (!opts->p_srates[0]) 100162306a36Sopenharmony_ci msg = "incorrect playback sampling rate"; 100262306a36Sopenharmony_ci else if (!opts->c_srates[0]) 100362306a36Sopenharmony_ci msg = "incorrect capture sampling rate"; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci else if (opts->p_volume_max <= opts->p_volume_min) 100662306a36Sopenharmony_ci msg = "incorrect playback volume max/min"; 100762306a36Sopenharmony_ci else if (opts->c_volume_max <= opts->c_volume_min) 100862306a36Sopenharmony_ci msg = "incorrect capture volume max/min"; 100962306a36Sopenharmony_ci else if (opts->p_volume_res <= 0) 101062306a36Sopenharmony_ci msg = "negative/zero playback volume resolution"; 101162306a36Sopenharmony_ci else if (opts->c_volume_res <= 0) 101262306a36Sopenharmony_ci msg = "negative/zero capture volume resolution"; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci else if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) 101562306a36Sopenharmony_ci msg = "incorrect playback volume resolution"; 101662306a36Sopenharmony_ci else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) 101762306a36Sopenharmony_ci msg = "incorrect capture volume resolution"; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci else if ((opts->p_hs_bint < 0) || (opts->p_hs_bint > 4)) 102062306a36Sopenharmony_ci msg = "incorrect playback HS/SS bInterval (1-4: fixed, 0: auto)"; 102162306a36Sopenharmony_ci else if ((opts->c_hs_bint < 0) || (opts->c_hs_bint > 4)) 102262306a36Sopenharmony_ci msg = "incorrect capture HS/SS bInterval (1-4: fixed, 0: auto)"; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (msg) { 102562306a36Sopenharmony_ci dev_err(dev, "Error: %s\n", msg); 102662306a36Sopenharmony_ci return -EINVAL; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int 103362306a36Sopenharmony_ciafunc_bind(struct usb_configuration *cfg, struct usb_function *fn) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 103662306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 103762306a36Sopenharmony_ci struct usb_composite_dev *cdev = cfg->cdev; 103862306a36Sopenharmony_ci struct usb_gadget *gadget = cdev->gadget; 103962306a36Sopenharmony_ci struct device *dev = &gadget->dev; 104062306a36Sopenharmony_ci struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev); 104162306a36Sopenharmony_ci struct usb_string *us; 104262306a36Sopenharmony_ci int ret; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ret = afunc_validate_opts(agdev, dev); 104562306a36Sopenharmony_ci if (ret) 104662306a36Sopenharmony_ci return ret; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci strings_fn[STR_ASSOC].s = uac2_opts->function_name; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); 105162306a36Sopenharmony_ci if (IS_ERR(us)) 105262306a36Sopenharmony_ci return PTR_ERR(us); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts)) { 105562306a36Sopenharmony_ci out_feature_unit_desc = build_fu_desc(uac2_opts->c_chmask); 105662306a36Sopenharmony_ci if (!out_feature_unit_desc) 105762306a36Sopenharmony_ci return -ENOMEM; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci if (FUIN_EN(uac2_opts)) { 106062306a36Sopenharmony_ci in_feature_unit_desc = build_fu_desc(uac2_opts->p_chmask); 106162306a36Sopenharmony_ci if (!in_feature_unit_desc) { 106262306a36Sopenharmony_ci ret = -ENOMEM; 106362306a36Sopenharmony_ci goto err_free_fu; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci iad_desc.iFunction = us[STR_ASSOC].id; 106862306a36Sopenharmony_ci std_ac_if_desc.iInterface = us[STR_IF_CTRL].id; 106962306a36Sopenharmony_ci in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id; 107062306a36Sopenharmony_ci out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id; 107162306a36Sopenharmony_ci usb_out_it_desc.iTerminal = us[STR_USB_IT].id; 107262306a36Sopenharmony_ci io_in_it_desc.iTerminal = us[STR_IO_IT].id; 107362306a36Sopenharmony_ci usb_in_ot_desc.iTerminal = us[STR_USB_OT].id; 107462306a36Sopenharmony_ci io_out_ot_desc.iTerminal = us[STR_IO_OT].id; 107562306a36Sopenharmony_ci std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id; 107662306a36Sopenharmony_ci std_as_out_if1_desc.iInterface = us[STR_AS_OUT_ALT1].id; 107762306a36Sopenharmony_ci std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id; 107862306a36Sopenharmony_ci std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts)) { 108162306a36Sopenharmony_ci u8 *i_feature = (u8 *)out_feature_unit_desc + 108262306a36Sopenharmony_ci out_feature_unit_desc->bLength - 1; 108362306a36Sopenharmony_ci *i_feature = us[STR_FU_OUT].id; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci if (FUIN_EN(uac2_opts)) { 108662306a36Sopenharmony_ci u8 *i_feature = (u8 *)in_feature_unit_desc + 108762306a36Sopenharmony_ci in_feature_unit_desc->bLength - 1; 108862306a36Sopenharmony_ci *i_feature = us[STR_FU_IN].id; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* Initialize the configurable parameters */ 109362306a36Sopenharmony_ci usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask); 109462306a36Sopenharmony_ci usb_out_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask); 109562306a36Sopenharmony_ci io_in_it_desc.bNrChannels = num_channels(uac2_opts->p_chmask); 109662306a36Sopenharmony_ci io_in_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask); 109762306a36Sopenharmony_ci as_out_hdr_desc.bNrChannels = num_channels(uac2_opts->c_chmask); 109862306a36Sopenharmony_ci as_out_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask); 109962306a36Sopenharmony_ci as_in_hdr_desc.bNrChannels = num_channels(uac2_opts->p_chmask); 110062306a36Sopenharmony_ci as_in_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask); 110162306a36Sopenharmony_ci as_out_fmt1_desc.bSubslotSize = uac2_opts->c_ssize; 110262306a36Sopenharmony_ci as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8; 110362306a36Sopenharmony_ci as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize; 110462306a36Sopenharmony_ci as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8; 110562306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts)) { 110662306a36Sopenharmony_ci __le32 *bma = (__le32 *)&out_feature_unit_desc->bmaControls[0]; 110762306a36Sopenharmony_ci u32 control = 0; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (uac2_opts->c_mute_present) 111062306a36Sopenharmony_ci control |= CONTROL_RDWR << FU_MUTE_CTRL; 111162306a36Sopenharmony_ci if (uac2_opts->c_volume_present) 111262306a36Sopenharmony_ci control |= CONTROL_RDWR << FU_VOL_CTRL; 111362306a36Sopenharmony_ci *bma = cpu_to_le32(control); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci if (FUIN_EN(uac2_opts)) { 111662306a36Sopenharmony_ci __le32 *bma = (__le32 *)&in_feature_unit_desc->bmaControls[0]; 111762306a36Sopenharmony_ci u32 control = 0; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (uac2_opts->p_mute_present) 112062306a36Sopenharmony_ci control |= CONTROL_RDWR << FU_MUTE_CTRL; 112162306a36Sopenharmony_ci if (uac2_opts->p_volume_present) 112262306a36Sopenharmony_ci control |= CONTROL_RDWR << FU_VOL_CTRL; 112362306a36Sopenharmony_ci *bma = cpu_to_le32(control); 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci ret = usb_interface_id(cfg, fn); 112762306a36Sopenharmony_ci if (ret < 0) { 112862306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 112962306a36Sopenharmony_ci goto err_free_fu; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci iad_desc.bFirstInterface = ret; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci std_ac_if_desc.bInterfaceNumber = ret; 113462306a36Sopenharmony_ci uac2->ac_intf = ret; 113562306a36Sopenharmony_ci uac2->ac_alt = 0; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (EPOUT_EN(uac2_opts)) { 113862306a36Sopenharmony_ci ret = usb_interface_id(cfg, fn); 113962306a36Sopenharmony_ci if (ret < 0) { 114062306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 114162306a36Sopenharmony_ci goto err_free_fu; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci std_as_out_if0_desc.bInterfaceNumber = ret; 114462306a36Sopenharmony_ci std_as_out_if1_desc.bInterfaceNumber = ret; 114562306a36Sopenharmony_ci std_as_out_if1_desc.bNumEndpoints = 1; 114662306a36Sopenharmony_ci uac2->as_out_intf = ret; 114762306a36Sopenharmony_ci uac2->as_out_alt = 0; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (EPOUT_FBACK_IN_EN(uac2_opts)) { 115062306a36Sopenharmony_ci fs_epout_desc.bmAttributes = 115162306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; 115262306a36Sopenharmony_ci hs_epout_desc.bmAttributes = 115362306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; 115462306a36Sopenharmony_ci ss_epout_desc.bmAttributes = 115562306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; 115662306a36Sopenharmony_ci std_as_out_if1_desc.bNumEndpoints++; 115762306a36Sopenharmony_ci } else { 115862306a36Sopenharmony_ci fs_epout_desc.bmAttributes = 115962306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; 116062306a36Sopenharmony_ci hs_epout_desc.bmAttributes = 116162306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; 116262306a36Sopenharmony_ci ss_epout_desc.bmAttributes = 116362306a36Sopenharmony_ci USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (EPIN_EN(uac2_opts)) { 116862306a36Sopenharmony_ci ret = usb_interface_id(cfg, fn); 116962306a36Sopenharmony_ci if (ret < 0) { 117062306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 117162306a36Sopenharmony_ci goto err_free_fu; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci std_as_in_if0_desc.bInterfaceNumber = ret; 117462306a36Sopenharmony_ci std_as_in_if1_desc.bInterfaceNumber = ret; 117562306a36Sopenharmony_ci uac2->as_in_intf = ret; 117662306a36Sopenharmony_ci uac2->as_in_alt = 0; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) { 118062306a36Sopenharmony_ci uac2->int_ep = usb_ep_autoconfig(gadget, &fs_ep_int_desc); 118162306a36Sopenharmony_ci if (!uac2->int_ep) { 118262306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 118362306a36Sopenharmony_ci ret = -ENODEV; 118462306a36Sopenharmony_ci goto err_free_fu; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci std_ac_if_desc.bNumEndpoints = 1; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci hs_epin_desc.bInterval = uac2_opts->p_hs_bint; 119162306a36Sopenharmony_ci ss_epin_desc.bInterval = uac2_opts->p_hs_bint; 119262306a36Sopenharmony_ci hs_epout_desc.bInterval = uac2_opts->c_hs_bint; 119362306a36Sopenharmony_ci ss_epout_desc.bInterval = uac2_opts->c_hs_bint; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* Calculate wMaxPacketSize according to audio bandwidth */ 119662306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epin_desc, 119762306a36Sopenharmony_ci USB_SPEED_FULL, true); 119862306a36Sopenharmony_ci if (ret < 0) { 119962306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 120062306a36Sopenharmony_ci return ret; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epout_desc, 120462306a36Sopenharmony_ci USB_SPEED_FULL, false); 120562306a36Sopenharmony_ci if (ret < 0) { 120662306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 120762306a36Sopenharmony_ci return ret; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epin_desc, 121162306a36Sopenharmony_ci USB_SPEED_HIGH, true); 121262306a36Sopenharmony_ci if (ret < 0) { 121362306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 121462306a36Sopenharmony_ci return ret; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epout_desc, 121862306a36Sopenharmony_ci USB_SPEED_HIGH, false); 121962306a36Sopenharmony_ci if (ret < 0) { 122062306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 122162306a36Sopenharmony_ci return ret; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epin_desc, 122562306a36Sopenharmony_ci USB_SPEED_SUPER, true); 122662306a36Sopenharmony_ci if (ret < 0) { 122762306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 122862306a36Sopenharmony_ci return ret; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epout_desc, 123262306a36Sopenharmony_ci USB_SPEED_SUPER, false); 123362306a36Sopenharmony_ci if (ret < 0) { 123462306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 123562306a36Sopenharmony_ci return ret; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (EPOUT_EN(uac2_opts)) { 123962306a36Sopenharmony_ci agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); 124062306a36Sopenharmony_ci if (!agdev->out_ep) { 124162306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 124262306a36Sopenharmony_ci ret = -ENODEV; 124362306a36Sopenharmony_ci goto err_free_fu; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci if (EPOUT_FBACK_IN_EN(uac2_opts)) { 124662306a36Sopenharmony_ci agdev->in_ep_fback = usb_ep_autoconfig(gadget, 124762306a36Sopenharmony_ci &fs_epin_fback_desc); 124862306a36Sopenharmony_ci if (!agdev->in_ep_fback) { 124962306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", 125062306a36Sopenharmony_ci __func__, __LINE__); 125162306a36Sopenharmony_ci ret = -ENODEV; 125262306a36Sopenharmony_ci goto err_free_fu; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (EPIN_EN(uac2_opts)) { 125862306a36Sopenharmony_ci agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); 125962306a36Sopenharmony_ci if (!agdev->in_ep) { 126062306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 126162306a36Sopenharmony_ci ret = -ENODEV; 126262306a36Sopenharmony_ci goto err_free_fu; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci agdev->in_ep_maxpsize = max_t(u16, 126762306a36Sopenharmony_ci le16_to_cpu(fs_epin_desc.wMaxPacketSize), 126862306a36Sopenharmony_ci le16_to_cpu(hs_epin_desc.wMaxPacketSize)); 126962306a36Sopenharmony_ci agdev->out_ep_maxpsize = max_t(u16, 127062306a36Sopenharmony_ci le16_to_cpu(fs_epout_desc.wMaxPacketSize), 127162306a36Sopenharmony_ci le16_to_cpu(hs_epout_desc.wMaxPacketSize)); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci agdev->in_ep_maxpsize = max_t(u16, agdev->in_ep_maxpsize, 127462306a36Sopenharmony_ci le16_to_cpu(ss_epin_desc.wMaxPacketSize)); 127562306a36Sopenharmony_ci agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize, 127662306a36Sopenharmony_ci le16_to_cpu(ss_epout_desc.wMaxPacketSize)); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci ss_epin_desc_comp.wBytesPerInterval = ss_epin_desc.wMaxPacketSize; 127962306a36Sopenharmony_ci ss_epout_desc_comp.wBytesPerInterval = ss_epout_desc.wMaxPacketSize; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci // HS and SS endpoint addresses are copied from autoconfigured FS descriptors 128262306a36Sopenharmony_ci hs_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; 128362306a36Sopenharmony_ci hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; 128462306a36Sopenharmony_ci hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; 128562306a36Sopenharmony_ci hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; 128662306a36Sopenharmony_ci ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; 128762306a36Sopenharmony_ci ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; 128862306a36Sopenharmony_ci ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; 128962306a36Sopenharmony_ci ss_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci setup_descriptor(uac2_opts); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc, 129462306a36Sopenharmony_ci ss_audio_desc); 129562306a36Sopenharmony_ci if (ret) 129662306a36Sopenharmony_ci goto err_free_fu; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci agdev->gadget = gadget; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci agdev->params.p_chmask = uac2_opts->p_chmask; 130162306a36Sopenharmony_ci memcpy(agdev->params.p_srates, uac2_opts->p_srates, 130262306a36Sopenharmony_ci sizeof(agdev->params.p_srates)); 130362306a36Sopenharmony_ci agdev->params.p_ssize = uac2_opts->p_ssize; 130462306a36Sopenharmony_ci if (FUIN_EN(uac2_opts)) { 130562306a36Sopenharmony_ci agdev->params.p_fu.id = USB_IN_FU_ID; 130662306a36Sopenharmony_ci agdev->params.p_fu.mute_present = uac2_opts->p_mute_present; 130762306a36Sopenharmony_ci agdev->params.p_fu.volume_present = uac2_opts->p_volume_present; 130862306a36Sopenharmony_ci agdev->params.p_fu.volume_min = uac2_opts->p_volume_min; 130962306a36Sopenharmony_ci agdev->params.p_fu.volume_max = uac2_opts->p_volume_max; 131062306a36Sopenharmony_ci agdev->params.p_fu.volume_res = uac2_opts->p_volume_res; 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci agdev->params.c_chmask = uac2_opts->c_chmask; 131362306a36Sopenharmony_ci memcpy(agdev->params.c_srates, uac2_opts->c_srates, 131462306a36Sopenharmony_ci sizeof(agdev->params.c_srates)); 131562306a36Sopenharmony_ci agdev->params.c_ssize = uac2_opts->c_ssize; 131662306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts)) { 131762306a36Sopenharmony_ci agdev->params.c_fu.id = USB_OUT_FU_ID; 131862306a36Sopenharmony_ci agdev->params.c_fu.mute_present = uac2_opts->c_mute_present; 131962306a36Sopenharmony_ci agdev->params.c_fu.volume_present = uac2_opts->c_volume_present; 132062306a36Sopenharmony_ci agdev->params.c_fu.volume_min = uac2_opts->c_volume_min; 132162306a36Sopenharmony_ci agdev->params.c_fu.volume_max = uac2_opts->c_volume_max; 132262306a36Sopenharmony_ci agdev->params.c_fu.volume_res = uac2_opts->c_volume_res; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci agdev->params.req_number = uac2_opts->req_number; 132562306a36Sopenharmony_ci agdev->params.fb_max = uac2_opts->fb_max; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) 132862306a36Sopenharmony_ci agdev->notify = afunc_notify; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget"); 133162306a36Sopenharmony_ci if (ret) 133262306a36Sopenharmony_ci goto err_free_descs; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci return 0; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cierr_free_descs: 133762306a36Sopenharmony_ci usb_free_all_descriptors(fn); 133862306a36Sopenharmony_ci agdev->gadget = NULL; 133962306a36Sopenharmony_cierr_free_fu: 134062306a36Sopenharmony_ci kfree(out_feature_unit_desc); 134162306a36Sopenharmony_ci out_feature_unit_desc = NULL; 134262306a36Sopenharmony_ci kfree(in_feature_unit_desc); 134362306a36Sopenharmony_ci in_feature_unit_desc = NULL; 134462306a36Sopenharmony_ci return ret; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic void 134862306a36Sopenharmony_ciafunc_notify_complete(struct usb_ep *_ep, struct usb_request *req) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct g_audio *agdev = req->context; 135162306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(&agdev->func); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci atomic_dec(&uac2->int_count); 135462306a36Sopenharmony_ci kfree(req->buf); 135562306a36Sopenharmony_ci usb_ep_free_request(_ep, req); 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic int 135962306a36Sopenharmony_ciafunc_notify(struct g_audio *agdev, int unit_id, int cs) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(&agdev->func); 136262306a36Sopenharmony_ci struct usb_request *req; 136362306a36Sopenharmony_ci struct uac2_interrupt_data_msg *msg; 136462306a36Sopenharmony_ci u16 w_index, w_value; 136562306a36Sopenharmony_ci int ret; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (!uac2->int_ep->enabled) 136862306a36Sopenharmony_ci return 0; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (atomic_inc_return(&uac2->int_count) > UAC2_DEF_INT_REQ_NUM) { 137162306a36Sopenharmony_ci atomic_dec(&uac2->int_count); 137262306a36Sopenharmony_ci return 0; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci req = usb_ep_alloc_request(uac2->int_ep, GFP_ATOMIC); 137662306a36Sopenharmony_ci if (req == NULL) { 137762306a36Sopenharmony_ci ret = -ENOMEM; 137862306a36Sopenharmony_ci goto err_dec_int_count; 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci msg = kzalloc(sizeof(*msg), GFP_ATOMIC); 138262306a36Sopenharmony_ci if (msg == NULL) { 138362306a36Sopenharmony_ci ret = -ENOMEM; 138462306a36Sopenharmony_ci goto err_free_request; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci w_index = unit_id << 8 | uac2->ac_intf; 138862306a36Sopenharmony_ci w_value = cs << 8; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci msg->bInfo = 0; /* Non-vendor, interface interrupt */ 139162306a36Sopenharmony_ci msg->bAttribute = UAC2_CS_CUR; 139262306a36Sopenharmony_ci msg->wIndex = cpu_to_le16(w_index); 139362306a36Sopenharmony_ci msg->wValue = cpu_to_le16(w_value); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci req->length = sizeof(*msg); 139662306a36Sopenharmony_ci req->buf = msg; 139762306a36Sopenharmony_ci req->context = agdev; 139862306a36Sopenharmony_ci req->complete = afunc_notify_complete; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci ret = usb_ep_queue(uac2->int_ep, req, GFP_ATOMIC); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci if (ret) 140362306a36Sopenharmony_ci goto err_free_msg; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci return 0; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cierr_free_msg: 140862306a36Sopenharmony_ci kfree(msg); 140962306a36Sopenharmony_cierr_free_request: 141062306a36Sopenharmony_ci usb_ep_free_request(uac2->int_ep, req); 141162306a36Sopenharmony_cierr_dec_int_count: 141262306a36Sopenharmony_ci atomic_dec(&uac2->int_count); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci return ret; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic int 141862306a36Sopenharmony_ciafunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci struct usb_composite_dev *cdev = fn->config->cdev; 142162306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 142262306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 142362306a36Sopenharmony_ci struct usb_gadget *gadget = cdev->gadget; 142462306a36Sopenharmony_ci struct device *dev = &gadget->dev; 142562306a36Sopenharmony_ci int ret = 0; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci /* No i/f has more than 2 alt settings */ 142862306a36Sopenharmony_ci if (alt > 1) { 142962306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 143062306a36Sopenharmony_ci return -EINVAL; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (intf == uac2->ac_intf) { 143462306a36Sopenharmony_ci /* Control I/f has only 1 AltSetting - 0 */ 143562306a36Sopenharmony_ci if (alt) { 143662306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 143762306a36Sopenharmony_ci return -EINVAL; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* restart interrupt endpoint */ 144162306a36Sopenharmony_ci if (uac2->int_ep) { 144262306a36Sopenharmony_ci usb_ep_disable(uac2->int_ep); 144362306a36Sopenharmony_ci config_ep_by_speed(gadget, &agdev->func, uac2->int_ep); 144462306a36Sopenharmony_ci usb_ep_enable(uac2->int_ep); 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return 0; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (intf == uac2->as_out_intf) { 145162306a36Sopenharmony_ci uac2->as_out_alt = alt; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (alt) 145462306a36Sopenharmony_ci ret = u_audio_start_capture(&uac2->g_audio); 145562306a36Sopenharmony_ci else 145662306a36Sopenharmony_ci u_audio_stop_capture(&uac2->g_audio); 145762306a36Sopenharmony_ci } else if (intf == uac2->as_in_intf) { 145862306a36Sopenharmony_ci uac2->as_in_alt = alt; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (alt) 146162306a36Sopenharmony_ci ret = u_audio_start_playback(&uac2->g_audio); 146262306a36Sopenharmony_ci else 146362306a36Sopenharmony_ci u_audio_stop_playback(&uac2->g_audio); 146462306a36Sopenharmony_ci } else { 146562306a36Sopenharmony_ci dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 146662306a36Sopenharmony_ci return -EINVAL; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return ret; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic int 147362306a36Sopenharmony_ciafunc_get_alt(struct usb_function *fn, unsigned intf) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 147662306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if (intf == uac2->ac_intf) 147962306a36Sopenharmony_ci return uac2->ac_alt; 148062306a36Sopenharmony_ci else if (intf == uac2->as_out_intf) 148162306a36Sopenharmony_ci return uac2->as_out_alt; 148262306a36Sopenharmony_ci else if (intf == uac2->as_in_intf) 148362306a36Sopenharmony_ci return uac2->as_in_alt; 148462306a36Sopenharmony_ci else 148562306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 148662306a36Sopenharmony_ci "%s:%d Invalid Interface %d!\n", 148762306a36Sopenharmony_ci __func__, __LINE__, intf); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci return -EINVAL; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic void 149362306a36Sopenharmony_ciafunc_disable(struct usb_function *fn) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci uac2->as_in_alt = 0; 149862306a36Sopenharmony_ci uac2->as_out_alt = 0; 149962306a36Sopenharmony_ci u_audio_stop_capture(&uac2->g_audio); 150062306a36Sopenharmony_ci u_audio_stop_playback(&uac2->g_audio); 150162306a36Sopenharmony_ci if (uac2->int_ep) 150262306a36Sopenharmony_ci usb_ep_disable(uac2->int_ep); 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic void 150662306a36Sopenharmony_ciafunc_suspend(struct usb_function *fn) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci u_audio_suspend(&uac2->g_audio); 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int 151462306a36Sopenharmony_ciin_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci struct usb_request *req = fn->config->cdev->req; 151762306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 151862306a36Sopenharmony_ci struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); 151962306a36Sopenharmony_ci u16 w_length = le16_to_cpu(cr->wLength); 152062306a36Sopenharmony_ci u16 w_index = le16_to_cpu(cr->wIndex); 152162306a36Sopenharmony_ci u16 w_value = le16_to_cpu(cr->wValue); 152262306a36Sopenharmony_ci u8 entity_id = (w_index >> 8) & 0xff; 152362306a36Sopenharmony_ci u8 control_selector = w_value >> 8; 152462306a36Sopenharmony_ci int value = -EOPNOTSUPP; 152562306a36Sopenharmony_ci u32 p_srate, c_srate; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci u_audio_get_playback_srate(agdev, &p_srate); 152862306a36Sopenharmony_ci u_audio_get_capture_srate(agdev, &c_srate); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { 153162306a36Sopenharmony_ci if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { 153262306a36Sopenharmony_ci struct cntrl_cur_lay3 c; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci memset(&c, 0, sizeof(struct cntrl_cur_lay3)); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (entity_id == USB_IN_CLK_ID) 153762306a36Sopenharmony_ci c.dCUR = cpu_to_le32(p_srate); 153862306a36Sopenharmony_ci else if (entity_id == USB_OUT_CLK_ID) 153962306a36Sopenharmony_ci c.dCUR = cpu_to_le32(c_srate); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci value = min_t(unsigned int, w_length, sizeof(c)); 154262306a36Sopenharmony_ci memcpy(req->buf, &c, value); 154362306a36Sopenharmony_ci } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { 154462306a36Sopenharmony_ci *(u8 *)req->buf = 1; 154562306a36Sopenharmony_ci value = min_t(unsigned int, w_length, 1); 154662306a36Sopenharmony_ci } else { 154762306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 154862306a36Sopenharmony_ci "%s:%d control_selector=%d TODO!\n", 154962306a36Sopenharmony_ci __func__, __LINE__, control_selector); 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || 155262306a36Sopenharmony_ci (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { 155362306a36Sopenharmony_ci unsigned int is_playback = 0; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) 155662306a36Sopenharmony_ci is_playback = 1; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (control_selector == UAC_FU_MUTE) { 155962306a36Sopenharmony_ci unsigned int mute; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci u_audio_get_mute(agdev, is_playback, &mute); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci *(u8 *)req->buf = mute; 156462306a36Sopenharmony_ci value = min_t(unsigned int, w_length, 1); 156562306a36Sopenharmony_ci } else if (control_selector == UAC_FU_VOLUME) { 156662306a36Sopenharmony_ci struct cntrl_cur_lay2 c; 156762306a36Sopenharmony_ci s16 volume; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci memset(&c, 0, sizeof(struct cntrl_cur_lay2)); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci u_audio_get_volume(agdev, is_playback, &volume); 157262306a36Sopenharmony_ci c.wCUR = cpu_to_le16(volume); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci value = min_t(unsigned int, w_length, sizeof(c)); 157562306a36Sopenharmony_ci memcpy(req->buf, &c, value); 157662306a36Sopenharmony_ci } else { 157762306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 157862306a36Sopenharmony_ci "%s:%d control_selector=%d TODO!\n", 157962306a36Sopenharmony_ci __func__, __LINE__, control_selector); 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci } else { 158262306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 158362306a36Sopenharmony_ci "%s:%d entity_id=%d control_selector=%d TODO!\n", 158462306a36Sopenharmony_ci __func__, __LINE__, entity_id, control_selector); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci return value; 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_cistatic int 159162306a36Sopenharmony_ciin_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct usb_request *req = fn->config->cdev->req; 159462306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 159562306a36Sopenharmony_ci struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); 159662306a36Sopenharmony_ci u16 w_length = le16_to_cpu(cr->wLength); 159762306a36Sopenharmony_ci u16 w_index = le16_to_cpu(cr->wIndex); 159862306a36Sopenharmony_ci u16 w_value = le16_to_cpu(cr->wValue); 159962306a36Sopenharmony_ci u8 entity_id = (w_index >> 8) & 0xff; 160062306a36Sopenharmony_ci u8 control_selector = w_value >> 8; 160162306a36Sopenharmony_ci int value = -EOPNOTSUPP; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { 160462306a36Sopenharmony_ci if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { 160562306a36Sopenharmony_ci struct cntrl_ranges_lay3_srates rs; 160662306a36Sopenharmony_ci int i; 160762306a36Sopenharmony_ci int wNumSubRanges = 0; 160862306a36Sopenharmony_ci int srate; 160962306a36Sopenharmony_ci int *srates; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (entity_id == USB_IN_CLK_ID) 161262306a36Sopenharmony_ci srates = opts->p_srates; 161362306a36Sopenharmony_ci else if (entity_id == USB_OUT_CLK_ID) 161462306a36Sopenharmony_ci srates = opts->c_srates; 161562306a36Sopenharmony_ci else 161662306a36Sopenharmony_ci return -EOPNOTSUPP; 161762306a36Sopenharmony_ci for (i = 0; i < UAC_MAX_RATES; i++) { 161862306a36Sopenharmony_ci srate = srates[i]; 161962306a36Sopenharmony_ci if (srate == 0) 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci rs.r[wNumSubRanges].dMIN = cpu_to_le32(srate); 162362306a36Sopenharmony_ci rs.r[wNumSubRanges].dMAX = cpu_to_le32(srate); 162462306a36Sopenharmony_ci rs.r[wNumSubRanges].dRES = 0; 162562306a36Sopenharmony_ci wNumSubRanges++; 162662306a36Sopenharmony_ci dev_dbg(&agdev->gadget->dev, 162762306a36Sopenharmony_ci "%s(): clk %d: rate ID %d: %d\n", 162862306a36Sopenharmony_ci __func__, entity_id, wNumSubRanges, srate); 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci rs.wNumSubRanges = cpu_to_le16(wNumSubRanges); 163162306a36Sopenharmony_ci value = min_t(unsigned int, w_length, ranges_lay3_size(rs)); 163262306a36Sopenharmony_ci dev_dbg(&agdev->gadget->dev, "%s(): sending %d rates, size %d\n", 163362306a36Sopenharmony_ci __func__, rs.wNumSubRanges, value); 163462306a36Sopenharmony_ci memcpy(req->buf, &rs, value); 163562306a36Sopenharmony_ci } else { 163662306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 163762306a36Sopenharmony_ci "%s:%d control_selector=%d TODO!\n", 163862306a36Sopenharmony_ci __func__, __LINE__, control_selector); 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || 164162306a36Sopenharmony_ci (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { 164262306a36Sopenharmony_ci unsigned int is_playback = 0; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) 164562306a36Sopenharmony_ci is_playback = 1; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (control_selector == UAC_FU_VOLUME) { 164862306a36Sopenharmony_ci struct cntrl_range_lay2 r; 164962306a36Sopenharmony_ci s16 max_db, min_db, res_db; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (is_playback) { 165262306a36Sopenharmony_ci max_db = opts->p_volume_max; 165362306a36Sopenharmony_ci min_db = opts->p_volume_min; 165462306a36Sopenharmony_ci res_db = opts->p_volume_res; 165562306a36Sopenharmony_ci } else { 165662306a36Sopenharmony_ci max_db = opts->c_volume_max; 165762306a36Sopenharmony_ci min_db = opts->c_volume_min; 165862306a36Sopenharmony_ci res_db = opts->c_volume_res; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci r.wMAX = cpu_to_le16(max_db); 166262306a36Sopenharmony_ci r.wMIN = cpu_to_le16(min_db); 166362306a36Sopenharmony_ci r.wRES = cpu_to_le16(res_db); 166462306a36Sopenharmony_ci r.wNumSubRanges = cpu_to_le16(1); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci value = min_t(unsigned int, w_length, sizeof(r)); 166762306a36Sopenharmony_ci memcpy(req->buf, &r, value); 166862306a36Sopenharmony_ci } else { 166962306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 167062306a36Sopenharmony_ci "%s:%d control_selector=%d TODO!\n", 167162306a36Sopenharmony_ci __func__, __LINE__, control_selector); 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci } else { 167462306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 167562306a36Sopenharmony_ci "%s:%d entity_id=%d control_selector=%d TODO!\n", 167662306a36Sopenharmony_ci __func__, __LINE__, entity_id, control_selector); 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci return value; 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic int 168362306a36Sopenharmony_ciac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci if (cr->bRequest == UAC2_CS_CUR) 168662306a36Sopenharmony_ci return in_rq_cur(fn, cr); 168762306a36Sopenharmony_ci else if (cr->bRequest == UAC2_CS_RANGE) 168862306a36Sopenharmony_ci return in_rq_range(fn, cr); 168962306a36Sopenharmony_ci else 169062306a36Sopenharmony_ci return -EOPNOTSUPP; 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic void uac2_cs_control_sam_freq(struct usb_ep *ep, struct usb_request *req) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci struct usb_function *fn = ep->driver_data; 169662306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 169762306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 169862306a36Sopenharmony_ci u32 val; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci if (req->actual != 4) 170162306a36Sopenharmony_ci return; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci val = le32_to_cpu(*((__le32 *)req->buf)); 170462306a36Sopenharmony_ci dev_dbg(&agdev->gadget->dev, "%s val: %d.\n", __func__, val); 170562306a36Sopenharmony_ci if (uac2->clock_id == USB_IN_CLK_ID) { 170662306a36Sopenharmony_ci u_audio_set_playback_srate(agdev, val); 170762306a36Sopenharmony_ci } else if (uac2->clock_id == USB_OUT_CLK_ID) { 170862306a36Sopenharmony_ci u_audio_set_capture_srate(agdev, val); 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic void 171362306a36Sopenharmony_ciout_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct g_audio *agdev = req->context; 171662306a36Sopenharmony_ci struct usb_composite_dev *cdev = agdev->func.config->cdev; 171762306a36Sopenharmony_ci struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); 171862306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(&agdev->func); 171962306a36Sopenharmony_ci struct usb_ctrlrequest *cr = &uac2->setup_cr; 172062306a36Sopenharmony_ci u16 w_index = le16_to_cpu(cr->wIndex); 172162306a36Sopenharmony_ci u16 w_value = le16_to_cpu(cr->wValue); 172262306a36Sopenharmony_ci u8 entity_id = (w_index >> 8) & 0xff; 172362306a36Sopenharmony_ci u8 control_selector = w_value >> 8; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (req->status != 0) { 172662306a36Sopenharmony_ci dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); 172762306a36Sopenharmony_ci return; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || 173162306a36Sopenharmony_ci (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { 173262306a36Sopenharmony_ci unsigned int is_playback = 0; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) 173562306a36Sopenharmony_ci is_playback = 1; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (control_selector == UAC_FU_MUTE) { 173862306a36Sopenharmony_ci u8 mute = *(u8 *)req->buf; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci u_audio_set_mute(agdev, is_playback, mute); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci return; 174362306a36Sopenharmony_ci } else if (control_selector == UAC_FU_VOLUME) { 174462306a36Sopenharmony_ci struct cntrl_cur_lay2 *c = req->buf; 174562306a36Sopenharmony_ci s16 volume; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci volume = le16_to_cpu(c->wCUR); 174862306a36Sopenharmony_ci u_audio_set_volume(agdev, is_playback, volume); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci return; 175162306a36Sopenharmony_ci } else { 175262306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 175362306a36Sopenharmony_ci "%s:%d control_selector=%d TODO!\n", 175462306a36Sopenharmony_ci __func__, __LINE__, control_selector); 175562306a36Sopenharmony_ci usb_ep_set_halt(ep); 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic int 176162306a36Sopenharmony_ciout_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci struct usb_composite_dev *cdev = fn->config->cdev; 176462306a36Sopenharmony_ci struct usb_request *req = fn->config->cdev->req; 176562306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 176662306a36Sopenharmony_ci struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); 176762306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 176862306a36Sopenharmony_ci u16 w_length = le16_to_cpu(cr->wLength); 176962306a36Sopenharmony_ci u16 w_index = le16_to_cpu(cr->wIndex); 177062306a36Sopenharmony_ci u16 w_value = le16_to_cpu(cr->wValue); 177162306a36Sopenharmony_ci u8 entity_id = (w_index >> 8) & 0xff; 177262306a36Sopenharmony_ci u8 control_selector = w_value >> 8; 177362306a36Sopenharmony_ci u8 clock_id = w_index >> 8; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { 177662306a36Sopenharmony_ci if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { 177762306a36Sopenharmony_ci dev_dbg(&agdev->gadget->dev, 177862306a36Sopenharmony_ci "control_selector UAC2_CS_CONTROL_SAM_FREQ, clock: %d\n", clock_id); 177962306a36Sopenharmony_ci cdev->gadget->ep0->driver_data = fn; 178062306a36Sopenharmony_ci uac2->clock_id = clock_id; 178162306a36Sopenharmony_ci req->complete = uac2_cs_control_sam_freq; 178262306a36Sopenharmony_ci return w_length; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || 178562306a36Sopenharmony_ci (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { 178662306a36Sopenharmony_ci memcpy(&uac2->setup_cr, cr, sizeof(*cr)); 178762306a36Sopenharmony_ci req->context = agdev; 178862306a36Sopenharmony_ci req->complete = out_rq_cur_complete; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci return w_length; 179162306a36Sopenharmony_ci } else { 179262306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 179362306a36Sopenharmony_ci "%s:%d entity_id=%d control_selector=%d TODO!\n", 179462306a36Sopenharmony_ci __func__, __LINE__, entity_id, control_selector); 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci return -EOPNOTSUPP; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic int 180062306a36Sopenharmony_cisetup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci struct f_uac2 *uac2 = func_to_uac2(fn); 180362306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 180462306a36Sopenharmony_ci u16 w_index = le16_to_cpu(cr->wIndex); 180562306a36Sopenharmony_ci u8 intf = w_index & 0xff; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (intf != uac2->ac_intf) { 180862306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 180962306a36Sopenharmony_ci "%s:%d Error!\n", __func__, __LINE__); 181062306a36Sopenharmony_ci return -EOPNOTSUPP; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci if (cr->bRequestType & USB_DIR_IN) 181462306a36Sopenharmony_ci return ac_rq_in(fn, cr); 181562306a36Sopenharmony_ci else if (cr->bRequest == UAC2_CS_CUR) 181662306a36Sopenharmony_ci return out_rq_cur(fn, cr); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci return -EOPNOTSUPP; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic int 182262306a36Sopenharmony_ciafunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci struct usb_composite_dev *cdev = fn->config->cdev; 182562306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(fn); 182662306a36Sopenharmony_ci struct usb_request *req = cdev->req; 182762306a36Sopenharmony_ci u16 w_length = le16_to_cpu(cr->wLength); 182862306a36Sopenharmony_ci int value = -EOPNOTSUPP; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* Only Class specific requests are supposed to reach here */ 183162306a36Sopenharmony_ci if ((cr->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) 183262306a36Sopenharmony_ci return -EOPNOTSUPP; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if ((cr->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE) 183562306a36Sopenharmony_ci value = setup_rq_inf(fn, cr); 183662306a36Sopenharmony_ci else 183762306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, "%s:%d Error!\n", 183862306a36Sopenharmony_ci __func__, __LINE__); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (value >= 0) { 184162306a36Sopenharmony_ci req->length = value; 184262306a36Sopenharmony_ci req->zero = value < w_length; 184362306a36Sopenharmony_ci value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); 184462306a36Sopenharmony_ci if (value < 0) { 184562306a36Sopenharmony_ci dev_err(&agdev->gadget->dev, 184662306a36Sopenharmony_ci "%s:%d Error!\n", __func__, __LINE__); 184762306a36Sopenharmony_ci req->status = 0; 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci return value; 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_cistatic inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci return container_of(to_config_group(item), struct f_uac2_opts, 185762306a36Sopenharmony_ci func_inst.group); 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_cistatic void f_uac2_attr_release(struct config_item *item) 186162306a36Sopenharmony_ci{ 186262306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci usb_put_function_instance(&opts->func_inst); 186562306a36Sopenharmony_ci} 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_cistatic struct configfs_item_operations f_uac2_item_ops = { 186862306a36Sopenharmony_ci .release = f_uac2_attr_release, 186962306a36Sopenharmony_ci}; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci#define uac2_kstrtou8 kstrtou8 187262306a36Sopenharmony_ci#define uac2_kstrtou32 kstrtou32 187362306a36Sopenharmony_ci#define uac2_kstrtos16 kstrtos16 187462306a36Sopenharmony_ci#define uac2_kstrtobool(s, base, res) kstrtobool((s), (res)) 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_cistatic const char *u8_fmt = "%u\n"; 187762306a36Sopenharmony_cistatic const char *u32_fmt = "%u\n"; 187862306a36Sopenharmony_cistatic const char *s16_fmt = "%hd\n"; 187962306a36Sopenharmony_cistatic const char *bool_fmt = "%u\n"; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci#define UAC2_ATTRIBUTE(type, name) \ 188262306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ 188362306a36Sopenharmony_ci char *page) \ 188462306a36Sopenharmony_ci{ \ 188562306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 188662306a36Sopenharmony_ci int result; \ 188762306a36Sopenharmony_ci \ 188862306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 188962306a36Sopenharmony_ci result = sprintf(page, type##_fmt, opts->name); \ 189062306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 189162306a36Sopenharmony_ci \ 189262306a36Sopenharmony_ci return result; \ 189362306a36Sopenharmony_ci} \ 189462306a36Sopenharmony_ci \ 189562306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ 189662306a36Sopenharmony_ci const char *page, size_t len) \ 189762306a36Sopenharmony_ci{ \ 189862306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 189962306a36Sopenharmony_ci int ret; \ 190062306a36Sopenharmony_ci type num; \ 190162306a36Sopenharmony_ci \ 190262306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 190362306a36Sopenharmony_ci if (opts->refcnt) { \ 190462306a36Sopenharmony_ci ret = -EBUSY; \ 190562306a36Sopenharmony_ci goto end; \ 190662306a36Sopenharmony_ci } \ 190762306a36Sopenharmony_ci \ 190862306a36Sopenharmony_ci ret = uac2_kstrto##type(page, 0, &num); \ 190962306a36Sopenharmony_ci if (ret) \ 191062306a36Sopenharmony_ci goto end; \ 191162306a36Sopenharmony_ci \ 191262306a36Sopenharmony_ci opts->name = num; \ 191362306a36Sopenharmony_ci ret = len; \ 191462306a36Sopenharmony_ci \ 191562306a36Sopenharmony_ciend: \ 191662306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 191762306a36Sopenharmony_ci return ret; \ 191862306a36Sopenharmony_ci} \ 191962306a36Sopenharmony_ci \ 192062306a36Sopenharmony_ciCONFIGFS_ATTR(f_uac2_opts_, name) 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci#define UAC2_ATTRIBUTE_SYNC(name) \ 192362306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ 192462306a36Sopenharmony_ci char *page) \ 192562306a36Sopenharmony_ci{ \ 192662306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 192762306a36Sopenharmony_ci int result; \ 192862306a36Sopenharmony_ci char *str; \ 192962306a36Sopenharmony_ci \ 193062306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 193162306a36Sopenharmony_ci switch (opts->name) { \ 193262306a36Sopenharmony_ci case USB_ENDPOINT_SYNC_ASYNC: \ 193362306a36Sopenharmony_ci str = "async"; \ 193462306a36Sopenharmony_ci break; \ 193562306a36Sopenharmony_ci case USB_ENDPOINT_SYNC_ADAPTIVE: \ 193662306a36Sopenharmony_ci str = "adaptive"; \ 193762306a36Sopenharmony_ci break; \ 193862306a36Sopenharmony_ci default: \ 193962306a36Sopenharmony_ci str = "unknown"; \ 194062306a36Sopenharmony_ci break; \ 194162306a36Sopenharmony_ci } \ 194262306a36Sopenharmony_ci result = sprintf(page, "%s\n", str); \ 194362306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 194462306a36Sopenharmony_ci \ 194562306a36Sopenharmony_ci return result; \ 194662306a36Sopenharmony_ci} \ 194762306a36Sopenharmony_ci \ 194862306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ 194962306a36Sopenharmony_ci const char *page, size_t len) \ 195062306a36Sopenharmony_ci{ \ 195162306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 195262306a36Sopenharmony_ci int ret = 0; \ 195362306a36Sopenharmony_ci \ 195462306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 195562306a36Sopenharmony_ci if (opts->refcnt) { \ 195662306a36Sopenharmony_ci ret = -EBUSY; \ 195762306a36Sopenharmony_ci goto end; \ 195862306a36Sopenharmony_ci } \ 195962306a36Sopenharmony_ci \ 196062306a36Sopenharmony_ci if (!strncmp(page, "async", 5)) \ 196162306a36Sopenharmony_ci opts->name = USB_ENDPOINT_SYNC_ASYNC; \ 196262306a36Sopenharmony_ci else if (!strncmp(page, "adaptive", 8)) \ 196362306a36Sopenharmony_ci opts->name = USB_ENDPOINT_SYNC_ADAPTIVE; \ 196462306a36Sopenharmony_ci else { \ 196562306a36Sopenharmony_ci ret = -EINVAL; \ 196662306a36Sopenharmony_ci goto end; \ 196762306a36Sopenharmony_ci } \ 196862306a36Sopenharmony_ci \ 196962306a36Sopenharmony_ci ret = len; \ 197062306a36Sopenharmony_ci \ 197162306a36Sopenharmony_ciend: \ 197262306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 197362306a36Sopenharmony_ci return ret; \ 197462306a36Sopenharmony_ci} \ 197562306a36Sopenharmony_ci \ 197662306a36Sopenharmony_ciCONFIGFS_ATTR(f_uac2_opts_, name) 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci#define UAC2_RATE_ATTRIBUTE(name) \ 197962306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ 198062306a36Sopenharmony_ci char *page) \ 198162306a36Sopenharmony_ci{ \ 198262306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 198362306a36Sopenharmony_ci int result = 0; \ 198462306a36Sopenharmony_ci int i; \ 198562306a36Sopenharmony_ci \ 198662306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 198762306a36Sopenharmony_ci page[0] = '\0'; \ 198862306a36Sopenharmony_ci for (i = 0; i < UAC_MAX_RATES; i++) { \ 198962306a36Sopenharmony_ci if (opts->name##s[i] == 0) \ 199062306a36Sopenharmony_ci break; \ 199162306a36Sopenharmony_ci result += sprintf(page + strlen(page), "%u,", \ 199262306a36Sopenharmony_ci opts->name##s[i]); \ 199362306a36Sopenharmony_ci } \ 199462306a36Sopenharmony_ci if (strlen(page) > 0) \ 199562306a36Sopenharmony_ci page[strlen(page) - 1] = '\n'; \ 199662306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 199762306a36Sopenharmony_ci \ 199862306a36Sopenharmony_ci return result; \ 199962306a36Sopenharmony_ci} \ 200062306a36Sopenharmony_ci \ 200162306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ 200262306a36Sopenharmony_ci const char *page, size_t len) \ 200362306a36Sopenharmony_ci{ \ 200462306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 200562306a36Sopenharmony_ci char *split_page = NULL; \ 200662306a36Sopenharmony_ci int ret = -EINVAL; \ 200762306a36Sopenharmony_ci char *token; \ 200862306a36Sopenharmony_ci u32 num; \ 200962306a36Sopenharmony_ci int i; \ 201062306a36Sopenharmony_ci \ 201162306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 201262306a36Sopenharmony_ci if (opts->refcnt) { \ 201362306a36Sopenharmony_ci ret = -EBUSY; \ 201462306a36Sopenharmony_ci goto end; \ 201562306a36Sopenharmony_ci } \ 201662306a36Sopenharmony_ci \ 201762306a36Sopenharmony_ci i = 0; \ 201862306a36Sopenharmony_ci memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ 201962306a36Sopenharmony_ci split_page = kstrdup(page, GFP_KERNEL); \ 202062306a36Sopenharmony_ci while ((token = strsep(&split_page, ",")) != NULL) { \ 202162306a36Sopenharmony_ci ret = kstrtou32(token, 0, &num); \ 202262306a36Sopenharmony_ci if (ret) \ 202362306a36Sopenharmony_ci goto end; \ 202462306a36Sopenharmony_ci \ 202562306a36Sopenharmony_ci opts->name##s[i++] = num; \ 202662306a36Sopenharmony_ci ret = len; \ 202762306a36Sopenharmony_ci }; \ 202862306a36Sopenharmony_ci \ 202962306a36Sopenharmony_ciend: \ 203062306a36Sopenharmony_ci kfree(split_page); \ 203162306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 203262306a36Sopenharmony_ci return ret; \ 203362306a36Sopenharmony_ci} \ 203462306a36Sopenharmony_ci \ 203562306a36Sopenharmony_ciCONFIGFS_ATTR(f_uac2_opts_, name) 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci#define UAC2_ATTRIBUTE_STRING(name) \ 203862306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ 203962306a36Sopenharmony_ci char *page) \ 204062306a36Sopenharmony_ci{ \ 204162306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 204262306a36Sopenharmony_ci int result; \ 204362306a36Sopenharmony_ci \ 204462306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 204562306a36Sopenharmony_ci result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ 204662306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 204762306a36Sopenharmony_ci \ 204862306a36Sopenharmony_ci return result; \ 204962306a36Sopenharmony_ci} \ 205062306a36Sopenharmony_ci \ 205162306a36Sopenharmony_cistatic ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ 205262306a36Sopenharmony_ci const char *page, size_t len) \ 205362306a36Sopenharmony_ci{ \ 205462306a36Sopenharmony_ci struct f_uac2_opts *opts = to_f_uac2_opts(item); \ 205562306a36Sopenharmony_ci int ret = 0; \ 205662306a36Sopenharmony_ci \ 205762306a36Sopenharmony_ci mutex_lock(&opts->lock); \ 205862306a36Sopenharmony_ci if (opts->refcnt) { \ 205962306a36Sopenharmony_ci ret = -EBUSY; \ 206062306a36Sopenharmony_ci goto end; \ 206162306a36Sopenharmony_ci } \ 206262306a36Sopenharmony_ci \ 206362306a36Sopenharmony_ci ret = snprintf(opts->name, min(sizeof(opts->name), len), \ 206462306a36Sopenharmony_ci "%s", page); \ 206562306a36Sopenharmony_ci \ 206662306a36Sopenharmony_ciend: \ 206762306a36Sopenharmony_ci mutex_unlock(&opts->lock); \ 206862306a36Sopenharmony_ci return ret; \ 206962306a36Sopenharmony_ci} \ 207062306a36Sopenharmony_ci \ 207162306a36Sopenharmony_ciCONFIGFS_ATTR(f_uac2_opts_, name) 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, p_chmask); 207462306a36Sopenharmony_ciUAC2_RATE_ATTRIBUTE(p_srate); 207562306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, p_ssize); 207662306a36Sopenharmony_ciUAC2_ATTRIBUTE(u8, p_hs_bint); 207762306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, c_chmask); 207862306a36Sopenharmony_ciUAC2_RATE_ATTRIBUTE(c_srate); 207962306a36Sopenharmony_ciUAC2_ATTRIBUTE_SYNC(c_sync); 208062306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, c_ssize); 208162306a36Sopenharmony_ciUAC2_ATTRIBUTE(u8, c_hs_bint); 208262306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, req_number); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ciUAC2_ATTRIBUTE(bool, p_mute_present); 208562306a36Sopenharmony_ciUAC2_ATTRIBUTE(bool, p_volume_present); 208662306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, p_volume_min); 208762306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, p_volume_max); 208862306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, p_volume_res); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ciUAC2_ATTRIBUTE(bool, c_mute_present); 209162306a36Sopenharmony_ciUAC2_ATTRIBUTE(bool, c_volume_present); 209262306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, c_volume_min); 209362306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, c_volume_max); 209462306a36Sopenharmony_ciUAC2_ATTRIBUTE(s16, c_volume_res); 209562306a36Sopenharmony_ciUAC2_ATTRIBUTE(u32, fb_max); 209662306a36Sopenharmony_ciUAC2_ATTRIBUTE_STRING(function_name); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_cistatic struct configfs_attribute *f_uac2_attrs[] = { 209962306a36Sopenharmony_ci &f_uac2_opts_attr_p_chmask, 210062306a36Sopenharmony_ci &f_uac2_opts_attr_p_srate, 210162306a36Sopenharmony_ci &f_uac2_opts_attr_p_ssize, 210262306a36Sopenharmony_ci &f_uac2_opts_attr_p_hs_bint, 210362306a36Sopenharmony_ci &f_uac2_opts_attr_c_chmask, 210462306a36Sopenharmony_ci &f_uac2_opts_attr_c_srate, 210562306a36Sopenharmony_ci &f_uac2_opts_attr_c_ssize, 210662306a36Sopenharmony_ci &f_uac2_opts_attr_c_hs_bint, 210762306a36Sopenharmony_ci &f_uac2_opts_attr_c_sync, 210862306a36Sopenharmony_ci &f_uac2_opts_attr_req_number, 210962306a36Sopenharmony_ci &f_uac2_opts_attr_fb_max, 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci &f_uac2_opts_attr_p_mute_present, 211262306a36Sopenharmony_ci &f_uac2_opts_attr_p_volume_present, 211362306a36Sopenharmony_ci &f_uac2_opts_attr_p_volume_min, 211462306a36Sopenharmony_ci &f_uac2_opts_attr_p_volume_max, 211562306a36Sopenharmony_ci &f_uac2_opts_attr_p_volume_res, 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci &f_uac2_opts_attr_c_mute_present, 211862306a36Sopenharmony_ci &f_uac2_opts_attr_c_volume_present, 211962306a36Sopenharmony_ci &f_uac2_opts_attr_c_volume_min, 212062306a36Sopenharmony_ci &f_uac2_opts_attr_c_volume_max, 212162306a36Sopenharmony_ci &f_uac2_opts_attr_c_volume_res, 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci &f_uac2_opts_attr_function_name, 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci NULL, 212662306a36Sopenharmony_ci}; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_cistatic const struct config_item_type f_uac2_func_type = { 212962306a36Sopenharmony_ci .ct_item_ops = &f_uac2_item_ops, 213062306a36Sopenharmony_ci .ct_attrs = f_uac2_attrs, 213162306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 213262306a36Sopenharmony_ci}; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_cistatic void afunc_free_inst(struct usb_function_instance *f) 213562306a36Sopenharmony_ci{ 213662306a36Sopenharmony_ci struct f_uac2_opts *opts; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci opts = container_of(f, struct f_uac2_opts, func_inst); 213962306a36Sopenharmony_ci kfree(opts); 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_cistatic struct usb_function_instance *afunc_alloc_inst(void) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci struct f_uac2_opts *opts; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci opts = kzalloc(sizeof(*opts), GFP_KERNEL); 214762306a36Sopenharmony_ci if (!opts) 214862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci mutex_init(&opts->lock); 215162306a36Sopenharmony_ci opts->func_inst.free_func_inst = afunc_free_inst; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci config_group_init_type_name(&opts->func_inst.group, "", 215462306a36Sopenharmony_ci &f_uac2_func_type); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci opts->p_chmask = UAC2_DEF_PCHMASK; 215762306a36Sopenharmony_ci opts->p_srates[0] = UAC2_DEF_PSRATE; 215862306a36Sopenharmony_ci opts->p_ssize = UAC2_DEF_PSSIZE; 215962306a36Sopenharmony_ci opts->p_hs_bint = UAC2_DEF_PHSBINT; 216062306a36Sopenharmony_ci opts->c_chmask = UAC2_DEF_CCHMASK; 216162306a36Sopenharmony_ci opts->c_srates[0] = UAC2_DEF_CSRATE; 216262306a36Sopenharmony_ci opts->c_ssize = UAC2_DEF_CSSIZE; 216362306a36Sopenharmony_ci opts->c_hs_bint = UAC2_DEF_CHSBINT; 216462306a36Sopenharmony_ci opts->c_sync = UAC2_DEF_CSYNC; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci opts->p_mute_present = UAC2_DEF_MUTE_PRESENT; 216762306a36Sopenharmony_ci opts->p_volume_present = UAC2_DEF_VOLUME_PRESENT; 216862306a36Sopenharmony_ci opts->p_volume_min = UAC2_DEF_MIN_DB; 216962306a36Sopenharmony_ci opts->p_volume_max = UAC2_DEF_MAX_DB; 217062306a36Sopenharmony_ci opts->p_volume_res = UAC2_DEF_RES_DB; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci opts->c_mute_present = UAC2_DEF_MUTE_PRESENT; 217362306a36Sopenharmony_ci opts->c_volume_present = UAC2_DEF_VOLUME_PRESENT; 217462306a36Sopenharmony_ci opts->c_volume_min = UAC2_DEF_MIN_DB; 217562306a36Sopenharmony_ci opts->c_volume_max = UAC2_DEF_MAX_DB; 217662306a36Sopenharmony_ci opts->c_volume_res = UAC2_DEF_RES_DB; 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci opts->req_number = UAC2_DEF_REQ_NUM; 217962306a36Sopenharmony_ci opts->fb_max = FBACK_FAST_MAX; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci return &opts->func_inst; 218462306a36Sopenharmony_ci} 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_cistatic void afunc_free(struct usb_function *f) 218762306a36Sopenharmony_ci{ 218862306a36Sopenharmony_ci struct g_audio *agdev; 218962306a36Sopenharmony_ci struct f_uac2_opts *opts; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci agdev = func_to_g_audio(f); 219262306a36Sopenharmony_ci opts = container_of(f->fi, struct f_uac2_opts, func_inst); 219362306a36Sopenharmony_ci kfree(agdev); 219462306a36Sopenharmony_ci mutex_lock(&opts->lock); 219562306a36Sopenharmony_ci --opts->refcnt; 219662306a36Sopenharmony_ci mutex_unlock(&opts->lock); 219762306a36Sopenharmony_ci} 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic void afunc_unbind(struct usb_configuration *c, struct usb_function *f) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci struct g_audio *agdev = func_to_g_audio(f); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci g_audio_cleanup(agdev); 220462306a36Sopenharmony_ci usb_free_all_descriptors(f); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci agdev->gadget = NULL; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci kfree(out_feature_unit_desc); 220962306a36Sopenharmony_ci out_feature_unit_desc = NULL; 221062306a36Sopenharmony_ci kfree(in_feature_unit_desc); 221162306a36Sopenharmony_ci in_feature_unit_desc = NULL; 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic struct usb_function *afunc_alloc(struct usb_function_instance *fi) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci struct f_uac2 *uac2; 221762306a36Sopenharmony_ci struct f_uac2_opts *opts; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL); 222062306a36Sopenharmony_ci if (uac2 == NULL) 222162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci opts = container_of(fi, struct f_uac2_opts, func_inst); 222462306a36Sopenharmony_ci mutex_lock(&opts->lock); 222562306a36Sopenharmony_ci ++opts->refcnt; 222662306a36Sopenharmony_ci mutex_unlock(&opts->lock); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci uac2->g_audio.func.name = "uac2_func"; 222962306a36Sopenharmony_ci uac2->g_audio.func.bind = afunc_bind; 223062306a36Sopenharmony_ci uac2->g_audio.func.unbind = afunc_unbind; 223162306a36Sopenharmony_ci uac2->g_audio.func.set_alt = afunc_set_alt; 223262306a36Sopenharmony_ci uac2->g_audio.func.get_alt = afunc_get_alt; 223362306a36Sopenharmony_ci uac2->g_audio.func.disable = afunc_disable; 223462306a36Sopenharmony_ci uac2->g_audio.func.suspend = afunc_suspend; 223562306a36Sopenharmony_ci uac2->g_audio.func.setup = afunc_setup; 223662306a36Sopenharmony_ci uac2->g_audio.func.free_func = afunc_free; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci return &uac2->g_audio.func; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ciDECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc); 224262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 224362306a36Sopenharmony_ciMODULE_AUTHOR("Yadwinder Singh"); 224462306a36Sopenharmony_ciMODULE_AUTHOR("Jaswinder Singh"); 224562306a36Sopenharmony_ciMODULE_AUTHOR("Ruslan Bilovol"); 2246