blob: 5d63244ba319cb555e36d762e42419a31692d1e9 [file] [log] [blame]
Greg Kroah-Hartman5fd54ac2017-11-03 11:28:30 +01001// SPDX-License-Identifier: GPL-2.0+
Jassi Brar132fcb42012-02-02 22:01:34 +05302/*
3 * f_uac2.c -- USB Audio Class 2.0 Function
4 *
5 * Copyright (C) 2011
6 * Yadwinder Singh (yadi.brar01@gmail.com)
7 * Jaswinder Singh (jaswinder.singh@linaro.org)
Jassi Brar132fcb42012-02-02 22:01:34 +05308 */
9
10#include <linux/usb/audio.h>
11#include <linux/usb/audio-v2.h>
Jassi Brar132fcb42012-02-02 22:01:34 +053012#include <linux/module.h>
13
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +030014#include "u_audio.h"
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +020015#include "u_uac2.h"
16
Ruslan Bilovol3713d5c2021-03-01 13:49:33 +020017/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */
18#define UAC2_CHANNEL_MASK 0x07FFFFFF
19
Jassi Brar132fcb42012-02-02 22:01:34 +053020/*
21 * The driver implements a simple UAC_2 topology.
22 * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
23 * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN
24 * Capture and Playback sampling rates are independently
25 * controlled by two clock sources :
26 * CLK_5 := c_srate, and CLK_6 := p_srate
27 */
Andreas Pape3fa4eaa2018-06-21 17:22:51 +020028#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID)
29#define USB_IN_CLK_ID (in_clk_src_desc.bClockID)
Jassi Brar132fcb42012-02-02 22:01:34 +053030
31#define CONTROL_ABSENT 0
32#define CONTROL_RDONLY 1
33#define CONTROL_RDWR 3
34
35#define CLK_FREQ_CTRL 0
36#define CLK_VLD_CTRL 2
37
38#define COPY_CTRL 0
39#define CONN_CTRL 2
40#define OVRLD_CTRL 4
41#define CLSTR_CTRL 6
42#define UNFLW_CTRL 8
43#define OVFLW_CTRL 10
44
Andreas Pape3fa4eaa2018-06-21 17:22:51 +020045#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
46#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
47
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +030048struct f_uac2 {
49 struct g_audio g_audio;
50 u8 ac_intf, as_in_intf, as_out_intf;
51 u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */
Jassi Brar132fcb42012-02-02 22:01:34 +053052};
53
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +030054static inline struct f_uac2 *func_to_uac2(struct usb_function *f)
Jassi Brar132fcb42012-02-02 22:01:34 +053055{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +030056 return container_of(f, struct f_uac2, g_audio.func);
Jassi Brar132fcb42012-02-02 22:01:34 +053057}
58
59static inline
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +030060struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev)
Daniel Mack254b3bf2014-08-27 19:09:05 +020061{
62 return container_of(agdev->func.fi, struct f_uac2_opts, func_inst);
63}
64
Jassi Brar132fcb42012-02-02 22:01:34 +053065/* --------- USB Function Interface ------------- */
66
67enum {
68 STR_ASSOC,
69 STR_IF_CTRL,
70 STR_CLKSRC_IN,
71 STR_CLKSRC_OUT,
72 STR_USB_IT,
73 STR_IO_IT,
74 STR_USB_OT,
75 STR_IO_OT,
76 STR_AS_OUT_ALT0,
77 STR_AS_OUT_ALT1,
78 STR_AS_IN_ALT0,
79 STR_AS_IN_ALT1,
80};
81
Jassi Brar132fcb42012-02-02 22:01:34 +053082static char clksrc_in[8];
83static char clksrc_out[8];
Jassi Brar132fcb42012-02-02 22:01:34 +053084
85static struct usb_string strings_fn[] = {
Sebastian Andrzej Siewiorb36c3472012-10-22 22:15:09 +020086 [STR_ASSOC].s = "Source/Sink",
87 [STR_IF_CTRL].s = "Topology Control",
Jassi Brar132fcb42012-02-02 22:01:34 +053088 [STR_CLKSRC_IN].s = clksrc_in,
89 [STR_CLKSRC_OUT].s = clksrc_out,
Sebastian Andrzej Siewiorb36c3472012-10-22 22:15:09 +020090 [STR_USB_IT].s = "USBH Out",
91 [STR_IO_IT].s = "USBD Out",
92 [STR_USB_OT].s = "USBH In",
93 [STR_IO_OT].s = "USBD In",
94 [STR_AS_OUT_ALT0].s = "Playback Inactive",
95 [STR_AS_OUT_ALT1].s = "Playback Active",
96 [STR_AS_IN_ALT0].s = "Capture Inactive",
97 [STR_AS_IN_ALT1].s = "Capture Active",
Jassi Brar132fcb42012-02-02 22:01:34 +053098 { },
99};
100
101static struct usb_gadget_strings str_fn = {
102 .language = 0x0409, /* en-us */
103 .strings = strings_fn,
104};
105
106static struct usb_gadget_strings *fn_strings[] = {
107 &str_fn,
108 NULL,
109};
110
Jassi Brar132fcb42012-02-02 22:01:34 +0530111static struct usb_interface_assoc_descriptor iad_desc = {
112 .bLength = sizeof iad_desc,
113 .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
114
115 .bFirstInterface = 0,
116 .bInterfaceCount = 3,
117 .bFunctionClass = USB_CLASS_AUDIO,
118 .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED,
119 .bFunctionProtocol = UAC_VERSION_2,
120};
121
122/* Audio Control Interface */
123static struct usb_interface_descriptor std_ac_if_desc = {
124 .bLength = sizeof std_ac_if_desc,
125 .bDescriptorType = USB_DT_INTERFACE,
126
127 .bAlternateSetting = 0,
128 .bNumEndpoints = 0,
129 .bInterfaceClass = USB_CLASS_AUDIO,
130 .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
131 .bInterfaceProtocol = UAC_VERSION_2,
132};
133
134/* Clock source for IN traffic */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000135static struct uac_clock_source_descriptor in_clk_src_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530136 .bLength = sizeof in_clk_src_desc,
137 .bDescriptorType = USB_DT_CS_INTERFACE,
138
139 .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200140 /* .bClockID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530141 .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
142 .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
143 .bAssocTerminal = 0,
144};
145
146/* Clock source for OUT traffic */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000147static struct uac_clock_source_descriptor out_clk_src_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530148 .bLength = sizeof out_clk_src_desc,
149 .bDescriptorType = USB_DT_CS_INTERFACE,
150
151 .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200152 /* .bClockID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530153 .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
154 .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
155 .bAssocTerminal = 0,
156};
157
158/* Input Terminal for USB_OUT */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000159static struct uac2_input_terminal_descriptor usb_out_it_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530160 .bLength = sizeof usb_out_it_desc,
161 .bDescriptorType = USB_DT_CS_INTERFACE,
162
163 .bDescriptorSubtype = UAC_INPUT_TERMINAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200164 /* .bTerminalID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530165 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
166 .bAssocTerminal = 0,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200167 /* .bCSourceID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530168 .iChannelNames = 0,
Ruslan Bilovol14e1d562017-06-25 16:23:47 +0300169 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
Jassi Brar132fcb42012-02-02 22:01:34 +0530170};
171
172/* Input Terminal for I/O-In */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000173static struct uac2_input_terminal_descriptor io_in_it_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530174 .bLength = sizeof io_in_it_desc,
175 .bDescriptorType = USB_DT_CS_INTERFACE,
176
177 .bDescriptorSubtype = UAC_INPUT_TERMINAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200178 /* .bTerminalID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530179 .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
180 .bAssocTerminal = 0,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200181 /* .bCSourceID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530182 .iChannelNames = 0,
Ruslan Bilovol14e1d562017-06-25 16:23:47 +0300183 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
Jassi Brar132fcb42012-02-02 22:01:34 +0530184};
185
186/* Ouput Terminal for USB_IN */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000187static struct uac2_output_terminal_descriptor usb_in_ot_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530188 .bLength = sizeof usb_in_ot_desc,
189 .bDescriptorType = USB_DT_CS_INTERFACE,
190
191 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200192 /* .bTerminalID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530193 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
194 .bAssocTerminal = 0,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200195 /* .bSourceID = DYNAMIC */
196 /* .bCSourceID = DYNAMIC */
Ruslan Bilovol14e1d562017-06-25 16:23:47 +0300197 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
Jassi Brar132fcb42012-02-02 22:01:34 +0530198};
199
200/* Ouput Terminal for I/O-Out */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000201static struct uac2_output_terminal_descriptor io_out_ot_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530202 .bLength = sizeof io_out_ot_desc,
203 .bDescriptorType = USB_DT_CS_INTERFACE,
204
205 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200206 /* .bTerminalID = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530207 .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
208 .bAssocTerminal = 0,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200209 /* .bSourceID = DYNAMIC */
210 /* .bCSourceID = DYNAMIC */
Ruslan Bilovol14e1d562017-06-25 16:23:47 +0300211 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL),
Jassi Brar132fcb42012-02-02 22:01:34 +0530212};
213
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000214static struct uac2_ac_header_descriptor ac_hdr_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530215 .bLength = sizeof ac_hdr_desc,
216 .bDescriptorType = USB_DT_CS_INTERFACE,
217
218 .bDescriptorSubtype = UAC_MS_HEADER,
219 .bcdADC = cpu_to_le16(0x200),
220 .bCategory = UAC2_FUNCTION_IO_BOX,
Ruslan Bilovola9cf8712020-07-03 16:49:03 +0300221 /* .wTotalLength = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530222 .bmControls = 0,
223};
224
225/* Audio Streaming OUT Interface - Alt0 */
226static struct usb_interface_descriptor std_as_out_if0_desc = {
227 .bLength = sizeof std_as_out_if0_desc,
228 .bDescriptorType = USB_DT_INTERFACE,
229
230 .bAlternateSetting = 0,
231 .bNumEndpoints = 0,
232 .bInterfaceClass = USB_CLASS_AUDIO,
233 .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
234 .bInterfaceProtocol = UAC_VERSION_2,
235};
236
237/* Audio Streaming OUT Interface - Alt1 */
238static struct usb_interface_descriptor std_as_out_if1_desc = {
239 .bLength = sizeof std_as_out_if1_desc,
240 .bDescriptorType = USB_DT_INTERFACE,
241
242 .bAlternateSetting = 1,
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200243 .bNumEndpoints = 2,
Jassi Brar132fcb42012-02-02 22:01:34 +0530244 .bInterfaceClass = USB_CLASS_AUDIO,
245 .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
246 .bInterfaceProtocol = UAC_VERSION_2,
247};
248
249/* Audio Stream OUT Intface Desc */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000250static struct uac2_as_header_descriptor as_out_hdr_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530251 .bLength = sizeof as_out_hdr_desc,
252 .bDescriptorType = USB_DT_CS_INTERFACE,
253
254 .bDescriptorSubtype = UAC_AS_GENERAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200255 /* .bTerminalLink = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530256 .bmControls = 0,
257 .bFormatType = UAC_FORMAT_TYPE_I,
258 .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
259 .iChannelNames = 0,
260};
261
262/* Audio USB_OUT Format */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000263static struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530264 .bLength = sizeof as_out_fmt1_desc,
265 .bDescriptorType = USB_DT_CS_INTERFACE,
266 .bDescriptorSubtype = UAC_FORMAT_TYPE,
267 .bFormatType = UAC_FORMAT_TYPE_I,
268};
269
270/* STD AS ISO OUT Endpoint */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000271static struct usb_endpoint_descriptor fs_epout_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530272 .bLength = USB_DT_ENDPOINT_SIZE,
273 .bDescriptorType = USB_DT_ENDPOINT,
274
275 .bEndpointAddress = USB_DIR_OUT,
276 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
Jerome Brunet93890442020-12-21 18:35:28 +0100277 /* .wMaxPacketSize = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530278 .bInterval = 1,
279};
280
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000281static struct usb_endpoint_descriptor hs_epout_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530282 .bLength = USB_DT_ENDPOINT_SIZE,
283 .bDescriptorType = USB_DT_ENDPOINT,
284
285 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
Jerome Brunet93890442020-12-21 18:35:28 +0100286 /* .wMaxPacketSize = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530287 .bInterval = 4,
288};
289
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100290static struct usb_endpoint_descriptor ss_epout_desc = {
291 .bLength = USB_DT_ENDPOINT_SIZE,
292 .bDescriptorType = USB_DT_ENDPOINT,
293
294 .bEndpointAddress = USB_DIR_OUT,
295 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
296 /* .wMaxPacketSize = DYNAMIC */
297 .bInterval = 4,
298};
299
300static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = {
301 .bLength = sizeof(ss_epout_desc_comp),
302 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
303 .bMaxBurst = 0,
304 .bmAttributes = 0,
305 /* wBytesPerInterval = DYNAMIC */
306};
307
Jassi Brar132fcb42012-02-02 22:01:34 +0530308/* CS AS ISO OUT Endpoint */
309static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
310 .bLength = sizeof as_iso_out_desc,
311 .bDescriptorType = USB_DT_CS_ENDPOINT,
312
313 .bDescriptorSubtype = UAC_EP_GENERAL,
314 .bmAttributes = 0,
315 .bmControls = 0,
316 .bLockDelayUnits = 0,
317 .wLockDelay = 0,
318};
319
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200320/* STD AS ISO IN Feedback Endpoint */
321static struct usb_endpoint_descriptor fs_epin_fback_desc = {
322 .bLength = USB_DT_ENDPOINT_SIZE,
323 .bDescriptorType = USB_DT_ENDPOINT,
324
325 .bEndpointAddress = USB_DIR_IN,
326 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
327 .wMaxPacketSize = cpu_to_le16(3),
328 .bInterval = 1,
329};
330
331static struct usb_endpoint_descriptor hs_epin_fback_desc = {
332 .bLength = USB_DT_ENDPOINT_SIZE,
333 .bDescriptorType = USB_DT_ENDPOINT,
334
335 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
336 .wMaxPacketSize = cpu_to_le16(4),
337 .bInterval = 4,
338};
339
340static struct usb_endpoint_descriptor ss_epin_fback_desc = {
341 .bLength = USB_DT_ENDPOINT_SIZE,
342 .bDescriptorType = USB_DT_ENDPOINT,
343
344 .bEndpointAddress = USB_DIR_IN,
345 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
346 .wMaxPacketSize = cpu_to_le16(4),
347 .bInterval = 4,
348};
349
350
Jassi Brar132fcb42012-02-02 22:01:34 +0530351/* Audio Streaming IN Interface - Alt0 */
352static struct usb_interface_descriptor std_as_in_if0_desc = {
353 .bLength = sizeof std_as_in_if0_desc,
354 .bDescriptorType = USB_DT_INTERFACE,
355
356 .bAlternateSetting = 0,
357 .bNumEndpoints = 0,
358 .bInterfaceClass = USB_CLASS_AUDIO,
359 .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
360 .bInterfaceProtocol = UAC_VERSION_2,
361};
362
363/* Audio Streaming IN Interface - Alt1 */
364static struct usb_interface_descriptor std_as_in_if1_desc = {
365 .bLength = sizeof std_as_in_if1_desc,
366 .bDescriptorType = USB_DT_INTERFACE,
367
368 .bAlternateSetting = 1,
369 .bNumEndpoints = 1,
370 .bInterfaceClass = USB_CLASS_AUDIO,
371 .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
372 .bInterfaceProtocol = UAC_VERSION_2,
373};
374
375/* Audio Stream IN Intface Desc */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000376static struct uac2_as_header_descriptor as_in_hdr_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530377 .bLength = sizeof as_in_hdr_desc,
378 .bDescriptorType = USB_DT_CS_INTERFACE,
379
380 .bDescriptorSubtype = UAC_AS_GENERAL,
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200381 /* .bTerminalLink = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530382 .bmControls = 0,
383 .bFormatType = UAC_FORMAT_TYPE_I,
384 .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
385 .iChannelNames = 0,
386};
387
388/* Audio USB_IN Format */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000389static struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530390 .bLength = sizeof as_in_fmt1_desc,
391 .bDescriptorType = USB_DT_CS_INTERFACE,
392 .bDescriptorSubtype = UAC_FORMAT_TYPE,
393 .bFormatType = UAC_FORMAT_TYPE_I,
394};
395
396/* STD AS ISO IN Endpoint */
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000397static struct usb_endpoint_descriptor fs_epin_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530398 .bLength = USB_DT_ENDPOINT_SIZE,
399 .bDescriptorType = USB_DT_ENDPOINT,
400
401 .bEndpointAddress = USB_DIR_IN,
402 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
Jerome Brunet93890442020-12-21 18:35:28 +0100403 /* .wMaxPacketSize = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530404 .bInterval = 1,
405};
406
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +0000407static struct usb_endpoint_descriptor hs_epin_desc = {
Jassi Brar132fcb42012-02-02 22:01:34 +0530408 .bLength = USB_DT_ENDPOINT_SIZE,
409 .bDescriptorType = USB_DT_ENDPOINT,
410
411 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
Jerome Brunet93890442020-12-21 18:35:28 +0100412 /* .wMaxPacketSize = DYNAMIC */
Jassi Brar132fcb42012-02-02 22:01:34 +0530413 .bInterval = 4,
414};
415
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100416static struct usb_endpoint_descriptor ss_epin_desc = {
417 .bLength = USB_DT_ENDPOINT_SIZE,
418 .bDescriptorType = USB_DT_ENDPOINT,
419
420 .bEndpointAddress = USB_DIR_IN,
421 .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
422 /* .wMaxPacketSize = DYNAMIC */
423 .bInterval = 4,
424};
425
426static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = {
427 .bLength = sizeof(ss_epin_desc_comp),
428 .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
429 .bMaxBurst = 0,
430 .bmAttributes = 0,
431 /* wBytesPerInterval = DYNAMIC */
432};
433
Jassi Brar132fcb42012-02-02 22:01:34 +0530434/* CS AS ISO IN Endpoint */
435static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
436 .bLength = sizeof as_iso_in_desc,
437 .bDescriptorType = USB_DT_CS_ENDPOINT,
438
439 .bDescriptorSubtype = UAC_EP_GENERAL,
440 .bmAttributes = 0,
441 .bmControls = 0,
442 .bLockDelayUnits = 0,
443 .wLockDelay = 0,
444};
445
446static struct usb_descriptor_header *fs_audio_desc[] = {
447 (struct usb_descriptor_header *)&iad_desc,
448 (struct usb_descriptor_header *)&std_ac_if_desc,
449
450 (struct usb_descriptor_header *)&ac_hdr_desc,
451 (struct usb_descriptor_header *)&in_clk_src_desc,
452 (struct usb_descriptor_header *)&out_clk_src_desc,
453 (struct usb_descriptor_header *)&usb_out_it_desc,
454 (struct usb_descriptor_header *)&io_in_it_desc,
455 (struct usb_descriptor_header *)&usb_in_ot_desc,
456 (struct usb_descriptor_header *)&io_out_ot_desc,
457
458 (struct usb_descriptor_header *)&std_as_out_if0_desc,
459 (struct usb_descriptor_header *)&std_as_out_if1_desc,
460
461 (struct usb_descriptor_header *)&as_out_hdr_desc,
462 (struct usb_descriptor_header *)&as_out_fmt1_desc,
463 (struct usb_descriptor_header *)&fs_epout_desc,
464 (struct usb_descriptor_header *)&as_iso_out_desc,
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200465 (struct usb_descriptor_header *)&fs_epin_fback_desc,
Jassi Brar132fcb42012-02-02 22:01:34 +0530466
467 (struct usb_descriptor_header *)&std_as_in_if0_desc,
468 (struct usb_descriptor_header *)&std_as_in_if1_desc,
469
470 (struct usb_descriptor_header *)&as_in_hdr_desc,
471 (struct usb_descriptor_header *)&as_in_fmt1_desc,
472 (struct usb_descriptor_header *)&fs_epin_desc,
473 (struct usb_descriptor_header *)&as_iso_in_desc,
474 NULL,
475};
476
477static struct usb_descriptor_header *hs_audio_desc[] = {
478 (struct usb_descriptor_header *)&iad_desc,
479 (struct usb_descriptor_header *)&std_ac_if_desc,
480
481 (struct usb_descriptor_header *)&ac_hdr_desc,
482 (struct usb_descriptor_header *)&in_clk_src_desc,
483 (struct usb_descriptor_header *)&out_clk_src_desc,
484 (struct usb_descriptor_header *)&usb_out_it_desc,
485 (struct usb_descriptor_header *)&io_in_it_desc,
486 (struct usb_descriptor_header *)&usb_in_ot_desc,
487 (struct usb_descriptor_header *)&io_out_ot_desc,
488
489 (struct usb_descriptor_header *)&std_as_out_if0_desc,
490 (struct usb_descriptor_header *)&std_as_out_if1_desc,
491
492 (struct usb_descriptor_header *)&as_out_hdr_desc,
493 (struct usb_descriptor_header *)&as_out_fmt1_desc,
494 (struct usb_descriptor_header *)&hs_epout_desc,
495 (struct usb_descriptor_header *)&as_iso_out_desc,
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200496 (struct usb_descriptor_header *)&hs_epin_fback_desc,
Jassi Brar132fcb42012-02-02 22:01:34 +0530497
498 (struct usb_descriptor_header *)&std_as_in_if0_desc,
499 (struct usb_descriptor_header *)&std_as_in_if1_desc,
500
501 (struct usb_descriptor_header *)&as_in_hdr_desc,
502 (struct usb_descriptor_header *)&as_in_fmt1_desc,
503 (struct usb_descriptor_header *)&hs_epin_desc,
504 (struct usb_descriptor_header *)&as_iso_in_desc,
505 NULL,
506};
507
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100508static struct usb_descriptor_header *ss_audio_desc[] = {
509 (struct usb_descriptor_header *)&iad_desc,
510 (struct usb_descriptor_header *)&std_ac_if_desc,
511
512 (struct usb_descriptor_header *)&ac_hdr_desc,
513 (struct usb_descriptor_header *)&in_clk_src_desc,
514 (struct usb_descriptor_header *)&out_clk_src_desc,
515 (struct usb_descriptor_header *)&usb_out_it_desc,
516 (struct usb_descriptor_header *)&io_in_it_desc,
517 (struct usb_descriptor_header *)&usb_in_ot_desc,
518 (struct usb_descriptor_header *)&io_out_ot_desc,
519
520 (struct usb_descriptor_header *)&std_as_out_if0_desc,
521 (struct usb_descriptor_header *)&std_as_out_if1_desc,
522
523 (struct usb_descriptor_header *)&as_out_hdr_desc,
524 (struct usb_descriptor_header *)&as_out_fmt1_desc,
525 (struct usb_descriptor_header *)&ss_epout_desc,
526 (struct usb_descriptor_header *)&ss_epout_desc_comp,
527 (struct usb_descriptor_header *)&as_iso_out_desc,
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200528 (struct usb_descriptor_header *)&ss_epin_fback_desc,
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100529
530 (struct usb_descriptor_header *)&std_as_in_if0_desc,
531 (struct usb_descriptor_header *)&std_as_in_if1_desc,
532
533 (struct usb_descriptor_header *)&as_in_hdr_desc,
534 (struct usb_descriptor_header *)&as_in_fmt1_desc,
535 (struct usb_descriptor_header *)&ss_epin_desc,
536 (struct usb_descriptor_header *)&ss_epin_desc_comp,
537 (struct usb_descriptor_header *)&as_iso_in_desc,
538 NULL,
539};
540
Jassi Brar132fcb42012-02-02 22:01:34 +0530541struct cntrl_cur_lay3 {
Eugeniu Roscaeec24f22018-07-02 23:46:47 +0200542 __le32 dCUR;
Jassi Brar132fcb42012-02-02 22:01:34 +0530543};
544
545struct cntrl_range_lay3 {
Eugeniu Roscaeec24f22018-07-02 23:46:47 +0200546 __le16 wNumSubRanges;
547 __le32 dMIN;
548 __le32 dMAX;
549 __le32 dRES;
Jassi Brar132fcb42012-02-02 22:01:34 +0530550} __packed;
551
Jerome Brunet93890442020-12-21 18:35:28 +0100552static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
Peter Chen913e4a92015-07-30 13:13:03 +0800553 struct usb_endpoint_descriptor *ep_desc,
Jerome Brunet93890442020-12-21 18:35:28 +0100554 enum usb_device_speed speed, bool is_playback)
Peter Chen913e4a92015-07-30 13:13:03 +0800555{
556 int chmask, srate, ssize;
Jerome Brunet93890442020-12-21 18:35:28 +0100557 u16 max_size_bw, max_size_ep;
558 unsigned int factor;
559
560 switch (speed) {
561 case USB_SPEED_FULL:
562 max_size_ep = 1023;
563 factor = 1000;
564 break;
565
566 case USB_SPEED_HIGH:
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100567 case USB_SPEED_SUPER:
Jerome Brunet93890442020-12-21 18:35:28 +0100568 max_size_ep = 1024;
569 factor = 8000;
570 break;
571
572 default:
573 return -EINVAL;
574 }
Peter Chen913e4a92015-07-30 13:13:03 +0800575
576 if (is_playback) {
577 chmask = uac2_opts->p_chmask;
578 srate = uac2_opts->p_srate;
579 ssize = uac2_opts->p_ssize;
580 } else {
581 chmask = uac2_opts->c_chmask;
582 srate = uac2_opts->c_srate;
583 ssize = uac2_opts->c_ssize;
584 }
585
Jerome Brunet93890442020-12-21 18:35:28 +0100586 max_size_bw = num_channels(chmask) * ssize *
Ruslan Bilovol789ea772021-03-01 13:49:31 +0200587 ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1);
Jerome Brunet93890442020-12-21 18:35:28 +0100588 ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
589 max_size_ep));
590
591 return 0;
Peter Chen913e4a92015-07-30 13:13:03 +0800592}
593
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200594/* Use macro to overcome line length limitation */
595#define USBDHDR(p) (struct usb_descriptor_header *)(p)
596
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100597static void setup_headers(struct f_uac2_opts *opts,
598 struct usb_descriptor_header **headers,
599 enum usb_device_speed speed)
600{
601 struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL;
602 struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL;
603 struct usb_endpoint_descriptor *epout_desc;
604 struct usb_endpoint_descriptor *epin_desc;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200605 struct usb_endpoint_descriptor *epin_fback_desc;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100606 int i;
607
608 switch (speed) {
609 case USB_SPEED_FULL:
610 epout_desc = &fs_epout_desc;
611 epin_desc = &fs_epin_desc;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200612 epin_fback_desc = &fs_epin_fback_desc;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100613 break;
614 case USB_SPEED_HIGH:
615 epout_desc = &hs_epout_desc;
616 epin_desc = &hs_epin_desc;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200617 epin_fback_desc = &hs_epin_fback_desc;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100618 break;
619 default:
620 epout_desc = &ss_epout_desc;
621 epin_desc = &ss_epin_desc;
622 epout_desc_comp = &ss_epout_desc_comp;
623 epin_desc_comp = &ss_epin_desc_comp;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200624 epin_fback_desc = &ss_epin_fback_desc;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100625 }
626
627 i = 0;
628 headers[i++] = USBDHDR(&iad_desc);
629 headers[i++] = USBDHDR(&std_ac_if_desc);
630 headers[i++] = USBDHDR(&ac_hdr_desc);
631 if (EPIN_EN(opts))
632 headers[i++] = USBDHDR(&in_clk_src_desc);
633 if (EPOUT_EN(opts)) {
634 headers[i++] = USBDHDR(&out_clk_src_desc);
635 headers[i++] = USBDHDR(&usb_out_it_desc);
636 }
637 if (EPIN_EN(opts)) {
638 headers[i++] = USBDHDR(&io_in_it_desc);
639 headers[i++] = USBDHDR(&usb_in_ot_desc);
640 }
641 if (EPOUT_EN(opts)) {
642 headers[i++] = USBDHDR(&io_out_ot_desc);
643 headers[i++] = USBDHDR(&std_as_out_if0_desc);
644 headers[i++] = USBDHDR(&std_as_out_if1_desc);
645 headers[i++] = USBDHDR(&as_out_hdr_desc);
646 headers[i++] = USBDHDR(&as_out_fmt1_desc);
647 headers[i++] = USBDHDR(epout_desc);
648 if (epout_desc_comp)
649 headers[i++] = USBDHDR(epout_desc_comp);
650
651 headers[i++] = USBDHDR(&as_iso_out_desc);
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200652 headers[i++] = USBDHDR(epin_fback_desc);
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100653 }
654 if (EPIN_EN(opts)) {
655 headers[i++] = USBDHDR(&std_as_in_if0_desc);
656 headers[i++] = USBDHDR(&std_as_in_if1_desc);
657 headers[i++] = USBDHDR(&as_in_hdr_desc);
658 headers[i++] = USBDHDR(&as_in_fmt1_desc);
659 headers[i++] = USBDHDR(epin_desc);
660 if (epin_desc_comp)
661 headers[i++] = USBDHDR(epin_desc_comp);
662
663 headers[i++] = USBDHDR(&as_iso_in_desc);
664 }
665 headers[i] = NULL;
666}
667
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200668static void setup_descriptor(struct f_uac2_opts *opts)
669{
670 /* patch descriptors */
671 int i = 1; /* ID's start with 1 */
672
673 if (EPOUT_EN(opts))
674 usb_out_it_desc.bTerminalID = i++;
675 if (EPIN_EN(opts))
676 io_in_it_desc.bTerminalID = i++;
677 if (EPOUT_EN(opts))
678 io_out_ot_desc.bTerminalID = i++;
679 if (EPIN_EN(opts))
680 usb_in_ot_desc.bTerminalID = i++;
681 if (EPOUT_EN(opts))
682 out_clk_src_desc.bClockID = i++;
683 if (EPIN_EN(opts))
684 in_clk_src_desc.bClockID = i++;
685
686 usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID;
687 usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID;
688 usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID;
689 io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID;
690 io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID;
691 io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID;
692 as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID;
693 as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID;
694
695 iad_desc.bInterfaceCount = 1;
Ruslan Bilovola9cf8712020-07-03 16:49:03 +0300696 ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc));
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200697
698 if (EPIN_EN(opts)) {
699 u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
700
701 len += sizeof(in_clk_src_desc);
702 len += sizeof(usb_in_ot_desc);
703 len += sizeof(io_in_it_desc);
704 ac_hdr_desc.wTotalLength = cpu_to_le16(len);
705 iad_desc.bInterfaceCount++;
706 }
707 if (EPOUT_EN(opts)) {
708 u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
709
710 len += sizeof(out_clk_src_desc);
711 len += sizeof(usb_out_it_desc);
712 len += sizeof(io_out_ot_desc);
713 ac_hdr_desc.wTotalLength = cpu_to_le16(len);
714 iad_desc.bInterfaceCount++;
715 }
716
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100717 setup_headers(opts, fs_audio_desc, USB_SPEED_FULL);
718 setup_headers(opts, hs_audio_desc, USB_SPEED_HIGH);
719 setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER);
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200720}
721
Ruslan Bilovol3713d5c2021-03-01 13:49:33 +0200722static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
723{
724 struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
725
726 if (!opts->p_chmask && !opts->c_chmask) {
727 dev_err(dev, "Error: no playback and capture channels\n");
728 return -EINVAL;
729 } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) {
730 dev_err(dev, "Error: unsupported playback channels mask\n");
731 return -EINVAL;
732 } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) {
733 dev_err(dev, "Error: unsupported capture channels mask\n");
734 return -EINVAL;
735 } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
736 dev_err(dev, "Error: incorrect playback sample size\n");
737 return -EINVAL;
738 } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
739 dev_err(dev, "Error: incorrect capture sample size\n");
740 return -EINVAL;
741 } else if (!opts->p_srate) {
742 dev_err(dev, "Error: incorrect playback sampling rate\n");
743 return -EINVAL;
744 } else if (!opts->c_srate) {
745 dev_err(dev, "Error: incorrect capture sampling rate\n");
746 return -EINVAL;
747 }
748
749 return 0;
750}
751
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +0200752static int
Jassi Brar132fcb42012-02-02 22:01:34 +0530753afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
754{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300755 struct f_uac2 *uac2 = func_to_uac2(fn);
756 struct g_audio *agdev = func_to_g_audio(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +0530757 struct usb_composite_dev *cdev = cfg->cdev;
758 struct usb_gadget *gadget = cdev->gadget;
Ruslan Bilovol7158b572017-06-18 16:23:51 +0300759 struct device *dev = &gadget->dev;
Ruslan Bilovol3713d5c2021-03-01 13:49:33 +0200760 struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev);
Andrzej Pietrasiewiczf4087572014-07-22 19:58:33 +0200761 struct usb_string *us;
Jassi Brar132fcb42012-02-02 22:01:34 +0530762 int ret;
763
Ruslan Bilovol3713d5c2021-03-01 13:49:33 +0200764 ret = afunc_validate_opts(agdev, dev);
765 if (ret)
766 return ret;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +0200767
Andrzej Pietrasiewiczf4087572014-07-22 19:58:33 +0200768 us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
769 if (IS_ERR(us))
770 return PTR_ERR(us);
771 iad_desc.iFunction = us[STR_ASSOC].id;
772 std_ac_if_desc.iInterface = us[STR_IF_CTRL].id;
773 in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id;
774 out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id;
775 usb_out_it_desc.iTerminal = us[STR_USB_IT].id;
776 io_in_it_desc.iTerminal = us[STR_IO_IT].id;
777 usb_in_ot_desc.iTerminal = us[STR_USB_OT].id;
778 io_out_ot_desc.iTerminal = us[STR_IO_OT].id;
779 std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id;
780 std_as_out_if1_desc.iInterface = us[STR_AS_OUT_ALT1].id;
781 std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
782 std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
783
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +0200784
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +0200785 /* Initialize the configurable parameters */
786 usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
787 usb_out_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask);
788 io_in_it_desc.bNrChannels = num_channels(uac2_opts->p_chmask);
789 io_in_it_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask);
790 as_out_hdr_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
791 as_out_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->c_chmask);
792 as_in_hdr_desc.bNrChannels = num_channels(uac2_opts->p_chmask);
793 as_in_hdr_desc.bmChannelConfig = cpu_to_le32(uac2_opts->p_chmask);
794 as_out_fmt1_desc.bSubslotSize = uac2_opts->c_ssize;
795 as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8;
796 as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize;
797 as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8;
798
799 snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
800 snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +0200801
Jassi Brar132fcb42012-02-02 22:01:34 +0530802 ret = usb_interface_id(cfg, fn);
803 if (ret < 0) {
Daniel Macka8147da2014-08-27 19:09:04 +0200804 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
Jassi Brar132fcb42012-02-02 22:01:34 +0530805 return ret;
806 }
John Keeping8813a592018-01-12 18:43:32 +0000807 iad_desc.bFirstInterface = ret;
808
Jassi Brar132fcb42012-02-02 22:01:34 +0530809 std_ac_if_desc.bInterfaceNumber = ret;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300810 uac2->ac_intf = ret;
811 uac2->ac_alt = 0;
Jassi Brar132fcb42012-02-02 22:01:34 +0530812
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200813 if (EPOUT_EN(uac2_opts)) {
814 ret = usb_interface_id(cfg, fn);
815 if (ret < 0) {
816 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
817 return ret;
818 }
819 std_as_out_if0_desc.bInterfaceNumber = ret;
820 std_as_out_if1_desc.bInterfaceNumber = ret;
821 uac2->as_out_intf = ret;
822 uac2->as_out_alt = 0;
Jassi Brar132fcb42012-02-02 22:01:34 +0530823 }
Jassi Brar132fcb42012-02-02 22:01:34 +0530824
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200825 if (EPIN_EN(uac2_opts)) {
826 ret = usb_interface_id(cfg, fn);
827 if (ret < 0) {
828 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
829 return ret;
830 }
831 std_as_in_if0_desc.bInterfaceNumber = ret;
832 std_as_in_if1_desc.bInterfaceNumber = ret;
833 uac2->as_in_intf = ret;
834 uac2->as_in_alt = 0;
Jassi Brar132fcb42012-02-02 22:01:34 +0530835 }
Jassi Brar132fcb42012-02-02 22:01:34 +0530836
Sekhar Nori0db56e42017-05-17 13:45:17 +0530837 /* Calculate wMaxPacketSize according to audio bandwidth */
Jerome Brunet93890442020-12-21 18:35:28 +0100838 ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL,
839 true);
840 if (ret < 0) {
841 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
842 return ret;
843 }
844
845 ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL,
846 false);
847 if (ret < 0) {
848 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
849 return ret;
850 }
851
852 ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH,
853 true);
854 if (ret < 0) {
855 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
856 return ret;
857 }
858
859 ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH,
860 false);
861 if (ret < 0) {
862 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
863 return ret;
864 }
Sekhar Nori0db56e42017-05-17 13:45:17 +0530865
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100866 ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER,
867 true);
868 if (ret < 0) {
869 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
870 return ret;
871 }
872
873 ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER,
874 false);
875 if (ret < 0) {
876 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
877 return ret;
878 }
879
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200880 if (EPOUT_EN(uac2_opts)) {
881 agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
882 if (!agdev->out_ep) {
883 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
884 return -ENODEV;
885 }
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200886 agdev->in_ep_fback = usb_ep_autoconfig(gadget,
887 &fs_epin_fback_desc);
888 if (!agdev->in_ep_fback) {
889 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
890 return -ENODEV;
891 }
Sebastian Andrzej Siewior391aa852012-10-22 22:14:59 +0200892 }
Jassi Brar132fcb42012-02-02 22:01:34 +0530893
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200894 if (EPIN_EN(uac2_opts)) {
895 agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
896 if (!agdev->in_ep) {
897 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
898 return -ENODEV;
899 }
Sebastian Andrzej Siewior391aa852012-10-22 22:14:59 +0200900 }
Jassi Brar132fcb42012-02-02 22:01:34 +0530901
Ruslan Bilovol14e1d562017-06-25 16:23:47 +0300902 agdev->in_ep_maxpsize = max_t(u16,
903 le16_to_cpu(fs_epin_desc.wMaxPacketSize),
904 le16_to_cpu(hs_epin_desc.wMaxPacketSize));
905 agdev->out_ep_maxpsize = max_t(u16,
906 le16_to_cpu(fs_epout_desc.wMaxPacketSize),
907 le16_to_cpu(hs_epout_desc.wMaxPacketSize));
Jassi Brareb127cb2013-05-30 18:23:33 +0530908
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100909 agdev->in_ep_maxpsize = max_t(u16, agdev->in_ep_maxpsize,
910 le16_to_cpu(ss_epin_desc.wMaxPacketSize));
911 agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize,
912 le16_to_cpu(ss_epout_desc.wMaxPacketSize));
913
Jassi Brar132fcb42012-02-02 22:01:34 +0530914 hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200915 hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
Jassi Brar132fcb42012-02-02 22:01:34 +0530916 hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100917 ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
Ruslan Bilovol24f779d2021-06-04 00:01:02 +0200918 ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress;
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100919 ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
Jassi Brar132fcb42012-02-02 22:01:34 +0530920
Andreas Pape3fa4eaa2018-06-21 17:22:51 +0200921 setup_descriptor(uac2_opts);
922
Pawel Laszczakf8cb3d52021-03-10 11:52:16 +0100923 ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc,
924 ss_audio_desc);
Sebastian Andrzej Siewior10287ba2012-10-22 22:15:06 +0200925 if (ret)
Peter Chenf1d38612016-11-08 10:10:44 +0800926 return ret;
Jassi Brar132fcb42012-02-02 22:01:34 +0530927
Ruslan Bilovol7158b572017-06-18 16:23:51 +0300928 agdev->gadget = gadget;
929
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300930 agdev->params.p_chmask = uac2_opts->p_chmask;
931 agdev->params.p_srate = uac2_opts->p_srate;
932 agdev->params.p_ssize = uac2_opts->p_ssize;
933 agdev->params.c_chmask = uac2_opts->c_chmask;
934 agdev->params.c_srate = uac2_opts->c_srate;
935 agdev->params.c_ssize = uac2_opts->c_ssize;
936 agdev->params.req_number = uac2_opts->req_number;
937 ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget");
Sebastian Andrzej Siewior391aa852012-10-22 22:14:59 +0200938 if (ret)
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300939 goto err_free_descs;
Sebastian Andrzej Siewior391aa852012-10-22 22:14:59 +0200940 return 0;
Pavitrakumar Managutted12a8722014-10-22 19:24:58 +0530941
Peter Chenf1d38612016-11-08 10:10:44 +0800942err_free_descs:
943 usb_free_all_descriptors(fn);
Ruslan Bilovol7158b572017-06-18 16:23:51 +0300944 agdev->gadget = NULL;
Peter Chen88f950a2017-01-04 10:19:22 +0800945 return ret;
Jassi Brar132fcb42012-02-02 22:01:34 +0530946}
947
Jassi Brar132fcb42012-02-02 22:01:34 +0530948static int
949afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
950{
951 struct usb_composite_dev *cdev = fn->config->cdev;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300952 struct f_uac2 *uac2 = func_to_uac2(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +0530953 struct usb_gadget *gadget = cdev->gadget;
Ruslan Bilovol7158b572017-06-18 16:23:51 +0300954 struct device *dev = &gadget->dev;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300955 int ret = 0;
Jassi Brar132fcb42012-02-02 22:01:34 +0530956
957 /* No i/f has more than 2 alt settings */
958 if (alt > 1) {
Daniel Macka8147da2014-08-27 19:09:04 +0200959 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
Jassi Brar132fcb42012-02-02 22:01:34 +0530960 return -EINVAL;
961 }
962
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300963 if (intf == uac2->ac_intf) {
Jassi Brar132fcb42012-02-02 22:01:34 +0530964 /* Control I/f has only 1 AltSetting - 0 */
965 if (alt) {
Daniel Macka8147da2014-08-27 19:09:04 +0200966 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
Jassi Brar132fcb42012-02-02 22:01:34 +0530967 return -EINVAL;
968 }
969 return 0;
970 }
971
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300972 if (intf == uac2->as_out_intf) {
973 uac2->as_out_alt = alt;
Daniel Mack9bb87f12014-08-27 19:09:07 +0200974
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300975 if (alt)
976 ret = u_audio_start_capture(&uac2->g_audio);
Daniel Mack9bb87f12014-08-27 19:09:07 +0200977 else
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300978 u_audio_stop_capture(&uac2->g_audio);
979 } else if (intf == uac2->as_in_intf) {
980 uac2->as_in_alt = alt;
Daniel Mack9bb87f12014-08-27 19:09:07 +0200981
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300982 if (alt)
983 ret = u_audio_start_playback(&uac2->g_audio);
984 else
985 u_audio_stop_playback(&uac2->g_audio);
Jassi Brar132fcb42012-02-02 22:01:34 +0530986 } else {
Daniel Macka8147da2014-08-27 19:09:04 +0200987 dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
Jassi Brar132fcb42012-02-02 22:01:34 +0530988 return -EINVAL;
989 }
990
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300991 return ret;
Jassi Brar132fcb42012-02-02 22:01:34 +0530992}
993
994static int
995afunc_get_alt(struct usb_function *fn, unsigned intf)
996{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +0300997 struct f_uac2 *uac2 = func_to_uac2(fn);
998 struct g_audio *agdev = func_to_g_audio(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +0530999
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001000 if (intf == uac2->ac_intf)
1001 return uac2->ac_alt;
1002 else if (intf == uac2->as_out_intf)
1003 return uac2->as_out_alt;
1004 else if (intf == uac2->as_in_intf)
1005 return uac2->as_in_alt;
Jassi Brar132fcb42012-02-02 22:01:34 +05301006 else
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001007 dev_err(&agdev->gadget->dev,
Jassi Brar132fcb42012-02-02 22:01:34 +05301008 "%s:%d Invalid Interface %d!\n",
1009 __func__, __LINE__, intf);
1010
1011 return -EINVAL;
1012}
1013
1014static void
1015afunc_disable(struct usb_function *fn)
1016{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001017 struct f_uac2 *uac2 = func_to_uac2(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +05301018
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001019 uac2->as_in_alt = 0;
1020 uac2->as_out_alt = 0;
1021 u_audio_stop_capture(&uac2->g_audio);
1022 u_audio_stop_playback(&uac2->g_audio);
Jassi Brar132fcb42012-02-02 22:01:34 +05301023}
1024
1025static int
1026in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1027{
1028 struct usb_request *req = fn->config->cdev->req;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001029 struct g_audio *agdev = func_to_g_audio(fn);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001030 struct f_uac2_opts *opts;
Jassi Brar132fcb42012-02-02 22:01:34 +05301031 u16 w_length = le16_to_cpu(cr->wLength);
1032 u16 w_index = le16_to_cpu(cr->wIndex);
1033 u16 w_value = le16_to_cpu(cr->wValue);
1034 u8 entity_id = (w_index >> 8) & 0xff;
1035 u8 control_selector = w_value >> 8;
1036 int value = -EOPNOTSUPP;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001037 int p_srate, c_srate;
1038
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001039 opts = g_audio_to_uac2_opts(agdev);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001040 p_srate = opts->p_srate;
1041 c_srate = opts->c_srate;
Jassi Brar132fcb42012-02-02 22:01:34 +05301042
1043 if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
1044 struct cntrl_cur_lay3 c;
Heinrich Schuchardtffeee832016-05-08 23:20:59 +02001045 memset(&c, 0, sizeof(struct cntrl_cur_lay3));
Jassi Brar132fcb42012-02-02 22:01:34 +05301046
1047 if (entity_id == USB_IN_CLK_ID)
Eugeniu Roscaeec24f22018-07-02 23:46:47 +02001048 c.dCUR = cpu_to_le32(p_srate);
Jassi Brar132fcb42012-02-02 22:01:34 +05301049 else if (entity_id == USB_OUT_CLK_ID)
Eugeniu Roscaeec24f22018-07-02 23:46:47 +02001050 c.dCUR = cpu_to_le32(c_srate);
Jassi Brar132fcb42012-02-02 22:01:34 +05301051
1052 value = min_t(unsigned, w_length, sizeof c);
1053 memcpy(req->buf, &c, value);
1054 } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) {
1055 *(u8 *)req->buf = 1;
1056 value = min_t(unsigned, w_length, 1);
1057 } else {
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001058 dev_err(&agdev->gadget->dev,
Jassi Brar132fcb42012-02-02 22:01:34 +05301059 "%s:%d control_selector=%d TODO!\n",
1060 __func__, __LINE__, control_selector);
1061 }
1062
1063 return value;
1064}
1065
1066static int
1067in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1068{
1069 struct usb_request *req = fn->config->cdev->req;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001070 struct g_audio *agdev = func_to_g_audio(fn);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001071 struct f_uac2_opts *opts;
Jassi Brar132fcb42012-02-02 22:01:34 +05301072 u16 w_length = le16_to_cpu(cr->wLength);
1073 u16 w_index = le16_to_cpu(cr->wIndex);
1074 u16 w_value = le16_to_cpu(cr->wValue);
1075 u8 entity_id = (w_index >> 8) & 0xff;
1076 u8 control_selector = w_value >> 8;
1077 struct cntrl_range_lay3 r;
1078 int value = -EOPNOTSUPP;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001079 int p_srate, c_srate;
1080
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001081 opts = g_audio_to_uac2_opts(agdev);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001082 p_srate = opts->p_srate;
1083 c_srate = opts->c_srate;
Jassi Brar132fcb42012-02-02 22:01:34 +05301084
1085 if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
1086 if (entity_id == USB_IN_CLK_ID)
Eugeniu Roscaeec24f22018-07-02 23:46:47 +02001087 r.dMIN = cpu_to_le32(p_srate);
Jassi Brar132fcb42012-02-02 22:01:34 +05301088 else if (entity_id == USB_OUT_CLK_ID)
Eugeniu Roscaeec24f22018-07-02 23:46:47 +02001089 r.dMIN = cpu_to_le32(c_srate);
Jassi Brar132fcb42012-02-02 22:01:34 +05301090 else
1091 return -EOPNOTSUPP;
1092
1093 r.dMAX = r.dMIN;
1094 r.dRES = 0;
Eugeniu Roscaeec24f22018-07-02 23:46:47 +02001095 r.wNumSubRanges = cpu_to_le16(1);
Jassi Brar132fcb42012-02-02 22:01:34 +05301096
1097 value = min_t(unsigned, w_length, sizeof r);
1098 memcpy(req->buf, &r, value);
1099 } else {
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001100 dev_err(&agdev->gadget->dev,
Jassi Brar132fcb42012-02-02 22:01:34 +05301101 "%s:%d control_selector=%d TODO!\n",
1102 __func__, __LINE__, control_selector);
1103 }
1104
1105 return value;
1106}
1107
1108static int
1109ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1110{
1111 if (cr->bRequest == UAC2_CS_CUR)
1112 return in_rq_cur(fn, cr);
1113 else if (cr->bRequest == UAC2_CS_RANGE)
1114 return in_rq_range(fn, cr);
1115 else
1116 return -EOPNOTSUPP;
1117}
1118
1119static int
1120out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1121{
1122 u16 w_length = le16_to_cpu(cr->wLength);
1123 u16 w_value = le16_to_cpu(cr->wValue);
1124 u8 control_selector = w_value >> 8;
1125
1126 if (control_selector == UAC2_CS_CONTROL_SAM_FREQ)
1127 return w_length;
1128
1129 return -EOPNOTSUPP;
1130}
1131
1132static int
1133setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1134{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001135 struct f_uac2 *uac2 = func_to_uac2(fn);
1136 struct g_audio *agdev = func_to_g_audio(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +05301137 u16 w_index = le16_to_cpu(cr->wIndex);
1138 u8 intf = w_index & 0xff;
1139
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001140 if (intf != uac2->ac_intf) {
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001141 dev_err(&agdev->gadget->dev,
Jassi Brar132fcb42012-02-02 22:01:34 +05301142 "%s:%d Error!\n", __func__, __LINE__);
1143 return -EOPNOTSUPP;
1144 }
1145
1146 if (cr->bRequestType & USB_DIR_IN)
1147 return ac_rq_in(fn, cr);
1148 else if (cr->bRequest == UAC2_CS_CUR)
1149 return out_rq_cur(fn, cr);
1150
1151 return -EOPNOTSUPP;
1152}
1153
1154static int
1155afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
1156{
1157 struct usb_composite_dev *cdev = fn->config->cdev;
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001158 struct g_audio *agdev = func_to_g_audio(fn);
Jassi Brar132fcb42012-02-02 22:01:34 +05301159 struct usb_request *req = cdev->req;
1160 u16 w_length = le16_to_cpu(cr->wLength);
1161 int value = -EOPNOTSUPP;
1162
1163 /* Only Class specific requests are supposed to reach here */
1164 if ((cr->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
1165 return -EOPNOTSUPP;
1166
1167 if ((cr->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE)
1168 value = setup_rq_inf(fn, cr);
1169 else
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001170 dev_err(&agdev->gadget->dev, "%s:%d Error!\n",
1171 __func__, __LINE__);
Jassi Brar132fcb42012-02-02 22:01:34 +05301172
1173 if (value >= 0) {
1174 req->length = value;
1175 req->zero = value < w_length;
1176 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1177 if (value < 0) {
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001178 dev_err(&agdev->gadget->dev,
Jassi Brar132fcb42012-02-02 22:01:34 +05301179 "%s:%d Error!\n", __func__, __LINE__);
1180 req->status = 0;
1181 }
1182 }
1183
1184 return value;
1185}
1186
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001187static inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item)
1188{
1189 return container_of(to_config_group(item), struct f_uac2_opts,
1190 func_inst.group);
1191}
1192
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001193static void f_uac2_attr_release(struct config_item *item)
1194{
1195 struct f_uac2_opts *opts = to_f_uac2_opts(item);
1196
1197 usb_put_function_instance(&opts->func_inst);
1198}
1199
1200static struct configfs_item_operations f_uac2_item_ops = {
1201 .release = f_uac2_attr_release,
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001202};
1203
1204#define UAC2_ATTRIBUTE(name) \
Christoph Hellwig495702b2015-10-03 15:32:49 +02001205static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001206 char *page) \
1207{ \
Christoph Hellwig495702b2015-10-03 15:32:49 +02001208 struct f_uac2_opts *opts = to_f_uac2_opts(item); \
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001209 int result; \
1210 \
1211 mutex_lock(&opts->lock); \
1212 result = sprintf(page, "%u\n", opts->name); \
1213 mutex_unlock(&opts->lock); \
1214 \
1215 return result; \
1216} \
1217 \
Christoph Hellwig495702b2015-10-03 15:32:49 +02001218static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001219 const char *page, size_t len) \
1220{ \
Christoph Hellwig495702b2015-10-03 15:32:49 +02001221 struct f_uac2_opts *opts = to_f_uac2_opts(item); \
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001222 int ret; \
1223 u32 num; \
1224 \
1225 mutex_lock(&opts->lock); \
1226 if (opts->refcnt) { \
1227 ret = -EBUSY; \
1228 goto end; \
1229 } \
1230 \
1231 ret = kstrtou32(page, 0, &num); \
1232 if (ret) \
1233 goto end; \
1234 \
1235 opts->name = num; \
1236 ret = len; \
1237 \
1238end: \
1239 mutex_unlock(&opts->lock); \
1240 return ret; \
1241} \
1242 \
Christoph Hellwig495702b2015-10-03 15:32:49 +02001243CONFIGFS_ATTR(f_uac2_opts_, name)
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001244
1245UAC2_ATTRIBUTE(p_chmask);
1246UAC2_ATTRIBUTE(p_srate);
1247UAC2_ATTRIBUTE(p_ssize);
1248UAC2_ATTRIBUTE(c_chmask);
1249UAC2_ATTRIBUTE(c_srate);
1250UAC2_ATTRIBUTE(c_ssize);
Peter Chene92b9d42017-01-04 10:19:23 +08001251UAC2_ATTRIBUTE(req_number);
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001252
1253static struct configfs_attribute *f_uac2_attrs[] = {
Christoph Hellwig495702b2015-10-03 15:32:49 +02001254 &f_uac2_opts_attr_p_chmask,
1255 &f_uac2_opts_attr_p_srate,
1256 &f_uac2_opts_attr_p_ssize,
1257 &f_uac2_opts_attr_c_chmask,
1258 &f_uac2_opts_attr_c_srate,
1259 &f_uac2_opts_attr_c_ssize,
Peter Chene92b9d42017-01-04 10:19:23 +08001260 &f_uac2_opts_attr_req_number,
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001261 NULL,
1262};
1263
Bhumika Goyal97363902017-10-16 17:18:41 +02001264static const struct config_item_type f_uac2_func_type = {
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001265 .ct_item_ops = &f_uac2_item_ops,
1266 .ct_attrs = f_uac2_attrs,
1267 .ct_owner = THIS_MODULE,
1268};
1269
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001270static void afunc_free_inst(struct usb_function_instance *f)
1271{
1272 struct f_uac2_opts *opts;
1273
1274 opts = container_of(f, struct f_uac2_opts, func_inst);
1275 kfree(opts);
1276}
1277
1278static struct usb_function_instance *afunc_alloc_inst(void)
1279{
1280 struct f_uac2_opts *opts;
1281
1282 opts = kzalloc(sizeof(*opts), GFP_KERNEL);
1283 if (!opts)
1284 return ERR_PTR(-ENOMEM);
1285
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001286 mutex_init(&opts->lock);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001287 opts->func_inst.free_func_inst = afunc_free_inst;
1288
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001289 config_group_init_type_name(&opts->func_inst.group, "",
1290 &f_uac2_func_type);
1291
1292 opts->p_chmask = UAC2_DEF_PCHMASK;
1293 opts->p_srate = UAC2_DEF_PSRATE;
1294 opts->p_ssize = UAC2_DEF_PSSIZE;
1295 opts->c_chmask = UAC2_DEF_CCHMASK;
1296 opts->c_srate = UAC2_DEF_CSRATE;
1297 opts->c_ssize = UAC2_DEF_CSSIZE;
Peter Chene92b9d42017-01-04 10:19:23 +08001298 opts->req_number = UAC2_DEF_REQ_NUM;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001299 return &opts->func_inst;
1300}
1301
1302static void afunc_free(struct usb_function *f)
1303{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001304 struct g_audio *agdev;
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001305 struct f_uac2_opts *opts;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001306
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001307 agdev = func_to_g_audio(f);
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001308 opts = container_of(f->fi, struct f_uac2_opts, func_inst);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001309 kfree(agdev);
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001310 mutex_lock(&opts->lock);
1311 --opts->refcnt;
1312 mutex_unlock(&opts->lock);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001313}
1314
1315static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
1316{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001317 struct g_audio *agdev = func_to_g_audio(f);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001318
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001319 g_audio_cleanup(agdev);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001320 usb_free_all_descriptors(f);
Ruslan Bilovol7158b572017-06-18 16:23:51 +03001321
1322 agdev->gadget = NULL;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001323}
1324
Lad, Prabhakaref16e7c2015-02-04 18:01:11 +00001325static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001326{
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001327 struct f_uac2 *uac2;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001328 struct f_uac2_opts *opts;
1329
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001330 uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL);
1331 if (uac2 == NULL)
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001332 return ERR_PTR(-ENOMEM);
1333
1334 opts = container_of(fi, struct f_uac2_opts, func_inst);
Andrzej Pietrasiewicz3aeea3c2014-07-22 19:58:35 +02001335 mutex_lock(&opts->lock);
1336 ++opts->refcnt;
1337 mutex_unlock(&opts->lock);
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001338
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001339 uac2->g_audio.func.name = "uac2_func";
1340 uac2->g_audio.func.bind = afunc_bind;
1341 uac2->g_audio.func.unbind = afunc_unbind;
1342 uac2->g_audio.func.set_alt = afunc_set_alt;
1343 uac2->g_audio.func.get_alt = afunc_get_alt;
1344 uac2->g_audio.func.disable = afunc_disable;
1345 uac2->g_audio.func.setup = afunc_setup;
1346 uac2->g_audio.func.free_func = afunc_free;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001347
Ruslan Bilovoleb9fecb2017-06-18 16:23:52 +03001348 return &uac2->g_audio.func;
Andrzej Pietrasiewiczf8f93d22014-07-22 19:58:30 +02001349}
1350
1351DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc);
1352MODULE_LICENSE("GPL");
1353MODULE_AUTHOR("Yadwinder Singh");
1354MODULE_AUTHOR("Jaswinder Singh");