.. | .. |
---|
5 | 5 | * Copyright (C) 2011 |
---|
6 | 6 | * Yadwinder Singh (yadi.brar01@gmail.com) |
---|
7 | 7 | * Jaswinder Singh (jaswinder.singh@linaro.org) |
---|
8 | | - * Copyright (C) 2017 Julian Scheel <julian@jusst.de> |
---|
| 8 | + * |
---|
| 9 | + * Copyright (C) 2020 |
---|
| 10 | + * Ruslan Bilovol (ruslan.bilovol@gmail.com) |
---|
9 | 11 | */ |
---|
10 | 12 | |
---|
11 | 13 | #include <linux/usb/audio.h> |
---|
.. | .. |
---|
13 | 15 | #include <linux/module.h> |
---|
14 | 16 | |
---|
15 | 17 | #include "u_audio.h" |
---|
16 | | -#include "u_uac.h" |
---|
| 18 | + |
---|
| 19 | +#include "u_uac2.h" |
---|
| 20 | + |
---|
| 21 | +/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ |
---|
| 22 | +#define UAC2_CHANNEL_MASK 0x07FFFFFF |
---|
17 | 23 | |
---|
18 | 24 | /* |
---|
19 | 25 | * The driver implements a simple UAC_2 topology. |
---|
20 | | - * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture |
---|
21 | | - * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN |
---|
| 26 | + * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture |
---|
| 27 | + * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN |
---|
22 | 28 | * Capture and Playback sampling rates are independently |
---|
23 | 29 | * controlled by two clock sources : |
---|
24 | 30 | * CLK_5 := c_srate, and CLK_6 := p_srate |
---|
25 | 31 | */ |
---|
26 | 32 | #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) |
---|
27 | 33 | #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) |
---|
| 34 | +#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) |
---|
| 35 | +#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) |
---|
28 | 36 | |
---|
29 | 37 | #define CONTROL_ABSENT 0 |
---|
30 | 38 | #define CONTROL_RDONLY 1 |
---|
.. | .. |
---|
32 | 40 | |
---|
33 | 41 | #define CLK_FREQ_CTRL 0 |
---|
34 | 42 | #define CLK_VLD_CTRL 2 |
---|
| 43 | +#define FU_MUTE_CTRL 0 |
---|
| 44 | +#define FU_VOL_CTRL 2 |
---|
35 | 45 | |
---|
36 | 46 | #define COPY_CTRL 0 |
---|
37 | 47 | #define CONN_CTRL 2 |
---|
.. | .. |
---|
39 | 49 | #define CLSTR_CTRL 6 |
---|
40 | 50 | #define UNFLW_CTRL 8 |
---|
41 | 51 | #define OVFLW_CTRL 10 |
---|
| 52 | + |
---|
| 53 | +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) |
---|
| 54 | +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) |
---|
| 55 | +#define FUIN_EN(_opts) (EPIN_EN(_opts) \ |
---|
| 56 | + && ((_opts)->p_mute_present \ |
---|
| 57 | + || (_opts)->p_volume_present)) |
---|
| 58 | +#define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ |
---|
| 59 | + && ((_opts)->c_mute_present \ |
---|
| 60 | + || (_opts)->c_volume_present)) |
---|
| 61 | +#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) |
---|
| 62 | + |
---|
| 63 | +struct f_uac2 { |
---|
| 64 | + struct g_audio g_audio; |
---|
| 65 | + u8 ac_intf, as_in_intf, as_out_intf; |
---|
| 66 | + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ |
---|
| 67 | + |
---|
| 68 | + struct usb_ctrlrequest setup_cr; /* will be used in data stage */ |
---|
| 69 | + |
---|
| 70 | + /* Interrupt IN endpoint of AC interface */ |
---|
| 71 | + struct usb_ep *int_ep; |
---|
| 72 | + atomic_t int_count; |
---|
| 73 | + /* transient state, only valid during handling of a single control request */ |
---|
| 74 | + int clock_id; |
---|
| 75 | +}; |
---|
| 76 | + |
---|
| 77 | +static inline struct f_uac2 *func_to_uac2(struct usb_function *f) |
---|
| 78 | +{ |
---|
| 79 | + return container_of(f, struct f_uac2, g_audio.func); |
---|
| 80 | +} |
---|
| 81 | + |
---|
| 82 | +static inline |
---|
| 83 | +struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) |
---|
| 84 | +{ |
---|
| 85 | + return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); |
---|
| 86 | +} |
---|
| 87 | + |
---|
| 88 | +static int afunc_notify(struct g_audio *agdev, int unit_id, int cs); |
---|
42 | 89 | |
---|
43 | 90 | /* --------- USB Function Interface ------------- */ |
---|
44 | 91 | |
---|
.. | .. |
---|
49 | 96 | STR_CLKSRC_OUT, |
---|
50 | 97 | STR_USB_IT, |
---|
51 | 98 | STR_IO_IT, |
---|
52 | | - STR_USB_OT_FU, |
---|
53 | | - STR_IO_OT_FU, |
---|
54 | 99 | STR_USB_OT, |
---|
55 | 100 | STR_IO_OT, |
---|
| 101 | + STR_FU_IN, |
---|
| 102 | + STR_FU_OUT, |
---|
56 | 103 | STR_AS_OUT_ALT0, |
---|
57 | 104 | STR_AS_OUT_ALT1, |
---|
58 | 105 | STR_AS_IN_ALT0, |
---|
.. | .. |
---|
60 | 107 | }; |
---|
61 | 108 | |
---|
62 | 109 | static struct usb_string strings_fn[] = { |
---|
63 | | - [STR_ASSOC].s = "Source/Sink", |
---|
| 110 | + /* [STR_ASSOC].s = DYNAMIC, */ |
---|
64 | 111 | [STR_IF_CTRL].s = "Topology Control", |
---|
65 | | - [STR_CLKSRC_IN].s = "Input clock", |
---|
66 | | - [STR_CLKSRC_OUT].s = "Output clock", |
---|
| 112 | + [STR_CLKSRC_IN].s = "Input Clock", |
---|
| 113 | + [STR_CLKSRC_OUT].s = "Output Clock", |
---|
67 | 114 | [STR_USB_IT].s = "USBH Out", |
---|
68 | 115 | [STR_IO_IT].s = "USBD Out", |
---|
69 | | - [STR_USB_OT_FU].s = "USBH In Feature Unit", |
---|
70 | | - [STR_IO_OT_FU].s = "USBD In Feature Unit", |
---|
71 | 116 | [STR_USB_OT].s = "USBH In", |
---|
72 | 117 | [STR_IO_OT].s = "USBD In", |
---|
| 118 | + [STR_FU_IN].s = "Capture Volume", |
---|
| 119 | + [STR_FU_OUT].s = "Playback Volume", |
---|
73 | 120 | [STR_AS_OUT_ALT0].s = "Playback Inactive", |
---|
74 | 121 | [STR_AS_OUT_ALT1].s = "Playback Active", |
---|
75 | 122 | [STR_AS_IN_ALT0].s = "Capture Inactive", |
---|
76 | 123 | [STR_AS_IN_ALT1].s = "Capture Active", |
---|
77 | 124 | { }, |
---|
| 125 | +}; |
---|
| 126 | + |
---|
| 127 | +static const char *const speed_names[] = { |
---|
| 128 | + [USB_SPEED_UNKNOWN] = "UNKNOWN", |
---|
| 129 | + [USB_SPEED_LOW] = "LS", |
---|
| 130 | + [USB_SPEED_FULL] = "FS", |
---|
| 131 | + [USB_SPEED_HIGH] = "HS", |
---|
| 132 | + [USB_SPEED_WIRELESS] = "W", |
---|
| 133 | + [USB_SPEED_SUPER] = "SS", |
---|
| 134 | + [USB_SPEED_SUPER_PLUS] = "SS+", |
---|
78 | 135 | }; |
---|
79 | 136 | |
---|
80 | 137 | static struct usb_gadget_strings str_fn = { |
---|
.. | .. |
---|
104 | 161 | .bDescriptorType = USB_DT_INTERFACE, |
---|
105 | 162 | |
---|
106 | 163 | .bAlternateSetting = 0, |
---|
107 | | - .bNumEndpoints = 0, |
---|
| 164 | + /* .bNumEndpoints = DYNAMIC */ |
---|
108 | 165 | .bInterfaceClass = USB_CLASS_AUDIO, |
---|
109 | 166 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, |
---|
110 | 167 | .bInterfaceProtocol = UAC_VERSION_2, |
---|
.. | .. |
---|
162 | 219 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
---|
163 | 220 | }; |
---|
164 | 221 | |
---|
165 | | -DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR(0); |
---|
166 | | - |
---|
167 | | -/* Feature Unit for I/O-out */ |
---|
168 | | -static struct uac2_feature_unit_descriptor_0 io_out_ot_fu_desc = { |
---|
169 | | - |
---|
170 | | - .bLength = UAC2_DT_FEATURE_UNIT_SIZE(0), |
---|
171 | | - .bDescriptorType = USB_DT_CS_INTERFACE, |
---|
172 | | - |
---|
173 | | - .bDescriptorSubtype = UAC_FEATURE_UNIT, |
---|
174 | | - /* .bUnitID = DYNAMIC */ |
---|
175 | | - /* .bSourceID = DYNAMIC */ |
---|
176 | | - .bmaControls[0] = (UAC2_CONTROL_BIT_RW(UAC_FU_MUTE) | |
---|
177 | | - UAC2_CONTROL_BIT_RW(UAC_FU_VOLUME)), |
---|
178 | | -}; |
---|
179 | | - |
---|
180 | | -static struct usb_audio_control c_mute_control = { |
---|
181 | | - .list = LIST_HEAD_INIT(c_mute_control.list), |
---|
182 | | - .name = "Capture Mute", |
---|
183 | | - .type = UAC_FU_MUTE, |
---|
184 | | - .set = u_audio_fu_set_cmd, |
---|
185 | | - .get = u_audio_fu_get_cmd, |
---|
186 | | -}; |
---|
187 | | - |
---|
188 | | -static struct usb_audio_control c_volume_control = { |
---|
189 | | - .list = LIST_HEAD_INIT(c_volume_control.list), |
---|
190 | | - .name = "Capture Volume", |
---|
191 | | - .type = UAC_FU_VOLUME, |
---|
192 | | - .set = u_audio_fu_set_cmd, |
---|
193 | | - .get = u_audio_fu_get_cmd, |
---|
194 | | -}; |
---|
195 | | - |
---|
196 | | -static struct usb_audio_control_selector c_feature_unit = { |
---|
197 | | - .list = LIST_HEAD_INIT(c_feature_unit.list), |
---|
198 | | - /* .id = DYNAMIC */ |
---|
199 | | - .name = "Capture Mute & Volume Control", |
---|
200 | | - .type = UAC_FEATURE_UNIT, |
---|
201 | | - .desc = (struct usb_descriptor_header *)&io_out_ot_fu_desc, |
---|
202 | | -}; |
---|
203 | | - |
---|
204 | | -/* Feature Unit for USB_IN */ |
---|
205 | | -static struct uac2_feature_unit_descriptor_0 usb_in_ot_fu_desc = { |
---|
206 | | - .bLength = UAC2_DT_FEATURE_UNIT_SIZE(0), |
---|
207 | | - .bDescriptorType = USB_DT_CS_INTERFACE, |
---|
208 | | - |
---|
209 | | - .bDescriptorSubtype = UAC_FEATURE_UNIT, |
---|
210 | | - /* .bUnitID = DYNAMIC */ |
---|
211 | | - /* .bSourceID = DYNAMIC */ |
---|
212 | | - .bmaControls[0] = (UAC2_CONTROL_BIT_RW(UAC_FU_MUTE) | |
---|
213 | | - UAC2_CONTROL_BIT_RW(UAC_FU_VOLUME)), |
---|
214 | | -}; |
---|
215 | | - |
---|
216 | | -static struct usb_audio_control p_mute_control = { |
---|
217 | | - .list = LIST_HEAD_INIT(p_mute_control.list), |
---|
218 | | - .name = "Playback Mute", |
---|
219 | | - .type = UAC_FU_MUTE, |
---|
220 | | - .set = u_audio_fu_set_cmd, |
---|
221 | | - .get = u_audio_fu_get_cmd, |
---|
222 | | -}; |
---|
223 | | - |
---|
224 | | -static struct usb_audio_control p_volume_control = { |
---|
225 | | - .list = LIST_HEAD_INIT(p_volume_control.list), |
---|
226 | | - .name = "Playback Volume", |
---|
227 | | - .type = UAC_FU_VOLUME, |
---|
228 | | - .set = u_audio_fu_set_cmd, |
---|
229 | | - .get = u_audio_fu_get_cmd, |
---|
230 | | -}; |
---|
231 | | - |
---|
232 | | -static struct usb_audio_control_selector p_feature_unit = { |
---|
233 | | - .list = LIST_HEAD_INIT(p_feature_unit.list), |
---|
234 | | - /* .id = DYNAMIC */ |
---|
235 | | - .name = "Playback Mute & Volume Control", |
---|
236 | | - .type = UAC_FEATURE_UNIT, |
---|
237 | | - .desc = (struct usb_descriptor_header *)&usb_in_ot_fu_desc, |
---|
238 | | -}; |
---|
239 | | - |
---|
240 | 222 | /* Ouput Terminal for USB_IN */ |
---|
241 | 223 | static struct uac2_output_terminal_descriptor usb_in_ot_desc = { |
---|
242 | 224 | .bLength = sizeof usb_in_ot_desc, |
---|
.. | .. |
---|
265 | 247 | .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), |
---|
266 | 248 | }; |
---|
267 | 249 | |
---|
| 250 | +static struct uac2_feature_unit_descriptor *in_feature_unit_desc; |
---|
| 251 | +static struct uac2_feature_unit_descriptor *out_feature_unit_desc; |
---|
| 252 | + |
---|
268 | 253 | static struct uac2_ac_header_descriptor ac_hdr_desc = { |
---|
269 | 254 | .bLength = sizeof ac_hdr_desc, |
---|
270 | 255 | .bDescriptorType = USB_DT_CS_INTERFACE, |
---|
271 | 256 | |
---|
272 | | - .bDescriptorSubtype = UAC_HEADER, |
---|
| 257 | + .bDescriptorSubtype = UAC_MS_HEADER, |
---|
273 | 258 | .bcdADC = cpu_to_le16(0x200), |
---|
274 | 259 | .bCategory = UAC2_FUNCTION_IO_BOX, |
---|
275 | | - .wTotalLength = cpu_to_le16(sizeof ac_hdr_desc + sizeof in_clk_src_desc |
---|
276 | | - + sizeof out_clk_src_desc + sizeof usb_out_it_desc |
---|
277 | | - + sizeof io_in_it_desc + sizeof usb_in_ot_desc |
---|
278 | | - + sizeof io_out_ot_desc + sizeof usb_in_ot_fu_desc |
---|
279 | | - + sizeof io_out_ot_fu_desc), |
---|
| 260 | + /* .wTotalLength = DYNAMIC */ |
---|
280 | 261 | .bmControls = 0, |
---|
| 262 | +}; |
---|
| 263 | + |
---|
| 264 | +/* AC IN Interrupt Endpoint */ |
---|
| 265 | +static struct usb_endpoint_descriptor fs_ep_int_desc = { |
---|
| 266 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 267 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 268 | + |
---|
| 269 | + .bEndpointAddress = USB_DIR_IN, |
---|
| 270 | + .bmAttributes = USB_ENDPOINT_XFER_INT, |
---|
| 271 | + .wMaxPacketSize = cpu_to_le16(6), |
---|
| 272 | + .bInterval = 1, |
---|
| 273 | +}; |
---|
| 274 | + |
---|
| 275 | +static struct usb_endpoint_descriptor hs_ep_int_desc = { |
---|
| 276 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 277 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 278 | + |
---|
| 279 | + .bmAttributes = USB_ENDPOINT_XFER_INT, |
---|
| 280 | + .wMaxPacketSize = cpu_to_le16(6), |
---|
| 281 | + .bInterval = 4, |
---|
| 282 | +}; |
---|
| 283 | + |
---|
| 284 | +static struct usb_endpoint_descriptor ss_ep_int_desc = { |
---|
| 285 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 286 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 287 | + |
---|
| 288 | + .bEndpointAddress = USB_DIR_IN, |
---|
| 289 | + .bmAttributes = USB_ENDPOINT_XFER_INT, |
---|
| 290 | + .wMaxPacketSize = cpu_to_le16(6), |
---|
| 291 | + .bInterval = 4, |
---|
| 292 | +}; |
---|
| 293 | + |
---|
| 294 | +static struct usb_ss_ep_comp_descriptor ss_ep_int_desc_comp = { |
---|
| 295 | + .bLength = sizeof(ss_ep_int_desc_comp), |
---|
| 296 | + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
---|
| 297 | + .wBytesPerInterval = cpu_to_le16(6), |
---|
281 | 298 | }; |
---|
282 | 299 | |
---|
283 | 300 | /* Audio Streaming OUT Interface - Alt0 */ |
---|
.. | .. |
---|
331 | 348 | .bDescriptorType = USB_DT_ENDPOINT, |
---|
332 | 349 | |
---|
333 | 350 | .bEndpointAddress = USB_DIR_OUT, |
---|
334 | | - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE, |
---|
| 351 | + /* .bmAttributes = DYNAMIC */ |
---|
335 | 352 | /* .wMaxPacketSize = DYNAMIC */ |
---|
336 | 353 | .bInterval = 1, |
---|
337 | 354 | }; |
---|
.. | .. |
---|
340 | 357 | .bLength = USB_DT_ENDPOINT_SIZE, |
---|
341 | 358 | .bDescriptorType = USB_DT_ENDPOINT, |
---|
342 | 359 | |
---|
343 | | - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE, |
---|
| 360 | + /* .bmAttributes = DYNAMIC */ |
---|
344 | 361 | /* .wMaxPacketSize = DYNAMIC */ |
---|
345 | | - .bInterval = 4, |
---|
| 362 | + /* .bInterval = DYNAMIC */ |
---|
346 | 363 | }; |
---|
347 | 364 | |
---|
348 | 365 | static struct usb_endpoint_descriptor ss_epout_desc = { |
---|
.. | .. |
---|
350 | 367 | .bDescriptorType = USB_DT_ENDPOINT, |
---|
351 | 368 | |
---|
352 | 369 | .bEndpointAddress = USB_DIR_OUT, |
---|
353 | | - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE, |
---|
| 370 | + /* .bmAttributes = DYNAMIC */ |
---|
354 | 371 | /* .wMaxPacketSize = DYNAMIC */ |
---|
355 | | - .bInterval = 4, |
---|
| 372 | + /* .bInterval = DYNAMIC */ |
---|
356 | 373 | }; |
---|
357 | 374 | |
---|
358 | 375 | static struct usb_ss_ep_comp_descriptor ss_epout_desc_comp = { |
---|
.. | .. |
---|
374 | 391 | .bLockDelayUnits = 0, |
---|
375 | 392 | .wLockDelay = 0, |
---|
376 | 393 | }; |
---|
| 394 | + |
---|
| 395 | +/* STD AS ISO IN Feedback Endpoint */ |
---|
| 396 | +static struct usb_endpoint_descriptor fs_epin_fback_desc = { |
---|
| 397 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 398 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 399 | + |
---|
| 400 | + .bEndpointAddress = USB_DIR_IN, |
---|
| 401 | + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, |
---|
| 402 | + .wMaxPacketSize = cpu_to_le16(3), |
---|
| 403 | + .bInterval = 1, |
---|
| 404 | +}; |
---|
| 405 | + |
---|
| 406 | +static struct usb_endpoint_descriptor hs_epin_fback_desc = { |
---|
| 407 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 408 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 409 | + |
---|
| 410 | + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, |
---|
| 411 | + .wMaxPacketSize = cpu_to_le16(4), |
---|
| 412 | + .bInterval = 4, |
---|
| 413 | +}; |
---|
| 414 | + |
---|
| 415 | +static struct usb_endpoint_descriptor ss_epin_fback_desc = { |
---|
| 416 | + .bLength = USB_DT_ENDPOINT_SIZE, |
---|
| 417 | + .bDescriptorType = USB_DT_ENDPOINT, |
---|
| 418 | + |
---|
| 419 | + .bEndpointAddress = USB_DIR_IN, |
---|
| 420 | + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK, |
---|
| 421 | + .wMaxPacketSize = cpu_to_le16(4), |
---|
| 422 | + .bInterval = 4, |
---|
| 423 | +}; |
---|
| 424 | + |
---|
| 425 | +static struct usb_ss_ep_comp_descriptor ss_epin_fback_desc_comp = { |
---|
| 426 | + .bLength = sizeof(ss_epin_fback_desc_comp), |
---|
| 427 | + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, |
---|
| 428 | + .bMaxBurst = 0, |
---|
| 429 | + .bmAttributes = 0, |
---|
| 430 | + .wBytesPerInterval = cpu_to_le16(4), |
---|
| 431 | +}; |
---|
| 432 | + |
---|
377 | 433 | |
---|
378 | 434 | /* Audio Streaming IN Interface - Alt0 */ |
---|
379 | 435 | static struct usb_interface_descriptor std_as_in_if0_desc = { |
---|
.. | .. |
---|
426 | 482 | .bDescriptorType = USB_DT_ENDPOINT, |
---|
427 | 483 | |
---|
428 | 484 | .bEndpointAddress = USB_DIR_IN, |
---|
429 | | - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_SYNC, |
---|
| 485 | + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, |
---|
430 | 486 | /* .wMaxPacketSize = DYNAMIC */ |
---|
431 | 487 | .bInterval = 1, |
---|
432 | 488 | }; |
---|
.. | .. |
---|
435 | 491 | .bLength = USB_DT_ENDPOINT_SIZE, |
---|
436 | 492 | .bDescriptorType = USB_DT_ENDPOINT, |
---|
437 | 493 | |
---|
438 | | - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_SYNC, |
---|
| 494 | + .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, |
---|
439 | 495 | /* .wMaxPacketSize = DYNAMIC */ |
---|
440 | | - .bInterval = 4, |
---|
| 496 | + /* .bInterval = DYNAMIC */ |
---|
441 | 497 | }; |
---|
442 | 498 | |
---|
443 | 499 | static struct usb_endpoint_descriptor ss_epin_desc = { |
---|
.. | .. |
---|
447 | 503 | .bEndpointAddress = USB_DIR_IN, |
---|
448 | 504 | .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, |
---|
449 | 505 | /* .wMaxPacketSize = DYNAMIC */ |
---|
450 | | - .bInterval = 4, |
---|
| 506 | + /* .bInterval = DYNAMIC */ |
---|
451 | 507 | }; |
---|
452 | 508 | |
---|
453 | 509 | static struct usb_ss_ep_comp_descriptor ss_epin_desc_comp = { |
---|
.. | .. |
---|
478 | 534 | (struct usb_descriptor_header *)&in_clk_src_desc, |
---|
479 | 535 | (struct usb_descriptor_header *)&out_clk_src_desc, |
---|
480 | 536 | (struct usb_descriptor_header *)&usb_out_it_desc, |
---|
| 537 | + (struct usb_descriptor_header *)&out_feature_unit_desc, |
---|
481 | 538 | (struct usb_descriptor_header *)&io_in_it_desc, |
---|
482 | | - (struct usb_descriptor_header *)&usb_in_ot_fu_desc, |
---|
483 | | - (struct usb_descriptor_header *)&io_out_ot_fu_desc, |
---|
484 | 539 | (struct usb_descriptor_header *)&usb_in_ot_desc, |
---|
| 540 | + (struct usb_descriptor_header *)&in_feature_unit_desc, |
---|
485 | 541 | (struct usb_descriptor_header *)&io_out_ot_desc, |
---|
| 542 | + |
---|
| 543 | + (struct usb_descriptor_header *)&fs_ep_int_desc, |
---|
486 | 544 | |
---|
487 | 545 | (struct usb_descriptor_header *)&std_as_out_if0_desc, |
---|
488 | 546 | (struct usb_descriptor_header *)&std_as_out_if1_desc, |
---|
.. | .. |
---|
491 | 549 | (struct usb_descriptor_header *)&as_out_fmt1_desc, |
---|
492 | 550 | (struct usb_descriptor_header *)&fs_epout_desc, |
---|
493 | 551 | (struct usb_descriptor_header *)&as_iso_out_desc, |
---|
| 552 | + (struct usb_descriptor_header *)&fs_epin_fback_desc, |
---|
494 | 553 | |
---|
495 | 554 | (struct usb_descriptor_header *)&std_as_in_if0_desc, |
---|
496 | 555 | (struct usb_descriptor_header *)&std_as_in_if1_desc, |
---|
.. | .. |
---|
510 | 569 | (struct usb_descriptor_header *)&in_clk_src_desc, |
---|
511 | 570 | (struct usb_descriptor_header *)&out_clk_src_desc, |
---|
512 | 571 | (struct usb_descriptor_header *)&usb_out_it_desc, |
---|
| 572 | + (struct usb_descriptor_header *)&out_feature_unit_desc, |
---|
513 | 573 | (struct usb_descriptor_header *)&io_in_it_desc, |
---|
514 | | - (struct usb_descriptor_header *)&usb_in_ot_fu_desc, |
---|
515 | | - (struct usb_descriptor_header *)&io_out_ot_fu_desc, |
---|
516 | 574 | (struct usb_descriptor_header *)&usb_in_ot_desc, |
---|
| 575 | + (struct usb_descriptor_header *)&in_feature_unit_desc, |
---|
517 | 576 | (struct usb_descriptor_header *)&io_out_ot_desc, |
---|
| 577 | + |
---|
| 578 | + (struct usb_descriptor_header *)&hs_ep_int_desc, |
---|
518 | 579 | |
---|
519 | 580 | (struct usb_descriptor_header *)&std_as_out_if0_desc, |
---|
520 | 581 | (struct usb_descriptor_header *)&std_as_out_if1_desc, |
---|
.. | .. |
---|
523 | 584 | (struct usb_descriptor_header *)&as_out_fmt1_desc, |
---|
524 | 585 | (struct usb_descriptor_header *)&hs_epout_desc, |
---|
525 | 586 | (struct usb_descriptor_header *)&as_iso_out_desc, |
---|
| 587 | + (struct usb_descriptor_header *)&hs_epin_fback_desc, |
---|
526 | 588 | |
---|
527 | 589 | (struct usb_descriptor_header *)&std_as_in_if0_desc, |
---|
528 | 590 | (struct usb_descriptor_header *)&std_as_in_if1_desc, |
---|
.. | .. |
---|
542 | 604 | (struct usb_descriptor_header *)&in_clk_src_desc, |
---|
543 | 605 | (struct usb_descriptor_header *)&out_clk_src_desc, |
---|
544 | 606 | (struct usb_descriptor_header *)&usb_out_it_desc, |
---|
| 607 | + (struct usb_descriptor_header *)&out_feature_unit_desc, |
---|
545 | 608 | (struct usb_descriptor_header *)&io_in_it_desc, |
---|
546 | | - (struct usb_descriptor_header *)&usb_in_ot_fu_desc, |
---|
547 | | - (struct usb_descriptor_header *)&io_out_ot_fu_desc, |
---|
548 | 609 | (struct usb_descriptor_header *)&usb_in_ot_desc, |
---|
| 610 | + (struct usb_descriptor_header *)&in_feature_unit_desc, |
---|
549 | 611 | (struct usb_descriptor_header *)&io_out_ot_desc, |
---|
| 612 | + |
---|
| 613 | + (struct usb_descriptor_header *)&ss_ep_int_desc, |
---|
| 614 | + (struct usb_descriptor_header *)&ss_ep_int_desc_comp, |
---|
550 | 615 | |
---|
551 | 616 | (struct usb_descriptor_header *)&std_as_out_if0_desc, |
---|
552 | 617 | (struct usb_descriptor_header *)&std_as_out_if1_desc, |
---|
.. | .. |
---|
556 | 621 | (struct usb_descriptor_header *)&ss_epout_desc, |
---|
557 | 622 | (struct usb_descriptor_header *)&ss_epout_desc_comp, |
---|
558 | 623 | (struct usb_descriptor_header *)&as_iso_out_desc, |
---|
| 624 | + (struct usb_descriptor_header *)&ss_epin_fback_desc, |
---|
| 625 | + (struct usb_descriptor_header *)&ss_epin_fback_desc_comp, |
---|
559 | 626 | |
---|
560 | 627 | (struct usb_descriptor_header *)&std_as_in_if0_desc, |
---|
561 | 628 | (struct usb_descriptor_header *)&std_as_in_if1_desc, |
---|
.. | .. |
---|
569 | 636 | }; |
---|
570 | 637 | |
---|
571 | 638 | struct cntrl_cur_lay2 { |
---|
572 | | - __le16 dCUR; |
---|
| 639 | + __le16 wCUR; |
---|
573 | 640 | }; |
---|
574 | 641 | |
---|
575 | 642 | struct cntrl_range_lay2 { |
---|
576 | 643 | __le16 wNumSubRanges; |
---|
577 | | - __le16 dMIN; |
---|
578 | | - __le16 dMAX; |
---|
579 | | - __le16 dRES; |
---|
| 644 | + __le16 wMIN; |
---|
| 645 | + __le16 wMAX; |
---|
| 646 | + __le16 wRES; |
---|
580 | 647 | } __packed; |
---|
581 | 648 | |
---|
582 | 649 | struct cntrl_cur_lay3 { |
---|
583 | 650 | __le32 dCUR; |
---|
584 | 651 | }; |
---|
585 | 652 | |
---|
586 | | -struct cntrl_range_lay3 { |
---|
| 653 | +struct cntrl_subrange_lay3 { |
---|
587 | 654 | __le32 dMIN; |
---|
588 | 655 | __le32 dMAX; |
---|
589 | 656 | __le32 dRES; |
---|
590 | 657 | } __packed; |
---|
591 | 658 | |
---|
592 | | -#define ranges_size(c) (sizeof(c.wNumSubRanges) + c.wNumSubRanges \ |
---|
593 | | - * sizeof(struct cntrl_range_lay3)) |
---|
594 | | -struct cntrl_ranges_lay3 { |
---|
595 | | - __u16 wNumSubRanges; |
---|
596 | | - struct cntrl_range_lay3 r[UAC_MAX_RATES]; |
---|
597 | | -} __packed; |
---|
| 659 | +#define ranges_lay3_size(c) (sizeof(c.wNumSubRanges) \ |
---|
| 660 | + + le16_to_cpu(c.wNumSubRanges) \ |
---|
| 661 | + * sizeof(struct cntrl_subrange_lay3)) |
---|
598 | 662 | |
---|
599 | | -static int set_ep_max_packet_size(const struct f_uac_opts *uac2_opts, |
---|
| 663 | +#define DECLARE_UAC2_CNTRL_RANGES_LAY3(k, n) \ |
---|
| 664 | + struct cntrl_ranges_lay3_##k { \ |
---|
| 665 | + __le16 wNumSubRanges; \ |
---|
| 666 | + struct cntrl_subrange_lay3 r[n]; \ |
---|
| 667 | +} __packed |
---|
| 668 | + |
---|
| 669 | +DECLARE_UAC2_CNTRL_RANGES_LAY3(srates, UAC_MAX_RATES); |
---|
| 670 | + |
---|
| 671 | +static int get_max_srate(const int *srates) |
---|
| 672 | +{ |
---|
| 673 | + int i, max_srate = 0; |
---|
| 674 | + |
---|
| 675 | + for (i = 0; i < UAC_MAX_RATES; i++) { |
---|
| 676 | + if (srates[i] == 0) |
---|
| 677 | + break; |
---|
| 678 | + if (srates[i] > max_srate) |
---|
| 679 | + max_srate = srates[i]; |
---|
| 680 | + } |
---|
| 681 | + return max_srate; |
---|
| 682 | +} |
---|
| 683 | + |
---|
| 684 | +static int get_max_bw_for_bint(const struct f_uac2_opts *uac2_opts, |
---|
| 685 | + u8 bint, unsigned int factor, bool is_playback) |
---|
| 686 | +{ |
---|
| 687 | + int chmask, srate, ssize; |
---|
| 688 | + u16 max_size_bw; |
---|
| 689 | + |
---|
| 690 | + if (is_playback) { |
---|
| 691 | + chmask = uac2_opts->p_chmask; |
---|
| 692 | + srate = get_max_srate(uac2_opts->p_srates); |
---|
| 693 | + ssize = uac2_opts->p_ssize; |
---|
| 694 | + } else { |
---|
| 695 | + chmask = uac2_opts->c_chmask; |
---|
| 696 | + srate = get_max_srate(uac2_opts->c_srates); |
---|
| 697 | + ssize = uac2_opts->c_ssize; |
---|
| 698 | + } |
---|
| 699 | + |
---|
| 700 | + if (is_playback || (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { |
---|
| 701 | + // playback is always async, capture only when configured |
---|
| 702 | + // Win10 requires max packet size + 1 frame |
---|
| 703 | + srate = srate * (1000 + uac2_opts->fb_max) / 1000; |
---|
| 704 | + // updated srate is always bigger, therefore DIV_ROUND_UP always yields +1 |
---|
| 705 | + max_size_bw = num_channels(chmask) * ssize * |
---|
| 706 | + (DIV_ROUND_UP(srate, factor / (1 << (bint - 1)))); |
---|
| 707 | + } else { |
---|
| 708 | + // adding 1 frame provision for Win10 |
---|
| 709 | + max_size_bw = num_channels(chmask) * ssize * |
---|
| 710 | + (DIV_ROUND_UP(srate, factor / (1 << (bint - 1))) + 1); |
---|
| 711 | + } |
---|
| 712 | + return max_size_bw; |
---|
| 713 | +} |
---|
| 714 | + |
---|
| 715 | +static int set_ep_max_packet_size_bint(struct device *dev, const struct f_uac2_opts *uac2_opts, |
---|
600 | 716 | struct usb_endpoint_descriptor *ep_desc, |
---|
601 | 717 | enum usb_device_speed speed, bool is_playback) |
---|
602 | 718 | { |
---|
603 | | - int chmask, srate = 0, ssize; |
---|
604 | 719 | u16 max_size_bw, max_size_ep; |
---|
605 | | - unsigned int factor; |
---|
606 | | - int i; |
---|
| 720 | + u8 bint, opts_bint; |
---|
| 721 | + char *dir; |
---|
607 | 722 | |
---|
608 | 723 | switch (speed) { |
---|
609 | 724 | case USB_SPEED_FULL: |
---|
610 | 725 | max_size_ep = 1023; |
---|
611 | | - factor = 1000; |
---|
| 726 | + // fixed |
---|
| 727 | + bint = ep_desc->bInterval; |
---|
| 728 | + max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 1000, is_playback); |
---|
612 | 729 | break; |
---|
613 | 730 | |
---|
614 | 731 | case USB_SPEED_HIGH: |
---|
615 | 732 | case USB_SPEED_SUPER: |
---|
616 | 733 | max_size_ep = 1024; |
---|
617 | | - factor = 8000; |
---|
| 734 | + if (is_playback) |
---|
| 735 | + opts_bint = uac2_opts->p_hs_bint; |
---|
| 736 | + else |
---|
| 737 | + opts_bint = uac2_opts->c_hs_bint; |
---|
| 738 | + |
---|
| 739 | + if (opts_bint > 0) { |
---|
| 740 | + /* fixed bint */ |
---|
| 741 | + bint = opts_bint; |
---|
| 742 | + max_size_bw = get_max_bw_for_bint(uac2_opts, bint, 8000, is_playback); |
---|
| 743 | + } else { |
---|
| 744 | + /* checking bInterval from 4 to 1 whether the required bandwidth fits */ |
---|
| 745 | + for (bint = 4; bint > 0; --bint) { |
---|
| 746 | + max_size_bw = get_max_bw_for_bint( |
---|
| 747 | + uac2_opts, bint, 8000, is_playback); |
---|
| 748 | + if (max_size_bw <= max_size_ep) |
---|
| 749 | + break; |
---|
| 750 | + } |
---|
| 751 | + } |
---|
618 | 752 | break; |
---|
619 | 753 | |
---|
620 | 754 | default: |
---|
621 | 755 | return -EINVAL; |
---|
622 | 756 | } |
---|
623 | 757 | |
---|
624 | | - if (is_playback) { |
---|
625 | | - chmask = uac2_opts->p_chmask; |
---|
626 | | - for (i = 0; i < UAC_MAX_RATES; i++) { |
---|
627 | | - if (uac2_opts->p_srate[i] == 0) |
---|
628 | | - break; |
---|
629 | | - if (uac2_opts->p_srate[i] > srate) |
---|
630 | | - srate = uac2_opts->p_srate[i]; |
---|
631 | | - } |
---|
632 | | - ssize = uac2_opts->p_ssize; |
---|
633 | | - } else { |
---|
634 | | - chmask = uac2_opts->c_chmask; |
---|
635 | | - for (i = 0; i < UAC_MAX_RATES; i++) { |
---|
636 | | - if (uac2_opts->c_srate[i] == 0) |
---|
637 | | - break; |
---|
638 | | - if (uac2_opts->c_srate[i] > srate) |
---|
639 | | - srate = uac2_opts->c_srate[i]; |
---|
640 | | - } |
---|
641 | | - ssize = uac2_opts->c_ssize; |
---|
| 758 | + if (is_playback) |
---|
| 759 | + dir = "Playback"; |
---|
| 760 | + else |
---|
| 761 | + dir = "Capture"; |
---|
| 762 | + |
---|
| 763 | + if (max_size_bw <= max_size_ep) |
---|
| 764 | + dev_dbg(dev, |
---|
| 765 | + "%s %s: Would use wMaxPacketSize %d and bInterval %d\n", |
---|
| 766 | + speed_names[speed], dir, max_size_bw, bint); |
---|
| 767 | + else { |
---|
| 768 | + dev_warn(dev, |
---|
| 769 | + "%s %s: Req. wMaxPacketSize %d at bInterval %d > max ISOC %d, may drop data!\n", |
---|
| 770 | + speed_names[speed], dir, max_size_bw, bint, max_size_ep); |
---|
| 771 | + max_size_bw = max_size_ep; |
---|
642 | 772 | } |
---|
643 | 773 | |
---|
644 | | - max_size_bw = num_channels(chmask) * ssize * |
---|
645 | | - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); |
---|
646 | | - ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, |
---|
647 | | - max_size_ep)); |
---|
| 774 | + ep_desc->wMaxPacketSize = cpu_to_le16(max_size_bw); |
---|
| 775 | + ep_desc->bInterval = bint; |
---|
648 | 776 | |
---|
649 | 777 | return 0; |
---|
| 778 | +} |
---|
| 779 | + |
---|
| 780 | +static struct uac2_feature_unit_descriptor *build_fu_desc(int chmask) |
---|
| 781 | +{ |
---|
| 782 | + struct uac2_feature_unit_descriptor *fu_desc; |
---|
| 783 | + int channels = num_channels(chmask); |
---|
| 784 | + int fu_desc_size = UAC2_DT_FEATURE_UNIT_SIZE(channels); |
---|
| 785 | + |
---|
| 786 | + fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); |
---|
| 787 | + if (!fu_desc) |
---|
| 788 | + return NULL; |
---|
| 789 | + |
---|
| 790 | + fu_desc->bLength = fu_desc_size; |
---|
| 791 | + fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; |
---|
| 792 | + |
---|
| 793 | + fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; |
---|
| 794 | + |
---|
| 795 | + /* bUnitID, bSourceID and bmaControls will be defined later */ |
---|
| 796 | + |
---|
| 797 | + return fu_desc; |
---|
650 | 798 | } |
---|
651 | 799 | |
---|
652 | 800 | /* Use macro to overcome line length limitation */ |
---|
653 | 801 | #define USBDHDR(p) (struct usb_descriptor_header *)(p) |
---|
654 | 802 | |
---|
655 | | -static void setup_headers(struct f_uac_opts *opts, |
---|
| 803 | +static void setup_headers(struct f_uac2_opts *opts, |
---|
656 | 804 | struct usb_descriptor_header **headers, |
---|
657 | 805 | enum usb_device_speed speed) |
---|
658 | 806 | { |
---|
659 | 807 | struct usb_ss_ep_comp_descriptor *epout_desc_comp = NULL; |
---|
660 | 808 | struct usb_ss_ep_comp_descriptor *epin_desc_comp = NULL; |
---|
| 809 | + struct usb_ss_ep_comp_descriptor *epin_fback_desc_comp = NULL; |
---|
| 810 | + struct usb_ss_ep_comp_descriptor *ep_int_desc_comp = NULL; |
---|
661 | 811 | struct usb_endpoint_descriptor *epout_desc; |
---|
662 | 812 | struct usb_endpoint_descriptor *epin_desc; |
---|
| 813 | + struct usb_endpoint_descriptor *epin_fback_desc; |
---|
| 814 | + struct usb_endpoint_descriptor *ep_int_desc; |
---|
663 | 815 | int i; |
---|
664 | 816 | |
---|
665 | 817 | switch (speed) { |
---|
666 | 818 | case USB_SPEED_FULL: |
---|
667 | 819 | epout_desc = &fs_epout_desc; |
---|
668 | 820 | epin_desc = &fs_epin_desc; |
---|
| 821 | + epin_fback_desc = &fs_epin_fback_desc; |
---|
| 822 | + ep_int_desc = &fs_ep_int_desc; |
---|
669 | 823 | break; |
---|
670 | 824 | case USB_SPEED_HIGH: |
---|
671 | 825 | epout_desc = &hs_epout_desc; |
---|
672 | 826 | epin_desc = &hs_epin_desc; |
---|
| 827 | + epin_fback_desc = &hs_epin_fback_desc; |
---|
| 828 | + ep_int_desc = &hs_ep_int_desc; |
---|
673 | 829 | break; |
---|
674 | 830 | default: |
---|
675 | 831 | epout_desc = &ss_epout_desc; |
---|
676 | 832 | epin_desc = &ss_epin_desc; |
---|
677 | 833 | epout_desc_comp = &ss_epout_desc_comp; |
---|
678 | 834 | epin_desc_comp = &ss_epin_desc_comp; |
---|
| 835 | + epin_fback_desc = &ss_epin_fback_desc; |
---|
| 836 | + epin_fback_desc_comp = &ss_epin_fback_desc_comp; |
---|
| 837 | + ep_int_desc = &ss_ep_int_desc; |
---|
| 838 | + ep_int_desc_comp = &ss_ep_int_desc_comp; |
---|
679 | 839 | } |
---|
680 | 840 | |
---|
681 | 841 | i = 0; |
---|
.. | .. |
---|
687 | 847 | if (EPOUT_EN(opts)) { |
---|
688 | 848 | headers[i++] = USBDHDR(&out_clk_src_desc); |
---|
689 | 849 | headers[i++] = USBDHDR(&usb_out_it_desc); |
---|
| 850 | + |
---|
| 851 | + if (FUOUT_EN(opts)) |
---|
| 852 | + headers[i++] = USBDHDR(out_feature_unit_desc); |
---|
690 | 853 | } |
---|
| 854 | + |
---|
691 | 855 | if (EPIN_EN(opts)) { |
---|
692 | 856 | headers[i++] = USBDHDR(&io_in_it_desc); |
---|
693 | | - if (EPIN_FU(opts)) |
---|
694 | | - headers[i++] = USBDHDR(&usb_in_ot_fu_desc); |
---|
| 857 | + |
---|
| 858 | + if (FUIN_EN(opts)) |
---|
| 859 | + headers[i++] = USBDHDR(in_feature_unit_desc); |
---|
| 860 | + |
---|
695 | 861 | headers[i++] = USBDHDR(&usb_in_ot_desc); |
---|
696 | 862 | } |
---|
697 | | - if (EPOUT_EN(opts)) { |
---|
698 | | - if (EPOUT_FU(opts)) |
---|
699 | | - headers[i++] = USBDHDR(&io_out_ot_fu_desc); |
---|
| 863 | + |
---|
| 864 | + if (EPOUT_EN(opts)) |
---|
700 | 865 | headers[i++] = USBDHDR(&io_out_ot_desc); |
---|
| 866 | + |
---|
| 867 | + if (FUOUT_EN(opts) || FUIN_EN(opts)) { |
---|
| 868 | + headers[i++] = USBDHDR(ep_int_desc); |
---|
| 869 | + if (ep_int_desc_comp) |
---|
| 870 | + headers[i++] = USBDHDR(ep_int_desc_comp); |
---|
| 871 | + } |
---|
| 872 | + |
---|
| 873 | + if (EPOUT_EN(opts)) { |
---|
701 | 874 | headers[i++] = USBDHDR(&std_as_out_if0_desc); |
---|
702 | 875 | headers[i++] = USBDHDR(&std_as_out_if1_desc); |
---|
703 | 876 | headers[i++] = USBDHDR(&as_out_hdr_desc); |
---|
.. | .. |
---|
707 | 880 | headers[i++] = USBDHDR(epout_desc_comp); |
---|
708 | 881 | |
---|
709 | 882 | headers[i++] = USBDHDR(&as_iso_out_desc); |
---|
| 883 | + |
---|
| 884 | + if (EPOUT_FBACK_IN_EN(opts)) { |
---|
| 885 | + headers[i++] = USBDHDR(epin_fback_desc); |
---|
| 886 | + if (epin_fback_desc_comp) |
---|
| 887 | + headers[i++] = USBDHDR(epin_fback_desc_comp); |
---|
| 888 | + } |
---|
710 | 889 | } |
---|
| 890 | + |
---|
711 | 891 | if (EPIN_EN(opts)) { |
---|
712 | 892 | headers[i++] = USBDHDR(&std_as_in_if0_desc); |
---|
713 | 893 | headers[i++] = USBDHDR(&std_as_in_if1_desc); |
---|
.. | .. |
---|
722 | 902 | headers[i] = NULL; |
---|
723 | 903 | } |
---|
724 | 904 | |
---|
725 | | -static void setup_descriptor(struct f_uac_opts *opts) |
---|
| 905 | +static void setup_descriptor(struct f_uac2_opts *opts) |
---|
726 | 906 | { |
---|
727 | 907 | /* patch descriptors */ |
---|
728 | 908 | int i = 1; /* ID's start with 1 */ |
---|
.. | .. |
---|
731 | 911 | usb_out_it_desc.bTerminalID = i++; |
---|
732 | 912 | if (EPIN_EN(opts)) |
---|
733 | 913 | io_in_it_desc.bTerminalID = i++; |
---|
734 | | - if (EPOUT_EN(opts) && EPOUT_FU(opts)) |
---|
735 | | - io_out_ot_fu_desc.bUnitID = i++; |
---|
736 | | - if (EPIN_EN(opts) && EPIN_FU(opts)) |
---|
737 | | - usb_in_ot_fu_desc.bUnitID = i++; |
---|
738 | 914 | if (EPOUT_EN(opts)) |
---|
739 | 915 | io_out_ot_desc.bTerminalID = i++; |
---|
740 | 916 | if (EPIN_EN(opts)) |
---|
741 | 917 | usb_in_ot_desc.bTerminalID = i++; |
---|
| 918 | + if (FUOUT_EN(opts)) |
---|
| 919 | + out_feature_unit_desc->bUnitID = i++; |
---|
| 920 | + if (FUIN_EN(opts)) |
---|
| 921 | + in_feature_unit_desc->bUnitID = i++; |
---|
742 | 922 | if (EPOUT_EN(opts)) |
---|
743 | 923 | out_clk_src_desc.bClockID = i++; |
---|
744 | 924 | if (EPIN_EN(opts)) |
---|
745 | 925 | in_clk_src_desc.bClockID = i++; |
---|
746 | 926 | |
---|
747 | 927 | usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; |
---|
748 | | - if (EPIN_FU(opts)) { |
---|
749 | | - usb_in_ot_fu_desc.bSourceID = io_in_it_desc.bTerminalID; |
---|
750 | | - usb_in_ot_desc.bSourceID = usb_in_ot_fu_desc.bUnitID; |
---|
751 | | - p_feature_unit.id = usb_in_ot_fu_desc.bUnitID; |
---|
| 928 | + |
---|
| 929 | + if (FUIN_EN(opts)) { |
---|
| 930 | + usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; |
---|
| 931 | + in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; |
---|
752 | 932 | } else { |
---|
753 | 933 | usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; |
---|
754 | 934 | } |
---|
| 935 | + |
---|
755 | 936 | usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; |
---|
756 | 937 | io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; |
---|
757 | 938 | io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; |
---|
758 | | - if (EPOUT_FU(opts)) { |
---|
759 | | - io_out_ot_fu_desc.bSourceID = usb_out_it_desc.bTerminalID; |
---|
760 | | - io_out_ot_desc.bSourceID = io_out_ot_fu_desc.bUnitID; |
---|
761 | | - c_feature_unit.id = io_out_ot_fu_desc.bUnitID; |
---|
| 939 | + |
---|
| 940 | + if (FUOUT_EN(opts)) { |
---|
| 941 | + io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; |
---|
| 942 | + out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; |
---|
762 | 943 | } else { |
---|
763 | 944 | io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; |
---|
764 | 945 | } |
---|
| 946 | + |
---|
765 | 947 | as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; |
---|
766 | 948 | as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; |
---|
767 | 949 | |
---|
768 | 950 | iad_desc.bInterfaceCount = 1; |
---|
769 | | - ac_hdr_desc.wTotalLength = sizeof ac_hdr_desc; |
---|
| 951 | + ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc)); |
---|
770 | 952 | |
---|
771 | 953 | if (EPIN_EN(opts)) { |
---|
772 | 954 | u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); |
---|
773 | 955 | |
---|
774 | 956 | len += sizeof(in_clk_src_desc); |
---|
775 | 957 | len += sizeof(usb_in_ot_desc); |
---|
776 | | - if (EPIN_FU(opts)) |
---|
777 | | - len += sizeof(usb_in_ot_fu_desc); |
---|
| 958 | + |
---|
| 959 | + if (FUIN_EN(opts)) |
---|
| 960 | + len += in_feature_unit_desc->bLength; |
---|
| 961 | + |
---|
778 | 962 | len += sizeof(io_in_it_desc); |
---|
779 | 963 | ac_hdr_desc.wTotalLength = cpu_to_le16(len); |
---|
780 | 964 | iad_desc.bInterfaceCount++; |
---|
.. | .. |
---|
784 | 968 | |
---|
785 | 969 | len += sizeof(out_clk_src_desc); |
---|
786 | 970 | len += sizeof(usb_out_it_desc); |
---|
787 | | - if (EPOUT_FU(opts)) |
---|
788 | | - len += sizeof(io_out_ot_fu_desc); |
---|
| 971 | + |
---|
| 972 | + if (FUOUT_EN(opts)) |
---|
| 973 | + len += out_feature_unit_desc->bLength; |
---|
| 974 | + |
---|
789 | 975 | len += sizeof(io_out_ot_desc); |
---|
790 | 976 | ac_hdr_desc.wTotalLength = cpu_to_le16(len); |
---|
791 | 977 | iad_desc.bInterfaceCount++; |
---|
.. | .. |
---|
796 | 982 | setup_headers(opts, ss_audio_desc, USB_SPEED_SUPER); |
---|
797 | 983 | } |
---|
798 | 984 | |
---|
| 985 | +static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) |
---|
| 986 | +{ |
---|
| 987 | + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); |
---|
| 988 | + const char *msg = NULL; |
---|
| 989 | + |
---|
| 990 | + if (!opts->p_chmask && !opts->c_chmask) |
---|
| 991 | + msg = "no playback and capture channels"; |
---|
| 992 | + else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) |
---|
| 993 | + msg = "unsupported playback channels mask"; |
---|
| 994 | + else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) |
---|
| 995 | + msg = "unsupported capture channels mask"; |
---|
| 996 | + else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) |
---|
| 997 | + msg = "incorrect playback sample size"; |
---|
| 998 | + else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) |
---|
| 999 | + msg = "incorrect capture sample size"; |
---|
| 1000 | + else if (!opts->p_srates[0]) |
---|
| 1001 | + msg = "incorrect playback sampling rate"; |
---|
| 1002 | + else if (!opts->c_srates[0]) |
---|
| 1003 | + msg = "incorrect capture sampling rate"; |
---|
| 1004 | + |
---|
| 1005 | + else if (opts->p_volume_max <= opts->p_volume_min) |
---|
| 1006 | + msg = "incorrect playback volume max/min"; |
---|
| 1007 | + else if (opts->c_volume_max <= opts->c_volume_min) |
---|
| 1008 | + msg = "incorrect capture volume max/min"; |
---|
| 1009 | + else if (opts->p_volume_res <= 0) |
---|
| 1010 | + msg = "negative/zero playback volume resolution"; |
---|
| 1011 | + else if (opts->c_volume_res <= 0) |
---|
| 1012 | + msg = "negative/zero capture volume resolution"; |
---|
| 1013 | + |
---|
| 1014 | + else if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) |
---|
| 1015 | + msg = "incorrect playback volume resolution"; |
---|
| 1016 | + else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) |
---|
| 1017 | + msg = "incorrect capture volume resolution"; |
---|
| 1018 | + |
---|
| 1019 | + else if ((opts->p_hs_bint < 0) || (opts->p_hs_bint > 4)) |
---|
| 1020 | + msg = "incorrect playback HS/SS bInterval (1-4: fixed, 0: auto)"; |
---|
| 1021 | + else if ((opts->c_hs_bint < 0) || (opts->c_hs_bint > 4)) |
---|
| 1022 | + msg = "incorrect capture HS/SS bInterval (1-4: fixed, 0: auto)"; |
---|
| 1023 | + |
---|
| 1024 | + if (msg) { |
---|
| 1025 | + dev_err(dev, "Error: %s\n", msg); |
---|
| 1026 | + return -EINVAL; |
---|
| 1027 | + } |
---|
| 1028 | + |
---|
| 1029 | + return 0; |
---|
| 1030 | +} |
---|
| 1031 | + |
---|
799 | 1032 | static int |
---|
800 | 1033 | afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) |
---|
801 | 1034 | { |
---|
802 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
| 1035 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
803 | 1036 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
804 | 1037 | struct usb_composite_dev *cdev = cfg->cdev; |
---|
805 | 1038 | struct usb_gadget *gadget = cdev->gadget; |
---|
806 | 1039 | struct device *dev = &gadget->dev; |
---|
807 | | - struct f_uac_opts *uac2_opts; |
---|
| 1040 | + struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev); |
---|
808 | 1041 | struct usb_string *us; |
---|
809 | 1042 | int ret; |
---|
810 | 1043 | |
---|
811 | | - uac2_opts = container_of(fn->fi, struct f_uac_opts, func_inst); |
---|
| 1044 | + ret = afunc_validate_opts(agdev, dev); |
---|
| 1045 | + if (ret) |
---|
| 1046 | + return ret; |
---|
| 1047 | + |
---|
| 1048 | + strings_fn[STR_ASSOC].s = uac2_opts->function_name; |
---|
812 | 1049 | |
---|
813 | 1050 | us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); |
---|
814 | 1051 | if (IS_ERR(us)) |
---|
815 | 1052 | return PTR_ERR(us); |
---|
| 1053 | + |
---|
| 1054 | + if (FUOUT_EN(uac2_opts)) { |
---|
| 1055 | + out_feature_unit_desc = build_fu_desc(uac2_opts->c_chmask); |
---|
| 1056 | + if (!out_feature_unit_desc) |
---|
| 1057 | + return -ENOMEM; |
---|
| 1058 | + } |
---|
| 1059 | + if (FUIN_EN(uac2_opts)) { |
---|
| 1060 | + in_feature_unit_desc = build_fu_desc(uac2_opts->p_chmask); |
---|
| 1061 | + if (!in_feature_unit_desc) { |
---|
| 1062 | + ret = -ENOMEM; |
---|
| 1063 | + goto err_free_fu; |
---|
| 1064 | + } |
---|
| 1065 | + } |
---|
| 1066 | + |
---|
816 | 1067 | iad_desc.iFunction = us[STR_ASSOC].id; |
---|
817 | 1068 | std_ac_if_desc.iInterface = us[STR_IF_CTRL].id; |
---|
818 | 1069 | in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id; |
---|
819 | 1070 | out_clk_src_desc.iClockSource = us[STR_CLKSRC_OUT].id; |
---|
820 | 1071 | usb_out_it_desc.iTerminal = us[STR_USB_IT].id; |
---|
821 | 1072 | io_in_it_desc.iTerminal = us[STR_IO_IT].id; |
---|
822 | | - usb_in_ot_fu_desc.iFeature = us[STR_USB_OT_FU].id; |
---|
823 | | - io_out_ot_fu_desc.iFeature = us[STR_IO_OT_FU].id; |
---|
824 | 1073 | usb_in_ot_desc.iTerminal = us[STR_USB_OT].id; |
---|
825 | 1074 | io_out_ot_desc.iTerminal = us[STR_IO_OT].id; |
---|
826 | 1075 | std_as_out_if0_desc.iInterface = us[STR_AS_OUT_ALT0].id; |
---|
827 | 1076 | std_as_out_if1_desc.iInterface = us[STR_AS_OUT_ALT1].id; |
---|
828 | 1077 | std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id; |
---|
829 | 1078 | std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id; |
---|
| 1079 | + |
---|
| 1080 | + if (FUOUT_EN(uac2_opts)) { |
---|
| 1081 | + u8 *i_feature = (u8 *)out_feature_unit_desc + |
---|
| 1082 | + out_feature_unit_desc->bLength - 1; |
---|
| 1083 | + *i_feature = us[STR_FU_OUT].id; |
---|
| 1084 | + } |
---|
| 1085 | + if (FUIN_EN(uac2_opts)) { |
---|
| 1086 | + u8 *i_feature = (u8 *)in_feature_unit_desc + |
---|
| 1087 | + in_feature_unit_desc->bLength - 1; |
---|
| 1088 | + *i_feature = us[STR_FU_IN].id; |
---|
| 1089 | + } |
---|
830 | 1090 | |
---|
831 | 1091 | |
---|
832 | 1092 | /* Initialize the configurable parameters */ |
---|
.. | .. |
---|
842 | 1102 | as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8; |
---|
843 | 1103 | as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize; |
---|
844 | 1104 | as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8; |
---|
| 1105 | + if (FUOUT_EN(uac2_opts)) { |
---|
| 1106 | + __le32 *bma = (__le32 *)&out_feature_unit_desc->bmaControls[0]; |
---|
| 1107 | + u32 control = 0; |
---|
| 1108 | + |
---|
| 1109 | + if (uac2_opts->c_mute_present) |
---|
| 1110 | + control |= CONTROL_RDWR << FU_MUTE_CTRL; |
---|
| 1111 | + if (uac2_opts->c_volume_present) |
---|
| 1112 | + control |= CONTROL_RDWR << FU_VOL_CTRL; |
---|
| 1113 | + *bma = cpu_to_le32(control); |
---|
| 1114 | + } |
---|
| 1115 | + if (FUIN_EN(uac2_opts)) { |
---|
| 1116 | + __le32 *bma = (__le32 *)&in_feature_unit_desc->bmaControls[0]; |
---|
| 1117 | + u32 control = 0; |
---|
| 1118 | + |
---|
| 1119 | + if (uac2_opts->p_mute_present) |
---|
| 1120 | + control |= CONTROL_RDWR << FU_MUTE_CTRL; |
---|
| 1121 | + if (uac2_opts->p_volume_present) |
---|
| 1122 | + control |= CONTROL_RDWR << FU_VOL_CTRL; |
---|
| 1123 | + *bma = cpu_to_le32(control); |
---|
| 1124 | + } |
---|
845 | 1125 | |
---|
846 | 1126 | ret = usb_interface_id(cfg, fn); |
---|
847 | 1127 | if (ret < 0) { |
---|
848 | 1128 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
849 | | - return ret; |
---|
| 1129 | + goto err_free_fu; |
---|
850 | 1130 | } |
---|
851 | 1131 | iad_desc.bFirstInterface = ret; |
---|
852 | 1132 | |
---|
.. | .. |
---|
858 | 1138 | ret = usb_interface_id(cfg, fn); |
---|
859 | 1139 | if (ret < 0) { |
---|
860 | 1140 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
861 | | - return ret; |
---|
| 1141 | + goto err_free_fu; |
---|
862 | 1142 | } |
---|
863 | 1143 | std_as_out_if0_desc.bInterfaceNumber = ret; |
---|
864 | 1144 | std_as_out_if1_desc.bInterfaceNumber = ret; |
---|
| 1145 | + std_as_out_if1_desc.bNumEndpoints = 1; |
---|
865 | 1146 | uac2->as_out_intf = ret; |
---|
866 | 1147 | uac2->as_out_alt = 0; |
---|
| 1148 | + |
---|
| 1149 | + if (EPOUT_FBACK_IN_EN(uac2_opts)) { |
---|
| 1150 | + fs_epout_desc.bmAttributes = |
---|
| 1151 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; |
---|
| 1152 | + hs_epout_desc.bmAttributes = |
---|
| 1153 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; |
---|
| 1154 | + ss_epout_desc.bmAttributes = |
---|
| 1155 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC; |
---|
| 1156 | + std_as_out_if1_desc.bNumEndpoints++; |
---|
| 1157 | + } else { |
---|
| 1158 | + fs_epout_desc.bmAttributes = |
---|
| 1159 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; |
---|
| 1160 | + hs_epout_desc.bmAttributes = |
---|
| 1161 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; |
---|
| 1162 | + ss_epout_desc.bmAttributes = |
---|
| 1163 | + USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ADAPTIVE; |
---|
| 1164 | + } |
---|
867 | 1165 | } |
---|
868 | 1166 | |
---|
869 | 1167 | if (EPIN_EN(uac2_opts)) { |
---|
870 | 1168 | ret = usb_interface_id(cfg, fn); |
---|
871 | 1169 | if (ret < 0) { |
---|
872 | 1170 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
873 | | - return ret; |
---|
| 1171 | + goto err_free_fu; |
---|
874 | 1172 | } |
---|
875 | 1173 | std_as_in_if0_desc.bInterfaceNumber = ret; |
---|
876 | 1174 | std_as_in_if1_desc.bInterfaceNumber = ret; |
---|
.. | .. |
---|
878 | 1176 | uac2->as_in_alt = 0; |
---|
879 | 1177 | } |
---|
880 | 1178 | |
---|
| 1179 | + if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) { |
---|
| 1180 | + uac2->int_ep = usb_ep_autoconfig(gadget, &fs_ep_int_desc); |
---|
| 1181 | + if (!uac2->int_ep) { |
---|
| 1182 | + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
| 1183 | + ret = -ENODEV; |
---|
| 1184 | + goto err_free_fu; |
---|
| 1185 | + } |
---|
| 1186 | + |
---|
| 1187 | + std_ac_if_desc.bNumEndpoints = 1; |
---|
| 1188 | + } |
---|
| 1189 | + |
---|
| 1190 | + hs_epin_desc.bInterval = uac2_opts->p_hs_bint; |
---|
| 1191 | + ss_epin_desc.bInterval = uac2_opts->p_hs_bint; |
---|
| 1192 | + hs_epout_desc.bInterval = uac2_opts->c_hs_bint; |
---|
| 1193 | + ss_epout_desc.bInterval = uac2_opts->c_hs_bint; |
---|
| 1194 | + |
---|
881 | 1195 | /* Calculate wMaxPacketSize according to audio bandwidth */ |
---|
882 | | - ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL, |
---|
883 | | - true); |
---|
| 1196 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epin_desc, |
---|
| 1197 | + USB_SPEED_FULL, true); |
---|
884 | 1198 | if (ret < 0) { |
---|
885 | 1199 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
886 | 1200 | return ret; |
---|
887 | 1201 | } |
---|
888 | 1202 | |
---|
889 | | - ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL, |
---|
890 | | - false); |
---|
| 1203 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &fs_epout_desc, |
---|
| 1204 | + USB_SPEED_FULL, false); |
---|
891 | 1205 | if (ret < 0) { |
---|
892 | 1206 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
893 | 1207 | return ret; |
---|
894 | 1208 | } |
---|
895 | 1209 | |
---|
896 | | - ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH, |
---|
897 | | - true); |
---|
| 1210 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epin_desc, |
---|
| 1211 | + USB_SPEED_HIGH, true); |
---|
898 | 1212 | if (ret < 0) { |
---|
899 | 1213 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
900 | 1214 | return ret; |
---|
901 | 1215 | } |
---|
902 | 1216 | |
---|
903 | | - ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH, |
---|
904 | | - false); |
---|
| 1217 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &hs_epout_desc, |
---|
| 1218 | + USB_SPEED_HIGH, false); |
---|
905 | 1219 | if (ret < 0) { |
---|
906 | 1220 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
907 | 1221 | return ret; |
---|
908 | 1222 | } |
---|
909 | 1223 | |
---|
910 | | - ret = set_ep_max_packet_size(uac2_opts, &ss_epin_desc, USB_SPEED_SUPER, |
---|
911 | | - true); |
---|
| 1224 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epin_desc, |
---|
| 1225 | + USB_SPEED_SUPER, true); |
---|
912 | 1226 | if (ret < 0) { |
---|
913 | 1227 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
914 | 1228 | return ret; |
---|
915 | 1229 | } |
---|
916 | 1230 | |
---|
917 | | - ss_epin_desc_comp.wBytesPerInterval = ss_epin_desc.wMaxPacketSize; |
---|
918 | | - |
---|
919 | | - ret = set_ep_max_packet_size(uac2_opts, &ss_epout_desc, USB_SPEED_SUPER, |
---|
920 | | - false); |
---|
| 1231 | + ret = set_ep_max_packet_size_bint(dev, uac2_opts, &ss_epout_desc, |
---|
| 1232 | + USB_SPEED_SUPER, false); |
---|
921 | 1233 | if (ret < 0) { |
---|
922 | 1234 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
923 | 1235 | return ret; |
---|
924 | 1236 | } |
---|
925 | | - |
---|
926 | | - ss_epout_desc_comp.wBytesPerInterval = ss_epout_desc.wMaxPacketSize; |
---|
927 | 1237 | |
---|
928 | 1238 | if (EPOUT_EN(uac2_opts)) { |
---|
929 | 1239 | agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); |
---|
930 | 1240 | if (!agdev->out_ep) { |
---|
931 | 1241 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
932 | | - return -ENODEV; |
---|
| 1242 | + ret = -ENODEV; |
---|
| 1243 | + goto err_free_fu; |
---|
| 1244 | + } |
---|
| 1245 | + if (EPOUT_FBACK_IN_EN(uac2_opts)) { |
---|
| 1246 | + agdev->in_ep_fback = usb_ep_autoconfig(gadget, |
---|
| 1247 | + &fs_epin_fback_desc); |
---|
| 1248 | + if (!agdev->in_ep_fback) { |
---|
| 1249 | + dev_err(dev, "%s:%d Error!\n", |
---|
| 1250 | + __func__, __LINE__); |
---|
| 1251 | + ret = -ENODEV; |
---|
| 1252 | + goto err_free_fu; |
---|
| 1253 | + } |
---|
933 | 1254 | } |
---|
934 | 1255 | } |
---|
935 | 1256 | |
---|
.. | .. |
---|
937 | 1258 | agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); |
---|
938 | 1259 | if (!agdev->in_ep) { |
---|
939 | 1260 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
940 | | - return -ENODEV; |
---|
| 1261 | + ret = -ENODEV; |
---|
| 1262 | + goto err_free_fu; |
---|
941 | 1263 | } |
---|
942 | | - agdev->in_ep->maxpacket = usb_endpoint_maxp(&fs_epin_desc); |
---|
943 | 1264 | } |
---|
944 | 1265 | |
---|
945 | 1266 | agdev->in_ep_maxpsize = max_t(u16, |
---|
.. | .. |
---|
954 | 1275 | agdev->out_ep_maxpsize = max_t(u16, agdev->out_ep_maxpsize, |
---|
955 | 1276 | le16_to_cpu(ss_epout_desc.wMaxPacketSize)); |
---|
956 | 1277 | |
---|
| 1278 | + ss_epin_desc_comp.wBytesPerInterval = ss_epin_desc.wMaxPacketSize; |
---|
| 1279 | + ss_epout_desc_comp.wBytesPerInterval = ss_epout_desc.wMaxPacketSize; |
---|
| 1280 | + |
---|
| 1281 | + // HS and SS endpoint addresses are copied from autoconfigured FS descriptors |
---|
| 1282 | + hs_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; |
---|
957 | 1283 | hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; |
---|
| 1284 | + hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; |
---|
958 | 1285 | hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; |
---|
959 | 1286 | ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; |
---|
| 1287 | + ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; |
---|
960 | 1288 | ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; |
---|
| 1289 | + ss_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; |
---|
961 | 1290 | |
---|
962 | 1291 | setup_descriptor(uac2_opts); |
---|
963 | 1292 | |
---|
964 | 1293 | ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc, |
---|
965 | 1294 | ss_audio_desc); |
---|
966 | 1295 | if (ret) |
---|
967 | | - return ret; |
---|
| 1296 | + goto err_free_fu; |
---|
968 | 1297 | |
---|
969 | 1298 | agdev->gadget = gadget; |
---|
970 | 1299 | |
---|
971 | 1300 | agdev->params.p_chmask = uac2_opts->p_chmask; |
---|
972 | | - memcpy(agdev->params.p_srate, uac2_opts->p_srate, |
---|
973 | | - sizeof(agdev->params.p_srate)); |
---|
974 | | - agdev->params.p_srate_active = uac2_opts->p_srate_active; |
---|
| 1301 | + memcpy(agdev->params.p_srates, uac2_opts->p_srates, |
---|
| 1302 | + sizeof(agdev->params.p_srates)); |
---|
975 | 1303 | agdev->params.p_ssize = uac2_opts->p_ssize; |
---|
| 1304 | + if (FUIN_EN(uac2_opts)) { |
---|
| 1305 | + agdev->params.p_fu.id = USB_IN_FU_ID; |
---|
| 1306 | + agdev->params.p_fu.mute_present = uac2_opts->p_mute_present; |
---|
| 1307 | + agdev->params.p_fu.volume_present = uac2_opts->p_volume_present; |
---|
| 1308 | + agdev->params.p_fu.volume_min = uac2_opts->p_volume_min; |
---|
| 1309 | + agdev->params.p_fu.volume_max = uac2_opts->p_volume_max; |
---|
| 1310 | + agdev->params.p_fu.volume_res = uac2_opts->p_volume_res; |
---|
| 1311 | + } |
---|
976 | 1312 | agdev->params.c_chmask = uac2_opts->c_chmask; |
---|
977 | | - memcpy(agdev->params.c_srate, uac2_opts->c_srate, |
---|
978 | | - sizeof(agdev->params.c_srate)); |
---|
979 | | - agdev->params.c_srate_active = uac2_opts->c_srate_active; |
---|
| 1313 | + memcpy(agdev->params.c_srates, uac2_opts->c_srates, |
---|
| 1314 | + sizeof(agdev->params.c_srates)); |
---|
980 | 1315 | agdev->params.c_ssize = uac2_opts->c_ssize; |
---|
| 1316 | + if (FUOUT_EN(uac2_opts)) { |
---|
| 1317 | + agdev->params.c_fu.id = USB_OUT_FU_ID; |
---|
| 1318 | + agdev->params.c_fu.mute_present = uac2_opts->c_mute_present; |
---|
| 1319 | + agdev->params.c_fu.volume_present = uac2_opts->c_volume_present; |
---|
| 1320 | + agdev->params.c_fu.volume_min = uac2_opts->c_volume_min; |
---|
| 1321 | + agdev->params.c_fu.volume_max = uac2_opts->c_volume_max; |
---|
| 1322 | + agdev->params.c_fu.volume_res = uac2_opts->c_volume_res; |
---|
| 1323 | + } |
---|
981 | 1324 | agdev->params.req_number = uac2_opts->req_number; |
---|
| 1325 | + agdev->params.fb_max = uac2_opts->fb_max; |
---|
| 1326 | + |
---|
| 1327 | + if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) |
---|
| 1328 | + agdev->notify = afunc_notify; |
---|
| 1329 | + |
---|
982 | 1330 | ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget"); |
---|
983 | 1331 | if (ret) |
---|
984 | 1332 | goto err_free_descs; |
---|
| 1333 | + |
---|
985 | 1334 | return 0; |
---|
986 | 1335 | |
---|
987 | 1336 | err_free_descs: |
---|
988 | 1337 | usb_free_all_descriptors(fn); |
---|
989 | 1338 | agdev->gadget = NULL; |
---|
| 1339 | +err_free_fu: |
---|
| 1340 | + kfree(out_feature_unit_desc); |
---|
| 1341 | + out_feature_unit_desc = NULL; |
---|
| 1342 | + kfree(in_feature_unit_desc); |
---|
| 1343 | + in_feature_unit_desc = NULL; |
---|
| 1344 | + return ret; |
---|
| 1345 | +} |
---|
| 1346 | + |
---|
| 1347 | +static void |
---|
| 1348 | +afunc_notify_complete(struct usb_ep *_ep, struct usb_request *req) |
---|
| 1349 | +{ |
---|
| 1350 | + struct g_audio *agdev = req->context; |
---|
| 1351 | + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); |
---|
| 1352 | + |
---|
| 1353 | + atomic_dec(&uac2->int_count); |
---|
| 1354 | + kfree(req->buf); |
---|
| 1355 | + usb_ep_free_request(_ep, req); |
---|
| 1356 | +} |
---|
| 1357 | + |
---|
| 1358 | +static int |
---|
| 1359 | +afunc_notify(struct g_audio *agdev, int unit_id, int cs) |
---|
| 1360 | +{ |
---|
| 1361 | + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); |
---|
| 1362 | + struct usb_request *req; |
---|
| 1363 | + struct uac2_interrupt_data_msg *msg; |
---|
| 1364 | + u16 w_index, w_value; |
---|
| 1365 | + int ret; |
---|
| 1366 | + |
---|
| 1367 | + if (!uac2->int_ep->enabled) |
---|
| 1368 | + return 0; |
---|
| 1369 | + |
---|
| 1370 | + if (atomic_inc_return(&uac2->int_count) > UAC2_DEF_INT_REQ_NUM) { |
---|
| 1371 | + atomic_dec(&uac2->int_count); |
---|
| 1372 | + return 0; |
---|
| 1373 | + } |
---|
| 1374 | + |
---|
| 1375 | + req = usb_ep_alloc_request(uac2->int_ep, GFP_ATOMIC); |
---|
| 1376 | + if (req == NULL) { |
---|
| 1377 | + ret = -ENOMEM; |
---|
| 1378 | + goto err_dec_int_count; |
---|
| 1379 | + } |
---|
| 1380 | + |
---|
| 1381 | + msg = kzalloc(sizeof(*msg), GFP_ATOMIC); |
---|
| 1382 | + if (msg == NULL) { |
---|
| 1383 | + ret = -ENOMEM; |
---|
| 1384 | + goto err_free_request; |
---|
| 1385 | + } |
---|
| 1386 | + |
---|
| 1387 | + w_index = unit_id << 8 | uac2->ac_intf; |
---|
| 1388 | + w_value = cs << 8; |
---|
| 1389 | + |
---|
| 1390 | + msg->bInfo = 0; /* Non-vendor, interface interrupt */ |
---|
| 1391 | + msg->bAttribute = UAC2_CS_CUR; |
---|
| 1392 | + msg->wIndex = cpu_to_le16(w_index); |
---|
| 1393 | + msg->wValue = cpu_to_le16(w_value); |
---|
| 1394 | + |
---|
| 1395 | + req->length = sizeof(*msg); |
---|
| 1396 | + req->buf = msg; |
---|
| 1397 | + req->context = agdev; |
---|
| 1398 | + req->complete = afunc_notify_complete; |
---|
| 1399 | + |
---|
| 1400 | + ret = usb_ep_queue(uac2->int_ep, req, GFP_ATOMIC); |
---|
| 1401 | + |
---|
| 1402 | + if (ret) |
---|
| 1403 | + goto err_free_msg; |
---|
| 1404 | + |
---|
| 1405 | + return 0; |
---|
| 1406 | + |
---|
| 1407 | +err_free_msg: |
---|
| 1408 | + kfree(msg); |
---|
| 1409 | +err_free_request: |
---|
| 1410 | + usb_ep_free_request(uac2->int_ep, req); |
---|
| 1411 | +err_dec_int_count: |
---|
| 1412 | + atomic_dec(&uac2->int_count); |
---|
| 1413 | + |
---|
990 | 1414 | return ret; |
---|
991 | 1415 | } |
---|
992 | 1416 | |
---|
.. | .. |
---|
994 | 1418 | afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) |
---|
995 | 1419 | { |
---|
996 | 1420 | struct usb_composite_dev *cdev = fn->config->cdev; |
---|
997 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
| 1421 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
| 1422 | + struct g_audio *agdev = func_to_g_audio(fn); |
---|
998 | 1423 | struct usb_gadget *gadget = cdev->gadget; |
---|
999 | 1424 | struct device *dev = &gadget->dev; |
---|
1000 | 1425 | int ret = 0; |
---|
.. | .. |
---|
1011 | 1436 | dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); |
---|
1012 | 1437 | return -EINVAL; |
---|
1013 | 1438 | } |
---|
| 1439 | + |
---|
| 1440 | + /* restart interrupt endpoint */ |
---|
| 1441 | + if (uac2->int_ep) { |
---|
| 1442 | + usb_ep_disable(uac2->int_ep); |
---|
| 1443 | + config_ep_by_speed(gadget, &agdev->func, uac2->int_ep); |
---|
| 1444 | + usb_ep_enable(uac2->int_ep); |
---|
| 1445 | + } |
---|
| 1446 | + |
---|
1014 | 1447 | return 0; |
---|
1015 | 1448 | } |
---|
1016 | 1449 | |
---|
.. | .. |
---|
1039 | 1472 | static int |
---|
1040 | 1473 | afunc_get_alt(struct usb_function *fn, unsigned intf) |
---|
1041 | 1474 | { |
---|
1042 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
| 1475 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
1043 | 1476 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
1044 | 1477 | |
---|
1045 | 1478 | if (intf == uac2->ac_intf) |
---|
.. | .. |
---|
1059 | 1492 | static void |
---|
1060 | 1493 | afunc_disable(struct usb_function *fn) |
---|
1061 | 1494 | { |
---|
1062 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
| 1495 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
1063 | 1496 | |
---|
1064 | 1497 | uac2->as_in_alt = 0; |
---|
1065 | 1498 | uac2->as_out_alt = 0; |
---|
1066 | 1499 | u_audio_stop_capture(&uac2->g_audio); |
---|
1067 | 1500 | u_audio_stop_playback(&uac2->g_audio); |
---|
| 1501 | + if (uac2->int_ep) |
---|
| 1502 | + usb_ep_disable(uac2->int_ep); |
---|
| 1503 | +} |
---|
| 1504 | + |
---|
| 1505 | +static void |
---|
| 1506 | +afunc_suspend(struct usb_function *fn) |
---|
| 1507 | +{ |
---|
| 1508 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
| 1509 | + |
---|
| 1510 | + u_audio_suspend(&uac2->g_audio); |
---|
1068 | 1511 | } |
---|
1069 | 1512 | |
---|
1070 | 1513 | static int |
---|
1071 | | -in_rq_cs_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
| 1514 | +in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1072 | 1515 | { |
---|
1073 | 1516 | struct usb_request *req = fn->config->cdev->req; |
---|
1074 | 1517 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
1075 | | - struct f_uac_opts *opts; |
---|
| 1518 | + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); |
---|
1076 | 1519 | u16 w_length = le16_to_cpu(cr->wLength); |
---|
1077 | 1520 | u16 w_index = le16_to_cpu(cr->wIndex); |
---|
1078 | 1521 | u16 w_value = le16_to_cpu(cr->wValue); |
---|
1079 | 1522 | u8 entity_id = (w_index >> 8) & 0xff; |
---|
1080 | 1523 | u8 control_selector = w_value >> 8; |
---|
1081 | 1524 | int value = -EOPNOTSUPP; |
---|
1082 | | - int p_srate, c_srate; |
---|
| 1525 | + u32 p_srate, c_srate; |
---|
1083 | 1526 | |
---|
1084 | | - opts = g_audio_to_uac_opts(agdev); |
---|
1085 | | - p_srate = opts->p_srate_active; |
---|
1086 | | - c_srate = opts->c_srate_active; |
---|
| 1527 | + u_audio_get_playback_srate(agdev, &p_srate); |
---|
| 1528 | + u_audio_get_capture_srate(agdev, &c_srate); |
---|
1087 | 1529 | |
---|
1088 | | - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
1089 | | - struct cntrl_cur_lay3 c; |
---|
1090 | | - memset(&c, 0, sizeof(struct cntrl_cur_lay3)); |
---|
| 1530 | + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { |
---|
| 1531 | + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
| 1532 | + struct cntrl_cur_lay3 c; |
---|
1091 | 1533 | |
---|
1092 | | - if (entity_id == USB_IN_CLK_ID) |
---|
1093 | | - c.dCUR = cpu_to_le32(p_srate); |
---|
1094 | | - else if (entity_id == USB_OUT_CLK_ID) |
---|
1095 | | - c.dCUR = cpu_to_le32(c_srate); |
---|
| 1534 | + memset(&c, 0, sizeof(struct cntrl_cur_lay3)); |
---|
1096 | 1535 | |
---|
1097 | | - DBG(fn->config->cdev, "%s(): %d\n", __func__, c.dCUR); |
---|
1098 | | - value = min_t(unsigned, w_length, sizeof c); |
---|
1099 | | - memcpy(req->buf, &c, value); |
---|
1100 | | - } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { |
---|
1101 | | - *(u8 *)req->buf = 1; |
---|
1102 | | - value = min_t(unsigned, w_length, 1); |
---|
| 1536 | + if (entity_id == USB_IN_CLK_ID) |
---|
| 1537 | + c.dCUR = cpu_to_le32(p_srate); |
---|
| 1538 | + else if (entity_id == USB_OUT_CLK_ID) |
---|
| 1539 | + c.dCUR = cpu_to_le32(c_srate); |
---|
| 1540 | + |
---|
| 1541 | + value = min_t(unsigned int, w_length, sizeof(c)); |
---|
| 1542 | + memcpy(req->buf, &c, value); |
---|
| 1543 | + } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { |
---|
| 1544 | + *(u8 *)req->buf = 1; |
---|
| 1545 | + value = min_t(unsigned int, w_length, 1); |
---|
| 1546 | + } else { |
---|
| 1547 | + dev_err(&agdev->gadget->dev, |
---|
| 1548 | + "%s:%d control_selector=%d TODO!\n", |
---|
| 1549 | + __func__, __LINE__, control_selector); |
---|
| 1550 | + } |
---|
| 1551 | + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || |
---|
| 1552 | + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { |
---|
| 1553 | + unsigned int is_playback = 0; |
---|
| 1554 | + |
---|
| 1555 | + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) |
---|
| 1556 | + is_playback = 1; |
---|
| 1557 | + |
---|
| 1558 | + if (control_selector == UAC_FU_MUTE) { |
---|
| 1559 | + unsigned int mute; |
---|
| 1560 | + |
---|
| 1561 | + u_audio_get_mute(agdev, is_playback, &mute); |
---|
| 1562 | + |
---|
| 1563 | + *(u8 *)req->buf = mute; |
---|
| 1564 | + value = min_t(unsigned int, w_length, 1); |
---|
| 1565 | + } else if (control_selector == UAC_FU_VOLUME) { |
---|
| 1566 | + struct cntrl_cur_lay2 c; |
---|
| 1567 | + s16 volume; |
---|
| 1568 | + |
---|
| 1569 | + memset(&c, 0, sizeof(struct cntrl_cur_lay2)); |
---|
| 1570 | + |
---|
| 1571 | + u_audio_get_volume(agdev, is_playback, &volume); |
---|
| 1572 | + c.wCUR = cpu_to_le16(volume); |
---|
| 1573 | + |
---|
| 1574 | + value = min_t(unsigned int, w_length, sizeof(c)); |
---|
| 1575 | + memcpy(req->buf, &c, value); |
---|
| 1576 | + } else { |
---|
| 1577 | + dev_err(&agdev->gadget->dev, |
---|
| 1578 | + "%s:%d control_selector=%d TODO!\n", |
---|
| 1579 | + __func__, __LINE__, control_selector); |
---|
| 1580 | + } |
---|
1103 | 1581 | } else { |
---|
1104 | 1582 | dev_err(&agdev->gadget->dev, |
---|
1105 | | - "%s:%d control_selector=%d TODO!\n", |
---|
1106 | | - __func__, __LINE__, control_selector); |
---|
| 1583 | + "%s:%d entity_id=%d control_selector=%d TODO!\n", |
---|
| 1584 | + __func__, __LINE__, entity_id, control_selector); |
---|
1107 | 1585 | } |
---|
1108 | 1586 | |
---|
1109 | 1587 | return value; |
---|
1110 | 1588 | } |
---|
1111 | 1589 | |
---|
1112 | 1590 | static int |
---|
1113 | | -in_rq_cs_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
| 1591 | +in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1114 | 1592 | { |
---|
1115 | 1593 | struct usb_request *req = fn->config->cdev->req; |
---|
1116 | 1594 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
1117 | | - struct f_uac_opts *opts; |
---|
| 1595 | + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); |
---|
1118 | 1596 | u16 w_length = le16_to_cpu(cr->wLength); |
---|
1119 | 1597 | u16 w_index = le16_to_cpu(cr->wIndex); |
---|
1120 | 1598 | u16 w_value = le16_to_cpu(cr->wValue); |
---|
1121 | 1599 | u8 entity_id = (w_index >> 8) & 0xff; |
---|
1122 | 1600 | u8 control_selector = w_value >> 8; |
---|
1123 | | - struct cntrl_ranges_lay3 rs; |
---|
1124 | 1601 | int value = -EOPNOTSUPP; |
---|
1125 | | - int srate = 0; |
---|
1126 | | - int i; |
---|
1127 | 1602 | |
---|
1128 | | - opts = g_audio_to_uac_opts(agdev); |
---|
| 1603 | + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { |
---|
| 1604 | + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
| 1605 | + struct cntrl_ranges_lay3_srates rs; |
---|
| 1606 | + int i; |
---|
| 1607 | + int wNumSubRanges = 0; |
---|
| 1608 | + int srate; |
---|
| 1609 | + int *srates; |
---|
1129 | 1610 | |
---|
1130 | | - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
1131 | | - rs.wNumSubRanges = 0; |
---|
1132 | | - for (i = 0; i < UAC_MAX_RATES; i++) { |
---|
1133 | 1611 | if (entity_id == USB_IN_CLK_ID) |
---|
1134 | | - srate = opts->p_srate[i]; |
---|
| 1612 | + srates = opts->p_srates; |
---|
1135 | 1613 | else if (entity_id == USB_OUT_CLK_ID) |
---|
1136 | | - srate = opts->c_srate[i]; |
---|
| 1614 | + srates = opts->c_srates; |
---|
1137 | 1615 | else |
---|
1138 | 1616 | return -EOPNOTSUPP; |
---|
| 1617 | + for (i = 0; i < UAC_MAX_RATES; i++) { |
---|
| 1618 | + srate = srates[i]; |
---|
| 1619 | + if (srate == 0) |
---|
| 1620 | + break; |
---|
1139 | 1621 | |
---|
1140 | | - if (srate == 0) |
---|
1141 | | - break; |
---|
1142 | | - |
---|
1143 | | - rs.r[rs.wNumSubRanges].dMIN = srate; |
---|
1144 | | - rs.r[rs.wNumSubRanges].dMAX = srate; |
---|
1145 | | - rs.r[rs.wNumSubRanges].dRES = 0; |
---|
1146 | | - rs.wNumSubRanges++; |
---|
1147 | | - DBG(fn->config->cdev, |
---|
1148 | | - "%s(): clk %d: report rate %d. %d\n", |
---|
1149 | | - __func__, entity_id, rs.wNumSubRanges, |
---|
1150 | | - srate); |
---|
1151 | | - } |
---|
1152 | | - |
---|
1153 | | - value = min_t(unsigned int, w_length, ranges_size(rs)); |
---|
1154 | | - DBG(fn->config->cdev, "%s(): send %d rates, size %d\n", |
---|
| 1622 | + rs.r[wNumSubRanges].dMIN = cpu_to_le32(srate); |
---|
| 1623 | + rs.r[wNumSubRanges].dMAX = cpu_to_le32(srate); |
---|
| 1624 | + rs.r[wNumSubRanges].dRES = 0; |
---|
| 1625 | + wNumSubRanges++; |
---|
| 1626 | + dev_dbg(&agdev->gadget->dev, |
---|
| 1627 | + "%s(): clk %d: rate ID %d: %d\n", |
---|
| 1628 | + __func__, entity_id, wNumSubRanges, srate); |
---|
| 1629 | + } |
---|
| 1630 | + rs.wNumSubRanges = cpu_to_le16(wNumSubRanges); |
---|
| 1631 | + value = min_t(unsigned int, w_length, ranges_lay3_size(rs)); |
---|
| 1632 | + dev_dbg(&agdev->gadget->dev, "%s(): sending %d rates, size %d\n", |
---|
1155 | 1633 | __func__, rs.wNumSubRanges, value); |
---|
1156 | | - memcpy(req->buf, &rs, value); |
---|
| 1634 | + memcpy(req->buf, &rs, value); |
---|
| 1635 | + } else { |
---|
| 1636 | + dev_err(&agdev->gadget->dev, |
---|
| 1637 | + "%s:%d control_selector=%d TODO!\n", |
---|
| 1638 | + __func__, __LINE__, control_selector); |
---|
| 1639 | + } |
---|
| 1640 | + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || |
---|
| 1641 | + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { |
---|
| 1642 | + unsigned int is_playback = 0; |
---|
| 1643 | + |
---|
| 1644 | + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) |
---|
| 1645 | + is_playback = 1; |
---|
| 1646 | + |
---|
| 1647 | + if (control_selector == UAC_FU_VOLUME) { |
---|
| 1648 | + struct cntrl_range_lay2 r; |
---|
| 1649 | + s16 max_db, min_db, res_db; |
---|
| 1650 | + |
---|
| 1651 | + if (is_playback) { |
---|
| 1652 | + max_db = opts->p_volume_max; |
---|
| 1653 | + min_db = opts->p_volume_min; |
---|
| 1654 | + res_db = opts->p_volume_res; |
---|
| 1655 | + } else { |
---|
| 1656 | + max_db = opts->c_volume_max; |
---|
| 1657 | + min_db = opts->c_volume_min; |
---|
| 1658 | + res_db = opts->c_volume_res; |
---|
| 1659 | + } |
---|
| 1660 | + |
---|
| 1661 | + r.wMAX = cpu_to_le16(max_db); |
---|
| 1662 | + r.wMIN = cpu_to_le16(min_db); |
---|
| 1663 | + r.wRES = cpu_to_le16(res_db); |
---|
| 1664 | + r.wNumSubRanges = cpu_to_le16(1); |
---|
| 1665 | + |
---|
| 1666 | + value = min_t(unsigned int, w_length, sizeof(r)); |
---|
| 1667 | + memcpy(req->buf, &r, value); |
---|
| 1668 | + } else { |
---|
| 1669 | + dev_err(&agdev->gadget->dev, |
---|
| 1670 | + "%s:%d control_selector=%d TODO!\n", |
---|
| 1671 | + __func__, __LINE__, control_selector); |
---|
| 1672 | + } |
---|
1157 | 1673 | } else { |
---|
1158 | 1674 | dev_err(&agdev->gadget->dev, |
---|
1159 | | - "%s:%d control_selector=%d TODO!\n", |
---|
1160 | | - __func__, __LINE__, control_selector); |
---|
| 1675 | + "%s:%d entity_id=%d control_selector=%d TODO!\n", |
---|
| 1676 | + __func__, __LINE__, entity_id, control_selector); |
---|
1161 | 1677 | } |
---|
1162 | 1678 | |
---|
1163 | 1679 | return value; |
---|
1164 | | -} |
---|
1165 | | - |
---|
1166 | | -static int |
---|
1167 | | -in_rq_fu(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1168 | | -{ |
---|
1169 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
1170 | | - struct usb_request *req = fn->config->cdev->req; |
---|
1171 | | - u16 w_length = le16_to_cpu(cr->wLength); |
---|
1172 | | - struct usb_audio_control *con = uac2->get_con; |
---|
1173 | | - u8 cmd = uac2->get_cmd; |
---|
1174 | | - char c1; |
---|
1175 | | - struct cntrl_cur_lay2 c2; |
---|
1176 | | - struct cntrl_range_lay2 r; |
---|
1177 | | - int value = -EOPNOTSUPP; |
---|
1178 | | - |
---|
1179 | | - if (cmd == UAC2_CS_CUR && con->type == UAC_FU_MUTE) { |
---|
1180 | | - c1 = con->get(con, UAC__CUR); |
---|
1181 | | - value = min_t(unsigned int, w_length, 1); |
---|
1182 | | - memcpy(req->buf, &c1, value); |
---|
1183 | | - } else if (cmd == UAC2_CS_CUR && con->type == UAC_FU_VOLUME) { |
---|
1184 | | - c2.dCUR = cpu_to_le16(con->get(con, UAC__CUR)); |
---|
1185 | | - value = min_t(unsigned int, w_length, sizeof(c2)); |
---|
1186 | | - memcpy(req->buf, &c2, value); |
---|
1187 | | - } else if (cmd == UAC2_CS_RANGE) { |
---|
1188 | | - r.wNumSubRanges = cpu_to_le16(1); |
---|
1189 | | - r.dMIN = cpu_to_le16(con->get(con, UAC__MIN)); |
---|
1190 | | - r.dMAX = cpu_to_le16(con->get(con, UAC__MAX)); |
---|
1191 | | - r.dRES = cpu_to_le16(con->get(con, UAC__RES)); |
---|
1192 | | - value = min_t(unsigned int, w_length, sizeof(r)); |
---|
1193 | | - memcpy(req->buf, &r, value); |
---|
1194 | | - } |
---|
1195 | | - |
---|
1196 | | - DBG(fn->config->cdev, "%s(): send size %d\n", __func__, value); |
---|
1197 | | - |
---|
1198 | | - return value; |
---|
1199 | | -} |
---|
1200 | | - |
---|
1201 | | -static void uac2_fu_control_complt(struct usb_ep *ep, struct usb_request *req) |
---|
1202 | | -{ |
---|
1203 | | - struct f_uac *uac2 = req->context; |
---|
1204 | | - struct usb_audio_control *con = uac2->set_con; |
---|
1205 | | - u8 cmd = uac2->set_cmd; |
---|
1206 | | - int status = req->status; |
---|
1207 | | - char c1; |
---|
1208 | | - struct cntrl_cur_lay2 c2; |
---|
1209 | | - struct cntrl_range_lay2 r; |
---|
1210 | | - |
---|
1211 | | - switch (status) { |
---|
1212 | | - case 0: /* normal completion? */ |
---|
1213 | | - if (!con) |
---|
1214 | | - break; |
---|
1215 | | - |
---|
1216 | | - if (cmd == UAC2_CS_CUR && con->type == UAC_FU_MUTE) { |
---|
1217 | | - memcpy(&c1, req->buf, 1); |
---|
1218 | | - con->set(con, UAC__CUR, c1); |
---|
1219 | | - } else if (cmd == UAC2_CS_CUR && con->type == UAC_FU_VOLUME) { |
---|
1220 | | - memcpy(&c2, req->buf, sizeof(c2)); |
---|
1221 | | - con->set(con, UAC__CUR, le16_to_cpu(c2.dCUR)); |
---|
1222 | | - } else if (cmd == UAC2_CS_RANGE) { |
---|
1223 | | - memcpy(&r, req->buf, sizeof(r)); |
---|
1224 | | - con->set(con, UAC__MIN, le16_to_cpu(r.dMIN)); |
---|
1225 | | - con->set(con, UAC__MAX, le16_to_cpu(r.dMAX)); |
---|
1226 | | - con->set(con, UAC__RES, le16_to_cpu(r.dRES)); |
---|
1227 | | - } |
---|
1228 | | - |
---|
1229 | | - uac2->set_con = NULL; |
---|
1230 | | - break; |
---|
1231 | | - default: |
---|
1232 | | - break; |
---|
1233 | | - } |
---|
1234 | 1680 | } |
---|
1235 | 1681 | |
---|
1236 | 1682 | static int |
---|
1237 | 1683 | ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1238 | 1684 | { |
---|
1239 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
1240 | | - struct usb_composite_dev *cdev = fn->config->cdev; |
---|
1241 | | - struct usb_request *req = cdev->req; |
---|
1242 | | - u8 id = ((le16_to_cpu(cr->wIndex) >> 8) & 0xFF); |
---|
1243 | | - u16 len = le16_to_cpu(cr->wLength); |
---|
1244 | | - u16 w_value = le16_to_cpu(cr->wValue); |
---|
1245 | | - u8 con_sel = (w_value >> 8) & 0xFF; |
---|
1246 | | - u8 cmd = (cr->bRequest & 0x0F); |
---|
1247 | | - struct usb_audio_control_selector *cs; |
---|
1248 | | - struct usb_audio_control *con; |
---|
1249 | | - |
---|
1250 | | - DBG(cdev, "bRequest in 0x%x, w_value 0x%04x, len %d, entity %d\n", |
---|
1251 | | - cr->bRequest, w_value, len, id); |
---|
1252 | | - |
---|
1253 | | - if (id == USB_OUT_CLK_ID || id == USB_IN_CLK_ID) { |
---|
1254 | | - if (cr->bRequest == UAC2_CS_CUR) |
---|
1255 | | - return in_rq_cs_cur(fn, cr); |
---|
1256 | | - else if (cr->bRequest == UAC2_CS_RANGE) |
---|
1257 | | - return in_rq_cs_range(fn, cr); |
---|
1258 | | - } |
---|
1259 | | - |
---|
1260 | | - list_for_each_entry(cs, &uac2->cs, list) |
---|
1261 | | - if (cs->id == id) |
---|
1262 | | - list_for_each_entry(con, &cs->control, list) |
---|
1263 | | - if (con->type == con_sel) { |
---|
1264 | | - req->context = uac2; |
---|
1265 | | - uac2->get_con = con; |
---|
1266 | | - uac2->get_cmd = cmd; |
---|
1267 | | - req->complete = uac2_fu_control_complt; |
---|
1268 | | - return in_rq_fu(fn, cr); |
---|
1269 | | - } |
---|
1270 | | - |
---|
1271 | | - return -EOPNOTSUPP; |
---|
| 1685 | + if (cr->bRequest == UAC2_CS_CUR) |
---|
| 1686 | + return in_rq_cur(fn, cr); |
---|
| 1687 | + else if (cr->bRequest == UAC2_CS_RANGE) |
---|
| 1688 | + return in_rq_range(fn, cr); |
---|
| 1689 | + else |
---|
| 1690 | + return -EOPNOTSUPP; |
---|
1272 | 1691 | } |
---|
1273 | 1692 | |
---|
1274 | 1693 | static void uac2_cs_control_sam_freq(struct usb_ep *ep, struct usb_request *req) |
---|
1275 | 1694 | { |
---|
1276 | 1695 | struct usb_function *fn = ep->driver_data; |
---|
1277 | | - struct usb_composite_dev *cdev = fn->config->cdev; |
---|
1278 | 1696 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
1279 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
1280 | | - struct f_uac_opts *opts = g_audio_to_uac_opts(agdev); |
---|
| 1697 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
1281 | 1698 | u32 val; |
---|
1282 | 1699 | |
---|
1283 | | - if (req->actual != 4) { |
---|
1284 | | - WARN(cdev, "Invalid data size for UAC2_CS_CONTROL_SAM_FREQ.\n"); |
---|
| 1700 | + if (req->actual != 4) |
---|
| 1701 | + return; |
---|
| 1702 | + |
---|
| 1703 | + val = le32_to_cpu(*((__le32 *)req->buf)); |
---|
| 1704 | + dev_dbg(&agdev->gadget->dev, "%s val: %d.\n", __func__, val); |
---|
| 1705 | + if (uac2->clock_id == USB_IN_CLK_ID) { |
---|
| 1706 | + u_audio_set_playback_srate(agdev, val); |
---|
| 1707 | + } else if (uac2->clock_id == USB_OUT_CLK_ID) { |
---|
| 1708 | + u_audio_set_capture_srate(agdev, val); |
---|
| 1709 | + } |
---|
| 1710 | +} |
---|
| 1711 | + |
---|
| 1712 | +static void |
---|
| 1713 | +out_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) |
---|
| 1714 | +{ |
---|
| 1715 | + struct g_audio *agdev = req->context; |
---|
| 1716 | + struct usb_composite_dev *cdev = agdev->func.config->cdev; |
---|
| 1717 | + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); |
---|
| 1718 | + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); |
---|
| 1719 | + struct usb_ctrlrequest *cr = &uac2->setup_cr; |
---|
| 1720 | + u16 w_index = le16_to_cpu(cr->wIndex); |
---|
| 1721 | + u16 w_value = le16_to_cpu(cr->wValue); |
---|
| 1722 | + u8 entity_id = (w_index >> 8) & 0xff; |
---|
| 1723 | + u8 control_selector = w_value >> 8; |
---|
| 1724 | + |
---|
| 1725 | + if (req->status != 0) { |
---|
| 1726 | + dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); |
---|
1285 | 1727 | return; |
---|
1286 | 1728 | } |
---|
1287 | 1729 | |
---|
1288 | | - val = le32_to_cpu(*((u32 *)req->buf)); |
---|
1289 | | - if (uac2->ctl_id == USB_IN_CLK_ID) { |
---|
1290 | | - opts->p_srate_active = val; |
---|
1291 | | - u_audio_set_playback_srate(agdev, opts->p_srate_active); |
---|
1292 | | - } else if (uac2->ctl_id == USB_OUT_CLK_ID) { |
---|
1293 | | - opts->c_srate_active = val; |
---|
1294 | | - u_audio_set_capture_srate(agdev, opts->c_srate_active); |
---|
| 1730 | + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || |
---|
| 1731 | + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { |
---|
| 1732 | + unsigned int is_playback = 0; |
---|
| 1733 | + |
---|
| 1734 | + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) |
---|
| 1735 | + is_playback = 1; |
---|
| 1736 | + |
---|
| 1737 | + if (control_selector == UAC_FU_MUTE) { |
---|
| 1738 | + u8 mute = *(u8 *)req->buf; |
---|
| 1739 | + |
---|
| 1740 | + u_audio_set_mute(agdev, is_playback, mute); |
---|
| 1741 | + |
---|
| 1742 | + return; |
---|
| 1743 | + } else if (control_selector == UAC_FU_VOLUME) { |
---|
| 1744 | + struct cntrl_cur_lay2 *c = req->buf; |
---|
| 1745 | + s16 volume; |
---|
| 1746 | + |
---|
| 1747 | + volume = le16_to_cpu(c->wCUR); |
---|
| 1748 | + u_audio_set_volume(agdev, is_playback, volume); |
---|
| 1749 | + |
---|
| 1750 | + return; |
---|
| 1751 | + } else { |
---|
| 1752 | + dev_err(&agdev->gadget->dev, |
---|
| 1753 | + "%s:%d control_selector=%d TODO!\n", |
---|
| 1754 | + __func__, __LINE__, control_selector); |
---|
| 1755 | + usb_ep_set_halt(ep); |
---|
| 1756 | + } |
---|
1295 | 1757 | } |
---|
1296 | 1758 | } |
---|
1297 | 1759 | |
---|
1298 | 1760 | static int |
---|
1299 | | -out_rq_cs_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
| 1761 | +out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1300 | 1762 | { |
---|
1301 | 1763 | struct usb_composite_dev *cdev = fn->config->cdev; |
---|
1302 | | - struct usb_request *req = cdev->req; |
---|
| 1764 | + struct usb_request *req = fn->config->cdev->req; |
---|
| 1765 | + struct g_audio *agdev = func_to_g_audio(fn); |
---|
| 1766 | + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); |
---|
| 1767 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
1303 | 1768 | u16 w_length = le16_to_cpu(cr->wLength); |
---|
1304 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
1305 | | - u16 w_value = le16_to_cpu(cr->wValue); |
---|
1306 | 1769 | u16 w_index = le16_to_cpu(cr->wIndex); |
---|
| 1770 | + u16 w_value = le16_to_cpu(cr->wValue); |
---|
| 1771 | + u8 entity_id = (w_index >> 8) & 0xff; |
---|
1307 | 1772 | u8 control_selector = w_value >> 8; |
---|
1308 | 1773 | u8 clock_id = w_index >> 8; |
---|
1309 | 1774 | |
---|
1310 | | - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
1311 | | - DBG(cdev, "control_selector UAC2_CS_CONTROL_SAM_FREQ, clock: %d\n", |
---|
1312 | | - clock_id); |
---|
1313 | | - cdev->gadget->ep0->driver_data = fn; |
---|
1314 | | - uac2->ctl_id = clock_id; |
---|
1315 | | - req->complete = uac2_cs_control_sam_freq; |
---|
| 1775 | + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { |
---|
| 1776 | + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { |
---|
| 1777 | + dev_dbg(&agdev->gadget->dev, |
---|
| 1778 | + "control_selector UAC2_CS_CONTROL_SAM_FREQ, clock: %d\n", clock_id); |
---|
| 1779 | + cdev->gadget->ep0->driver_data = fn; |
---|
| 1780 | + uac2->clock_id = clock_id; |
---|
| 1781 | + req->complete = uac2_cs_control_sam_freq; |
---|
| 1782 | + return w_length; |
---|
| 1783 | + } |
---|
| 1784 | + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || |
---|
| 1785 | + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { |
---|
| 1786 | + memcpy(&uac2->setup_cr, cr, sizeof(*cr)); |
---|
| 1787 | + req->context = agdev; |
---|
| 1788 | + req->complete = out_rq_cur_complete; |
---|
| 1789 | + |
---|
1316 | 1790 | return w_length; |
---|
| 1791 | + } else { |
---|
| 1792 | + dev_err(&agdev->gadget->dev, |
---|
| 1793 | + "%s:%d entity_id=%d control_selector=%d TODO!\n", |
---|
| 1794 | + __func__, __LINE__, entity_id, control_selector); |
---|
1317 | 1795 | } |
---|
1318 | | - |
---|
1319 | | - return -EOPNOTSUPP; |
---|
1320 | | -} |
---|
1321 | | - |
---|
1322 | | -static int |
---|
1323 | | -ac_rq_out(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1324 | | -{ |
---|
1325 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
1326 | | - struct usb_composite_dev *cdev = fn->config->cdev; |
---|
1327 | | - struct usb_request *req = cdev->req; |
---|
1328 | | - u16 w_index = le16_to_cpu(cr->wIndex); |
---|
1329 | | - u16 w_value = le16_to_cpu(cr->wValue); |
---|
1330 | | - u16 w_length = le16_to_cpu(cr->wLength); |
---|
1331 | | - u8 id = (w_index >> 8) & 0xff; |
---|
1332 | | - u8 con_sel = (w_value >> 8) & 0xff; |
---|
1333 | | - u8 cmd = (cr->bRequest & 0x0f); |
---|
1334 | | - struct usb_audio_control_selector *cs; |
---|
1335 | | - struct usb_audio_control *con; |
---|
1336 | | - |
---|
1337 | | - DBG(cdev, "bRequest out 0x%x, w_value 0x%04x, len %d, entity %d\n", |
---|
1338 | | - cr->bRequest, w_value, w_length, id); |
---|
1339 | | - |
---|
1340 | | - if (id == USB_OUT_CLK_ID || id == USB_IN_CLK_ID) { |
---|
1341 | | - if (cr->bRequest == UAC2_CS_CUR) |
---|
1342 | | - return out_rq_cs_cur(fn, cr); |
---|
1343 | | - } |
---|
1344 | | - |
---|
1345 | | - list_for_each_entry(cs, &uac2->cs, list) |
---|
1346 | | - if (cs->id == id) |
---|
1347 | | - list_for_each_entry(con, &cs->control, list) |
---|
1348 | | - if (con->type == con_sel) { |
---|
1349 | | - req->context = uac2; |
---|
1350 | | - uac2->set_con = con; |
---|
1351 | | - uac2->set_cmd = cmd; |
---|
1352 | | - req->complete = uac2_fu_control_complt; |
---|
1353 | | - return w_length; |
---|
1354 | | - } |
---|
1355 | | - |
---|
1356 | 1796 | return -EOPNOTSUPP; |
---|
1357 | 1797 | } |
---|
1358 | 1798 | |
---|
1359 | 1799 | static int |
---|
1360 | 1800 | setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) |
---|
1361 | 1801 | { |
---|
1362 | | - struct f_uac *uac2 = func_to_uac(fn); |
---|
| 1802 | + struct f_uac2 *uac2 = func_to_uac2(fn); |
---|
1363 | 1803 | struct g_audio *agdev = func_to_g_audio(fn); |
---|
1364 | 1804 | u16 w_index = le16_to_cpu(cr->wIndex); |
---|
1365 | 1805 | u8 intf = w_index & 0xff; |
---|
.. | .. |
---|
1372 | 1812 | |
---|
1373 | 1813 | if (cr->bRequestType & USB_DIR_IN) |
---|
1374 | 1814 | return ac_rq_in(fn, cr); |
---|
1375 | | - else |
---|
1376 | | - return ac_rq_out(fn, cr); |
---|
| 1815 | + else if (cr->bRequest == UAC2_CS_CUR) |
---|
| 1816 | + return out_rq_cur(fn, cr); |
---|
| 1817 | + |
---|
| 1818 | + return -EOPNOTSUPP; |
---|
1377 | 1819 | } |
---|
1378 | 1820 | |
---|
1379 | 1821 | static int |
---|
.. | .. |
---|
1409 | 1851 | return value; |
---|
1410 | 1852 | } |
---|
1411 | 1853 | |
---|
| 1854 | +static inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item) |
---|
| 1855 | +{ |
---|
| 1856 | + return container_of(to_config_group(item), struct f_uac2_opts, |
---|
| 1857 | + func_inst.group); |
---|
| 1858 | +} |
---|
| 1859 | + |
---|
| 1860 | +static void f_uac2_attr_release(struct config_item *item) |
---|
| 1861 | +{ |
---|
| 1862 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); |
---|
| 1863 | + |
---|
| 1864 | + usb_put_function_instance(&opts->func_inst); |
---|
| 1865 | +} |
---|
| 1866 | + |
---|
1412 | 1867 | static struct configfs_item_operations f_uac2_item_ops = { |
---|
1413 | | - .release = f_uac_attr_release, |
---|
| 1868 | + .release = f_uac2_attr_release, |
---|
1414 | 1869 | }; |
---|
1415 | 1870 | |
---|
1416 | | -UAC_ATTRIBUTE(p_chmask); |
---|
1417 | | -UAC_ATTRIBUTE(p_ssize); |
---|
1418 | | -UAC_ATTRIBUTE(p_feature_unit); |
---|
1419 | | -UAC_ATTRIBUTE(c_chmask); |
---|
1420 | | -UAC_ATTRIBUTE(c_ssize); |
---|
1421 | | -UAC_ATTRIBUTE(c_feature_unit); |
---|
1422 | | -UAC_ATTRIBUTE(req_number); |
---|
| 1871 | +#define uac2_kstrtou8 kstrtou8 |
---|
| 1872 | +#define uac2_kstrtou32 kstrtou32 |
---|
| 1873 | +#define uac2_kstrtos16 kstrtos16 |
---|
| 1874 | +#define uac2_kstrtobool(s, base, res) kstrtobool((s), (res)) |
---|
1423 | 1875 | |
---|
1424 | | -UAC_RATE_ATTRIBUTE(p_srate); |
---|
1425 | | -UAC_RATE_ATTRIBUTE(c_srate); |
---|
| 1876 | +static const char *u8_fmt = "%u\n"; |
---|
| 1877 | +static const char *u32_fmt = "%u\n"; |
---|
| 1878 | +static const char *s16_fmt = "%hd\n"; |
---|
| 1879 | +static const char *bool_fmt = "%u\n"; |
---|
| 1880 | + |
---|
| 1881 | +#define UAC2_ATTRIBUTE(type, name) \ |
---|
| 1882 | +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ |
---|
| 1883 | + char *page) \ |
---|
| 1884 | +{ \ |
---|
| 1885 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 1886 | + int result; \ |
---|
| 1887 | + \ |
---|
| 1888 | + mutex_lock(&opts->lock); \ |
---|
| 1889 | + result = sprintf(page, type##_fmt, opts->name); \ |
---|
| 1890 | + mutex_unlock(&opts->lock); \ |
---|
| 1891 | + \ |
---|
| 1892 | + return result; \ |
---|
| 1893 | +} \ |
---|
| 1894 | + \ |
---|
| 1895 | +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ |
---|
| 1896 | + const char *page, size_t len) \ |
---|
| 1897 | +{ \ |
---|
| 1898 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 1899 | + int ret; \ |
---|
| 1900 | + type num; \ |
---|
| 1901 | + \ |
---|
| 1902 | + mutex_lock(&opts->lock); \ |
---|
| 1903 | + if (opts->refcnt) { \ |
---|
| 1904 | + ret = -EBUSY; \ |
---|
| 1905 | + goto end; \ |
---|
| 1906 | + } \ |
---|
| 1907 | + \ |
---|
| 1908 | + ret = uac2_kstrto##type(page, 0, &num); \ |
---|
| 1909 | + if (ret) \ |
---|
| 1910 | + goto end; \ |
---|
| 1911 | + \ |
---|
| 1912 | + opts->name = num; \ |
---|
| 1913 | + ret = len; \ |
---|
| 1914 | + \ |
---|
| 1915 | +end: \ |
---|
| 1916 | + mutex_unlock(&opts->lock); \ |
---|
| 1917 | + return ret; \ |
---|
| 1918 | +} \ |
---|
| 1919 | + \ |
---|
| 1920 | +CONFIGFS_ATTR(f_uac2_opts_, name) |
---|
| 1921 | + |
---|
| 1922 | +#define UAC2_ATTRIBUTE_SYNC(name) \ |
---|
| 1923 | +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ |
---|
| 1924 | + char *page) \ |
---|
| 1925 | +{ \ |
---|
| 1926 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 1927 | + int result; \ |
---|
| 1928 | + char *str; \ |
---|
| 1929 | + \ |
---|
| 1930 | + mutex_lock(&opts->lock); \ |
---|
| 1931 | + switch (opts->name) { \ |
---|
| 1932 | + case USB_ENDPOINT_SYNC_ASYNC: \ |
---|
| 1933 | + str = "async"; \ |
---|
| 1934 | + break; \ |
---|
| 1935 | + case USB_ENDPOINT_SYNC_ADAPTIVE: \ |
---|
| 1936 | + str = "adaptive"; \ |
---|
| 1937 | + break; \ |
---|
| 1938 | + default: \ |
---|
| 1939 | + str = "unknown"; \ |
---|
| 1940 | + break; \ |
---|
| 1941 | + } \ |
---|
| 1942 | + result = sprintf(page, "%s\n", str); \ |
---|
| 1943 | + mutex_unlock(&opts->lock); \ |
---|
| 1944 | + \ |
---|
| 1945 | + return result; \ |
---|
| 1946 | +} \ |
---|
| 1947 | + \ |
---|
| 1948 | +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ |
---|
| 1949 | + const char *page, size_t len) \ |
---|
| 1950 | +{ \ |
---|
| 1951 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 1952 | + int ret = 0; \ |
---|
| 1953 | + \ |
---|
| 1954 | + mutex_lock(&opts->lock); \ |
---|
| 1955 | + if (opts->refcnt) { \ |
---|
| 1956 | + ret = -EBUSY; \ |
---|
| 1957 | + goto end; \ |
---|
| 1958 | + } \ |
---|
| 1959 | + \ |
---|
| 1960 | + if (!strncmp(page, "async", 5)) \ |
---|
| 1961 | + opts->name = USB_ENDPOINT_SYNC_ASYNC; \ |
---|
| 1962 | + else if (!strncmp(page, "adaptive", 8)) \ |
---|
| 1963 | + opts->name = USB_ENDPOINT_SYNC_ADAPTIVE; \ |
---|
| 1964 | + else { \ |
---|
| 1965 | + ret = -EINVAL; \ |
---|
| 1966 | + goto end; \ |
---|
| 1967 | + } \ |
---|
| 1968 | + \ |
---|
| 1969 | + ret = len; \ |
---|
| 1970 | + \ |
---|
| 1971 | +end: \ |
---|
| 1972 | + mutex_unlock(&opts->lock); \ |
---|
| 1973 | + return ret; \ |
---|
| 1974 | +} \ |
---|
| 1975 | + \ |
---|
| 1976 | +CONFIGFS_ATTR(f_uac2_opts_, name) |
---|
| 1977 | + |
---|
| 1978 | +#define UAC2_RATE_ATTRIBUTE(name) \ |
---|
| 1979 | +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ |
---|
| 1980 | + char *page) \ |
---|
| 1981 | +{ \ |
---|
| 1982 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 1983 | + int result = 0; \ |
---|
| 1984 | + int i; \ |
---|
| 1985 | + \ |
---|
| 1986 | + mutex_lock(&opts->lock); \ |
---|
| 1987 | + page[0] = '\0'; \ |
---|
| 1988 | + for (i = 0; i < UAC_MAX_RATES; i++) { \ |
---|
| 1989 | + if (opts->name##s[i] == 0) \ |
---|
| 1990 | + break; \ |
---|
| 1991 | + result += sprintf(page + strlen(page), "%u,", \ |
---|
| 1992 | + opts->name##s[i]); \ |
---|
| 1993 | + } \ |
---|
| 1994 | + if (strlen(page) > 0) \ |
---|
| 1995 | + page[strlen(page) - 1] = '\n'; \ |
---|
| 1996 | + mutex_unlock(&opts->lock); \ |
---|
| 1997 | + \ |
---|
| 1998 | + return result; \ |
---|
| 1999 | +} \ |
---|
| 2000 | + \ |
---|
| 2001 | +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ |
---|
| 2002 | + const char *page, size_t len) \ |
---|
| 2003 | +{ \ |
---|
| 2004 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 2005 | + char *split_page = NULL; \ |
---|
| 2006 | + int ret = -EINVAL; \ |
---|
| 2007 | + char *token; \ |
---|
| 2008 | + u32 num; \ |
---|
| 2009 | + int i; \ |
---|
| 2010 | + \ |
---|
| 2011 | + mutex_lock(&opts->lock); \ |
---|
| 2012 | + if (opts->refcnt) { \ |
---|
| 2013 | + ret = -EBUSY; \ |
---|
| 2014 | + goto end; \ |
---|
| 2015 | + } \ |
---|
| 2016 | + \ |
---|
| 2017 | + i = 0; \ |
---|
| 2018 | + memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ |
---|
| 2019 | + split_page = kstrdup(page, GFP_KERNEL); \ |
---|
| 2020 | + while ((token = strsep(&split_page, ",")) != NULL) { \ |
---|
| 2021 | + ret = kstrtou32(token, 0, &num); \ |
---|
| 2022 | + if (ret) \ |
---|
| 2023 | + goto end; \ |
---|
| 2024 | + \ |
---|
| 2025 | + opts->name##s[i++] = num; \ |
---|
| 2026 | + ret = len; \ |
---|
| 2027 | + }; \ |
---|
| 2028 | + \ |
---|
| 2029 | +end: \ |
---|
| 2030 | + kfree(split_page); \ |
---|
| 2031 | + mutex_unlock(&opts->lock); \ |
---|
| 2032 | + return ret; \ |
---|
| 2033 | +} \ |
---|
| 2034 | + \ |
---|
| 2035 | +CONFIGFS_ATTR(f_uac2_opts_, name) |
---|
| 2036 | + |
---|
| 2037 | +#define UAC2_ATTRIBUTE_STRING(name) \ |
---|
| 2038 | +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ |
---|
| 2039 | + char *page) \ |
---|
| 2040 | +{ \ |
---|
| 2041 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 2042 | + int result; \ |
---|
| 2043 | + \ |
---|
| 2044 | + mutex_lock(&opts->lock); \ |
---|
| 2045 | + result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ |
---|
| 2046 | + mutex_unlock(&opts->lock); \ |
---|
| 2047 | + \ |
---|
| 2048 | + return result; \ |
---|
| 2049 | +} \ |
---|
| 2050 | + \ |
---|
| 2051 | +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ |
---|
| 2052 | + const char *page, size_t len) \ |
---|
| 2053 | +{ \ |
---|
| 2054 | + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ |
---|
| 2055 | + int ret = 0; \ |
---|
| 2056 | + \ |
---|
| 2057 | + mutex_lock(&opts->lock); \ |
---|
| 2058 | + if (opts->refcnt) { \ |
---|
| 2059 | + ret = -EBUSY; \ |
---|
| 2060 | + goto end; \ |
---|
| 2061 | + } \ |
---|
| 2062 | + \ |
---|
| 2063 | + ret = snprintf(opts->name, min(sizeof(opts->name), len), \ |
---|
| 2064 | + "%s", page); \ |
---|
| 2065 | + \ |
---|
| 2066 | +end: \ |
---|
| 2067 | + mutex_unlock(&opts->lock); \ |
---|
| 2068 | + return ret; \ |
---|
| 2069 | +} \ |
---|
| 2070 | + \ |
---|
| 2071 | +CONFIGFS_ATTR(f_uac2_opts_, name) |
---|
| 2072 | + |
---|
| 2073 | +UAC2_ATTRIBUTE(u32, p_chmask); |
---|
| 2074 | +UAC2_RATE_ATTRIBUTE(p_srate); |
---|
| 2075 | +UAC2_ATTRIBUTE(u32, p_ssize); |
---|
| 2076 | +UAC2_ATTRIBUTE(u8, p_hs_bint); |
---|
| 2077 | +UAC2_ATTRIBUTE(u32, c_chmask); |
---|
| 2078 | +UAC2_RATE_ATTRIBUTE(c_srate); |
---|
| 2079 | +UAC2_ATTRIBUTE_SYNC(c_sync); |
---|
| 2080 | +UAC2_ATTRIBUTE(u32, c_ssize); |
---|
| 2081 | +UAC2_ATTRIBUTE(u8, c_hs_bint); |
---|
| 2082 | +UAC2_ATTRIBUTE(u32, req_number); |
---|
| 2083 | + |
---|
| 2084 | +UAC2_ATTRIBUTE(bool, p_mute_present); |
---|
| 2085 | +UAC2_ATTRIBUTE(bool, p_volume_present); |
---|
| 2086 | +UAC2_ATTRIBUTE(s16, p_volume_min); |
---|
| 2087 | +UAC2_ATTRIBUTE(s16, p_volume_max); |
---|
| 2088 | +UAC2_ATTRIBUTE(s16, p_volume_res); |
---|
| 2089 | + |
---|
| 2090 | +UAC2_ATTRIBUTE(bool, c_mute_present); |
---|
| 2091 | +UAC2_ATTRIBUTE(bool, c_volume_present); |
---|
| 2092 | +UAC2_ATTRIBUTE(s16, c_volume_min); |
---|
| 2093 | +UAC2_ATTRIBUTE(s16, c_volume_max); |
---|
| 2094 | +UAC2_ATTRIBUTE(s16, c_volume_res); |
---|
| 2095 | +UAC2_ATTRIBUTE(u32, fb_max); |
---|
| 2096 | +UAC2_ATTRIBUTE_STRING(function_name); |
---|
1426 | 2097 | |
---|
1427 | 2098 | static struct configfs_attribute *f_uac2_attrs[] = { |
---|
1428 | | - &f_uac_opts_attr_p_chmask, |
---|
1429 | | - &f_uac_opts_attr_p_srate, |
---|
1430 | | - &f_uac_opts_attr_p_ssize, |
---|
1431 | | - &f_uac_opts_attr_p_feature_unit, |
---|
1432 | | - &f_uac_opts_attr_c_chmask, |
---|
1433 | | - &f_uac_opts_attr_c_srate, |
---|
1434 | | - &f_uac_opts_attr_c_ssize, |
---|
1435 | | - &f_uac_opts_attr_c_feature_unit, |
---|
1436 | | - &f_uac_opts_attr_req_number, |
---|
| 2099 | + &f_uac2_opts_attr_p_chmask, |
---|
| 2100 | + &f_uac2_opts_attr_p_srate, |
---|
| 2101 | + &f_uac2_opts_attr_p_ssize, |
---|
| 2102 | + &f_uac2_opts_attr_p_hs_bint, |
---|
| 2103 | + &f_uac2_opts_attr_c_chmask, |
---|
| 2104 | + &f_uac2_opts_attr_c_srate, |
---|
| 2105 | + &f_uac2_opts_attr_c_ssize, |
---|
| 2106 | + &f_uac2_opts_attr_c_hs_bint, |
---|
| 2107 | + &f_uac2_opts_attr_c_sync, |
---|
| 2108 | + &f_uac2_opts_attr_req_number, |
---|
| 2109 | + &f_uac2_opts_attr_fb_max, |
---|
| 2110 | + |
---|
| 2111 | + &f_uac2_opts_attr_p_mute_present, |
---|
| 2112 | + &f_uac2_opts_attr_p_volume_present, |
---|
| 2113 | + &f_uac2_opts_attr_p_volume_min, |
---|
| 2114 | + &f_uac2_opts_attr_p_volume_max, |
---|
| 2115 | + &f_uac2_opts_attr_p_volume_res, |
---|
| 2116 | + |
---|
| 2117 | + &f_uac2_opts_attr_c_mute_present, |
---|
| 2118 | + &f_uac2_opts_attr_c_volume_present, |
---|
| 2119 | + &f_uac2_opts_attr_c_volume_min, |
---|
| 2120 | + &f_uac2_opts_attr_c_volume_max, |
---|
| 2121 | + &f_uac2_opts_attr_c_volume_res, |
---|
| 2122 | + |
---|
| 2123 | + &f_uac2_opts_attr_function_name, |
---|
| 2124 | + |
---|
1437 | 2125 | NULL, |
---|
1438 | 2126 | }; |
---|
1439 | 2127 | |
---|
.. | .. |
---|
1445 | 2133 | |
---|
1446 | 2134 | static void afunc_free_inst(struct usb_function_instance *f) |
---|
1447 | 2135 | { |
---|
1448 | | - struct f_uac_opts *opts; |
---|
| 2136 | + struct f_uac2_opts *opts; |
---|
1449 | 2137 | |
---|
1450 | | - opts = container_of(f, struct f_uac_opts, func_inst); |
---|
| 2138 | + opts = container_of(f, struct f_uac2_opts, func_inst); |
---|
1451 | 2139 | kfree(opts); |
---|
1452 | 2140 | } |
---|
1453 | 2141 | |
---|
1454 | 2142 | static struct usb_function_instance *afunc_alloc_inst(void) |
---|
1455 | 2143 | { |
---|
1456 | | - struct f_uac_opts *opts; |
---|
| 2144 | + struct f_uac2_opts *opts; |
---|
1457 | 2145 | |
---|
1458 | 2146 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
---|
1459 | 2147 | if (!opts) |
---|
.. | .. |
---|
1465 | 2153 | config_group_init_type_name(&opts->func_inst.group, "", |
---|
1466 | 2154 | &f_uac2_func_type); |
---|
1467 | 2155 | |
---|
1468 | | - opts->p_chmask = UAC_DEF_PCHMASK; |
---|
1469 | | - opts->p_srate[0] = UAC_DEF_PSRATE; |
---|
1470 | | - opts->p_srate_active = UAC_DEF_PSRATE; |
---|
1471 | | - opts->p_ssize = UAC_DEF_PSSIZE; |
---|
1472 | | - opts->p_feature_unit = UAC_DEF_PFU; |
---|
1473 | | - opts->c_chmask = UAC_DEF_CCHMASK; |
---|
1474 | | - opts->c_srate[0] = UAC_DEF_CSRATE; |
---|
1475 | | - opts->c_srate_active = UAC_DEF_CSRATE; |
---|
1476 | | - opts->c_ssize = UAC_DEF_CSSIZE; |
---|
1477 | | - opts->c_feature_unit = UAC_DEF_CFU; |
---|
1478 | | - opts->req_number = UAC_DEF_REQ_NUM; |
---|
| 2156 | + opts->p_chmask = UAC2_DEF_PCHMASK; |
---|
| 2157 | + opts->p_srates[0] = UAC2_DEF_PSRATE; |
---|
| 2158 | + opts->p_ssize = UAC2_DEF_PSSIZE; |
---|
| 2159 | + opts->p_hs_bint = UAC2_DEF_PHSBINT; |
---|
| 2160 | + opts->c_chmask = UAC2_DEF_CCHMASK; |
---|
| 2161 | + opts->c_srates[0] = UAC2_DEF_CSRATE; |
---|
| 2162 | + opts->c_ssize = UAC2_DEF_CSSIZE; |
---|
| 2163 | + opts->c_hs_bint = UAC2_DEF_CHSBINT; |
---|
| 2164 | + opts->c_sync = UAC2_DEF_CSYNC; |
---|
| 2165 | + |
---|
| 2166 | + opts->p_mute_present = UAC2_DEF_MUTE_PRESENT; |
---|
| 2167 | + opts->p_volume_present = UAC2_DEF_VOLUME_PRESENT; |
---|
| 2168 | + opts->p_volume_min = UAC2_DEF_MIN_DB; |
---|
| 2169 | + opts->p_volume_max = UAC2_DEF_MAX_DB; |
---|
| 2170 | + opts->p_volume_res = UAC2_DEF_RES_DB; |
---|
| 2171 | + |
---|
| 2172 | + opts->c_mute_present = UAC2_DEF_MUTE_PRESENT; |
---|
| 2173 | + opts->c_volume_present = UAC2_DEF_VOLUME_PRESENT; |
---|
| 2174 | + opts->c_volume_min = UAC2_DEF_MIN_DB; |
---|
| 2175 | + opts->c_volume_max = UAC2_DEF_MAX_DB; |
---|
| 2176 | + opts->c_volume_res = UAC2_DEF_RES_DB; |
---|
| 2177 | + |
---|
| 2178 | + opts->req_number = UAC2_DEF_REQ_NUM; |
---|
| 2179 | + opts->fb_max = FBACK_FAST_MAX; |
---|
| 2180 | + |
---|
| 2181 | + snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); |
---|
| 2182 | + |
---|
1479 | 2183 | return &opts->func_inst; |
---|
1480 | 2184 | } |
---|
1481 | 2185 | |
---|
1482 | 2186 | static void afunc_free(struct usb_function *f) |
---|
1483 | 2187 | { |
---|
1484 | 2188 | struct g_audio *agdev; |
---|
1485 | | - struct f_uac_opts *opts; |
---|
| 2189 | + struct f_uac2_opts *opts; |
---|
1486 | 2190 | |
---|
1487 | 2191 | agdev = func_to_g_audio(f); |
---|
1488 | | - opts = container_of(f->fi, struct f_uac_opts, func_inst); |
---|
| 2192 | + opts = container_of(f->fi, struct f_uac2_opts, func_inst); |
---|
1489 | 2193 | kfree(agdev); |
---|
1490 | 2194 | mutex_lock(&opts->lock); |
---|
1491 | 2195 | --opts->refcnt; |
---|
.. | .. |
---|
1500 | 2204 | usb_free_all_descriptors(f); |
---|
1501 | 2205 | |
---|
1502 | 2206 | agdev->gadget = NULL; |
---|
| 2207 | + |
---|
| 2208 | + kfree(out_feature_unit_desc); |
---|
| 2209 | + out_feature_unit_desc = NULL; |
---|
| 2210 | + kfree(in_feature_unit_desc); |
---|
| 2211 | + in_feature_unit_desc = NULL; |
---|
1503 | 2212 | } |
---|
1504 | | - |
---|
1505 | | -/* Todo: add more control selecotor dynamically */ |
---|
1506 | | -static int control_selector_init(struct f_uac *uac2) |
---|
1507 | | -{ |
---|
1508 | | - INIT_LIST_HEAD(&uac2->cs); |
---|
1509 | | - |
---|
1510 | | - /* playback feature unit */ |
---|
1511 | | - list_add(&p_feature_unit.list, &uac2->cs); |
---|
1512 | | - |
---|
1513 | | - INIT_LIST_HEAD(&p_feature_unit.control); |
---|
1514 | | - list_add(&p_mute_control.list, &p_feature_unit.control); |
---|
1515 | | - list_add(&p_volume_control.list, &p_feature_unit.control); |
---|
1516 | | - |
---|
1517 | | - p_volume_control.data[UAC__CUR] = UAC_VOLUME_CUR; |
---|
1518 | | - p_volume_control.data[UAC__MIN] = UAC_VOLUME_MIN; |
---|
1519 | | - p_volume_control.data[UAC__MAX] = UAC_VOLUME_MAX; |
---|
1520 | | - p_volume_control.data[UAC__RES] = UAC_VOLUME_RES; |
---|
1521 | | - |
---|
1522 | | - p_volume_control.context = &uac2->g_audio; |
---|
1523 | | - p_mute_control.context = &uac2->g_audio; |
---|
1524 | | - |
---|
1525 | | - /* capture feature unit */ |
---|
1526 | | - list_add(&c_feature_unit.list, &uac2->cs); |
---|
1527 | | - |
---|
1528 | | - INIT_LIST_HEAD(&c_feature_unit.control); |
---|
1529 | | - list_add(&c_mute_control.list, &c_feature_unit.control); |
---|
1530 | | - list_add(&c_volume_control.list, &c_feature_unit.control); |
---|
1531 | | - |
---|
1532 | | - c_volume_control.data[UAC__CUR] = UAC_VOLUME_CUR; |
---|
1533 | | - c_volume_control.data[UAC__MIN] = UAC_VOLUME_MIN; |
---|
1534 | | - c_volume_control.data[UAC__MAX] = UAC_VOLUME_MAX; |
---|
1535 | | - c_volume_control.data[UAC__RES] = UAC_VOLUME_RES; |
---|
1536 | | - |
---|
1537 | | - c_volume_control.context = &uac2->g_audio; |
---|
1538 | | - c_mute_control.context = &uac2->g_audio; |
---|
1539 | | - |
---|
1540 | | - return 0; |
---|
1541 | | -} |
---|
1542 | | - |
---|
1543 | 2213 | |
---|
1544 | 2214 | static struct usb_function *afunc_alloc(struct usb_function_instance *fi) |
---|
1545 | 2215 | { |
---|
1546 | | - struct f_uac *uac2; |
---|
1547 | | - struct f_uac_opts *opts; |
---|
| 2216 | + struct f_uac2 *uac2; |
---|
| 2217 | + struct f_uac2_opts *opts; |
---|
1548 | 2218 | |
---|
1549 | 2219 | uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL); |
---|
1550 | 2220 | if (uac2 == NULL) |
---|
1551 | 2221 | return ERR_PTR(-ENOMEM); |
---|
1552 | 2222 | |
---|
1553 | | - opts = container_of(fi, struct f_uac_opts, func_inst); |
---|
| 2223 | + opts = container_of(fi, struct f_uac2_opts, func_inst); |
---|
1554 | 2224 | mutex_lock(&opts->lock); |
---|
1555 | 2225 | ++opts->refcnt; |
---|
1556 | 2226 | mutex_unlock(&opts->lock); |
---|
.. | .. |
---|
1561 | 2231 | uac2->g_audio.func.set_alt = afunc_set_alt; |
---|
1562 | 2232 | uac2->g_audio.func.get_alt = afunc_get_alt; |
---|
1563 | 2233 | uac2->g_audio.func.disable = afunc_disable; |
---|
| 2234 | + uac2->g_audio.func.suspend = afunc_suspend; |
---|
1564 | 2235 | uac2->g_audio.func.setup = afunc_setup; |
---|
1565 | 2236 | uac2->g_audio.func.free_func = afunc_free; |
---|
1566 | | - |
---|
1567 | | - control_selector_init(uac2); |
---|
1568 | 2237 | |
---|
1569 | 2238 | return &uac2->g_audio.func; |
---|
1570 | 2239 | } |
---|
.. | .. |
---|
1573 | 2242 | MODULE_LICENSE("GPL"); |
---|
1574 | 2243 | MODULE_AUTHOR("Yadwinder Singh"); |
---|
1575 | 2244 | MODULE_AUTHOR("Jaswinder Singh"); |
---|
| 2245 | +MODULE_AUTHOR("Ruslan Bilovol"); |
---|