1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Scarlett Driver for ALSA |
4 | * |
5 | * Copyright (c) 2013 by Tobias Hoffmann |
6 | * Copyright (c) 2013 by Robin Gareus <robin at gareus.org> |
7 | * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de> |
8 | * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com> |
9 | * |
10 | * Many codes borrowed from audio.c by |
11 | * Alan Cox (alan at lxorguk.ukuu.org.uk) |
12 | * Thomas Sailer (sailer at ife.ee.ethz.ch) |
13 | * |
14 | * Code cleanup: |
15 | * David Henningsson <david.henningsson at canonical.com> |
16 | */ |
17 | |
18 | /* |
19 | * Rewritten and extended to support more models, e.g. Scarlett 18i8. |
20 | * |
21 | * Auto-detection via UAC2 is not feasible to properly discover the vast |
22 | * majority of features. It's related to both Linux/ALSA's UAC2 as well as |
23 | * Focusrite's implementation of it. Eventually quirks may be sufficient but |
24 | * right now it's a major headache to work around these things. |
25 | * |
26 | * NB. Neither the OSX nor the win driver provided by Focusrite performs |
27 | * discovery, they seem to operate the same as this driver. |
28 | */ |
29 | |
30 | /* Mixer Interface for the Focusrite Scarlett 18i6 audio interface. |
31 | * |
32 | * The protocol was reverse engineered by looking at communication between |
33 | * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6 |
34 | * (firmware v305) using wireshark and usbmon in January 2013. |
35 | * Extended in July 2013. |
36 | * |
37 | * this mixer gives complete access to all features of the device: |
38 | * - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z) |
39 | * - select clock source |
40 | * - dynamic input to mixer-matrix assignment |
41 | * - 18 x 6 mixer-matrix gain stages |
42 | * - bus routing & volume control |
43 | * - automatic re-initialization on connect if device was power-cycled |
44 | * |
45 | * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR) |
46 | * wIndex |
47 | * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 + |
48 | * channel, data=Line/Inst (2bytes) |
49 | * pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes) |
50 | * ?? wValue=0x0803/04, ?? (2bytes) |
51 | * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes) |
52 | * Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes) |
53 | * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte) |
54 | * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes) |
55 | * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes) |
56 | * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes) |
57 | * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes) |
58 | * 0x3c Matrix Mixer gains, wValue=mixer-node data=gain(2bytes) |
59 | * ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff) |
60 | * |
61 | * USB reads: (i.e. actually issued by original software) |
62 | * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!) |
63 | * 0x29 wValue=0x0100 sample-rate(4bytes) |
64 | * wValue=0x0200 ?? 1byte (only once) |
65 | * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ?? |
66 | * |
67 | * USB reads with bRequest = 0x03 = UAC2_CS_MEM |
68 | * 0x3c wValue=0x0002 1byte: sync status (locked=1) |
69 | * wValue=0x0000 18*2byte: peak meter (inputs) |
70 | * wValue=0x0001 8(?)*2byte: peak meter (mix) |
71 | * wValue=0x0003 6*2byte: peak meter (pcm/daw) |
72 | * |
73 | * USB write with bRequest = 0x03 |
74 | * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5 |
75 | * |
76 | * |
77 | * <ditaa> |
78 | * /--------------\ 18chn 6chn /--------------\ |
79 | * | Hardware in +--+-------\ /------+--+ ALSA PCM out | |
80 | * \--------------/ | | | | \--------------/ |
81 | * | | | | |
82 | * | v v | |
83 | * | +---------------+ | |
84 | * | \ Matrix Mux / | |
85 | * | +-----+-----+ | |
86 | * | | | |
87 | * | | 18chn | |
88 | * | v | |
89 | * | +-----------+ | |
90 | * | | Mixer | | |
91 | * | | Matrix | | |
92 | * | | | | |
93 | * | | 18x6 Gain | | |
94 | * | | stages | | |
95 | * | +-----+-----+ | |
96 | * | | | |
97 | * | | | |
98 | * | 18chn | 6chn | 6chn |
99 | * v v v |
100 | * ========================= |
101 | * +---------------+ +--—------------+ |
102 | * \ Output Mux / \ Capture Mux / |
103 | * +-----+-----+ +-----+-----+ |
104 | * | | |
105 | * | 6chn | |
106 | * v | |
107 | * +-------------+ | |
108 | * | Master Gain | | |
109 | * +------+------+ | |
110 | * | | |
111 | * | 6chn | 18chn |
112 | * | (3 stereo pairs) | |
113 | * /--------------\ | | /--------------\ |
114 | * | Hardware out |<--/ \-->| ALSA PCM in | |
115 | * \--------------/ \--------------/ |
116 | * </ditaa> |
117 | * |
118 | */ |
119 | |
120 | #include <linux/slab.h> |
121 | #include <linux/usb.h> |
122 | #include <linux/usb/audio-v2.h> |
123 | |
124 | #include <sound/core.h> |
125 | #include <sound/control.h> |
126 | #include <sound/tlv.h> |
127 | |
128 | #include "usbaudio.h" |
129 | #include "mixer.h" |
130 | #include "helper.h" |
131 | #include "power.h" |
132 | |
133 | #include "mixer_scarlett.h" |
134 | |
135 | /* some gui mixers can't handle negative ctl values */ |
136 | #define SND_SCARLETT_LEVEL_BIAS 128 |
137 | #define SND_SCARLETT_MATRIX_IN_MAX 18 |
138 | #define SND_SCARLETT_CONTROLS_MAX 10 |
139 | #define SND_SCARLETT_OFFSETS_MAX 5 |
140 | |
141 | enum { |
142 | SCARLETT_OUTPUTS, |
143 | SCARLETT_SWITCH_IMPEDANCE, |
144 | SCARLETT_SWITCH_PAD, |
145 | SCARLETT_SWITCH_GAIN, |
146 | }; |
147 | |
148 | enum { |
149 | SCARLETT_OFFSET_PCM = 0, |
150 | SCARLETT_OFFSET_ANALOG = 1, |
151 | SCARLETT_OFFSET_SPDIF = 2, |
152 | SCARLETT_OFFSET_ADAT = 3, |
153 | SCARLETT_OFFSET_MIX = 4, |
154 | }; |
155 | |
156 | struct scarlett_mixer_elem_enum_info { |
157 | int start; |
158 | int len; |
159 | int offsets[SND_SCARLETT_OFFSETS_MAX]; |
160 | char const * const *names; |
161 | }; |
162 | |
163 | struct scarlett_mixer_control { |
164 | unsigned char num; |
165 | unsigned char type; |
166 | const char *name; |
167 | }; |
168 | |
169 | struct scarlett_device_info { |
170 | int matrix_in; |
171 | int matrix_out; |
172 | int input_len; |
173 | int output_len; |
174 | |
175 | struct scarlett_mixer_elem_enum_info opt_master; |
176 | struct scarlett_mixer_elem_enum_info opt_matrix; |
177 | |
178 | /* initial values for matrix mux */ |
179 | int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX]; |
180 | |
181 | int num_controls; /* number of items in controls */ |
182 | const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX]; |
183 | }; |
184 | |
185 | /********************** Enum Strings *************************/ |
186 | |
187 | static const struct scarlett_mixer_elem_enum_info opt_pad = { |
188 | .start = 0, |
189 | .len = 2, |
190 | .offsets = {}, |
191 | .names = (char const * const []){ |
192 | "0dB" , "-10dB" |
193 | } |
194 | }; |
195 | |
196 | static const struct scarlett_mixer_elem_enum_info opt_gain = { |
197 | .start = 0, |
198 | .len = 2, |
199 | .offsets = {}, |
200 | .names = (char const * const []){ |
201 | "Lo" , "Hi" |
202 | } |
203 | }; |
204 | |
205 | static const struct scarlett_mixer_elem_enum_info opt_impedance = { |
206 | .start = 0, |
207 | .len = 2, |
208 | .offsets = {}, |
209 | .names = (char const * const []){ |
210 | "Line" , "Hi-Z" |
211 | } |
212 | }; |
213 | |
214 | static const struct scarlett_mixer_elem_enum_info opt_clock = { |
215 | .start = 1, |
216 | .len = 3, |
217 | .offsets = {}, |
218 | .names = (char const * const []){ |
219 | "Internal" , "SPDIF" , "ADAT" |
220 | } |
221 | }; |
222 | |
223 | static const struct scarlett_mixer_elem_enum_info opt_sync = { |
224 | .start = 0, |
225 | .len = 2, |
226 | .offsets = {}, |
227 | .names = (char const * const []){ |
228 | "No Lock" , "Locked" |
229 | } |
230 | }; |
231 | |
232 | static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl, |
233 | struct snd_ctl_elem_info *uinfo) |
234 | { |
235 | struct usb_mixer_elem_info *elem = kctl->private_data; |
236 | |
237 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
238 | uinfo->count = elem->channels; |
239 | uinfo->value.integer.min = 0; |
240 | uinfo->value.integer.max = 1; |
241 | return 0; |
242 | } |
243 | |
244 | static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl, |
245 | struct snd_ctl_elem_value *ucontrol) |
246 | { |
247 | struct usb_mixer_elem_info *elem = kctl->private_data; |
248 | int i, err, val; |
249 | |
250 | for (i = 0; i < elem->channels; i++) { |
251 | err = snd_usb_get_cur_mix_value(cval: elem, channel: i, index: i, value: &val); |
252 | if (err < 0) |
253 | return err; |
254 | |
255 | val = !val; /* invert mute logic for mixer */ |
256 | ucontrol->value.integer.value[i] = val; |
257 | } |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, |
263 | struct snd_ctl_elem_value *ucontrol) |
264 | { |
265 | struct usb_mixer_elem_info *elem = kctl->private_data; |
266 | int i, changed = 0; |
267 | int err, oval, val; |
268 | |
269 | for (i = 0; i < elem->channels; i++) { |
270 | err = snd_usb_get_cur_mix_value(cval: elem, channel: i, index: i, value: &oval); |
271 | if (err < 0) |
272 | return err; |
273 | |
274 | val = ucontrol->value.integer.value[i]; |
275 | val = !val; |
276 | if (oval != val) { |
277 | err = snd_usb_set_cur_mix_value(cval: elem, channel: i, index: i, value: val); |
278 | if (err < 0) |
279 | return err; |
280 | |
281 | changed = 1; |
282 | } |
283 | } |
284 | |
285 | return changed; |
286 | } |
287 | |
288 | static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) |
289 | { |
290 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
291 | int i; |
292 | |
293 | for (i = 0; i < elem->channels; i++) |
294 | if (elem->cached & (1 << i)) |
295 | snd_usb_set_cur_mix_value(cval: elem, channel: i, index: i, |
296 | value: elem->cache_val[i]); |
297 | return 0; |
298 | } |
299 | |
300 | static int scarlett_ctl_info(struct snd_kcontrol *kctl, |
301 | struct snd_ctl_elem_info *uinfo) |
302 | { |
303 | struct usb_mixer_elem_info *elem = kctl->private_data; |
304 | |
305 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
306 | uinfo->count = elem->channels; |
307 | uinfo->value.integer.min = 0; |
308 | uinfo->value.integer.max = (int)kctl->private_value + |
309 | SND_SCARLETT_LEVEL_BIAS; |
310 | uinfo->value.integer.step = 1; |
311 | return 0; |
312 | } |
313 | |
314 | static int scarlett_ctl_get(struct snd_kcontrol *kctl, |
315 | struct snd_ctl_elem_value *ucontrol) |
316 | { |
317 | struct usb_mixer_elem_info *elem = kctl->private_data; |
318 | int i, err, val; |
319 | |
320 | for (i = 0; i < elem->channels; i++) { |
321 | err = snd_usb_get_cur_mix_value(cval: elem, channel: i, index: i, value: &val); |
322 | if (err < 0) |
323 | return err; |
324 | |
325 | val = clamp(val / 256, -128, (int)kctl->private_value) + |
326 | SND_SCARLETT_LEVEL_BIAS; |
327 | ucontrol->value.integer.value[i] = val; |
328 | } |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | static int scarlett_ctl_put(struct snd_kcontrol *kctl, |
334 | struct snd_ctl_elem_value *ucontrol) |
335 | { |
336 | struct usb_mixer_elem_info *elem = kctl->private_data; |
337 | int i, changed = 0; |
338 | int err, oval, val; |
339 | |
340 | for (i = 0; i < elem->channels; i++) { |
341 | err = snd_usb_get_cur_mix_value(cval: elem, channel: i, index: i, value: &oval); |
342 | if (err < 0) |
343 | return err; |
344 | |
345 | val = ucontrol->value.integer.value[i] - |
346 | SND_SCARLETT_LEVEL_BIAS; |
347 | val = val * 256; |
348 | if (oval != val) { |
349 | err = snd_usb_set_cur_mix_value(cval: elem, channel: i, index: i, value: val); |
350 | if (err < 0) |
351 | return err; |
352 | |
353 | changed = 1; |
354 | } |
355 | } |
356 | |
357 | return changed; |
358 | } |
359 | |
360 | static void scarlett_generate_name(int i, char *dst, int offsets[]) |
361 | { |
362 | if (i > offsets[SCARLETT_OFFSET_MIX]) |
363 | sprintf(buf: dst, fmt: "Mix %c" , |
364 | 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); |
365 | else if (i > offsets[SCARLETT_OFFSET_ADAT]) |
366 | sprintf(buf: dst, fmt: "ADAT %d" , i - offsets[SCARLETT_OFFSET_ADAT]); |
367 | else if (i > offsets[SCARLETT_OFFSET_SPDIF]) |
368 | sprintf(buf: dst, fmt: "SPDIF %d" , i - offsets[SCARLETT_OFFSET_SPDIF]); |
369 | else if (i > offsets[SCARLETT_OFFSET_ANALOG]) |
370 | sprintf(buf: dst, fmt: "Analog %d" , i - offsets[SCARLETT_OFFSET_ANALOG]); |
371 | else if (i > offsets[SCARLETT_OFFSET_PCM]) |
372 | sprintf(buf: dst, fmt: "PCM %d" , i - offsets[SCARLETT_OFFSET_PCM]); |
373 | else |
374 | sprintf(buf: dst, fmt: "Off" ); |
375 | } |
376 | |
377 | static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, |
378 | struct snd_ctl_elem_info *uinfo) |
379 | { |
380 | struct usb_mixer_elem_info *elem = kctl->private_data; |
381 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; |
382 | unsigned int items = opt->len; |
383 | |
384 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
385 | uinfo->count = elem->channels; |
386 | uinfo->value.enumerated.items = items; |
387 | |
388 | if (uinfo->value.enumerated.item >= items) |
389 | uinfo->value.enumerated.item = items - 1; |
390 | |
391 | /* generate name dynamically based on item number and offset info */ |
392 | scarlett_generate_name(i: uinfo->value.enumerated.item, |
393 | dst: uinfo->value.enumerated.name, |
394 | offsets: opt->offsets); |
395 | |
396 | return 0; |
397 | } |
398 | |
399 | static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl, |
400 | struct snd_ctl_elem_info *uinfo) |
401 | { |
402 | struct usb_mixer_elem_info *elem = kctl->private_data; |
403 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; |
404 | |
405 | return snd_ctl_enum_info(info: uinfo, channels: elem->channels, items: opt->len, |
406 | names: (const char * const *)opt->names); |
407 | } |
408 | |
409 | static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl, |
410 | struct snd_ctl_elem_value *ucontrol) |
411 | { |
412 | struct usb_mixer_elem_info *elem = kctl->private_data; |
413 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; |
414 | int err, val; |
415 | |
416 | err = snd_usb_get_cur_mix_value(cval: elem, channel: 0, index: 0, value: &val); |
417 | if (err < 0) |
418 | return err; |
419 | |
420 | val = clamp(val - opt->start, 0, opt->len-1); |
421 | |
422 | ucontrol->value.enumerated.item[0] = val; |
423 | |
424 | return 0; |
425 | } |
426 | |
427 | static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, |
428 | struct snd_ctl_elem_value *ucontrol) |
429 | { |
430 | struct usb_mixer_elem_info *elem = kctl->private_data; |
431 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; |
432 | int err, oval, val; |
433 | |
434 | err = snd_usb_get_cur_mix_value(cval: elem, channel: 0, index: 0, value: &oval); |
435 | if (err < 0) |
436 | return err; |
437 | |
438 | val = ucontrol->value.integer.value[0]; |
439 | val = val + opt->start; |
440 | if (val != oval) { |
441 | snd_usb_set_cur_mix_value(cval: elem, channel: 0, index: 0, value: val); |
442 | return 1; |
443 | } |
444 | return 0; |
445 | } |
446 | |
447 | static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) |
448 | { |
449 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
450 | |
451 | if (elem->cached) |
452 | snd_usb_set_cur_mix_value(cval: elem, channel: 0, index: 0, value: *elem->cache_val); |
453 | return 0; |
454 | } |
455 | |
456 | static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, |
457 | struct snd_ctl_elem_value *ucontrol) |
458 | { |
459 | struct usb_mixer_elem_info *elem = kctl->private_data; |
460 | struct snd_usb_audio *chip = elem->head.mixer->chip; |
461 | unsigned char buf[2 * MAX_CHANNELS] = {0, }; |
462 | int wValue = (elem->control << 8) | elem->idx_off; |
463 | int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); |
464 | int err; |
465 | |
466 | err = snd_usb_ctl_msg(dev: chip->dev, |
467 | usb_rcvctrlpipe(chip->dev, 0), |
468 | UAC2_CS_MEM, |
469 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | |
470 | USB_DIR_IN, value: wValue, index: idx, data: buf, size: elem->channels); |
471 | if (err < 0) |
472 | return err; |
473 | |
474 | ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1); |
475 | return 0; |
476 | } |
477 | |
478 | static const struct snd_kcontrol_new usb_scarlett_ctl_switch = { |
479 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
480 | .name = "" , |
481 | .info = scarlett_ctl_switch_info, |
482 | .get = scarlett_ctl_switch_get, |
483 | .put = scarlett_ctl_switch_put, |
484 | }; |
485 | |
486 | static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); |
487 | |
488 | static const struct snd_kcontrol_new usb_scarlett_ctl = { |
489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
490 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
491 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
492 | .name = "" , |
493 | .info = scarlett_ctl_info, |
494 | .get = scarlett_ctl_get, |
495 | .put = scarlett_ctl_put, |
496 | .private_value = 6, /* max value */ |
497 | .tlv = { .p = db_scale_scarlett_gain } |
498 | }; |
499 | |
500 | static const struct snd_kcontrol_new usb_scarlett_ctl_master = { |
501 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
502 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
503 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
504 | .name = "" , |
505 | .info = scarlett_ctl_info, |
506 | .get = scarlett_ctl_get, |
507 | .put = scarlett_ctl_put, |
508 | .private_value = 6, /* max value */ |
509 | .tlv = { .p = db_scale_scarlett_gain } |
510 | }; |
511 | |
512 | static const struct snd_kcontrol_new usb_scarlett_ctl_enum = { |
513 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
514 | .name = "" , |
515 | .info = scarlett_ctl_enum_info, |
516 | .get = scarlett_ctl_enum_get, |
517 | .put = scarlett_ctl_enum_put, |
518 | }; |
519 | |
520 | static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { |
521 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
522 | .name = "" , |
523 | .info = scarlett_ctl_enum_dynamic_info, |
524 | .get = scarlett_ctl_enum_get, |
525 | .put = scarlett_ctl_enum_put, |
526 | }; |
527 | |
528 | static const struct snd_kcontrol_new usb_scarlett_ctl_sync = { |
529 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
530 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, |
531 | .name = "" , |
532 | .info = scarlett_ctl_enum_info, |
533 | .get = scarlett_ctl_meter_get, |
534 | }; |
535 | |
536 | static int add_new_ctl(struct usb_mixer_interface *mixer, |
537 | const struct snd_kcontrol_new *ncontrol, |
538 | usb_mixer_elem_resume_func_t resume, |
539 | int index, int offset, int num, |
540 | int val_type, int channels, const char *name, |
541 | const struct scarlett_mixer_elem_enum_info *opt, |
542 | struct usb_mixer_elem_info **elem_ret |
543 | ) |
544 | { |
545 | struct snd_kcontrol *kctl; |
546 | struct usb_mixer_elem_info *elem; |
547 | int err; |
548 | |
549 | elem = kzalloc(size: sizeof(*elem), GFP_KERNEL); |
550 | if (!elem) |
551 | return -ENOMEM; |
552 | |
553 | elem->head.mixer = mixer; |
554 | elem->head.resume = resume; |
555 | elem->control = offset; |
556 | elem->idx_off = num; |
557 | elem->head.id = index; |
558 | elem->val_type = val_type; |
559 | |
560 | elem->channels = channels; |
561 | |
562 | /* add scarlett_mixer_elem_enum_info struct */ |
563 | elem->private_data = (void *)opt; |
564 | |
565 | kctl = snd_ctl_new1(kcontrolnew: ncontrol, private_data: elem); |
566 | if (!kctl) { |
567 | kfree(objp: elem); |
568 | return -ENOMEM; |
569 | } |
570 | kctl->private_free = snd_usb_mixer_elem_free; |
571 | |
572 | strscpy(p: kctl->id.name, q: name, size: sizeof(kctl->id.name)); |
573 | |
574 | err = snd_usb_mixer_add_control(&elem->head, kctl); |
575 | if (err < 0) |
576 | return err; |
577 | |
578 | if (elem_ret) |
579 | *elem_ret = elem; |
580 | |
581 | return 0; |
582 | } |
583 | |
584 | static int add_output_ctls(struct usb_mixer_interface *mixer, |
585 | int index, const char *name, |
586 | const struct scarlett_device_info *info) |
587 | { |
588 | int err; |
589 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
590 | struct usb_mixer_elem_info *elem; |
591 | |
592 | /* Add mute switch */ |
593 | snprintf(buf: mx, size: sizeof(mx), fmt: "Master %d (%s) Playback Switch" , |
594 | index + 1, name); |
595 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_switch, |
596 | resume: scarlett_ctl_resume, index: 0x0a, offset: 0x01, |
597 | num: 2*index+1, val_type: USB_MIXER_S16, channels: 2, name: mx, NULL, elem_ret: &elem); |
598 | if (err < 0) |
599 | return err; |
600 | |
601 | /* Add volume control and initialize to 0 */ |
602 | snprintf(buf: mx, size: sizeof(mx), fmt: "Master %d (%s) Playback Volume" , |
603 | index + 1, name); |
604 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_master, |
605 | resume: scarlett_ctl_resume, index: 0x0a, offset: 0x02, |
606 | num: 2*index+1, val_type: USB_MIXER_S16, channels: 2, name: mx, NULL, elem_ret: &elem); |
607 | if (err < 0) |
608 | return err; |
609 | |
610 | /* Add L channel source playback enumeration */ |
611 | snprintf(buf: mx, size: sizeof(mx), fmt: "Master %dL (%s) Source Playback Enum" , |
612 | index + 1, name); |
613 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_dynamic_enum, |
614 | resume: scarlett_ctl_enum_resume, index: 0x33, offset: 0x00, |
615 | num: 2*index, val_type: USB_MIXER_S16, channels: 1, name: mx, opt: &info->opt_master, |
616 | elem_ret: &elem); |
617 | if (err < 0) |
618 | return err; |
619 | |
620 | /* Add R channel source playback enumeration */ |
621 | snprintf(buf: mx, size: sizeof(mx), fmt: "Master %dR (%s) Source Playback Enum" , |
622 | index + 1, name); |
623 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_dynamic_enum, |
624 | resume: scarlett_ctl_enum_resume, index: 0x33, offset: 0x00, |
625 | num: 2*index+1, val_type: USB_MIXER_S16, channels: 1, name: mx, opt: &info->opt_master, |
626 | elem_ret: &elem); |
627 | if (err < 0) |
628 | return err; |
629 | |
630 | return 0; |
631 | } |
632 | |
633 | /********************** device-specific config *************************/ |
634 | |
635 | /* untested... */ |
636 | static const struct scarlett_device_info s6i6_info = { |
637 | .matrix_in = 18, |
638 | .matrix_out = 8, |
639 | .input_len = 6, |
640 | .output_len = 6, |
641 | |
642 | .opt_master = { |
643 | .start = -1, |
644 | .len = 27, |
645 | .offsets = {0, 12, 16, 18, 18}, |
646 | .names = NULL |
647 | }, |
648 | |
649 | .opt_matrix = { |
650 | .start = -1, |
651 | .len = 19, |
652 | .offsets = {0, 12, 16, 18, 18}, |
653 | .names = NULL |
654 | }, |
655 | |
656 | .num_controls = 9, |
657 | .controls = { |
658 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, |
659 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, |
660 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, |
661 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
662 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
663 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
664 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
665 | { .num = 3, .type = SCARLETT_SWITCH_GAIN, .name = NULL}, |
666 | { .num = 4, .type = SCARLETT_SWITCH_GAIN, .name = NULL}, |
667 | }, |
668 | |
669 | .matrix_mux_init = { |
670 | 12, 13, 14, 15, /* Analog -> 1..4 */ |
671 | 16, 17, /* SPDIF -> 5,6 */ |
672 | 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ |
673 | 8, 9, 10, 11 |
674 | } |
675 | }; |
676 | |
677 | /* untested... */ |
678 | static const struct scarlett_device_info s8i6_info = { |
679 | .matrix_in = 18, |
680 | .matrix_out = 6, |
681 | .input_len = 8, |
682 | .output_len = 6, |
683 | |
684 | .opt_master = { |
685 | .start = -1, |
686 | .len = 25, |
687 | .offsets = {0, 12, 16, 18, 18}, |
688 | .names = NULL |
689 | }, |
690 | |
691 | .opt_matrix = { |
692 | .start = -1, |
693 | .len = 19, |
694 | .offsets = {0, 12, 16, 18, 18}, |
695 | .names = NULL |
696 | }, |
697 | |
698 | .num_controls = 7, |
699 | .controls = { |
700 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, |
701 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, |
702 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, |
703 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
704 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
705 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
706 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
707 | }, |
708 | |
709 | .matrix_mux_init = { |
710 | 12, 13, 14, 15, /* Analog -> 1..4 */ |
711 | 16, 17, /* SPDIF -> 5,6 */ |
712 | 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ |
713 | 8, 9, 10, 11 |
714 | } |
715 | }; |
716 | |
717 | static const struct scarlett_device_info s18i6_info = { |
718 | .matrix_in = 18, |
719 | .matrix_out = 6, |
720 | .input_len = 18, |
721 | .output_len = 6, |
722 | |
723 | .opt_master = { |
724 | .start = -1, |
725 | .len = 31, |
726 | .offsets = {0, 6, 14, 16, 24}, |
727 | .names = NULL, |
728 | }, |
729 | |
730 | .opt_matrix = { |
731 | .start = -1, |
732 | .len = 25, |
733 | .offsets = {0, 6, 14, 16, 24}, |
734 | .names = NULL, |
735 | }, |
736 | |
737 | .num_controls = 5, |
738 | .controls = { |
739 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, |
740 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, |
741 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, |
742 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
743 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
744 | }, |
745 | |
746 | .matrix_mux_init = { |
747 | 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */ |
748 | 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */ |
749 | 14, 15, /* SPDIF -> 15,16 */ |
750 | 0, 1 /* PCM[1,2] -> 17,18 */ |
751 | } |
752 | }; |
753 | |
754 | static const struct scarlett_device_info s18i8_info = { |
755 | .matrix_in = 18, |
756 | .matrix_out = 8, |
757 | .input_len = 18, |
758 | .output_len = 8, |
759 | |
760 | .opt_master = { |
761 | .start = -1, |
762 | .len = 35, |
763 | .offsets = {0, 8, 16, 18, 26}, |
764 | .names = NULL |
765 | }, |
766 | |
767 | .opt_matrix = { |
768 | .start = -1, |
769 | .len = 27, |
770 | .offsets = {0, 8, 16, 18, 26}, |
771 | .names = NULL |
772 | }, |
773 | |
774 | .num_controls = 10, |
775 | .controls = { |
776 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, |
777 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" }, |
778 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" }, |
779 | { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, |
780 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
781 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
782 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
783 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
784 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
785 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
786 | }, |
787 | |
788 | .matrix_mux_init = { |
789 | 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */ |
790 | 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */ |
791 | 16, 17, /* SPDIF -> 15,16 */ |
792 | 0, 1 /* PCM[1,2] -> 17,18 */ |
793 | } |
794 | }; |
795 | |
796 | static const struct scarlett_device_info s18i20_info = { |
797 | .matrix_in = 18, |
798 | .matrix_out = 8, |
799 | .input_len = 18, |
800 | .output_len = 20, |
801 | |
802 | .opt_master = { |
803 | .start = -1, |
804 | .len = 47, |
805 | .offsets = {0, 20, 28, 30, 38}, |
806 | .names = NULL |
807 | }, |
808 | |
809 | .opt_matrix = { |
810 | .start = -1, |
811 | .len = 39, |
812 | .offsets = {0, 20, 28, 30, 38}, |
813 | .names = NULL |
814 | }, |
815 | |
816 | .num_controls = 10, |
817 | .controls = { |
818 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, |
819 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" }, |
820 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" }, |
821 | { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" }, |
822 | { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" }, |
823 | { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, |
824 | { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" }, |
825 | { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" }, |
826 | { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" }, |
827 | { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" }, |
828 | /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
829 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
830 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, |
831 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
832 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, |
833 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/ |
834 | }, |
835 | |
836 | .matrix_mux_init = { |
837 | 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */ |
838 | 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */ |
839 | 28, 29, /* SPDIF -> 15,16 */ |
840 | 0, 1 /* PCM[1,2] -> 17,18 */ |
841 | } |
842 | }; |
843 | |
844 | |
845 | static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, |
846 | const struct scarlett_device_info *info) |
847 | { |
848 | int i, err; |
849 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
850 | const struct scarlett_mixer_control *ctl; |
851 | struct usb_mixer_elem_info *elem; |
852 | |
853 | /* create master switch and playback volume */ |
854 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_switch, |
855 | resume: scarlett_ctl_resume, index: 0x0a, offset: 0x01, num: 0, |
856 | val_type: USB_MIXER_S16, channels: 1, name: "Master Playback Switch" , NULL, |
857 | elem_ret: &elem); |
858 | if (err < 0) |
859 | return err; |
860 | |
861 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_master, |
862 | resume: scarlett_ctl_resume, index: 0x0a, offset: 0x02, num: 0, |
863 | val_type: USB_MIXER_S16, channels: 1, name: "Master Playback Volume" , NULL, |
864 | elem_ret: &elem); |
865 | if (err < 0) |
866 | return err; |
867 | |
868 | /* iterate through controls in info struct and create each one */ |
869 | for (i = 0; i < info->num_controls; i++) { |
870 | ctl = &info->controls[i]; |
871 | |
872 | switch (ctl->type) { |
873 | case SCARLETT_OUTPUTS: |
874 | err = add_output_ctls(mixer, index: ctl->num, name: ctl->name, info); |
875 | if (err < 0) |
876 | return err; |
877 | break; |
878 | case SCARLETT_SWITCH_IMPEDANCE: |
879 | sprintf(buf: mx, fmt: "Input %d Impedance Switch" , ctl->num); |
880 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_enum, |
881 | resume: scarlett_ctl_enum_resume, index: 0x01, |
882 | offset: 0x09, num: ctl->num, val_type: USB_MIXER_S16, channels: 1, name: mx, |
883 | opt: &opt_impedance, elem_ret: &elem); |
884 | if (err < 0) |
885 | return err; |
886 | break; |
887 | case SCARLETT_SWITCH_PAD: |
888 | sprintf(buf: mx, fmt: "Input %d Pad Switch" , ctl->num); |
889 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_enum, |
890 | resume: scarlett_ctl_enum_resume, index: 0x01, |
891 | offset: 0x0b, num: ctl->num, val_type: USB_MIXER_S16, channels: 1, name: mx, |
892 | opt: &opt_pad, elem_ret: &elem); |
893 | if (err < 0) |
894 | return err; |
895 | break; |
896 | case SCARLETT_SWITCH_GAIN: |
897 | sprintf(buf: mx, fmt: "Input %d Gain Switch" , ctl->num); |
898 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_enum, |
899 | resume: scarlett_ctl_enum_resume, index: 0x01, |
900 | offset: 0x08, num: ctl->num, val_type: USB_MIXER_S16, channels: 1, name: mx, |
901 | opt: &opt_gain, elem_ret: &elem); |
902 | if (err < 0) |
903 | return err; |
904 | break; |
905 | } |
906 | } |
907 | |
908 | return 0; |
909 | } |
910 | |
911 | /* |
912 | * Create and initialize a mixer for the Focusrite(R) Scarlett |
913 | */ |
914 | int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) |
915 | { |
916 | int err, i, o; |
917 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
918 | const struct scarlett_device_info *info; |
919 | struct usb_mixer_elem_info *elem; |
920 | static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' }; |
921 | |
922 | /* only use UAC_VERSION_2 */ |
923 | if (!mixer->protocol) |
924 | return 0; |
925 | |
926 | switch (mixer->chip->usb_id) { |
927 | case USB_ID(0x1235, 0x8012): |
928 | info = &s6i6_info; |
929 | break; |
930 | case USB_ID(0x1235, 0x8002): |
931 | info = &s8i6_info; |
932 | break; |
933 | case USB_ID(0x1235, 0x8004): |
934 | info = &s18i6_info; |
935 | break; |
936 | case USB_ID(0x1235, 0x8014): |
937 | info = &s18i8_info; |
938 | break; |
939 | case USB_ID(0x1235, 0x800c): |
940 | info = &s18i20_info; |
941 | break; |
942 | default: /* device not (yet) supported */ |
943 | return -EINVAL; |
944 | } |
945 | |
946 | /* generic function to create controls */ |
947 | err = scarlett_controls_create_generic(mixer, info); |
948 | if (err < 0) |
949 | return err; |
950 | |
951 | /* setup matrix controls */ |
952 | for (i = 0; i < info->matrix_in; i++) { |
953 | snprintf(buf: mx, size: sizeof(mx), fmt: "Matrix %02d Input Playback Route" , |
954 | i+1); |
955 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_dynamic_enum, |
956 | resume: scarlett_ctl_enum_resume, index: 0x32, |
957 | offset: 0x06, num: i, val_type: USB_MIXER_S16, channels: 1, name: mx, |
958 | opt: &info->opt_matrix, elem_ret: &elem); |
959 | if (err < 0) |
960 | return err; |
961 | |
962 | for (o = 0; o < info->matrix_out; o++) { |
963 | sprintf(buf: mx, fmt: "Matrix %02d Mix %c Playback Volume" , i+1, |
964 | o+'A'); |
965 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl, |
966 | resume: scarlett_ctl_resume, index: 0x3c, offset: 0x00, |
967 | num: (i << 3) + (o & 0x07), val_type: USB_MIXER_S16, |
968 | channels: 1, name: mx, NULL, elem_ret: &elem); |
969 | if (err < 0) |
970 | return err; |
971 | |
972 | } |
973 | } |
974 | |
975 | for (i = 0; i < info->input_len; i++) { |
976 | snprintf(buf: mx, size: sizeof(mx), fmt: "Input Source %02d Capture Route" , |
977 | i+1); |
978 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_dynamic_enum, |
979 | resume: scarlett_ctl_enum_resume, index: 0x34, |
980 | offset: 0x00, num: i, val_type: USB_MIXER_S16, channels: 1, name: mx, |
981 | opt: &info->opt_master, elem_ret: &elem); |
982 | if (err < 0) |
983 | return err; |
984 | } |
985 | |
986 | /* val_len == 1 needed here */ |
987 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_enum, |
988 | resume: scarlett_ctl_enum_resume, index: 0x28, offset: 0x01, num: 0, |
989 | val_type: USB_MIXER_U8, channels: 1, name: "Sample Clock Source" , |
990 | opt: &opt_clock, elem_ret: &elem); |
991 | if (err < 0) |
992 | return err; |
993 | |
994 | /* val_len == 1 and UAC2_CS_MEM */ |
995 | err = add_new_ctl(mixer, ncontrol: &usb_scarlett_ctl_sync, NULL, index: 0x3c, offset: 0x00, num: 2, |
996 | val_type: USB_MIXER_U8, channels: 1, name: "Sample Clock Sync Status" , |
997 | opt: &opt_sync, elem_ret: &elem); |
998 | if (err < 0) |
999 | return err; |
1000 | |
1001 | /* initialize sampling rate to 48000 */ |
1002 | err = snd_usb_ctl_msg(dev: mixer->chip->dev, |
1003 | usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, |
1004 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | |
1005 | USB_DIR_OUT, value: 0x0100, index: snd_usb_ctrl_intf(chip: mixer->chip) | |
1006 | (0x29 << 8), data: sample_rate_buffer, size: 4); |
1007 | if (err < 0) |
1008 | return err; |
1009 | |
1010 | return err; |
1011 | } |
1012 | |