diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 22:42:31 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 22:42:31 +0100 |
| commit | 769e39f484145599bb4a2757165a019a60d27823 (patch) | |
| tree | 67f8809034013b8f0d716a6a097c81893be422d1 /sound | |
| parent | b86bd25caad27a24628d8f9a7eca3e7d72816301 (diff) | |
| parent | 17065203e1bc7e7f2786998d532cd93a06265156 (diff) | |
| download | linux-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')
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, ¶ms); + err = snd_rawmidi_output_params(rfile.output, ¶ms); 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); |
