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.
Unified · Split
| @@ -332,6 +332,7 @@ enum { · 331 unmodified lines | ||
| 332 | 332 | SCARLETT2_CONFIG_MUTE_SWITCH, |
| 333 | 333 | SCARLETT2_CONFIG_SW_HW_SWITCH, |
| 334 | 334 | SCARLETT2_CONFIG_MASTER_VOLUME, |
| 335 | + SCARLETT2_CONFIG_HEADPHONE_VOLUME, | |
| 335 | 336 | SCARLETT2_CONFIG_LEVEL_SWITCH, |
| 336 | 337 | SCARLETT2_CONFIG_PAD_SWITCH, |
| 337 | 338 | SCARLETT2_CONFIG_MSD_SWITCH, |
| @@ -784,6 +785,7 @@ struct scarlett2_data { · 446 unmodified lines | ||
| 784 | 785 | u8 power_status_updated; |
| 785 | 786 | u8 sync; |
| 786 | 787 | u8 master_vol; |
| 788 | + u8 headphone_vol; | |
| 787 | 789 | u8 vol[SCARLETT2_ANALOGUE_MAX]; |
| 788 | 790 | u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; |
| 789 | 791 | u8 mute_switch[SCARLETT2_ANALOGUE_MAX]; |
| @@ -809,6 +811,7 @@ struct scarlett2_data { · 19 unmodified lines | ||
| 809 | 811 | u8 meter_level_map[SCARLETT2_MAX_METERS]; |
| 810 | 812 | struct snd_kcontrol *sync_ctl; |
| 811 | 813 | struct snd_kcontrol *master_vol_ctl; |
| 814 | + struct snd_kcontrol *headphone_vol_ctl; | |
| 812 | 815 | struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; |
| 813 | 816 | struct snd_kcontrol *sw_hw_ctls[SCARLETT2_ANALOGUE_MAX]; |
| 814 | 817 | struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX]; |
| @@ -3324,6 +3327,18 @@ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer) · 2509 unmodified lines | ||
| 3324 | 3327 | private->vol[i] = private->master_vol; |
| 3325 | 3328 | } |
| 3326 | 3329 | |
| 3330 | + if (scarlett2_has_config_item(private, | |
| 3331 | + SCARLETT2_CONFIG_HEADPHONE_VOLUME)) { | |
| 3332 | + err = scarlett2_usb_get_config( | |
| 3333 | + mixer, SCARLETT2_CONFIG_HEADPHONE_VOLUME, | |
| 3334 | + 1, &vol); | |
| 3335 | + if (err < 0) | |
| 3336 | + return err; | |
| 3337 | + | |
| 3338 | + private->headphone_vol = clamp(vol + SCARLETT2_VOLUME_BIAS, | |
| 3339 | + 0, SCARLETT2_VOLUME_BIAS); | |
| 3340 | + } | |
| 3341 | + | |
| 3327 | 3342 | return 0; |
| 3328 | 3343 | } |
| 3329 | 3344 | |
| @@ -3367,6 +3382,34 @@ unlock: · 37 unmodified lines | ||
| 3367 | 3382 | return err; |
| 3368 | 3383 | } |
| 3369 | 3384 | |
| 3385 | +static int scarlett2_headphone_volume_ctl_get( | |
| 3386 | + struct snd_kcontrol *kctl, | |
| 3387 | + struct snd_ctl_elem_value *ucontrol) | |
| 3388 | +{ | |
| 3389 | + struct usb_mixer_elem_info *elem = kctl->private_data; | |
| 3390 | + struct usb_mixer_interface *mixer = elem->head.mixer; | |
| 3391 | + struct scarlett2_data *private = mixer->private_data; | |
| 3392 | + int err = 0; | |
| 3393 | + | |
| 3394 | + mutex_lock(&private->data_mutex); | |
| 3395 | + | |
| 3396 | + if (private->hwdep_in_use) { | |
| 3397 | + err = -EBUSY; | |
| 3398 | + goto unlock; | |
| 3399 | + } | |
| 3400 | + | |
| 3401 | + if (private->vol_updated) { | |
| 3402 | + err = scarlett2_update_volumes(mixer); | |
| 3403 | + if (err < 0) | |
| 3404 | + goto unlock; | |
| 3405 | + } | |
| 3406 | + ucontrol->value.integer.value[0] = private->headphone_vol; | |
| 3407 | + | |
| 3408 | +unlock: | |
| 3409 | + mutex_unlock(&private->data_mutex); | |
| 3410 | + return err; | |
| 3411 | +} | |
| 3412 | + | |
| 3370 | 3413 | static int line_out_remap(struct scarlett2_data *private, int index) |
| 3371 | 3414 | { |
| 3372 | 3415 | const struct scarlett2_device_info *info = private->info; |
| @@ -3456,6 +3499,17 @@ static const struct snd_kcontrol_new scarlett2_master_volume_ctl = { · 83 unmodified lines | ||
| 3456 | 3499 | .tlv = { .p = db_scale_scarlett2_volume } |
| 3457 | 3500 | }; |
| 3458 | 3501 | |
| 3502 | +static const struct snd_kcontrol_new scarlett2_headphone_volume_ctl = { | |
| 3503 | + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
| 3504 | + .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
| 3505 | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
| 3506 | + .name = "", | |
| 3507 | + .info = scarlett2_volume_ctl_info, | |
| 3508 | + .get = scarlett2_headphone_volume_ctl_get, | |
| 3509 | + .private_value = 0, /* max value */ | |
| 3510 | + .tlv = { .p = db_scale_scarlett2_volume } | |
| 3511 | +}; | |
| 3512 | + | |
| 3459 | 3513 | static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = { |
| 3460 | 3514 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 3461 | 3515 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| @@ -4806,6 +4860,18 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) · 1344 unmodified lines | ||
| 4806 | 4860 | return err; |
| 4807 | 4861 | } |
| 4808 | 4862 | |
| 4863 | + /* Add R/O headphone volume control */ | |
| 4864 | + if (scarlett2_has_config_item(private, | |
| 4865 | + SCARLETT2_CONFIG_HEADPHONE_VOLUME)) { | |
| 4866 | + snprintf(s, sizeof(s), "Headphone Playback Volume"); | |
| 4867 | + err = scarlett2_add_new_ctl(mixer, | |
| 4868 | + &scarlett2_headphone_volume_ctl, | |
| 4869 | + 0, 1, s, | |
| 4870 | + &private->headphone_vol_ctl); | |
| 4871 | + if (err < 0) | |
| 4872 | + return err; | |
| 4873 | + } | |
| 4874 | + | |
| 4809 | 4875 | /* Remaining controls are only applicable if the device |
| 4810 | 4876 | * has per-channel line-out volume controls. |
| 4811 | 4877 | */ |
| @@ -6265,7 +6331,7 @@ static void scarlett2_notify_sync(struct usb_mixer_interface *mixer) · 1453 unmodified lines | ||
| 6265 | 6331 | &private->sync_ctl->id); |
| 6266 | 6332 | } |
| 6267 | 6333 | |
| 6268 | −/* Notify on monitor change */ | |
| 6334 | +/* Notify on monitor change (Gen 2/3) */ | |
| 6269 | 6335 | static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer) |
| 6270 | 6336 | { |
| 6271 | 6337 | struct snd_card *card = mixer->chip->card; |
| @@ -6286,6 +6352,20 @@ static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer) · 14 unmodified lines | ||
| 6286 | 6352 | &private->vol_ctls[i]->id); |
| 6287 | 6353 | } |
| 6288 | 6354 | |
| 6355 | +/* Notify on volume change (Gen 4) */ | |
| 6356 | +static __always_unused void scarlett2_notify_volume( | |
| 6357 | + struct usb_mixer_interface *mixer) | |
| 6358 | +{ | |
| 6359 | + struct scarlett2_data *private = mixer->private_data; | |
| 6360 | + | |
| 6361 | + private->vol_updated = 1; | |
| 6362 | + | |
| 6363 | + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | |
| 6364 | + &private->master_vol_ctl->id); | |
| 6365 | + snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | |
| 6366 | + &private->headphone_vol_ctl->id); | |
| 6367 | +} | |
| 6368 | + | |
| 6289 | 6369 | /* Notify on dim/mute change */ |
| 6290 | 6370 | static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer) |
| 6291 | 6371 | { |