summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2026-04-29 12:30:30 +0200
committerThierry Reding <treding@nvidia.com>2026-04-29 12:30:30 +0200
commit1a69830701cb8de4cb43af5e1afba7afe6ef35ef (patch)
treee244f8742a102905624a91f93ed794f4ba6b28bb
parent2c2967676d24a27a1d86a728f4e2b8d7901f53dc (diff)
parent6e934725ec3abb63247a0cb4cd455fff3c009ef5 (diff)
downloadlinux-next-1a69830701cb8de4cb43af5e1afba7afe6ef35ef.tar.gz
linux-next-1a69830701cb8de4cb43af5e1afba7afe6ef35ef.zip
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
-rw-r--r--include/sound/snd_wavefront.h7
-rw-r--r--sound/isa/opti9xx/miro.c268
-rw-r--r--sound/isa/wavefront/wavefront.c61
-rw-r--r--sound/isa/wavefront/wavefront_midi.c47
-rw-r--r--sound/isa/wavefront/wavefront_synth.c96
-rw-r--r--sound/oss/dmasound/dmasound_core.c10
-rw-r--r--sound/pci/ctxfi/ctmixer.c27
-rw-r--r--sound/pci/ctxfi/ctmixer.h4
-rw-r--r--sound/usb/mixer.c17
-rw-r--r--sound/usb/mixer_scarlett.c4
-rw-r--r--sound/usb/mixer_scarlett2.c515
-rw-r--r--sound/usb/mixer_us16x08.c127
12 files changed, 1049 insertions, 134 deletions
diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h
index 30f508a56766..ac749bb2b836 100644
--- a/include/sound/snd_wavefront.h
+++ b/include/sound/snd_wavefront.h
@@ -12,6 +12,7 @@
struct _snd_wavefront_midi;
struct _snd_wavefront_card;
struct _snd_wavefront;
+struct snd_wss;
typedef struct _snd_wavefront_midi snd_wavefront_midi_t;
typedef struct _snd_wavefront_card snd_wavefront_card_t;
@@ -46,6 +47,8 @@ extern void snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *);
extern void snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *);
extern void snd_wavefront_midi_interrupt (snd_wavefront_card_t *);
extern int snd_wavefront_midi_start (snd_wavefront_card_t *);
+void snd_wavefront_midi_suspend(snd_wavefront_card_t *card);
+void snd_wavefront_midi_resume(snd_wavefront_card_t *card);
struct _snd_wavefront {
unsigned long irq; /* "you were one, one of the few ..." */
@@ -93,6 +96,7 @@ struct _snd_wavefront {
int samples_used; /* how many */
char interrupts_are_midi; /* h/w MPU interrupts enabled ? */
char rom_samples_rdonly; /* can we write on ROM samples */
+ char midi_in_to_synth; /* route external MIDI to synth */
spinlock_t irq_lock;
wait_queue_head_t interrupt_sleeper;
snd_wavefront_midi_t midi; /* ICS2115 MIDI interface */
@@ -101,6 +105,7 @@ struct _snd_wavefront {
struct _snd_wavefront_card {
snd_wavefront_t wavefront;
+ struct snd_wss *chip;
#ifdef CONFIG_PNP
struct pnp_dev *wss;
struct pnp_dev *ctrl;
@@ -110,8 +115,10 @@ struct _snd_wavefront_card {
};
extern void snd_wavefront_internal_interrupt (snd_wavefront_card_t *card);
+void snd_wavefront_cache_firmware(snd_wavefront_t *dev);
extern int snd_wavefront_start (snd_wavefront_t *dev);
extern int snd_wavefront_detect (snd_wavefront_card_t *card);
+int snd_wavefront_resume_synth(snd_wavefront_card_t *card);
extern int snd_wavefront_cmd (snd_wavefront_t *, int, unsigned char *,
unsigned char *);
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c320af3e9a05..e5870e5e07db 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -88,6 +88,25 @@ MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
#define OPTi9XX_MC_REG(n) n
+enum {
+ MIRO_ACI_MASTER,
+ MIRO_ACI_MIC,
+ MIRO_ACI_LINE,
+ MIRO_ACI_CD,
+ MIRO_ACI_SYNTH,
+ MIRO_ACI_PCM,
+ MIRO_ACI_LINE1,
+ MIRO_ACI_LINE2,
+ MIRO_ACI_EQ1,
+ MIRO_ACI_EQ2,
+ MIRO_ACI_EQ3,
+ MIRO_ACI_EQ4,
+ MIRO_ACI_EQ5,
+ MIRO_ACI_EQ6,
+ MIRO_ACI_EQ7,
+ MIRO_ACI_COUNT,
+};
+
struct snd_miro {
unsigned short hardware;
unsigned char password;
@@ -102,6 +121,7 @@ struct snd_miro {
spinlock_t lock;
struct snd_pcm *pcm;
+ struct snd_wss *codec;
long wss_base;
int irq;
@@ -113,6 +133,12 @@ struct snd_miro {
struct snd_card *card;
struct snd_miro_aci *aci;
+#ifdef CONFIG_PM
+ unsigned char aci_saved[MIRO_ACI_COUNT][2];
+ unsigned char aci_saved_amp;
+ unsigned char aci_saved_preamp;
+ unsigned char aci_saved_solomode;
+#endif
};
static struct snd_miro_aci aci_device;
@@ -664,6 +690,44 @@ static const unsigned char aci_init_values[][2] = {
{ ACI_SET_MASTER + 1, 0x20 },
};
+#ifdef CONFIG_PM
+static const unsigned char snd_miro_saved_get_regs[MIRO_ACI_COUNT] = {
+ [MIRO_ACI_MASTER] = ACI_GET_MASTER,
+ [MIRO_ACI_MIC] = ACI_GET_MIC,
+ [MIRO_ACI_LINE] = ACI_GET_LINE,
+ [MIRO_ACI_CD] = ACI_GET_CD,
+ [MIRO_ACI_SYNTH] = ACI_GET_SYNTH,
+ [MIRO_ACI_PCM] = ACI_GET_PCM,
+ [MIRO_ACI_LINE1] = ACI_GET_LINE1,
+ [MIRO_ACI_LINE2] = ACI_GET_LINE2,
+ [MIRO_ACI_EQ1] = ACI_GET_EQ1,
+ [MIRO_ACI_EQ2] = ACI_GET_EQ2,
+ [MIRO_ACI_EQ3] = ACI_GET_EQ3,
+ [MIRO_ACI_EQ4] = ACI_GET_EQ4,
+ [MIRO_ACI_EQ5] = ACI_GET_EQ5,
+ [MIRO_ACI_EQ6] = ACI_GET_EQ6,
+ [MIRO_ACI_EQ7] = ACI_GET_EQ7,
+};
+
+static const unsigned char snd_miro_saved_set_regs[MIRO_ACI_COUNT] = {
+ [MIRO_ACI_MASTER] = ACI_SET_MASTER,
+ [MIRO_ACI_MIC] = ACI_SET_MIC,
+ [MIRO_ACI_LINE] = ACI_SET_LINE,
+ [MIRO_ACI_CD] = ACI_SET_CD,
+ [MIRO_ACI_SYNTH] = ACI_SET_SYNTH,
+ [MIRO_ACI_PCM] = ACI_SET_PCM,
+ [MIRO_ACI_LINE1] = ACI_SET_LINE1,
+ [MIRO_ACI_LINE2] = ACI_SET_LINE2,
+ [MIRO_ACI_EQ1] = ACI_SET_EQ1,
+ [MIRO_ACI_EQ2] = ACI_SET_EQ2,
+ [MIRO_ACI_EQ3] = ACI_SET_EQ3,
+ [MIRO_ACI_EQ4] = ACI_SET_EQ4,
+ [MIRO_ACI_EQ5] = ACI_SET_EQ5,
+ [MIRO_ACI_EQ6] = ACI_SET_EQ6,
+ [MIRO_ACI_EQ7] = ACI_SET_EQ7,
+};
+#endif
+
static int snd_set_aci_init_values(struct snd_miro *miro)
{
int idx, error;
@@ -702,11 +766,116 @@ static int snd_set_aci_init_values(struct snd_miro *miro)
}
aci->aci_amp = 0;
aci->aci_preamp = 0;
- aci->aci_solomode = 1;
+ aci->aci_solomode = 0;
+
+ return 0;
+}
+
+static int snd_miro_aci_force_known_state(struct snd_miro_aci *aci)
+{
+ int i, err;
+
+ for (i = 0; i < 3; i++) {
+ err = snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1);
+ if (err < 0)
+ return err;
+ }
return 0;
}
+static int snd_miro_aci_initialize(struct snd_miro_aci *aci)
+{
+ int err;
+
+ err = snd_aci_cmd(aci, ACI_INIT, -1, -1);
+ if (err < 0)
+ return err;
+ err = snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP);
+ if (err < 0)
+ return err;
+
+ return snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP);
+}
+
+#ifdef CONFIG_PM
+static int snd_miro_save_aci_state(struct snd_miro *miro)
+{
+ struct snd_miro_aci *aci = miro->aci;
+ int i, limit, value;
+
+ limit = aci->aci_product == 'C' ? MIRO_ACI_COUNT : MIRO_ACI_LINE2 + 1;
+ for (i = 0; i < limit; i++) {
+ value = aci_getvalue(aci, snd_miro_saved_get_regs[i]);
+ if (value < 0)
+ return value;
+ miro->aci_saved[i][1] = value;
+
+ value = aci_getvalue(aci, snd_miro_saved_get_regs[i] + 1);
+ if (value < 0)
+ return value;
+ miro->aci_saved[i][0] = value;
+ }
+
+ miro->aci_saved_amp = aci->aci_amp;
+ if (aci->aci_version <= 176) {
+ miro->aci_saved_preamp = aci->aci_preamp;
+ } else {
+ value = aci_getvalue(aci, ACI_GET_PREAMP);
+ if (value < 0)
+ return value;
+ miro->aci_saved_preamp = value;
+ }
+
+ value = aci_getvalue(aci, ACI_S_GENERAL);
+ if (value < 0)
+ return value;
+ miro->aci_saved_solomode = !(value & 0x20);
+
+ return 0;
+}
+
+static int snd_miro_restore_aci_state(struct snd_miro *miro)
+{
+ struct snd_miro_aci *aci = miro->aci;
+ int i, limit, err, left_reg;
+
+ err = snd_set_aci_init_values(miro);
+ if (err < 0)
+ return err;
+
+ limit = aci->aci_product == 'C' ? MIRO_ACI_COUNT : MIRO_ACI_LINE2 + 1;
+ for (i = 0; i < limit; i++) {
+ left_reg = snd_miro_saved_set_regs[i] == ACI_SET_MASTER ?
+ snd_miro_saved_set_regs[i] + 1 :
+ snd_miro_saved_set_regs[i] + 8;
+ err = aci_setvalue(aci, left_reg, miro->aci_saved[i][0]);
+ if (err < 0)
+ return err;
+ err = aci_setvalue(aci, snd_miro_saved_set_regs[i],
+ miro->aci_saved[i][1]);
+ if (err < 0)
+ return err;
+ }
+
+ err = aci_setvalue(aci, ACI_SET_POWERAMP, miro->aci_saved_amp);
+ if (err < 0)
+ return err;
+ err = aci_setvalue(aci, ACI_SET_PREAMP, miro->aci_saved_preamp);
+ if (err < 0)
+ return err;
+ err = aci_setvalue(aci, ACI_SET_SOLOMODE, miro->aci_saved_solomode);
+ if (err < 0)
+ return err;
+
+ aci->aci_amp = miro->aci_saved_amp;
+ aci->aci_preamp = miro->aci_saved_preamp;
+ aci->aci_solomode = miro->aci_saved_solomode;
+
+ return 0;
+}
+#endif
+
static int snd_miro_mixer(struct snd_card *card,
struct snd_miro *miro)
{
@@ -1203,7 +1372,7 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
struct snd_miro *miro)
{
unsigned char regval;
- int i;
+ int err;
struct snd_miro_aci *aci = &aci_device;
miro->aci = aci;
@@ -1224,12 +1393,12 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
return -ENOMEM;
}
- /* force ACI into a known state */
- for (i = 0; i < 3; i++)
- if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
- dev_err(card->dev, "can't force aci into known state.\n");
- return -ENXIO;
- }
+ /* force ACI into a known state */
+ err = snd_miro_aci_force_known_state(aci);
+ if (err < 0) {
+ dev_err(card->dev, "can't force aci into known state.\n");
+ return -ENXIO;
+ }
aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
@@ -1246,9 +1415,8 @@ static int snd_card_miro_aci_detect(struct snd_card *card,
return -ENXIO;
}
- if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
- snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
- snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
+ err = snd_miro_aci_initialize(aci);
+ if (err < 0) {
dev_err(card->dev, "can't initialize aci.\n");
return -ENXIO;
}
@@ -1299,6 +1467,7 @@ static int snd_miro_probe(struct snd_card *card)
WSS_HW_DETECT, 0, &codec);
if (error < 0)
return error;
+ miro->codec = codec;
error = snd_wss_pcm(codec, 0);
if (error < 0)
@@ -1408,6 +1577,7 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
return error;
miro = card->private_data;
+ miro->card = card;
error = snd_card_miro_detect(card, miro);
if (error < 0) {
@@ -1470,12 +1640,69 @@ static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
return 0;
}
+#ifdef CONFIG_PM
+static int snd_miro_suspend(struct snd_card *card)
+{
+ struct snd_miro *miro = card->private_data;
+ int error;
+
+ error = snd_miro_save_aci_state(miro);
+ if (error < 0)
+ return error;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ miro->codec->suspend(miro->codec);
+ return 0;
+}
+
+static int snd_miro_resume(struct snd_card *card)
+{
+ struct snd_miro *miro = card->private_data;
+ int error;
+
+ error = snd_miro_configure(miro);
+ if (error < 0)
+ return error;
+ error = snd_miro_aci_force_known_state(miro->aci);
+ if (error < 0) {
+ dev_err(card->dev, "can't force aci into known state\n");
+ return error;
+ }
+ error = snd_miro_aci_initialize(miro->aci);
+ if (error < 0) {
+ dev_err(card->dev, "can't initialize aci\n");
+ return error;
+ }
+ error = snd_miro_restore_aci_state(miro);
+ if (error < 0)
+ return error;
+
+ miro->codec->resume(miro->codec);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+
+static int snd_miro_isa_suspend(struct device *dev, unsigned int n,
+ pm_message_t state)
+{
+ return snd_miro_suspend(dev_get_drvdata(dev));
+}
+
+static int snd_miro_isa_resume(struct device *dev, unsigned int n)
+{
+ return snd_miro_resume(dev_get_drvdata(dev));
+}
+#endif
+
#define DEV_NAME "miro"
static struct isa_driver snd_miro_driver = {
.match = snd_miro_isa_match,
.probe = snd_miro_isa_probe,
- /* FIXME: suspend/resume */
+#ifdef CONFIG_PM
+ .suspend = snd_miro_isa_suspend,
+ .resume = snd_miro_isa_resume,
+#endif
.driver = {
.name = DEV_NAME
},
@@ -1591,12 +1818,29 @@ static void snd_miro_pnp_remove(struct pnp_card_link *pcard)
snd_miro_pnp_is_probed = 0;
}
+#ifdef CONFIG_PM
+static int snd_miro_pnp_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ return snd_miro_suspend(pnp_get_card_drvdata(pcard));
+}
+
+static int snd_miro_pnp_resume(struct pnp_card_link *pcard)
+{
+ return snd_miro_resume(pnp_get_card_drvdata(pcard));
+}
+#endif
+
static struct pnp_card_driver miro_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "miro",
.id_table = snd_miro_pnpids,
.probe = snd_miro_pnp_probe,
.remove = snd_miro_pnp_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_miro_pnp_suspend,
+ .resume = snd_miro_pnp_resume,
+#endif
};
#endif
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 07c68568091d..f4a0c21c905e 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -353,6 +353,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
dev_err(card->dev, "can't allocate WSS device\n");
return err;
}
+ acard->chip = chip;
err = snd_wss_pcm(chip, 0);
if (err < 0)
@@ -400,6 +401,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
acard->wavefront.irq = ics2115_irq[dev];
card->sync_irq = acard->wavefront.irq;
acard->wavefront.base = ics2115_port[dev];
+ snd_wavefront_cache_firmware(&acard->wavefront);
wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard);
if (wavefront_synth == NULL) {
@@ -553,12 +555,51 @@ static int snd_wavefront_isa_probe(struct device *pdev,
return 0;
}
+#ifdef CONFIG_PM
+static int snd_wavefront_suspend(struct snd_card *card)
+{
+ snd_wavefront_card_t *acard = card->private_data;
+
+ snd_wavefront_midi_suspend(acard);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ acard->chip->suspend(acard->chip);
+ return 0;
+}
+
+static int snd_wavefront_resume(struct snd_card *card)
+{
+ snd_wavefront_card_t *acard = card->private_data;
+ int err;
+
+ acard->chip->resume(acard->chip);
+ err = snd_wavefront_resume_synth(acard);
+ if (err < 0)
+ return err;
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+
+static int snd_wavefront_isa_suspend(struct device *dev, unsigned int id,
+ pm_message_t state)
+{
+ return snd_wavefront_suspend(dev_get_drvdata(dev));
+}
+
+static int snd_wavefront_isa_resume(struct device *dev, unsigned int id)
+{
+ return snd_wavefront_resume(dev_get_drvdata(dev));
+}
+#endif
+
#define DEV_NAME "wavefront"
static struct isa_driver snd_wavefront_driver = {
.match = snd_wavefront_isa_match,
.probe = snd_wavefront_isa_probe,
- /* FIXME: suspend, resume */
+#ifdef CONFIG_PM
+ .suspend = snd_wavefront_isa_suspend,
+ .resume = snd_wavefront_isa_resume,
+#endif
.driver = {
.name = DEV_NAME
},
@@ -600,12 +641,28 @@ static int snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
return 0;
}
+#ifdef CONFIG_PM
+static int snd_wavefront_pnpc_suspend(struct pnp_card_link *pcard,
+ pm_message_t state)
+{
+ return snd_wavefront_suspend(pnp_get_card_drvdata(pcard));
+}
+
+static int snd_wavefront_pnpc_resume(struct pnp_card_link *pcard)
+{
+ return snd_wavefront_resume(pnp_get_card_drvdata(pcard));
+}
+#endif
+
static struct pnp_card_driver wavefront_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "wavefront",
.id_table = snd_wavefront_pnpids,
.probe = snd_wavefront_pnp_detect,
- /* FIXME: suspend,resume */
+#ifdef CONFIG_PM
+ .suspend = snd_wavefront_pnpc_suspend,
+ .resume = snd_wavefront_pnpc_resume,
+#endif
};
#endif /* CONFIG_PNP */
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 69d87c4cafae..fb184d9ef284 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -455,6 +455,49 @@ snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
card->wavefront.midi.isvirtual = 0;
}
+void
+snd_wavefront_midi_suspend(snd_wavefront_card_t *card)
+
+{
+ snd_wavefront_midi_t *midi = &card->wavefront.midi;
+
+ if (!midi->istimer)
+ return;
+
+ timer_delete_sync(&midi->timer);
+
+ guard(spinlock_irqsave)(&midi->virtual);
+ midi->istimer = 0;
+}
+
+void
+snd_wavefront_midi_resume(snd_wavefront_card_t *card)
+
+{
+ snd_wavefront_midi_t *midi = &card->wavefront.midi;
+ int istimer = 0;
+ bool pending_output = false;
+
+ midi->timer_card = card;
+
+ scoped_guard(spinlock_irqsave, &midi->virtual) {
+ if (midi->mode[internal_mpu] & MPU401_MODE_OUTPUT_TRIGGER)
+ istimer++;
+ if (midi->mode[external_mpu] & MPU401_MODE_OUTPUT_TRIGGER)
+ istimer++;
+ if (!istimer)
+ return;
+
+ midi->istimer = istimer;
+ timer_setup(&midi->timer, snd_wavefront_midi_output_timer, 0);
+ mod_timer(&midi->timer, 1 + jiffies);
+ pending_output = true;
+ }
+
+ if (pending_output)
+ snd_wavefront_midi_output_write(card);
+}
+
int
snd_wavefront_midi_start (snd_wavefront_card_t *card)
@@ -466,6 +509,7 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
dev = &card->wavefront;
midi = &dev->midi;
+ midi->timer_card = card;
/* The ICS2115 MPU-401 interface doesn't do anything
until its set into UART mode.
@@ -511,6 +555,8 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
dev_warn(card->wavefront.card->dev,
"can't enable MIDI-IN-2-synth routing.\n");
/* XXX error ? */
+ } else {
+ dev->midi_in_to_synth = 1;
}
/* Turn on Virtual MIDI, but first *always* turn it off,
@@ -553,4 +599,3 @@ const struct snd_rawmidi_ops snd_wavefront_midi_input =
.close = snd_wavefront_midi_input_close,
.trigger = snd_wavefront_midi_input_trigger,
};
-
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 33b563707a58..2f57a6795d22 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1626,6 +1626,14 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
"support for sample aliases still being considered.\n");
break;
+ case WFC_MISYNTH_OFF:
+ dev->midi_in_to_synth = 0;
+ break;
+
+ case WFC_MISYNTH_ON:
+ dev->midi_in_to_synth = 1;
+ break;
+
case WFC_VMIDI_OFF:
snd_wavefront_midi_disable_virtual (acard);
break;
@@ -1639,6 +1647,83 @@ wavefront_synth_control (snd_wavefront_card_t *acard,
return 0;
}
+static int
+wavefront_restore_midi_state(snd_wavefront_card_t *acard, char isvirtual,
+ char midi_in_to_synth)
+{
+ snd_wavefront_t *dev = &acard->wavefront;
+ unsigned char rbuf[4], wbuf[4];
+
+ if (dev->midi_in_to_synth != midi_in_to_synth) {
+ if (snd_wavefront_cmd(dev, midi_in_to_synth ?
+ WFC_MISYNTH_ON : WFC_MISYNTH_OFF,
+ rbuf, wbuf)) {
+ dev_err(dev->card->dev,
+ "cannot restore MIDI-IN routing after resume\n");
+ return -EIO;
+ }
+ dev->midi_in_to_synth = midi_in_to_synth;
+ }
+
+ if (dev->midi.isvirtual != isvirtual) {
+ if (snd_wavefront_cmd(dev, isvirtual ?
+ WFC_VMIDI_ON : WFC_VMIDI_OFF,
+ rbuf, wbuf)) {
+ dev_err(dev->card->dev,
+ "cannot restore virtual MIDI mode after resume\n");
+ return -EIO;
+ }
+ if (isvirtual)
+ snd_wavefront_midi_enable_virtual(acard);
+ else
+ snd_wavefront_midi_disable_virtual(acard);
+ }
+
+ return 0;
+}
+
+int snd_wavefront_resume_synth(snd_wavefront_card_t *acard)
+{
+ snd_wavefront_t *dev = &acard->wavefront;
+ char was_virtual = dev->midi.isvirtual;
+ char midi_in_to_synth = dev->midi_in_to_synth;
+ char rom_samples_rdonly = dev->rom_samples_rdonly;
+ int err;
+
+ err = snd_wavefront_detect(acard);
+ if (err < 0)
+ dev->israw = 1;
+
+ if (dev->israw) {
+ dev->fx_initialized = 0;
+ err = snd_wavefront_start(dev);
+ if (err < 0)
+ return err;
+ } else {
+ dev->has_fx = (snd_wavefront_fx_detect(dev) == 0);
+ wavefront_get_sample_status(dev, 0);
+ wavefront_get_program_status(dev);
+ wavefront_get_patch_status(dev);
+ outb(0x80 | 0x40 | 0x20, dev->control_port);
+ }
+
+ dev->rom_samples_rdonly = rom_samples_rdonly;
+ dev->midi.base = dev->base;
+
+ err = snd_wavefront_midi_start(acard);
+ if (err < 0)
+ return err;
+
+ err = wavefront_restore_midi_state(acard, was_virtual,
+ midi_in_to_synth);
+ if (err < 0)
+ return err;
+
+ snd_wavefront_midi_resume(acard);
+
+ return 0;
+}
+
int
snd_wavefront_synth_open (struct snd_hwdep *hw, struct file *file)
@@ -2032,6 +2117,17 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
return 1;
}
+void snd_wavefront_cache_firmware(snd_wavefront_t *dev)
+{
+ int err;
+
+ err = firmware_request_cache(dev->card->dev, ospath);
+ if (err < 0)
+ dev_warn(dev->card->dev,
+ "unable to cache firmware %s for resume: %d\n",
+ ospath, err);
+}
+
static int
wavefront_do_reset (snd_wavefront_t *dev)
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index a718b75bb6a0..e80f730d0803 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -574,11 +574,6 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
uWritten = 0 ;
}
-/* FIXME: I think that this may be the wrong behaviour when we get strapped
- for time and the cpu is close to being (or actually) behind in sending data.
- - because we've lost the time that the N samples, already in the buffer,
- would have given us to get here with the next lot from the user.
-*/
/* The interrupt doesn't start to play the last, incomplete frame.
* Thus we can append to it without disabling the interrupts! (Note
* also that write_sq.rear isn't affected by the interrupt.)
@@ -598,6 +593,11 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
write_sq.syncing &= ~2 ; /* take out POST status */
spin_unlock_irqrestore(&dmasound.lock, flags);
+ /* Start any already-complete fragments before we spend
+ * more time extending the incomplete tail fragment.
+ */
+ sq_play();
+
if (write_sq.count > 0 &&
(bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
dest = write_sq.buffers[write_sq.rear];
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index e3ee76bd8482..50ab69aca2fa 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -965,35 +965,20 @@ error1:
static int ct_mixer_get_mem(struct ct_mixer **rmixer)
{
struct ct_mixer *mixer;
- int err;
+ size_t alloc_size;
*rmixer = NULL;
/* Allocate mem for mixer obj */
- mixer = kzalloc_obj(*mixer);
+ alloc_size = struct_size(mixer, amixers, NUM_CT_AMIXERS * CHN_NUM);
+ alloc_size += sizeof(*mixer->sums) * NUM_CT_SUMS * CHN_NUM;
+ mixer = kzalloc(alloc_size, GFP_KERNEL);
if (!mixer)
return -ENOMEM;
- mixer->amixers = kcalloc(NUM_CT_AMIXERS * CHN_NUM, sizeof(void *),
- GFP_KERNEL);
- if (!mixer->amixers) {
- err = -ENOMEM;
- goto error1;
- }
- mixer->sums = kcalloc(NUM_CT_SUMS * CHN_NUM, sizeof(void *),
- GFP_KERNEL);
- if (!mixer->sums) {
- err = -ENOMEM;
- goto error2;
- }
+ mixer->sums = (struct sum **)(mixer->amixers + (NUM_CT_AMIXERS * CHN_NUM));
*rmixer = mixer;
return 0;
-
-error2:
- kfree(mixer->amixers);
-error1:
- kfree(mixer);
- return err;
}
static int ct_mixer_topology_build(struct ct_mixer *mixer)
@@ -1228,8 +1213,6 @@ int ct_mixer_destroy(struct ct_mixer *mixer)
}
/* Release mem assigned to mixer object */
- kfree(mixer->sums);
- kfree(mixer->amixers);
kfree(mixer);
return 0;
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h
index e812f6c93b41..dd23d227aeb5 100644
--- a/sound/pci/ctxfi/ctmixer.h
+++ b/sound/pci/ctxfi/ctmixer.h
@@ -41,8 +41,7 @@ enum MIXER_PORT_T {
struct ct_mixer {
struct ct_atc *atc;
- void **amixers; /* amixer resources for volume control */
- void **sums; /* sum resources for signal collection */
+ struct sum **sums; /* sum resources for signal collection */
unsigned int switch_state; /* A bit-map to indicate state of switches */
int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type,
@@ -55,6 +54,7 @@ struct ct_mixer {
#ifdef CONFIG_PM_SLEEP
int (*resume)(struct ct_mixer *mixer);
#endif
+ struct amixer *amixers[]; /* amixer resources for volume control */
};
int ct_alsa_mix_create(struct ct_atc *atc,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 5fba456eb4a9..4bd2e93f1dd4 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1536,7 +1536,10 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = get_abs_value(cval, val);
if (oval != val) {
- snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
+ err = snd_usb_set_cur_mix_value(cval, c + 1,
+ cnt, val);
+ if (err < 0)
+ return filter_error(cval, err);
changed = 1;
}
cnt++;
@@ -1551,7 +1554,9 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
- snd_usb_set_cur_mix_value(cval, 0, 0, val);
+ err = snd_usb_set_cur_mix_value(cval, 0, 0, val);
+ if (err < 0)
+ return filter_error(cval, err);
changed = 1;
}
}
@@ -2476,7 +2481,9 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
- set_cur_ctl_value(cval, cval->control << 8, val);
+ err = set_cur_ctl_value(cval, cval->control << 8, val);
+ if (err < 0)
+ return filter_error(cval, err);
return 1;
}
return 0;
@@ -2842,7 +2849,9 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
- set_cur_ctl_value(cval, cval->control << 8, val);
+ err = set_cur_ctl_value(cval, cval->control << 8, val);
+ if (err < 0)
+ return filter_error(cval, err);
return 1;
}
return 0;
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index 1bb01e827654..673eb8d8724d 100644
--- a/sound/usb/mixer_scarlett.c
+++ b/sound/usb/mixer_scarlett.c
@@ -680,7 +680,9 @@ static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
val = ucontrol->value.integer.value[0];
val = val + opt->start;
if (val != oval) {
- snd_usb_set_cur_mix_value(elem, 0, 0, val);
+ err = snd_usb_set_cur_mix_value(elem, 0, 0, val);
+ if (err < 0)
+ return err;
return 1;
}
return 0;
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index 8eaa96222759..6f66149baea6 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -192,6 +192,9 @@
/* maximum Bluetooth volume value */
#define SCARLETT2_MAX_BLUETOOTH_VOLUME 30
+/* maximum front-panel sleep time in seconds (24 hours) */
+#define SCARLETT2_MAX_FP_SLEEP_TIME 86400
+
/* mixer range from -80dB to +12dB in 0.5dB steps */
#define SCARLETT2_MIXER_MIN_DB -80
#define SCARLETT2_MIXER_BIAS (-SCARLETT2_MIXER_MIN_DB * 2)
@@ -398,6 +401,7 @@ static const char *const scarlett2_autogain_status_gen4[] = {
"FailMaxGainLimit",
"FailClipped",
"Cancelled",
+ "Root",
"Invalid",
NULL
};
@@ -567,6 +571,8 @@ enum {
SCARLETT2_CONFIG_BLUETOOTH_VOLUME,
SCARLETT2_CONFIG_SPDIF_MODE,
SCARLETT2_CONFIG_SP_HP_MUTE,
+ SCARLETT2_CONFIG_FP_BRIGHTNESS,
+ SCARLETT2_CONFIG_FP_SLEEP_TIME,
SCARLETT2_CONFIG_COUNT
};
@@ -612,6 +618,20 @@ struct scarlett2_config_set {
const struct scarlett2_config items[SCARLETT2_CONFIG_COUNT];
};
+/* Map firmware versions to config sets per-device.
+ *
+ * Each device lists one or more entries, sorted in ascending order of
+ * from_firmware_version. At probe time the running firmware version
+ * is looked up against this list and the last entry whose
+ * from_firmware_version is <= the running version is selected.
+ *
+ * The list is terminated by a sentinel entry with config_set == NULL.
+ */
+struct scarlett2_config_set_entry {
+ u16 from_firmware_version;
+ const struct scarlett2_config_set *config_set;
+};
+
/* Input gain TLV dB ranges */
static const DECLARE_TLV_DB_MINMAX(
@@ -870,6 +890,42 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_solo = {
}
};
+/* Solo Gen 4, firmware version 2417 and above */
+static const struct scarlett2_config_set scarlett2_config_set_gen4_solo_2417 = {
+ .notifications = scarlett4_solo_notifications,
+ .param_buf_addr = 0xd8,
+ .items = {
+ [SCARLETT2_CONFIG_MSD_SWITCH] = {
+ .offset = 0x47, .size = 8, .activate = 4 },
+
+ [SCARLETT2_CONFIG_DIRECT_MONITOR] = {
+ .offset = 0x108, .size = 8, .activate = 12, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
+ .offset = 0x46, .size = 8, .activate = 9, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_LEVEL_SWITCH] = {
+ .offset = 0x3d, .size = 8, .activate = 10, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_AIR_SWITCH] = {
+ .offset = 0x3e, .size = 8, .activate = 11, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_PCM_INPUT_SWITCH] = {
+ .offset = 0x206, .size = 8, .activate = 25, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = {
+ .offset = 0x232, .size = 16, .activate = 26 },
+
+ [SCARLETT2_CONFIG_FP_BRIGHTNESS] = {
+ .offset = 0x243, .size = 8, .activate = 27, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_FP_SLEEP_TIME] = {
+ .offset = 0x248, .size = 32, .activate = 29 }
+ }
+};
+
/* 2i2 Gen 4 */
static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = {
.notifications = scarlett4_2i2_notifications,
@@ -923,6 +979,70 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = {
}
};
+/* 2i2 Gen 4, firmware version 2417 and above
+ *
+ * Firmware 2417 shifted DIRECT_MONITOR_GAIN by 4 bytes and added
+ * front-panel brightness and sleep controls; all other offsets are
+ * unchanged from scarlett2_config_set_gen4_2i2.
+ */
+static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2_2417 = {
+ .notifications = scarlett4_2i2_notifications,
+ .param_buf_addr = 0xfc,
+ .input_gain_tlv = db_scale_gen4_gain,
+ .autogain_status_texts = scarlett2_autogain_status_gen4,
+ .items = {
+ [SCARLETT2_CONFIG_MSD_SWITCH] = {
+ .offset = 0x49, .size = 8, .activate = 4 },
+
+ [SCARLETT2_CONFIG_DIRECT_MONITOR] = {
+ .offset = 0x14a, .size = 8, .activate = 16, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = {
+ .offset = 0x135, .size = 8, .activate = 10, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = {
+ .offset = 0x137, .size = 8 },
+
+ [SCARLETT2_CONFIG_AG_MEAN_TARGET] = {
+ .offset = 0x131, .size = 8, .activate = 29, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AG_PEAK_TARGET] = {
+ .offset = 0x132, .size = 8, .activate = 30, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
+ .offset = 0x48, .size = 8, .activate = 11, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_GAIN] = {
+ .offset = 0x4b, .size = 8, .activate = 12, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_LEVEL_SWITCH] = {
+ .offset = 0x3c, .size = 8, .activate = 13, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_SAFE_SWITCH] = {
+ .offset = 0x147, .size = 8, .activate = 14, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AIR_SWITCH] = {
+ .offset = 0x3e, .size = 8, .activate = 15, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = {
+ .offset = 0x14b, .size = 8, .activate = 17, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = {
+ .offset = 0x14e, .size = 8, .activate = 18, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = {
+ .offset = 0x2a4, .size = 16, .activate = 36 },
+
+ [SCARLETT2_CONFIG_FP_BRIGHTNESS] = {
+ .offset = 0x2c7, .size = 8, .activate = 37, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_FP_SLEEP_TIME] = {
+ .offset = 0x2cc, .size = 32, .activate = 39 }
+ }
+};
+
/* 4i4 Gen 4 */
static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = {
.notifications = scarlett4_4i4_notifications,
@@ -982,6 +1102,71 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = {
}
};
+/* 4i4 Gen 4, firmware version 2417 and above */
+static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4_2417 = {
+ .notifications = scarlett4_4i4_notifications,
+ .param_buf_addr = 0x130,
+ .input_gain_tlv = db_scale_gen4_gain,
+ .autogain_status_texts = scarlett2_autogain_status_gen4,
+ .items = {
+ [SCARLETT2_CONFIG_MSD_SWITCH] = {
+ .offset = 0x5c, .size = 8, .activate = 4 },
+
+ [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = {
+ .offset = 0x13e, .size = 8, .activate = 10, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = {
+ .offset = 0x140, .size = 8 },
+
+ [SCARLETT2_CONFIG_AG_MEAN_TARGET] = {
+ .offset = 0x13a, .size = 8, .activate = 23, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AG_PEAK_TARGET] = {
+ .offset = 0x13b, .size = 8, .activate = 24, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
+ .offset = 0x5a, .size = 8, .activate = 11, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_GAIN] = {
+ .offset = 0x5e, .size = 8, .activate = 12, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_LEVEL_SWITCH] = {
+ .offset = 0x4e, .size = 8, .activate = 13, .pbuf = 1,
+ .mute = 1 },
+
+ [SCARLETT2_CONFIG_SAFE_SWITCH] = {
+ .offset = 0x150, .size = 8, .activate = 14, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_AIR_SWITCH] = {
+ .offset = 0x50, .size = 8, .activate = 15, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = {
+ .offset = 0x153, .size = 8, .activate = 16, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = {
+ .offset = 0x156, .size = 8, .activate = 17, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_MASTER_VOLUME] = {
+ .offset = 0x32, .size = 16 },
+
+ [SCARLETT2_CONFIG_HEADPHONE_VOLUME] = {
+ .offset = 0x3a, .size = 16 },
+
+ [SCARLETT2_CONFIG_POWER_EXT] = {
+ .offset = 0x168, .size = 8 },
+
+ [SCARLETT2_CONFIG_POWER_LOW] = {
+ .offset = 0x16d, .size = 8 },
+
+ [SCARLETT2_CONFIG_FP_BRIGHTNESS] = {
+ .offset = 0x3a9, .size = 8, .activate = 36, .pbuf = 1 },
+
+ [SCARLETT2_CONFIG_FP_SLEEP_TIME] = {
+ .offset = 0x3ac, .size = 32, .activate = 38 }
+ }
+};
+
/* Clarett USB and Clarett+ devices: 2Pre, 4Pre, 8Pre */
static const struct scarlett2_config_set scarlett2_config_set_clarett = {
.notifications = scarlett2_notifications,
@@ -1100,11 +1285,8 @@ struct scarlett2_meter_entry {
};
struct scarlett2_device_info {
- /* which set of configuration parameters the device uses */
- const struct scarlett2_config_set *config_set;
-
- /* minimum firmware version required */
- u16 min_firmware_version;
+ /* which sets of configuration parameters the device uses */
+ const struct scarlett2_config_set_entry *config_sets;
/* has a downloadable device map */
u8 has_devmap;
@@ -1335,6 +1517,8 @@ struct scarlett2_data {
struct snd_kcontrol *talkback_ctl;
struct snd_kcontrol *power_status_ctl;
struct snd_kcontrol *bluetooth_volume_ctl;
+ u8 fp_brightness;
+ u32 fp_sleep_time;
u8 mux[SCARLETT2_MUX_MAX];
u8 mix[SCARLETT2_MIX_MAX];
u8 monitor_mix[SCARLETT2_MONITOR_MIX_MAX];
@@ -1343,7 +1527,10 @@ struct scarlett2_data {
/*** Model-specific data ***/
static const struct scarlett2_device_info s6i6_gen2_info = {
- .config_set = &scarlett2_config_set_gen2a,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen2a },
+ { }
+ },
.level_input_count = 2,
.pad_input_count = 2,
@@ -1393,7 +1580,10 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
};
static const struct scarlett2_device_info s18i8_gen2_info = {
- .config_set = &scarlett2_config_set_gen2a,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen2a },
+ { }
+ },
.level_input_count = 2,
.pad_input_count = 4,
@@ -1446,7 +1636,10 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
};
static const struct scarlett2_device_info s18i20_gen2_info = {
- .config_set = &scarlett2_config_set_gen2b,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen2b },
+ { }
+ },
.line_out_descrs = {
"Monitor L",
@@ -1503,7 +1696,10 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
};
static const struct scarlett2_device_info solo_gen3_info = {
- .config_set = &scarlett2_config_set_gen3a,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3a },
+ { }
+ },
.level_input_count = 1,
.level_input_first = 1,
.air_input_count = 1,
@@ -1513,7 +1709,10 @@ static const struct scarlett2_device_info solo_gen3_info = {
};
static const struct scarlett2_device_info s2i2_gen3_info = {
- .config_set = &scarlett2_config_set_gen3a,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3a },
+ { }
+ },
.level_input_count = 2,
.air_input_count = 2,
.phantom_count = 1,
@@ -1522,7 +1721,10 @@ static const struct scarlett2_device_info s2i2_gen3_info = {
};
static const struct scarlett2_device_info s4i4_gen3_info = {
- .config_set = &scarlett2_config_set_gen3b,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3b },
+ { }
+ },
.level_input_count = 2,
.pad_input_count = 2,
.air_input_count = 2,
@@ -1571,7 +1773,10 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
};
static const struct scarlett2_device_info s8i6_gen3_info = {
- .config_set = &scarlett2_config_set_gen3b,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3b },
+ { }
+ },
.level_input_count = 2,
.pad_input_count = 2,
.air_input_count = 2,
@@ -1637,7 +1842,10 @@ static const char * const scarlett2_spdif_s18i8_gen3_texts[] = {
};
static const struct scarlett2_device_info s18i8_gen3_info = {
- .config_set = &scarlett2_config_set_gen3c,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3c },
+ { }
+ },
.has_speaker_switching = 1,
.level_input_count = 2,
.pad_input_count = 4,
@@ -1729,7 +1937,10 @@ static const char * const scarlett2_spdif_s18i20_gen3_texts[] = {
};
static const struct scarlett2_device_info s18i20_gen3_info = {
- .config_set = &scarlett2_config_set_gen3c,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_gen3c },
+ { }
+ },
.has_speaker_switching = 1,
.has_talkback = 1,
.level_input_count = 2,
@@ -1803,8 +2014,10 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
};
static const struct scarlett2_device_info vocaster_one_info = {
- .config_set = &scarlett2_config_set_vocaster,
- .min_firmware_version = 1769,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 1769, &scarlett2_config_set_vocaster },
+ { }
+ },
.has_devmap = 1,
.phantom_count = 1,
@@ -1847,8 +2060,10 @@ static const struct scarlett2_device_info vocaster_one_info = {
};
static const struct scarlett2_device_info vocaster_two_info = {
- .config_set = &scarlett2_config_set_vocaster,
- .min_firmware_version = 1769,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 1769, &scarlett2_config_set_vocaster },
+ { }
+ },
.has_devmap = 1,
.phantom_count = 2,
@@ -1892,8 +2107,11 @@ static const struct scarlett2_device_info vocaster_two_info = {
};
static const struct scarlett2_device_info solo_gen4_info = {
- .config_set = &scarlett2_config_set_gen4_solo,
- .min_firmware_version = 2115,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 2115, &scarlett2_config_set_gen4_solo },
+ { 2417, &scarlett2_config_set_gen4_solo_2417 },
+ { }
+ },
.has_devmap = 1,
.level_input_count = 1,
@@ -1947,8 +2165,11 @@ static const struct scarlett2_device_info solo_gen4_info = {
};
static const struct scarlett2_device_info s2i2_gen4_info = {
- .config_set = &scarlett2_config_set_gen4_2i2,
- .min_firmware_version = 2115,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 2115, &scarlett2_config_set_gen4_2i2 },
+ { 2417, &scarlett2_config_set_gen4_2i2_2417 },
+ { }
+ },
.has_devmap = 1,
.level_input_count = 2,
@@ -2002,8 +2223,11 @@ static const struct scarlett2_device_info s2i2_gen4_info = {
};
static const struct scarlett2_device_info s4i4_gen4_info = {
- .config_set = &scarlett2_config_set_gen4_4i4,
- .min_firmware_version = 2089,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 2089, &scarlett2_config_set_gen4_4i4 },
+ { 2417, &scarlett2_config_set_gen4_4i4_2417 },
+ { }
+ },
.has_devmap = 1,
.level_input_count = 2,
@@ -2051,7 +2275,10 @@ static const struct scarlett2_device_info s4i4_gen4_info = {
};
static const struct scarlett2_device_info clarett_2pre_info = {
- .config_set = &scarlett2_config_set_clarett,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_clarett },
+ { }
+ },
.level_input_count = 2,
.air_input_count = 2,
@@ -2107,7 +2334,10 @@ static const char * const scarlett2_spdif_clarett_texts[] = {
};
static const struct scarlett2_device_info clarett_4pre_info = {
- .config_set = &scarlett2_config_set_clarett,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_clarett },
+ { }
+ },
.level_input_count = 2,
.air_input_count = 4,
@@ -2163,7 +2393,10 @@ static const struct scarlett2_device_info clarett_4pre_info = {
};
static const struct scarlett2_device_info clarett_8pre_info = {
- .config_set = &scarlett2_config_set_clarett,
+ .config_sets = (const struct scarlett2_config_set_entry[]) {
+ { 0, &scarlett2_config_set_clarett },
+ { }
+ },
.level_input_count = 2,
.air_input_count = 8,
@@ -3276,7 +3509,8 @@ static int scarlett2_min_firmware_version_ctl_get(
struct usb_mixer_elem_info *elem = kctl->private_data;
struct scarlett2_data *private = elem->head.mixer->private_data;
- ucontrol->value.integer.value[0] = private->info->min_firmware_version;
+ ucontrol->value.integer.value[0] =
+ private->info->config_sets[0].from_firmware_version;
return 0;
}
@@ -7626,6 +7860,172 @@ static int scarlett2_add_bluetooth_volume_ctl(
&private->bluetooth_volume_ctl);
}
+/*** Front Panel Brightness/Sleep Controls ***/
+
+static int scarlett2_update_fp(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+ int err;
+
+ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_FP_BRIGHTNESS)) {
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_FP_BRIGHTNESS,
+ 1, &private->fp_brightness);
+ if (err < 0)
+ return err;
+ }
+
+ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_FP_SLEEP_TIME)) {
+ err = scarlett2_usb_get_config(
+ mixer, SCARLETT2_CONFIG_FP_SLEEP_TIME,
+ 1, &private->fp_sleep_time);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static const char * const scarlett2_fp_brightness_texts[] = {
+ "High", "Medium", "Low"
+};
+
+static int scarlett2_fp_brightness_ctl_info(
+ struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ return snd_ctl_enum_info(uinfo, 1,
+ ARRAY_SIZE(scarlett2_fp_brightness_texts),
+ scarlett2_fp_brightness_texts);
+}
+
+static int scarlett2_fp_brightness_ctl_get(
+ struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett2_data *private = elem->head.mixer->private_data;
+
+ ucontrol->value.enumerated.item[0] = private->fp_brightness;
+ return 0;
+}
+
+static int scarlett2_fp_brightness_ctl_put(
+ 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 oval, val, err;
+
+ guard(mutex)(&private->data_mutex);
+
+ if (private->hwdep_in_use)
+ return -EBUSY;
+
+ oval = private->fp_brightness;
+ val = min(ucontrol->value.enumerated.item[0],
+ ARRAY_SIZE(scarlett2_fp_brightness_texts) - 1);
+
+ if (oval == val)
+ return 0;
+
+ private->fp_brightness = val;
+
+ err = scarlett2_usb_set_config(
+ mixer, SCARLETT2_CONFIG_FP_BRIGHTNESS, 0, val);
+
+ return err < 0 ? err : 1;
+}
+
+static const struct snd_kcontrol_new scarlett2_fp_brightness_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .name = "",
+ .info = scarlett2_fp_brightness_ctl_info,
+ .get = scarlett2_fp_brightness_ctl_get,
+ .put = scarlett2_fp_brightness_ctl_put,
+};
+
+static int scarlett2_fp_sleep_time_ctl_info(
+ struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SCARLETT2_MAX_FP_SLEEP_TIME;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int scarlett2_fp_sleep_time_ctl_get(
+ struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett2_data *private = elem->head.mixer->private_data;
+
+ ucontrol->value.integer.value[0] = private->fp_sleep_time;
+ return 0;
+}
+
+static int scarlett2_fp_sleep_time_ctl_put(
+ 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;
+ u32 oval, val;
+ int err;
+
+ guard(mutex)(&private->data_mutex);
+
+ if (private->hwdep_in_use)
+ return -EBUSY;
+
+ oval = private->fp_sleep_time;
+ val = clamp(ucontrol->value.integer.value[0],
+ 0L, (long)SCARLETT2_MAX_FP_SLEEP_TIME);
+
+ if (oval == val)
+ return 0;
+
+ private->fp_sleep_time = val;
+
+ err = scarlett2_usb_set_config(
+ mixer, SCARLETT2_CONFIG_FP_SLEEP_TIME, 0, val);
+
+ return err < 0 ? err : 1;
+}
+
+static const struct snd_kcontrol_new scarlett2_fp_sleep_time_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .name = "",
+ .info = scarlett2_fp_sleep_time_ctl_info,
+ .get = scarlett2_fp_sleep_time_ctl_get,
+ .put = scarlett2_fp_sleep_time_ctl_put,
+};
+
+static int scarlett2_add_fp_ctls(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+ int err;
+
+ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_FP_BRIGHTNESS)) {
+ err = scarlett2_add_new_ctl(
+ mixer, &scarlett2_fp_brightness_ctl, 0, 1,
+ "Front Panel Brightness", NULL);
+ if (err < 0)
+ return err;
+ }
+
+ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_FP_SLEEP_TIME)) {
+ err = scarlett2_add_new_ctl(
+ mixer, &scarlett2_fp_sleep_time_ctl, 0, 1,
+ "Front Panel Sleep Time", NULL);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/*** S/PDIF Mode Controls ***/
static int scarlett2_update_spdif_mode(struct usb_mixer_interface *mixer)
@@ -8184,10 +8584,32 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
/*** Initialisation ***/
+/* Select the config_set matching the running firmware version.
+ *
+ * The device info's config_sets array is ordered by ascending
+ * from_firmware_version; pick the last entry whose version is <= the
+ * running firmware version. If the running firmware is older than the
+ * first entry's from_firmware_version (i.e. older than the driver's
+ * minimum supported version for this device), the first entry's
+ * config_set is selected anyway so firmware updates can still be done
+ * (requires only the ACK handler), but the usual mixer controls
+ * aren't created.
+ */
+static void scarlett2_resolve_config_set(struct scarlett2_data *private)
+{
+ const struct scarlett2_config_set_entry *entry =
+ private->info->config_sets;
+
+ private->config_set = entry->config_set;
+ for (entry++; entry->config_set; entry++)
+ if (entry->from_firmware_version <= private->firmware_version)
+ private->config_set = entry->config_set;
+}
+
static void scarlett2_count_io(struct scarlett2_data *private)
{
const struct scarlett2_device_info *info = private->info;
- const struct scarlett2_config_set *config_set = info->config_set;
+ const struct scarlett2_config_set *config_set = private->config_set;
const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
int port_type, srcs = 0, dsts = 0, i;
@@ -8284,9 +8706,14 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer,
mixer->private_suspend = scarlett2_private_suspend;
private->info = entry->info;
- private->config_set = entry->info->config_set;
+
+ /* Set config_set to the first entry's config_set so the
+ * notify handler has a valid pointer while USB init runs; it
+ * is re-resolved once the firmware version has been read.
+ */
+ private->config_set = entry->info->config_sets[0].config_set;
+
private->series_name = entry->series_name;
- scarlett2_count_io(private);
private->scarlett2_seq = 0;
private->mixer = mixer;
@@ -8476,6 +8903,7 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
{
struct scarlett2_data *private = mixer->private_data;
const struct scarlett2_device_info *info = private->info;
+ u16 min_firmware_version = info->config_sets[0].from_firmware_version;
int err, i;
if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) {
@@ -8486,13 +8914,13 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
return err;
}
- if (private->firmware_version < info->min_firmware_version) {
+ if (private->firmware_version < 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);
+ min_firmware_version);
return 0;
}
@@ -8646,6 +9074,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
if (err < 0)
return err;
+ err = scarlett2_update_fp(mixer);
+ if (err < 0)
+ return err;
+
err = scarlett2_update_spdif_mode(mixer);
if (err < 0)
return err;
@@ -8676,6 +9108,7 @@ static int snd_scarlett2_controls_create(
const struct scarlett2_device_entry *entry)
{
struct scarlett2_data *private;
+ u16 min_firmware_version;
int err;
/* Initialise private data */
@@ -8684,12 +9117,21 @@ static int snd_scarlett2_controls_create(
return err;
private = mixer->private_data;
+ min_firmware_version =
+ private->info->config_sets[0].from_firmware_version;
/* Send proprietary USB initialisation sequence */
err = scarlett2_usb_init(mixer);
if (err < 0)
return err;
+ /* Now that the firmware version is known, pick the matching
+ * config_set
+ */
+ scarlett2_resolve_config_set(private);
+
+ scarlett2_count_io(private);
+
/* Get the upgrade & settings flash segment numbers */
err = scarlett2_get_flash_segment_nums(mixer);
if (err < 0)
@@ -8719,7 +9161,7 @@ static int snd_scarlett2_controls_create(
* old, don't create any other controls
*/
if (private->msd_switch ||
- private->firmware_version < private->info->min_firmware_version)
+ private->firmware_version < min_firmware_version)
return 0;
/* Create the analogue output controls */
@@ -8782,6 +9224,11 @@ static int snd_scarlett2_controls_create(
if (err < 0)
return err;
+ /* Create the front-panel brightness/sleep controls */
+ err = scarlett2_add_fp_ctls(mixer);
+ if (err < 0)
+ return err;
+
/* Create the S/PDIF mode control */
err = scarlett2_add_spdif_mode_ctl(mixer);
if (err < 0)
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
index 8a02964e5d7b..ebff185cbd2c 100644
--- a/sound/usb/mixer_us16x08.c
+++ b/sound/usb/mixer_us16x08.c
@@ -224,14 +224,14 @@ static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
- if (err > 0) {
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err);
+ return err;
}
- return err > 0 ? 1 : 0;
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ return 1;
}
static int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
@@ -283,14 +283,14 @@ static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
buf[5] = index + 1;
err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
- if (err > 0) {
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set master, err:%d\n", err);
+ return err;
}
- return err > 0 ? 1 : 0;
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ return 1;
}
static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
@@ -324,14 +324,14 @@ static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
break;
}
- if (err > 0) {
- elem->cached |= 1;
- elem->cache_val[0] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set bus parameter, err:%d\n", err);
+ return err;
}
- return err > 0 ? 1 : 0;
+ elem->cached |= 1;
+ elem->cache_val[0] = val;
+ return 1;
}
static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol,
@@ -392,14 +392,14 @@ static int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol,
err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
- if (err > 0) {
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err);
+ return err;
}
- return err > 0 ? 1 : 0;
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ return 1;
}
static int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
@@ -435,6 +435,7 @@ static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
int index = ucontrol->id.index;
char buf[sizeof(comp_msg)];
int val_idx, val;
+ int threshold, ratio, attack, release, gain, switch_on;
int err;
val = ucontrol->value.integer.value[0];
@@ -447,36 +448,61 @@ static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
/* new control value incl. bias*/
val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE;
- store->val[val_idx][index] = ucontrol->value.integer.value[0];
+ threshold = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)]
+ [index];
+ ratio = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index];
+ attack = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index];
+ release = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)]
+ [index];
+ gain = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
+ switch_on = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)]
+ [index];
+
+ switch (val_idx) {
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD):
+ threshold = val;
+ break;
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO):
+ ratio = val;
+ break;
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK):
+ attack = val;
+ break;
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE):
+ release = val;
+ break;
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN):
+ gain = val;
+ break;
+ case COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH):
+ switch_on = val;
+ break;
+ }
/* prepare compressor URB message from template */
memcpy(buf, comp_msg, sizeof(comp_msg));
/* place comp values in message buffer watch bias! */
- buf[8] = store->val[
- COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index]
- - SND_US16X08_COMP_THRESHOLD_BIAS;
- buf[11] = ratio_map[store->val[
- COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]];
- buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index]
- + SND_US16X08_COMP_ATTACK_BIAS;
- buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index]
- + SND_US16X08_COMP_RELEASE_BIAS;
- buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
- buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index];
+ buf[8] = threshold - SND_US16X08_COMP_THRESHOLD_BIAS;
+ buf[11] = ratio_map[ratio];
+ buf[14] = attack + SND_US16X08_COMP_ATTACK_BIAS;
+ buf[17] = release + SND_US16X08_COMP_RELEASE_BIAS;
+ buf[20] = gain;
+ buf[26] = switch_on;
/* place channel selector in message buffer */
buf[5] = index + 1;
err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
- if (err > 0) {
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err);
+ return err;
}
+ store->val[val_idx][index] = val;
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
return 1;
}
@@ -529,13 +555,13 @@ static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
msleep(15);
}
- if (err > 0) {
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err);
+ return err;
}
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
return 1;
}
@@ -578,11 +604,10 @@ static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
/* copy URB buffer from EQ template */
memcpy(buf, eqs_msq, sizeof(eqs_msq));
- store->val[b_idx][p_idx][index] = val;
- buf[20] = store->val[b_idx][3][index];
- buf[17] = store->val[b_idx][2][index];
- buf[14] = store->val[b_idx][1][index];
- buf[11] = store->val[b_idx][0][index];
+ buf[20] = p_idx == 3 ? val : store->val[b_idx][3][index];
+ buf[17] = p_idx == 2 ? val : store->val[b_idx][2][index];
+ buf[14] = p_idx == 1 ? val : store->val[b_idx][1][index];
+ buf[11] = p_idx == 0 ? val : store->val[b_idx][0][index];
/* place channel index in URB buffer */
buf[5] = index + 1;
@@ -592,14 +617,15 @@ static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
- if (err > 0) {
- /* store new value in EQ band cache */
- elem->cached |= 1 << index;
- elem->cache_val[index] = val;
- } else {
+ if (err < 0) {
usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err);
+ return err;
}
+ store->val[b_idx][p_idx][index] = val;
+ /* store new value in EQ band cache */
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
return 1;
}
@@ -1418,4 +1444,3 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
return 0;
}
-