aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 22:42:31 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 22:42:31 +0100
commit769e39f484145599bb4a2757165a019a60d27823 (patch)
tree67f8809034013b8f0d716a6a097c81893be422d1 /sound
parentb86bd25caad27a24628d8f9a7eca3e7d72816301 (diff)
parent17065203e1bc7e7f2786998d532cd93a06265156 (diff)
downloadlinux-next-history-769e39f484145599bb4a2757165a019a60d27823.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
Diffstat (limited to 'sound')
-rw-r--r--sound/ac97_bus.c4
-rw-r--r--sound/aoa/fabrics/layout.c6
-rw-r--r--sound/core/hrtimer.c2
-rw-r--r--sound/core/jack.c13
-rw-r--r--sound/core/oss/pcm_oss.c4
-rw-r--r--sound/core/oss/pcm_plugin.c2
-rw-r--r--sound/core/pcm_native.c14
-rw-r--r--sound/core/rawmidi.c4
-rw-r--r--sound/core/seq/oss/seq_oss_event.c6
-rw-r--r--sound/core/seq/oss/seq_oss_event.h3
-rw-r--r--sound/core/seq/oss/seq_oss_init.c4
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c5
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c6
-rw-r--r--sound/core/seq/oss/seq_oss_midi.h2
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c13
-rw-r--r--sound/core/seq/oss/seq_oss_readq.h3
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c5
-rw-r--r--sound/core/seq/seq_clientmgr.c7
-rw-r--r--sound/core/seq/seq_dummy.c2
-rw-r--r--sound/core/seq/seq_midi.c55
-rw-r--r--sound/core/seq/seq_midi_emul.c38
-rw-r--r--sound/core/seq/seq_ports.c24
-rw-r--r--sound/core/seq/seq_ports.h8
-rw-r--r--sound/core/seq/seq_prioq.c14
-rw-r--r--sound/drivers/mpu401/mpu401.c2
-rw-r--r--sound/drivers/pcmtest.c4
-rw-r--r--sound/hda/codecs/Kconfig1
-rw-r--r--sound/hda/codecs/ca0132.c111
-rw-r--r--sound/hda/codecs/hdmi/hdmi.c8
-rw-r--r--sound/hda/codecs/realtek/alc269.c33
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig2
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.c77
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.h5
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_i2c.c3
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c3
-rw-r--r--sound/hda/common/jack.c6
-rw-r--r--sound/hda/core/i915.c30
-rw-r--r--sound/isa/cmi8330.c4
-rw-r--r--sound/isa/cs423x/cs4236.c6
-rw-r--r--sound/isa/es18xx.c6
-rw-r--r--sound/isa/gus/gus_pcm.c2
-rw-r--r--sound/isa/gus/interwave.c4
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c4
-rw-r--r--sound/isa/opl3sa2.c6
-rw-r--r--sound/isa/opti9xx/miro.c268
-rw-r--r--sound/isa/sb/sb16.c4
-rw-r--r--sound/isa/sscape.c4
-rw-r--r--sound/isa/wavefront/wavefront.c65
-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/ali5451/ali5451.c4
-rw-r--r--sound/pci/als300.c6
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/asihpi/asihpi.c17
-rw-r--r--sound/pci/asihpi/hpicmn.c16
-rw-r--r--sound/pci/asihpi/hpicmn.h4
-rw-r--r--sound/pci/asihpi/hpipcida.h18
-rw-r--r--sound/pci/atiixp.c10
-rw-r--r--sound/pci/atiixp_modem.c6
-rw-r--r--sound/pci/au88x0/au8810.c4
-rw-r--r--sound/pci/au88x0/au8820.c4
-rw-r--r--sound/pci/au88x0/au8830.c4
-rw-r--r--sound/pci/aw2/aw2-alsa.c5
-rw-r--r--sound/pci/azt3328.c6
-rw-r--r--sound/pci/ca0106/ca0106_main.c4
-rw-r--r--sound/pci/cmipci.c18
-rw-r--r--sound/pci/cs4281.c4
-rw-r--r--sound/pci/cs46xx/cs46xx.c8
-rw-r--r--sound/pci/ctxfi/ctmixer.c44
-rw-r--r--sound/pci/ctxfi/ctmixer.h7
-rw-r--r--sound/pci/ctxfi/ctsrc.c15
-rw-r--r--sound/pci/ctxfi/ctsrc.h2
-rw-r--r--sound/pci/echoaudio/darla20.c4
-rw-r--r--sound/pci/echoaudio/darla24.c6
-rw-r--r--sound/pci/echoaudio/echo3g.c4
-rw-r--r--sound/pci/echoaudio/gina20.c4
-rw-r--r--sound/pci/echoaudio/gina24.c10
-rw-r--r--sound/pci/echoaudio/indigo.c4
-rw-r--r--sound/pci/echoaudio/indigodj.c4
-rw-r--r--sound/pci/echoaudio/indigodjx.c4
-rw-r--r--sound/pci/echoaudio/indigoio.c4
-rw-r--r--sound/pci/echoaudio/indigoiox.c4
-rw-r--r--sound/pci/echoaudio/layla20.c6
-rw-r--r--sound/pci/echoaudio/layla24.c4
-rw-r--r--sound/pci/echoaudio/mia.c6
-rw-r--r--sound/pci/echoaudio/mona.c20
-rw-r--r--sound/pci/emu10k1/emu10k1.c8
-rw-r--r--sound/pci/emu10k1/emu10k1x.c4
-rw-r--r--sound/pci/ens1370.c10
-rw-r--r--sound/pci/es1938.c6
-rw-r--r--sound/pci/es1968.c27
-rw-r--r--sound/pci/fm801.c15
-rw-r--r--sound/pci/ice1712/aureon.c2
-rw-r--r--sound/pci/ice1712/ice1712.c12
-rw-r--r--sound/pci/ice1712/ice1724.c29
-rw-r--r--sound/pci/intel8x0.c118
-rw-r--r--sound/pci/intel8x0m.c88
-rw-r--r--sound/pci/maestro3.c51
-rw-r--r--sound/pci/mixart/mixart.c4
-rw-r--r--sound/pci/nm256/nm256.c8
-rw-r--r--sound/pci/pcxhr/pcxhr.c70
-rw-r--r--sound/pci/rme32.c8
-rw-r--r--sound/pci/rme96.c10
-rw-r--r--sound/pci/sonicvibes.c4
-rw-r--r--sound/pci/trident/trident.c16
-rw-r--r--sound/pci/via82xx.c6
-rw-r--r--sound/pci/via82xx_modem.c4
-rw-r--r--sound/pci/vx222/vx222.c6
-rw-r--r--sound/pci/ymfpci/ymfpci.c14
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c6
-rw-r--r--sound/synth/emux/emux_seq.c11
-rw-r--r--sound/usb/endpoint.c10
-rw-r--r--sound/usb/fcp.c4
-rw-r--r--sound/usb/mixer.c58
-rw-r--r--sound/usb/mixer_quirks.c107
-rw-r--r--sound/usb/mixer_scarlett.c4
-rw-r--r--sound/usb/mixer_scarlett2.c558
-rw-r--r--sound/usb/mixer_us16x08.c127
-rw-r--r--sound/usb/quirks-table.h8
-rw-r--r--sound/usb/quirks.c3
-rw-r--r--sound/usb/usbaudio.h8
-rw-r--r--sound/usb/usx2y/usbusx2y.c39
-rw-r--r--sound/virtio/virtio_kctl.c50
-rw-r--r--sound/virtio/virtio_pcm.c3
-rw-r--r--sound/virtio/virtio_pcm_ops.c3
-rw-r--r--sound/xen/xen_snd_front_alsa.c17
-rw-r--r--sound/xen/xen_snd_front_evtchnl.c28
-rw-r--r--sound/xen/xen_snd_front_evtchnl.h6
129 files changed, 2185 insertions, 734 deletions
diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c
index 8a44297964f50..ad7fb6b0c2c00 100644
--- a/sound/ac97_bus.c
+++ b/sound/ac97_bus.c
@@ -73,7 +73,6 @@ int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
if (snd_ac97_check_id(ac97, id, id_mask))
return 0;
-
return -ENODEV;
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);
@@ -81,6 +80,7 @@ EXPORT_SYMBOL_GPL(snd_ac97_reset);
const struct bus_type ac97_bus_type = {
.name = "ac97",
};
+EXPORT_SYMBOL(ac97_bus_type);
static int __init ac97_bus_init(void)
{
@@ -96,7 +96,5 @@ static void __exit ac97_bus_exit(void)
module_exit(ac97_bus_exit);
-EXPORT_SYMBOL(ac97_bus_type);
-
MODULE_DESCRIPTION("Legacy AC97 bus interface");
MODULE_LICENSE("GPL");
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index c3ebb6de47891..7bb541577a263 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -948,6 +948,8 @@ static void layout_attached_codec(struct aoa_codec *codec)
if (lineout == 1)
ldev->gpio.methods->set_lineout(codec->gpio, 1);
ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
+ if (!ctl)
+ return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name, "Headphone Switch");
ldev->lineout_ctrl = ctl;
@@ -961,12 +963,16 @@ static void layout_attached_codec(struct aoa_codec *codec)
if (ldev->have_lineout_detect) {
ctl = snd_ctl_new1(&lineout_detect_choice,
ldev);
+ if (!ctl)
+ return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
"Headphone Detect Autoswitch");
aoa_snd_ctl_add(ctl);
ctl = snd_ctl_new1(&lineout_detected,
ldev);
+ if (!ctl)
+ return;
if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
strscpy(ctl->id.name,
"Headphone Detected");
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index 9fcd1c03dc5b2..92c585f8eeb10 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -20,7 +20,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
#define NANO_SEC 1000000000UL /* 10^9 in sec */
-static unsigned int resolution;
+static unsigned int resolution __ro_after_init;
struct snd_hrtimer {
struct snd_timer *timer;
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 5e8a2f3f41966..96e0733ede778 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -250,18 +250,15 @@ static const char * const jack_events_name[] = {
/* the recommended buffer size is 256 */
static int parse_mask_bits(unsigned int mask_bits, char *buf, size_t buf_size)
{
+ int len = scnprintf(buf, buf_size, "0x%04x", mask_bits);
int i;
- scnprintf(buf, buf_size, "0x%04x", mask_bits);
-
for (i = 0; i < ARRAY_SIZE(jack_events_name); i++)
- if (mask_bits & (1 << i)) {
- strlcat(buf, " ", buf_size);
- strlcat(buf, jack_events_name[i], buf_size);
- }
- strlcat(buf, "\n", buf_size);
+ if (mask_bits & (1 << i))
+ len += scnprintf(buf + len, buf_size - len, " %s", jack_events_name[i]);
+ len += scnprintf(buf + len, buf_size - len, "\n");
- return strlen(buf);
+ return len;
}
static ssize_t jack_kctl_mask_bits_read(struct file *file,
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 746eaf93e1a57..9826d9a0be6d3 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -32,8 +32,8 @@
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
-static int dsp_map[SNDRV_CARDS];
-static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
+static int dsp_map[SNDRV_CARDS] __ro_after_init;
+static int adsp_map[SNDRV_CARDS] __ro_after_init = {[0 ... (SNDRV_CARDS-1)] = 1};
static bool nonblock_open = 1;
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 14b4a390a2192..5f4d6945a7df6 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -146,7 +146,7 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *plug,
return -ENXIO;
if (snd_BUG_ON(!src_format || !dst_format))
return -ENXIO;
- plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL);
+ plugin = kzalloc_flex(*plugin, extra_data, extra);
if (plugin == NULL)
return -ENOMEM;
plugin->name = name;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a541bb235cfa1..50da38b141cb7 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1973,13 +1973,15 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream)
static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_state_t cur_state = snd_pcm_get_state(substream);
int f_flags = (__force int)state;
- if (runtime->state == SNDRV_PCM_STATE_OPEN ||
- runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
+ if (cur_state == SNDRV_PCM_STATE_OPEN ||
+ cur_state == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
- if (snd_pcm_running(substream))
+ if (cur_state == SNDRV_PCM_STATE_RUNNING ||
+ (cur_state == SNDRV_PCM_STATE_DRAINING &&
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EBUSY;
substream->f_flags = f_flags;
return 0;
@@ -2139,7 +2141,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
card = substream->pcm->card;
runtime = substream->runtime;
- if (runtime->state == SNDRV_PCM_STATE_OPEN)
+ if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if (file) {
@@ -3524,7 +3526,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
snd_pcm_uframes_t *frames = arg;
snd_pcm_sframes_t result;
- if (substream->runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
+ if (snd_pcm_get_state(substream) == SNDRV_PCM_STATE_DISCONNECTED)
return -EBADFD;
switch (cmd) {
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 3b1034a449386..4dfd9d53e6d3a 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -28,8 +28,8 @@ MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");
#ifdef CONFIG_SND_OSSEMUL
-static int midi_map[SNDRV_CARDS];
-static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
+static int midi_map[SNDRV_CARDS] __ro_after_init;
+static int amidi_map[SNDRV_CARDS] __ro_after_init = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
module_param_array(amidi_map, int, NULL, 0444);
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
index 76fb81077eef7..122735862044d 100644
--- a/sound/core/seq/oss/seq_oss_event.c
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -39,8 +39,10 @@ static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct s
*/
int
-snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
+snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
+ *lockp = NULL;
switch (q->s.code) {
case SEQ_EXTENDED:
return extended_event(dp, q, ev);
@@ -69,7 +71,7 @@ snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd
if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
break;
if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
- return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
+ return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev, lockp);
break;
case SEQ_ECHO:
diff --git a/sound/core/seq/oss/seq_oss_event.h b/sound/core/seq/oss/seq_oss_event.h
index b4f723949a170..a4524e51d0e9d 100644
--- a/sound/core/seq/oss/seq_oss_event.h
+++ b/sound/core/seq/oss/seq_oss_event.h
@@ -91,7 +91,8 @@ union evrec {
#define ev_is_long(ev) ((ev)->s.code >= 128)
#define ev_length(ev) ((ev)->s.code >= 128 ? LONG_EVENT_SIZE : SHORT_EVENT_SIZE)
-int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
+int snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *q);
int snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index d3e6a8a8d8234..1aece46c8b064 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -27,8 +27,8 @@ static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
module_param(maxqlen, int, 0444);
MODULE_PARM_DESC(maxqlen, "maximum queue length");
-static int system_client = -1; /* ALSA sequencer client number */
-static int system_port = -1;
+static int system_client __ro_after_init = -1; /* ALSA sequencer client number */
+static int system_port __ro_after_init = -1;
static int num_clients;
static struct seq_oss_devinfo *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
index ccf682689ec95..ce7a69d52b308 100644
--- a/sound/core/seq/oss/seq_oss_ioctl.c
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -45,14 +45,17 @@ static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg)
{
unsigned char ev[8];
struct snd_seq_event tmpev;
+ snd_use_lock_t *lock = NULL;
if (copy_from_user(ev, arg, 8))
return -EFAULT;
memset(&tmpev, 0, sizeof(tmpev));
snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.client, dp->addr.port);
tmpev.time.tick = 0;
- if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) {
+ if (!snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev, &lock)) {
snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
+ if (lock)
+ snd_use_lock_free(lock);
}
return 0;
}
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index b50a49ca42ff3..70f94df651446 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -593,7 +593,8 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
* non-zero : invalid - ignored
*/
int
-snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev)
+snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
+ struct snd_seq_event *ev, snd_use_lock_t **lockp)
{
struct seq_oss_midi *mdev __free(seq_oss_midi) =
get_mididev(dp, dev);
@@ -602,6 +603,9 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
+ /* the caller must release this later */
+ *lockp = &mdev->use_lock;
+ snd_use_lock_use(*lockp);
return 0;
}
return -EINVAL;
diff --git a/sound/core/seq/oss/seq_oss_midi.h b/sound/core/seq/oss/seq_oss_midi.h
index bcc1683773dfb..4819d4170bf6d 100644
--- a/sound/core/seq/oss/seq_oss_midi.h
+++ b/sound/core/seq/oss/seq_oss_midi.h
@@ -26,7 +26,7 @@ void snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode);
int snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev);
void snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c,
- struct snd_seq_event *ev);
+ struct snd_seq_event *ev, snd_use_lock_t **lockp);
int snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private);
int snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev);
int snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf);
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
index c880d47711698..6b474615ced89 100644
--- a/sound/core/seq/oss/seq_oss_readq.c
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -34,16 +34,10 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
{
struct seq_oss_readq *q;
- q = kzalloc_obj(*q);
+ q = kzalloc_flex(*q, q, maxlen);
if (!q)
return NULL;
- q->q = kzalloc_objs(union evrec, maxlen);
- if (!q->q) {
- kfree(q);
- return NULL;
- }
-
q->maxlen = maxlen;
q->qlen = 0;
q->head = q->tail = 0;
@@ -61,10 +55,7 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
void
snd_seq_oss_readq_delete(struct seq_oss_readq *q)
{
- if (q) {
- kfree(q->q);
- kfree(q);
- }
+ kfree(q);
}
/*
diff --git a/sound/core/seq/oss/seq_oss_readq.h b/sound/core/seq/oss/seq_oss_readq.h
index 38d0c4682b298..d8e1e7504d8fb 100644
--- a/sound/core/seq/oss/seq_oss_readq.h
+++ b/sound/core/seq/oss/seq_oss_readq.h
@@ -10,13 +10,13 @@
#define __SEQ_OSS_READQ_H
#include "seq_oss_device.h"
+#include "seq_oss_event.h"
/*
* definition of read queue
*/
struct seq_oss_readq {
- union evrec *q;
int qlen;
int maxlen;
int head, tail;
@@ -24,6 +24,7 @@ struct seq_oss_readq {
unsigned long input_time;
wait_queue_head_t midi_sleep;
spinlock_t lock;
+ union evrec q[] __counted_by(maxlen);
};
struct seq_oss_readq *snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen);
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
index 307ef98c44c7b..111c792bc72ca 100644
--- a/sound/core/seq/oss/seq_oss_rw.c
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -153,6 +153,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
{
int rc = 0;
struct snd_seq_event event;
+ snd_use_lock_t *lock = NULL;
/* if this is a timing event, process the current time */
if (snd_seq_oss_process_timer_event(dp->timer, rec))
@@ -164,7 +165,7 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
event.type = SNDRV_SEQ_EVENT_NOTEOFF;
snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
- if (snd_seq_oss_process_event(dp, rec, &event))
+ if (snd_seq_oss_process_event(dp, rec, &event, &lock))
return 0; /* invalid event - no need to insert queue */
event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
@@ -173,6 +174,8 @@ insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
else
rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
!is_nonblock_mode(dp->file_mode));
+ if (lock)
+ snd_use_lock_free(lock);
return rc;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 5719637575a91..19d6fea012f6a 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1287,7 +1287,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
port_idx = -1;
if (port_idx >= SNDRV_SEQ_ADDRESS_UNKNOWN)
return -EINVAL;
- err = snd_seq_create_port(client, port_idx, &port);
+ err = snd_seq_create_port(client, &port);
if (err < 0)
return err;
@@ -1309,6 +1309,11 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
info->addr = port->addr;
snd_seq_set_port_info(port, info);
+ err = snd_seq_insert_port(client, port_idx, port);
+ if (err < 0) {
+ kfree(port);
+ return err;
+ }
if (info->capability & SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT)
client->ump_endpoint_port = port->addr.port;
snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
index af45f328ae990..3fe0853aace34 100644
--- a/sound/core/seq/seq_dummy.c
+++ b/sound/core/seq/seq_dummy.c
@@ -71,7 +71,7 @@ struct snd_seq_dummy_port {
int connect;
};
-static int my_client = -1;
+static int my_client __ro_after_init = -1;
/*
* event input callback - just redirect events to subscribers
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index ca3f5fc309927..2eb12199c92f9 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -24,6 +24,7 @@ Possible options for midisynth module:
#include <sound/seq_device.h>
#include <sound/seq_midi_event.h>
#include <sound/initval.h>
+#include "seq_lock.h"
MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
@@ -42,6 +43,8 @@ struct seq_midisynth {
int device;
int subdevice;
struct snd_rawmidi_file input_rfile;
+ spinlock_t output_lock; /* protects output_rfile publication */
+ snd_use_lock_t output_use_lock; /* in-flight event_input users */
struct snd_rawmidi_file output_rfile;
int seq_client;
int seq_port;
@@ -125,31 +128,42 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
struct seq_midisynth *msynth = private_data;
unsigned char msg[10]; /* buffer for constructing midi messages */
struct snd_rawmidi_substream *substream;
+ int err = 0;
int len;
if (snd_BUG_ON(!msynth))
return -EINVAL;
- substream = msynth->output_rfile.output;
- if (substream == NULL)
- return -ENODEV;
+
+ scoped_guard(spinlock_irqsave, &msynth->output_lock) {
+ substream = msynth->output_rfile.output;
+ if (!substream)
+ return -ENODEV;
+ snd_use_lock_use(&msynth->output_use_lock);
+ }
+
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
/* invalid event */
pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
- return 0;
+ goto out;
}
snd_seq_dump_var_event(ev, __dump_midi, substream);
snd_midi_event_reset_decode(msynth->parser);
} else {
- if (msynth->parser == NULL)
- return -EIO;
+ if (!msynth->parser) {
+ err = -EIO;
+ goto out;
+ }
len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
if (len < 0)
- return 0;
+ goto out;
if (dump_midi(substream, msg, len) < 0)
snd_midi_event_reset_decode(msynth->parser);
}
- return 0;
+
+out:
+ snd_use_lock_free(&msynth->output_use_lock);
+ return err;
}
@@ -163,6 +177,8 @@ static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
msynth->card = card;
msynth->device = device;
msynth->subdevice = subdevice;
+ spin_lock_init(&msynth->output_lock);
+ snd_use_lock_init(&msynth->output_use_lock);
return 0;
}
@@ -215,12 +231,13 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
{
int err;
struct seq_midisynth *msynth = private_data;
+ struct snd_rawmidi_file rfile = {};
struct snd_rawmidi_params params;
/* open midi port */
err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
- &msynth->output_rfile);
+ &rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
@@ -229,12 +246,14 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
params.avail_min = 1;
params.buffer_size = output_buffer_size;
params.no_active_sensing = 1;
- err = snd_rawmidi_output_params(msynth->output_rfile.output, &params);
+ err = snd_rawmidi_output_params(rfile.output, &params);
if (err < 0) {
- snd_rawmidi_kernel_release(&msynth->output_rfile);
+ snd_rawmidi_kernel_release(&rfile);
return err;
}
snd_midi_event_reset_decode(msynth->parser);
+ scoped_guard(spinlock_irqsave, &msynth->output_lock)
+ msynth->output_rfile = rfile;
return 0;
}
@@ -242,11 +261,19 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
struct seq_midisynth *msynth = private_data;
+ struct snd_rawmidi_file rfile = {};
- if (snd_BUG_ON(!msynth->output_rfile.output))
+ scoped_guard(spinlock_irqsave, &msynth->output_lock) {
+ rfile = msynth->output_rfile;
+ msynth->output_rfile = (struct snd_rawmidi_file){};
+ }
+
+ if (snd_BUG_ON(!rfile.output))
return -EINVAL;
- snd_rawmidi_drain_output(msynth->output_rfile.output);
- return snd_rawmidi_kernel_release(&msynth->output_rfile);
+
+ snd_use_lock_sync(&msynth->output_use_lock);
+ snd_rawmidi_drain_output(rfile.output);
+ return snd_rawmidi_kernel_release(&rfile);
}
/* delete given midi synth port */
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index fd067c85c524f..a90ebc7b3811b 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -81,9 +81,6 @@ snd_midi_process_event(const struct snd_midi_op *ops,
pr_debug("ALSA: seq_midi_emul: ev or chanbase NULL (snd_midi_process_event)\n");
return;
}
- if (chanset->channels == NULL)
- return;
-
if (snd_seq_ev_is_channel_type(ev)) {
dest_channel = ev->data.note.channel;
if (dest_channel >= chanset->max_channels) {
@@ -643,23 +640,6 @@ static void snd_midi_channel_init(struct snd_midi_channel *p, int n)
}
/*
- * Allocate and initialise a set of midi channel control blocks.
- */
-static struct snd_midi_channel *snd_midi_channel_init_set(int n)
-{
- struct snd_midi_channel *chan;
- int i;
-
- chan = kmalloc_objs(struct snd_midi_channel, n);
- if (chan) {
- for (i = 0; i < n; i++)
- snd_midi_channel_init(chan+i, i);
- }
-
- return chan;
-}
-
-/*
* reset all midi channels
*/
static void
@@ -687,13 +667,18 @@ reset_all_channels(struct snd_midi_channel_set *chset)
struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n)
{
struct snd_midi_channel_set *chset;
+ int i;
+
+ chset = kmalloc_flex(*chset, channels, n);
+ if (!chset)
+ return NULL;
+
+ chset->max_channels = n;
+ chset->private_data = NULL;
+
+ for (i = 0; i < n; i++)
+ snd_midi_channel_init(&chset->channels[i], i);
- chset = kmalloc_obj(*chset);
- if (chset) {
- chset->channels = snd_midi_channel_init_set(n);
- chset->private_data = NULL;
- chset->max_channels = n;
- }
return chset;
}
EXPORT_SYMBOL(snd_midi_channel_alloc_set);
@@ -717,7 +702,6 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)
{
if (chset == NULL)
return;
- kfree(chset->channels);
kfree(chset);
}
EXPORT_SYMBOL(snd_midi_channel_free_set);
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 31ab4681c6012..17daacd4476aa 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -108,14 +108,13 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
}
-/* create a port, port number or a negative error code is returned
+/* create a port, 0 on success or a negative error code is returned
* the caller needs to unref the port via snd_seq_port_unlock() appropriately
*/
-int snd_seq_create_port(struct snd_seq_client *client, int port,
+int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret)
{
- struct snd_seq_client_port *new_port, *p;
- int num;
+ struct snd_seq_client_port *new_port;
*port_ret = NULL;
@@ -141,15 +140,25 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
port_subs_info_init(&new_port->c_dest);
snd_use_lock_use(&new_port->use_lock);
+ *port_ret = new_port;
+
+ return 0;
+}
+
+/* insert the port; return the port address or a negative error code */
+int snd_seq_insert_port(struct snd_seq_client *client, int port,
+ struct snd_seq_client_port *new_port)
+{
+ struct snd_seq_client_port *p;
+ int num;
+
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
- if (p->addr.port == port) {
- kfree(new_port);
+ if (p->addr.port == port)
return -EBUSY;
- }
if (p->addr.port > num) {
insert_before = &p->list;
break;
@@ -162,7 +171,6 @@ int snd_seq_create_port(struct snd_seq_client *client, int port,
client->num_ports++;
new_port->addr.port = num; /* store the port number in the port */
sprintf(new_port->name, "port-%d", num);
- *port_ret = new_port;
return num;
}
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index 40ed6cf7cb90b..b689c0f4867c4 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -98,10 +98,14 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
DEFINE_FREE(snd_seq_port, struct snd_seq_client_port *, if (!IS_ERR_OR_NULL(_T)) snd_seq_port_unlock(_T))
-/* create a port, port number or a negative error code is returned */
-int snd_seq_create_port(struct snd_seq_client *client, int port_index,
+/* create a port, 0 on success or a negative error code is returned */
+int snd_seq_create_port(struct snd_seq_client *client,
struct snd_seq_client_port **port_ret);
+/* insert the port; return the port address or a negative error code */
+int snd_seq_insert_port(struct snd_seq_client *client, int port,
+ struct snd_seq_client_port *new_port);
+
/* delete a port */
int snd_seq_delete_port(struct snd_seq_client *client, int port);
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 25c0ed8f9f0f8..d5bad1c585f64 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -132,7 +132,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
struct snd_seq_event_cell * cell)
{
struct snd_seq_event_cell *cur, *prev;
- int count;
+ int remaining;
int prior;
if (snd_BUG_ON(!f || !cell))
@@ -162,10 +162,16 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
prev = NULL; /* previous cell */
cur = f->head; /* cursor */
- count = 10000; /* FIXME: enough big, isn't it? */
+ remaining = f->cells;
while (cur != NULL) {
/* compare timestamps */
int rel = compare_timestamp_rel(&cell->event, &cur->event);
+
+ if (remaining-- <= 0) {
+ pr_err("ALSA: seq: inconsistent prioq cell count\n");
+ return -EINVAL;
+ }
+
if (rel < 0)
/* new cell has earlier schedule time, */
break;
@@ -176,10 +182,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
/* move cursor to next cell */
prev = cur;
cur = cur->next;
- if (! --count) {
- pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n");
- return -EINVAL;
- }
}
/* insert it before cursor */
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index d3f9424088d4f..b615a310c79ae 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -46,7 +46,7 @@ module_param_array(uart_enter, bool, NULL, 0444);
MODULE_PARM_DESC(uart_enter, "Issue UART_ENTER command at open.");
static struct platform_device *platform_devices[SNDRV_CARDS];
-static int pnp_registered;
+static int pnp_registered __ro_after_init;
static unsigned int snd_mpu401_devices;
static int snd_mpu401_create(struct device *devptr, int dev,
diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c
index 7f93557b51eca..5d5281e4deb7c 100644
--- a/sound/drivers/pcmtest.c
+++ b/sound/drivers/pcmtest.c
@@ -113,7 +113,7 @@ struct pcmtst_buf_iter {
struct timer_list timer_instance;
};
-static struct snd_pcm_hardware snd_pcmtst_hw = {
+static struct snd_pcm_hardware snd_pcmtst_hw __ro_after_init = {
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_NONINTERLEAVED |
@@ -137,7 +137,7 @@ struct pattern_buf {
u32 len;
};
-static int buf_allocated;
+static int buf_allocated __ro_after_init;
static struct pattern_buf patt_bufs[MAX_CHANNELS_NUM];
static inline void inc_buf_pos(struct pcmtst_buf_iter *v_iter, size_t by, size_t bytes)
diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
index addbc94243365..dcf340e5a0c1a 100644
--- a/sound/hda/codecs/Kconfig
+++ b/sound/hda/codecs/Kconfig
@@ -69,6 +69,7 @@ comment "Set to Y if you want auto-loading the codec driver"
config SND_HDA_CODEC_CA0132
tristate "Build Creative CA0132 codec support"
+ select SND_HDA_GENERIC
help
Say Y or M here to include Creative CA0132 codec support in
snd-hda-intel driver.
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
index be565ffaade0a..3fe11983d6ca1 100644
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -24,6 +24,7 @@
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
+#include "generic.h"
#include "ca0132_regs.h"
@@ -1060,6 +1061,8 @@ enum dsp_download_state {
*/
struct ca0132_spec {
+ struct hda_gen_spec gen;
+
const struct snd_kcontrol_new *mixers[5];
unsigned int num_mixers;
const struct hda_verb *base_init_verbs;
@@ -1174,6 +1177,7 @@ enum {
QUIRK_R3D,
QUIRK_AE5,
QUIRK_AE7,
+ QUIRK_GENERIC,
QUIRK_NONE = HDA_FIXUP_ID_NOT_SET,
};
@@ -1292,6 +1296,20 @@ static const struct hda_pintbl ae7_pincfgs[] = {
{}
};
+static const struct hda_pintbl ca0132_generic_pincfgs[] = {
+ { 0x0b, 0x41014111 },
+ { 0x0c, 0x414520f0 }, /* SPDIF out */
+ { 0x0d, 0x01014010 }, /* lineout */
+ { 0x0e, 0x41c501f0 },
+ { 0x0f, 0x411111f0 }, /* disabled */
+ { 0x10, 0x411111f0 }, /* disabled */
+ { 0x11, 0x41012014 },
+ { 0x12, 0x37a790f0 }, /* mic */
+ { 0x13, 0x77a701f0 },
+ { 0x18, 0x500000f0 },
+ {}
+};
+
static const struct hda_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4),
SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
@@ -1304,6 +1322,7 @@ static const struct hda_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x1458, 0xA046, "Gigabyte GA-Z170X-Gaming G1", QUIRK_GENERIC),
SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
SND_PCI_QUIRK(0x3842, 0x104b, "EVGA X299 Dark", QUIRK_R3DI),
SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI),
@@ -1325,6 +1344,7 @@ static const struct hda_model_fixup ca0132_quirk_models[] = {
{ .id = QUIRK_R3D, .name = "r3d" },
{ .id = QUIRK_AE5, .name = "ae5" },
{ .id = QUIRK_AE7, .name = "ae7" },
+ { .id = QUIRK_GENERIC, .name = "generic" },
{}
};
@@ -9897,14 +9917,57 @@ static void sbz_detect_quirk(struct hda_codec *codec)
}
}
+static void ca0132_generic_init_hook(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+
+ snd_hda_sequence_write(codec, spec->spec_init_verbs);
+}
+
+static int ca0132_generic_probe(struct hda_codec *codec)
+{
+ struct ca0132_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+ int err;
+
+ snd_hda_gen_spec_init(&spec->gen);
+
+ snd_hda_apply_pincfgs(codec, ca0132_generic_pincfgs);
+
+ ca0132_init_chip(codec);
+
+ err = ca0132_prepare_verbs(codec);
+ if (err < 0)
+ return err;
+
+ err = snd_hda_parse_pin_def_config(codec, cfg, NULL);
+ if (err < 0)
+ return err;
+ err = snd_hda_gen_parse_auto_config(codec, cfg);
+ if (err < 0)
+ return err;
+
+ spec->gen.init_hook = ca0132_generic_init_hook;
+ spec->gen.automute_speaker = 0;
+ spec->gen.automute_lo = 0;
+
+ snd_hda_sequence_write(codec, spec->spec_init_verbs);
+ return 0;
+}
+
static void ca0132_codec_remove(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ switch (ca0132_quirk(spec)) {
+ case QUIRK_GENERIC:
+ snd_hda_gen_remove(codec);
+ return;
+ case QUIRK_ZXR_DBPRO:
return dbpro_free(codec);
- else
+ default:
return ca0132_free(codec);
+ }
}
static int ca0132_codec_probe(struct hda_codec *codec,
@@ -9921,14 +9984,21 @@ static int ca0132_codec_probe(struct hda_codec *codec,
codec->spec = spec;
spec->codec = codec;
- /* Detect codec quirk */
- snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL);
- if (ca0132_quirk(spec) == QUIRK_SBZ)
- sbz_detect_quirk(codec);
-
+ /* These must be set before any path is taken */
codec->pcm_format_first = 1;
codec->no_sticky_stream = 1;
+ /* Detect codec quirk */
+ snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL);
+ switch (ca0132_quirk(spec)) {
+ case QUIRK_SBZ:
+ sbz_detect_quirk(codec);
+ break;
+ case QUIRK_GENERIC:
+ return ca0132_generic_probe(codec);
+ default:
+ break;
+ }
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->num_mixers = 1;
@@ -10029,36 +10099,51 @@ static int ca0132_codec_build_controls(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ switch (ca0132_quirk(spec)) {
+ case QUIRK_GENERIC:
+ return snd_hda_gen_build_controls(codec);
+ case QUIRK_ZXR_DBPRO:
return dbpro_build_controls(codec);
- else
+ default:
return ca0132_build_controls(codec);
+ }
}
static int ca0132_codec_build_pcms(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ switch (ca0132_quirk(spec)) {
+ case QUIRK_GENERIC:
+ return snd_hda_gen_build_pcms(codec);
+ case QUIRK_ZXR_DBPRO:
return dbpro_build_pcms(codec);
- else
+ default:
return ca0132_build_pcms(codec);
+ }
}
static int ca0132_codec_init(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+ switch (ca0132_quirk(spec)) {
+ case QUIRK_GENERIC:
+ return snd_hda_gen_init(codec);
+ case QUIRK_ZXR_DBPRO:
return dbpro_init(codec);
- else
+ default:
return ca0132_init(codec);
+ }
}
static int ca0132_codec_suspend(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
+ if (ca0132_quirk(spec) == QUIRK_GENERIC)
+ return 0;
+
cancel_delayed_work_sync(&spec->unsol_hp_work);
return 0;
}
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
index f20d1715da62c..423cd9f683c62 100644
--- a/sound/hda/codecs/hdmi/hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -2285,6 +2285,7 @@ EXPORT_SYMBOL_NS_GPL(snd_hda_hdmi_acomp_init, "SND_HDA_CODEC_HDMI");
enum {
MODEL_GENERIC,
MODEL_GF,
+ MODEL_LOONGSON,
};
static int generichdmi_probe(struct hda_codec *codec,
@@ -2302,6 +2303,11 @@ static int generichdmi_probe(struct hda_codec *codec,
if (id->driver_data == MODEL_GF)
codec->no_sticky_stream = 1;
+ if (id->driver_data == MODEL_LOONGSON) {
+ if (codec->bus && codec->bus->pci->revision == 0x2)
+ codec->eld_jack_detect = 1; /* Jack-detection by ELD */
+ }
+
return 0;
}
@@ -2319,7 +2325,7 @@ static const struct hda_codec_ops generichdmi_codec_ops = {
/*
*/
static const struct hda_device_id snd_hda_id_generichdmi[] = {
- HDA_CODEC_ID_MODEL(0x00147a47, "Loongson HDMI", MODEL_GENERIC),
+ HDA_CODEC_ID_MODEL(0x00147a47, "Loongson HDMI", MODEL_LOONGSON),
HDA_CODEC_ID_MODEL(0x10951390, "SiI1390 HDMI", MODEL_GENERIC),
HDA_CODEC_ID_MODEL(0x10951392, "SiI1392 HDMI", MODEL_GENERIC),
HDA_CODEC_ID_MODEL(0x11069f84, "VX11 HDMI/DP", MODEL_GENERIC),
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index dcbc669842e05..9f378a32523b0 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -3338,6 +3338,18 @@ static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
}
+static void alc287_fixup_acer_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ alc_fixup_hp_gpio_led(codec, action, 0, 0x10);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->micmute_led_polarity = 1;
+ spec->gpio_mask |= 0x10;
+ spec->gpio_dir |= 0x10;
+ }
+}
/* for alc295_fixup_hp_top_speakers */
#include "../helpers/hp_x360.c"
@@ -4076,6 +4088,7 @@ enum {
ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
ALC298_FIXUP_LENOVO_C940_DUET7,
ALC287_FIXUP_LENOVO_YOGA_BOOK_9I,
+ ALC287_FIXUP_LENOVO_YOGA_PRO7,
ALC287_FIXUP_13S_GEN2_SPEAKERS,
ALC256_FIXUP_SET_COEF_DEFAULTS,
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
@@ -4155,6 +4168,7 @@ enum {
ALC236_FIXUP_HP_DMIC,
ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO,
ALC245_FIXUP_HP_ENVY_X360_15_FH0XXX,
+ ALC287_FIXUP_ACER_MICMUTE_LED,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -6101,6 +6115,13 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
},
+ [ALC287_FIXUP_LENOVO_YOGA_PRO7] = {
+ .type = HDA_FIXUP_FUNC,
+ /* Reuse the DAC routing selected for ThinkPad X1 Gen7 */
+ .v.func = alc285_fixup_thinkpad_x1_gen7,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LENOVO_XPAD_ACPI,
+ },
[ALC623_FIXUP_LENOVO_THINKSTATION_P340] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_no_shutup,
@@ -6727,7 +6748,13 @@ static const struct hda_fixup alc269_fixups[] = {
.v.func = cs35l41_fixup_i2c_two,
.chained = true,
.chain_id = ALC245_FIXUP_HP_X360_MUTE_LEDS
- }
+ },
+ [ALC287_FIXUP_ACER_MICMUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_acer_micmute_led,
+ .chained = true,
+ .chain_id = ALC2XX_FIXUP_HEADSET_MIC,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -6777,7 +6804,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1539, "Acer Nitro 5 AN515-57", ALC2XX_FIXUP_HEADSET_MIC),
- SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC287_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
@@ -7769,7 +7796,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
- SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC245_FIXUP_BASS_HP_DAC),
+ SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC287_FIXUP_LENOVO_YOGA_PRO7),
SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index e51964c0a0916..2a2e8804bf9e4 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -28,6 +28,7 @@ config SND_HDA_SCODEC_CS35L41_I2C
depends on ACPI
depends on EFI
depends on SND_SOC
+ imply SERIAL_MULTI_INSTANTIATE
select SND_SOC_CS35L41_LIB
select SND_HDA_SCODEC_CS35L41
select SND_SOC_CS_AMP_LIB
@@ -44,6 +45,7 @@ config SND_HDA_SCODEC_CS35L41_SPI
depends on ACPI
depends on EFI
depends on SND_SOC
+ imply SERIAL_MULTI_INSTANTIATE
select SND_SOC_CS35L41_LIB
select SND_HDA_SCODEC_CS35L41
select SND_SOC_CS_AMP_LIB
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index acfccc848f82d..64a5bd895fd1e 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -1325,6 +1325,43 @@ static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ct
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l41_hda_fw_ids);
}
+static void cs35l41_remove_controls(struct cs35l41_hda *cs35l41)
+{
+ if (!cs35l41->codec)
+ return;
+
+ snd_ctl_remove(cs35l41->codec->card, cs35l41->mute_override_ctl);
+ cs35l41->mute_override_ctl = NULL;
+
+ snd_ctl_remove(cs35l41->codec->card, cs35l41->fw_load_ctl);
+ cs35l41->fw_load_ctl = NULL;
+
+ snd_ctl_remove(cs35l41->codec->card, cs35l41->fw_type_ctl);
+ cs35l41->fw_type_ctl = NULL;
+}
+
+static int cs35l41_add_control(struct cs35l41_hda *cs35l41,
+ struct snd_kcontrol_new *ctl,
+ struct snd_kcontrol **kctl)
+{
+ int ret;
+
+ *kctl = snd_ctl_new1(ctl, cs35l41);
+ if (!*kctl)
+ return -ENOMEM;
+
+ ret = snd_ctl_add(cs35l41->codec->card, *kctl);
+ if (ret) {
+ dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", ctl->name, ret);
+ *kctl = NULL;
+ return ret;
+ }
+
+ dev_dbg(cs35l41->dev, "Added Control %s\n", ctl->name);
+
+ return 0;
+}
+
static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
{
char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
@@ -1360,32 +1397,23 @@ static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
scnprintf(mute_override_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s Forced Mute Status",
cs35l41->amp_name);
- ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
- if (ret) {
- dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret);
- return ret;
- }
-
- dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name);
-
- ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41));
- if (ret) {
- dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret);
- return ret;
- }
-
- dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
+ ret = cs35l41_add_control(cs35l41, &fw_type_ctl, &cs35l41->fw_type_ctl);
+ if (ret)
+ goto err;
- ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&mute_override_ctl, cs35l41));
- if (ret) {
- dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", mute_override_ctl.name,
- ret);
- return ret;
- }
+ ret = cs35l41_add_control(cs35l41, &fw_load_ctl, &cs35l41->fw_load_ctl);
+ if (ret)
+ goto err;
- dev_dbg(cs35l41->dev, "Added Control %s\n", mute_override_ctl.name);
+ ret = cs35l41_add_control(cs35l41, &mute_override_ctl, &cs35l41->mute_override_ctl);
+ if (ret)
+ goto err;
return 0;
+
+err:
+ cs35l41_remove_controls(cs35l41);
+ return ret;
}
static bool cs35l41_dsm_supported(acpi_handle handle, unsigned int commands)
@@ -1522,6 +1550,10 @@ static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *
device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
unlock_system_sleep(sleep_flags);
memset(comp, 0, sizeof(*comp));
+
+ cs35l41_remove_controls(cs35l41);
+ cancel_work_sync(&cs35l41->fw_load_work);
+ cs35l41->codec = NULL;
}
}
@@ -2060,6 +2092,7 @@ void cs35l41_hda_remove(struct device *dev)
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
+ cancel_work_sync(&cs35l41->fw_load_work);
pm_runtime_get_sync(cs35l41->dev);
pm_runtime_dont_use_autosuspend(cs35l41->dev);
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.h b/sound/hda/codecs/side-codecs/cs35l41_hda.h
index 7d003c598e93e..56ec07c0bb745 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.h
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.h
@@ -57,6 +57,8 @@ enum control_bus {
SPI
};
+struct snd_kcontrol;
+
struct cs35l41_hda {
struct device *dev;
struct regmap *regmap;
@@ -75,6 +77,9 @@ struct cs35l41_hda {
int speaker_id;
struct mutex fw_mutex;
struct work_struct fw_load_work;
+ struct snd_kcontrol *fw_type_ctl;
+ struct snd_kcontrol *fw_load_ctl;
+ struct snd_kcontrol *mute_override_ctl;
struct regmap_irq_chip_data *irq_data;
bool firmware_running;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index 67240ce184e1a..dd1b0cc63ad6c 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -588,6 +588,9 @@ static void tas2781_hda_unbind(struct device *dev,
comp->playback_hook = NULL;
}
+ request_firmware_nowait_cancel(tas_hda->priv->dev, tas_hda->priv,
+ tasdev_fw_ready);
+
tas2781_hda_remove_controls(tas_hda);
tasdevice_config_info_remove(tas_hda->priv);
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index 0e4f3553f2738..d243baff95a72 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -750,6 +750,9 @@ static void tas2781_hda_unbind(struct device *dev, struct device *master,
comp->playback_hook = NULL;
}
+ request_firmware_nowait_cancel(tas_priv->dev, tas_priv,
+ tasdev_fw_ready);
+
tas2781_hda_remove_controls(tas_hda);
tasdevice_config_info_remove(tas_priv);
diff --git a/sound/hda/common/jack.c b/sound/hda/common/jack.c
index 98ba1c4d5ba4f..e0a5cc38540ba 100644
--- a/sound/hda/common/jack.c
+++ b/sound/hda/common/jack.c
@@ -58,6 +58,12 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id)
AC_VERB_GET_PIN_SENSE, dev_id);
if (codec->inv_jack_detect)
val ^= AC_PINSENSE_PRESENCE;
+ if (codec->eld_jack_detect) {
+ if (val & AC_PINSENSE_ELDV)
+ val |= AC_PINSENSE_PRESENCE;
+ else
+ val &= ~AC_PINSENSE_PRESENCE;
+ }
return val;
}
diff --git a/sound/hda/core/i915.c b/sound/hda/core/i915.c
index 44438c799f957..6c068b135b7dc 100644
--- a/sound/hda/core/i915.c
+++ b/sound/hda/core/i915.c
@@ -130,22 +130,22 @@ static int i915_gfx_present(struct pci_dev *hdac_pci)
/* List of known platforms with no i915 support. */
static const struct pci_device_id denylist[] = {
/* CNL */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), 0x030000, 0xff0000 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), .class = 0x030000, .class_mask = 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), .class = 0x030000, .class_mask = 0xff0000 },
/* LKF */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), 0x030000, 0xff0000 },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), .class = 0x030000, .class_mask = 0xff0000 },
{}
};
struct pci_dev *display_dev = NULL;
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 3d1f19321b9e9..ecff521957cb3 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -103,8 +103,8 @@ MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330/CMI8329 driver.");
module_param_hw_array(mpuirq, int, irq, NULL, 0444);
MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330/CMI8329 MPU-401 port.");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
#endif
#define CMI8330_RMUX3D 16
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index e36cc147651a4..238065ffa1d26 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -69,9 +69,9 @@ module_param_hw_array(dma2, int, dma, NULL, 0444);
MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnpc_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnpc_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
#endif /* CONFIG_PNP */
struct snd_card_cs4236 {
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 1da7b400a17b6..df88d91e0fb20 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -1924,9 +1924,9 @@ module_param_hw_array(dma2, int, dma, NULL, 0444);
MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
-static int pnpc_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
+static int pnpc_registered __ro_after_init;
static const struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
{ .id = "ESS1869" },
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index a0757e1ede465..08ccb4d80adeb 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -851,6 +851,8 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);
else
kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.index = control_index;
err = snd_ctl_add(card, kctl);
if (err < 0)
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 6c3a2977dcb3f..115f900fa0638 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -111,8 +111,8 @@ struct snd_interwave {
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
static const struct pnp_card_device_id snd_interwave_pnpids[] = {
#ifndef SNDRV_STB
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 5b729bb02ef62..0d5f4461a7bc8 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -1199,8 +1199,8 @@ static int snd_msnd_pnp_resume(struct pnp_card_link *pcard)
}
#endif
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
static const struct pnp_card_device_id msnd_pnpids[] = {
/* Pinnacle PnP */
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 8c1767697b625..88eada933a1f9 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -69,9 +69,9 @@ module_param_array(opl3sa3_ymode, int, NULL, 0444);
MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi.");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
-static int pnpc_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
+static int pnpc_registered __ro_after_init;
#endif
/* control ports */
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c320af3e9a05c..e5870e5e07db8 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/sb/sb16.c b/sound/isa/sb/sb16.c
index 208d1942a015a..866d7f5c58a01 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -99,8 +99,8 @@ MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
#endif
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
#endif
struct snd_card_sb16 {
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 553ceb92d2989..ce8a59650e383 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -71,8 +71,8 @@ module_param_array(joystick, bool, NULL, 0444);
MODULE_PARM_DESC(joystick, "Enable gameport.");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
static const struct pnp_card_device_id sscape_pnpids[] = {
{ .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 07c68568091d1..5b1917cc19ce4 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -71,8 +71,8 @@ module_param_array(use_cs4232_midi, bool, NULL, 0444);
MODULE_PARM_DESC(use_cs4232_midi, "Use CS4232 MPU-401 interface (inaccessibly located inside your computer)");
#ifdef CONFIG_PNP
-static int isa_registered;
-static int pnp_registered;
+static int isa_registered __ro_after_init;
+static int pnp_registered __ro_after_init;
static const struct pnp_card_device_id snd_wavefront_pnpids[] = {
/* Tropez */
@@ -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 69d87c4cafaed..fb184d9ef284a 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 33b563707a58d..2f57a6795d22b 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 a718b75bb6a09..e80f730d08038 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/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 571d89a6a8da2..f07c5f4c23801 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -247,8 +247,8 @@ struct snd_ali {
};
static const struct pci_device_id snd_ali_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0},
- {0, }
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_ali_ids);
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index a73893a2cbd66..00f0720169c3a 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -127,9 +127,9 @@ struct snd_als300_substream_data {
};
static const struct pci_device_id snd_als300_ids[] = {
- { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 },
- { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS },
- { 0, }
+ { PCI_DEVICE(0x4005, 0x0300), .driver_data = DEVICE_ALS300 },
+ { PCI_DEVICE(0x4005, 0x0308), .driver_data = DEVICE_ALS300_PLUS },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_als300_ids);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 636f309c94240..6396aa6c3bf07 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -102,8 +102,8 @@ struct snd_card_als4000 {
};
static const struct pci_device_id snd_als4000_ids[] = {
- { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */
- { 0, }
+ { PCI_DEVICE(0x4005, 0x4000) }, /* ALS4000 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_als4000_ids);
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index b1c7ed7f1604e..4dbc79899c091 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -2933,13 +2933,16 @@ static void snd_asihpi_remove(struct pci_dev *pci_dev)
}
static const struct pci_device_id asihpi_pci_tbl[] = {
- {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
- HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
- (kernel_ulong_t)HPI_6205},
- {HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
- HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
- (kernel_ulong_t)HPI_6000},
- {0,}
+ {
+ PCI_DEVICE_SUB(HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
+ HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID),
+ .driver_data = (kernel_ulong_t)HPI_6205,
+ }, {
+ PCI_DEVICE_SUB(HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
+ HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID),
+ .driver_data = (kernel_ulong_t)HPI_6000,
+ },
+ {}
};
MODULE_DEVICE_TABLE(pci, asihpi_pci_tbl);
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index 19f0da2e65014..5f69c04c672aa 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -647,17 +647,12 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
const u32 size_in_bytes, u8 *p_dsp_control_buffer)
{
- struct hpi_control_cache *p_cache = kmalloc_obj(*p_cache);
+ struct hpi_control_cache *p_cache;
+
+ p_cache = kzalloc_flex(*p_cache, p_info, control_count);
if (!p_cache)
return NULL;
- p_cache->p_info =
- kzalloc_objs(*p_cache->p_info, control_count);
- if (!p_cache->p_info) {
- kfree(p_cache);
- return NULL;
- }
-
p_cache->cache_size_in_bytes = size_in_bytes;
p_cache->control_count = control_count;
p_cache->p_cache = p_dsp_control_buffer;
@@ -667,10 +662,7 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
void hpi_free_control_cache(struct hpi_control_cache *p_cache)
{
- if (p_cache) {
- kfree(p_cache->p_info);
- kfree(p_cache);
- }
+ kfree(p_cache);
}
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h
index 8ec656cf8848c..40af7329587a1 100644
--- a/sound/pci/asihpi/hpicmn.h
+++ b/sound/pci/asihpi/hpicmn.h
@@ -37,10 +37,10 @@ struct hpi_control_cache {
u16 adap_idx;
u32 control_count;
u32 cache_size_in_bytes;
- /** pointer to allocated memory of lookup pointers. */
- struct hpi_control_cache_info **p_info;
/** pointer to DSP's control cache. */
u8 *p_cache;
+ /** pointer to allocated memory of lookup pointers. */
+ struct hpi_control_cache_info *p_info[] __counted_by(control_count);
};
struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index);
diff --git a/sound/pci/asihpi/hpipcida.h b/sound/pci/asihpi/hpipcida.h
index 0673e82780707..6dceff2b47419 100644
--- a/sound/pci/asihpi/hpipcida.h
+++ b/sound/pci/asihpi/hpipcida.h
@@ -15,12 +15,12 @@
*/
{
-HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
- HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
- (kernel_ulong_t) HPI_6205}
-, {
-HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
- HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID, 0, 0,
- (kernel_ulong_t) HPI_6000}
-, {
-0}
+ PCI_DEVICE_SUB(HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_DSP6205,
+ HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID),
+ .driver_data = (kernel_ulong_t) HPI_6205,
+}, {
+ PCI_DEVICE_SUB(HPI_PCI_VENDOR_ID_TI, HPI_PCI_DEV_ID_PCI2040,
+ HPI_PCI_VENDOR_ID_AUDIOSCIENCE, PCI_ANY_ID),
+ .driver_data = (kernel_ulong_t) HPI_6000,
+},
+{ }
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 2a0c59d5afa58..b738295b41e5d 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -272,11 +272,11 @@ struct atiixp {
/*
*/
static const struct pci_device_id snd_atiixp_ids[] = {
- { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */
- { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */
- { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */
- { PCI_VDEVICE(ATI, 0x4382), 0 }, /* SB600 */
- { 0, }
+ { PCI_VDEVICE(ATI, 0x4341) }, /* SB200 */
+ { PCI_VDEVICE(ATI, 0x4361) }, /* SB300 */
+ { PCI_VDEVICE(ATI, 0x4370) }, /* SB400 */
+ { PCI_VDEVICE(ATI, 0x4382) }, /* SB600 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 91f31e2ad3d3b..8aaeb197ce458 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -247,9 +247,9 @@ struct atiixp_modem {
/*
*/
static const struct pci_device_id snd_atiixp_ids[] = {
- { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */
- { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */
- { 0, }
+ { PCI_VDEVICE(ATI, 0x434d) }, /* SB200 */
+ { PCI_VDEVICE(ATI, 0x4378) }, /* SB400 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_atiixp_ids);
diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c
index b2bfa50bfe30e..f712e32d33700 100644
--- a/sound/pci/au88x0/au8810.c
+++ b/sound/pci/au88x0/au8810.c
@@ -2,8 +2,8 @@
#include "au8810.h"
#include "au88x0.h"
static const struct pci_device_id snd_vortex_ids[] = {
- {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
- {0,}
+ { PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), .driver_data = 1 },
+ { }
};
#include "au88x0_core.c"
diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c
index dbc2263b49c6e..aa841b615182c 100644
--- a/sound/pci/au88x0/au8820.c
+++ b/sound/pci/au88x0/au8820.c
@@ -2,8 +2,8 @@
#include "au8820.h"
#include "au88x0.h"
static const struct pci_device_id snd_vortex_ids[] = {
- {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
- {0,}
+ { PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), .driver_data = 0 },
+ { }
};
#include "au88x0_synth.c"
diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c
index e963c4e2f026c..aeb8d458c6299 100644
--- a/sound/pci/au88x0/au8830.c
+++ b/sound/pci/au88x0/au8830.c
@@ -2,8 +2,8 @@
#include "au8830.h"
#include "au88x0.h"
static const struct pci_device_id snd_vortex_ids[] = {
- {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
- {0,}
+ { PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), .driver_data = 0 },
+ { }
};
#include "au88x0_synth.c"
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index e2c501f4394c1..60a87322eae49 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -142,9 +142,8 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
static const struct pci_device_id snd_aw2_ids[] = {
- {PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
- 0, 0, 0},
- {0}
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 6cdf76e2b7d2e..ccca82417657b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -305,9 +305,9 @@ struct snd_azf3328 {
};
static const struct pci_device_id snd_azf3328_ids[] = {
- { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */
- { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */
- { 0, }
+ { PCI_DEVICE(0x122D, 0x50DC) }, /* PCI168/3328 */
+ { PCI_DEVICE(0x122D, 0x80DA) }, /* 3328 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 35392f6525b3b..cf923f551211e 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1820,8 +1820,8 @@ static SIMPLE_DEV_PM_OPS(snd_ca0106_pm, snd_ca0106_suspend, snd_ca0106_resume);
// PCI IDs
static const struct pci_device_id snd_ca0106_ids[] = {
- { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */
- { 0, }
+ { PCI_VDEVICE(CREATIVE, 0x0007) }, /* Audigy LS or Live 24bit */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index cd73b68336394..9d9f784e3a8c1 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -2637,16 +2637,22 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
}
if (cm->can_ac3_hw) {
kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = pcm_spdif_device;
err = snd_ctl_add(card, kctl);
if (err < 0)
@@ -2721,12 +2727,12 @@ static void snd_cmipci_proc_init(struct cmipci *cm)
}
static const struct pci_device_id snd_cmipci_ids[] = {
- {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0},
- {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0},
- {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
- {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B), 0},
- {PCI_VDEVICE(AL, PCI_DEVICE_ID_CMEDIA_CM8738), 0},
- {0,},
+ {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A) },
+ {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B) },
+ {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738) },
+ {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B) },
+ {PCI_VDEVICE(AL, PCI_DEVICE_ID_CMEDIA_CM8738) },
+ { }
};
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index d00b2c9fb1e38..f51f4bb637664 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -476,8 +476,8 @@ struct cs4281 {
static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
static const struct pci_device_id snd_cs4281_ids[] = {
- { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */
- { 0, }
+ { PCI_VDEVICE(CIRRUS, 0x6005) }, /* CS4281 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_cs4281_ids);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 9c1995737eb7f..0cb7c2a2929fe 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -43,10 +43,10 @@ module_param_array(mmap_valid, bool, NULL, 0444);
MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
static const struct pci_device_id snd_cs46xx_ids[] = {
- { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */
- { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */
- { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */
- { 0, }
+ { PCI_VDEVICE(CIRRUS, 0x6001) }, /* CS4280 */
+ { PCI_VDEVICE(CIRRUS, 0x6003) }, /* CS4612 */
+ { PCI_VDEVICE(CIRRUS, 0x6004) }, /* CS4615 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_cs46xx_ids);
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index e3ee76bd84824..9abe1d53c3c5e 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -221,10 +221,6 @@ ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
static void
ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
-/* FIXME: this static looks like it would fail if more than one card was */
-/* installed. */
-static struct snd_kcontrol *kctls[2] = {NULL};
-
static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
{
switch (alsa_index) {
@@ -481,17 +477,18 @@ static struct snd_kcontrol_new mic_source_ctl = {
static void
do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
{
+ struct ct_mixer *mixer = atc->mixer;
if (MIXER_LINEIN_C_S == type) {
atc->select_line_in(atc);
- set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
+ set_switch_state(mixer, MIXER_MIC_C_S, 0);
snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &kctls[1]->id);
+ &mixer->line_mic_kctls[1]->id);
} else if (MIXER_MIC_C_S == type) {
atc->select_mic_in(atc);
- set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
+ set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
- &kctls[0]->id);
+ &mixer->line_mic_kctls[0]->id);
}
}
@@ -778,9 +775,9 @@ ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
switch (new->private_value) {
case MIXER_LINEIN_C_S:
- kctls[0] = kctl; break;
+ mixer->line_mic_kctls[0] = kctl; break;
case MIXER_MIC_C_S:
- kctls[1] = kctl; break;
+ mixer->line_mic_kctls[1] = kctl; break;
default:
break;
}
@@ -965,35 +962,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 +1210,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 e812f6c93b41c..0c0963bba99c8 100644
--- a/sound/pci/ctxfi/ctmixer.h
+++ b/sound/pci/ctxfi/ctmixer.h
@@ -17,6 +17,8 @@
#include "ctatc.h"
#include "ctresource.h"
+struct snd_kcontrol;
+
#define INIT_VOL 0x1c00
enum MIXER_PORT_T {
@@ -41,8 +43,8 @@ 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 */
+ struct snd_kcontrol *line_mic_kctls[2]; /* line/mic capture switch controls */
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 +57,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/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
index 326997bb885df..46dc1f509234f 100644
--- a/sound/pci/ctxfi/ctsrc.c
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -668,13 +668,6 @@ static int srcimp_rsc_init(struct srcimp *srcimp,
if (err)
return err;
- /* Reserve memory for imapper nodes */
- srcimp->imappers = kzalloc_objs(struct imapper, desc->msr);
- if (!srcimp->imappers) {
- err = -ENOMEM;
- goto error1;
- }
-
/* Set srcimp specific operations */
srcimp->rsc.ops = &srcimp_basic_rsc_ops;
srcimp->ops = &srcimp_ops;
@@ -683,16 +676,10 @@ static int srcimp_rsc_init(struct srcimp *srcimp,
srcimp->rsc.ops->master(&srcimp->rsc);
return 0;
-
-error1:
- rsc_uninit(&srcimp->rsc);
- return err;
}
static int srcimp_rsc_uninit(struct srcimp *srcimp)
{
- kfree(srcimp->imappers);
- srcimp->imappers = NULL;
srcimp->ops = NULL;
srcimp->mgr = NULL;
rsc_uninit(&srcimp->rsc);
@@ -711,7 +698,7 @@ static int get_srcimp_rsc(struct srcimp_mgr *mgr,
*rsrcimp = NULL;
/* Allocate mem for SRCIMP resource */
- srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL);
+ srcimp = kzalloc_flex(*srcimp, imappers, desc->msr);
if (!srcimp)
return -ENOMEM;
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
index e6366cc6a7ae6..7ba94adde9208 100644
--- a/sound/pci/ctxfi/ctsrc.h
+++ b/sound/pci/ctxfi/ctsrc.h
@@ -103,10 +103,10 @@ struct srcimp_rsc_ops;
struct srcimp {
struct rsc rsc;
unsigned char idx[8];
- struct imapper *imappers;
unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */
struct srcimp_mgr *mgr;
const struct srcimp_rsc_ops *ops;
+ struct imapper imappers[];
};
struct srcimp_rsc_ops {
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
index e295c71c7a390..48c25bd3f401e 100644
--- a/sound/pci/echoaudio/darla20.c
+++ b/sound/pci/echoaudio/darla20.c
@@ -52,8 +52,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0010) }, /* DSP 56301 Darla20 rev.0 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
index ae816e78f5991..c8cdd1b052df6 100644
--- a/sound/pci/echoaudio/darla24.c
+++ b/sound/pci/echoaudio/darla24.c
@@ -56,9 +56,9 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */
- {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0040) }, /* DSP 56301 Darla24 rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0041) }, /* DSP 56301 Darla24 rev.1 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
index 3d37bb4030ec2..e8b476e073073 100644
--- a/sound/pci/echoaudio/echo3g.c
+++ b/sound/pci/echoaudio/echo3g.c
@@ -70,8 +70,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0100) }, /* Echo 3G */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
index 4f864ddc95309..b5f88922e19a2 100644
--- a/sound/pci/echoaudio/gina20.c
+++ b/sound/pci/echoaudio/gina20.c
@@ -56,8 +56,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0020) }, /* DSP 56301 Gina20 rev.0 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
index eff69e83ca0a1..fe0e510209ed3 100644
--- a/sound/pci/echoaudio/gina24.c
+++ b/sound/pci/echoaudio/gina24.c
@@ -74,11 +74,11 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */
- {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */
- {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */
- {0x1057, 0x3410, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56361 Gina24 rev.1 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0050) }, /* DSP 56301 Gina24 rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0051) }, /* DSP 56301 Gina24 rev.1 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0050) }, /* DSP 56361 Gina24 rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0051) }, /* DSP 56361 Gina24 rev.1 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
index a9f2efc58f6e0..496cc5aa9516d 100644
--- a/sound/pci/echoaudio/indigo.c
+++ b/sound/pci/echoaudio/indigo.c
@@ -57,8 +57,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0090) }, /* Indigo */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
index 14e9769ceba14..45ad92e8f5311 100644
--- a/sound/pci/echoaudio/indigodj.c
+++ b/sound/pci/echoaudio/indigodj.c
@@ -57,8 +57,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x00B0) }, /* Indigo DJ*/
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c
index a14a7dc8c87db..b1878ecb83753 100644
--- a/sound/pci/echoaudio/indigodjx.c
+++ b/sound/pci/echoaudio/indigodjx.c
@@ -57,8 +57,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x00E0) }, /* Indigo DJx*/
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
index 97e024450d19c..2c6a6f74b0bdc 100644
--- a/sound/pci/echoaudio/indigoio.c
+++ b/sound/pci/echoaudio/indigoio.c
@@ -58,8 +58,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x00A0) }, /* Indigo IO*/
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c
index a017c966b4dce..dfaa563317ad1 100644
--- a/sound/pci/echoaudio/indigoiox.c
+++ b/sound/pci/echoaudio/indigoiox.c
@@ -58,8 +58,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x00D0) }, /* Indigo IOx */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
index 7e38bc9c025d5..82c089f7b452b 100644
--- a/sound/pci/echoaudio/layla20.c
+++ b/sound/pci/echoaudio/layla20.c
@@ -65,9 +65,9 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */
- {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0030) }, /* DSP 56301 Layla20 rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0031) }, /* DSP 56301 Layla20 rev.1 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
index 95c52210fb654..efd676467a374 100644
--- a/sound/pci/echoaudio/layla24.c
+++ b/sound/pci/echoaudio/layla24.c
@@ -76,8 +76,8 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0060) }, /* DSP 56361 Layla24 rev.0 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
index a2d4b0003b570..950aaec74a439 100644
--- a/sound/pci/echoaudio/mia.c
+++ b/sound/pci/echoaudio/mia.c
@@ -66,9 +66,9 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */
- {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */
- {0,}
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0080) }, /* DSP 56361 Mia rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0081) }, /* DSP 56361 Mia rev.1 */
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
index 1b45a2b5066fe..4f999324f388d 100644
--- a/sound/pci/echoaudio/mona.c
+++ b/sound/pci/echoaudio/mona.c
@@ -81,13 +81,19 @@ static const struct firmware card_fw[] = {
};
static const struct pci_device_id snd_echo_ids[] = {
- {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */
- {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */
- {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */
- {0x1057, 0x3410, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56361 Mona rev.0 */
- {0x1057, 0x3410, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56361 Mona rev.1 */
- {0x1057, 0x3410, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56361 Mona rev.2 */
- {0,}
+ /* DSP 56301 Mona rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0070) },
+ /* DSP 56301 Mona rev.1 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0071) },
+ /* DSP 56301 Mona rev.2 */
+ { PCI_DEVICE_SUB(0x1057, 0x1801, 0xECC0, 0x0072) },
+ /* DSP 56361 Mona rev.0 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0070) },
+ /* DSP 56361 Mona rev.1 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0071) },
+ /* DSP 56361 Mona rev.2 */
+ { PCI_DEVICE_SUB(0x1057, 0x3410, 0xECC0, 0x0072) },
+ { }
};
static const struct snd_pcm_hardware pcm_hardware_skel = {
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 548e7d0499013..3b21bd2883b64 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -58,10 +58,10 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
* Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
*/
static const struct pci_device_id snd_emu10k1_ids[] = {
- { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */
- { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */
- { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */
- { 0, }
+ { PCI_VDEVICE(CREATIVE, 0x0002), .driver_data = 0 }, /* EMU10K1 */
+ { PCI_VDEVICE(CREATIVE, 0x0004), .driver_data = 1 }, /* Audigy */
+ { PCI_VDEVICE(CREATIVE, 0x0008), .driver_data = 1 }, /* Audigy 2 Value SB0400 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 1b207ca25814e..ed4630c8342b4 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1518,8 +1518,8 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
// PCI IDs
static const struct pci_device_id snd_emu10k1x_ids[] = {
- { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */
- { 0, }
+ { PCI_VDEVICE(CREATIVE, 0x0006) }, /* Dell OEM version (EMU10K1) */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 657056a59175b..0b9eb55a21218 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -426,14 +426,14 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
static const struct pci_device_id snd_audiopci_ids[] = {
#ifdef CHIP1370
- { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */
+ { PCI_VDEVICE(ENSONIQ, 0x5000) }, /* ES1370 */
#endif
#ifdef CHIP1371
- { PCI_VDEVICE(ENSONIQ, 0x1371), 0, }, /* ES1371 */
- { PCI_VDEVICE(ENSONIQ, 0x5880), 0, }, /* ES1373 - CT5880 */
- { PCI_VDEVICE(ECTIVA, 0x8938), 0, }, /* Ectiva EV1938 */
+ { PCI_VDEVICE(ENSONIQ, 0x1371) }, /* ES1371 */
+ { PCI_VDEVICE(ENSONIQ, 0x5880) }, /* ES1373 - CT5880 */
+ { PCI_VDEVICE(ECTIVA, 0x8938) }, /* Ectiva EV1938 */
#endif
- { 0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_audiopci_ids);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 280125eff3624..217beb9376aca 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -222,8 +222,8 @@ struct es1938 {
static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
static const struct pci_device_id snd_es1938_ids[] = {
- { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */
- { 0, }
+ { PCI_VDEVICE(ESS, 0x1969) }, /* Solo-1 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_es1938_ids);
@@ -1655,6 +1655,8 @@ static int snd_es1938_mixer(struct es1938 *chip)
for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) {
struct snd_kcontrol *kctl;
kctl = snd_ctl_new1(&snd_es1938_controls[idx], chip);
+ if (!kctl)
+ return -ENOMEM;
switch (idx) {
case 0:
chip->master_volume = kctl;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index b7282b3fa1b16..f04628c8cbb72 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -549,13 +549,26 @@ struct es1968 {
static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
static const struct pci_device_id snd_es1968_ids[] = {
- /* Maestro 1 */
- { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO },
- /* Maestro 2 */
- { 0x125d, 0x1968, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2 },
- /* Maestro 2E */
- { 0x125d, 0x1978, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO2E },
- { 0, }
+ {
+ /* Maestro 1 */
+ PCI_DEVICE(0x1285, 0x0100),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ .driver_data = TYPE_MAESTRO,
+ }, {
+ /* Maestro 2 */
+ PCI_DEVICE(0x125d, 0x1968),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ .driver_data = TYPE_MAESTRO2,
+ }, {
+ /* Maestro 2E */
+ PCI_DEVICE(0x125d, 0x1978),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ .driver_data = TYPE_MAESTRO2E,
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_es1968_ids);
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 4ca992449ea30..9cc96b807dd79 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -240,9 +240,18 @@ static inline u16 fm801_ioread16(struct fm801 *chip, unsigned short offset)
}
static const struct pci_device_id snd_fm801_ids[] = {
- { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */
- { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */
- { 0, }
+ {
+ /* FM801 */
+ PCI_DEVICE(0x1319, 0x0801),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ /* Gallant Odyssey Sound 4 */
+ PCI_DEVICE(0x5213, 0x0510),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_fm801_ids);
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 1191a2686dfd2..d6abff2978f3d 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -1891,6 +1891,8 @@ static int aureon_add_controls(struct snd_ice1712 *ice)
for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
struct snd_kcontrol *kctl;
kctl = snd_ctl_new1(&cs8415_controls[i], ice);
+ if (!kctl)
+ return -ENOMEM;
if (i > 1)
kctl->id.device = ice->pcm->device;
err = snd_ctl_add(ice->card, kctl);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 1e39b985bef26..7d1a357ed90dc 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -86,8 +86,8 @@ MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
static const struct pci_device_id snd_ice1712_ids[] = {
- { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */
- { 0, }
+ { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712) }, /* ICE1712 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_ice1712_ids);
@@ -2346,21 +2346,29 @@ int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice)
if (snd_BUG_ON(!ice->pcm_pro))
return -EIO;
kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm_pro->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm_pro->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm_pro->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm_pro->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 65bf48647d089..859bb87393b41 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -62,8 +62,8 @@ MODULE_PARM_DESC(model, "Use the given board model.");
/* Both VT1720 and VT1724 have the same PCI IDs */
static const struct pci_device_id snd_vt1724_ids[] = {
- { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 },
- { 0, }
+ { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_vt1724_ids);
@@ -730,13 +730,22 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream,
static int snd_vt1724_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
+ bool released = false;
int i;
- guard(mutex)(&ice->open_mutex);
- /* unmark surround channels */
- for (i = 0; i < 3; i++)
- if (ice->pcm_reserved[i] == substream)
+ scoped_guard(mutex, &ice->open_mutex) {
+ /* unmark surround channels */
+ for (i = 0; i < 3; i++) {
+ if (ice->pcm_reserved[i] != substream)
+ continue;
ice->pcm_reserved[i] = NULL;
+ released = true;
+ }
+ }
+
+ if (released && ice->pcm_ds)
+ wake_up(&ice->pcm_ds->open_wait);
+
return 0;
}
@@ -1364,7 +1373,7 @@ static int snd_vt1724_playback_indep_open(struct snd_pcm_substream *substream)
scoped_guard(mutex, &ice->open_mutex) {
/* already used by PDMA0? */
if (ice->pcm_reserved[substream->number])
- return -EBUSY; /* FIXME: should handle blocking mode properly */
+ return -EAGAIN;
}
runtime->private_data = (void *)&vt1724_playback_dma_regs[substream->number];
ice->playback_con_substream_ds[substream->number] = substream;
@@ -2379,16 +2388,22 @@ static int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice)
return err;
kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = ice->pcm->device;
err = snd_ctl_add(ice->card, kctl);
if (err < 0)
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 3b53c5e63c298..e2ea9016a73e4 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -384,30 +384,100 @@ struct intel8x0 {
};
static const struct pci_device_id snd_intel8x0_ids[] = {
- { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */
- { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */
- { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */
- { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL }, /* ICH3 */
- { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */
- { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */
- { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */
- { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */
- { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */
- { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */
- { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL }, /* 440MX */
- { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS }, /* SI7012 */
- { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */
- { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */
- { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */
- { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */
- { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */
- { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */
- { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */
- { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */
- { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL }, /* AMD8111 */
- { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL }, /* AMD768 */
- { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */
- { 0, }
+ {
+ /* 82801AA */
+ PCI_VDEVICE(INTEL, 0x2415),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* 82901AB */
+ PCI_VDEVICE(INTEL, 0x2425),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* 82801BA */
+ PCI_VDEVICE(INTEL, 0x2445),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* ICH3 */
+ PCI_VDEVICE(INTEL, 0x2485),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* ICH4 */
+ PCI_VDEVICE(INTEL, 0x24c5),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* ICH5 */
+ PCI_VDEVICE(INTEL, 0x24d5),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* ESB */
+ PCI_VDEVICE(INTEL, 0x25a6),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* ICH6 */
+ PCI_VDEVICE(INTEL, 0x266e),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* ICH7 */
+ PCI_VDEVICE(INTEL, 0x27de),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* ESB2 */
+ PCI_VDEVICE(INTEL, 0x2698),
+ .driver_data = DEVICE_INTEL_ICH4,
+ }, {
+ /* 440MX */
+ PCI_VDEVICE(INTEL, 0x7195),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* SI7012 */
+ PCI_VDEVICE(SI, 0x7012),
+ .driver_data = DEVICE_SIS,
+ }, {
+ /* NFORCE */
+ PCI_VDEVICE(NVIDIA, 0x01b1),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* MCP04 */
+ PCI_VDEVICE(NVIDIA, 0x003a),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* NFORCE2 */
+ PCI_VDEVICE(NVIDIA, 0x006a),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* CK804 */
+ PCI_VDEVICE(NVIDIA, 0x0059),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* CK8 */
+ PCI_VDEVICE(NVIDIA, 0x008a),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* NFORCE3 */
+ PCI_VDEVICE(NVIDIA, 0x00da),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* CK8S */
+ PCI_VDEVICE(NVIDIA, 0x00ea),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* MCP51 */
+ PCI_VDEVICE(NVIDIA, 0x026b),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* AMD8111 */
+ PCI_VDEVICE(AMD, 0x746d),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* AMD768 */
+ PCI_VDEVICE(AMD, 0x7445),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* Ali5455 */
+ PCI_VDEVICE(AL, 0x5455),
+ .driver_data = DEVICE_ALI,
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 84e1b7ea34e2a..27dbf61254278 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -190,26 +190,78 @@ struct intel8x0m {
};
static const struct pci_device_id snd_intel8x0m_ids[] = {
- { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */
- { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */
- { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */
- { PCI_VDEVICE(INTEL, 0x2486), DEVICE_INTEL }, /* ICH3 */
- { PCI_VDEVICE(INTEL, 0x24c6), DEVICE_INTEL }, /* ICH4 */
- { PCI_VDEVICE(INTEL, 0x24d6), DEVICE_INTEL }, /* ICH5 */
- { PCI_VDEVICE(INTEL, 0x266d), DEVICE_INTEL }, /* ICH6 */
- { PCI_VDEVICE(INTEL, 0x27dd), DEVICE_INTEL }, /* ICH7 */
- { PCI_VDEVICE(INTEL, 0x7196), DEVICE_INTEL }, /* 440MX */
- { PCI_VDEVICE(AMD, 0x7446), DEVICE_INTEL }, /* AMD768 */
- { PCI_VDEVICE(SI, 0x7013), DEVICE_SIS }, /* SI7013 */
- { PCI_VDEVICE(NVIDIA, 0x01c1), DEVICE_NFORCE }, /* NFORCE */
- { PCI_VDEVICE(NVIDIA, 0x0069), DEVICE_NFORCE }, /* NFORCE2 */
- { PCI_VDEVICE(NVIDIA, 0x0089), DEVICE_NFORCE }, /* NFORCE2s */
- { PCI_VDEVICE(NVIDIA, 0x00d9), DEVICE_NFORCE }, /* NFORCE3 */
- { PCI_VDEVICE(AMD, 0x746e), DEVICE_INTEL }, /* AMD8111 */
+ {
+ /* 82801AA */
+ PCI_VDEVICE(INTEL, 0x2416),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* 82901AB */
+ PCI_VDEVICE(INTEL, 0x2426),
+ .driver_data = DEVICE_INTEL
+ }, {
+ /* 82801BA */
+ PCI_VDEVICE(INTEL, 0x2446),
+ .driver_data = DEVICE_INTEL
+ }, {
+ /* ICH3 */
+ PCI_VDEVICE(INTEL, 0x2486),
+ .driver_data = DEVICE_INTEL
+ }, {
+ /* ICH4 */
+ PCI_VDEVICE(INTEL, 0x24c6),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* ICH5 */
+ PCI_VDEVICE(INTEL, 0x24d6),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* ICH6 */
+ PCI_VDEVICE(INTEL, 0x266d),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* ICH7 */
+ PCI_VDEVICE(INTEL, 0x27dd),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* 440MX */
+ PCI_VDEVICE(INTEL, 0x7196),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* AMD768 */
+ PCI_VDEVICE(AMD, 0x7446),
+ .driver_data = DEVICE_INTEL,
+ }, {
+ /* SI7013 */
+ PCI_VDEVICE(SI, 0x7013),
+ .driver_data = DEVICE_SIS,
+ }, {
+ /* NFORCE */
+ PCI_VDEVICE(NVIDIA, 0x01c1),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* NFORCE2 */
+ PCI_VDEVICE(NVIDIA, 0x0069),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* NFORCE2s */
+ PCI_VDEVICE(NVIDIA, 0x0089),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* NFORCE3 */
+ PCI_VDEVICE(NVIDIA, 0x00d9),
+ .driver_data = DEVICE_NFORCE,
+ }, {
+ /* AMD8111 */
+ PCI_VDEVICE(AMD, 0x746e),
+ .driver_data = DEVICE_INTEL
#if 0
- { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */
+ }, {
+ /* Ali5455 */
+ PCI_VDEVICE(AL, 0x5455),
+ .driver_data = DEVICE_ALI,
#endif
- { 0, }
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids);
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 3353980d5cd8a..dd45ffa171e18 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -779,23 +779,40 @@ struct snd_m3 {
* pci ids
*/
static const struct pci_device_id snd_m3_ids[] = {
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2LE, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_1, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_HW, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_2, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {0,},
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2LE),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_CANYON3D_2),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_1),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_HW),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_MAESTRO3_2),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ },
+ { },
};
MODULE_DEVICE_TABLE(pci, snd_m3_ids);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index a7760a23bfe90..f451554cff5f1 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -48,8 +48,8 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard.");
*/
static const struct pci_device_id snd_mixart_ids[] = {
- { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */
- { 0, }
+ { PCI_VDEVICE(MOTOROLA, 0x0003) }, /* MC8240 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_mixart_ids);
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index da74b923bc88f..a7da55d9c025a 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -245,10 +245,10 @@ struct nm256 {
* PCI ids
*/
static const struct pci_device_id snd_nm256_ids[] = {
- {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0},
- {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0},
- {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0},
- {0,},
+ { PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO) },
+ { PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO) },
+ { PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO) },
+ { },
};
MODULE_DEVICE_TABLE(pci, snd_nm256_ids);
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index e7d63972c2caf..1eea40e94c43c 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -89,41 +89,41 @@ enum {
};
static const struct pci_device_id pcxhr_ids[] = {
- { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, },
- { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, },
- { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, },
- { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, },
- { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, },
- { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, },
- { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, },
- { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, },
- { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, },
- { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, },
- { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, },
- { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, },
- { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, },
- { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, },
- { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, },
- { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, },
- { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, },
- { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, },
- { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
- { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
- { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
- { 0x10b5, 0x9656, 0x1369, 0xd001, 0, 0, PCI_ID_VX442HR, },
- { 0x10b5, 0x9656, 0x1369, 0xd101, 0, 0, PCI_ID_PCX442HR, },
- { 0x10b5, 0x9056, 0x1369, 0xd021, 0, 0, PCI_ID_VX442E, },
- { 0x10b5, 0x9056, 0x1369, 0xd121, 0, 0, PCI_ID_PCX442E, },
- { 0x10b5, 0x9656, 0x1369, 0xd201, 0, 0, PCI_ID_VX822HR, },
- { 0x10b5, 0x9656, 0x1369, 0xd301, 0, 0, PCI_ID_PCX822HR, },
- { 0x10b5, 0x9056, 0x1369, 0xd221, 0, 0, PCI_ID_VX822E, },
- { 0x10b5, 0x9056, 0x1369, 0xd321, 0, 0, PCI_ID_PCX822E, },
- { 0, }
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb001), .driver_data = PCI_ID_VX882HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb101), .driver_data = PCI_ID_PCX882HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb201), .driver_data = PCI_ID_VX881HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb301), .driver_data = PCI_ID_PCX881HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb021), .driver_data = PCI_ID_VX882E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb121), .driver_data = PCI_ID_PCX882E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb221), .driver_data = PCI_ID_VX881E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb321), .driver_data = PCI_ID_PCX881E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb401), .driver_data = PCI_ID_VX1222HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb501), .driver_data = PCI_ID_PCX1222HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb601), .driver_data = PCI_ID_VX1221HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xb701), .driver_data = PCI_ID_PCX1221HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb421), .driver_data = PCI_ID_VX1222E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb521), .driver_data = PCI_ID_PCX1222E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb621), .driver_data = PCI_ID_VX1221E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xb721), .driver_data = PCI_ID_PCX1221E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xba01), .driver_data = PCI_ID_VX222HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xba21), .driver_data = PCI_ID_VX222E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbd01), .driver_data = PCI_ID_PCX22HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbd21), .driver_data = PCI_ID_PCX22E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbc01), .driver_data = PCI_ID_VX222HRMIC },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbc21), .driver_data = PCI_ID_VX222E_MIC },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbb01), .driver_data = PCI_ID_PCX924HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbb21), .driver_data = PCI_ID_PCX924E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbf01), .driver_data = PCI_ID_PCX924HRMIC },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xbf21), .driver_data = PCI_ID_PCX924E_MIC },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xd001), .driver_data = PCI_ID_VX442HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xd101), .driver_data = PCI_ID_PCX442HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xd021), .driver_data = PCI_ID_VX442E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xd121), .driver_data = PCI_ID_PCX442E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xd201), .driver_data = PCI_ID_VX822HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9656, 0x1369, 0xd301), .driver_data = PCI_ID_PCX822HR },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xd221), .driver_data = PCI_ID_VX822E },
+ { PCI_DEVICE_SUB(0x10b5, 0x9056, 0x1369, 0xd321), .driver_data = PCI_ID_PCX822E },
+ { }
};
MODULE_DEVICE_TABLE(pci, pcxhr_ids);
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index ca9bbf5546509..454a30a2c07e1 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -211,10 +211,10 @@ struct rme32 {
};
static const struct pci_device_id snd_rme32_ids[] = {
- {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,},
- {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,},
- {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,},
- {0,}
+ { PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32) },
+ { PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8) },
+ { PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_rme32_ids);
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 58b8ebf1a24e7..892fcc5985575 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -242,11 +242,11 @@ struct rme96 {
};
static const struct pci_device_id snd_rme96_ids[] = {
- { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, },
- { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, },
- { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, },
- { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST), 0, },
- { 0, }
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96) },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8) },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO) },
+ { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_rme96_ids);
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index a4c72799d0348..a885d544acd65 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -227,8 +227,8 @@ struct sonicvibes {
};
static const struct pci_device_id snd_sonic_ids[] = {
- { PCI_VDEVICE(S3, 0xca00), 0, },
- { 0, }
+ { PCI_VDEVICE(S3, 0xca00) },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_sonic_ids);
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index ddb6ccc72e443..8dcbd022ca1fc 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -36,12 +36,16 @@ module_param_array(wavetable_size, int, NULL, 0444);
MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth.");
static const struct pci_device_id snd_trident_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX),
- PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0},
- {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX),
- 0, 0, 0},
- {PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018), 0, 0, 0},
- { 0, }
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX),
+ .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
+ .class_mask = 0xffff00,
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX),
+ }, {
+ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018)
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_trident_ids);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 41b322fbd9efd..24ee1302f27d3 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -389,10 +389,10 @@ struct via82xx {
static const struct pci_device_id snd_via82xx_ids[] = {
/* 0x1106, 0x3058 */
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), .driver_data = TYPE_CARD_VIA686 }, /* 686A */
/* 0x1106, 0x3059 */
- { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8233_5), TYPE_CARD_VIA8233, }, /* VT8233 */
- { 0, }
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8233_5), .driver_data = TYPE_CARD_VIA8233 }, /* VT8233 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index a6f176d612e3a..9b84d3fb9eaf5 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -246,8 +246,8 @@ struct via82xx_modem {
};
static const struct pci_device_id snd_via82xx_modem_ids[] = {
- { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, },
- { 0, }
+ { PCI_VDEVICE(VIA, 0x3068), .driver_data = TYPE_CARD_VIA82XX_MODEM },
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_via82xx_modem_ids);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 693a4e471cf7f..0b89ca859e667 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -47,9 +47,9 @@ enum {
};
static const struct pci_device_id snd_vx222_ids[] = {
- { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */
- { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */
- { 0, }
+ { PCI_DEVICE_SUB(0x10b5, 0x9050, 0x1369, PCI_ANY_ID), .driver_data = VX_PCI_VX222_OLD }, /* PLX */
+ { PCI_DEVICE_SUB(0x10b5, 0x9030, 0x1369, PCI_ANY_ID), .driver_data = VX_PCI_VX222_NEW }, /* PLX */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_vx222_ids);
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 764ca59e98d1d..d3fb047c9a450 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -46,13 +46,13 @@ module_param_array(rear_switch, bool, NULL, 0444);
MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
static const struct pci_device_id snd_ymfpci_ids[] = {
- { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */
- { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */
- { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */
- { PCI_VDEVICE(YAMAHA, 0x000c), 0, }, /* YMF740C */
- { PCI_VDEVICE(YAMAHA, 0x0010), 0, }, /* YMF744 */
- { PCI_VDEVICE(YAMAHA, 0x0012), 0, }, /* YMF754 */
- { 0, }
+ { PCI_VDEVICE(YAMAHA, 0x0004) }, /* YMF724 */
+ { PCI_VDEVICE(YAMAHA, 0x000d) }, /* YMF724F */
+ { PCI_VDEVICE(YAMAHA, 0x000a) }, /* YMF740 */
+ { PCI_VDEVICE(YAMAHA, 0x000c) }, /* YMF740C */
+ { PCI_VDEVICE(YAMAHA, 0x0010) }, /* YMF744 */
+ { PCI_VDEVICE(YAMAHA, 0x0012) }, /* YMF754 */
+ { }
};
MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids);
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index b9a09568afc9e..2ccb976e68e0b 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1781,16 +1781,22 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
if (snd_BUG_ON(!chip->pcm_spdif))
return -ENXIO;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
return err;
kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip);
+ if (!kctl)
+ return -ENOMEM;
kctl->id.device = chip->pcm_spdif->device;
err = snd_ctl_add(chip->card, kctl);
if (err < 0)
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index 2ed01e9d79bb9..01ad5b12b680f 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -132,19 +132,15 @@ snd_emux_create_port(struct snd_emux *emu, char *name,
int i, type, cap;
/* Allocate structures for this channel */
- p = kzalloc_obj(*p);
+ p = kzalloc_flex(*p, chset.channels, max_channels);
if (!p)
return NULL;
- p->chset.channels = kzalloc_objs(*p->chset.channels, max_channels);
- if (!p->chset.channels) {
- kfree(p);
- return NULL;
- }
+ p->chset.max_channels = max_channels;
+
for (i = 0; i < max_channels; i++)
p->chset.channels[i].number = i;
p->chset.private_data = p;
- p->chset.max_channels = max_channels;
p->emu = emu;
p->chset.client = emu->client;
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
@@ -182,7 +178,6 @@ free_port(void *private_data)
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
snd_emux_delete_effect(p);
#endif
- kfree(p->chset.channels);
kfree(p);
}
}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 6fbcb117555c6..24cd7692bd01c 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1780,8 +1780,16 @@ static void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
/*
* skip empty packets. At least M-Audio's Fast Track Ultra stops
* streaming once it received a 0-byte OUT URB
+ *
+ * However, on devices where bytes==0 means every sync-source
+ * packet errored (e.g. Behringer Flow 8 returning -EXDEV bursts
+ * for entire capture URBs), an unconditional return starves the
+ * IFB-fed OUT ring permanently. Such devices set
+ * QUIRK_FLAG_IFB_SILENCE_ON_EMPTY to fall through and enqueue a
+ * packet_info with size 0 packets, so playback emits silence
+ * and the OUT ring keeps moving.
*/
- if (bytes == 0)
+ if (bytes == 0 && !(ep->chip->quirk_flags & QUIRK_FLAG_IFB_SILENCE_ON_EMPTY))
return;
spin_lock_irqsave(&ep->lock, flags);
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c
index 0fc4d063c48a5..ea746bdb36ffc 100644
--- a/sound/usb/fcp.c
+++ b/sound/usb/fcp.c
@@ -191,13 +191,13 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode,
struct fcp_usb_packet *req __free(kfree) = NULL;
size_t req_buf_size = struct_size(req, data, req_size);
- req = kmalloc(req_buf_size, GFP_KERNEL);
+ req = kmalloc_flex(*req, data, req_size);
if (!req)
return -ENOMEM;
struct fcp_usb_packet *resp __free(kfree) = NULL;
size_t resp_buf_size = struct_size(resp, data, resp_size);
- resp = kmalloc(resp_buf_size, GFP_KERNEL);
+ resp = kmalloc_flex(*resp, data, resp_size);
if (!resp)
return -ENOMEM;
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 5fba456eb4a96..d61bde6542197 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -665,17 +665,13 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter
return 0;
switch (iterm->type >> 16) {
case UAC3_SELECTOR_UNIT:
- strscpy(name, "Selector", maxlen);
- return 8;
+ return strscpy(name, "Selector", maxlen);
case UAC3_PROCESSING_UNIT:
- strscpy(name, "Process Unit", maxlen);
- return 12;
+ return strscpy(name, "Process Unit", maxlen);
case UAC3_EXTENSION_UNIT:
- strscpy(name, "Ext Unit", maxlen);
- return 8;
+ return strscpy(name, "Ext Unit", maxlen);
case UAC3_MIXER_UNIT:
- strscpy(name, "Mixer", maxlen);
- return 5;
+ return strscpy(name, "Mixer", maxlen);
default:
return scnprintf(name, maxlen, "Unit %d", iterm->id);
}
@@ -683,25 +679,18 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter
switch (iterm->type & 0xff00) {
case 0x0100:
- strscpy(name, "PCM", maxlen);
- return 3;
+ return strscpy(name, "PCM", maxlen);
case 0x0200:
- strscpy(name, "Mic", maxlen);
- return 3;
+ return strscpy(name, "Mic", maxlen);
case 0x0400:
- strscpy(name, "Headset", maxlen);
- return 7;
+ return strscpy(name, "Headset", maxlen);
case 0x0500:
- strscpy(name, "Phone", maxlen);
- return 5;
+ return strscpy(name, "Phone", maxlen);
}
- for (names = iterm_names; names->type; names++) {
- if (names->type == iterm->type) {
- strscpy(name, names->name, maxlen);
- return strlen(names->name);
- }
- }
+ for (names = iterm_names; names->type; names++)
+ if (names->type == iterm->type)
+ return strscpy(name, names->name, maxlen);
return 0;
}
@@ -1536,7 +1525,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 +1543,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;
}
}
@@ -1988,7 +1982,9 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer,
int name_len = get_term_name(mixer->chip, term, name, name_size, 0);
if (name_len == 0)
- strscpy(name, "Unknown", name_size);
+ name_len = strscpy(name, "Unknown", name_size);
+ if (name_len < 0)
+ return;
/*
* sound/core/ctljack.c has a convention of naming jack controls
@@ -1996,9 +1992,9 @@ static void get_connector_control_name(struct usb_mixer_interface *mixer,
* indicating Input or Output after the terminal name.
*/
if (is_input)
- strlcat(name, " - Input Jack", name_size);
+ strscpy(name + name_len, " - Input Jack", name_size - name_len);
else
- strlcat(name, " - Output Jack", name_size);
+ strscpy(name + name_len, " - Output Jack", name_size - name_len);
}
/* get connector value to "wake up" the USB audio */
@@ -2476,7 +2472,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 +2840,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_quirks.c b/sound/usb/mixer_quirks.c
index 1bdaa46d4fe18..628f841b04aae 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -333,6 +333,7 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
int index = kcontrol->private_value & 0xff;
unsigned int value = ucontrol->value.integer.value[0];
int old_value = kcontrol->private_value >> 8;
+ unsigned long old_pval = kcontrol->private_value;
int err;
if (value > 1)
@@ -341,7 +342,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
return 0;
kcontrol->private_value = (value << 8) | index;
err = snd_audigy2nx_led_update(mixer, value, index);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kcontrol->private_value = old_pval;
+ return err;
+ }
+ return 1;
}
static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list)
@@ -487,6 +492,7 @@ static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
struct usb_mixer_interface *mixer = list->mixer;
unsigned int value = ucontrol->value.enumerated.item[0];
+ unsigned long old_pval = kcontrol->private_value;
int err;
if (value > 1)
@@ -497,7 +503,11 @@ static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
kcontrol->private_value = value;
err = snd_emu0204_ch_switch_update(mixer, value);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kcontrol->private_value = old_pval;
+ return err;
+ }
+ return 1;
}
static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list)
@@ -821,7 +831,11 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
kcontrol->private_value = new_status;
err = snd_xonar_u1_switch_update(list->mixer, new_status);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kcontrol->private_value = old_status;
+ return err;
+ }
+ return 1;
}
static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list)
@@ -1159,7 +1173,8 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
- u8 oldval = (kcontrol->private_value >> 24) & 0xff;
+ unsigned long old_pval = kcontrol->private_value;
+ u8 oldval = (old_pval >> 24) & 0xff;
u8 newval = ucontrol->value.integer.value[0];
int err;
@@ -1169,7 +1184,11 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
kcontrol->private_value &= ~(0xff << 24);
kcontrol->private_value |= (unsigned int)newval << 24;
err = snd_ni_update_cur_val(list);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kcontrol->private_value = old_pval;
+ return err;
+ }
+ return 1;
}
static const struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
@@ -1282,7 +1301,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- pval & 0xff00,
+ (pval & 0xff00) | ((pval & 0xff0000) >> 16),
snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
value, 2);
if (err < 0)
@@ -1315,7 +1334,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- pval & 0xff00,
+ (pval & 0xff00) | ((pval & 0xff0000) >> 16),
snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
value, 2);
}
@@ -1324,7 +1343,8 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
- unsigned int pval = list->kctl->private_value;
+ unsigned long old_pval = list->kctl->private_value;
+ unsigned int pval = old_pval;
int cur_val, err, new_val;
cur_val = pval >> 24;
@@ -1335,7 +1355,11 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
kctl->private_value &= ~(0xff << 24);
kctl->private_value |= new_val << 24;
err = snd_ftu_eff_switch_update(list);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kctl->private_value = old_pval;
+ return err;
+ }
+ return 1;
}
static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
@@ -1730,6 +1754,44 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer
return 0;
}
+/* output gain knob selectively adjusts outputs as stereo pairs */
+/* reuses functions from FTU effect switch */
+static int snd_c400_knob_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *const texts[8] = {
+ "None", "1/2", "3/4", "1/2 3/4",
+ "5/6", "1/2 5/6", "3/4 5/6", "1/2 3/4 5/6"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int snd_c400_create_knob_switch(struct usb_mixer_interface *mixer,
+ int validx, int bUnitID)
+{
+ static struct snd_kcontrol_new template = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Output Gain Knob",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_c400_knob_switch_info,
+ .get = snd_ftu_eff_switch_get,
+ .put = snd_ftu_eff_switch_put
+ };
+ struct usb_mixer_elem_list *list;
+ int err;
+
+ err = add_single_ctl_with_resume(mixer, bUnitID,
+ snd_ftu_eff_switch_update,
+ &template, &list);
+ if (err < 0)
+ return err;
+ list->kctl->private_value = (validx << 8) | bUnitID;
+ snd_ftu_eff_switch_init(mixer, list->kctl);
+ return 0;
+}
+
static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)
{
int err;
@@ -1762,6 +1824,10 @@ static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)
if (err < 0)
return err;
+ err = snd_c400_create_knob_switch(mixer, 0x0900, 0x20);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -2114,13 +2180,18 @@ static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol,
{
struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
unsigned char value = !!ucontrol->value.integer.value[0];
+ unsigned long old_pval = kcontrol->private_value;
int err;
if (kcontrol->private_value == value)
return 0;
kcontrol->private_value = value;
err = snd_soundblaster_e1_switch_update(list->mixer, value);
- return err < 0 ? err : 1;
+ if (err < 0) {
+ kcontrol->private_value = old_pval;
+ return err;
+ }
+ return 1;
}
static int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list)
@@ -2998,12 +3069,14 @@ static int snd_bbfpro_ctl_put(struct snd_kcontrol *kcontrol,
if (val == old_value)
return 0;
+ err = snd_bbfpro_ctl_update(mixer, reg, idx, val);
+ if (err < 0)
+ return err;
+
kcontrol->private_value = reg
| ((idx & SND_BBFPRO_CTL_IDX_MASK) << SND_BBFPRO_CTL_IDX_SHIFT)
| ((val & SND_BBFPRO_CTL_VAL_MASK) << SND_BBFPRO_CTL_VAL_SHIFT);
-
- err = snd_bbfpro_ctl_update(mixer, reg, idx, val);
- return err < 0 ? err : 1;
+ return 1;
}
static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list)
@@ -3188,11 +3261,13 @@ static int snd_bbfpro_vol_put(struct snd_kcontrol *kcontrol,
new_val = uvalue & SND_BBFPRO_MIXER_VAL_MASK;
+ err = snd_bbfpro_vol_update(mixer, idx, new_val);
+ if (err < 0)
+ return err;
+
kcontrol->private_value = idx
| (new_val << SND_BBFPRO_MIXER_VAL_SHIFT);
-
- err = snd_bbfpro_vol_update(mixer, idx, new_val);
- return err < 0 ? err : 1;
+ return 1;
}
static int snd_bbfpro_vol_resume(struct usb_mixer_elem_list *list)
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index 1bb01e8276549..673eb8d8724db 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 a4fac46522013..78fb72e626cac 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,
@@ -2381,13 +2614,13 @@ static int scarlett2_usb(
struct scarlett2_usb_packet *req __free(kfree) = NULL;
size_t req_buf_size = struct_size(req, data, req_size);
- req = kmalloc(req_buf_size, GFP_KERNEL);
+ req = kmalloc_flex(*req, data, req_size);
if (!req)
return -ENOMEM;
struct scarlett2_usb_packet *resp __free(kfree) = NULL;
size_t resp_buf_size = struct_size(resp, data, resp_size);
- resp = kmalloc(resp_buf_size, GFP_KERNEL);
+ resp = kmalloc_flex(*resp, data, resp_size);
if (!resp)
return -ENOMEM;
@@ -2504,27 +2737,6 @@ static int scarlett2_has_config_item(
return !!private->config_set->items[config_item_num].offset;
}
-/* Return the configuration item's offset, applying any per-firmware
- * overrides.
- *
- * Firmware 2417 for the 2i2 Gen 4 moved DIRECT_MONITOR_GAIN by 4
- * bytes. Apply that shift here so that the rest of the driver can
- * keep using the single config set. This override can be removed
- * once the multi-config-set framework lands.
- */
-static int scarlett2_config_item_offset(
- struct scarlett2_data *private, int config_item_num)
-{
- int offset = private->config_set->items[config_item_num].offset;
-
- if (config_item_num == SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN &&
- private->info == &s2i2_gen4_info &&
- private->firmware_version >= 2417)
- offset = 0x2a4;
-
- return offset;
-}
-
/* Send a USB message to get configuration parameters; result placed in *buf */
static int scarlett2_usb_get_config(
struct usb_mixer_interface *mixer,
@@ -2534,7 +2746,6 @@ static int scarlett2_usb_get_config(
const struct scarlett2_config *config_item =
&private->config_set->items[config_item_num];
int size, err, i;
- int item_offset;
u8 *buf_8;
u8 value;
@@ -2544,15 +2755,13 @@ static int scarlett2_usb_get_config(
if (!config_item->offset)
return -EFAULT;
- item_offset = scarlett2_config_item_offset(private, config_item_num);
-
/* Writes to the parameter buffer are always 1 byte */
size = config_item->size ? config_item->size : 8;
/* For byte-sized parameters, retrieve directly into buf */
if (size >= 8) {
size = size / 8 * count;
- err = scarlett2_usb_get(mixer, item_offset, buf, size);
+ err = scarlett2_usb_get(mixer, config_item->offset, buf, size);
if (err < 0)
return err;
if (config_item->size == 16) {
@@ -2570,7 +2779,7 @@ static int scarlett2_usb_get_config(
}
/* For bit-sized parameters, retrieve into value */
- err = scarlett2_usb_get(mixer, item_offset, &value, 1);
+ err = scarlett2_usb_get(mixer, config_item->offset, &value, 1);
if (err < 0)
return err;
@@ -2621,9 +2830,9 @@ static int scarlett2_usb_set_data_buf(
u8 data[];
} __packed *req;
int err;
- int buf_size = struct_size(req, data, bytes);
+ size_t buf_size = struct_size(req, data, bytes);
- req = kmalloc(buf_size, GFP_KERNEL);
+ req = kmalloc_flex(*req, data, bytes);
if (!req)
return -ENOMEM;
@@ -2720,8 +2929,7 @@ static int scarlett2_usb_set_config(
*/
if (config_item->size >= 8) {
size = config_item->size / 8;
- offset = scarlett2_config_item_offset(private, config_item_num) +
- index * size;
+ offset = config_item->offset + index * size;
/* If updating a bit, retrieve the old value, set/clear the
* bit as needed, and update value
@@ -2730,7 +2938,7 @@ static int scarlett2_usb_set_config(
u8 tmp;
size = 1;
- offset = scarlett2_config_item_offset(private, config_item_num);
+ offset = config_item->offset;
err = scarlett2_usb_get(mixer, offset, &tmp, 1);
if (err < 0)
@@ -3301,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;
}
@@ -7653,6 +7862,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)
@@ -8211,10 +8586,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;
@@ -8311,9 +8708,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;
@@ -8503,6 +8905,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)) {
@@ -8513,13 +8916,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;
}
@@ -8673,6 +9076,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;
@@ -8703,6 +9110,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 */
@@ -8711,12 +9119,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)
@@ -8746,7 +9163,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 */
@@ -8809,6 +9226,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)
@@ -9227,7 +9649,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw,
/* Create and send the request */
len = struct_size(req, data, count);
- req = kzalloc(len, GFP_KERNEL);
+ req = kzalloc_flex(*req, data, count);
if (!req)
return -ENOMEM;
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
index 8a02964e5d7b6..ebff185cbd2c0 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;
}
-
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 4e9cfff4047fc..97f28c53d2015 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2132,6 +2132,14 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ USB_DEVICE(0x1235, 0x001e),
+ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Novation", */
+ /* .product_name = "Mininova", */
+ QUIRK_DATA_RAW_BYTES(0)
+ }
+},
+{
USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
QUIRK_DRIVER_INFO {
.vendor_name = "Novation",
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 3d1b3523b020c..410f5a92c0cfb 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2365,6 +2365,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+ DEVICE_FLG(0x1397, 0x050c, /* Behringer Flow 8 */
+ QUIRK_FLAG_IFB_SILENCE_ON_EMPTY),
DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x152a, 0x880a, /* NeuralDSP Quad Cortex */
@@ -2604,6 +2606,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
QUIRK_STRING_ENTRY(SKIP_IFACE_SETUP),
QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL),
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
+ QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
NULL
};
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 58fd07f8c3c97..9afcad8f143a0 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -236,6 +236,12 @@ extern bool snd_usb_skip_validation;
* QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL
* Similar to QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL, but for capture streams.
* Overrides QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE
+ * QUIRK_FLAG_IFB_SILENCE_ON_EMPTY
+ * In implicit feedback mode, when an entire capture URB returns with
+ * all iso_frame_desc[i].status != 0 (bytes==0), do not silently return
+ * from snd_usb_handle_sync_urb. Instead fall through and enqueue a
+ * packet_info containing only size-0 packets, so the OUT ring keeps
+ * moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
*/
enum {
@@ -268,6 +274,7 @@ enum {
QUIRK_TYPE_SKIP_IFACE_SETUP = 26,
QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27,
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
+ QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
/* Please also edit snd_usb_audio_quirk_flag_names */
};
@@ -302,5 +309,6 @@ enum {
#define QUIRK_FLAG_SKIP_IFACE_SETUP QUIRK_FLAG(SKIP_IFACE_SETUP)
#define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL)
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
+#define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
#endif /* __USBAUDIO_H */
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index f34e78910200a..4190227c5a2a5 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -180,7 +180,7 @@ static void i_usx2y_in04_int(struct urb *urb)
struct usx2ydev *usx2y = urb->context;
struct us428ctls_sharedmem *us428ctls = usx2y->us428ctls_sharedmem;
struct us428_p4out *p4out;
- int i, j, n, diff, send;
+ int i, j, n, diff, send, len;
usx2y->in04_int_calls++;
@@ -222,24 +222,31 @@ static void i_usx2y_in04_int(struct urb *urb)
} while (!err && usx2y->us04->submitted < usx2y->us04->len);
}
} else {
- if (us428ctls && us428ctls->p4out_last >= 0 && us428ctls->p4out_last < N_US428_P4OUT_BUFS) {
- if (us428ctls->p4out_last != us428ctls->p4out_sent) {
- send = us428ctls->p4out_sent + 1;
- if (send >= N_US428_P4OUT_BUFS)
- send = 0;
- for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) {
- if (!usx2y->as04.urb[j]->status) {
- p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost.
- usb_fill_bulk_urb(usx2y->as04.urb[j], usx2y->dev,
- usb_sndbulkpipe(usx2y->dev, 0x04), &p4out->val.vol,
- p4out->type == ELT_LIGHT ? sizeof(struct us428_lights) : 5,
- i_usx2y_out04_int, usx2y);
- err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
+ while (us428ctls &&
+ us428ctls->p4out_last >= 0 &&
+ us428ctls->p4out_last < N_US428_P4OUT_BUFS &&
+ us428ctls->p4out_last != us428ctls->p4out_sent) {
+ for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) {
+ if (!usx2y->as04.urb[j]->status) {
+ send = us428ctls->p4out_sent + 1;
+ if (send >= N_US428_P4OUT_BUFS)
+ send = 0;
+
+ p4out = us428ctls->p4out + send;
+ len = p4out->type == ELT_LIGHT ?
+ sizeof(struct us428_lights) : 5;
+ memcpy(usx2y->as04.urb[j]->transfer_buffer,
+ &p4out->val.vol, len);
+ usx2y->as04.urb[j]->transfer_buffer_length = len;
+ err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
+ if (!err)
us428ctls->p4out_sent = send;
- break;
- }
+
+ break;
}
}
+ if (j >= URBS_ASYNC_SEQ || err)
+ break;
}
}
diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c
index ffb903d56297a..45f7b6a5b3080 100644
--- a/sound/virtio/virtio_kctl.c
+++ b/sound/virtio/virtio_kctl.c
@@ -18,6 +18,21 @@ static const snd_ctl_elem_type_t g_v2a_type_map[] = {
[VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958
};
+/* Map for converting VirtIO types to maximum value counts. */
+static const unsigned int g_v2a_count_map[] = {
+ [VIRTIO_SND_CTL_TYPE_BOOLEAN] =
+ ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
+ [VIRTIO_SND_CTL_TYPE_INTEGER] =
+ ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
+ [VIRTIO_SND_CTL_TYPE_INTEGER64] =
+ ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer64),
+ [VIRTIO_SND_CTL_TYPE_ENUMERATED] =
+ ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.enumerated),
+ [VIRTIO_SND_CTL_TYPE_BYTES] =
+ ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.bytes),
+ [VIRTIO_SND_CTL_TYPE_IEC958] = 1
+};
+
/* Map for converting VirtIO access rights to ALSA access rights. */
static const unsigned int g_v2a_access_map[] = {
[VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -36,6 +51,37 @@ static const unsigned int g_v2a_mask_map[] = {
[VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV
};
+static int virtsnd_kctl_validate_info(struct virtio_snd *snd, u32 cid,
+ struct virtio_snd_ctl_info *kinfo)
+{
+ struct virtio_device *vdev = snd->vdev;
+ unsigned int type = le32_to_cpu(kinfo->type);
+ unsigned int count = le32_to_cpu(kinfo->count);
+
+ if (type >= ARRAY_SIZE(g_v2a_type_map)) {
+ dev_err(&vdev->dev, "control #%u: unknown type %u\n",
+ cid, type);
+ return -EINVAL;
+ }
+
+ if (count > g_v2a_count_map[type] ||
+ (type == VIRTIO_SND_CTL_TYPE_IEC958 && count != 1)) {
+ dev_err(&vdev->dev, "control #%u: invalid count %u for type %u\n",
+ cid, count, type);
+ return -EINVAL;
+ }
+
+ if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED &&
+ !le32_to_cpu(kinfo->value.enumerated.items)) {
+ dev_err(&vdev->dev,
+ "control #%u: no items for enumerated control\n",
+ cid);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* virtsnd_kctl_info() - Returns information about the control.
* @kcontrol: ALSA control element.
@@ -385,6 +431,10 @@ int virtsnd_kctl_parse_cfg(struct virtio_snd *snd)
struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i];
unsigned int type = le32_to_cpu(kinfo->type);
+ rc = virtsnd_kctl_validate_info(snd, i, kinfo);
+ if (rc)
+ return rc;
+
if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) {
rc = virtsnd_kctl_get_enum_items(snd, i);
if (rc)
diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c
index eb9cc8131905d..be3893de40a55 100644
--- a/sound/virtio/virtio_pcm.c
+++ b/sound/virtio/virtio_pcm.c
@@ -77,7 +77,8 @@ static const struct virtsnd_v2a_rate g_v2a_rate_map[] = {
[VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 },
[VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 },
[VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 },
- [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 }
+ [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 },
+ [VIRTIO_SND_PCM_RATE_384000] = { SNDRV_PCM_RATE_384000, 384000 }
};
/**
diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
index 6297a9c61e70b..1105e7ff3523a 100644
--- a/sound/virtio/virtio_pcm_ops.c
+++ b/sound/virtio/virtio_pcm_ops.c
@@ -90,7 +90,8 @@ static const struct virtsnd_a2v_rate g_a2v_rate_map[] = {
{ 88200, VIRTIO_SND_PCM_RATE_88200 },
{ 96000, VIRTIO_SND_PCM_RATE_96000 },
{ 176400, VIRTIO_SND_PCM_RATE_176400 },
- { 192000, VIRTIO_SND_PCM_RATE_192000 }
+ { 192000, VIRTIO_SND_PCM_RATE_192000 },
+ { 384000, VIRTIO_SND_PCM_RATE_384000 }
};
static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream);
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c
index dc626480123ac..a6dd196f73d66 100644
--- a/sound/xen/xen_snd_front_alsa.c
+++ b/sound/xen/xen_snd_front_alsa.c
@@ -378,7 +378,7 @@ static int alsa_open(struct snd_pcm_substream *substream)
stream_clear(stream);
- xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true);
+ xen_snd_front_evtchnl_set_connected(&stream->evt_pair->req, true);
ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
alsa_hw_rule, stream,
@@ -498,6 +498,8 @@ static int alsa_hw_free(struct snd_pcm_substream *substream)
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
int ret;
+ xen_snd_front_evtchnl_set_connected(&stream->evt_pair->evt, false);
+
ret = xen_snd_front_stream_close(&stream->evt_pair->req);
stream_free(stream);
return ret;
@@ -532,6 +534,7 @@ static int alsa_prepare(struct snd_pcm_substream *substream)
return ret;
stream->is_open = true;
+ xen_snd_front_evtchnl_set_connected(&stream->evt_pair->evt, true);
}
return 0;
@@ -571,20 +574,24 @@ void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl,
{
struct snd_pcm_substream *substream = evtchnl->u.evt.substream;
struct xen_snd_front_pcm_stream_info *stream = stream_get(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t delta, new_hw_ptr, cur_frame;
- cur_frame = bytes_to_frames(substream->runtime, pos_bytes);
+ if (!runtime->buffer_size || !runtime->period_size)
+ return;
+
+ cur_frame = bytes_to_frames(runtime, pos_bytes);
delta = cur_frame - stream->be_cur_frame;
stream->be_cur_frame = cur_frame;
new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr);
- new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size;
+ new_hw_ptr = (new_hw_ptr + delta) % runtime->buffer_size;
atomic_set(&stream->hw_ptr, (int)new_hw_ptr);
stream->out_frames += delta;
- if (stream->out_frames > substream->runtime->period_size) {
- stream->out_frames %= substream->runtime->period_size;
+ if (stream->out_frames > runtime->period_size) {
+ stream->out_frames %= runtime->period_size;
snd_pcm_period_elapsed(substream);
}
}
diff --git a/sound/xen/xen_snd_front_evtchnl.c b/sound/xen/xen_snd_front_evtchnl.c
index bc03f71bf16e3..17a30452c0cca 100644
--- a/sound/xen/xen_snd_front_evtchnl.c
+++ b/sound/xen/xen_snd_front_evtchnl.c
@@ -94,6 +94,9 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id)
guard(mutex)(&channel->ring_io_lock);
+ if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED))
+ return IRQ_HANDLED;
+
prod = page->in_prod;
/* Ensure we see ring contents up to prod. */
virt_rmb();
@@ -430,8 +433,8 @@ fail_to_end:
return ret;
}
-void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair,
- bool is_connected)
+void xen_snd_front_evtchnl_set_connected(struct xen_snd_front_evtchnl *channel,
+ bool is_connected)
{
enum xen_snd_front_evtchnl_state state;
@@ -440,13 +443,16 @@ void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair
else
state = EVTCHNL_STATE_DISCONNECTED;
- scoped_guard(mutex, &evt_pair->req.ring_io_lock) {
- evt_pair->req.state = state;
+ scoped_guard(mutex, &channel->ring_io_lock) {
+ channel->state = state;
}
+}
- scoped_guard(mutex, &evt_pair->evt.ring_io_lock) {
- evt_pair->evt.state = state;
- }
+void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair,
+ bool is_connected)
+{
+ xen_snd_front_evtchnl_set_connected(&evt_pair->req, is_connected);
+ xen_snd_front_evtchnl_set_connected(&evt_pair->evt, is_connected);
}
void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair)
@@ -456,7 +462,11 @@ void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pai
}
scoped_guard(mutex, &evt_pair->evt.ring_io_lock) {
- evt_pair->evt.evt_next_id = 0;
+ evt_pair->evt.evt_id = 0;
+ /* Drop obsolete events queued for the previous stream instance. */
+ evt_pair->evt.u.evt.page->in_cons =
+ evt_pair->evt.u.evt.page->in_prod;
+ /* Ensure the consumer index is visible before stream reuse. */
+ virt_wmb();
}
}
-
diff --git a/sound/xen/xen_snd_front_evtchnl.h b/sound/xen/xen_snd_front_evtchnl.h
index 3675fba705647..f6ebdb09c0298 100644
--- a/sound/xen/xen_snd_front_evtchnl.h
+++ b/sound/xen/xen_snd_front_evtchnl.h
@@ -37,9 +37,9 @@ struct xen_snd_front_evtchnl {
/* State of the event channel. */
enum xen_snd_front_evtchnl_state state;
enum xen_snd_front_evtchnl_type type;
- /* Either response id or incoming event id. */
+ /* Current response id or next expected incoming event id. */
u16 evt_id;
- /* Next request id or next expected event id. */
+ /* Next request id. */
u16 evt_next_id;
/* Shared ring access lock. */
struct mutex ring_io_lock;
@@ -77,6 +77,8 @@ void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info);
int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info);
void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *evtchnl);
+void xen_snd_front_evtchnl_set_connected(struct xen_snd_front_evtchnl *channel,
+ bool is_connected);
void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair,
bool is_connected);