Commit 4074f8d2 authored by Geoffrey D. Bennett's avatar Geoffrey D. Bennett Committed by Takashi Iwai

ALSA: scarlett2: Move initialisation code lower in the source

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: default avatarGeoffrey D. Bennett <g@b4.vu>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Message-ID: <0922071cb8be99a2394705de27b917d1e4e46f3f.1710264833.git.g@b4.vu>
parent a9b16d59
......@@ -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(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment