Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
76b188c4 CA |
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> | |
76b188c4 CA |
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 arount 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 | }; | |
146 | ||
147 | enum { | |
148 | SCARLETT_OFFSET_PCM = 0, | |
149 | SCARLETT_OFFSET_ANALOG = 1, | |
150 | SCARLETT_OFFSET_SPDIF = 2, | |
151 | SCARLETT_OFFSET_ADAT = 3, | |
152 | SCARLETT_OFFSET_MIX = 4, | |
153 | }; | |
154 | ||
155 | struct scarlett_mixer_elem_enum_info { | |
156 | int start; | |
157 | int len; | |
158 | int offsets[SND_SCARLETT_OFFSETS_MAX]; | |
159 | char const * const *names; | |
160 | }; | |
161 | ||
162 | struct scarlett_mixer_control { | |
163 | unsigned char num; | |
164 | unsigned char type; | |
165 | const char *name; | |
166 | }; | |
167 | ||
168 | struct scarlett_device_info { | |
169 | int matrix_in; | |
170 | int matrix_out; | |
171 | int input_len; | |
172 | int output_len; | |
173 | ||
174 | struct scarlett_mixer_elem_enum_info opt_master; | |
175 | struct scarlett_mixer_elem_enum_info opt_matrix; | |
176 | ||
177 | /* initial values for matrix mux */ | |
178 | int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX]; | |
179 | ||
180 | int num_controls; /* number of items in controls */ | |
181 | const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX]; | |
182 | }; | |
183 | ||
184 | /********************** Enum Strings *************************/ | |
185 | ||
186 | static const struct scarlett_mixer_elem_enum_info opt_pad = { | |
187 | .start = 0, | |
188 | .len = 2, | |
189 | .offsets = {}, | |
190 | .names = (char const * const []){ | |
191 | "0dB", "-10dB" | |
192 | } | |
193 | }; | |
194 | ||
195 | static const struct scarlett_mixer_elem_enum_info opt_impedance = { | |
196 | .start = 0, | |
197 | .len = 2, | |
198 | .offsets = {}, | |
199 | .names = (char const * const []){ | |
200 | "Line", "Hi-Z" | |
201 | } | |
202 | }; | |
203 | ||
204 | static const struct scarlett_mixer_elem_enum_info opt_clock = { | |
205 | .start = 1, | |
206 | .len = 3, | |
207 | .offsets = {}, | |
208 | .names = (char const * const []){ | |
209 | "Internal", "SPDIF", "ADAT" | |
210 | } | |
211 | }; | |
212 | ||
213 | static const struct scarlett_mixer_elem_enum_info opt_sync = { | |
214 | .start = 0, | |
215 | .len = 2, | |
216 | .offsets = {}, | |
217 | .names = (char const * const []){ | |
218 | "No Lock", "Locked" | |
219 | } | |
220 | }; | |
221 | ||
222 | static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl, | |
223 | struct snd_ctl_elem_info *uinfo) | |
224 | { | |
225 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
226 | ||
227 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |
228 | uinfo->count = elem->channels; | |
229 | uinfo->value.integer.min = 0; | |
230 | uinfo->value.integer.max = 1; | |
231 | return 0; | |
232 | } | |
233 | ||
234 | static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl, | |
235 | struct snd_ctl_elem_value *ucontrol) | |
236 | { | |
237 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
238 | int i, err, val; | |
239 | ||
240 | for (i = 0; i < elem->channels; i++) { | |
241 | err = snd_usb_get_cur_mix_value(elem, i, i, &val); | |
242 | if (err < 0) | |
243 | return err; | |
244 | ||
245 | val = !val; /* invert mute logic for mixer */ | |
246 | ucontrol->value.integer.value[i] = val; | |
247 | } | |
248 | ||
249 | return 0; | |
250 | } | |
251 | ||
252 | static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, | |
253 | struct snd_ctl_elem_value *ucontrol) | |
254 | { | |
255 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
256 | int i, changed = 0; | |
257 | int err, oval, val; | |
258 | ||
259 | for (i = 0; i < elem->channels; i++) { | |
260 | err = snd_usb_get_cur_mix_value(elem, i, i, &oval); | |
261 | if (err < 0) | |
262 | return err; | |
263 | ||
264 | val = ucontrol->value.integer.value[i]; | |
265 | val = !val; | |
266 | if (oval != val) { | |
267 | err = snd_usb_set_cur_mix_value(elem, i, i, val); | |
268 | if (err < 0) | |
269 | return err; | |
270 | ||
271 | changed = 1; | |
272 | } | |
273 | } | |
274 | ||
275 | return changed; | |
276 | } | |
277 | ||
b61f90ea TI |
278 | static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) |
279 | { | |
8c558076 | 280 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
b61f90ea TI |
281 | int i; |
282 | ||
283 | for (i = 0; i < elem->channels; i++) | |
284 | if (elem->cached & (1 << i)) | |
285 | snd_usb_set_cur_mix_value(elem, i, i, | |
286 | elem->cache_val[i]); | |
287 | return 0; | |
288 | } | |
289 | ||
76b188c4 CA |
290 | static int scarlett_ctl_info(struct snd_kcontrol *kctl, |
291 | struct snd_ctl_elem_info *uinfo) | |
292 | { | |
293 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
294 | ||
295 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
296 | uinfo->count = elem->channels; | |
297 | uinfo->value.integer.min = 0; | |
298 | uinfo->value.integer.max = (int)kctl->private_value + | |
299 | SND_SCARLETT_LEVEL_BIAS; | |
300 | uinfo->value.integer.step = 1; | |
301 | return 0; | |
302 | } | |
303 | ||
304 | static int scarlett_ctl_get(struct snd_kcontrol *kctl, | |
305 | struct snd_ctl_elem_value *ucontrol) | |
306 | { | |
307 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
308 | int i, err, val; | |
309 | ||
310 | for (i = 0; i < elem->channels; i++) { | |
311 | err = snd_usb_get_cur_mix_value(elem, i, i, &val); | |
312 | if (err < 0) | |
313 | return err; | |
314 | ||
315 | val = clamp(val / 256, -128, (int)kctl->private_value) + | |
316 | SND_SCARLETT_LEVEL_BIAS; | |
317 | ucontrol->value.integer.value[i] = val; | |
318 | } | |
319 | ||
320 | return 0; | |
321 | } | |
322 | ||
323 | static int scarlett_ctl_put(struct snd_kcontrol *kctl, | |
324 | struct snd_ctl_elem_value *ucontrol) | |
325 | { | |
326 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
327 | int i, changed = 0; | |
328 | int err, oval, val; | |
329 | ||
330 | for (i = 0; i < elem->channels; i++) { | |
331 | err = snd_usb_get_cur_mix_value(elem, i, i, &oval); | |
332 | if (err < 0) | |
333 | return err; | |
334 | ||
335 | val = ucontrol->value.integer.value[i] - | |
336 | SND_SCARLETT_LEVEL_BIAS; | |
337 | val = val * 256; | |
338 | if (oval != val) { | |
339 | err = snd_usb_set_cur_mix_value(elem, i, i, val); | |
340 | if (err < 0) | |
341 | return err; | |
342 | ||
343 | changed = 1; | |
344 | } | |
345 | } | |
346 | ||
347 | return changed; | |
348 | } | |
349 | ||
350 | static void scarlett_generate_name(int i, char *dst, int offsets[]) | |
351 | { | |
352 | if (i > offsets[SCARLETT_OFFSET_MIX]) | |
353 | sprintf(dst, "Mix %c", | |
354 | 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); | |
355 | else if (i > offsets[SCARLETT_OFFSET_ADAT]) | |
356 | sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]); | |
357 | else if (i > offsets[SCARLETT_OFFSET_SPDIF]) | |
358 | sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]); | |
359 | else if (i > offsets[SCARLETT_OFFSET_ANALOG]) | |
360 | sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]); | |
361 | else if (i > offsets[SCARLETT_OFFSET_PCM]) | |
362 | sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]); | |
363 | else | |
364 | sprintf(dst, "Off"); | |
365 | } | |
366 | ||
367 | static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, | |
368 | struct snd_ctl_elem_info *uinfo) | |
369 | { | |
370 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
371 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; | |
372 | unsigned int items = opt->len; | |
373 | ||
374 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
375 | uinfo->count = elem->channels; | |
376 | uinfo->value.enumerated.items = items; | |
377 | ||
378 | if (uinfo->value.enumerated.item >= items) | |
379 | uinfo->value.enumerated.item = items - 1; | |
380 | ||
381 | /* generate name dynamically based on item number and offset info */ | |
382 | scarlett_generate_name(uinfo->value.enumerated.item, | |
383 | uinfo->value.enumerated.name, | |
384 | opt->offsets); | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl, | |
390 | struct snd_ctl_elem_info *uinfo) | |
391 | { | |
392 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
393 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; | |
394 | ||
395 | return snd_ctl_enum_info(uinfo, elem->channels, opt->len, | |
396 | (const char * const *)opt->names); | |
397 | } | |
398 | ||
399 | static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl, | |
400 | struct snd_ctl_elem_value *ucontrol) | |
401 | { | |
402 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
403 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; | |
404 | int err, val; | |
405 | ||
406 | err = snd_usb_get_cur_mix_value(elem, 0, 0, &val); | |
407 | if (err < 0) | |
408 | return err; | |
409 | ||
410 | val = clamp(val - opt->start, 0, opt->len-1); | |
411 | ||
412 | ucontrol->value.enumerated.item[0] = val; | |
413 | ||
414 | return 0; | |
415 | } | |
416 | ||
417 | static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, | |
418 | struct snd_ctl_elem_value *ucontrol) | |
419 | { | |
420 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
421 | struct scarlett_mixer_elem_enum_info *opt = elem->private_data; | |
422 | int err, oval, val; | |
423 | ||
424 | err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval); | |
425 | if (err < 0) | |
426 | return err; | |
427 | ||
428 | val = ucontrol->value.integer.value[0]; | |
429 | val = val + opt->start; | |
430 | if (val != oval) { | |
431 | snd_usb_set_cur_mix_value(elem, 0, 0, val); | |
432 | return 1; | |
433 | } | |
434 | return 0; | |
435 | } | |
436 | ||
b61f90ea TI |
437 | static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) |
438 | { | |
8c558076 | 439 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
b61f90ea TI |
440 | |
441 | if (elem->cached) | |
442 | snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); | |
443 | return 0; | |
444 | } | |
445 | ||
76b188c4 CA |
446 | static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, |
447 | struct snd_ctl_elem_value *ucontrol) | |
448 | { | |
449 | struct usb_mixer_elem_info *elem = kctl->private_data; | |
3360b84b | 450 | struct snd_usb_audio *chip = elem->head.mixer->chip; |
76b188c4 CA |
451 | unsigned char buf[2 * MAX_CHANNELS] = {0, }; |
452 | int wValue = (elem->control << 8) | elem->idx_off; | |
3360b84b | 453 | int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); |
76b188c4 CA |
454 | int err; |
455 | ||
456 | err = snd_usb_ctl_msg(chip->dev, | |
457 | usb_rcvctrlpipe(chip->dev, 0), | |
458 | UAC2_CS_MEM, | |
459 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | | |
460 | USB_DIR_IN, wValue, idx, buf, elem->channels); | |
461 | if (err < 0) | |
462 | return err; | |
463 | ||
464 | ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1); | |
465 | return 0; | |
466 | } | |
467 | ||
04bab350 | 468 | static const struct snd_kcontrol_new usb_scarlett_ctl_switch = { |
76b188c4 CA |
469 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
470 | .name = "", | |
471 | .info = scarlett_ctl_switch_info, | |
472 | .get = scarlett_ctl_switch_get, | |
473 | .put = scarlett_ctl_switch_put, | |
474 | }; | |
475 | ||
476 | static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); | |
477 | ||
04bab350 | 478 | static const struct snd_kcontrol_new usb_scarlett_ctl = { |
76b188c4 CA |
479 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
480 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
481 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
482 | .name = "", | |
483 | .info = scarlett_ctl_info, | |
484 | .get = scarlett_ctl_get, | |
485 | .put = scarlett_ctl_put, | |
486 | .private_value = 6, /* max value */ | |
487 | .tlv = { .p = db_scale_scarlett_gain } | |
488 | }; | |
489 | ||
04bab350 | 490 | static const struct snd_kcontrol_new usb_scarlett_ctl_master = { |
76b188c4 CA |
491 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
492 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
493 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
494 | .name = "", | |
495 | .info = scarlett_ctl_info, | |
496 | .get = scarlett_ctl_get, | |
497 | .put = scarlett_ctl_put, | |
498 | .private_value = 6, /* max value */ | |
499 | .tlv = { .p = db_scale_scarlett_gain } | |
500 | }; | |
501 | ||
04bab350 | 502 | static const struct snd_kcontrol_new usb_scarlett_ctl_enum = { |
76b188c4 CA |
503 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
504 | .name = "", | |
505 | .info = scarlett_ctl_enum_info, | |
506 | .get = scarlett_ctl_enum_get, | |
507 | .put = scarlett_ctl_enum_put, | |
508 | }; | |
509 | ||
04bab350 | 510 | static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { |
76b188c4 CA |
511 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
512 | .name = "", | |
513 | .info = scarlett_ctl_enum_dynamic_info, | |
514 | .get = scarlett_ctl_enum_get, | |
515 | .put = scarlett_ctl_enum_put, | |
516 | }; | |
517 | ||
04bab350 | 518 | static const struct snd_kcontrol_new usb_scarlett_ctl_sync = { |
76b188c4 CA |
519 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
520 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
521 | .name = "", | |
522 | .info = scarlett_ctl_enum_info, | |
523 | .get = scarlett_ctl_meter_get, | |
524 | }; | |
525 | ||
526 | static int add_new_ctl(struct usb_mixer_interface *mixer, | |
527 | const struct snd_kcontrol_new *ncontrol, | |
b61f90ea | 528 | usb_mixer_elem_resume_func_t resume, |
76b188c4 CA |
529 | int index, int offset, int num, |
530 | int val_type, int channels, const char *name, | |
531 | const struct scarlett_mixer_elem_enum_info *opt, | |
532 | struct usb_mixer_elem_info **elem_ret | |
533 | ) | |
534 | { | |
535 | struct snd_kcontrol *kctl; | |
536 | struct usb_mixer_elem_info *elem; | |
537 | int err; | |
538 | ||
539 | elem = kzalloc(sizeof(*elem), GFP_KERNEL); | |
540 | if (!elem) | |
541 | return -ENOMEM; | |
542 | ||
3360b84b | 543 | elem->head.mixer = mixer; |
b61f90ea | 544 | elem->head.resume = resume; |
76b188c4 CA |
545 | elem->control = offset; |
546 | elem->idx_off = num; | |
3360b84b | 547 | elem->head.id = index; |
76b188c4 CA |
548 | elem->val_type = val_type; |
549 | ||
550 | elem->channels = channels; | |
551 | ||
552 | /* add scarlett_mixer_elem_enum_info struct */ | |
553 | elem->private_data = (void *)opt; | |
554 | ||
555 | kctl = snd_ctl_new1(ncontrol, elem); | |
556 | if (!kctl) { | |
557 | kfree(elem); | |
558 | return -ENOMEM; | |
559 | } | |
560 | kctl->private_free = snd_usb_mixer_elem_free; | |
561 | ||
562 | strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); | |
563 | ||
b61f90ea | 564 | err = snd_usb_mixer_add_control(&elem->head, kctl); |
76b188c4 CA |
565 | if (err < 0) |
566 | return err; | |
567 | ||
568 | if (elem_ret) | |
569 | *elem_ret = elem; | |
570 | ||
571 | return 0; | |
572 | } | |
573 | ||
574 | static int add_output_ctls(struct usb_mixer_interface *mixer, | |
575 | int index, const char *name, | |
576 | const struct scarlett_device_info *info) | |
577 | { | |
578 | int err; | |
579 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | |
580 | struct usb_mixer_elem_info *elem; | |
581 | ||
582 | /* Add mute switch */ | |
583 | snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch", | |
584 | index + 1, name); | |
b61f90ea TI |
585 | err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, |
586 | scarlett_ctl_resume, 0x0a, 0x01, | |
76b188c4 CA |
587 | 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); |
588 | if (err < 0) | |
589 | return err; | |
590 | ||
591 | /* Add volume control and initialize to 0 */ | |
592 | snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume", | |
593 | index + 1, name); | |
b61f90ea TI |
594 | err = add_new_ctl(mixer, &usb_scarlett_ctl_master, |
595 | scarlett_ctl_resume, 0x0a, 0x02, | |
76b188c4 CA |
596 | 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); |
597 | if (err < 0) | |
598 | return err; | |
599 | ||
600 | /* Add L channel source playback enumeration */ | |
601 | snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum", | |
602 | index + 1, name); | |
b61f90ea TI |
603 | err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, |
604 | scarlett_ctl_enum_resume, 0x33, 0x00, | |
76b188c4 CA |
605 | 2*index, USB_MIXER_S16, 1, mx, &info->opt_master, |
606 | &elem); | |
607 | if (err < 0) | |
608 | return err; | |
609 | ||
610 | /* Add R channel source playback enumeration */ | |
611 | snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum", | |
612 | index + 1, name); | |
b61f90ea TI |
613 | err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, |
614 | scarlett_ctl_enum_resume, 0x33, 0x00, | |
76b188c4 CA |
615 | 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master, |
616 | &elem); | |
617 | if (err < 0) | |
618 | return err; | |
619 | ||
620 | return 0; | |
621 | } | |
622 | ||
623 | /********************** device-specific config *************************/ | |
624 | ||
625 | /* untested... */ | |
626 | static struct scarlett_device_info s6i6_info = { | |
627 | .matrix_in = 18, | |
628 | .matrix_out = 8, | |
629 | .input_len = 6, | |
630 | .output_len = 6, | |
631 | ||
632 | .opt_master = { | |
633 | .start = -1, | |
634 | .len = 27, | |
635 | .offsets = {0, 12, 16, 18, 18}, | |
636 | .names = NULL | |
637 | }, | |
638 | ||
639 | .opt_matrix = { | |
640 | .start = -1, | |
641 | .len = 19, | |
642 | .offsets = {0, 12, 16, 18, 18}, | |
643 | .names = NULL | |
644 | }, | |
645 | ||
c99b9e85 | 646 | .num_controls = 9, |
76b188c4 CA |
647 | .controls = { |
648 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, | |
649 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, | |
650 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, | |
651 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
652 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
653 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
654 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
655 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
656 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
657 | }, | |
658 | ||
659 | .matrix_mux_init = { | |
660 | 12, 13, 14, 15, /* Analog -> 1..4 */ | |
661 | 16, 17, /* SPDIF -> 5,6 */ | |
662 | 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ | |
663 | 8, 9, 10, 11 | |
664 | } | |
665 | }; | |
666 | ||
667 | /* untested... */ | |
668 | static struct scarlett_device_info s8i6_info = { | |
669 | .matrix_in = 18, | |
670 | .matrix_out = 6, | |
671 | .input_len = 8, | |
672 | .output_len = 6, | |
673 | ||
674 | .opt_master = { | |
675 | .start = -1, | |
676 | .len = 25, | |
677 | .offsets = {0, 12, 16, 18, 18}, | |
678 | .names = NULL | |
679 | }, | |
680 | ||
681 | .opt_matrix = { | |
682 | .start = -1, | |
683 | .len = 19, | |
684 | .offsets = {0, 12, 16, 18, 18}, | |
685 | .names = NULL | |
686 | }, | |
687 | ||
688 | .num_controls = 7, | |
689 | .controls = { | |
690 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, | |
691 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, | |
692 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, | |
693 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
694 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
695 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
696 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
697 | }, | |
698 | ||
699 | .matrix_mux_init = { | |
700 | 12, 13, 14, 15, /* Analog -> 1..4 */ | |
701 | 16, 17, /* SPDIF -> 5,6 */ | |
702 | 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ | |
703 | 8, 9, 10, 11 | |
704 | } | |
705 | }; | |
706 | ||
707 | static struct scarlett_device_info s18i6_info = { | |
708 | .matrix_in = 18, | |
709 | .matrix_out = 6, | |
710 | .input_len = 18, | |
711 | .output_len = 6, | |
712 | ||
713 | .opt_master = { | |
714 | .start = -1, | |
715 | .len = 31, | |
716 | .offsets = {0, 6, 14, 16, 24}, | |
717 | .names = NULL, | |
718 | }, | |
719 | ||
720 | .opt_matrix = { | |
721 | .start = -1, | |
722 | .len = 25, | |
723 | .offsets = {0, 6, 14, 16, 24}, | |
724 | .names = NULL, | |
725 | }, | |
726 | ||
727 | .num_controls = 5, | |
728 | .controls = { | |
729 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, | |
730 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, | |
731 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, | |
732 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
733 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
734 | }, | |
735 | ||
736 | .matrix_mux_init = { | |
737 | 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */ | |
738 | 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */ | |
739 | 14, 15, /* SPDIF -> 15,16 */ | |
740 | 0, 1 /* PCM[1,2] -> 17,18 */ | |
741 | } | |
742 | }; | |
743 | ||
744 | static struct scarlett_device_info s18i8_info = { | |
745 | .matrix_in = 18, | |
746 | .matrix_out = 8, | |
747 | .input_len = 18, | |
748 | .output_len = 8, | |
749 | ||
750 | .opt_master = { | |
751 | .start = -1, | |
752 | .len = 35, | |
753 | .offsets = {0, 8, 16, 18, 26}, | |
754 | .names = NULL | |
755 | }, | |
756 | ||
757 | .opt_matrix = { | |
758 | .start = -1, | |
759 | .len = 27, | |
760 | .offsets = {0, 8, 16, 18, 26}, | |
761 | .names = NULL | |
762 | }, | |
763 | ||
764 | .num_controls = 10, | |
765 | .controls = { | |
766 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, | |
767 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" }, | |
768 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" }, | |
769 | { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, | |
770 | { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
771 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
772 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
773 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
774 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
775 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
776 | }, | |
777 | ||
778 | .matrix_mux_init = { | |
779 | 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */ | |
780 | 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */ | |
781 | 16, 17, /* SPDIF -> 15,16 */ | |
782 | 0, 1 /* PCM[1,2] -> 17,18 */ | |
783 | } | |
784 | }; | |
785 | ||
786 | static struct scarlett_device_info s18i20_info = { | |
787 | .matrix_in = 18, | |
788 | .matrix_out = 8, | |
789 | .input_len = 18, | |
790 | .output_len = 20, | |
791 | ||
792 | .opt_master = { | |
793 | .start = -1, | |
794 | .len = 47, | |
795 | .offsets = {0, 20, 28, 30, 38}, | |
796 | .names = NULL | |
797 | }, | |
798 | ||
799 | .opt_matrix = { | |
800 | .start = -1, | |
801 | .len = 39, | |
802 | .offsets = {0, 20, 28, 30, 38}, | |
803 | .names = NULL | |
804 | }, | |
805 | ||
806 | .num_controls = 10, | |
807 | .controls = { | |
808 | { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, | |
809 | { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" }, | |
810 | { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" }, | |
811 | { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" }, | |
812 | { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" }, | |
813 | { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, | |
814 | { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" }, | |
815 | { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" }, | |
816 | { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" }, | |
817 | { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" }, | |
818 | /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
819 | { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
820 | { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, | |
821 | { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
822 | { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, | |
823 | { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/ | |
824 | }, | |
825 | ||
826 | .matrix_mux_init = { | |
827 | 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */ | |
828 | 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */ | |
829 | 28, 29, /* SPDIF -> 15,16 */ | |
830 | 0, 1 /* PCM[1,2] -> 17,18 */ | |
831 | } | |
832 | }; | |
833 | ||
834 | ||
835 | static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, | |
836 | struct scarlett_device_info *info) | |
837 | { | |
838 | int i, err; | |
839 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | |
840 | const struct scarlett_mixer_control *ctl; | |
841 | struct usb_mixer_elem_info *elem; | |
842 | ||
843 | /* create master switch and playback volume */ | |
b61f90ea TI |
844 | err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, |
845 | scarlett_ctl_resume, 0x0a, 0x01, 0, | |
76b188c4 CA |
846 | USB_MIXER_S16, 1, "Master Playback Switch", NULL, |
847 | &elem); | |
848 | if (err < 0) | |
849 | return err; | |
850 | ||
b61f90ea TI |
851 | err = add_new_ctl(mixer, &usb_scarlett_ctl_master, |
852 | scarlett_ctl_resume, 0x0a, 0x02, 0, | |
76b188c4 CA |
853 | USB_MIXER_S16, 1, "Master Playback Volume", NULL, |
854 | &elem); | |
855 | if (err < 0) | |
856 | return err; | |
857 | ||
858 | /* iterate through controls in info struct and create each one */ | |
859 | for (i = 0; i < info->num_controls; i++) { | |
860 | ctl = &info->controls[i]; | |
861 | ||
862 | switch (ctl->type) { | |
863 | case SCARLETT_OUTPUTS: | |
864 | err = add_output_ctls(mixer, ctl->num, ctl->name, info); | |
865 | if (err < 0) | |
866 | return err; | |
867 | break; | |
868 | case SCARLETT_SWITCH_IMPEDANCE: | |
869 | sprintf(mx, "Input %d Impedance Switch", ctl->num); | |
b61f90ea TI |
870 | err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, |
871 | scarlett_ctl_enum_resume, 0x01, | |
76b188c4 CA |
872 | 0x09, ctl->num, USB_MIXER_S16, 1, mx, |
873 | &opt_impedance, &elem); | |
874 | if (err < 0) | |
875 | return err; | |
876 | break; | |
877 | case SCARLETT_SWITCH_PAD: | |
878 | sprintf(mx, "Input %d Pad Switch", ctl->num); | |
b61f90ea TI |
879 | err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, |
880 | scarlett_ctl_enum_resume, 0x01, | |
76b188c4 CA |
881 | 0x0b, ctl->num, USB_MIXER_S16, 1, mx, |
882 | &opt_pad, &elem); | |
883 | if (err < 0) | |
884 | return err; | |
885 | break; | |
886 | } | |
887 | } | |
888 | ||
889 | return 0; | |
890 | } | |
891 | ||
892 | /* | |
893 | * Create and initialize a mixer for the Focusrite(R) Scarlett | |
894 | */ | |
895 | int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) | |
896 | { | |
897 | int err, i, o; | |
898 | char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | |
899 | struct scarlett_device_info *info; | |
900 | struct usb_mixer_elem_info *elem; | |
901 | static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' }; | |
902 | ||
903 | /* only use UAC_VERSION_2 */ | |
904 | if (!mixer->protocol) | |
905 | return 0; | |
906 | ||
907 | switch (mixer->chip->usb_id) { | |
908 | case USB_ID(0x1235, 0x8012): | |
909 | info = &s6i6_info; | |
910 | break; | |
911 | case USB_ID(0x1235, 0x8002): | |
912 | info = &s8i6_info; | |
913 | break; | |
914 | case USB_ID(0x1235, 0x8004): | |
915 | info = &s18i6_info; | |
916 | break; | |
917 | case USB_ID(0x1235, 0x8014): | |
918 | info = &s18i8_info; | |
919 | break; | |
920 | case USB_ID(0x1235, 0x800c): | |
921 | info = &s18i20_info; | |
922 | break; | |
923 | default: /* device not (yet) supported */ | |
924 | return -EINVAL; | |
925 | } | |
926 | ||
927 | /* generic function to create controls */ | |
928 | err = scarlett_controls_create_generic(mixer, info); | |
929 | if (err < 0) | |
930 | return err; | |
931 | ||
932 | /* setup matrix controls */ | |
933 | for (i = 0; i < info->matrix_in; i++) { | |
934 | snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route", | |
935 | i+1); | |
b61f90ea TI |
936 | err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, |
937 | scarlett_ctl_enum_resume, 0x32, | |
76b188c4 CA |
938 | 0x06, i, USB_MIXER_S16, 1, mx, |
939 | &info->opt_matrix, &elem); | |
940 | if (err < 0) | |
941 | return err; | |
942 | ||
943 | for (o = 0; o < info->matrix_out; o++) { | |
944 | sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1, | |
945 | o+'A'); | |
b61f90ea TI |
946 | err = add_new_ctl(mixer, &usb_scarlett_ctl, |
947 | scarlett_ctl_resume, 0x3c, 0x00, | |
76b188c4 CA |
948 | (i << 3) + (o & 0x07), USB_MIXER_S16, |
949 | 1, mx, NULL, &elem); | |
950 | if (err < 0) | |
951 | return err; | |
952 | ||
953 | } | |
954 | } | |
955 | ||
956 | for (i = 0; i < info->input_len; i++) { | |
957 | snprintf(mx, sizeof(mx), "Input Source %02d Capture Route", | |
958 | i+1); | |
b61f90ea TI |
959 | err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, |
960 | scarlett_ctl_enum_resume, 0x34, | |
76b188c4 CA |
961 | 0x00, i, USB_MIXER_S16, 1, mx, |
962 | &info->opt_master, &elem); | |
963 | if (err < 0) | |
964 | return err; | |
965 | } | |
966 | ||
967 | /* val_len == 1 needed here */ | |
b61f90ea TI |
968 | err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, |
969 | scarlett_ctl_enum_resume, 0x28, 0x01, 0, | |
76b188c4 CA |
970 | USB_MIXER_U8, 1, "Sample Clock Source", |
971 | &opt_clock, &elem); | |
972 | if (err < 0) | |
973 | return err; | |
974 | ||
975 | /* val_len == 1 and UAC2_CS_MEM */ | |
b61f90ea | 976 | err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2, |
76b188c4 CA |
977 | USB_MIXER_U8, 1, "Sample Clock Sync Status", |
978 | &opt_sync, &elem); | |
979 | if (err < 0) | |
980 | return err; | |
981 | ||
982 | /* initialize sampling rate to 48000 */ | |
983 | err = snd_usb_ctl_msg(mixer->chip->dev, | |
984 | usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, | |
985 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | | |
986 | USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) | | |
987 | (0x29 << 8), sample_rate_buffer, 4); | |
988 | if (err < 0) | |
989 | return err; | |
990 | ||
991 | return err; | |
992 | } |