diff options
author | Geoffrey D. Bennett <g@b4.vu> | 2023-12-26 19:08:52 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-12-29 15:52:14 +0100 |
commit | 2ecca0df90cbd082ab61530bb4e758a0fb970d21 (patch) | |
tree | 124260b33c47174654d8eb3c9b8275df014ce971 /sound/usb | |
parent | ALSA: scarlett2: Add minimum firmware version check (diff) | |
download | linux-2ecca0df90cbd082ab61530bb4e758a0fb970d21.tar.xz linux-2ecca0df90cbd082ab61530bb4e758a0fb970d21.zip |
ALSA: scarlett2: Add R/O headphone volume control
The Scarlett 4i4 Gen 4 adds a R/O headphone volume control in addition
to a R/O master volume control (which is already supported).
Mark the new scarlett2_notify_volume() function with __always_unused
until it gets used when the Gen 4 notification callback function arrays
are added.
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/bd4a76da157f8cc3fbfa02eba96d02bdb86817c5.1703612638.git.g@b4.vu
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/mixer_scarlett2.c | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index f1c9f6b022ce..94413fca2b6c 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -332,6 +332,7 @@ enum { SCARLETT2_CONFIG_MUTE_SWITCH, SCARLETT2_CONFIG_SW_HW_SWITCH, SCARLETT2_CONFIG_MASTER_VOLUME, + SCARLETT2_CONFIG_HEADPHONE_VOLUME, SCARLETT2_CONFIG_LEVEL_SWITCH, SCARLETT2_CONFIG_PAD_SWITCH, SCARLETT2_CONFIG_MSD_SWITCH, @@ -784,6 +785,7 @@ struct scarlett2_data { u8 power_status_updated; u8 sync; u8 master_vol; + u8 headphone_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; u8 mute_switch[SCARLETT2_ANALOGUE_MAX]; @@ -809,6 +811,7 @@ struct scarlett2_data { u8 meter_level_map[SCARLETT2_MAX_METERS]; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; + struct snd_kcontrol *headphone_vol_ctl; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *sw_hw_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX]; @@ -3324,6 +3327,18 @@ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer) private->vol[i] = private->master_vol; } + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_HEADPHONE_VOLUME)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_HEADPHONE_VOLUME, + 1, &vol); + if (err < 0) + return err; + + private->headphone_vol = clamp(vol + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + } + return 0; } @@ -3367,6 +3382,34 @@ unlock: return err; } +static int scarlett2_headphone_volume_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; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->vol_updated) { + err = scarlett2_update_volumes(mixer); + if (err < 0) + goto unlock; + } + ucontrol->value.integer.value[0] = private->headphone_vol; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + static int line_out_remap(struct scarlett2_data *private, int index) { const struct scarlett2_device_info *info = private->info; @@ -3456,6 +3499,17 @@ static const struct snd_kcontrol_new scarlett2_master_volume_ctl = { .tlv = { .p = db_scale_scarlett2_volume } }; +static const struct snd_kcontrol_new scarlett2_headphone_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_volume_ctl_info, + .get = scarlett2_headphone_volume_ctl_get, + .private_value = 0, /* max value */ + .tlv = { .p = db_scale_scarlett2_volume } +}; + static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -4806,6 +4860,18 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add R/O headphone volume control */ + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_HEADPHONE_VOLUME)) { + snprintf(s, sizeof(s), "Headphone Playback Volume"); + err = scarlett2_add_new_ctl(mixer, + &scarlett2_headphone_volume_ctl, + 0, 1, s, + &private->headphone_vol_ctl); + if (err < 0) + return err; + } + /* Remaining controls are only applicable if the device * has per-channel line-out volume controls. */ @@ -6265,7 +6331,7 @@ static void scarlett2_notify_sync(struct usb_mixer_interface *mixer) &private->sync_ctl->id); } -/* Notify on monitor change */ +/* Notify on monitor change (Gen 2/3) */ static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer) { struct snd_card *card = mixer->chip->card; @@ -6286,6 +6352,20 @@ static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer) &private->vol_ctls[i]->id); } +/* Notify on volume change (Gen 4) */ +static __always_unused void scarlett2_notify_volume( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + private->vol_updated = 1; + + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->master_vol_ctl->id); + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->headphone_vol_ctl->id); +} + /* Notify on dim/mute change */ static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer) { |