Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/mixer_s1810c.c
29265 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Presonus Studio 1810c driver for ALSA
4
* Copyright (C) 2019 Nick Kossifidis <[email protected]>
5
*
6
* Based on reverse engineering of the communication protocol
7
* between the windows driver / Univeral Control (UC) program
8
* and the device, through usbmon.
9
*
10
* For now this bypasses the mixer, with all channels split,
11
* so that the software can mix with greater flexibility.
12
* It also adds controls for the 4 buttons on the front of
13
* the device.
14
*/
15
16
#include <linux/usb.h>
17
#include <linux/usb/audio-v2.h>
18
#include <linux/slab.h>
19
#include <sound/core.h>
20
#include <sound/control.h>
21
22
#include "usbaudio.h"
23
#include "mixer.h"
24
#include "mixer_quirks.h"
25
#include "helper.h"
26
#include "mixer_s1810c.h"
27
28
#define SC1810C_CMD_REQ 160
29
#define SC1810C_CMD_REQTYPE \
30
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT)
31
#define SC1810C_CMD_F1 0x50617269
32
#define SC1810C_CMD_F2 0x14
33
34
/*
35
* DISCLAIMER: These are just guesses based on the
36
* dumps I got.
37
*
38
* It seems like a selects between
39
* device (0), mixer (0x64) and output (0x65)
40
*
41
* For mixer (0x64):
42
* * b selects an input channel (see below).
43
* * c selects an output channel pair (see below).
44
* * d selects left (0) or right (1) of that pair.
45
* * e 0-> disconnect, 0x01000000-> connect,
46
* 0x0109-> used for stereo-linking channels,
47
* e is also used for setting volume levels
48
* in which case b is also set so I guess
49
* this way it is possible to set the volume
50
* level from the specified input to the
51
* specified output.
52
*
53
* IN Channels:
54
* 0 - 7 Mic/Inst/Line (Analog inputs)
55
* 8 - 9 S/PDIF
56
* 10 - 17 ADAT
57
* 18 - 35 DAW (Inputs from the host)
58
*
59
* OUT Channels (pairs):
60
* 0 -> Main out
61
* 1 -> Line1/2
62
* 2 -> Line3/4
63
* 3 -> S/PDIF
64
* 4 -> ADAT?
65
*
66
* For device (0):
67
* * b and c are not used, at least not on the
68
* dumps I got.
69
* * d sets the control id to be modified
70
* (see below).
71
* * e sets the setting for that control.
72
* (so for the switches I was interested
73
* in it's 0/1)
74
*
75
* For output (0x65):
76
* * b is the output channel (see above).
77
* * c is zero.
78
* * e I guess the same as with mixer except 0x0109
79
* which I didn't see in my dumps.
80
*
81
* The two fixed fields have the same values for
82
* mixer and output but a different set for device.
83
*/
84
struct s1810c_ctl_packet {
85
u32 a;
86
u32 b;
87
u32 fixed1;
88
u32 fixed2;
89
u32 c;
90
u32 d;
91
u32 e;
92
};
93
94
#define SC1810C_CTL_LINE_SW 0
95
#define SC1810C_CTL_MUTE_SW 1
96
#define SC1824C_CTL_MONO_SW 2
97
#define SC1810C_CTL_AB_SW 3
98
#define SC1810C_CTL_48V_SW 4
99
100
#define SC1810C_SET_STATE_REQ 161
101
#define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE
102
#define SC1810C_SET_STATE_F1 0x64656D73
103
#define SC1810C_SET_STATE_F2 0xF4
104
105
#define SC1810C_GET_STATE_REQ 162
106
#define SC1810C_GET_STATE_REQTYPE \
107
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN)
108
#define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1
109
#define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2
110
111
#define SC1810C_STATE_F1_IDX 2
112
#define SC1810C_STATE_F2_IDX 3
113
114
/*
115
* This packet includes mixer volumes and
116
* various other fields, it's an extended
117
* version of ctl_packet, with a and b
118
* being zero and different f1/f2.
119
*/
120
struct s1810c_state_packet {
121
u32 fields[63];
122
};
123
124
#define SC1810C_STATE_48V_SW 58
125
#define SC1810C_STATE_LINE_SW 59
126
#define SC1810C_STATE_MUTE_SW 60
127
#define SC1824C_STATE_MONO_SW 61
128
#define SC1810C_STATE_AB_SW 62
129
130
struct s1810_mixer_state {
131
uint16_t seqnum;
132
struct mutex usb_mutex;
133
struct mutex data_mutex;
134
};
135
136
static int
137
snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a,
138
u32 b, u32 c, u32 d, u32 e)
139
{
140
struct s1810c_ctl_packet pkt = { 0 };
141
int ret = 0;
142
143
pkt.fixed1 = SC1810C_CMD_F1;
144
pkt.fixed2 = SC1810C_CMD_F2;
145
146
pkt.a = a;
147
pkt.b = b;
148
pkt.c = c;
149
pkt.d = d;
150
pkt.e = e;
151
152
ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
153
SC1810C_CMD_REQ,
154
SC1810C_CMD_REQTYPE, 0, 0, &pkt, sizeof(pkt));
155
if (ret < 0) {
156
dev_warn(&dev->dev, "could not send ctl packet\n");
157
return ret;
158
}
159
return 0;
160
}
161
162
/*
163
* When opening Universal Control the program periodically
164
* sends and receives state packets for syncinc state between
165
* the device and the host.
166
*
167
* Note that if we send only the request to get data back we'll
168
* get an error, we need to first send an empty state packet and
169
* then ask to receive a filled. Their seqnumbers must also match.
170
*/
171
static int
172
snd_sc1810c_get_status_field(struct usb_device *dev,
173
u32 *field, int field_idx, uint16_t *seqnum)
174
{
175
struct s1810c_state_packet pkt_out = { { 0 } };
176
struct s1810c_state_packet pkt_in = { { 0 } };
177
int ret = 0;
178
179
pkt_out.fields[SC1810C_STATE_F1_IDX] = SC1810C_SET_STATE_F1;
180
pkt_out.fields[SC1810C_STATE_F2_IDX] = SC1810C_SET_STATE_F2;
181
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
182
SC1810C_SET_STATE_REQ,
183
SC1810C_SET_STATE_REQTYPE,
184
(*seqnum), 0, &pkt_out, sizeof(pkt_out));
185
if (ret < 0) {
186
dev_warn(&dev->dev, "could not send state packet (%d)\n", ret);
187
return ret;
188
}
189
190
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
191
SC1810C_GET_STATE_REQ,
192
SC1810C_GET_STATE_REQTYPE,
193
(*seqnum), 0, &pkt_in, sizeof(pkt_in));
194
if (ret < 0) {
195
dev_warn(&dev->dev, "could not get state field %u (%d)\n",
196
field_idx, ret);
197
return ret;
198
}
199
200
(*field) = pkt_in.fields[field_idx];
201
(*seqnum)++;
202
return 0;
203
}
204
205
/*
206
* This is what I got when bypassing the mixer with
207
* all channels split. I'm not 100% sure of what's going
208
* on, I could probably clean this up based on my observations
209
* but I prefer to keep the same behavior as the windows driver.
210
*/
211
static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip)
212
{
213
u32 a, b, c, e, n, off, left, right;
214
struct usb_device *dev = chip->dev;
215
216
switch (chip->usb_id) {
217
case USB_ID(0x194f, 0x010c): /* 1810c */
218
/* Set initial volume levels ? */
219
a = 0x64;
220
e = 0xbc;
221
for (n = 0; n < 2; n++) {
222
off = n * 18;
223
for (b = off; b < 18 + off; b++) {
224
/* This channel to all outputs ? */
225
for (c = 0; c <= 8; c++) {
226
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e);
227
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e);
228
}
229
/* This channel to main output (again) */
230
snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e);
231
snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e);
232
}
233
/*
234
* I noticed on UC that DAW channels have different
235
* initial volumes, so this makes sense.
236
*/
237
e = 0xb53bf0;
238
}
239
240
/* Connect analog outputs ? */
241
a = 0x65;
242
e = 0x01000000;
243
for (b = 1; b < 3; b++) {
244
snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e);
245
snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e);
246
}
247
snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, e);
248
snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, e);
249
250
/* Set initial volume levels for S/PDIF mappings ? */
251
a = 0x64;
252
e = 0xbc;
253
c = 3;
254
for (n = 0; n < 2; n++) {
255
off = n * 18;
256
for (b = off; b < 18 + off; b++) {
257
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e);
258
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e);
259
}
260
e = 0xb53bf0;
261
}
262
263
/* Connect S/PDIF output ? */
264
a = 0x65;
265
e = 0x01000000;
266
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e);
267
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e);
268
269
/* Connect all outputs (again) ? */
270
a = 0x65;
271
e = 0x01000000;
272
for (b = 0; b < 4; b++) {
273
snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e);
274
snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e);
275
}
276
277
/* Basic routing to get sound out of the device */
278
a = 0x64;
279
e = 0x01000000;
280
for (c = 0; c < 4; c++) {
281
for (b = 0; b < 36; b++) {
282
if ((c == 0 && b == 18) || /* DAW1/2 -> Main */
283
(c == 1 && b == 20) || /* DAW3/4 -> Line3/4 */
284
(c == 2 && b == 22) || /* DAW4/5 -> Line5/6 */
285
(c == 3 && b == 24)) { /* DAW5/6 -> S/PDIF */
286
/* Left */
287
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e);
288
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0);
289
b++;
290
/* Right */
291
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0);
292
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e);
293
} else {
294
/* Leave the rest disconnected */
295
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0);
296
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0);
297
}
298
}
299
}
300
301
/* Set initial volume levels for S/PDIF (again) ? */
302
a = 0x64;
303
e = 0xbc;
304
c = 3;
305
for (n = 0; n < 2; n++) {
306
off = n * 18;
307
for (b = off; b < 18 + off; b++) {
308
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e);
309
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e);
310
}
311
e = 0xb53bf0;
312
}
313
314
/* Connect S/PDIF outputs (again) ? */
315
a = 0x65;
316
e = 0x01000000;
317
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e);
318
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e);
319
320
/* Again ? */
321
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e);
322
snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e);
323
break;
324
325
case USB_ID(0x194f, 0x010d): /* 1824c */
326
/* Set all output faders to unity gain */
327
a = 0x65;
328
c = 0x00;
329
e = 0x01000000;
330
331
for (b = 0; b < 9; b++) {
332
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e);
333
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e);
334
}
335
336
/* Set
337
* Daw 1 -> Line out 1 (left), Daw 2 -> Line out 2 (right)
338
* Daw 3 -> Line out 3, (left) Daw 4 -> Line out 4 (right)
339
* Daw 5 -> Line out 5, (left) Daw 6 -> Line out 6 (right)
340
* Daw 7 -> Line out 7, (left) Daw 8 -> Line out 8 (right)
341
* Daw 9 -> SPDIF out 1, (left) Daw 10 -> SPDIF out 2 (right)
342
* Daw 11 -> ADAT out 1, (left) Daw 12 -> ADAT out 2 (right)
343
* Daw 13 -> ADAT out 3, (left) Daw 14 -> ADAT out 4 (right)
344
* Daw 15 -> ADAT out 5, (left) Daw 16 -> ADAT out 6 (right)
345
* Daw 17 -> ADAT out 7, (left) Daw 18 -> ADAT out 8 (right)
346
* Everything else muted
347
*/
348
a = 0x64;
349
/* The first Daw channel is channel 18 */
350
left = 18;
351
352
for (c = 0; c < 9; c++) {
353
right = left + 1;
354
355
for (b = 0; b < 36; b++) {
356
if (b == left) {
357
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x01000000);
358
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00);
359
} else if (b == right) {
360
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00);
361
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x01000000);
362
} else {
363
snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00);
364
snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00);
365
}
366
}
367
left += 2;
368
}
369
break;
370
}
371
return 0;
372
}
373
374
/*
375
* Sync state with the device and retrieve the requested field,
376
* whose index is specified in (kctl->private_value & 0xFF),
377
* from the received fields array.
378
*/
379
static int
380
snd_s1810c_get_switch_state(struct usb_mixer_interface *mixer,
381
struct snd_kcontrol *kctl, u32 *state)
382
{
383
struct snd_usb_audio *chip = mixer->chip;
384
struct s1810_mixer_state *private = mixer->private_data;
385
u32 field = 0;
386
u32 ctl_idx = (u32) (kctl->private_value & 0xFF);
387
int ret;
388
389
guard(mutex)(&private->usb_mutex);
390
ret = snd_sc1810c_get_status_field(chip->dev, &field,
391
ctl_idx, &private->seqnum);
392
if (ret < 0)
393
return ret;
394
395
*state = field;
396
return ret;
397
}
398
399
/*
400
* Send a control packet to the device for the control id
401
* specified in (kctl->private_value >> 8) with value
402
* specified in (kctl->private_value >> 16).
403
*/
404
static int
405
snd_s1810c_set_switch_state(struct usb_mixer_interface *mixer,
406
struct snd_kcontrol *kctl)
407
{
408
struct snd_usb_audio *chip = mixer->chip;
409
struct s1810_mixer_state *private = mixer->private_data;
410
u32 pval = (u32) kctl->private_value;
411
u32 ctl_id = (pval >> 8) & 0xFF;
412
u32 ctl_val = (pval >> 16) & 0x1;
413
414
guard(mutex)(&private->usb_mutex);
415
return snd_s1810c_send_ctl_packet(chip->dev, 0, 0, 0, ctl_id, ctl_val);
416
}
417
418
/* Generic get/set/init functions for switch controls */
419
420
static int
421
snd_s1810c_switch_get(struct snd_kcontrol *kctl,
422
struct snd_ctl_elem_value *ctl_elem)
423
{
424
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
425
struct usb_mixer_interface *mixer = list->mixer;
426
struct s1810_mixer_state *private = mixer->private_data;
427
u32 pval = (u32) kctl->private_value;
428
u32 ctl_idx = pval & 0xFF;
429
u32 state = 0;
430
int ret;
431
432
guard(mutex)(&private->data_mutex);
433
ret = snd_s1810c_get_switch_state(mixer, kctl, &state);
434
if (ret < 0)
435
return ret;
436
437
switch (ctl_idx) {
438
case SC1810C_STATE_LINE_SW:
439
case SC1810C_STATE_AB_SW:
440
ctl_elem->value.enumerated.item[0] = (int)state;
441
break;
442
default:
443
ctl_elem->value.integer.value[0] = (long)state;
444
}
445
446
return 0;
447
}
448
449
static int
450
snd_s1810c_switch_set(struct snd_kcontrol *kctl,
451
struct snd_ctl_elem_value *ctl_elem)
452
{
453
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
454
struct usb_mixer_interface *mixer = list->mixer;
455
struct s1810_mixer_state *private = mixer->private_data;
456
u32 pval = (u32) kctl->private_value;
457
u32 ctl_idx = pval & 0xFF;
458
u32 curval = 0;
459
u32 newval = 0;
460
int ret = 0;
461
462
guard(mutex)(&private->data_mutex);
463
ret = snd_s1810c_get_switch_state(mixer, kctl, &curval);
464
if (ret < 0)
465
return ret;
466
467
switch (ctl_idx) {
468
case SC1810C_STATE_LINE_SW:
469
case SC1810C_STATE_AB_SW:
470
newval = (u32) ctl_elem->value.enumerated.item[0];
471
break;
472
default:
473
newval = (u32) ctl_elem->value.integer.value[0];
474
}
475
476
if (curval == newval)
477
return 0;
478
479
kctl->private_value &= ~(0x1 << 16);
480
kctl->private_value |= (unsigned int)(newval & 0x1) << 16;
481
ret = snd_s1810c_set_switch_state(mixer, kctl);
482
483
return (ret < 0) ? 0 : 1;
484
}
485
486
static int
487
snd_s1810c_switch_init(struct usb_mixer_interface *mixer,
488
const struct snd_kcontrol_new *new_kctl)
489
{
490
struct snd_kcontrol *kctl;
491
struct usb_mixer_elem_info *elem;
492
493
elem = kzalloc(sizeof(struct usb_mixer_elem_info), GFP_KERNEL);
494
if (!elem)
495
return -ENOMEM;
496
497
elem->head.mixer = mixer;
498
elem->control = 0;
499
elem->head.id = 0;
500
elem->channels = 1;
501
502
kctl = snd_ctl_new1(new_kctl, elem);
503
if (!kctl) {
504
kfree(elem);
505
return -ENOMEM;
506
}
507
kctl->private_free = snd_usb_mixer_elem_free;
508
509
return snd_usb_mixer_add_control(&elem->head, kctl);
510
}
511
512
static int
513
snd_s1810c_line_sw_info(struct snd_kcontrol *kctl,
514
struct snd_ctl_elem_info *uinfo)
515
{
516
static const char *const texts[2] = {
517
"Preamp On (Mic/Inst)",
518
"Preamp Off (Line in)"
519
};
520
521
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
522
}
523
524
static const struct snd_kcontrol_new snd_s1810c_line_sw = {
525
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
526
.name = "Line 1/2 Source Type",
527
.info = snd_s1810c_line_sw_info,
528
.get = snd_s1810c_switch_get,
529
.put = snd_s1810c_switch_set,
530
.private_value = (SC1810C_STATE_LINE_SW | SC1810C_CTL_LINE_SW << 8)
531
};
532
533
static const struct snd_kcontrol_new snd_s1810c_mute_sw = {
534
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
535
.name = "Mute Main Out Switch",
536
.info = snd_ctl_boolean_mono_info,
537
.get = snd_s1810c_switch_get,
538
.put = snd_s1810c_switch_set,
539
.private_value = (SC1810C_STATE_MUTE_SW | SC1810C_CTL_MUTE_SW << 8)
540
};
541
542
static const struct snd_kcontrol_new snd_s1824c_mono_sw = {
543
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
544
.name = "Mono Main Out Switch",
545
.info = snd_ctl_boolean_mono_info,
546
.get = snd_s1810c_switch_get,
547
.put = snd_s1810c_switch_set,
548
.private_value = (SC1824C_STATE_MONO_SW | SC1824C_CTL_MONO_SW << 8)
549
};
550
551
static const struct snd_kcontrol_new snd_s1810c_48v_sw = {
552
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
553
.name = "48V Phantom Power On Mic Inputs Switch",
554
.info = snd_ctl_boolean_mono_info,
555
.get = snd_s1810c_switch_get,
556
.put = snd_s1810c_switch_set,
557
.private_value = (SC1810C_STATE_48V_SW | SC1810C_CTL_48V_SW << 8)
558
};
559
560
static int
561
snd_s1810c_ab_sw_info(struct snd_kcontrol *kctl,
562
struct snd_ctl_elem_info *uinfo)
563
{
564
static const char *const texts[2] = {
565
"1/2",
566
"3/4"
567
};
568
569
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
570
}
571
572
static const struct snd_kcontrol_new snd_s1810c_ab_sw = {
573
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
574
.name = "Headphone 1 Source Route",
575
.info = snd_s1810c_ab_sw_info,
576
.get = snd_s1810c_switch_get,
577
.put = snd_s1810c_switch_set,
578
.private_value = (SC1810C_STATE_AB_SW | SC1810C_CTL_AB_SW << 8)
579
};
580
581
static void snd_sc1810_mixer_state_free(struct usb_mixer_interface *mixer)
582
{
583
struct s1810_mixer_state *private = mixer->private_data;
584
kfree(private);
585
mixer->private_data = NULL;
586
}
587
588
/* Entry point, called from mixer_quirks.c */
589
int snd_sc1810_init_mixer(struct usb_mixer_interface *mixer)
590
{
591
struct s1810_mixer_state *private = NULL;
592
struct snd_usb_audio *chip = mixer->chip;
593
struct usb_device *dev = chip->dev;
594
int ret = 0;
595
596
/* Run this only once */
597
if (!list_empty(&chip->mixer_list))
598
return 0;
599
600
dev_info(&dev->dev,
601
"Presonus Studio 1810c, device_setup: %u\n", chip->setup);
602
if (chip->setup == 1)
603
dev_info(&dev->dev, "(8out/18in @ 48kHz)\n");
604
else if (chip->setup == 2)
605
dev_info(&dev->dev, "(6out/8in @ 192kHz)\n");
606
else
607
dev_info(&dev->dev, "(8out/14in @ 96kHz)\n");
608
609
ret = snd_s1810c_init_mixer_maps(chip);
610
if (ret < 0)
611
return ret;
612
613
private = kzalloc(sizeof(struct s1810_mixer_state), GFP_KERNEL);
614
if (!private)
615
return -ENOMEM;
616
617
mutex_init(&private->usb_mutex);
618
mutex_init(&private->data_mutex);
619
620
mixer->private_data = private;
621
mixer->private_free = snd_sc1810_mixer_state_free;
622
623
private->seqnum = 1;
624
625
ret = snd_s1810c_switch_init(mixer, &snd_s1810c_line_sw);
626
if (ret < 0)
627
return ret;
628
629
ret = snd_s1810c_switch_init(mixer, &snd_s1810c_mute_sw);
630
if (ret < 0)
631
return ret;
632
633
ret = snd_s1810c_switch_init(mixer, &snd_s1810c_48v_sw);
634
if (ret < 0)
635
return ret;
636
637
// The 1824c has a Mono Main switch instead of a
638
// A/B select switch.
639
if (mixer->chip->usb_id == USB_ID(0x194f, 0x010d)) {
640
ret = snd_s1810c_switch_init(mixer, &snd_s1824c_mono_sw);
641
if (ret < 0)
642
return ret;
643
} else if (mixer->chip->usb_id == USB_ID(0x194f, 0x010c)) {
644
ret = snd_s1810c_switch_init(mixer, &snd_s1810c_ab_sw);
645
if (ret < 0)
646
return ret;
647
}
648
649
return ret;
650
}
651
652