Commit 303f204e authored by Geoffrey D. Bennett's avatar Geoffrey D. Bennett Committed by Takashi Iwai

ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch

Add a control to disable the Gen 3 MSD mode so that the full
functionality of the device is available. Don't create the other
controls until MSD mode is disabled.
Signed-off-by: default avatarGeoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/1cb93bbe585f6b0a74f5dc27450bc87e1f3776dc.1624379707.git.g@b4.vuSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a5b36123
...@@ -44,12 +44,13 @@ ...@@ -44,12 +44,13 @@
* interface during driver initialisation added in May 2021 (thanks to * interface during driver initialisation added in May 2021 (thanks to
* Vladimir Sadovnikov for figuring out how). * Vladimir Sadovnikov for figuring out how).
* *
* This ALSA mixer gives access to: * This ALSA mixer gives access to (model-dependent):
* - input, output, mixer-matrix muxes * - input, output, mixer-matrix muxes
* - mixer-matrix gain stages * - mixer-matrix gain stages
* - gain/volume/mute controls * - gain/volume/mute controls
* - level meters * - level meters
* - line/inst level and pad controls * - line/inst level and pad controls
* - disable/enable MSD mode
* *
* <ditaa> * <ditaa>
* /--------------\ 18chn 20chn /--------------\ * /--------------\ 18chn 20chn /--------------\
...@@ -102,6 +103,14 @@ ...@@ -102,6 +103,14 @@
* \--------------/ * \--------------/
* </ditaa> * </ditaa>
* *
* Gen 3 devices have a Mass Storage Device (MSD) mode where a small
* disk with registration and driver download information is presented
* to the host. To access the full functionality of the device without
* proprietary software, MSD mode can be disabled by:
* - holding down the 48V button for five seconds while powering on
* the device, or
* - using this driver and alsamixer to change the "MSD Mode" setting
* to Off and power-cycling the device
*/ */
#include <linux/slab.h> #include <linux/slab.h>
...@@ -120,6 +129,9 @@ ...@@ -120,6 +129,9 @@
/* device_setup value to enable */ /* device_setup value to enable */
#define SCARLETT2_ENABLE 0x01 #define SCARLETT2_ENABLE 0x01
/* device_setup value to allow turning MSD mode back on */
#define SCARLETT2_MSD_ENABLE 0x02
/* some gui mixers can't handle negative ctl values */ /* some gui mixers can't handle negative ctl values */
#define SCARLETT2_VOLUME_BIAS 127 #define SCARLETT2_VOLUME_BIAS 127
...@@ -279,6 +291,12 @@ struct scarlett2_mux_entry { ...@@ -279,6 +291,12 @@ struct scarlett2_mux_entry {
struct scarlett2_device_info { struct scarlett2_device_info {
u32 usb_id; /* USB device identifier */ u32 usb_id; /* USB device identifier */
/* Gen 3 devices have an internal MSD mode switch that needs
* to be disabled in order to access the full functionality of
* the device.
*/
u8 has_msd_mode;
/* line out hw volume is sw controlled */ /* line out hw volume is sw controlled */
u8 line_out_hw_vol; u8 line_out_hw_vol;
...@@ -327,6 +345,7 @@ struct scarlett2_data { ...@@ -327,6 +345,7 @@ struct scarlett2_data {
u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
u8 msd_switch;
struct snd_kcontrol *sync_ctl; struct snd_kcontrol *sync_ctl;
struct snd_kcontrol *master_vol_ctl; struct snd_kcontrol *master_vol_ctl;
struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
...@@ -489,6 +508,7 @@ static const struct scarlett2_device_info s18i20_gen2_info = { ...@@ -489,6 +508,7 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
static const struct scarlett2_device_info s4i4_gen3_info = { static const struct scarlett2_device_info s4i4_gen3_info = {
.usb_id = USB_ID(0x1235, 0x8212), .usb_id = USB_ID(0x1235, 0x8212),
.has_msd_mode = 1,
.level_input_count = 2, .level_input_count = 2,
.pad_input_count = 2, .pad_input_count = 2,
...@@ -530,6 +550,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = { ...@@ -530,6 +550,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
static const struct scarlett2_device_info s8i6_gen3_info = { static const struct scarlett2_device_info s8i6_gen3_info = {
.usb_id = USB_ID(0x1235, 0x8213), .usb_id = USB_ID(0x1235, 0x8213),
.has_msd_mode = 1,
.level_input_count = 2, .level_input_count = 2,
.pad_input_count = 2, .pad_input_count = 2,
...@@ -578,6 +599,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = { ...@@ -578,6 +599,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
static const struct scarlett2_device_info s18i8_gen3_info = { static const struct scarlett2_device_info s18i8_gen3_info = {
.usb_id = USB_ID(0x1235, 0x8214), .usb_id = USB_ID(0x1235, 0x8214),
.has_msd_mode = 1,
.line_out_hw_vol = 1, .line_out_hw_vol = 1,
.level_input_count = 2, .level_input_count = 2,
.pad_input_count = 2, .pad_input_count = 2,
...@@ -639,6 +661,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { ...@@ -639,6 +661,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
static const struct scarlett2_device_info s18i20_gen3_info = { static const struct scarlett2_device_info s18i20_gen3_info = {
.usb_id = USB_ID(0x1235, 0x8215), .usb_id = USB_ID(0x1235, 0x8215),
.has_msd_mode = 1,
.line_out_hw_vol = 1, .line_out_hw_vol = 1,
.level_input_count = 2, .level_input_count = 2,
.pad_input_count = 8, .pad_input_count = 8,
...@@ -786,7 +809,8 @@ enum { ...@@ -786,7 +809,8 @@ enum {
SCARLETT2_CONFIG_SW_HW_SWITCH = 3, SCARLETT2_CONFIG_SW_HW_SWITCH = 3,
SCARLETT2_CONFIG_LEVEL_SWITCH = 4, SCARLETT2_CONFIG_LEVEL_SWITCH = 4,
SCARLETT2_CONFIG_PAD_SWITCH = 5, SCARLETT2_CONFIG_PAD_SWITCH = 5,
SCARLETT2_CONFIG_COUNT = 6 SCARLETT2_CONFIG_MSD_SWITCH = 6,
SCARLETT2_CONFIG_COUNT = 7
}; };
/* Location, size, and activation command number for the configuration /* Location, size, and activation command number for the configuration
...@@ -817,6 +841,9 @@ static const struct scarlett2_config ...@@ -817,6 +841,9 @@ static const struct scarlett2_config
[SCARLETT2_CONFIG_PAD_SWITCH] = { [SCARLETT2_CONFIG_PAD_SWITCH] = {
.offset = 0x84, .size = 1, .activate = 8 }, .offset = 0x84, .size = 1, .activate = 8 },
[SCARLETT2_CONFIG_MSD_SWITCH] = {
.offset = 0x9d, .size = 1, .activate = 6 },
}; };
/* proprietary request/response format */ /* proprietary request/response format */
...@@ -1016,7 +1043,8 @@ static int scarlett2_usb_set_config( ...@@ -1016,7 +1043,8 @@ static int scarlett2_usb_set_config(
return err; return err;
/* Schedule the change to be written to NVRAM */ /* Schedule the change to be written to NVRAM */
schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); if (config_item->activate != SCARLETT2_USB_CONFIG_SAVE)
schedule_delayed_work(&private->work, msecs_to_jiffies(2000));
return 0; return 0;
} }
...@@ -2351,6 +2379,71 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) ...@@ -2351,6 +2379,71 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer)
"Level Meter", NULL); "Level Meter", NULL);
} }
/*** MSD Controls ***/
static int scarlett2_msd_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_info *elem = kctl->private_data;
struct scarlett2_data *private = elem->head.mixer->private_data;
ucontrol->value.integer.value[0] = private->msd_switch;
return 0;
}
static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_info *elem = kctl->private_data;
struct usb_mixer_interface *mixer = elem->head.mixer;
struct scarlett2_data *private = mixer->private_data;
int oval, val, err = 0;
mutex_lock(&private->data_mutex);
oval = private->msd_switch;
val = !!ucontrol->value.integer.value[0];
if (oval == val)
goto unlock;
private->msd_switch = val;
/* Send switch change to the device */
err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MSD_SWITCH,
0, val);
unlock:
mutex_unlock(&private->data_mutex);
return err;
}
static const struct snd_kcontrol_new scarlett2_msd_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "",
.info = snd_ctl_boolean_mono_info,
.get = scarlett2_msd_ctl_get,
.put = scarlett2_msd_ctl_put,
};
static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer)
{
struct scarlett2_data *private = mixer->private_data;
const struct scarlett2_device_info *info = private->info;
if (!info->has_msd_mode)
return 0;
/* If MSD mode is off, hide the switch by default */
if (!private->msd_switch && !(mixer->chip->setup & SCARLETT2_MSD_ENABLE))
return 0;
/* Add MSD control */
return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl,
0, 1, "MSD Mode", NULL);
}
/*** Cleanup/Suspend Callbacks ***/ /*** Cleanup/Suspend Callbacks ***/
static void scarlett2_private_free(struct usb_mixer_interface *mixer) static void scarlett2_private_free(struct usb_mixer_interface *mixer)
...@@ -2488,6 +2581,18 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) ...@@ -2488,6 +2581,18 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
struct scarlett2_usb_volume_status volume_status; struct scarlett2_usb_volume_status volume_status;
int err, i; int err, i;
if (info->has_msd_mode) {
err = scarlett2_usb_get_config(
mixer, SCARLETT2_CONFIG_MSD_SWITCH,
1, &private->msd_switch);
if (err < 0)
return err;
/* no other controls are created if MSD mode is on */
if (private->msd_switch)
return 0;
}
err = scarlett2_update_input_other(mixer); err = scarlett2_update_input_other(mixer);
if (err < 0) if (err < 0)
return err; return err;
...@@ -2710,6 +2815,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) ...@@ -2710,6 +2815,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
if (err < 0) if (err < 0)
return err; return err;
/* Create the MSD control */
err = scarlett2_add_msd_ctl(mixer);
if (err < 0)
return err;
/* If MSD mode is enabled, don't create any other controls */
if (((struct scarlett2_data *)mixer->private_data)->msd_switch)
return 0;
/* Create the analogue output controls */ /* Create the analogue output controls */
err = scarlett2_add_line_out_ctls(mixer); err = scarlett2_add_line_out_ctls(mixer);
if (err < 0) if (err < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment