summaryrefslogtreecommitdiff
path: root/sound/usb
diff options
context:
space:
mode:
authorGeoffrey D. Bennett <g@b4.vu>2023-12-27 04:37:56 +1030
committerTakashi Iwai <tiwai@suse.de>2023-12-29 15:52:13 +0100
commit882a2a36c41df96d0449c3751dceb86415b44a56 (patch)
tree6e74b973343ae289a2938f29769e8da1da7454bf /sound/usb
parent0d2e791db4c81d295334ca09ad30cc2083f94b04 (diff)
ALSA: scarlett2: Disable autogain during phantom power state change
When phantom power is enabled or disabled, the autogain control cannot be enabled until the interface has signalled that the change is complete and the input is unmuted. Update those controls to be read-only during this time. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://lore.kernel.org/r/f49f7bf9358e1f20713d95d407d8d6a436859877.1703612638.git.g@b4.vu
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/mixer_scarlett2.c123
1 files changed, 113 insertions, 10 deletions
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index e1b7398fae33..6266f5d3fab8 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -2391,6 +2391,10 @@ static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer)
/*** Autogain Switch and Status Controls ***/
+/* Forward declarations as phantom power and autogain can disable each other */
+static int scarlett2_check_input_phantom_updated(struct usb_mixer_interface *);
+static int scarlett2_phantom_is_switching(struct scarlett2_data *, int);
+
/* Set the access mode of a control to read-only (val = 0) or
* read-write (val = 1).
*/
@@ -2557,6 +2561,27 @@ static int scarlett2_check_put_during_autogain(
return 0;
}
+static int scarlett2_autogain_switch_ctl_info(
+ struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ 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 err;
+
+ mutex_lock(&private->data_mutex);
+
+ err = scarlett2_check_input_phantom_updated(mixer);
+ if (err < 0)
+ goto unlock;
+
+ err = snd_ctl_boolean_mono_info(kctl, uinfo);
+
+unlock:
+ mutex_unlock(&private->data_mutex);
+ return err;
+}
+
static int scarlett2_autogain_switch_ctl_get(
struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
{
@@ -2619,7 +2644,7 @@ static int scarlett2_autogain_switch_ctl_put(
struct scarlett2_data *private = mixer->private_data;
int index = elem->control;
- int oval, val, err = 0;
+ int oval, val, err;
mutex_lock(&private->data_mutex);
@@ -2628,6 +2653,15 @@ static int scarlett2_autogain_switch_ctl_put(
goto unlock;
}
+ err = scarlett2_check_input_phantom_updated(mixer);
+ if (err < 0)
+ goto unlock;
+
+ if (scarlett2_phantom_is_switching(private, index)) {
+ err = -EPERM;
+ goto unlock;
+ }
+
oval = private->autogain_switch[index];
val = !!ucontrol->value.integer.value[0];
@@ -2664,7 +2698,7 @@ static int scarlett2_autogain_status_ctl_info(
static const struct snd_kcontrol_new scarlett2_autogain_switch_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "",
- .info = snd_ctl_boolean_mono_info,
+ .info = scarlett2_autogain_switch_ctl_info,
.get = scarlett2_autogain_switch_ctl_get,
.put = scarlett2_autogain_switch_ctl_put
};
@@ -3983,13 +4017,74 @@ static int scarlett2_update_input_phantom(struct usb_mixer_interface *mixer)
return 0;
}
+/* Check if phantom power on the given input is currently changing state */
+static int scarlett2_phantom_is_switching(
+ struct scarlett2_data *private, int line_num)
+{
+ const struct scarlett2_device_info *info = private->info;
+ int index = line_num / info->inputs_per_phantom;
+
+ return !!(private->phantom_switch[index] & 0x02);
+}
+
+/* Update autogain controls' access mode when phantom power changes state */
+static void scarlett2_phantom_update_access(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+ const struct scarlett2_device_info *info = private->info;
+ int i;
+
+ /* Disable autogain controls if phantom power is changing state */
+ for (i = 0; i < info->gain_input_count; i++) {
+ int val = !scarlett2_phantom_is_switching(private, i);
+
+ scarlett2_set_ctl_access(private->autogain_ctls[i], val);
+ }
+}
+
+/* Notify of access mode change for autogain which can't be enabled
+ * while phantom power is changing.
+ */
+static void scarlett2_phantom_notify_access(struct usb_mixer_interface *mixer)
+{
+ struct snd_card *card = mixer->chip->card;
+ struct scarlett2_data *private = mixer->private_data;
+ const struct scarlett2_device_info *info = private->info;
+ int i;
+
+ for (i = 0; i < info->gain_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
+ &private->autogain_ctls[i]->id);
+}
+
+/* Call scarlett2_update_input_phantom() and
+ * scarlett2_phantom_update_access() if input_phantom_updated is set.
+ */
+static int scarlett2_check_input_phantom_updated(
+ struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+ int err;
+
+ if (!private->input_phantom_updated)
+ return 0;
+
+ err = scarlett2_update_input_phantom(mixer);
+ if (err < 0)
+ return err;
+
+ scarlett2_phantom_update_access(mixer);
+
+ return 0;
+}
+
static int scarlett2_phantom_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 = mixer->private_data;
- int err = 0;
+ int err;
mutex_lock(&private->data_mutex);
@@ -3998,11 +4093,10 @@ static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl,
goto unlock;
}
- if (private->input_phantom_updated) {
- err = scarlett2_update_input_phantom(mixer);
- if (err < 0)
- goto unlock;
- }
+ err = scarlett2_check_input_phantom_updated(mixer);
+ if (err < 0)
+ goto unlock;
+
ucontrol->value.integer.value[0] = scarlett2_decode_muteable(
private->phantom_switch[elem->control]);
@@ -4051,6 +4145,9 @@ static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl,
if (err == 0)
err = 1;
+ scarlett2_phantom_update_access(mixer);
+ scarlett2_phantom_notify_access(mixer);
+
unlock:
mutex_unlock(&private->data_mutex);
return err;
@@ -5912,6 +6009,8 @@ static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer)
for (i = 0; i < info->phantom_count; i++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->phantom_ctls[i]->id);
+
+ scarlett2_phantom_notify_access(mixer);
}
/* Notify on "input other" change (level/pad/air/phantom) */
@@ -6231,9 +6330,13 @@ static int snd_scarlett2_controls_create(
if (err < 0)
return err;
- /* Set the access mode of controls disabled during autogain */
- if (private->info->gain_input_count)
+ /* Set the access mode of controls disabled during
+ * autogain/phantom power switching.
+ */
+ if (private->info->gain_input_count) {
scarlett2_autogain_update_access(mixer);
+ scarlett2_phantom_update_access(mixer);
+ }
/* Set up the interrupt polling */
err = scarlett2_init_notify(mixer);