Commit | Line | Data |
---|---|---|
8dc5efe3 NK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Presonus Studio 1810c driver for ALSA | |
4 | * Copyright (C) 2019 Nick Kossifidis <mickflemm@gmail.com> | |
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 SC1810C_CTL_AB_SW 3 | |
97 | #define SC1810C_CTL_48V_SW 4 | |
98 | ||
99 | #define SC1810C_SET_STATE_REQ 161 | |
100 | #define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE | |
101 | #define SC1810C_SET_STATE_F1 0x64656D73 | |
102 | #define SC1810C_SET_STATE_F2 0xF4 | |
103 | ||
104 | #define SC1810C_GET_STATE_REQ 162 | |
105 | #define SC1810C_GET_STATE_REQTYPE \ | |
106 | (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN) | |
107 | #define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1 | |
108 | #define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2 | |
109 | ||
110 | #define SC1810C_STATE_F1_IDX 2 | |
111 | #define SC1810C_STATE_F2_IDX 3 | |
112 | ||
113 | /* | |
114 | * This packet includes mixer volumes and | |
115 | * various other fields, it's an extended | |
116 | * version of ctl_packet, with a and b | |
117 | * being zero and different f1/f2. | |
118 | */ | |
119 | struct s1810c_state_packet { | |
120 | u32 fields[63]; | |
121 | }; | |
122 | ||
123 | #define SC1810C_STATE_48V_SW 58 | |
124 | #define SC1810C_STATE_LINE_SW 59 | |
125 | #define SC1810C_STATE_MUTE_SW 60 | |
126 | #define SC1810C_STATE_AB_SW 62 | |
127 | ||
128 | struct s1810_mixer_state { | |
129 | uint16_t seqnum; | |
130 | struct mutex usb_mutex; | |
131 | struct mutex data_mutex; | |
132 | }; | |
133 | ||
134 | static int | |
135 | snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, | |
136 | u32 b, u32 c, u32 d, u32 e) | |
137 | { | |
138 | struct s1810c_ctl_packet pkt = { 0 }; | |
139 | int ret = 0; | |
140 | ||
141 | pkt.fixed1 = SC1810C_CMD_F1; | |
142 | pkt.fixed2 = SC1810C_CMD_F2; | |
143 | ||
144 | pkt.a = a; | |
145 | pkt.b = b; | |
146 | pkt.c = c; | |
147 | pkt.d = d; | |
148 | /* | |
149 | * Value for settings 0/1 for this | |
150 | * output channel is always 0 (probably because | |
151 | * there is no ADAT output on 1810c) | |
152 | */ | |
153 | pkt.e = (c == 4) ? 0 : e; | |
154 | ||
155 | ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), | |
156 | SC1810C_CMD_REQ, | |
157 | SC1810C_CMD_REQTYPE, 0, 0, &pkt, sizeof(pkt)); | |
158 | if (ret < 0) { | |
159 | dev_warn(&dev->dev, "could not send ctl packet\n"); | |
160 | return ret; | |
161 | } | |
162 | return 0; | |
163 | } | |
164 | ||
165 | /* | |
166 | * When opening Universal Control the program periodicaly | |
167 | * sends and receives state packets for syncinc state between | |
168 | * the device and the host. | |
169 | * | |
170 | * Note that if we send only the request to get data back we'll | |
171 | * get an error, we need to first send an empty state packet and | |
172 | * then ask to receive a filled. Their seqnumbers must also match. | |
173 | */ | |
174 | static int | |
175 | snd_sc1810c_get_status_field(struct usb_device *dev, | |
176 | u32 *field, int field_idx, uint16_t *seqnum) | |
177 | { | |
178 | struct s1810c_state_packet pkt_out = { 0 }; | |
179 | struct s1810c_state_packet pkt_in = { 0 }; | |
180 | int ret = 0; | |
181 | ||
182 | pkt_out.fields[SC1810C_STATE_F1_IDX] = SC1810C_SET_STATE_F1; | |
183 | pkt_out.fields[SC1810C_STATE_F2_IDX] = SC1810C_SET_STATE_F2; | |
184 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), | |
185 | SC1810C_SET_STATE_REQ, | |
186 | SC1810C_SET_STATE_REQTYPE, | |
187 | (*seqnum), 0, &pkt_out, sizeof(pkt_out)); | |
188 | if (ret < 0) { | |
189 | dev_warn(&dev->dev, "could not send state packet (%d)\n", ret); | |
190 | return ret; | |
191 | } | |
192 | ||
193 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), | |
194 | SC1810C_GET_STATE_REQ, | |
195 | SC1810C_GET_STATE_REQTYPE, | |
196 | (*seqnum), 0, &pkt_in, sizeof(pkt_in)); | |
197 | if (ret < 0) { | |
198 | dev_warn(&dev->dev, "could not get state field %u (%d)\n", | |
199 | field_idx, ret); | |
200 | return ret; | |
201 | } | |
202 | ||
203 | (*field) = pkt_in.fields[field_idx]; | |
204 | (*seqnum)++; | |
205 | return 0; | |
206 | } | |
207 | ||
208 | /* | |
209 | * This is what I got when bypassing the mixer with | |
210 | * all channels split. I'm not 100% sure of what's going | |
211 | * on, I could probably clean this up based on my observations | |
212 | * but I prefer to keep the same behavior as the windows driver. | |
213 | */ | |
214 | static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) | |
215 | { | |
216 | u32 a, b, c, e, n, off; | |
217 | struct usb_device *dev = chip->dev; | |
218 | ||
219 | /* Set initial volume levels ? */ | |
220 | a = 0x64; | |
221 | e = 0xbc; | |
222 | for (n = 0; n < 2; n++) { | |
223 | off = n * 18; | |
224 | for (b = off, c = 0; b < 18 + off; b++) { | |
225 | /* This channel to all outputs ? */ | |
226 | for (c = 0; c <= 8; c++) { | |
227 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); | |
228 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); | |
229 | } | |
230 | /* This channel to main output (again) */ | |
231 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); | |
232 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); | |
233 | } | |
234 | /* | |
235 | * I noticed on UC that DAW channels have different | |
236 | * initial volumes, so this makes sense. | |
237 | */ | |
238 | e = 0xb53bf0; | |
239 | } | |
240 | ||
241 | /* Connect analog outputs ? */ | |
242 | a = 0x65; | |
243 | e = 0x01000000; | |
244 | for (b = 1; b < 3; b++) { | |
245 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); | |
246 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); | |
247 | } | |
248 | snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, e); | |
249 | snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, e); | |
250 | ||
251 | /* Set initial volume levels for S/PDIF mappings ? */ | |
252 | a = 0x64; | |
253 | e = 0xbc; | |
254 | c = 3; | |
255 | for (n = 0; n < 2; n++) { | |
256 | off = n * 18; | |
257 | for (b = off; b < 18 + off; b++) { | |
258 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); | |
259 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); | |
260 | } | |
261 | e = 0xb53bf0; | |
262 | } | |
263 | ||
264 | /* Connect S/PDIF output ? */ | |
265 | a = 0x65; | |
266 | e = 0x01000000; | |
267 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); | |
268 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); | |
269 | ||
270 | /* Connect all outputs (again) ? */ | |
271 | a = 0x65; | |
272 | e = 0x01000000; | |
273 | for (b = 0; b < 4; b++) { | |
274 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); | |
275 | snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); | |
276 | } | |
277 | ||
278 | /* Basic routing to get sound out of the device */ | |
279 | a = 0x64; | |
280 | e = 0x01000000; | |
281 | for (c = 0; c < 4; c++) { | |
282 | for (b = 0; b < 36; b++) { | |
283 | if ((c == 0 && b == 18) || /* DAW1/2 -> Main */ | |
284 | (c == 1 && b == 20) || /* DAW3/4 -> Line3/4 */ | |
285 | (c == 2 && b == 22) || /* DAW4/5 -> Line5/6 */ | |
286 | (c == 3 && b == 24)) { /* DAW5/6 -> S/PDIF */ | |
287 | /* Left */ | |
288 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); | |
289 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); | |
290 | b++; | |
291 | /* Right */ | |
292 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); | |
293 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); | |
294 | } else { | |
295 | /* Leave the rest disconnected */ | |
296 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); | |
297 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | /* Set initial volume levels for S/PDIF (again) ? */ | |
303 | a = 0x64; | |
304 | e = 0xbc; | |
305 | c = 3; | |
306 | for (n = 0; n < 2; n++) { | |
307 | off = n * 18; | |
308 | for (b = off; b < 18 + off; b++) { | |
309 | snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); | |
310 | snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); | |
311 | } | |
312 | e = 0xb53bf0; | |
313 | } | |
314 | ||
315 | /* Connect S/PDIF outputs (again) ? */ | |
316 | a = 0x65; | |
317 | e = 0x01000000; | |
318 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); | |
319 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); | |
320 | ||
321 | /* Again ? */ | |
322 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); | |
323 | snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); | |
324 | ||
325 | return 0; | |
326 | } | |
327 | ||
328 | /* | |
329 | * Sync state with the device and retrieve the requested field, | |
330 | * whose index is specified in (kctl->private_value & 0xFF), | |
331 | * from the received fields array. | |
332 | */ | |
333 | static int | |
334 | snd_s1810c_get_switch_state(struct usb_mixer_interface *mixer, | |
335 | struct snd_kcontrol *kctl, u32 *state) | |
336 | { | |
337 | struct snd_usb_audio *chip = mixer->chip; | |
338 | struct s1810_mixer_state *private = mixer->private_data; | |
339 | u32 field = 0; | |
340 | u32 ctl_idx = (u32) (kctl->private_value & 0xFF); | |
341 | int ret = 0; | |
342 | ||
343 | mutex_lock(&private->usb_mutex); | |
344 | ret = snd_sc1810c_get_status_field(chip->dev, &field, | |
345 | ctl_idx, &private->seqnum); | |
346 | if (ret < 0) | |
347 | goto unlock; | |
348 | ||
349 | *state = field; | |
350 | unlock: | |
351 | mutex_unlock(&private->usb_mutex); | |
352 | return ret ? ret : 0; | |
353 | } | |
354 | ||
355 | /* | |
356 | * Send a control packet to the device for the control id | |
357 | * specified in (kctl->private_value >> 8) with value | |
358 | * specified in (kctl->private_value >> 16). | |
359 | */ | |
360 | static int | |
361 | snd_s1810c_set_switch_state(struct usb_mixer_interface *mixer, | |
362 | struct snd_kcontrol *kctl) | |
363 | { | |
364 | struct snd_usb_audio *chip = mixer->chip; | |
365 | struct s1810_mixer_state *private = mixer->private_data; | |
366 | u32 pval = (u32) kctl->private_value; | |
367 | u32 ctl_id = (pval >> 8) & 0xFF; | |
368 | u32 ctl_val = (pval >> 16) & 0x1; | |
369 | int ret = 0; | |
370 | ||
371 | mutex_lock(&private->usb_mutex); | |
372 | ret = snd_s1810c_send_ctl_packet(chip->dev, 0, 0, 0, ctl_id, ctl_val); | |
373 | mutex_unlock(&private->usb_mutex); | |
374 | return ret; | |
375 | } | |
376 | ||
377 | /* Generic get/set/init functions for switch controls */ | |
378 | ||
379 | static int | |
380 | snd_s1810c_switch_get(struct snd_kcontrol *kctl, | |
381 | struct snd_ctl_elem_value *ctl_elem) | |
382 | { | |
383 | struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); | |
384 | struct usb_mixer_interface *mixer = list->mixer; | |
385 | struct s1810_mixer_state *private = mixer->private_data; | |
386 | u32 pval = (u32) kctl->private_value; | |
387 | u32 ctl_idx = pval & 0xFF; | |
388 | u32 state = 0; | |
389 | int ret = 0; | |
390 | ||
391 | mutex_lock(&private->data_mutex); | |
392 | ret = snd_s1810c_get_switch_state(mixer, kctl, &state); | |
393 | if (ret < 0) | |
394 | goto unlock; | |
395 | ||
396 | switch (ctl_idx) { | |
397 | case SC1810C_STATE_LINE_SW: | |
398 | case SC1810C_STATE_AB_SW: | |
399 | ctl_elem->value.enumerated.item[0] = (int)state; | |
400 | break; | |
401 | default: | |
402 | ctl_elem->value.integer.value[0] = (long)state; | |
403 | } | |
404 | ||
405 | unlock: | |
406 | mutex_unlock(&private->data_mutex); | |
407 | return (ret < 0) ? ret : 0; | |
408 | } | |
409 | ||
410 | static int | |
411 | snd_s1810c_switch_set(struct snd_kcontrol *kctl, | |
412 | struct snd_ctl_elem_value *ctl_elem) | |
413 | { | |
414 | struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); | |
415 | struct usb_mixer_interface *mixer = list->mixer; | |
416 | struct s1810_mixer_state *private = mixer->private_data; | |
417 | u32 pval = (u32) kctl->private_value; | |
418 | u32 ctl_idx = pval & 0xFF; | |
419 | u32 curval = 0; | |
420 | u32 newval = 0; | |
421 | int ret = 0; | |
422 | ||
423 | mutex_lock(&private->data_mutex); | |
424 | ret = snd_s1810c_get_switch_state(mixer, kctl, &curval); | |
425 | if (ret < 0) | |
426 | goto unlock; | |
427 | ||
428 | switch (ctl_idx) { | |
429 | case SC1810C_STATE_LINE_SW: | |
430 | case SC1810C_STATE_AB_SW: | |
431 | newval = (u32) ctl_elem->value.enumerated.item[0]; | |
432 | break; | |
433 | default: | |
434 | newval = (u32) ctl_elem->value.integer.value[0]; | |
435 | } | |
436 | ||
437 | if (curval == newval) | |
438 | goto unlock; | |
439 | ||
440 | kctl->private_value &= ~(0x1 << 16); | |
441 | kctl->private_value |= (unsigned int)(newval & 0x1) << 16; | |
442 | ret = snd_s1810c_set_switch_state(mixer, kctl); | |
443 | ||
444 | unlock: | |
445 | mutex_unlock(&private->data_mutex); | |
446 | return (ret < 0) ? 0 : 1; | |
447 | } | |
448 | ||
449 | static int | |
450 | snd_s1810c_switch_init(struct usb_mixer_interface *mixer, | |
451 | const struct snd_kcontrol_new *new_kctl) | |
452 | { | |
453 | struct snd_kcontrol *kctl; | |
454 | struct usb_mixer_elem_info *elem; | |
455 | ||
456 | elem = kzalloc(sizeof(struct usb_mixer_elem_info), GFP_KERNEL); | |
457 | if (!elem) | |
458 | return -ENOMEM; | |
459 | ||
460 | elem->head.mixer = mixer; | |
461 | elem->control = 0; | |
462 | elem->head.id = 0; | |
463 | elem->channels = 1; | |
464 | ||
465 | kctl = snd_ctl_new1(new_kctl, elem); | |
466 | if (!kctl) { | |
467 | kfree(elem); | |
468 | return -ENOMEM; | |
469 | } | |
470 | kctl->private_free = snd_usb_mixer_elem_free; | |
471 | ||
472 | return snd_usb_mixer_add_control(&elem->head, kctl); | |
473 | } | |
474 | ||
475 | static int | |
476 | snd_s1810c_line_sw_info(struct snd_kcontrol *kctl, | |
477 | struct snd_ctl_elem_info *uinfo) | |
478 | { | |
479 | static const char *const texts[2] = { | |
480 | "Preamp On (Mic/Inst)", | |
481 | "Preamp Off (Line in)" | |
482 | }; | |
483 | ||
484 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); | |
485 | } | |
486 | ||
487 | static const struct snd_kcontrol_new snd_s1810c_line_sw = { | |
488 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
489 | .name = "Line 1/2 Source Type", | |
490 | .info = snd_s1810c_line_sw_info, | |
491 | .get = snd_s1810c_switch_get, | |
492 | .put = snd_s1810c_switch_set, | |
493 | .private_value = (SC1810C_STATE_LINE_SW | SC1810C_CTL_LINE_SW << 8) | |
494 | }; | |
495 | ||
496 | static const struct snd_kcontrol_new snd_s1810c_mute_sw = { | |
497 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
498 | .name = "Mute Main Out Switch", | |
499 | .info = snd_ctl_boolean_mono_info, | |
500 | .get = snd_s1810c_switch_get, | |
501 | .put = snd_s1810c_switch_set, | |
502 | .private_value = (SC1810C_STATE_MUTE_SW | SC1810C_CTL_MUTE_SW << 8) | |
503 | }; | |
504 | ||
505 | static const struct snd_kcontrol_new snd_s1810c_48v_sw = { | |
506 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
507 | .name = "48V Phantom Power On Mic Inputs Switch", | |
508 | .info = snd_ctl_boolean_mono_info, | |
509 | .get = snd_s1810c_switch_get, | |
510 | .put = snd_s1810c_switch_set, | |
511 | .private_value = (SC1810C_STATE_48V_SW | SC1810C_CTL_48V_SW << 8) | |
512 | }; | |
513 | ||
514 | static int | |
515 | snd_s1810c_ab_sw_info(struct snd_kcontrol *kctl, | |
516 | struct snd_ctl_elem_info *uinfo) | |
517 | { | |
518 | static const char *const texts[2] = { | |
519 | "1/2", | |
520 | "3/4" | |
521 | }; | |
522 | ||
523 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); | |
524 | } | |
525 | ||
526 | static const struct snd_kcontrol_new snd_s1810c_ab_sw = { | |
527 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
528 | .name = "Headphone 1 Source Route", | |
529 | .info = snd_s1810c_ab_sw_info, | |
530 | .get = snd_s1810c_switch_get, | |
531 | .put = snd_s1810c_switch_set, | |
532 | .private_value = (SC1810C_STATE_AB_SW | SC1810C_CTL_AB_SW << 8) | |
533 | }; | |
534 | ||
535 | static void snd_sc1810_mixer_state_free(struct usb_mixer_interface *mixer) | |
536 | { | |
537 | struct s1810_mixer_state *private = mixer->private_data; | |
538 | kfree(private); | |
539 | mixer->private_data = NULL; | |
540 | } | |
541 | ||
542 | /* Entry point, called from mixer_quirks.c */ | |
543 | int snd_sc1810_init_mixer(struct usb_mixer_interface *mixer) | |
544 | { | |
545 | struct s1810_mixer_state *private = NULL; | |
546 | struct snd_usb_audio *chip = mixer->chip; | |
547 | struct usb_device *dev = chip->dev; | |
548 | int ret = 0; | |
549 | ||
550 | /* Run this only once */ | |
551 | if (!list_empty(&chip->mixer_list)) | |
552 | return 0; | |
553 | ||
554 | dev_info(&dev->dev, | |
555 | "Presonus Studio 1810c, device_setup: %u\n", chip->setup); | |
556 | if (chip->setup == 1) | |
557 | dev_info(&dev->dev, "(8out/18in @ 48KHz)\n"); | |
558 | else if (chip->setup == 2) | |
559 | dev_info(&dev->dev, "(6out/8in @ 192KHz)\n"); | |
560 | else | |
561 | dev_info(&dev->dev, "(8out/14in @ 96KHz)\n"); | |
562 | ||
563 | ret = snd_s1810c_init_mixer_maps(chip); | |
564 | if (ret < 0) | |
565 | return ret; | |
566 | ||
567 | private = kzalloc(sizeof(struct s1810_mixer_state), GFP_KERNEL); | |
568 | if (!private) | |
569 | return -ENOMEM; | |
570 | ||
571 | mutex_init(&private->usb_mutex); | |
572 | mutex_init(&private->data_mutex); | |
573 | ||
574 | mixer->private_data = private; | |
575 | mixer->private_free = snd_sc1810_mixer_state_free; | |
576 | ||
577 | private->seqnum = 1; | |
578 | ||
579 | ret = snd_s1810c_switch_init(mixer, &snd_s1810c_line_sw); | |
580 | if (ret < 0) | |
581 | return ret; | |
582 | ||
583 | ret = snd_s1810c_switch_init(mixer, &snd_s1810c_mute_sw); | |
584 | if (ret < 0) | |
585 | return ret; | |
586 | ||
587 | ret = snd_s1810c_switch_init(mixer, &snd_s1810c_48v_sw); | |
588 | if (ret < 0) | |
589 | return ret; | |
590 | ||
591 | ret = snd_s1810c_switch_init(mixer, &snd_s1810c_ab_sw); | |
592 | if (ret < 0) | |
593 | return ret; | |
594 | return ret; | |
595 | } |