linux/sound/usb/mixer_scarlett.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *   Scarlett Driver for ALSA
 *
 *   Copyright (c) 2013 by Tobias Hoffmann
 *   Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
 *   Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
 *   Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
 *
 *   Many codes borrowed from audio.c by
 *	    Alan Cox (alan at lxorguk.ukuu.org.uk)
 *	    Thomas Sailer (sailer at ife.ee.ethz.ch)
 *
 *   Code cleanup:
 *   David Henningsson <david.henningsson at canonical.com>
 */

/*
 * Rewritten and extended to support more models, e.g. Scarlett 18i8.
 *
 * Auto-detection via UAC2 is not feasible to properly discover the vast
 * majority of features. It's related to both Linux/ALSA's UAC2 as well as
 * Focusrite's implementation of it. Eventually quirks may be sufficient but
 * right now it's a major headache to work around these things.
 *
 * NB. Neither the OSX nor the win driver provided by Focusrite performs
 * discovery, they seem to operate the same as this driver.
 */

/* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
 *
 * The protocol was reverse engineered by looking at communication between
 * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
 * (firmware v305) using wireshark and usbmon in January 2013.
 * Extended in July 2013.
 *
 * this mixer gives complete access to all features of the device:
 *  - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
 *  - select clock source
 *  - dynamic input to mixer-matrix assignment
 *  - 18 x 6 mixer-matrix gain stages
 *  - bus routing & volume control
 *  - automatic re-initialization on connect if device was power-cycled
 *
 * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
 * wIndex
 * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
 *      channel, data=Line/Inst (2bytes)
 *      pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
 *      ?? wValue=0x0803/04, ?? (2bytes)
 * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
 *      Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
 * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
 * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
 * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
 * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
 * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
 * 0x3c Matrix Mixer gains, wValue=mixer-node  data=gain(2bytes)
 *      ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
 *
 * USB reads: (i.e. actually issued by original software)
 * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
 * 0x29 wValue=0x0100 sample-rate(4bytes)
 *      wValue=0x0200 ?? 1byte (only once)
 * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
 *
 * USB reads with bRequest = 0x03 = UAC2_CS_MEM
 * 0x3c wValue=0x0002 1byte: sync status (locked=1)
 *      wValue=0x0000 18*2byte: peak meter (inputs)
 *      wValue=0x0001 8(?)*2byte: peak meter (mix)
 *      wValue=0x0003 6*2byte: peak meter (pcm/daw)
 *
 * USB write with bRequest = 0x03
 * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
 *
 *
 * <ditaa>
 *  /--------------\    18chn            6chn    /--------------\
 *  | Hardware  in +--+-------\        /------+--+ ALSA PCM out |
 *  \--------------/  |       |        |      |  \--------------/
 *                    |       |        |      |
 *                    |       v        v      |
 *                    |   +---------------+   |
 *                    |    \ Matrix  Mux /    |
 *                    |     +-----+-----+     |
 *                    |           |           |
 *                    |           | 18chn     |
 *                    |           v           |
 *                    |     +-----------+     |
 *                    |     | Mixer     |     |
 *                    |     |    Matrix |     |
 *                    |     |           |     |
 *                    |     | 18x6 Gain |     |
 *                    |     |   stages  |     |
 *                    |     +-----+-----+     |
 *                    |           |           |
 *                    |           |           |
 *                    | 18chn     | 6chn      | 6chn
 *                    v           v           v
 *                    =========================
 *             +---------------+     +--—------------+
 *              \ Output  Mux /       \ Capture Mux /
 *               +-----+-----+         +-----+-----+
 *                     |                     |
 *                     | 6chn                |
 *                     v                     |
 *              +-------------+              |
 *              | Master Gain |              |
 *              +------+------+              |
 *                     |                     |
 *                     | 6chn                | 18chn
 *                     | (3 stereo pairs)    |
 *  /--------------\   |                     |   /--------------\
 *  | Hardware out |<--/                     \-->| ALSA PCM  in |
 *  \--------------/                             \--------------/
 * </ditaa>
 *
 */

#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/audio-v2.h>

#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>

#include "usbaudio.h"
#include "mixer.h"
#include "helper.h"
#include "power.h"

#include "mixer_scarlett.h"

/* some gui mixers can't handle negative ctl values */
#define SND_SCARLETT_LEVEL_BIAS
#define SND_SCARLETT_MATRIX_IN_MAX
#define SND_SCARLETT_CONTROLS_MAX
#define SND_SCARLETT_OFFSETS_MAX

enum {};

enum {};

struct scarlett_mixer_elem_enum_info {};

struct scarlett_mixer_control {};

struct scarlett_device_info {};

/********************** Enum Strings *************************/

static const struct scarlett_mixer_elem_enum_info opt_pad =;

static const struct scarlett_mixer_elem_enum_info opt_gain =;

static const struct scarlett_mixer_elem_enum_info opt_impedance =;

static const struct scarlett_mixer_elem_enum_info opt_clock =;

static const struct scarlett_mixer_elem_enum_info opt_sync =;

static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
		struct snd_ctl_elem_info *uinfo)
{}

static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
		struct snd_ctl_elem_value *ucontrol)
{}

static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
		struct snd_ctl_elem_value *ucontrol)
{}

static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
{}

static int scarlett_ctl_info(struct snd_kcontrol *kctl,
			     struct snd_ctl_elem_info *uinfo)
{}

static int scarlett_ctl_get(struct snd_kcontrol *kctl,
			    struct snd_ctl_elem_value *ucontrol)
{}

static int scarlett_ctl_put(struct snd_kcontrol *kctl,
			    struct snd_ctl_elem_value *ucontrol)
{}

static void scarlett_generate_name(int i, char *dst, int offsets[])
{}

static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
					  struct snd_ctl_elem_info *uinfo)
{}

static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
				  struct snd_ctl_elem_info *uinfo)
{}

static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
				 struct snd_ctl_elem_value *ucontrol)
{}

static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
				 struct snd_ctl_elem_value *ucontrol)
{}

static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
{}

static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
				  struct snd_ctl_elem_value *ucontrol)
{}

static const struct snd_kcontrol_new usb_scarlett_ctl_switch =;

static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);

static const struct snd_kcontrol_new usb_scarlett_ctl =;

static const struct snd_kcontrol_new usb_scarlett_ctl_master =;

static const struct snd_kcontrol_new usb_scarlett_ctl_enum =;

static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum =;

static const struct snd_kcontrol_new usb_scarlett_ctl_sync =;

static int add_new_ctl(struct usb_mixer_interface *mixer,
		       const struct snd_kcontrol_new *ncontrol,
		       usb_mixer_elem_resume_func_t resume,
		       int index, int offset, int num,
		       int val_type, int channels, const char *name,
		       const struct scarlett_mixer_elem_enum_info *opt,
		       struct usb_mixer_elem_info **elem_ret
)
{}

static int add_output_ctls(struct usb_mixer_interface *mixer,
			   int index, const char *name,
			   const struct scarlett_device_info *info)
{}

/********************** device-specific config *************************/

/*  untested...  */
static const struct scarlett_device_info s6i6_info =;

/*  untested...  */
static const struct scarlett_device_info s8i6_info =;

static const struct scarlett_device_info s18i6_info =;

static const struct scarlett_device_info s18i8_info =;

static const struct scarlett_device_info s18i20_info =;


static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
	const struct scarlett_device_info *info)
{}

/*
 * Create and initialize a mixer for the Focusrite(R) Scarlett
 */
int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
{}