[SRU][N][PATCH 1/2] ALSA: scarlett2: Move initialisation code lower in the source
Roxana Nicolescu
roxana.nicolescu at canonical.com
Tue Sep 24 13:31:56 UTC 2024
From: "Geoffrey D. Bennett" <g at b4.vu>
BugLink: https://bugs.launchpad.net/bugs/2076402
So that more forward declarations won't be required when we add
handling of the ACK notification, move the initialisation functions to
after the notification functions.
Signed-off-by: Geoffrey D. Bennett <g at b4.vu>
Signed-off-by: Takashi Iwai <tiwai at suse.de>
Message-ID: <0922071cb8be99a2394705de27b917d1e4e46f3f.1710264833.git.g at b4.vu>
(cherry picked from commit 4074f8d23278e9e32aabe9dba60f6dddaf68e6ef)
Signed-off-by: Roxana Nicolescu <roxana.nicolescu at canonical.com>
---
sound/usb/mixer_scarlett2.c | 1187 ++++++++++++++++++-----------------
1 file changed, 595 insertions(+), 592 deletions(-)
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index bd114be537d7..8390b646c0ae 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -6383,798 +6383,801 @@ static int scarlett2_add_power_status_ctl(struct usb_mixer_interface *mixer)
&private->power_status_ctl);
}
-/*** Cleanup/Suspend Callbacks ***/
+/*** Notification Handlers ***/
-static void scarlett2_private_free(struct usb_mixer_interface *mixer)
+/* Notify on sync change */
+static void scarlett2_notify_sync(struct usb_mixer_interface *mixer)
{
struct scarlett2_data *private = mixer->private_data;
- cancel_delayed_work_sync(&private->work);
- kfree(private);
- mixer->private_data = NULL;
+ private->sync_updated = 1;
+
+ snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->sync_ctl->id);
}
-static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
+/* Notify on monitor change (Gen 2/3) */
+static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer)
{
+ struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
+ int i;
- if (cancel_delayed_work_sync(&private->work))
- scarlett2_config_save(private->mixer);
-}
-
-/*** Initialisation ***/
-
-static void scarlett2_count_io(struct scarlett2_data *private)
-{
- const struct scarlett2_device_info *info = private->info;
- const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
- int port_type, srcs = 0, dsts = 0;
+ if (!scarlett2_has_config_item(private, SCARLETT2_CONFIG_SW_HW_SWITCH))
+ return;
- /* Count the number of mux sources and destinations */
- for (port_type = 0;
- port_type < SCARLETT2_PORT_TYPE_COUNT;
- port_type++) {
- srcs += port_count[port_type][SCARLETT2_PORT_IN];
- dsts += port_count[port_type][SCARLETT2_PORT_OUT];
- }
+ private->vol_updated = 1;
- private->num_mux_srcs = srcs;
- private->num_mux_dsts = dsts;
+ snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->master_vol_ctl->id);
- /* Mixer inputs are mux outputs and vice versa.
- * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but
- * doesn't have mixer controls.
- */
- private->num_mix_in =
- port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] -
- info->dsp_count;
+ for (i = 0; i < private->num_line_out; i++)
+ if (private->vol_sw_hw_switch[line_out_remap(private, i)])
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->vol_ctls[i]->id);
+}
- private->num_mix_out =
- port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] -
- info->dsp_count;
+/* Notify on volume change (Gen 4) */
+static void scarlett2_notify_volume(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
- /* Number of analogue line outputs */
- private->num_line_out =
- port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
+ private->vol_updated = 1;
- /* Number of monitor mix controls */
- private->num_monitor_mix_ctls =
- info->direct_monitor * 2 * private->num_mix_in;
+ 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);
}
-/* Look through the interface descriptors for the Focusrite Control
- * interface (bInterfaceClass = 255 Vendor Specific Class) and set
- * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval
- * in private
- */
-static int scarlett2_find_fc_interface(struct usb_device *dev,
- struct scarlett2_data *private)
+/* Notify on dim/mute change */
+static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer)
{
- struct usb_host_config *config = dev->actconfig;
+ struct snd_card *card = mixer->chip->card;
+ struct scarlett2_data *private = mixer->private_data;
int i;
- for (i = 0; i < config->desc.bNumInterfaces; i++) {
- struct usb_interface *intf = config->interface[i];
- struct usb_interface_descriptor *desc =
- &intf->altsetting[0].desc;
- struct usb_endpoint_descriptor *epd;
+ if (!scarlett2_has_config_item(private, SCARLETT2_CONFIG_SW_HW_SWITCH))
+ return;
- if (desc->bInterfaceClass != 255)
- continue;
+ private->dim_mute_updated = 1;
- epd = get_endpoint(intf->altsetting, 0);
- private->bInterfaceNumber = desc->bInterfaceNumber;
- private->bEndpointAddress = epd->bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize);
- private->bInterval = epd->bInterval;
- return 0;
- }
+ for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->dim_mute_ctls[i]->id);
- return -EINVAL;
+ for (i = 0; i < private->num_line_out; i++)
+ if (private->vol_sw_hw_switch[line_out_remap(private, i)])
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->mute_ctls[i]->id);
}
-/* Initialise private data */
-static int scarlett2_init_private(struct usb_mixer_interface *mixer,
- const struct scarlett2_device_entry *entry)
+/* Notify on input level switch change */
+static void scarlett2_notify_input_level(struct usb_mixer_interface *mixer)
{
- struct scarlett2_data *private =
- kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL);
+ struct snd_card *card = mixer->chip->card;
+ struct scarlett2_data *private = mixer->private_data;
+ const struct scarlett2_device_info *info = private->info;
+ int i;
- if (!private)
- return -ENOMEM;
+ private->input_level_updated = 1;
- mutex_init(&private->usb_mutex);
- mutex_init(&private->data_mutex);
- INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work);
+ for (i = 0; i < info->level_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->level_ctls[i]->id);
+}
- mixer->private_data = private;
- mixer->private_free = scarlett2_private_free;
- mixer->private_suspend = scarlett2_private_suspend;
+/* Notify on input pad switch change */
+static void scarlett2_notify_input_pad(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;
- private->info = entry->info;
- private->config_set = entry->info->config_set;
- private->series_name = entry->series_name;
- scarlett2_count_io(private);
- private->scarlett2_seq = 0;
- private->mixer = mixer;
+ private->input_pad_updated = 1;
- return scarlett2_find_fc_interface(mixer->chip->dev, private);
+ for (i = 0; i < info->pad_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->pad_ctls[i]->id);
}
-/* Cargo cult proprietary initialisation sequence */
-static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
+/* Notify on input air switch change */
+static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer)
{
- struct usb_device *dev = mixer->chip->dev;
+ struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
- u8 step0_buf[24];
- u8 step2_buf[84];
- int err;
+ const struct scarlett2_device_info *info = private->info;
+ int i;
- if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0)))
- return -EINVAL;
+ private->input_air_updated = 1;
- /* step 0 */
- err = scarlett2_usb_rx(dev, private->bInterfaceNumber,
- SCARLETT2_USB_CMD_INIT,
- step0_buf, sizeof(step0_buf));
- if (err < 0)
- return err;
+ for (i = 0; i < info->air_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->air_ctls[i]->id);
+}
- /* step 1 */
- private->scarlett2_seq = 1;
- err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0);
- if (err < 0)
- return err;
+/* Notify on input phantom switch change */
+static void scarlett2_notify_input_phantom(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;
- /* step 2 */
- private->scarlett2_seq = 1;
- err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2,
- NULL, 0,
- step2_buf, sizeof(step2_buf));
- if (err < 0)
- return err;
+ private->input_phantom_updated = 1;
- /* extract 4-byte firmware version from step2_buf[8] */
- private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8));
- usb_audio_info(mixer->chip,
- "Firmware version %d\n",
- private->firmware_version);
+ for (i = 0; i < info->phantom_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->phantom_ctls[i]->id);
- return 0;
+ scarlett2_phantom_notify_access(mixer);
}
-/* Get the flash segment numbers for the App_Settings and App_Upgrade
- * segments and put them in the private data
- */
-static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer)
+/* Notify on "input other" change (level/pad/air/phantom) */
+static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer)
+{
+ scarlett2_notify_input_level(mixer);
+ scarlett2_notify_input_pad(mixer);
+ scarlett2_notify_input_air(mixer);
+ scarlett2_notify_input_phantom(mixer);
+}
+
+/* Notify on input select change */
+static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer)
{
+ struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
- int err, count, i;
+ const struct scarlett2_device_info *info = private->info;
+ int i;
- struct {
- __le32 size;
- __le32 count;
- u8 unknown[8];
- } __packed flash_info;
+ if (!info->gain_input_count)
+ return;
- struct {
- __le32 size;
- __le32 flags;
- char name[16];
- } __packed segment_info;
+ private->input_select_updated = 1;
- err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH,
- NULL, 0,
- &flash_info, sizeof(flash_info));
- if (err < 0)
- return err;
+ snd_ctl_notify(card,
+ SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
+ &private->input_select_ctl->id);
- count = le32_to_cpu(flash_info.count);
+ for (i = 0; i < info->gain_input_count / 2; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->input_link_ctls[i]->id);
+}
- /* sanity check count */
- if (count < SCARLETT2_SEGMENT_NUM_MIN ||
- count > SCARLETT2_SEGMENT_NUM_MAX + 1) {
- usb_audio_err(mixer->chip,
- "invalid flash segment count: %d\n", count);
- return -EINVAL;
- }
-
- for (i = 0; i < count; i++) {
- __le32 segment_num_req = cpu_to_le32(i);
- int flash_segment_id;
-
- err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT,
- &segment_num_req, sizeof(segment_num_req),
- &segment_info, sizeof(segment_info));
- if (err < 0) {
- usb_audio_err(mixer->chip,
- "failed to get flash segment info %d: %d\n",
- i, err);
- return err;
- }
-
- if (!strncmp(segment_info.name,
- SCARLETT2_SEGMENT_SETTINGS_NAME, 16))
- flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS;
- else if (!strncmp(segment_info.name,
- SCARLETT2_SEGMENT_FIRMWARE_NAME, 16))
- flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE;
- else
- continue;
+/* Notify on input gain change */
+static void scarlett2_notify_input_gain(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;
- private->flash_segment_nums[flash_segment_id] = i;
- private->flash_segment_blocks[flash_segment_id] =
- le32_to_cpu(segment_info.size) /
- SCARLETT2_FLASH_BLOCK_SIZE;
- }
+ if (!info->gain_input_count)
+ return;
- /* segment 0 is App_Gold and we never want to touch that, so
- * use 0 as the "not-found" value
- */
- if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) {
- usb_audio_err(mixer->chip,
- "failed to find flash segment %s\n",
- SCARLETT2_SEGMENT_SETTINGS_NAME);
- return -EINVAL;
- }
- if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) {
- usb_audio_err(mixer->chip,
- "failed to find flash segment %s\n",
- SCARLETT2_SEGMENT_FIRMWARE_NAME);
- return -EINVAL;
- }
+ private->input_gain_updated = 1;
- return 0;
+ for (i = 0; i < info->gain_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->input_gain_ctls[i]->id);
}
-/* Read configuration from the interface on start */
-static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
+/* Notify on autogain change */
+static void scarlett2_notify_autogain(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 err, i;
-
- if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) {
- err = scarlett2_usb_get_config(
- mixer, SCARLETT2_CONFIG_MSD_SWITCH,
- 1, &private->msd_switch);
- if (err < 0)
- return err;
- }
-
- if (private->firmware_version < info->min_firmware_version) {
- usb_audio_err(mixer->chip,
- "Focusrite %s firmware version %d is too old; "
- "need %d",
- private->series_name,
- private->firmware_version,
- info->min_firmware_version);
- return 0;
- }
-
- /* no other controls are created if MSD mode is on */
- if (private->msd_switch)
- return 0;
-
- err = scarlett2_update_input_level(mixer);
- if (err < 0)
- return err;
-
- err = scarlett2_update_input_pad(mixer);
- if (err < 0)
- return err;
+ int i;
- err = scarlett2_update_input_air(mixer);
- if (err < 0)
- return err;
+ if (!info->gain_input_count)
+ return;
- err = scarlett2_update_input_phantom(mixer);
- if (err < 0)
- return err;
+ private->autogain_updated = 1;
- err = scarlett2_update_direct_monitor(mixer);
- if (err < 0)
- return err;
+ for (i = 0; i < info->gain_input_count; i++) {
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->autogain_ctls[i]->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->autogain_status_ctls[i]->id);
+ }
- /* the rest of the configuration is for devices with a mixer */
- if (!scarlett2_has_mixer(private))
- return 0;
+ scarlett2_autogain_notify_access(mixer);
+}
- err = scarlett2_update_monitor_mix(mixer);
- if (err < 0)
- return err;
+/* Notify on input safe switch change */
+static void scarlett2_notify_input_safe(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;
- err = scarlett2_update_monitor_other(mixer);
- if (err < 0)
- return err;
+ if (!info->gain_input_count)
+ return;
- if (scarlett2_has_config_item(private,
- SCARLETT2_CONFIG_STANDALONE_SWITCH)) {
- err = scarlett2_usb_get_config(
- mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH,
- 1, &private->standalone_switch);
- if (err < 0)
- return err;
- }
+ private->input_safe_updated = 1;
- if (scarlett2_has_config_item(private,
- SCARLETT2_CONFIG_POWER_EXT)) {
- err = scarlett2_update_power_status(mixer);
- if (err < 0)
- return err;
- }
+ for (i = 0; i < info->gain_input_count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->safe_ctls[i]->id);
+}
- err = scarlett2_update_sync(mixer);
- if (err < 0)
- return err;
+/* 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;
+ struct scarlett2_data *private = mixer->private_data;
+ const struct scarlett2_device_info *info = private->info;
- if (scarlett2_has_config_item(private,
- SCARLETT2_CONFIG_LINE_OUT_VOLUME)) {
- s16 sw_vol[SCARLETT2_ANALOGUE_MAX];
+ private->monitor_other_updated = 1;
- /* read SW line out volume */
- err = scarlett2_usb_get_config(
- mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME,
- private->num_line_out, &sw_vol);
- if (err < 0)
- return err;
+ if (info->has_speaker_switching)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->speaker_switching_ctl->id);
- for (i = 0; i < private->num_line_out; i++)
- private->vol[i] = clamp(
- sw_vol[i] + SCARLETT2_VOLUME_BIAS,
- 0, SCARLETT2_VOLUME_BIAS);
+ if (info->has_talkback)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->talkback_ctl->id);
- /* read SW mute */
- err = scarlett2_usb_get_config(
- mixer, SCARLETT2_CONFIG_MUTE_SWITCH,
- private->num_line_out, &private->mute_switch);
- if (err < 0)
- return err;
+ /* if speaker switching was recently enabled or disabled,
+ * invalidate the dim/mute and mux enum controls
+ */
+ if (private->speaker_switching_switched) {
+ int i;
- for (i = 0; i < private->num_line_out; i++)
- private->mute_switch[i] =
- !!private->mute_switch[i];
+ scarlett2_notify_dim_mute(mixer);
- /* read SW/HW switches */
- if (scarlett2_has_config_item(private,
- SCARLETT2_CONFIG_SW_HW_SWITCH)) {
- err = scarlett2_usb_get_config(
- mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
- private->num_line_out,
- &private->vol_sw_hw_switch);
- if (err < 0)
- return err;
+ private->speaker_switching_switched = 0;
+ private->mux_updated = 1;
- for (i = 0; i < private->num_line_out; i++)
- private->vol_sw_hw_switch[i] =
- !!private->vol_sw_hw_switch[i];
- }
+ for (i = 0; i < private->num_mux_dsts; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->mux_ctls[i]->id);
}
+}
- err = scarlett2_update_volumes(mixer);
- if (err < 0)
- return err;
-
- err = scarlett2_update_dim_mute(mixer);
- if (err < 0)
- return err;
-
- err = scarlett2_update_input_select(mixer);
- if (err < 0)
- return err;
-
- err = scarlett2_update_input_gain(mixer);
- if (err < 0)
- return err;
+/* 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;
+ int count = private->num_mix_in * private->num_mix_out;
+ int i;
- err = scarlett2_update_autogain(mixer);
- if (err < 0)
- return err;
+ private->direct_monitor_updated = 1;
- err = scarlett2_update_input_safe(mixer);
- if (err < 0)
- return err;
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->direct_monitor_ctl->id);
- if (scarlett2_has_config_item(private,
- SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) {
- err = scarlett2_update_pcm_input_switch(mixer);
- if (err < 0)
- return err;
- }
+ if (!scarlett2_has_mixer(private))
+ return;
- err = scarlett2_update_mix(mixer);
- if (err < 0)
- return err;
+ private->mix_updated = 1;
- return scarlett2_usb_get_mux(mixer);
+ /* Notify of change to the mix controls */
+ for (i = 0; i < count; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->mix_ctls[i]->id);
}
-/* Notify on sync change */
-static void scarlett2_notify_sync(struct usb_mixer_interface *mixer)
+/* Notify on power change */
+static void scarlett2_notify_power_status(struct usb_mixer_interface *mixer)
{
+ struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
- private->sync_updated = 1;
+ private->power_status_updated = 1;
- snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->sync_ctl->id);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->power_status_ctl->id);
}
-/* Notify on monitor change (Gen 2/3) */
-static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer)
+/* Notify on mux change */
+static void scarlett2_notify_mux(struct usb_mixer_interface *mixer)
{
struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
int i;
- if (!scarlett2_has_config_item(private, SCARLETT2_CONFIG_SW_HW_SWITCH))
- return;
-
- private->vol_updated = 1;
-
- snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->master_vol_ctl->id);
+ private->mux_updated = 1;
- for (i = 0; i < private->num_line_out; i++)
- if (private->vol_sw_hw_switch[line_out_remap(private, i)])
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->vol_ctls[i]->id);
+ for (i = 0; i < private->num_mux_dsts; i++)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->mux_ctls[i]->id);
}
-/* Notify on volume change (Gen 4) */
-static void scarlett2_notify_volume(struct usb_mixer_interface *mixer)
+/* Notify on PCM input switch change */
+static void scarlett2_notify_pcm_input_switch(struct usb_mixer_interface *mixer)
{
+ struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
- private->vol_updated = 1;
+ private->pcm_input_switch_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);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &private->pcm_input_switch_ctl->id);
+
+ scarlett2_notify_mux(mixer);
}
-/* Notify on dim/mute change */
-static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer)
+/* Interrupt callback */
+static void scarlett2_notify(struct urb *urb)
{
- struct snd_card *card = mixer->chip->card;
+ struct usb_mixer_interface *mixer = urb->context;
+ int len = urb->actual_length;
+ int ustatus = urb->status;
+ u32 data;
struct scarlett2_data *private = mixer->private_data;
- int i;
+ const struct scarlett2_notification *notifications =
+ private->config_set->notifications;
- if (!scarlett2_has_config_item(private, SCARLETT2_CONFIG_SW_HW_SWITCH))
- return;
+ if (ustatus != 0 || len != 8)
+ goto requeue;
- private->dim_mute_updated = 1;
+ data = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
- for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->dim_mute_ctls[i]->id);
+ while (data && notifications->mask) {
+ if (data & notifications->mask) {
+ data &= ~notifications->mask;
+ if (notifications->func)
+ notifications->func(mixer);
+ }
+ notifications++;
+ }
- for (i = 0; i < private->num_line_out; i++)
- if (private->vol_sw_hw_switch[line_out_remap(private, i)])
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->mute_ctls[i]->id);
+ if (data)
+ usb_audio_warn(mixer->chip,
+ "%s: Unhandled notification: 0x%08x\n",
+ __func__, data);
+
+requeue:
+ if (ustatus != -ENOENT &&
+ ustatus != -ECONNRESET &&
+ ustatus != -ESHUTDOWN) {
+ urb->dev = mixer->chip->dev;
+ usb_submit_urb(urb, GFP_ATOMIC);
+ }
}
-/* Notify on input level switch change */
-static void scarlett2_notify_input_level(struct usb_mixer_interface *mixer)
+/*** Cleanup/Suspend Callbacks ***/
+
+static void scarlett2_private_free(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;
-
- private->input_level_updated = 1;
- for (i = 0; i < info->level_input_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->level_ctls[i]->id);
+ cancel_delayed_work_sync(&private->work);
+ kfree(private);
+ mixer->private_data = NULL;
}
-/* Notify on input pad switch change */
-static void scarlett2_notify_input_pad(struct usb_mixer_interface *mixer)
+static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
{
- struct snd_card *card = mixer->chip->card;
struct scarlett2_data *private = mixer->private_data;
+
+ if (cancel_delayed_work_sync(&private->work))
+ scarlett2_config_save(private->mixer);
+}
+
+/*** Initialisation ***/
+
+static void scarlett2_count_io(struct scarlett2_data *private)
+{
const struct scarlett2_device_info *info = private->info;
- int i;
+ const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
+ int port_type, srcs = 0, dsts = 0;
- private->input_pad_updated = 1;
+ /* Count the number of mux sources and destinations */
+ for (port_type = 0;
+ port_type < SCARLETT2_PORT_TYPE_COUNT;
+ port_type++) {
+ srcs += port_count[port_type][SCARLETT2_PORT_IN];
+ dsts += port_count[port_type][SCARLETT2_PORT_OUT];
+ }
- for (i = 0; i < info->pad_input_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->pad_ctls[i]->id);
+ private->num_mux_srcs = srcs;
+ private->num_mux_dsts = dsts;
+
+ /* Mixer inputs are mux outputs and vice versa.
+ * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but
+ * doesn't have mixer controls.
+ */
+ private->num_mix_in =
+ port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] -
+ info->dsp_count;
+
+ private->num_mix_out =
+ port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] -
+ info->dsp_count;
+
+ /* Number of analogue line outputs */
+ private->num_line_out =
+ port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
+
+ /* Number of monitor mix controls */
+ private->num_monitor_mix_ctls =
+ info->direct_monitor * 2 * private->num_mix_in;
}
-/* Notify on input air switch change */
-static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer)
+/* Look through the interface descriptors for the Focusrite Control
+ * interface (bInterfaceClass = 255 Vendor Specific Class) and set
+ * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval
+ * in private
+ */
+static int scarlett2_find_fc_interface(struct usb_device *dev,
+ struct scarlett2_data *private)
{
- struct snd_card *card = mixer->chip->card;
- struct scarlett2_data *private = mixer->private_data;
- const struct scarlett2_device_info *info = private->info;
+ struct usb_host_config *config = dev->actconfig;
int i;
- private->input_air_updated = 1;
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf = config->interface[i];
+ struct usb_interface_descriptor *desc =
+ &intf->altsetting[0].desc;
+ struct usb_endpoint_descriptor *epd;
- for (i = 0; i < info->air_input_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->air_ctls[i]->id);
+ if (desc->bInterfaceClass != 255)
+ continue;
+
+ epd = get_endpoint(intf->altsetting, 0);
+ private->bInterfaceNumber = desc->bInterfaceNumber;
+ private->bEndpointAddress = epd->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize);
+ private->bInterval = epd->bInterval;
+ return 0;
+ }
+
+ return -EINVAL;
}
-/* Notify on input phantom switch change */
-static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer)
+/* Initialise private data */
+static int scarlett2_init_private(struct usb_mixer_interface *mixer,
+ const struct scarlett2_device_entry *entry)
{
- struct snd_card *card = mixer->chip->card;
- struct scarlett2_data *private = mixer->private_data;
- const struct scarlett2_device_info *info = private->info;
- int i;
+ struct scarlett2_data *private =
+ kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL);
- private->input_phantom_updated = 1;
+ if (!private)
+ return -ENOMEM;
- for (i = 0; i < info->phantom_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->phantom_ctls[i]->id);
+ mutex_init(&private->usb_mutex);
+ mutex_init(&private->data_mutex);
+ INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work);
- scarlett2_phantom_notify_access(mixer);
-}
+ mixer->private_data = private;
+ mixer->private_free = scarlett2_private_free;
+ mixer->private_suspend = scarlett2_private_suspend;
-/* Notify on "input other" change (level/pad/air/phantom) */
-static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer)
-{
- scarlett2_notify_input_level(mixer);
- scarlett2_notify_input_pad(mixer);
- scarlett2_notify_input_air(mixer);
- scarlett2_notify_input_phantom(mixer);
+ private->info = entry->info;
+ private->config_set = entry->info->config_set;
+ private->series_name = entry->series_name;
+ scarlett2_count_io(private);
+ private->scarlett2_seq = 0;
+ private->mixer = mixer;
+
+ return scarlett2_find_fc_interface(mixer->chip->dev, private);
}
-/* Notify on input select change */
-static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer)
+/* Submit a URB to receive notifications from the device */
+static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
{
- struct snd_card *card = mixer->chip->card;
+ struct usb_device *dev = mixer->chip->dev;
struct scarlett2_data *private = mixer->private_data;
- const struct scarlett2_device_info *info = private->info;
- int i;
+ unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
+ void *transfer_buffer;
- if (!info->gain_input_count)
- return;
+ if (mixer->urb) {
+ usb_audio_err(mixer->chip,
+ "%s: mixer urb already in use!\n", __func__);
+ return 0;
+ }
- private->input_select_updated = 1;
+ if (usb_pipe_type_check(dev, pipe))
+ return -EINVAL;
- snd_ctl_notify(card,
- SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
- &private->input_select_ctl->id);
+ mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mixer->urb)
+ return -ENOMEM;
- for (i = 0; i < info->gain_input_count / 2; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->input_link_ctls[i]->id);
+ transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
+ if (!transfer_buffer)
+ return -ENOMEM;
+
+ usb_fill_int_urb(mixer->urb, dev, pipe,
+ transfer_buffer, private->wMaxPacketSize,
+ scarlett2_notify, mixer, private->bInterval);
+
+ return usb_submit_urb(mixer->urb, GFP_KERNEL);
}
-/* Notify on input gain change */
-static void scarlett2_notify_input_gain(struct usb_mixer_interface *mixer)
+/* Cargo cult proprietary initialisation sequence */
+static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
{
- struct snd_card *card = mixer->chip->card;
+ struct usb_device *dev = mixer->chip->dev;
struct scarlett2_data *private = mixer->private_data;
- const struct scarlett2_device_info *info = private->info;
- int i;
+ u8 step0_buf[24];
+ u8 step2_buf[84];
+ int err;
- if (!info->gain_input_count)
- return;
+ if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0)))
+ return -EINVAL;
- private->input_gain_updated = 1;
+ /* step 0 */
+ err = scarlett2_usb_rx(dev, private->bInterfaceNumber,
+ SCARLETT2_USB_CMD_INIT,
+ step0_buf, sizeof(step0_buf));
+ if (err < 0)
+ return err;
- for (i = 0; i < info->gain_input_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->input_gain_ctls[i]->id);
+ /* step 1 */
+ private->scarlett2_seq = 1;
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0);
+ if (err < 0)
+ return err;
+
+ /* step 2 */
+ private->scarlett2_seq = 1;
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2,
+ NULL, 0,
+ step2_buf, sizeof(step2_buf));
+ if (err < 0)
+ return err;
+
+ /* extract 4-byte firmware version from step2_buf[8] */
+ private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8));
+ usb_audio_info(mixer->chip,
+ "Firmware version %d\n",
+ private->firmware_version);
+
+ return 0;
}
-/* Notify on autogain change */
-static void scarlett2_notify_autogain(struct usb_mixer_interface *mixer)
+/* Get the flash segment numbers for the App_Settings and App_Upgrade
+ * segments and put them in the private data
+ */
+static int scarlett2_get_flash_segment_nums(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;
+ int err, count, i;
- if (!info->gain_input_count)
- return;
+ struct {
+ __le32 size;
+ __le32 count;
+ u8 unknown[8];
+ } __packed flash_info;
- private->autogain_updated = 1;
+ struct {
+ __le32 size;
+ __le32 flags;
+ char name[16];
+ } __packed segment_info;
- for (i = 0; i < info->gain_input_count; i++) {
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->autogain_ctls[i]->id);
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->autogain_status_ctls[i]->id);
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH,
+ NULL, 0,
+ &flash_info, sizeof(flash_info));
+ if (err < 0)
+ return err;
+
+ count = le32_to_cpu(flash_info.count);
+
+ /* sanity check count */
+ if (count < SCARLETT2_SEGMENT_NUM_MIN ||
+ count > SCARLETT2_SEGMENT_NUM_MAX + 1) {
+ usb_audio_err(mixer->chip,
+ "invalid flash segment count: %d\n", count);
+ return -EINVAL;
}
- scarlett2_autogain_notify_access(mixer);
-}
+ for (i = 0; i < count; i++) {
+ __le32 segment_num_req = cpu_to_le32(i);
+ int flash_segment_id;
-/* Notify on input safe switch change */
-static void scarlett2_notify_input_safe(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;
+ err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT,
+ &segment_num_req, sizeof(segment_num_req),
+ &segment_info, sizeof(segment_info));
+ if (err < 0) {
+ usb_audio_err(mixer->chip,
+ "failed to get flash segment info %d: %d\n",
+ i, err);
+ return err;
+ }
- if (!info->gain_input_count)
- return;
+ if (!strncmp(segment_info.name,
+ SCARLETT2_SEGMENT_SETTINGS_NAME, 16))
+ flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS;
+ else if (!strncmp(segment_info.name,
+ SCARLETT2_SEGMENT_FIRMWARE_NAME, 16))
+ flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE;
+ else
+ continue;
- private->input_safe_updated = 1;
+ private->flash_segment_nums[flash_segment_id] = i;
+ private->flash_segment_blocks[flash_segment_id] =
+ le32_to_cpu(segment_info.size) /
+ SCARLETT2_FLASH_BLOCK_SIZE;
+ }
- for (i = 0; i < info->gain_input_count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->safe_ctls[i]->id);
+ /* segment 0 is App_Gold and we never want to touch that, so
+ * use 0 as the "not-found" value
+ */
+ if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) {
+ usb_audio_err(mixer->chip,
+ "failed to find flash segment %s\n",
+ SCARLETT2_SEGMENT_SETTINGS_NAME);
+ return -EINVAL;
+ }
+ if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) {
+ usb_audio_err(mixer->chip,
+ "failed to find flash segment %s\n",
+ SCARLETT2_SEGMENT_FIRMWARE_NAME);
+ return -EINVAL;
+ }
+
+ return 0;
}
-/* Notify on "monitor other" change (speaker switching, talkback) */
-static void scarlett2_notify_monitor_other(struct usb_mixer_interface *mixer)
+/* Read configuration from the interface on start */
+static int scarlett2_read_configs(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 err, i;
- private->monitor_other_updated = 1;
-
- if (info->has_speaker_switching)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->speaker_switching_ctl->id);
-
- if (info->has_talkback)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->talkback_ctl->id);
-
- /* if speaker switching was recently enabled or disabled,
- * invalidate the dim/mute and mux enum controls
- */
- if (private->speaker_switching_switched) {
- int i;
-
- scarlett2_notify_dim_mute(mixer);
-
- private->speaker_switching_switched = 0;
- private->mux_updated = 1;
-
- for (i = 0; i < private->num_mux_dsts; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->mux_ctls[i]->id);
+ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) {
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_MSD_SWITCH,
+ 1, &private->msd_switch);
+ if (err < 0)
+ return err;
}
-}
-/* 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;
- int count = private->num_mix_in * private->num_mix_out;
- int i;
+ if (private->firmware_version < info->min_firmware_version) {
+ usb_audio_err(mixer->chip,
+ "Focusrite %s firmware version %d is too old; "
+ "need %d",
+ private->series_name,
+ private->firmware_version,
+ info->min_firmware_version);
+ return 0;
+ }
- private->direct_monitor_updated = 1;
+ /* no other controls are created if MSD mode is on */
+ if (private->msd_switch)
+ return 0;
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->direct_monitor_ctl->id);
+ err = scarlett2_update_input_level(mixer);
+ if (err < 0)
+ return err;
- if (!scarlett2_has_mixer(private))
- return;
+ err = scarlett2_update_input_pad(mixer);
+ if (err < 0)
+ return err;
- private->mix_updated = 1;
+ err = scarlett2_update_input_air(mixer);
+ if (err < 0)
+ return err;
- /* Notify of change to the mix controls */
- for (i = 0; i < count; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->mix_ctls[i]->id);
-}
+ err = scarlett2_update_input_phantom(mixer);
+ if (err < 0)
+ return err;
-/* Notify on power change */
-static void scarlett2_notify_power_status(struct usb_mixer_interface *mixer)
-{
- struct snd_card *card = mixer->chip->card;
- struct scarlett2_data *private = mixer->private_data;
+ err = scarlett2_update_direct_monitor(mixer);
+ if (err < 0)
+ return err;
- private->power_status_updated = 1;
+ /* the rest of the configuration is for devices with a mixer */
+ if (!scarlett2_has_mixer(private))
+ return 0;
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->power_status_ctl->id);
-}
+ err = scarlett2_update_monitor_mix(mixer);
+ if (err < 0)
+ return err;
-/* Notify on mux change */
-static void scarlett2_notify_mux(struct usb_mixer_interface *mixer)
-{
- struct snd_card *card = mixer->chip->card;
- struct scarlett2_data *private = mixer->private_data;
- int i;
+ err = scarlett2_update_monitor_other(mixer);
+ if (err < 0)
+ return err;
- private->mux_updated = 1;
+ if (scarlett2_has_config_item(private,
+ SCARLETT2_CONFIG_STANDALONE_SWITCH)) {
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH,
+ 1, &private->standalone_switch);
+ if (err < 0)
+ return err;
+ }
- for (i = 0; i < private->num_mux_dsts; i++)
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->mux_ctls[i]->id);
-}
+ if (scarlett2_has_config_item(private,
+ SCARLETT2_CONFIG_POWER_EXT)) {
+ err = scarlett2_update_power_status(mixer);
+ if (err < 0)
+ return err;
+ }
-/* Notify on PCM input switch change */
-static void scarlett2_notify_pcm_input_switch(struct usb_mixer_interface *mixer)
-{
- struct snd_card *card = mixer->chip->card;
- struct scarlett2_data *private = mixer->private_data;
+ err = scarlett2_update_sync(mixer);
+ if (err < 0)
+ return err;
- private->pcm_input_switch_updated = 1;
+ if (scarlett2_has_config_item(private,
+ SCARLETT2_CONFIG_LINE_OUT_VOLUME)) {
+ s16 sw_vol[SCARLETT2_ANALOGUE_MAX];
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
- &private->pcm_input_switch_ctl->id);
+ /* read SW line out volume */
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME,
+ private->num_line_out, &sw_vol);
+ if (err < 0)
+ return err;
- scarlett2_notify_mux(mixer);
-}
+ for (i = 0; i < private->num_line_out; i++)
+ private->vol[i] = clamp(
+ sw_vol[i] + SCARLETT2_VOLUME_BIAS,
+ 0, SCARLETT2_VOLUME_BIAS);
-/* Interrupt callback */
-static void scarlett2_notify(struct urb *urb)
-{
- struct usb_mixer_interface *mixer = urb->context;
- int len = urb->actual_length;
- int ustatus = urb->status;
- u32 data;
- struct scarlett2_data *private = mixer->private_data;
- const struct scarlett2_notification *notifications =
- private->config_set->notifications;
+ /* read SW mute */
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_MUTE_SWITCH,
+ private->num_line_out, &private->mute_switch);
+ if (err < 0)
+ return err;
- if (ustatus != 0 || len != 8)
- goto requeue;
+ for (i = 0; i < private->num_line_out; i++)
+ private->mute_switch[i] =
+ !!private->mute_switch[i];
- data = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
+ /* read SW/HW switches */
+ if (scarlett2_has_config_item(private,
+ SCARLETT2_CONFIG_SW_HW_SWITCH)) {
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
+ private->num_line_out,
+ &private->vol_sw_hw_switch);
+ if (err < 0)
+ return err;
- while (data && notifications->mask) {
- if (data & notifications->mask) {
- data &= ~notifications->mask;
- if (notifications->func)
- notifications->func(mixer);
+ for (i = 0; i < private->num_line_out; i++)
+ private->vol_sw_hw_switch[i] =
+ !!private->vol_sw_hw_switch[i];
}
- notifications++;
}
- if (data)
- usb_audio_warn(mixer->chip,
- "%s: Unhandled notification: 0x%08x\n",
- __func__, data);
+ err = scarlett2_update_volumes(mixer);
+ if (err < 0)
+ return err;
-requeue:
- if (ustatus != -ENOENT &&
- ustatus != -ECONNRESET &&
- ustatus != -ESHUTDOWN) {
- urb->dev = mixer->chip->dev;
- usb_submit_urb(urb, GFP_ATOMIC);
- }
-}
+ err = scarlett2_update_dim_mute(mixer);
+ if (err < 0)
+ return err;
-static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
-{
- struct usb_device *dev = mixer->chip->dev;
- struct scarlett2_data *private = mixer->private_data;
- unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
- void *transfer_buffer;
+ err = scarlett2_update_input_select(mixer);
+ if (err < 0)
+ return err;
- if (mixer->urb) {
- usb_audio_err(mixer->chip,
- "%s: mixer urb already in use!\n", __func__);
- return 0;
- }
+ err = scarlett2_update_input_gain(mixer);
+ if (err < 0)
+ return err;
- if (usb_pipe_type_check(dev, pipe))
- return -EINVAL;
+ err = scarlett2_update_autogain(mixer);
+ if (err < 0)
+ return err;
- mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mixer->urb)
- return -ENOMEM;
+ err = scarlett2_update_input_safe(mixer);
+ if (err < 0)
+ return err;
- transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
+ if (scarlett2_has_config_item(private,
+ SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) {
+ err = scarlett2_update_pcm_input_switch(mixer);
+ if (err < 0)
+ return err;
+ }
- usb_fill_int_urb(mixer->urb, dev, pipe,
- transfer_buffer, private->wMaxPacketSize,
- scarlett2_notify, mixer, private->bInterval);
+ err = scarlett2_update_mix(mixer);
+ if (err < 0)
+ return err;
- return usb_submit_urb(mixer->urb, GFP_KERNEL);
+ return scarlett2_usb_get_mux(mixer);
}
static const struct scarlett2_device_entry *get_scarlett2_device_entry(
--
2.34.1
More information about the kernel-team
mailing list