596 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Presonus Studio 1810c driver for ALSA4 * Copyright (C) 2019 Nick Kossifidis <mickflemm@gmail.com>5 *6 * Based on reverse engineering of the communication protocol7 * between the windows driver / Univeral Control (UC) program8 * 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 of13 * 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 16029#define SC1810C_CMD_REQTYPE \30 (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT)31#define SC1810C_CMD_F1 0x5061726932#define SC1810C_CMD_F2 0x1433 34/*35 * DISCLAIMER: These are just guesses based on the36 * dumps I got.37 *38 * It seems like a selects between39 * 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 levels48 * in which case b is also set so I guess49 * this way it is possible to set the volume50 * level from the specified input to the51 * specified output.52 *53 * IN Channels:54 * 0 - 7 Mic/Inst/Line (Analog inputs)55 * 8 - 9 S/PDIF56 * 10 - 17 ADAT57 * 18 - 35 DAW (Inputs from the host)58 *59 * OUT Channels (pairs):60 * 0 -> Main out61 * 1 -> Line1/262 * 2 -> Line3/463 * 3 -> S/PDIF64 * 4 -> ADAT?65 *66 * For device (0):67 * * b and c are not used, at least not on the68 * dumps I got.69 * * d sets the control id to be modified70 * (see below).71 * * e sets the setting for that control.72 * (so for the switches I was interested73 * 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 0x010979 * which I didn't see in my dumps.80 *81 * The two fixed fields have the same values for82 * mixer and output but a different set for device.83 */84struct 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 095#define SC1810C_CTL_MUTE_SW 196#define SC1810C_CTL_AB_SW 397#define SC1810C_CTL_48V_SW 498 99#define SC1810C_SET_STATE_REQ 161100#define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE101#define SC1810C_SET_STATE_F1 0x64656D73102#define SC1810C_SET_STATE_F2 0xF4103 104#define SC1810C_GET_STATE_REQ 162105#define SC1810C_GET_STATE_REQTYPE \106 (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN)107#define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1108#define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2109 110#define SC1810C_STATE_F1_IDX 2111#define SC1810C_STATE_F2_IDX 3112 113/*114 * This packet includes mixer volumes and115 * various other fields, it's an extended116 * version of ctl_packet, with a and b117 * being zero and different f1/f2.118 */119struct s1810c_state_packet {120 u32 fields[63];121};122 123#define SC1810C_STATE_48V_SW 58124#define SC1810C_STATE_LINE_SW 59125#define SC1810C_STATE_MUTE_SW 60126#define SC1810C_STATE_AB_SW 62127 128struct s1810_mixer_state {129 uint16_t seqnum;130 struct mutex usb_mutex;131 struct mutex data_mutex;132};133 134static int135snd_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 this150 * output channel is always 0 (probably because151 * 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 periodically167 * sends and receives state packets for syncinc state between168 * the device and the host.169 *170 * Note that if we send only the request to get data back we'll171 * get an error, we need to first send an empty state packet and172 * then ask to receive a filled. Their seqnumbers must also match.173 */174static int175snd_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 with210 * all channels split. I'm not 100% sure of what's going211 * on, I could probably clean this up based on my observations212 * but I prefer to keep the same behavior as the windows driver.213 */214static 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; 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 different236 * 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 */333static int334snd_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 id357 * specified in (kctl->private_value >> 8) with value358 * specified in (kctl->private_value >> 16).359 */360static int361snd_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 379static int380snd_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 410static int411snd_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 449static int450snd_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 475static int476snd_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 487static 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 496static 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 505static 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 514static int515snd_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 526static 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 535static 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 */543int 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 else561 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}596