mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-18 02:46:06 +00:00
ALSA: scarlett2: Split direct_monitor out from monitor_other
The notification value for monitor_other on the large interfaces is the same as the notification value for direct_monitor on the 3rd Gen small interfaces. Add a separate scarlett3a_notifications array and split out the direct_monitor handling. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Link: https://lore.kernel.org/r/9b56a483e3e9c1447684f18239a88652c1f01445.1703444932.git.g@b4.vu Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
d9b63123fb
commit
d3cf557b26
@ -277,8 +277,10 @@ static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer);
|
||||
static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer);
|
||||
static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer);
|
||||
static void scarlett2_notify_monitor_other(struct usb_mixer_interface *mixer);
|
||||
static void scarlett2_notify_direct_monitor(struct usb_mixer_interface *mixer);
|
||||
|
||||
/* Arrays of notification callback functions */
|
||||
|
||||
/* Array of notification callback functions */
|
||||
static const struct scarlett2_notification scarlett2_notifications[] = {
|
||||
{ 0x00000001, NULL }, /* ack, gets ignored */
|
||||
{ 0x00000008, scarlett2_notify_sync },
|
||||
@ -289,6 +291,13 @@ static const struct scarlett2_notification scarlett2_notifications[] = {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct scarlett2_notification scarlett3a_notifications[] = {
|
||||
{ 0x00000001, NULL }, /* ack, gets ignored */
|
||||
{ 0x00800000, scarlett2_notify_input_other },
|
||||
{ 0x01000000, scarlett2_notify_direct_monitor },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Configuration parameters that can be read and written */
|
||||
enum {
|
||||
SCARLETT2_CONFIG_DIM_MUTE,
|
||||
@ -379,7 +388,7 @@ static const struct scarlett2_config_set scarlett2_config_set_gen2b = {
|
||||
|
||||
/* Gen 3 devices without a mixer (Solo and 2i2) */
|
||||
static const struct scarlett2_config_set scarlett2_config_set_gen3a = {
|
||||
.notifications = scarlett2_notifications,
|
||||
.notifications = scarlett3a_notifications,
|
||||
.items = {
|
||||
[SCARLETT2_CONFIG_MSD_SWITCH] = {
|
||||
.offset = 0x04, .size = 8, .activate = 6 },
|
||||
@ -690,6 +699,7 @@ struct scarlett2_data {
|
||||
u8 input_air_updated;
|
||||
u8 input_phantom_updated;
|
||||
u8 monitor_other_updated;
|
||||
u8 direct_monitor_updated;
|
||||
u8 mux_updated;
|
||||
u8 speaker_switching_switched;
|
||||
u8 sync;
|
||||
@ -3127,7 +3137,7 @@ static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = {
|
||||
.put = scarlett2_phantom_persistence_ctl_put,
|
||||
};
|
||||
|
||||
/*** Direct Monitor Control ***/
|
||||
/*** Speaker Switching Control ***/
|
||||
|
||||
static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
@ -3147,11 +3157,6 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
|
||||
|
||||
private->monitor_other_updated = 0;
|
||||
|
||||
if (info->direct_monitor)
|
||||
return scarlett2_usb_get_config(
|
||||
mixer, SCARLETT2_CONFIG_DIRECT_MONITOR,
|
||||
1, &private->direct_monitor_switch);
|
||||
|
||||
/* if it doesn't do speaker switching then it also doesn't do
|
||||
* talkback
|
||||
*/
|
||||
@ -3196,119 +3201,6 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_ctl_get(
|
||||
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 = elem->head.mixer->private_data;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&private->data_mutex);
|
||||
|
||||
if (private->hwdep_in_use) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (private->monitor_other_updated) {
|
||||
err = scarlett2_update_monitor_other(mixer);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
}
|
||||
ucontrol->value.enumerated.item[0] = private->direct_monitor_switch;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&private->data_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_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 index = elem->control;
|
||||
int oval, val, err = 0;
|
||||
|
||||
mutex_lock(&private->data_mutex);
|
||||
|
||||
if (private->hwdep_in_use) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
oval = private->direct_monitor_switch;
|
||||
val = min(ucontrol->value.enumerated.item[0], 2U);
|
||||
|
||||
if (oval == val)
|
||||
goto unlock;
|
||||
|
||||
private->direct_monitor_switch = val;
|
||||
|
||||
/* Send switch change to the device */
|
||||
err = scarlett2_usb_set_config(
|
||||
mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val);
|
||||
if (err == 0)
|
||||
err = 1;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&private->data_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_stereo_enum_ctl_info(
|
||||
struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const values[3] = {
|
||||
"Off", "Mono", "Stereo"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1, 3, values);
|
||||
}
|
||||
|
||||
/* Direct Monitor for Solo is mono-only and only needs a boolean control
|
||||
* Direct Monitor for 2i2 is selectable between Off/Mono/Stereo
|
||||
*/
|
||||
static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl[2] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = scarlett2_direct_monitor_ctl_get,
|
||||
.put = scarlett2_direct_monitor_ctl_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "",
|
||||
.info = scarlett2_direct_monitor_stereo_enum_ctl_info,
|
||||
.get = scarlett2_direct_monitor_ctl_get,
|
||||
.put = scarlett2_direct_monitor_ctl_put,
|
||||
}
|
||||
};
|
||||
|
||||
static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct scarlett2_data *private = mixer->private_data;
|
||||
const struct scarlett2_device_info *info = private->info;
|
||||
const char *s;
|
||||
|
||||
if (!info->direct_monitor)
|
||||
return 0;
|
||||
|
||||
s = info->direct_monitor == 1
|
||||
? "Direct Monitor Playback Switch"
|
||||
: "Direct Monitor Playback Enum";
|
||||
|
||||
return scarlett2_add_new_ctl(
|
||||
mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1],
|
||||
0, 1, s, &private->direct_monitor_ctl);
|
||||
}
|
||||
|
||||
/*** Speaker Switching Control ***/
|
||||
|
||||
static int scarlett2_speaker_switch_enum_ctl_info(
|
||||
struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
@ -4014,6 +3906,133 @@ static int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Direct Monitor Control ***/
|
||||
|
||||
static int scarlett2_update_direct_monitor(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct scarlett2_data *private = mixer->private_data;
|
||||
|
||||
private->direct_monitor_updated = 0;
|
||||
|
||||
if (!private->info->direct_monitor)
|
||||
return 0;
|
||||
|
||||
return scarlett2_usb_get_config(
|
||||
mixer, SCARLETT2_CONFIG_DIRECT_MONITOR,
|
||||
1, &private->direct_monitor_switch);
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_ctl_get(
|
||||
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 = elem->head.mixer->private_data;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&private->data_mutex);
|
||||
|
||||
if (private->hwdep_in_use) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (private->direct_monitor_updated) {
|
||||
err = scarlett2_update_direct_monitor(mixer);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
}
|
||||
ucontrol->value.enumerated.item[0] = private->direct_monitor_switch;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&private->data_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_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 index = elem->control;
|
||||
int oval, val, err = 0;
|
||||
|
||||
mutex_lock(&private->data_mutex);
|
||||
|
||||
if (private->hwdep_in_use) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
oval = private->direct_monitor_switch;
|
||||
val = min(ucontrol->value.enumerated.item[0], 2U);
|
||||
|
||||
if (oval == val)
|
||||
goto unlock;
|
||||
|
||||
private->direct_monitor_switch = val;
|
||||
|
||||
/* Send switch change to the device */
|
||||
err = scarlett2_usb_set_config(
|
||||
mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val);
|
||||
if (err == 0)
|
||||
err = 1;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&private->data_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int scarlett2_direct_monitor_stereo_enum_ctl_info(
|
||||
struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
static const char *const values[3] = {
|
||||
"Off", "Mono", "Stereo"
|
||||
};
|
||||
|
||||
return snd_ctl_enum_info(uinfo, 1, 3, values);
|
||||
}
|
||||
|
||||
/* Direct Monitor for Solo is mono-only and only needs a boolean control
|
||||
* Direct Monitor for 2i2 is selectable between Off/Mono/Stereo
|
||||
*/
|
||||
static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl[2] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = scarlett2_direct_monitor_ctl_get,
|
||||
.put = scarlett2_direct_monitor_ctl_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "",
|
||||
.info = scarlett2_direct_monitor_stereo_enum_ctl_info,
|
||||
.get = scarlett2_direct_monitor_ctl_get,
|
||||
.put = scarlett2_direct_monitor_ctl_put,
|
||||
}
|
||||
};
|
||||
|
||||
static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct scarlett2_data *private = mixer->private_data;
|
||||
const struct scarlett2_device_info *info = private->info;
|
||||
const char *s;
|
||||
|
||||
if (!info->direct_monitor)
|
||||
return 0;
|
||||
|
||||
s = info->direct_monitor == 1
|
||||
? "Direct Monitor Playback Switch"
|
||||
: "Direct Monitor Playback Enum";
|
||||
|
||||
return scarlett2_add_new_ctl(
|
||||
mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1],
|
||||
0, 1, s, &private->direct_monitor_ctl);
|
||||
}
|
||||
|
||||
/*** Mux Source Selection Controls ***/
|
||||
|
||||
static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl,
|
||||
@ -4639,7 +4658,7 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = scarlett2_update_monitor_other(mixer);
|
||||
err = scarlett2_update_direct_monitor(mixer);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@ -4647,6 +4666,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
|
||||
if (!scarlett2_has_mixer(private))
|
||||
return 0;
|
||||
|
||||
err = scarlett2_update_monitor_other(mixer);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (scarlett2_has_config_item(private,
|
||||
SCARLETT2_CONFIG_STANDALONE_SWITCH)) {
|
||||
err = scarlett2_usb_get_config(
|
||||
@ -4843,9 +4866,7 @@ static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer)
|
||||
scarlett2_notify_input_phantom(mixer);
|
||||
}
|
||||
|
||||
/* Notify on "monitor other" change (direct monitor, speaker
|
||||
* switching, talkback)
|
||||
*/
|
||||
/* Notify on "monitor other" change (speaker switching, talkback) */
|
||||
static void scarlett2_notify_monitor_other(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct snd_card *card = mixer->chip->card;
|
||||
@ -4854,12 +4875,6 @@ static void scarlett2_notify_monitor_other(struct usb_mixer_interface *mixer)
|
||||
|
||||
private->monitor_other_updated = 1;
|
||||
|
||||
if (info->direct_monitor) {
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&private->direct_monitor_ctl->id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->has_speaker_switching)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&private->speaker_switching_ctl->id);
|
||||
@ -4885,6 +4900,18 @@ static void scarlett2_notify_monitor_other(struct usb_mixer_interface *mixer)
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify on direct monitor switch change */
|
||||
static void scarlett2_notify_direct_monitor(struct usb_mixer_interface *mixer)
|
||||
{
|
||||
struct snd_card *card = mixer->chip->card;
|
||||
struct scarlett2_data *private = mixer->private_data;
|
||||
|
||||
private->direct_monitor_updated = 1;
|
||||
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&private->direct_monitor_ctl->id);
|
||||
}
|
||||
|
||||
/* Interrupt callback */
|
||||
static void scarlett2_notify(struct urb *urb)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user