diff options
author | Mark Brown <broonie@kernel.org> | 2020-10-28 21:36:35 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-10-28 21:36:35 +0000 |
commit | ce038aeaee68f2e41c732b4b91c7185a1cac14b5 (patch) | |
tree | baa463fe66186edf19b3ca65d002f66dd75f09a1 /sound | |
parent | 6d6bc54ab4f2404d46078abc04bf4dee4db01def (diff) | |
parent | 3650b228f83adda7e5ee532e2b90429c03f7b9ec (diff) | |
download | linux-stable-ce038aeaee68f2e41c732b4b91c7185a1cac14b5.tar.gz linux-stable-ce038aeaee68f2e41c732b4b91c7185a1cac14b5.tar.bz2 linux-stable-ce038aeaee68f2e41c732b4b91c7185a1cac14b5.zip |
Merge tag 'v5.10-rc1' into asoc-5.10
Linux 5.10-rc1
Diffstat (limited to 'sound')
82 files changed, 2460 insertions, 1208 deletions
diff --git a/sound/ac97/ac97_core.h b/sound/ac97/ac97_core.h index 0c5956e4b2f3..5a9677c3d4c3 100644 --- a/sound/ac97/ac97_core.h +++ b/sound/ac97/ac97_core.h @@ -3,7 +3,7 @@ * Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr> */ -unsigned int snd_ac97_bus_scan_one(struct ac97_controller *ac97, +unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv, unsigned int codec_num); static inline bool ac97_ids_match(unsigned int id1, unsigned int id2, diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c index d350dbd24305..1c8e8131a716 100644 --- a/sound/aoa/soundbus/i2sbus/pcm.c +++ b/sound/aoa/soundbus/i2sbus/pcm.c @@ -254,12 +254,11 @@ static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, struct pcm_info *pi) { unsigned long flags; - struct completion done; + DECLARE_COMPLETION_ONSTACK(done); long timeout; spin_lock_irqsave(&i2sdev->low_lock, flags); if (pi->dbdma_ring.stopping) { - init_completion(&done); pi->stop_completion = &done; spin_unlock_irqrestore(&i2sdev->low_lock, flags); timeout = wait_for_completion_timeout(&done, HZ); diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 1006458f7f85..66ecbd4d034e 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -475,12 +475,12 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) struct snd_pcm_runtime *runtime; int offset, next_period, block_size; dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", - casr & AC97C_CSR_OVRUN ? " OVRUN" : "", - casr & AC97C_CSR_RXRDY ? " RXRDY" : "", - casr & AC97C_CSR_UNRUN ? " UNRUN" : "", - casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", - casr & AC97C_CSR_TXRDY ? " TXRDY" : "", - !casr ? " NONE" : ""); + (casr & AC97C_CSR_OVRUN) ? " OVRUN" : "", + (casr & AC97C_CSR_RXRDY) ? " RXRDY" : "", + (casr & AC97C_CSR_UNRUN) ? " UNRUN" : "", + (casr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "", + (casr & AC97C_CSR_TXRDY) ? " TXRDY" : "", + !casr ? " NONE" : ""); if ((casr & camr) & AC97C_CSR_ENDTX) { runtime = chip->playback_substream->runtime; block_size = frames_to_bytes(runtime, runtime->period_size); @@ -521,11 +521,11 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) if (sr & AC97C_SR_COEVT) { dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", - cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", - cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", - cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", - cosr & AC97C_CSR_TXRDY ? " TXRDY" : "", - !cosr ? " NONE" : ""); + (cosr & AC97C_CSR_OVRUN) ? " OVRUN" : "", + (cosr & AC97C_CSR_RXRDY) ? " RXRDY" : "", + (cosr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "", + (cosr & AC97C_CSR_TXRDY) ? " TXRDY" : "", + !cosr ? " NONE" : ""); retval = IRQ_HANDLED; } diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 0e53f6f31916..c1fec932c49d 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -513,10 +513,11 @@ EXPORT_SYMBOL(snd_compr_malloc_pages); int snd_compr_free_pages(struct snd_compr_stream *stream) { - struct snd_compr_runtime *runtime = stream->runtime; + struct snd_compr_runtime *runtime; if (snd_BUG_ON(!(stream) || !(stream)->runtime)) return -EINVAL; + runtime = stream->runtime; if (runtime->dma_area == NULL) return 0; if (runtime->dma_buffer_p != &stream->dma_buffer) { @@ -1031,7 +1032,7 @@ static const struct file_operations snd_compr_file_ops = { static int snd_compress_dev_register(struct snd_device *device) { - int ret = -EINVAL; + int ret; struct snd_compr *compr; if (snd_BUG_ON(!device || !device->device_data)) diff --git a/sound/core/control.c b/sound/core/control.c index aa0c0cf182af..421ddc76f264 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -150,14 +150,14 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, return; if (card->shutdown) return; - read_lock(&card->ctl_files_rwlock); + read_lock_irqsave(&card->ctl_files_rwlock, flags); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; #endif list_for_each_entry(ctl, &card->ctl_files, list) { if (!ctl->subscribed) continue; - spin_lock_irqsave(&ctl->read_lock, flags); + spin_lock(&ctl->read_lock); list_for_each_entry(ev, &ctl->events, list) { if (ev->id.numid == id->numid) { ev->mask |= mask; @@ -174,10 +174,10 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, } _found: wake_up(&ctl->change_sleep); - spin_unlock_irqrestore(&ctl->read_lock, flags); + spin_unlock(&ctl->read_lock); kill_fasync(&ctl->fasync, SIGIO, POLL_IN); } - read_unlock(&card->ctl_files_rwlock); + read_unlock_irqrestore(&card->ctl_files_rwlock, flags); } EXPORT_SYMBOL(snd_ctl_notify); @@ -717,22 +717,19 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, } static int snd_ctl_elem_list(struct snd_card *card, - struct snd_ctl_elem_list __user *_list) + struct snd_ctl_elem_list *list) { - struct snd_ctl_elem_list list; struct snd_kcontrol *kctl; struct snd_ctl_elem_id id; unsigned int offset, space, jidx; int err = 0; - if (copy_from_user(&list, _list, sizeof(list))) - return -EFAULT; - offset = list.offset; - space = list.space; + offset = list->offset; + space = list->space; down_read(&card->controls_rwsem); - list.count = card->controls_count; - list.used = 0; + list->count = card->controls_count; + list->used = 0; if (space > 0) { list_for_each_entry(kctl, &card->controls, list) { if (offset >= kctl->count) { @@ -741,12 +738,12 @@ static int snd_ctl_elem_list(struct snd_card *card, } for (jidx = offset; jidx < kctl->count; jidx++) { snd_ctl_build_ioff(&id, kctl, jidx); - if (copy_to_user(list.pids + list.used, &id, + if (copy_to_user(list->pids + list->used, &id, sizeof(id))) { err = -EFAULT; goto out; } - list.used++; + list->used++; if (!--space) goto out; } @@ -755,11 +752,26 @@ static int snd_ctl_elem_list(struct snd_card *card, } out: up_read(&card->controls_rwsem); - if (!err && copy_to_user(_list, &list, sizeof(list))) - err = -EFAULT; return err; } +static int snd_ctl_elem_list_user(struct snd_card *card, + struct snd_ctl_elem_list __user *_list) +{ + struct snd_ctl_elem_list list; + int err; + + if (copy_from_user(&list, _list, sizeof(list))) + return -EFAULT; + err = snd_ctl_elem_list(card, &list); + if (err) + return err; + if (copy_to_user(_list, &list, sizeof(list))) + return -EFAULT; + + return 0; +} + /* Check whether the given kctl info is valid */ static int snd_ctl_check_elem_info(struct snd_card *card, const struct snd_ctl_elem_info *info) @@ -1703,7 +1715,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_CARD_INFO: return snd_ctl_card_info(card, ctl, cmd, argp); case SNDRV_CTL_IOCTL_ELEM_LIST: - return snd_ctl_elem_list(card, argp); + return snd_ctl_elem_list_user(card, argp); case SNDRV_CTL_IOCTL_ELEM_INFO: return snd_ctl_elem_info_user(ctl, argp); case SNDRV_CTL_IOCTL_ELEM_READ: @@ -1939,8 +1951,9 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) { struct snd_ctl_file *kctl; int subdevice = -1; + unsigned long flags; - read_lock(&card->ctl_files_rwlock); + read_lock_irqsave(&card->ctl_files_rwlock, flags); list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == task_pid(current)) { subdevice = kctl->preferred_subdevice[type]; @@ -1948,7 +1961,7 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) break; } } - read_unlock(&card->ctl_files_rwlock); + read_unlock_irqrestore(&card->ctl_files_rwlock, flags); return subdevice; } EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); @@ -1997,13 +2010,14 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; struct snd_ctl_file *ctl; + unsigned long flags; - read_lock(&card->ctl_files_rwlock); + read_lock_irqsave(&card->ctl_files_rwlock, flags); list_for_each_entry(ctl, &card->ctl_files, list) { wake_up(&ctl->change_sleep); kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); } - read_unlock(&card->ctl_files_rwlock); + read_unlock_irqrestore(&card->ctl_files_rwlock, flags); return snd_unregister_device(&card->ctl_dev); } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 02df1d7db9a1..1d708aab9c98 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -22,24 +22,22 @@ struct snd_ctl_elem_list32 { static int snd_ctl_elem_list_compat(struct snd_card *card, struct snd_ctl_elem_list32 __user *data32) { - struct snd_ctl_elem_list __user *data; + struct snd_ctl_elem_list data = {}; compat_caddr_t ptr; int err; - data = compat_alloc_user_space(sizeof(*data)); - /* offset, space, used, count */ - if (copy_in_user(data, data32, 4 * sizeof(u32))) + if (copy_from_user(&data, data32, 4 * sizeof(u32))) return -EFAULT; /* pids */ - if (get_user(ptr, &data32->pids) || - put_user(compat_ptr(ptr), &data->pids)) + if (get_user(ptr, &data32->pids)) return -EFAULT; - err = snd_ctl_elem_list(card, data); + data.pids = compat_ptr(ptr); + err = snd_ctl_elem_list(card, &data); if (err < 0) return err; /* copy the result */ - if (copy_in_user(data32, data, 4 * sizeof(u32))) + if (copy_to_user(data32, &data, 4 * sizeof(u32))) return -EFAULT; return 0; } diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index c61ba52a530a..e97ff8cccb64 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -114,7 +114,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) } static const struct snd_timer_hardware hrtimer_hw __initconst = { - .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET, + .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK, .open = snd_hrtimer_open, .close = snd_hrtimer_close, .start = snd_hrtimer_start, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 21edb8ac95eb..0c029892880a 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -203,28 +203,35 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, } static int snd_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image __user *_info) + struct snd_hwdep_dsp_image *info) { - struct snd_hwdep_dsp_image info; int err; if (! hw->ops.dsp_load) return -ENXIO; - memset(&info, 0, sizeof(info)); - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; - if (info.index >= 32) + if (info->index >= 32) return -EINVAL; /* check whether the dsp was already loaded */ - if (hw->dsp_loaded & (1u << info.index)) + if (hw->dsp_loaded & (1u << info->index)) return -EBUSY; - err = hw->ops.dsp_load(hw, &info); + err = hw->ops.dsp_load(hw, info); if (err < 0) return err; - hw->dsp_loaded |= (1u << info.index); + hw->dsp_loaded |= (1u << info->index); return 0; } +static int snd_hwdep_dsp_load_user(struct snd_hwdep *hw, + struct snd_hwdep_dsp_image __user *_info) +{ + struct snd_hwdep_dsp_image info = {}; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + return snd_hwdep_dsp_load(hw, &info); +} + + static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { @@ -238,7 +245,7 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, case SNDRV_HWDEP_IOCTL_DSP_STATUS: return snd_hwdep_dsp_status(hw, argp); case SNDRV_HWDEP_IOCTL_DSP_LOAD: - return snd_hwdep_dsp_load(hw, argp); + return snd_hwdep_dsp_load_user(hw, argp); } if (hw->ops.ioctl) return hw->ops.ioctl(hw, file, cmd, arg); diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c index bc81db9cb3d4..a0b76706c083 100644 --- a/sound/core/hwdep_compat.c +++ b/sound/core/hwdep_compat.c @@ -19,26 +19,17 @@ struct snd_hwdep_dsp_image32 { static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw, struct snd_hwdep_dsp_image32 __user *src) { - struct snd_hwdep_dsp_image __user *dst; + struct snd_hwdep_dsp_image info = {}; compat_caddr_t ptr; - u32 val; - dst = compat_alloc_user_space(sizeof(*dst)); - - /* index and name */ - if (copy_in_user(dst, src, 4 + 64)) - return -EFAULT; - if (get_user(ptr, &src->image) || - put_user(compat_ptr(ptr), &dst->image)) - return -EFAULT; - if (get_user(val, &src->length) || - put_user(val, &dst->length)) - return -EFAULT; - if (get_user(val, &src->driver_data) || - put_user(val, &dst->driver_data)) + if (copy_from_user(&info, src, 4 + 64) || + get_user(ptr, &src->image) || + get_user(info.length, &src->length) || + get_user(info.driver_data, &src->driver_data)) return -EFAULT; + info.image = compat_ptr(ptr); - return snd_hwdep_dsp_load(hw, dst); + return snd_hwdep_dsp_load(hw, &info); } enum { diff --git a/sound/core/init.c b/sound/core/init.c index 0478847ba2b8..764dbe673d48 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -519,10 +519,9 @@ EXPORT_SYMBOL(snd_card_free_when_closed); */ int snd_card_free(struct snd_card *card) { - struct completion released; + DECLARE_COMPLETION_ONSTACK(released); int ret; - init_completion(&released); card->release_completion = &released; ret = snd_card_free_when_closed(card); if (ret) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index ad74ea9cbff5..0aeeb6244ff6 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -157,8 +157,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, * so if we fail to malloc, try to fetch memory traditionally. */ dmab->dev.type = SNDRV_DMA_TYPE_DEV; -#endif /* CONFIG_GENERIC_ALLOCATOR */ fallthrough; +#endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index b6d2331a82f7..be5714f1bb58 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -991,11 +991,13 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); /* Avoid concurrent access to runtime via PCM timer interface */ - if (substream->timer) + if (substream->timer) { spin_lock_irq(&substream->timer->lock); - substream->runtime = NULL; - if (substream->timer) + substream->runtime = NULL; spin_unlock_irq(&substream->timer->lock); + } else { + substream->runtime = NULL; + } kfree(runtime); put_pid(substream->pid); substream->pid = NULL; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 1bf6a3d9e0c2..4f03ba8ed0ae 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -377,7 +377,7 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne */ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) { - struct snd_card *card = substream->pcm->card; + struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_dma_buffer *dmab = NULL; @@ -387,6 +387,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) SNDRV_DMA_TYPE_UNKNOWN)) return -EINVAL; runtime = substream->runtime; + card = substream->pcm->card; if (runtime->dma_buffer_p) { /* perphaps, we might free the large DMA memory region diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2a688b711a9a..c78720a3299c 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -35,7 +35,7 @@ module_param_array(amidi_map, int, NULL, 0444); MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device."); #endif /* CONFIG_SND_OSSEMUL */ -static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); +static int snd_rawmidi_free(struct snd_rawmidi *rmidi); static int snd_rawmidi_dev_free(struct snd_device *device); static int snd_rawmidi_dev_register(struct snd_device *device); static int snd_rawmidi_dev_disconnect(struct snd_device *device); diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index c8b9c0b315d8..250a92b18726 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -174,9 +174,12 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (snd_BUG_ON(!dp)) return -ENXIO; - mutex_lock(®ister_mutex); + if (cmd != SNDCTL_SEQ_SYNC && + mutex_lock_interruptible(®ister_mutex)) + return -ERESTARTSYS; rc = snd_seq_oss_ioctl(dp, cmd, arg); - mutex_unlock(®ister_mutex); + if (cmd != SNDCTL_SEQ_SYNC) + mutex_unlock(®ister_mutex); return rc; } diff --git a/sound/core/timer.c b/sound/core/timer.c index 6e27d87b18ed..765ea66665a8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -173,7 +173,7 @@ EXPORT_SYMBOL(snd_timer_instance_free); */ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) { - struct snd_timer *timer = NULL; + struct snd_timer *timer; list_for_each_entry(timer, &snd_timer_list, device_list) { if (timer->tmr_class != tid->dev_class) @@ -813,12 +813,12 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer, } /* - * timer tasklet + * timer work * */ -static void snd_timer_tasklet(struct tasklet_struct *t) +static void snd_timer_work(struct work_struct *work) { - struct snd_timer *timer = from_tasklet(timer, t, task_queue); + struct snd_timer *timer = container_of(work, struct snd_timer, task_work); unsigned long flags; if (timer->card && timer->card->shutdown) { @@ -843,7 +843,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) unsigned long resolution; struct list_head *ack_list_head; unsigned long flags; - int use_tasklet = 0; + bool use_work = false; if (timer == NULL) return; @@ -884,7 +884,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) --timer->running; list_del_init(&ti->active_list); } - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || + if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) ack_list_head = &timer->ack_list_head; else @@ -919,11 +919,11 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) snd_timer_process_callbacks(timer, &timer->ack_list_head); /* do we have any slow callbacks? */ - use_tasklet = !list_empty(&timer->sack_list_head); + use_work = !list_empty(&timer->sack_list_head); spin_unlock_irqrestore(&timer->lock, flags); - if (use_tasklet) - tasklet_schedule(&timer->task_queue); + if (use_work) + queue_work(system_highpri_wq, &timer->task_work); } EXPORT_SYMBOL(snd_timer_interrupt); @@ -967,7 +967,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, INIT_LIST_HEAD(&timer->ack_list_head); INIT_LIST_HEAD(&timer->sack_list_head); spin_lock_init(&timer->lock); - tasklet_setup(&timer->task_queue, snd_timer_tasklet); + INIT_WORK(&timer->task_work, snd_timer_work); timer->max_instances = 1000; /* default limit per timer */ if (card != NULL) { timer->module = card->module; @@ -1200,7 +1200,7 @@ static int snd_timer_s_close(struct snd_timer *timer) static const struct snd_timer_hardware snd_timer_system = { - .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, + .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK, .resolution = 1000000000L / HZ, .ticks = 10000000L, .close = snd_timer_s_close, @@ -1280,8 +1280,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, list_for_each_entry(ti, &timer->open_list_head, open_list) snd_iprintf(buffer, " Client %s : %s\n", ti->owner ? ti->owner : "unknown", - ti->flags & (SNDRV_TIMER_IFLG_START | - SNDRV_TIMER_IFLG_RUNNING) + (ti->flags & (SNDRV_TIMER_IFLG_START | + SNDRV_TIMER_IFLG_RUNNING)) ? "running" : "stopped"); } mutex_unlock(®ister_mutex); diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 251eaf1152e2..c91356326699 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -110,7 +110,7 @@ struct loopback_cable { struct { int stream; struct snd_timer_id id; - struct tasklet_struct event_tasklet; + struct work_struct event_work; struct snd_timer_instance *instance; } snd_timer; }; @@ -309,8 +309,8 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) */ snd_timer_close(cable->snd_timer.instance); - /* wait till drain tasklet has finished if requested */ - tasklet_kill(&cable->snd_timer.event_tasklet); + /* wait till drain work has finished if requested */ + cancel_work_sync(&cable->snd_timer.event_work); snd_timer_instance_free(cable->snd_timer.instance); memset(&cable->snd_timer, 0, sizeof(cable->snd_timer)); @@ -794,11 +794,11 @@ static void loopback_snd_timer_function(struct snd_timer_instance *timeri, resolution); } -static void loopback_snd_timer_tasklet(unsigned long arg) +static void loopback_snd_timer_work(struct work_struct *work) { - struct snd_timer_instance *timeri = (struct snd_timer_instance *)arg; - struct loopback_cable *cable = timeri->callback_data; + struct loopback_cable *cable; + cable = container_of(work, struct loopback_cable, snd_timer.event_work); loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0); } @@ -828,9 +828,9 @@ static void loopback_snd_timer_event(struct snd_timer_instance *timeri, * state the streaming will be aborted by the usual timeout. It * should not be aborted here because may be the timer sound * card does only a recovery and the timer is back soon. - * This tasklet triggers loopback_snd_timer_tasklet() + * This work triggers loopback_snd_timer_work() */ - tasklet_schedule(&cable->snd_timer.event_tasklet); + schedule_work(&cable->snd_timer.event_work); } } @@ -1124,7 +1124,7 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) err = -ENOMEM; goto exit; } - /* The callback has to be called from another tasklet. If + /* The callback has to be called from another work. If * SNDRV_TIMER_IFLG_FAST is specified it will be called from the * snd_pcm_period_elapsed() call of the selected sound card. * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave(). @@ -1137,9 +1137,8 @@ static int loopback_snd_timer_open(struct loopback_pcm *dpcm) timeri->callback_data = (void *)cable; timeri->ccallback = loopback_snd_timer_event; - /* initialise a tasklet used for draining */ - tasklet_init(&cable->snd_timer.event_tasklet, - loopback_snd_timer_tasklet, (unsigned long)timeri); + /* initialise a work used for draining */ + INIT_WORK(&cable->snd_timer.event_work, loopback_snd_timer_work); /* The mutex loopback->cable_lock is kept locked. * Therefore snd_timer_open() cannot be called a second time diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 4e79293d7f11..ed40d0f7432c 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -23,10 +23,10 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " #define DMIX_WANTS_S16 1 /* - * Call snd_pcm_period_elapsed in a tasklet + * Call snd_pcm_period_elapsed in a work * This avoids spinlock messes and long-running irq contexts */ -static void pcsp_call_pcm_elapsed(unsigned long priv) +static void pcsp_call_pcm_elapsed(struct work_struct *work) { if (atomic_read(&pcsp_chip.timer_active)) { struct snd_pcm_substream *substream; @@ -36,7 +36,7 @@ static void pcsp_call_pcm_elapsed(unsigned long priv) } } -static DECLARE_TASKLET_OLD(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed); +static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed); /* write the port and returns the next expire time in ns; * called at the trigger-start and in hrtimer callback @@ -119,11 +119,9 @@ static void pcsp_pointer_update(struct snd_pcsp *chip) if (periods_elapsed) { chip->period_ptr += periods_elapsed * period_bytes; chip->period_ptr %= buffer_bytes; + queue_work(system_highpri_wq, &pcsp_pcm_work); } spin_unlock_irqrestore(&chip->substream_lock, flags); - - if (periods_elapsed) - tasklet_schedule(&pcsp_pcm_tasklet); } enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) @@ -196,7 +194,7 @@ void pcsp_sync_stop(struct snd_pcsp *chip) pcsp_stop_playing(chip); local_irq_enable(); hrtimer_cancel(&chip->timer); - tasklet_kill(&pcsp_pcm_tasklet); + cancel_work_sync(&pcsp_pcm_work); } static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 38603cb2bd5b..c876cf9b5005 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -467,7 +467,7 @@ static int portman_probe(struct parport *p) parport_write_control(p, 0); /* Reset Strobe=0. */ /* Check if Tx circuitry is functioning properly. If initialized - * unit TxEmpty is false, send out char and see if if goes true. + * unit TxEmpty is false, send out char and see if it goes true. */ /* 8 */ parport_write_control(p, TXDATA0); /* Tx channel 0, strobe off. */ diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 26d591fe6a6b..d5c65cab195b 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -597,9 +597,9 @@ static void vx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *b snd_iprintf(buffer, "%s\n", chip->card->longname); snd_iprintf(buffer, "Xilinx Firmware: %s\n", - chip->chip_status & VX_STAT_XILINX_LOADED ? "Loaded" : "No"); + (chip->chip_status & VX_STAT_XILINX_LOADED) ? "Loaded" : "No"); snd_iprintf(buffer, "Device Initialized: %s\n", - chip->chip_status & VX_STAT_DEVICE_INIT ? "Yes" : "No"); + (chip->chip_status & VX_STAT_DEVICE_INIT) ? "Yes" : "No"); snd_iprintf(buffer, "DSP audio info:"); if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME) snd_iprintf(buffer, " realtime"); diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 664b9efa9a50..3d2e3bcafca8 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -60,7 +60,6 @@ static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime * *buf++ = vx_inb(chip, RXL); if (++offset >= pipe->buffer_bytes) { offset = 0; - buf = (unsigned char *)runtime->dma_area; } pipe->hw_ptr = offset; } @@ -530,7 +529,6 @@ static int vx_pcm_playback_open(struct snd_pcm_substream *subs) err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */ if (err < 0) return err; - chip->playback_pipes[audio] = pipe; } /* open for playback */ pipe->references++; diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index ee1c428b1fd3..4e2f2bb7879f 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -64,7 +64,7 @@ #define IT_PKT_HEADER_SIZE_CIP 8 // For 2 CIP header. #define IT_PKT_HEADER_SIZE_NO_CIP 0 // Nothing. -static void pcm_period_tasklet(struct tasklet_struct *t); +static void pcm_period_work(struct work_struct *work); /** * amdtp_stream_init - initialize an AMDTP stream structure @@ -94,7 +94,7 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, s->flags = flags; s->context = ERR_PTR(-1); mutex_init(&s->mutex); - tasklet_setup(&s->period_tasklet, pcm_period_tasklet); + INIT_WORK(&s->period_work, pcm_period_work); s->packet_index = 0; init_waitqueue_head(&s->callback_wait); @@ -203,7 +203,7 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, // Linux driver for 1394 OHCI controller voluntarily flushes isoc // context when total size of accumulated context header reaches - // PAGE_SIZE. This kicks tasklet for the isoc context and brings + // PAGE_SIZE. This kicks work for the isoc context and brings // callback in the middle of scheduled interrupts. // Although AMDTP streams in the same domain use the same events per // IRQ, use the largest size of context header between IT/IR contexts. @@ -333,7 +333,7 @@ EXPORT_SYMBOL(amdtp_stream_get_max_payload); */ void amdtp_stream_pcm_prepare(struct amdtp_stream *s) { - tasklet_kill(&s->period_tasklet); + cancel_work_sync(&s->period_work); s->pcm_buffer_pointer = 0; s->pcm_period_pointer = 0; } @@ -437,13 +437,14 @@ static void update_pcm_pointers(struct amdtp_stream *s, s->pcm_period_pointer += frames; if (s->pcm_period_pointer >= pcm->runtime->period_size) { s->pcm_period_pointer -= pcm->runtime->period_size; - tasklet_hi_schedule(&s->period_tasklet); + queue_work(system_highpri_wq, &s->period_work); } } -static void pcm_period_tasklet(struct tasklet_struct *t) +static void pcm_period_work(struct work_struct *work) { - struct amdtp_stream *s = from_tasklet(s, t, period_tasklet); + struct amdtp_stream *s = container_of(work, struct amdtp_stream, + period_work); struct snd_pcm_substream *pcm = READ_ONCE(s->pcm); if (pcm) @@ -794,7 +795,7 @@ static void generate_pkt_descs(struct amdtp_stream *s, struct pkt_desc *descs, static inline void cancel_stream(struct amdtp_stream *s) { s->packet_index = -1; - if (in_interrupt()) + if (current_work() == &s->period_work) amdtp_stream_pcm_abort(s); WRITE_ONCE(s->pcm_buffer_pointer, SNDRV_PCM_POS_XRUN); } @@ -1184,7 +1185,7 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, if (irq_target && amdtp_stream_running(irq_target)) { // This function is called in software IRQ context of - // period_tasklet or process context. + // period_work or process context. // // When the software IRQ context was scheduled by software IRQ // context of IT contexts, queued packets were already handled. @@ -1195,9 +1196,9 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d, // immediately to keep better granularity of PCM pointer. // // Later, the process context will sometimes schedules software - // IRQ context of the period_tasklet. Then, no need to flush the + // IRQ context of the period_work. Then, no need to flush the // queue by the same reason as described in the above - if (!in_interrupt()) { + if (current_work() != &s->period_work) { // Queued packet should be processed without any kernel // preemption to keep latency against bus cycle. preempt_disable(); @@ -1263,7 +1264,7 @@ static void amdtp_stream_stop(struct amdtp_stream *s) return; } - tasklet_kill(&s->period_tasklet); + cancel_work_sync(&s->period_work); fw_iso_context_stop(s->context); fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 703b710aaf7f..2ceb57d1d58e 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -163,7 +163,7 @@ struct amdtp_stream { /* For a PCM substream processing. */ struct snd_pcm_substream *pcm; - struct tasklet_struct period_tasklet; + struct work_struct period_work; snd_pcm_uframes_t pcm_buffer_pointer; unsigned int pcm_period_pointer; diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c index 45b740f44c45..c362eb38ab90 100644 --- a/sound/firewire/bebob/bebob_hwdep.c +++ b/sound/firewire/bebob/bebob_hwdep.c @@ -36,12 +36,11 @@ hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, } memset(&event, 0, sizeof(event)); + count = min_t(long, count, sizeof(event.lock_status)); if (bebob->dev_lock_changed) { event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; event.lock_status.status = (bebob->dev_lock_count > 0); bebob->dev_lock_changed = false; - - count = min_t(long, count, sizeof(event.lock_status)); } spin_unlock_irq(&bebob->lock); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 980580dfbb39..a0d5db1d8eb2 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -148,7 +148,7 @@ pcm_init_hw_params(struct snd_efw *efw, } /* limit rates */ - runtime->hw.rates = efw->supported_sampling_rate, + runtime->hw.rates = efw->supported_sampling_rate; snd_pcm_limit_hw_rates(runtime); limit_channels(&runtime->hw, pcm_channels); diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 89126c6fd216..bb37e7e0bd79 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -210,12 +210,14 @@ static int hdac_component_master_bind(struct device *dev) goto module_put; } + complete_all(&acomp->master_bind_complete); return 0; module_put: module_put(acomp->ops->owner); out_unbind: component_unbind_all(dev, acomp); + complete_all(&acomp->master_bind_complete); return ret; } @@ -296,6 +298,7 @@ int snd_hdac_acomp_init(struct hdac_bus *bus, if (!acomp) return -ENOMEM; acomp->audio_ops = aops; + init_completion(&acomp->master_bind_complete); bus->audio_component = acomp; devres_add(dev, acomp); diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 3c2db3816029..454474ac5716 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -11,9 +11,7 @@ #include <sound/hda_i915.h> #include <sound/hda_register.h> -static struct completion bind_complete; - -#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ +#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \ ((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) @@ -41,7 +39,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) return; /* only for i915 binding */ - if (!CONTROLLER_IN_GPU(pci)) + if (!IS_HSW_CONTROLLER(pci)) return; /* only HSW/BDW */ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); @@ -73,11 +71,49 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); +/* returns true if the devices can be connected for audio */ +static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac) +{ + struct pci_bus *bus_a = i915->bus, *bus_b = hdac->bus; + + /* directly connected on the same bus */ + if (bus_a == bus_b) + return true; + + /* + * on i915 discrete GPUs with embedded HDA audio, the two + * devices are connected via 2nd level PCI bridge + */ + bus_a = bus_a->parent; + bus_b = bus_b->parent; + if (!bus_a || !bus_b) + return false; + bus_a = bus_a->parent; + bus_b = bus_b->parent; + if (bus_a && bus_a == bus_b) + return true; + + return false; +} + static int i915_component_master_match(struct device *dev, int subcomponent, void *data) { - return !strcmp(dev->driver->name, "i915") && - subcomponent == I915_COMPONENT_AUDIO; + struct pci_dev *hdac_pci, *i915_pci; + struct hdac_bus *bus = data; + + if (!dev_is_pci(dev)) + return 0; + + hdac_pci = to_pci_dev(bus->dev); + i915_pci = to_pci_dev(dev); + + if (!strcmp(dev->driver->name, "i915") && + subcomponent == I915_COMPONENT_AUDIO && + connectivity_check(i915_pci, hdac_pci)) + return 1; + + return 0; } /* check whether intel graphics is present */ @@ -92,19 +128,6 @@ static bool i915_gfx_present(void) return pci_dev_present(ids); } -static int i915_master_bind(struct device *dev, - struct drm_audio_component *acomp) -{ - complete_all(&bind_complete); - /* clear audio_ops here as it was needed only for completion call */ - acomp->audio_ops = NULL; - return 0; -} - -static const struct drm_audio_component_audio_ops i915_init_ops = { - .master_bind = i915_master_bind -}; - /** * snd_hdac_i915_init - Initialize i915 audio component * @bus: HDA core bus @@ -125,9 +148,7 @@ int snd_hdac_i915_init(struct hdac_bus *bus) if (!i915_gfx_present()) return -ENODEV; - init_completion(&bind_complete); - - err = snd_hdac_acomp_init(bus, &i915_init_ops, + err = snd_hdac_acomp_init(bus, NULL, i915_component_master_match, sizeof(struct i915_audio_component) - sizeof(*acomp)); if (err < 0) @@ -139,8 +160,8 @@ int snd_hdac_i915_init(struct hdac_bus *bus) if (!IS_ENABLED(CONFIG_MODULES) || !request_module("i915")) { /* 60s timeout */ - wait_for_completion_timeout(&bind_complete, - msecs_to_jiffies(60 * 1000)); + wait_for_completion_timeout(&acomp->master_bind_complete, + msecs_to_jiffies(60 * 1000)); } } if (!acomp->ops) { diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index ec84bc4c3a6e..9ac9b58d7c8c 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -441,7 +441,8 @@ static inline void hal2_stop_adc(struct snd_hal2 *hal2) hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; } -static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) +static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec, + enum dma_data_direction buffer_dir) { struct device *dev = hal2->card->dev; struct hal2_desc *desc; @@ -449,15 +450,15 @@ static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) int count = H2_BUF_SIZE / H2_BLOCK_SIZE; int i; - codec->buffer = dma_alloc_attrs(dev, H2_BUF_SIZE, &buffer_dma, - GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); + codec->buffer = dma_alloc_noncoherent(dev, H2_BUF_SIZE, &buffer_dma, + buffer_dir, GFP_KERNEL); if (!codec->buffer) return -ENOMEM; - desc = dma_alloc_attrs(dev, count * sizeof(struct hal2_desc), - &desc_dma, GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); + desc = dma_alloc_noncoherent(dev, count * sizeof(struct hal2_desc), + &desc_dma, DMA_BIDIRECTIONAL, GFP_KERNEL); if (!desc) { - dma_free_attrs(dev, H2_BUF_SIZE, codec->buffer, buffer_dma, - DMA_ATTR_NON_CONSISTENT); + dma_free_noncoherent(dev, H2_BUF_SIZE, codec->buffer, buffer_dma, + buffer_dir); return -ENOMEM; } codec->buffer_dma = buffer_dma; @@ -470,20 +471,22 @@ static int hal2_alloc_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc); desc++; } - dma_cache_sync(dev, codec->desc, count * sizeof(struct hal2_desc), - DMA_TO_DEVICE); + dma_sync_single_for_device(dev, codec->desc_dma, + count * sizeof(struct hal2_desc), + DMA_BIDIRECTIONAL); codec->desc_count = count; return 0; } -static void hal2_free_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec) +static void hal2_free_dmabuf(struct snd_hal2 *hal2, struct hal2_codec *codec, + enum dma_data_direction buffer_dir) { struct device *dev = hal2->card->dev; - dma_free_attrs(dev, codec->desc_count * sizeof(struct hal2_desc), - codec->desc, codec->desc_dma, DMA_ATTR_NON_CONSISTENT); - dma_free_attrs(dev, H2_BUF_SIZE, codec->buffer, codec->buffer_dma, - DMA_ATTR_NON_CONSISTENT); + dma_free_noncoherent(dev, codec->desc_count * sizeof(struct hal2_desc), + codec->desc, codec->desc_dma, DMA_BIDIRECTIONAL); + dma_free_noncoherent(dev, H2_BUF_SIZE, codec->buffer, codec->buffer_dma, + buffer_dir); } static const struct snd_pcm_hardware hal2_pcm_hw = { @@ -509,21 +512,16 @@ static int hal2_playback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - int err; runtime->hw = hal2_pcm_hw; - - err = hal2_alloc_dmabuf(hal2, &hal2->dac); - if (err) - return err; - return 0; + return hal2_alloc_dmabuf(hal2, &hal2->dac, DMA_TO_DEVICE); } static int hal2_playback_close(struct snd_pcm_substream *substream) { struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - hal2_free_dmabuf(hal2, &hal2->dac); + hal2_free_dmabuf(hal2, &hal2->dac, DMA_TO_DEVICE); return 0; } @@ -579,7 +577,9 @@ static void hal2_playback_transfer(struct snd_pcm_substream *substream, unsigned char *buf = hal2->dac.buffer + rec->hw_data; memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes); - dma_cache_sync(hal2->card->dev, buf, bytes, DMA_TO_DEVICE); + dma_sync_single_for_device(hal2->card->dev, + hal2->dac.buffer_dma + rec->hw_data, bytes, + DMA_TO_DEVICE); } @@ -597,22 +597,16 @@ static int hal2_capture_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - struct hal2_codec *adc = &hal2->adc; - int err; runtime->hw = hal2_pcm_hw; - - err = hal2_alloc_dmabuf(hal2, adc); - if (err) - return err; - return 0; + return hal2_alloc_dmabuf(hal2, &hal2->adc, DMA_FROM_DEVICE); } static int hal2_capture_close(struct snd_pcm_substream *substream) { struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); - hal2_free_dmabuf(hal2, &hal2->adc); + hal2_free_dmabuf(hal2, &hal2->adc, DMA_FROM_DEVICE); return 0; } @@ -667,7 +661,9 @@ static void hal2_capture_transfer(struct snd_pcm_substream *substream, struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); unsigned char *buf = hal2->adc.buffer + rec->hw_data; - dma_cache_sync(hal2->card->dev, buf, bytes, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(hal2->card->dev, + hal2->adc.buffer_dma + rec->hw_data, bytes, + DMA_FROM_DEVICE); memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes); } diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 35e76480306e..5e1f9f10051b 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -117,7 +117,6 @@ struct snd_card_asihpi { * snd_card_asihpi_timer_function(). */ struct snd_card_asihpi_pcm *llmode_streampriv; - struct tasklet_struct t; void (*pcm_start)(struct snd_pcm_substream *substream); void (*pcm_stop)(struct snd_pcm_substream *substream); @@ -258,15 +257,6 @@ static inline u16 hpi_stream_group_reset(u32 h_stream) return hpi_instream_group_reset(h_stream); } -static inline u16 hpi_stream_group_get_map( - u32 h_stream, u32 *mo, u32 *mi) -{ - if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_group_get_map(h_stream, mo, mi); - else - return hpi_instream_group_get_map(h_stream, mo, mi); -} - static u16 handle_error(u16 err, int line, char *filename) { if (err) @@ -547,9 +537,7 @@ static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) card = snd_pcm_substream_chip(substream); WARN_ON(in_interrupt()); - tasklet_disable(&card->t); card->llmode_streampriv = dpcm; - tasklet_enable(&card->t); hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, HPI_ADAPTER_PROPERTY_IRQ_RATE, @@ -565,13 +553,7 @@ static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream) hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); - if (in_interrupt()) - card->llmode_streampriv = NULL; - else { - tasklet_disable(&card->t); - card->llmode_streampriv = NULL; - tasklet_enable(&card->t); - } + card->llmode_streampriv = NULL; } static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, @@ -921,10 +903,9 @@ static void snd_card_asihpi_timer_function(struct timer_list *t) add_timer(&dpcm->timer); } -static void snd_card_asihpi_int_task(struct tasklet_struct *t) +static void snd_card_asihpi_isr(struct hpi_adapter *a) { - struct snd_card_asihpi *asihpi = from_tasklet(asihpi, t, t); - struct hpi_adapter *a = asihpi->hpi; + struct snd_card_asihpi *asihpi; WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; @@ -933,15 +914,6 @@ static void snd_card_asihpi_int_task(struct tasklet_struct *t) &asihpi->llmode_streampriv->timer); } -static void snd_card_asihpi_isr(struct hpi_adapter *a) -{ - struct snd_card_asihpi *asihpi; - - WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); - asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; - tasklet_schedule(&asihpi->t); -} - /***************************** PLAYBACK OPS ****************/ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream * substream) @@ -2871,7 +2843,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, if (hpi->interrupt_mode) { asihpi->pcm_start = snd_card_asihpi_pcm_int_start; asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop; - tasklet_setup(&asihpi->t, snd_card_asihpi_int_task); hpi->interrupt_callback = snd_card_asihpi_isr; } else { asihpi->pcm_start = snd_card_asihpi_pcm_timer_start; @@ -2960,14 +2931,12 @@ __nodev: static void snd_asihpi_remove(struct pci_dev *pci_dev) { struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); - struct snd_card_asihpi *asihpi = hpi->snd_card->private_data; /* Stop interrupts */ if (hpi->interrupt_mode) { hpi->interrupt_callback = NULL; hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index, HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); - tasklet_kill(&asihpi->t); } snd_card_free(hpi->snd_card); diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 496dcde9715d..bb31b7fe867d 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -329,8 +329,17 @@ static irqreturn_t asihpi_isr(int irq, void *dev_id) asihpi_irq_count, a->adapter->type, a->adapter->index); */ if (a->interrupt_callback) - a->interrupt_callback(a); + return IRQ_WAKE_THREAD; + + return IRQ_HANDLED; +} + +static irqreturn_t asihpi_isr_thread(int irq, void *dev_id) +{ + struct hpi_adapter *a = dev_id; + if (a->interrupt_callback) + a->interrupt_callback(a); return IRQ_HANDLED; } @@ -343,7 +352,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, struct hpi_message hm; struct hpi_response hr; struct hpi_adapter adapter; - struct hpi_pci pci; + struct hpi_pci pci = { 0 }; memset(&adapter, 0, sizeof(adapter)); @@ -478,8 +487,9 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, } /* Note: request_irq calls asihpi_isr here */ - if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED, - "asihpi", &adapters[adapter_index])) { + if (request_threaded_irq(pci_dev->irq, asihpi_isr, + asihpi_isr_thread, IRQF_SHARED, + "asihpi", &adapters[adapter_index])) { dev_err(&pci_dev->dev, "request_irq(%d) failed\n", pci_dev->irq); goto err; @@ -499,7 +509,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, return 0; err: - for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { + while (--idx >= 0) { if (pci.ap_mem_base[idx]) { iounmap(pci.ap_mem_base[idx]); pci.ap_mem_base[idx] = NULL; diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h index 26f7cf455a1e..9e551bc46264 100644 --- a/sound/pci/asihpi/hpios.h +++ b/sound/pci/asihpi/hpios.h @@ -67,7 +67,7 @@ struct hpi_ioctl_linux { }; /* Conflict?: H is already used by a number of drivers hid, bluetooth hci, - and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is ununsed command + and some sound drivers sb16, hdsp, emu10k. AFAIK 0xFC is unused command */ #define HPI_IOCTL_LINUX _IOWR('H', 0xFC, struct hpi_ioctl_linux) diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 824f4ac1a8ce..4dc01647753c 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -350,7 +350,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, */ if (!cfg->line_outs && cfg->hp_outs > 1 && !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { - int i = 0; + i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ if ((hp_out[i].seq & 0x0f) == 0x0f) { diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e96a87f1b611..a356c21edb90 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1000,6 +1000,9 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card, if (err < 0) goto error; + /* PM runtime needs to be enabled later after binding codec */ + pm_runtime_forbid(&codec->core.dev); + return 0; error: diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 36a9dbc33aa0..749b88090970 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -368,7 +368,8 @@ enum { #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ ((pci)->device == 0x0c0c) || \ ((pci)->device == 0x0d0c) || \ - ((pci)->device == 0x160c)) + ((pci)->device == 0x160c) || \ + ((pci)->device == 0x490d)) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) @@ -1001,12 +1002,14 @@ static void __azx_runtime_resume(struct azx *chip, bool from_rt) azx_init_pci(chip); hda_intel_init_chip(chip, true); - if (status && from_rt) { - list_for_each_codec(codec, &chip->bus) - if (!codec->relaxed_resume && - (status & (1 << codec->addr))) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); + if (from_rt) { + list_for_each_codec(codec, &chip->bus) { + if (codec->relaxed_resume) + continue; + + if (codec->forced_resume || (status & (1 << codec->addr))) + pm_request_resume(hda_codec_dev(codec)); + } } /* power down again for link-controlled chips */ @@ -2493,6 +2496,9 @@ static const struct pci_device_id azx_ids[] = { /* Tigerlake-H */ { PCI_DEVICE(0x8086, 0x43c8), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* DG1 */ + { PCI_DEVICE(0x8086, 0x490d), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Elkhart Lake */ { PCI_DEVICE(0x8086, 0x4b55), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 02cc682caa55..588059428d8f 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -275,6 +275,23 @@ int snd_hda_jack_detect_state_mst(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); +static struct hda_jack_callback * +find_callback_from_list(struct hda_jack_tbl *jack, + hda_jack_callback_fn func) +{ + struct hda_jack_callback *cb; + + if (!func) + return NULL; + + for (cb = jack->callback; cb; cb = cb->next) { + if (cb->func == func) + return cb; + } + + return NULL; +} + /** * snd_hda_jack_detect_enable_mst - enable the jack-detection * @codec: the HDA codec @@ -297,7 +314,10 @@ snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, jack = snd_hda_jack_tbl_new(codec, nid, dev_id); if (!jack) return ERR_PTR(-ENOMEM); - if (func) { + + callback = find_callback_from_list(jack, func); + + if (func && !callback) { callback = kzalloc(sizeof(*callback), GFP_KERNEL); if (!callback) return ERR_PTR(-ENOMEM); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 727b6d3ba454..8ceaf0ef5df1 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -77,7 +77,7 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, struct hda_jack_callback * snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, - int dev_id, hda_jack_callback_fn cb); + int dev_id, hda_jack_callback_fn func); /** * snd_hda_jack_detect_enable - enable the jack-detection diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8c28b1022f49..5beb8aa44ecd 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -100,7 +100,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv); + unsigned int size, unsigned int __user *_tlv); int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, @@ -119,7 +119,7 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int dir, int idx, int mask, int val); int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx, int mask, int val); + int direction, int idx, int mask, int val); int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, @@ -198,7 +198,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec, unsigned int *cur_val); int snd_hda_add_imux_item(struct hda_codec *codec, struct hda_input_mux *imux, const char *label, - int index, int *type_index_ret); + int index, int *type_idx); /* * Multi-channel / digital-out PCM helper @@ -642,7 +642,7 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, */ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo, - int num_entries, const char * const *texts); + int num_items, const char * const *texts); #define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b7dbf2e7f77a..e0c38f2735c6 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -38,6 +38,8 @@ #define FLOAT_ONE 0x3f800000 #define FLOAT_TWO 0x40000000 #define FLOAT_THREE 0x40400000 +#define FLOAT_FIVE 0x40a00000 +#define FLOAT_SIX 0x40c00000 #define FLOAT_EIGHT 0x41000000 #define FLOAT_MINUS_5 0xc0a00000 @@ -80,11 +82,11 @@ MODULE_FIRMWARE(R3DI_EFX_FILE); static const char *const dirstr[2] = { "Playback", "Capture" }; -#define NUM_OF_OUTPUTS 3 +#define NUM_OF_OUTPUTS 2 +static const char *const out_type_str[2] = { "Speakers", "Headphone" }; enum { SPEAKER_OUT, HEADPHONE_OUT, - SURROUND_OUT }; enum { @@ -143,7 +145,12 @@ enum { MIC_BOOST_ENUM, AE5_HEADPHONE_GAIN_ENUM, AE5_SOUND_FILTER_ENUM, - ZXR_HEADPHONE_GAIN + ZXR_HEADPHONE_GAIN, + SPEAKER_CHANNEL_CFG_ENUM, + SPEAKER_FULL_RANGE_FRONT, + SPEAKER_FULL_RANGE_REAR, + BASS_REDIRECTION, + BASS_REDIRECTION_XOVER, #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) }; @@ -589,46 +596,108 @@ static const struct ct_eq_preset ca0132_alt_eq_presets[] = { } }; -/* DSP command sequences for ca0132_alt_select_out */ -#define ALT_OUT_SET_MAX_COMMANDS 9 /* Max number of commands in sequence */ -struct ca0132_alt_out_set { - char *name; /*preset name*/ - unsigned char commands; - unsigned int mids[ALT_OUT_SET_MAX_COMMANDS]; - unsigned int reqs[ALT_OUT_SET_MAX_COMMANDS]; - unsigned int vals[ALT_OUT_SET_MAX_COMMANDS]; +/* + * DSP reqs for handling full-range speakers/bass redirection. If a speaker is + * set as not being full range, and bass redirection is enabled, all + * frequencies below the crossover frequency are redirected to the LFE + * channel. If the surround configuration has no LFE channel, this can't be + * enabled. X-Bass must be disabled when using these. + */ +enum speaker_range_reqs { + SPEAKER_BASS_REDIRECT = 0x15, + SPEAKER_BASS_REDIRECT_XOVER_FREQ = 0x16, + /* Between 0x16-0x1a are the X-Bass reqs. */ + SPEAKER_FULL_RANGE_FRONT_L_R = 0x1a, + SPEAKER_FULL_RANGE_CENTER_LFE = 0x1b, + SPEAKER_FULL_RANGE_REAR_L_R = 0x1c, + SPEAKER_FULL_RANGE_SURROUND_L_R = 0x1d, + SPEAKER_BASS_REDIRECT_SUB_GAIN = 0x1e, +}; + +/* + * Definitions for the DSP req's to handle speaker tuning. These all belong to + * module ID 0x96, the output effects module. + */ +enum speaker_tuning_reqs { + /* + * Currently, this value is always set to 0.0f. However, on Windows, + * when selecting certain headphone profiles on the new Sound Blaster + * connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is + * sent. This gets the speaker EQ address area, which is then used to + * send over (presumably) an equalizer profile for the specific + * headphone setup. It is sent using the same method the DSP + * firmware is uploaded with, which I believe is why the 'ctspeq.bin' + * file exists in linux firmware tree but goes unused. It would also + * explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused. + * Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is + * set to 1.0f. + */ + SPEAKER_TUNING_USE_SPEAKER_EQ = 0x1f, + SPEAKER_TUNING_ENABLE_CENTER_EQ = 0x20, + SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL = 0x21, + SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL = 0x22, + SPEAKER_TUNING_CENTER_VOL_LEVEL = 0x23, + SPEAKER_TUNING_LFE_VOL_LEVEL = 0x24, + SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL = 0x25, + SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL = 0x26, + SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL = 0x27, + SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28, + /* + * Inversion is used when setting headphone virtualization to line + * out. Not sure why this is, but it's the only place it's ever used. + */ + SPEAKER_TUNING_FRONT_LEFT_INVERT = 0x29, + SPEAKER_TUNING_FRONT_RIGHT_INVERT = 0x2a, + SPEAKER_TUNING_CENTER_INVERT = 0x2b, + SPEAKER_TUNING_LFE_INVERT = 0x2c, + SPEAKER_TUNING_REAR_LEFT_INVERT = 0x2d, + SPEAKER_TUNING_REAR_RIGHT_INVERT = 0x2e, + SPEAKER_TUNING_SURROUND_LEFT_INVERT = 0x2f, + SPEAKER_TUNING_SURROUND_RIGHT_INVERT = 0x30, + /* Delay is used when setting surround speaker distance in Windows. */ + SPEAKER_TUNING_FRONT_LEFT_DELAY = 0x31, + SPEAKER_TUNING_FRONT_RIGHT_DELAY = 0x32, + SPEAKER_TUNING_CENTER_DELAY = 0x33, + SPEAKER_TUNING_LFE_DELAY = 0x34, + SPEAKER_TUNING_REAR_LEFT_DELAY = 0x35, + SPEAKER_TUNING_REAR_RIGHT_DELAY = 0x36, + SPEAKER_TUNING_SURROUND_LEFT_DELAY = 0x37, + SPEAKER_TUNING_SURROUND_RIGHT_DELAY = 0x38, + /* Of these two, only mute seems to ever be used. */ + SPEAKER_TUNING_MAIN_VOLUME = 0x39, + SPEAKER_TUNING_MUTE = 0x3a, +}; + +/* Surround output channel count configuration structures. */ +#define SPEAKER_CHANNEL_CFG_COUNT 5 +enum { + SPEAKER_CHANNELS_2_0, + SPEAKER_CHANNELS_2_1, + SPEAKER_CHANNELS_4_0, + SPEAKER_CHANNELS_4_1, + SPEAKER_CHANNELS_5_1, +}; + +struct ca0132_alt_speaker_channel_cfg { + char *name; + unsigned int val; }; -static const struct ca0132_alt_out_set alt_out_presets[] = { - { .name = "Line Out", - .commands = 7, - .mids = { 0x96, 0x96, 0x96, 0x8F, - 0x96, 0x96, 0x96 }, - .reqs = { 0x19, 0x17, 0x18, 0x01, - 0x1F, 0x15, 0x3A }, - .vals = { 0x3F000000, 0x42A00000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, - 0x00000000 } +static const struct ca0132_alt_speaker_channel_cfg speaker_channel_cfgs[] = { + { .name = "2.0", + .val = FLOAT_ONE }, - { .name = "Headphone", - .commands = 7, - .mids = { 0x96, 0x96, 0x96, 0x8F, - 0x96, 0x96, 0x96 }, - .reqs = { 0x19, 0x17, 0x18, 0x01, - 0x1F, 0x15, 0x3A }, - .vals = { 0x3F000000, 0x42A00000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, - 0x00000000 } + { .name = "2.1", + .val = FLOAT_TWO }, - { .name = "Surround", - .commands = 8, - .mids = { 0x96, 0x8F, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96 }, - .reqs = { 0x18, 0x01, 0x1F, 0x15, - 0x3A, 0x1A, 0x1B, 0x1C }, - .vals = { 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000 } + { .name = "4.0", + .val = FLOAT_FIVE + }, + { .name = "4.1", + .val = FLOAT_SIX + }, + { .name = "5.1", + .val = FLOAT_EIGHT } }; @@ -658,26 +727,29 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = { }; /* Values for ca0113_mmio_command_set for selecting output. */ -#define AE5_CA0113_OUT_SET_COMMANDS 6 -struct ae5_ca0113_output_set { - unsigned int group[AE5_CA0113_OUT_SET_COMMANDS]; - unsigned int target[AE5_CA0113_OUT_SET_COMMANDS]; - unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS]; +#define AE_CA0113_OUT_SET_COMMANDS 6 +struct ae_ca0113_output_set { + unsigned int group[AE_CA0113_OUT_SET_COMMANDS]; + unsigned int target[AE_CA0113_OUT_SET_COMMANDS]; + unsigned int vals[NUM_OF_OUTPUTS][AE_CA0113_OUT_SET_COMMANDS]; }; -static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = { - { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, - .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, - .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } - }, - { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, - .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, - .vals = { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } - }, - { .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, - .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, - .vals = { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f } - } +static const struct ae_ca0113_output_set ae5_ca0113_output_presets = { + .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + /* Speakers. */ + .vals = { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }, + /* Headphones. */ + { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } }, +}; + +static const struct ae_ca0113_output_set ae7_ca0113_output_presets = { + .group = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 }, + .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 }, + /* Speakers. */ + .vals = { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }, + /* Headphones. */ + { 0x3f, 0x3f, 0x00, 0x00, 0x02, 0x00 } }, }; /* ae5 ca0113 command sequences to set headphone gain levels. */ @@ -1009,8 +1081,12 @@ struct ca0132_spec { /* ca0132_alt control related values */ unsigned char in_enum_val; unsigned char out_enum_val; + unsigned char channel_cfg_val; + unsigned char speaker_range_val[2]; unsigned char mic_boost_enum_val; unsigned char smart_volume_setting; + unsigned char bass_redirection_val; + long bass_redirect_xover_freq; long fx_ctl_val[EFFECT_LEVEL_SLIDERS]; long xbass_xover_freq; long eq_preset_val; @@ -1065,6 +1141,7 @@ enum { QUIRK_R3DI, QUIRK_R3D, QUIRK_AE5, + QUIRK_AE7, }; #ifdef CONFIG_PCI @@ -1168,6 +1245,20 @@ static const struct hda_pintbl r3di_pincfgs[] = { {} }; +static const struct hda_pintbl ae7_pincfgs[] = { + { 0x0b, 0x01017010 }, + { 0x0c, 0x014510f0 }, + { 0x0d, 0x414510f0 }, + { 0x0e, 0x01c520f0 }, + { 0x0f, 0x01017114 }, + { 0x10, 0x01017011 }, + { 0x11, 0x018170ff }, + { 0x12, 0x01a170f0 }, + { 0x13, 0x908700f0 }, + { 0x18, 0x500000f0 }, + {} +}; + static const struct snd_pci_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4), SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), @@ -1184,9 +1275,203 @@ static const struct snd_pci_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D), SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D), SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5), + SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7), {} }; +/* Output selection quirk info structures. */ +#define MAX_QUIRK_MMIO_GPIO_SET_VALS 3 +#define MAX_QUIRK_SCP_SET_VALS 2 +struct ca0132_alt_out_set_info { + unsigned int dac2port; /* ParamID 0x0d value. */ + + bool has_hda_gpio; + char hda_gpio_pin; + char hda_gpio_set; + + unsigned int mmio_gpio_count; + char mmio_gpio_pin[MAX_QUIRK_MMIO_GPIO_SET_VALS]; + char mmio_gpio_set[MAX_QUIRK_MMIO_GPIO_SET_VALS]; + + unsigned int scp_cmds_count; + unsigned int scp_cmd_mid[MAX_QUIRK_SCP_SET_VALS]; + unsigned int scp_cmd_req[MAX_QUIRK_SCP_SET_VALS]; + unsigned int scp_cmd_val[MAX_QUIRK_SCP_SET_VALS]; + + bool has_chipio_write; + unsigned int chipio_write_addr; + unsigned int chipio_write_data; +}; + +struct ca0132_alt_out_set_quirk_data { + int quirk_id; + + bool has_headphone_gain; + bool is_ae_series; + + struct ca0132_alt_out_set_info out_set_info[NUM_OF_OUTPUTS]; +}; + +static const struct ca0132_alt_out_set_quirk_data quirk_out_set_data[] = { + { .quirk_id = QUIRK_R3DI, + .has_headphone_gain = false, + .is_ae_series = false, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0x24, + .has_hda_gpio = true, + .hda_gpio_pin = 2, + .hda_gpio_set = 1, + .mmio_gpio_count = 0, + .scp_cmds_count = 0, + .has_chipio_write = false, + }, + /* Headphones. */ + { .dac2port = 0x21, + .has_hda_gpio = true, + .hda_gpio_pin = 2, + .hda_gpio_set = 0, + .mmio_gpio_count = 0, + .scp_cmds_count = 0, + .has_chipio_write = false, + } }, + }, + { .quirk_id = QUIRK_R3D, + .has_headphone_gain = false, + .is_ae_series = false, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0x24, + .has_hda_gpio = false, + .mmio_gpio_count = 1, + .mmio_gpio_pin = { 1 }, + .mmio_gpio_set = { 1 }, + .scp_cmds_count = 0, + .has_chipio_write = false, + }, + /* Headphones. */ + { .dac2port = 0x21, + .has_hda_gpio = false, + .mmio_gpio_count = 1, + .mmio_gpio_pin = { 1 }, + .mmio_gpio_set = { 0 }, + .scp_cmds_count = 0, + .has_chipio_write = false, + } }, + }, + { .quirk_id = QUIRK_SBZ, + .has_headphone_gain = false, + .is_ae_series = false, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0x18, + .has_hda_gpio = false, + .mmio_gpio_count = 3, + .mmio_gpio_pin = { 7, 4, 1 }, + .mmio_gpio_set = { 0, 1, 1 }, + .scp_cmds_count = 0, + .has_chipio_write = false, }, + /* Headphones. */ + { .dac2port = 0x12, + .has_hda_gpio = false, + .mmio_gpio_count = 3, + .mmio_gpio_pin = { 7, 4, 1 }, + .mmio_gpio_set = { 1, 1, 0 }, + .scp_cmds_count = 0, + .has_chipio_write = false, + } }, + }, + { .quirk_id = QUIRK_ZXR, + .has_headphone_gain = true, + .is_ae_series = false, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0x24, + .has_hda_gpio = false, + .mmio_gpio_count = 3, + .mmio_gpio_pin = { 2, 3, 5 }, + .mmio_gpio_set = { 1, 1, 0 }, + .scp_cmds_count = 0, + .has_chipio_write = false, + }, + /* Headphones. */ + { .dac2port = 0x21, + .has_hda_gpio = false, + .mmio_gpio_count = 3, + .mmio_gpio_pin = { 2, 3, 5 }, + .mmio_gpio_set = { 0, 1, 1 }, + .scp_cmds_count = 0, + .has_chipio_write = false, + } }, + }, + { .quirk_id = QUIRK_AE5, + .has_headphone_gain = true, + .is_ae_series = true, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0xa4, + .has_hda_gpio = false, + .mmio_gpio_count = 0, + .scp_cmds_count = 2, + .scp_cmd_mid = { 0x96, 0x96 }, + .scp_cmd_req = { SPEAKER_TUNING_FRONT_LEFT_INVERT, + SPEAKER_TUNING_FRONT_RIGHT_INVERT }, + .scp_cmd_val = { FLOAT_ZERO, FLOAT_ZERO }, + .has_chipio_write = true, + .chipio_write_addr = 0x0018b03c, + .chipio_write_data = 0x00000012 + }, + /* Headphones. */ + { .dac2port = 0xa1, + .has_hda_gpio = false, + .mmio_gpio_count = 0, + .scp_cmds_count = 2, + .scp_cmd_mid = { 0x96, 0x96 }, + .scp_cmd_req = { SPEAKER_TUNING_FRONT_LEFT_INVERT, + SPEAKER_TUNING_FRONT_RIGHT_INVERT }, + .scp_cmd_val = { FLOAT_ONE, FLOAT_ONE }, + .has_chipio_write = true, + .chipio_write_addr = 0x0018b03c, + .chipio_write_data = 0x00000012 + } }, + }, + { .quirk_id = QUIRK_AE7, + .has_headphone_gain = true, + .is_ae_series = true, + .out_set_info = { + /* Speakers. */ + { .dac2port = 0x58, + .has_hda_gpio = false, + .mmio_gpio_count = 1, + .mmio_gpio_pin = { 0 }, + .mmio_gpio_set = { 1 }, + .scp_cmds_count = 2, + .scp_cmd_mid = { 0x96, 0x96 }, + .scp_cmd_req = { SPEAKER_TUNING_FRONT_LEFT_INVERT, + SPEAKER_TUNING_FRONT_RIGHT_INVERT }, + .scp_cmd_val = { FLOAT_ZERO, FLOAT_ZERO }, + .has_chipio_write = true, + .chipio_write_addr = 0x0018b03c, + .chipio_write_data = 0x00000000 + }, + /* Headphones. */ + { .dac2port = 0x58, + .has_hda_gpio = false, + .mmio_gpio_count = 1, + .mmio_gpio_pin = { 0 }, + .mmio_gpio_set = { 1 }, + .scp_cmds_count = 2, + .scp_cmd_mid = { 0x96, 0x96 }, + .scp_cmd_req = { SPEAKER_TUNING_FRONT_LEFT_INVERT, + SPEAKER_TUNING_FRONT_RIGHT_INVERT }, + .scp_cmd_val = { FLOAT_ONE, FLOAT_ONE }, + .has_chipio_write = true, + .chipio_write_addr = 0x0018b03c, + .chipio_write_data = 0x00000010 + } }, + } +}; + /* * CA0132 codec access */ @@ -2829,7 +3114,7 @@ static int dspxfr_one_seg(struct hda_codec *codec, } data = fls->data; - chip_addx = fls->chip_addr, + chip_addx = fls->chip_addr; words_to_write = fls->count; if (!words_to_write) @@ -3339,6 +3624,7 @@ static void ca0132_gpio_init(struct hda_codec *codec) switch (ca0132_quirk(spec)) { case QUIRK_SBZ: case QUIRK_AE5: + case QUIRK_AE7: snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23); @@ -3444,26 +3730,6 @@ static void r3di_gpio_mic_set(struct hda_codec *codec, AC_VERB_SET_GPIO_DATA, cur_gpio); } -static void r3di_gpio_out_set(struct hda_codec *codec, - enum r3di_out_select cur_out) -{ - unsigned int cur_gpio; - - /* Get the current GPIO Data setup */ - cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0); - - switch (cur_out) { - case R3DI_HEADPHONE_OUT: - cur_gpio &= ~(1 << R3DI_OUT_SELECT_BIT); - break; - case R3DI_LINE_OUT: - cur_gpio |= (1 << R3DI_OUT_SELECT_BIT); - break; - } - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_GPIO_DATA, cur_gpio); -} - static void r3di_gpio_dsp_status_set(struct hda_codec *codec, enum r3di_dsp_status dsp_status) { @@ -4159,135 +4425,198 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); static void ae5_mmio_select_out(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + const struct ae_ca0113_output_set *out_cmds; unsigned int i; - for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++) - ca0113_mmio_command_set(codec, - ae5_ca0113_output_presets[spec->cur_out_type].group[i], - ae5_ca0113_output_presets[spec->cur_out_type].target[i], - ae5_ca0113_output_presets[spec->cur_out_type].vals[i]); + if (ca0132_quirk(spec) == QUIRK_AE5) + out_cmds = &ae5_ca0113_output_presets; + else + out_cmds = &ae7_ca0113_output_presets; + + for (i = 0; i < AE_CA0113_OUT_SET_COMMANDS; i++) + ca0113_mmio_command_set(codec, out_cmds->group[i], + out_cmds->target[i], + out_cmds->vals[spec->cur_out_type][i]); +} + +static int ca0132_alt_set_full_range_speaker(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + int quirk = ca0132_quirk(spec); + unsigned int tmp; + int err; + + /* 2.0/4.0 setup has no LFE channel, so setting full-range does nothing. */ + if (spec->channel_cfg_val == SPEAKER_CHANNELS_4_0 + || spec->channel_cfg_val == SPEAKER_CHANNELS_2_0) + return 0; + + /* Set front L/R full range. Zero for full-range, one for redirection. */ + tmp = spec->speaker_range_val[0] ? FLOAT_ZERO : FLOAT_ONE; + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_FULL_RANGE_FRONT_L_R, tmp); + if (err < 0) + return err; + + /* When setting full-range rear, both rear and center/lfe are set. */ + tmp = spec->speaker_range_val[1] ? FLOAT_ZERO : FLOAT_ONE; + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_FULL_RANGE_CENTER_LFE, tmp); + if (err < 0) + return err; + + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_FULL_RANGE_REAR_L_R, tmp); + if (err < 0) + return err; + + /* + * Only the AE series cards set this value when setting full-range, + * and it's always 1.0f. + */ + if (quirk == QUIRK_AE5 || quirk == QUIRK_AE7) { + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_FULL_RANGE_SURROUND_L_R, FLOAT_ONE); + if (err < 0) + return err; + } + + return 0; +} + +static int ca0132_alt_surround_set_bass_redirection(struct hda_codec *codec, + bool val) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + int err; + + if (val && spec->channel_cfg_val != SPEAKER_CHANNELS_4_0 && + spec->channel_cfg_val != SPEAKER_CHANNELS_2_0) + tmp = FLOAT_ONE; + else + tmp = FLOAT_ZERO; + + err = dspio_set_uint_param(codec, 0x96, SPEAKER_BASS_REDIRECT, tmp); + if (err < 0) + return err; + + /* If it is enabled, make sure to set the crossover frequency. */ + if (tmp) { + tmp = float_xbass_xover_lookup[spec->xbass_xover_freq]; + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_BASS_REDIRECT_XOVER_FREQ, tmp); + if (err < 0) + return err; + } + + return 0; } /* * These are the commands needed to setup output on each of the different card * types. */ -static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) +static void ca0132_alt_select_out_get_quirk_data(struct hda_codec *codec, + const struct ca0132_alt_out_set_quirk_data **quirk_data) { struct ca0132_spec *spec = codec->spec; - unsigned int tmp; + int quirk = ca0132_quirk(spec); + unsigned int i; - switch (spec->cur_out_type) { - case SPEAKER_OUT: - switch (ca0132_quirk(spec)) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0d, 0x18); - break; - case QUIRK_ZXR: - ca0113_mmio_gpio_set(codec, 2, true); - ca0113_mmio_gpio_set(codec, 3, true); - ca0113_mmio_gpio_set(codec, 5, false); - zxr_headphone_gain_set(codec, 0); - chipio_set_control_param(codec, 0x0d, 0x24); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0d, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0d, 0x24); - ca0113_mmio_gpio_set(codec, 1, true); - break; - case QUIRK_AE5: - ae5_mmio_select_out(codec); - ae5_headphone_gain_set(codec, 2); - tmp = FLOAT_ZERO; - dspio_set_uint_param(codec, 0x96, 0x29, tmp); - dspio_set_uint_param(codec, 0x96, 0x2a, tmp); - chipio_set_control_param(codec, 0x0d, 0xa4); - chipio_write(codec, 0x18b03c, 0x00000012); - break; - default: - break; + *quirk_data = NULL; + for (i = 0; i < ARRAY_SIZE(quirk_out_set_data); i++) { + if (quirk_out_set_data[i].quirk_id == quirk) { + *quirk_data = &quirk_out_set_data[i]; + return; } - break; - case HEADPHONE_OUT: - switch (ca0132_quirk(spec)) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, true); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, false); - chipio_set_control_param(codec, 0x0d, 0x12); - break; - case QUIRK_ZXR: - ca0113_mmio_gpio_set(codec, 2, false); - ca0113_mmio_gpio_set(codec, 3, false); - ca0113_mmio_gpio_set(codec, 5, true); - zxr_headphone_gain_set(codec, spec->zxr_gain_set); - chipio_set_control_param(codec, 0x0d, 0x21); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0d, 0x21); - r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); - break; - case QUIRK_R3D: - chipio_set_control_param(codec, 0x0d, 0x21); - ca0113_mmio_gpio_set(codec, 0x1, false); - break; - case QUIRK_AE5: - ae5_mmio_select_out(codec); - ae5_headphone_gain_set(codec, - spec->ae5_headphone_gain_val); - tmp = FLOAT_ONE; - dspio_set_uint_param(codec, 0x96, 0x29, tmp); - dspio_set_uint_param(codec, 0x96, 0x2a, tmp); - chipio_set_control_param(codec, 0x0d, 0xa1); - chipio_write(codec, 0x18b03c, 0x00000012); - break; - default: - break; + } +} + +static int ca0132_alt_select_out_quirk_set(struct hda_codec *codec) +{ + const struct ca0132_alt_out_set_quirk_data *quirk_data; + const struct ca0132_alt_out_set_info *out_info; + struct ca0132_spec *spec = codec->spec; + unsigned int i, gpio_data; + int err; + + ca0132_alt_select_out_get_quirk_data(codec, &quirk_data); + if (!quirk_data) + return 0; + + out_info = &quirk_data->out_set_info[spec->cur_out_type]; + if (quirk_data->is_ae_series) + ae5_mmio_select_out(codec); + + if (out_info->has_hda_gpio) { + gpio_data = snd_hda_codec_read(codec, codec->core.afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + + if (out_info->hda_gpio_set) + gpio_data |= (1 << out_info->hda_gpio_pin); + else + gpio_data &= ~(1 << out_info->hda_gpio_pin); + + snd_hda_codec_write(codec, codec->core.afg, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); + } + + if (out_info->mmio_gpio_count) { + for (i = 0; i < out_info->mmio_gpio_count; i++) { + ca0113_mmio_gpio_set(codec, out_info->mmio_gpio_pin[i], + out_info->mmio_gpio_set[i]); } - break; - case SURROUND_OUT: - switch (ca0132_quirk(spec)) { - case QUIRK_SBZ: - ca0113_mmio_gpio_set(codec, 7, false); - ca0113_mmio_gpio_set(codec, 4, true); - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0d, 0x18); - break; - case QUIRK_ZXR: - ca0113_mmio_gpio_set(codec, 2, true); - ca0113_mmio_gpio_set(codec, 3, true); - ca0113_mmio_gpio_set(codec, 5, false); - zxr_headphone_gain_set(codec, 0); - chipio_set_control_param(codec, 0x0d, 0x24); - break; - case QUIRK_R3DI: - chipio_set_control_param(codec, 0x0d, 0x24); - r3di_gpio_out_set(codec, R3DI_LINE_OUT); - break; - case QUIRK_R3D: - ca0113_mmio_gpio_set(codec, 1, true); - chipio_set_control_param(codec, 0x0d, 0x24); - break; - case QUIRK_AE5: - ae5_mmio_select_out(codec); - ae5_headphone_gain_set(codec, 2); - tmp = FLOAT_ZERO; - dspio_set_uint_param(codec, 0x96, 0x29, tmp); - dspio_set_uint_param(codec, 0x96, 0x2a, tmp); - chipio_set_control_param(codec, 0x0d, 0xa4); - chipio_write(codec, 0x18b03c, 0x00000012); - break; - default: - break; + } + + if (out_info->scp_cmds_count) { + for (i = 0; i < out_info->scp_cmds_count; i++) { + err = dspio_set_uint_param(codec, + out_info->scp_cmd_mid[i], + out_info->scp_cmd_req[i], + out_info->scp_cmd_val[i]); + if (err < 0) + return err; } - break; } + + chipio_set_control_param(codec, 0x0d, out_info->dac2port); + + if (out_info->has_chipio_write) { + chipio_write(codec, out_info->chipio_write_addr, + out_info->chipio_write_data); + } + + if (quirk_data->has_headphone_gain) { + if (spec->cur_out_type != HEADPHONE_OUT) { + if (quirk_data->is_ae_series) + ae5_headphone_gain_set(codec, 2); + else + zxr_headphone_gain_set(codec, 0); + } else { + if (quirk_data->is_ae_series) + ae5_headphone_gain_set(codec, + spec->ae5_headphone_gain_val); + else + zxr_headphone_gain_set(codec, + spec->zxr_gain_set); + } + } + + return 0; +} + +static void ca0132_set_out_node_pincfg(struct hda_codec *codec, hda_nid_t nid, + bool out_enable, bool hp_enable) +{ + unsigned int pin_ctl; + + pin_ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + + pin_ctl = hp_enable ? pin_ctl | PIN_HP_AMP : pin_ctl & ~PIN_HP_AMP; + pin_ctl = out_enable ? pin_ctl | PIN_OUT : pin_ctl & ~PIN_OUT; + snd_hda_set_pin_ctl(codec, nid, pin_ctl); } /* @@ -4296,18 +4625,14 @@ static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec) * output with an enumerated control "output source" if the auto detect * mute switch is set to off. If the auto detect mute switch is enabled, it * will detect either headphone or lineout(SPEAKER_OUT) from jack detection. - * It also adds the ability to auto-detect the front headphone port. The only - * way to select surround is to disable auto detect, and set Surround with the - * enumerated control. + * It also adds the ability to auto-detect the front headphone port. */ static int ca0132_alt_select_out(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - unsigned int pin_ctl; + unsigned int tmp, outfx_set; int jack_present; int auto_jack; - unsigned int i; - unsigned int tmp; int err; /* Default Headphone is rear headphone */ hda_nid_t headphone_nid = spec->out_pins[1]; @@ -4334,115 +4659,112 @@ static int ca0132_alt_select_out(struct hda_codec *codec) } else spec->cur_out_type = spec->out_enum_val; - /* Begin DSP output switch */ - tmp = FLOAT_ONE; - err = dspio_set_uint_param(codec, 0x96, 0x3A, tmp); + outfx_set = spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]; + + /* Begin DSP output switch, mute DSP volume. */ + err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ONE); if (err < 0) goto exit; - ca0132_alt_select_out_quirk_handler(codec); + if (ca0132_alt_select_out_quirk_set(codec) < 0) + goto exit; switch (spec->cur_out_type) { case SPEAKER_OUT: codec_dbg(codec, "%s speaker\n", __func__); - /* disable headphone node */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[1], - pin_ctl & ~PIN_HP); - /* enable line-out node */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[0], - pin_ctl | PIN_OUT); /* Enable EAPD */ snd_hda_codec_write(codec, spec->out_pins[0], 0, AC_VERB_SET_EAPD_BTLENABLE, 0x01); - /* If PlayEnhancement is enabled, set different source */ - if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); + /* Disable headphone node. */ + ca0132_set_out_node_pincfg(codec, spec->out_pins[1], 0, 0); + /* Set front L-R to output. */ + ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 1, 0); + /* Set Center/LFE to output. */ + ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 1, 0); + /* Set rear surround to output. */ + ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 1, 0); + + /* + * Without PlayEnhancement being enabled, if we've got a 2.0 + * setup, set it to floating point eight to disable any DSP + * processing effects. + */ + if (!outfx_set && spec->channel_cfg_val == SPEAKER_CHANNELS_2_0) + tmp = FLOAT_EIGHT; else - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); + tmp = speaker_channel_cfgs[spec->channel_cfg_val].val; + + err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); + if (err < 0) + goto exit; + break; case HEADPHONE_OUT: codec_dbg(codec, "%s hp\n", __func__); - snd_hda_codec_write(codec, spec->out_pins[0], 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00); - /* disable speaker*/ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[0], - pin_ctl & ~PIN_HP); + /* Disable all speaker nodes. */ + ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 0, 0); + ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 0, 0); + ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 0, 0); /* enable headphone, either front or rear */ - if (snd_hda_jack_detect(codec, spec->unsol_tag_front_hp)) headphone_nid = spec->out_pins[2]; else if (snd_hda_jack_detect(codec, spec->unsol_tag_hp)) headphone_nid = spec->out_pins[1]; - pin_ctl = snd_hda_codec_read(codec, headphone_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, headphone_nid, - pin_ctl | PIN_HP); + ca0132_set_out_node_pincfg(codec, headphone_nid, 1, 1); - if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); + if (outfx_set) + err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); else - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO); - break; - case SURROUND_OUT: - codec_dbg(codec, "%s surround\n", __func__); + err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO); - /* enable line out node */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[0], - pin_ctl | PIN_OUT); - /* Disable headphone out */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[1], - pin_ctl & ~PIN_HP); - /* Enable EAPD on line out */ - snd_hda_codec_write(codec, spec->out_pins[0], 0, - AC_VERB_SET_EAPD_BTLENABLE, 0x01); - /* enable center/lfe out node */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[2], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[2], - pin_ctl | PIN_OUT); - /* Now set rear surround node as out. */ - pin_ctl = snd_hda_codec_read(codec, spec->out_pins[3], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_set_pin_ctl(codec, spec->out_pins[3], - pin_ctl | PIN_OUT); - - dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); + if (err < 0) + goto exit; break; } /* - * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT. - * With this set though, X_BASS cannot be enabled. So, if we have OutFX - * enabled, we need to make sure X_BASS is off, otherwise everything - * sounds all muffled. Running ca0132_effects_set with X_BASS as the - * effect should sort this out. + * If output effects are enabled, set the X-Bass effect value again to + * make sure that it's properly enabled/disabled for speaker + * configurations with an LFE channel. */ - if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) + if (outfx_set) ca0132_effects_set(codec, X_BASS, spec->effects_switch[X_BASS - EFFECT_START_NID]); - /* run through the output dsp commands for the selected output. */ - for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { - err = dspio_set_uint_param(codec, - alt_out_presets[spec->cur_out_type].mids[i], - alt_out_presets[spec->cur_out_type].reqs[i], - alt_out_presets[spec->cur_out_type].vals[i]); + /* Set speaker EQ bypass attenuation to 0. */ + err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO); + if (err < 0) + goto exit; + + /* + * Although unused on all cards but the AE series, this is always set + * to zero when setting the output. + */ + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO); + if (err < 0) + goto exit; + + if (spec->cur_out_type == SPEAKER_OUT) + err = ca0132_alt_surround_set_bass_redirection(codec, + spec->bass_redirection_val); + else + err = ca0132_alt_surround_set_bass_redirection(codec, 0); + + /* Unmute DSP now that we're done with output selection. */ + err = dspio_set_uint_param(codec, 0x96, + SPEAKER_TUNING_MUTE, FLOAT_ZERO); + if (err < 0) + goto exit; + if (spec->cur_out_type == SPEAKER_OUT) { + err = ca0132_alt_set_full_range_speaker(codec); if (err < 0) goto exit; } @@ -4675,6 +4997,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec) ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); tmp = FLOAT_THREE; break; + case QUIRK_AE7: + ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); + tmp = FLOAT_THREE; + chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, + SR_96_000); + chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, + SR_96_000); + dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO); + break; default: tmp = FLOAT_ONE; break; @@ -4720,6 +5051,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec) case QUIRK_AE5: ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); break; + case QUIRK_AE7: + ca0113_mmio_command_set(codec, 0x30, 0x28, 0x3f); + chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, + SR_96_000); + chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, + SR_96_000); + dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO); + break; default: break; } @@ -4729,7 +5068,10 @@ static int ca0132_alt_select_in(struct hda_codec *codec) if (ca0132_quirk(spec) == QUIRK_R3DI) chipio_set_conn_rate(codec, 0x0F, SR_96_000); - tmp = FLOAT_ZERO; + if (ca0132_quirk(spec) == QUIRK_AE7) + tmp = FLOAT_THREE; + else + tmp = FLOAT_ZERO; dspio_set_uint_param(codec, 0x80, 0x00, tmp); switch (ca0132_quirk(spec)) { @@ -4852,7 +5194,7 @@ static int ca0132_voicefx_set(struct hda_codec *codec, int enable) static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) { struct ca0132_spec *spec = codec->spec; - unsigned int on, tmp; + unsigned int on, tmp, channel_cfg; int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; int err = 0; int idx = nid - EFFECT_START_NID; @@ -4865,8 +5207,12 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) /* if PE if off, turn off out effects. */ if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) val = 0; - if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS) - val = 0; + if (spec->cur_out_type == SPEAKER_OUT && nid == X_BASS) { + channel_cfg = spec->channel_cfg_val; + if (channel_cfg != SPEAKER_CHANNELS_2_0 && + channel_cfg != SPEAKER_CHANNELS_4_0) + val = 0; + } } /* for in effect, qualify with CrystalVoice */ @@ -5122,6 +5468,18 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, return ret; } /* End of control change helpers. */ + +static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec, + long idx) +{ + snd_hda_power_up(codec); + + dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ, + &(float_xbass_xover_lookup[idx]), sizeof(unsigned int)); + + snd_hda_power_down(codec); +} + /* * Below I've added controls to mess with the effect levels, I've only enabled * them on the Sound Blaster Z, but they would probably also work on the @@ -5130,6 +5488,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, */ /* Sets DSP effect level from the sliders above the controls */ + static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid, const unsigned int *lookup, int idx) { @@ -5175,8 +5534,13 @@ static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; long *valp = ucontrol->value.integer.value; + hda_nid_t nid = get_amp_nid(kcontrol); + + if (nid == BASS_REDIRECTION_XOVER) + *valp = spec->bass_redirect_xover_freq; + else + *valp = spec->xbass_xover_freq; - *valp = spec->xbass_xover_freq; return 0; } @@ -5230,16 +5594,25 @@ static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol, struct ca0132_spec *spec = codec->spec; hda_nid_t nid = get_amp_nid(kcontrol); long *valp = ucontrol->value.integer.value; + long *cur_val; int idx; + if (nid == BASS_REDIRECTION_XOVER) + cur_val = &spec->bass_redirect_xover_freq; + else + cur_val = &spec->xbass_xover_freq; + /* any change? */ - if (spec->xbass_xover_freq == *valp) + if (*cur_val == *valp) return 0; - spec->xbass_xover_freq = *valp; + *cur_val = *valp; idx = *valp; - ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx); + if (nid == BASS_REDIRECTION_XOVER) + ca0132_alt_bass_redirection_xover_set(codec, *cur_val); + else + ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx); return 0; } @@ -5466,6 +5839,13 @@ static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol, int sel = ucontrol->value.enumerated.item[0]; unsigned int items = IN_SRC_NUM_OF_INPUTS; + /* + * The AE-7 has no front microphone, so limit items to 2: rear mic and + * line-in. + */ + if (ca0132_quirk(spec) == QUIRK_AE7) + items = 2; + if (sel >= items) return 0; @@ -5489,7 +5869,7 @@ static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS) uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1; strcpy(uinfo->value.enumerated.name, - alt_out_presets[uinfo->value.enumerated.item].name); + out_type_str[uinfo->value.enumerated.item]); return 0; } @@ -5516,7 +5896,7 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol, return 0; codec_dbg(codec, "ca0132_alt_output_select: sel=%d, preset=%s\n", - sel, alt_out_presets[sel].name); + sel, out_type_str[sel]); spec->out_enum_val = sel; @@ -5528,6 +5908,54 @@ static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol, return 1; } +/* Select surround output type: 2.1, 4.0, 4.1, or 5.1. */ +static int ca0132_alt_speaker_channel_cfg_get_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int items = SPEAKER_CHANNEL_CFG_COUNT; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = items; + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; + strcpy(uinfo->value.enumerated.name, + speaker_channel_cfgs[uinfo->value.enumerated.item].name); + return 0; +} + +static int ca0132_alt_speaker_channel_cfg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->channel_cfg_val; + return 0; +} + +static int ca0132_alt_speaker_channel_cfg_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = SPEAKER_CHANNEL_CFG_COUNT; + + if (sel >= items) + return 0; + + codec_dbg(codec, "ca0132_alt_speaker_channels: sel=%d, channels=%s\n", + sel, speaker_channel_cfgs[sel].name); + + spec->channel_cfg_val = sel; + + if (spec->out_enum_val == SPEAKER_OUT) + ca0132_alt_select_out(codec); + + return 1; +} + /* * Smart Volume output setting control. Three different settings, Normal, * which takes the value from the smart volume slider. The two others, loud @@ -5754,6 +6182,16 @@ static int ca0132_switch_get(struct snd_kcontrol *kcontrol, return 0; } + if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) { + *valp = spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT]; + return 0; + } + + if (nid == BASS_REDIRECTION) { + *valp = spec->bass_redirection_val; + return 0; + } + return 0; } @@ -5832,6 +6270,22 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, goto exit; } + if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) { + spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT] = *valp; + if (spec->cur_out_type == SPEAKER_OUT) + ca0132_alt_set_full_range_speaker(codec); + + changed = 0; + } + + if (nid == BASS_REDIRECTION) { + spec->bass_redirection_val = *valp; + if (spec->cur_out_type == SPEAKER_OUT) + ca0132_alt_surround_set_bass_redirection(codec, *valp); + + changed = 0; + } + exit: snd_hda_power_down(codec); return changed; @@ -6173,6 +6627,81 @@ static int ca0132_alt_add_output_enum(struct hda_codec *codec) } /* + * Add a control for selecting channel count on speaker output. Setting this + * allows the DSP to do bass redirection and channel upmixing on surround + * configurations. + */ +static int ca0132_alt_add_speaker_channel_cfg_enum(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO("Surround Channel Config", + SPEAKER_CHANNEL_CFG_ENUM, 1, 0, HDA_OUTPUT); + knew.info = ca0132_alt_speaker_channel_cfg_get_info; + knew.get = ca0132_alt_speaker_channel_cfg_get; + knew.put = ca0132_alt_speaker_channel_cfg_put; + return snd_hda_ctl_add(codec, SPEAKER_CHANNEL_CFG_ENUM, + snd_ctl_new1(&knew, codec)); +} + +/* + * Full range front stereo and rear surround switches. When these are set to + * full range, the lower frequencies from these channels are no longer + * redirected to the LFE channel. + */ +static int ca0132_alt_add_front_full_range_switch(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO("Full-Range Front Speakers", + SPEAKER_FULL_RANGE_FRONT, 1, HDA_OUTPUT); + + return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_FRONT, + snd_ctl_new1(&knew, codec)); +} + +static int ca0132_alt_add_rear_full_range_switch(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO("Full-Range Rear Speakers", + SPEAKER_FULL_RANGE_REAR, 1, HDA_OUTPUT); + + return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_REAR, + snd_ctl_new1(&knew, codec)); +} + +/* + * Bass redirection redirects audio below the crossover frequency to the LFE + * channel on speakers that are set as not being full-range. On configurations + * without an LFE channel, it does nothing. Bass redirection seems to be the + * replacement for X-Bass on configurations with an LFE channel. + */ +static int ca0132_alt_add_bass_redirection_crossover(struct hda_codec *codec) +{ + const char *namestr = "Bass Redirection Crossover"; + struct snd_kcontrol_new knew = + HDA_CODEC_VOLUME_MONO(namestr, BASS_REDIRECTION_XOVER, 1, 0, + HDA_OUTPUT); + + knew.tlv.c = NULL; + knew.info = ca0132_alt_xbass_xover_slider_info; + knew.get = ca0132_alt_xbass_xover_slider_ctl_get; + knew.put = ca0132_alt_xbass_xover_slider_put; + + return snd_hda_ctl_add(codec, BASS_REDIRECTION_XOVER, + snd_ctl_new1(&knew, codec)); +} + +static int ca0132_alt_add_bass_redirection_switch(struct hda_codec *codec) +{ + const char *namestr = "Bass Redirection"; + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO(namestr, BASS_REDIRECTION, 1, + HDA_OUTPUT); + + return snd_hda_ctl_add(codec, BASS_REDIRECTION, + snd_ctl_new1(&knew, codec)); +} + +/* * Create an Input Source enumerated control for the alternate ca0132 codecs * because the front microphone has no auto-detect, and Line-in has to be set * somehow. @@ -6478,6 +7007,21 @@ static int ca0132_build_controls(struct hda_codec *codec) err = ca0132_alt_add_output_enum(codec); if (err < 0) return err; + err = ca0132_alt_add_speaker_channel_cfg_enum(codec); + if (err < 0) + return err; + err = ca0132_alt_add_front_full_range_switch(codec); + if (err < 0) + return err; + err = ca0132_alt_add_rear_full_range_switch(codec); + if (err < 0) + return err; + err = ca0132_alt_add_bass_redirection_crossover(codec); + if (err < 0) + return err; + err = ca0132_alt_add_bass_redirection_switch(codec); + if (err < 0) + return err; err = ca0132_alt_add_mic_boost_enum(codec); if (err < 0) return err; @@ -6492,20 +7036,25 @@ static int ca0132_build_controls(struct hda_codec *codec) } } - if (ca0132_quirk(spec) == QUIRK_AE5) { + switch (ca0132_quirk(spec)) { + case QUIRK_AE5: + case QUIRK_AE7: err = ae5_add_headphone_gain_enum(codec); if (err < 0) return err; err = ae5_add_sound_filter_enum(codec); if (err < 0) return err; - } - - if (ca0132_quirk(spec) == QUIRK_ZXR) { + break; + case QUIRK_ZXR: err = zxr_add_headphone_gain_switch(codec); if (err < 0) return err; + break; + default: + break; } + #ifdef ENABLE_TUNING_CONTROLS add_tuning_ctls(codec); #endif @@ -6875,6 +7424,68 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) } /* + * Default speaker tuning values setup for alternative codecs. + */ +static const unsigned int sbz_default_delay_values[] = { + /* Non-zero values are floating point 0.000198. */ + 0x394f9e38, 0x394f9e38, 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +static const unsigned int zxr_default_delay_values[] = { + /* Non-zero values are floating point 0.000220. */ + 0x00000000, 0x00000000, 0x3966afcd, 0x3966afcd, 0x3966afcd, 0x3966afcd +}; + +static const unsigned int ae5_default_delay_values[] = { + /* Non-zero values are floating point 0.000100. */ + 0x00000000, 0x00000000, 0x38d1b717, 0x38d1b717, 0x38d1b717, 0x38d1b717 +}; + +/* + * If we never change these, probably only need them on initialization. + */ +static void ca0132_alt_init_speaker_tuning(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int i, tmp, start_req, end_req; + const unsigned int *values; + + switch (ca0132_quirk(spec)) { + case QUIRK_SBZ: + values = sbz_default_delay_values; + break; + case QUIRK_ZXR: + values = zxr_default_delay_values; + break; + case QUIRK_AE5: + case QUIRK_AE7: + values = ae5_default_delay_values; + break; + default: + values = sbz_default_delay_values; + break; + } + + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_ENABLE_CENTER_EQ, tmp); + + start_req = SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL; + end_req = SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL; + for (i = start_req; i < end_req + 1; i++) + dspio_set_uint_param(codec, 0x96, i, tmp); + + start_req = SPEAKER_TUNING_FRONT_LEFT_INVERT; + end_req = SPEAKER_TUNING_REAR_RIGHT_INVERT; + for (i = start_req; i < end_req + 1; i++) + dspio_set_uint_param(codec, 0x96, i, tmp); + + + for (i = 0; i < 6; i++) + dspio_set_uint_param(codec, 0x96, + SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]); +} + +/* * Creates a dummy stream to bind the output to. This seems to have to be done * after changing the main outputs source and destination streams. */ @@ -7021,6 +7632,7 @@ static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec) switch (ca0132_quirk(spec)) { case QUIRK_SBZ: case QUIRK_AE5: + case QUIRK_AE7: tmp = 0x00000003; dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); tmp = 0x00000000; @@ -7230,6 +7842,212 @@ static void ae5_post_dsp_startup_data(struct hda_codec *codec) mutex_unlock(&spec->chipio_mutex); } +static const unsigned int ae7_port_set_data[] = { + 0x0001e0c0, 0x0001e1c1, 0x0001e4c2, 0x0001e5c3, 0x0001e2c4, 0x0001e3c5, + 0x0001e8c6, 0x0001e9c7, 0x0001ecc8, 0x0001edc9, 0x0001eaca, 0x0001ebcb +}; + +static void ae7_post_dsp_setup_ports(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int i, count, addr; + + mutex_lock(&spec->chipio_mutex); + + chipio_set_stream_channels(codec, 0x0c, 6); + chipio_set_stream_control(codec, 0x0c, 1); + + count = ARRAY_SIZE(ae7_port_set_data); + addr = 0x190030; + for (i = 0; i < count; i++) { + chipio_write_no_mutex(codec, addr, ae7_port_set_data[i]); + + /* Addresses are incremented by 4-bytes. */ + addr += 0x04; + } + + /* + * Port setting always ends with a write of 0x1 to address 0x19042c. + */ + chipio_write_no_mutex(codec, 0x19042c, 0x00000001); + + ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x0d, 0x40); + ca0113_mmio_command_set(codec, 0x48, 0x17, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x19, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x11, 0xff); + ca0113_mmio_command_set(codec, 0x48, 0x12, 0xff); + ca0113_mmio_command_set(codec, 0x48, 0x13, 0xff); + ca0113_mmio_command_set(codec, 0x48, 0x14, 0x7f); + + mutex_unlock(&spec->chipio_mutex); +} + +static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81); + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); + + chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000); + chipio_set_stream_channels(codec, 0x0c, 6); + chipio_set_stream_control(codec, 0x0c, 1); + + chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00); + chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0); + + chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000); + chipio_set_stream_channels(codec, 0x18, 6); + chipio_set_stream_control(codec, 0x18, 1); + + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4); + + mutex_unlock(&spec->chipio_mutex); +} + +static void ae7_post_dsp_pll_setup(struct hda_codec *codec) +{ + static const unsigned int addr[] = { + 0x41, 0x45, 0x40, 0x43, 0x51 + }; + static const unsigned int data[] = { + 0xc8, 0xcc, 0xcb, 0xc7, 0x8d + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, addr[i]); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, data[i]); + } +} + +static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + static const unsigned int target[] = { + 0x0b, 0x04, 0x06, 0x0a, 0x0c, 0x11, 0x12, 0x13, 0x14 + }; + static const unsigned int data[] = { + 0x12, 0x00, 0x48, 0x05, 0x5f, 0xff, 0xff, 0xff, 0x7f + }; + unsigned int i; + + mutex_lock(&spec->chipio_mutex); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + chipio_write_no_mutex(codec, 0x189000, 0x0001f101); + chipio_write_no_mutex(codec, 0x189004, 0x0001f101); + chipio_write_no_mutex(codec, 0x189024, 0x00014004); + chipio_write_no_mutex(codec, 0x189028, 0x0002000f); + + ae7_post_dsp_pll_setup(codec); + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7); + + for (i = 0; i < ARRAY_SIZE(target); i++) + ca0113_mmio_command_set(codec, 0x48, target[i], data[i]); + + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + + chipio_set_stream_source_dest(codec, 0x21, 0x64, 0x56); + chipio_set_stream_channels(codec, 0x21, 2); + chipio_set_conn_rate_no_mutex(codec, 0x56, SR_8_000); + + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_NODE_ID, 0x09); + /* + * In the 8051's memory, this param is referred to as 'n2sid', which I + * believe is 'node to streamID'. It seems to be a way to assign a + * stream to a given HDA node. + */ + chipio_set_control_param_no_mutex(codec, 0x20, 0x21); + + chipio_write_no_mutex(codec, 0x18b038, 0x00000088); + + /* + * Now, at this point on Windows, an actual stream is setup and + * seemingly sends data to the HDA node 0x09, which is the digital + * audio input node. This is left out here, because obviously I don't + * know what data is being sent. Interestingly, the AE-5 seems to go + * through the motions of getting here and never actually takes this + * step, but the AE-7 does. + */ + + ca0113_mmio_gpio_set(codec, 0, 1); + ca0113_mmio_gpio_set(codec, 1, 1); + + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); + chipio_write_no_mutex(codec, 0x18b03c, 0x00000000); + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00); + + chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00); + chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0); + + chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000); + chipio_set_stream_channels(codec, 0x18, 6); + + /* + * Runs again, this has been repeated a few times, but I'm just + * following what the Windows driver does. + */ + ae7_post_dsp_pll_setup(codec); + chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7); + + mutex_unlock(&spec->chipio_mutex); +} + +/* + * The Windows driver has commands that seem to setup ASI, which I believe to + * be some sort of audio serial interface. My current speculation is that it's + * related to communicating with the new DAC. + */ +static void ae7_post_dsp_asi_setup(struct hda_codec *codec) +{ + chipio_8051_write_direct(codec, 0x93, 0x10); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); + + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); + + chipio_set_control_param(codec, 3, 3); + chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83); + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + snd_hda_codec_write(codec, 0x17, 0, 0x794, 0x00); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x22); + + ae7_post_dsp_pll_setup(codec); + ae7_post_dsp_asi_stream_setup(codec); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7); + + ae7_post_dsp_asi_setup_ports(codec); +} + /* * Setup default parameters for DSP */ @@ -7306,6 +8124,12 @@ static void r3d_setup_defaults(struct hda_codec *codec) if (ca0132_quirk(spec) == QUIRK_R3DI) r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED); + /* Disable mute on Center/LFE. */ + if (ca0132_quirk(spec) == QUIRK_R3D) { + ca0113_mmio_gpio_set(codec, 2, false); + ca0113_mmio_gpio_set(codec, 4, true); + } + /* Setup effect defaults */ num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; for (idx = 0; idx < num_fx; idx++) { @@ -7373,6 +8197,8 @@ static void sbz_setup_defaults(struct hda_codec *codec) } } + ca0132_alt_init_speaker_tuning(codec); + ca0132_alt_create_dummy_stream(codec); } @@ -7440,6 +8266,93 @@ static void ae5_setup_defaults(struct hda_codec *codec) } } + ca0132_alt_init_speaker_tuning(codec); + + ca0132_alt_create_dummy_stream(codec); +} + +/* + * Setup default parameters for the Sound Blaster AE-7 DSP. + */ +static void ae7_setup_defaults(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + int num_fx; + int idx, i; + + if (spec->dsp_state != DSP_DOWNLOADED) + return; + + ca0132_alt_dsp_scp_startup(codec); + ca0132_alt_init_analog_mics(codec); + ae7_post_dsp_setup_ports(codec); + + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, + SPEAKER_TUNING_FRONT_LEFT_INVERT, tmp); + dspio_set_uint_param(codec, 0x96, + SPEAKER_TUNING_FRONT_RIGHT_INVERT, tmp); + + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); + + /* New, unknown SCP req's */ + dspio_set_uint_param(codec, 0x80, 0x0d, tmp); + dspio_set_uint_param(codec, 0x80, 0x0e, tmp); + + ca0113_mmio_gpio_set(codec, 0, false); + + /* Internal loopback off */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x37, 0x08, tmp); + dspio_set_uint_param(codec, 0x37, 0x10, tmp); + + /*remove DSP headroom*/ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x3C, tmp); + + /* set WUH source */ + tmp = FLOAT_TWO; + dspio_set_uint_param(codec, 0x31, 0x00, tmp); + chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); + + /* Set speaker source? */ + dspio_set_uint_param(codec, 0x32, 0x00, tmp); + ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00); + + /* + * This is the second time we've called this, but this is seemingly + * what Windows does. + */ + ca0132_alt_init_analog_mics(codec); + + ae7_post_dsp_asi_setup(codec); + + /* + * Not sure why, but these are both set to 1. They're only set to 0 + * upon shutdown. + */ + ca0113_mmio_gpio_set(codec, 0, true); + ca0113_mmio_gpio_set(codec, 1, true); + + /* Volume control related. */ + ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x04); + ca0113_mmio_command_set(codec, 0x48, 0x10, 0x04); + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x80); + + /* out, in effects + voicefx */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; + for (idx = 0; idx < num_fx; idx++) { + for (i = 0; i <= ca0132_effects[idx].params; i++) { + dspio_set_uint_param(codec, + ca0132_effects[idx].mid, + ca0132_effects[idx].reqs[i], + ca0132_effects[idx].def_vals[i]); + } + } + + ca0132_alt_init_speaker_tuning(codec); + ca0132_alt_create_dummy_stream(codec); } @@ -7757,9 +8670,15 @@ static void ca0132_init_chip(struct hda_codec *codec) * ca0132 codecs. Also sets x-bass crossover frequency to 80hz. */ if (ca0132_use_alt_controls(spec)) { + /* Set speakers to default to full range. */ + spec->speaker_range_val[0] = 1; + spec->speaker_range_val[1] = 1; + spec->xbass_xover_freq = 8; for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++) spec->fx_ctl_val[i] = effect_slider_defaults[i]; + + spec->bass_redirect_xover_freq = 8; } spec->voicefx_val = 0; @@ -7925,6 +8844,32 @@ static void ae5_exit_chip(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83); } +static void ae7_exit_chip(struct hda_codec *codec) +{ + chipio_set_stream_control(codec, 0x18, 0); + chipio_set_stream_source_dest(codec, 0x21, 0xc8, 0xc8); + chipio_set_stream_channels(codec, 0x21, 0); + chipio_set_control_param(codec, CONTROL_PARAM_NODE_ID, 0x09); + chipio_set_control_param(codec, 0x20, 0x01); + + chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0); + + chipio_set_stream_control(codec, 0x18, 0); + chipio_set_stream_control(codec, 0x0c, 0); + + ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00); + snd_hda_codec_write(codec, 0x15, 0, 0x724, 0x83); + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00); + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x00); + ca0113_mmio_gpio_set(codec, 0, false); + ca0113_mmio_gpio_set(codec, 1, false); + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + + snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); + snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); +} + static void zxr_exit_chip(struct hda_codec *codec) { chipio_set_stream_control(codec, 0x03, 0); @@ -8108,81 +9053,149 @@ static void r3di_pre_dsp_setup(struct hda_codec *codec) * what they do, or if they're necessary. Could possibly * be removed. Figure they're better to leave in. */ -static void ca0132_mmio_init(struct hda_codec *codec) +static const unsigned int ca0113_mmio_init_address_sbz[] = { + 0x400, 0x408, 0x40c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c, + 0xc0c, 0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04 +}; + +static const unsigned int ca0113_mmio_init_data_sbz[] = { + 0x00000030, 0x00000000, 0x00000003, 0x00000003, 0x00000003, + 0x00000003, 0x000000c1, 0x000000f1, 0x00000001, 0x000000c7, + 0x000000c1, 0x00000080 +}; + +static const unsigned int ca0113_mmio_init_data_zxr[] = { + 0x00000030, 0x00000000, 0x00000000, 0x00000003, 0x00000003, + 0x00000003, 0x00000001, 0x000000f1, 0x00000001, 0x000000c7, + 0x000000c1, 0x00000080 +}; + +static const unsigned int ca0113_mmio_init_address_ae5[] = { + 0x400, 0x42c, 0x46c, 0x4ac, 0x4ec, 0x43c, 0x47c, 0x4bc, 0x4fc, 0x408, + 0x100, 0x410, 0x40c, 0x100, 0x100, 0x830, 0x86c, 0x800, 0x86c, 0x800, + 0x804, 0x20c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c, 0xc0c, + 0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04, 0x01c +}; + +static const unsigned int ca0113_mmio_init_data_ae5[] = { + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000600, 0x00000014, 0x00000001, 0x0000060f, 0x0000070f, + 0x00000aff, 0x00000000, 0x0000006b, 0x00000001, 0x0000006b, + 0x00000057, 0x00800000, 0x00880680, 0x00000080, 0x00000030, + 0x00000000, 0x00000000, 0x00000003, 0x00000003, 0x00000003, + 0x00000001, 0x000000f1, 0x00000001, 0x000000c7, 0x000000c1, + 0x00000080, 0x00880680 +}; + +static void ca0132_mmio_init_sbz(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + unsigned int tmp[2], i, count, cur_addr; + const unsigned int *addr, *data; - if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000001, spec->mem_base + 0x400); - else - writel(0x00000000, spec->mem_base + 0x400); + addr = ca0113_mmio_init_address_sbz; + for (i = 0; i < 3; i++) + writel(0x00000000, spec->mem_base + addr[i]); - if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000001, spec->mem_base + 0x408); - else - writel(0x00000000, spec->mem_base + 0x408); + cur_addr = i; + switch (ca0132_quirk(spec)) { + case QUIRK_ZXR: + tmp[0] = 0x00880480; + tmp[1] = 0x00000080; + break; + case QUIRK_SBZ: + tmp[0] = 0x00820680; + tmp[1] = 0x00000083; + break; + case QUIRK_R3D: + tmp[0] = 0x00880680; + tmp[1] = 0x00000083; + break; + default: + tmp[0] = 0x00000000; + tmp[1] = 0x00000000; + break; + } - if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000001, spec->mem_base + 0x40c); - else - writel(0x00000000, spec->mem_base + 0x40C); + for (i = 0; i < 2; i++) + writel(tmp[i], spec->mem_base + addr[cur_addr + i]); - if (ca0132_quirk(spec) == QUIRK_ZXR) - writel(0x00880640, spec->mem_base + 0x01C); - else - writel(0x00880680, spec->mem_base + 0x01C); + cur_addr += i; - if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000080, spec->mem_base + 0xC0C); - else - writel(0x00000083, spec->mem_base + 0xC0C); + switch (ca0132_quirk(spec)) { + case QUIRK_ZXR: + count = ARRAY_SIZE(ca0113_mmio_init_data_zxr); + data = ca0113_mmio_init_data_zxr; + break; + default: + count = ARRAY_SIZE(ca0113_mmio_init_data_sbz); + data = ca0113_mmio_init_data_sbz; + break; + } - writel(0x00000030, spec->mem_base + 0xC00); - writel(0x00000000, spec->mem_base + 0xC04); + for (i = 0; i < count; i++) + writel(data[i], spec->mem_base + addr[cur_addr + i]); +} - if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000000, spec->mem_base + 0xC0C); - else - writel(0x00000003, spec->mem_base + 0xC0C); +static void ca0132_mmio_init_ae5(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + const unsigned int *addr, *data; + unsigned int i, count; + + addr = ca0113_mmio_init_address_ae5; + data = ca0113_mmio_init_data_ae5; + count = ARRAY_SIZE(ca0113_mmio_init_data_ae5); - writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x00000003, spec->mem_base + 0xC0C); - writel(0x00000003, spec->mem_base + 0xC0C); + if (ca0132_quirk(spec) == QUIRK_AE7) { + writel(0x00000680, spec->mem_base + 0x1c); + writel(0x00880680, spec->mem_base + 0x1c); + } + + for (i = 0; i < count; i++) { + /* + * AE-7 shares all writes with the AE-5, except that it writes + * a different value to 0x20c. + */ + if (i == 21 && ca0132_quirk(spec) == QUIRK_AE7) { + writel(0x00800001, spec->mem_base + addr[i]); + continue; + } + + writel(data[i], spec->mem_base + addr[i]); + } if (ca0132_quirk(spec) == QUIRK_AE5) - writel(0x00000001, spec->mem_base + 0xC08); - else - writel(0x000000C1, spec->mem_base + 0xC08); - - writel(0x000000F1, spec->mem_base + 0xC08); - writel(0x00000001, spec->mem_base + 0xC08); - writel(0x000000C7, spec->mem_base + 0xC08); - writel(0x000000C1, spec->mem_base + 0xC08); - writel(0x00000080, spec->mem_base + 0xC04); - - if (ca0132_quirk(spec) == QUIRK_AE5) { - writel(0x00000000, spec->mem_base + 0x42c); - writel(0x00000000, spec->mem_base + 0x46c); - writel(0x00000000, spec->mem_base + 0x4ac); - writel(0x00000000, spec->mem_base + 0x4ec); - writel(0x00000000, spec->mem_base + 0x43c); - writel(0x00000000, spec->mem_base + 0x47c); - writel(0x00000000, spec->mem_base + 0x4bc); - writel(0x00000000, spec->mem_base + 0x4fc); - writel(0x00000600, spec->mem_base + 0x100); - writel(0x00000014, spec->mem_base + 0x410); - writel(0x0000060f, spec->mem_base + 0x100); - writel(0x0000070f, spec->mem_base + 0x100); - writel(0x00000aff, spec->mem_base + 0x830); - writel(0x00000000, spec->mem_base + 0x86c); - writel(0x0000006b, spec->mem_base + 0x800); - writel(0x00000001, spec->mem_base + 0x86c); - writel(0x0000006b, spec->mem_base + 0x800); - writel(0x00000057, spec->mem_base + 0x804); - writel(0x00800000, spec->mem_base + 0x20c); + writel(0x00880680, spec->mem_base + 0x1c); +} + +static void ca0132_mmio_init(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + switch (ca0132_quirk(spec)) { + case QUIRK_R3D: + case QUIRK_SBZ: + case QUIRK_ZXR: + ca0132_mmio_init_sbz(codec); + break; + case QUIRK_AE5: + ca0132_mmio_init_ae5(codec); + break; } } +static const unsigned int ca0132_ae5_register_set_addresses[] = { + 0x304, 0x304, 0x304, 0x304, 0x100, 0x304, 0x100, 0x304, 0x100, 0x304, + 0x100, 0x304, 0x86c, 0x800, 0x86c, 0x800, 0x804 +}; + +static const unsigned char ca0132_ae5_register_set_data[] = { + 0x0f, 0x0e, 0x1f, 0x0c, 0x3f, 0x08, 0x7f, 0x00, 0xff, 0x00, 0x6b, + 0x01, 0x6b, 0x57 +}; + /* * This function writes to some SFR's, does some region2 writes, and then * eventually resets the codec with the 0x7ff verb. Not quite sure why it does @@ -8191,6 +9204,18 @@ static void ca0132_mmio_init(struct hda_codec *codec) static void ae5_register_set(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + unsigned int count = ARRAY_SIZE(ca0132_ae5_register_set_addresses); + const unsigned int *addr = ca0132_ae5_register_set_addresses; + const unsigned char *data = ca0132_ae5_register_set_data; + unsigned int i, cur_addr; + unsigned char tmp[3]; + + if (ca0132_quirk(spec) == QUIRK_AE7) { + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8); + } chipio_8051_write_direct(codec, 0x93, 0x10); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, @@ -8198,25 +9223,43 @@ static void ae5_register_set(struct hda_codec *codec) snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2); - writeb(0x0f, spec->mem_base + 0x304); - writeb(0x0f, spec->mem_base + 0x304); - writeb(0x0f, spec->mem_base + 0x304); - writeb(0x0f, spec->mem_base + 0x304); - writeb(0x0e, spec->mem_base + 0x100); - writeb(0x1f, spec->mem_base + 0x304); - writeb(0x0c, spec->mem_base + 0x100); - writeb(0x3f, spec->mem_base + 0x304); - writeb(0x08, spec->mem_base + 0x100); - writeb(0x7f, spec->mem_base + 0x304); - writeb(0x00, spec->mem_base + 0x100); - writeb(0xff, spec->mem_base + 0x304); + if (ca0132_quirk(spec) == QUIRK_AE7) { + tmp[0] = 0x03; + tmp[1] = 0x03; + tmp[2] = 0x07; + } else { + tmp[0] = 0x0f; + tmp[1] = 0x0f; + tmp[2] = 0x0f; + } - ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + for (i = cur_addr = 0; i < 3; i++, cur_addr++) + writeb(tmp[i], spec->mem_base + addr[cur_addr]); + + /* + * First writes are in single bytes, final are in 4 bytes. So, we use + * writeb, then writel. + */ + for (i = 0; cur_addr < 12; i++, cur_addr++) + writeb(data[i], spec->mem_base + addr[cur_addr]); + + for (; cur_addr < count; i++, cur_addr++) + writel(data[i], spec->mem_base + addr[cur_addr]); + + writel(0x00800001, spec->mem_base + 0x20c); + + if (ca0132_quirk(spec) == QUIRK_AE7) { + ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83); + ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f); + } else { + ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f); + } chipio_8051_write_direct(codec, 0x90, 0x00); chipio_8051_write_direct(codec, 0x90, 0x10); - ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); + if (ca0132_quirk(spec) == QUIRK_AE5) + ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83); chipio_write(codec, 0x18b0a4, 0x000000c2); @@ -8268,6 +9311,19 @@ static void ca0132_alt_init(struct hda_codec *codec) snd_hda_sequence_write(codec, spec->desktop_init_verbs); ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); break; + case QUIRK_AE7: + ca0132_gpio_init(codec); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88); + snd_hda_sequence_write(codec, spec->chip_init_verbs); + snd_hda_sequence_write(codec, spec->desktop_init_verbs); + chipio_write(codec, 0x18b008, 0x000000f8); + chipio_write(codec, 0x18b008, 0x000000f0); + chipio_write(codec, 0x18b030, 0x00000020); + ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f); + break; case QUIRK_ZXR: snd_hda_sequence_write(codec, spec->chip_init_verbs); snd_hda_sequence_write(codec, spec->desktop_init_verbs); @@ -8315,7 +9371,7 @@ static int ca0132_init(struct hda_codec *codec) snd_hda_power_up_pm(codec); - if (ca0132_quirk(spec) == QUIRK_AE5) + if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7) ae5_register_set(codec); ca0132_init_unsol(codec); @@ -8343,6 +9399,9 @@ static int ca0132_init(struct hda_codec *codec) case QUIRK_AE5: ae5_setup_defaults(codec); break; + case QUIRK_AE7: + ae7_setup_defaults(codec); + break; default: ca0132_setup_defaults(codec); ca0132_init_analog_mic2(codec); @@ -8430,6 +9489,9 @@ static void ca0132_free(struct hda_codec *codec) case QUIRK_AE5: ae5_exit_chip(codec); break; + case QUIRK_AE7: + ae7_exit_chip(codec); + break; case QUIRK_R3DI: r3di_gpio_shutdown(codec); break; @@ -8534,6 +9596,10 @@ static void ca0132_config(struct hda_codec *codec) codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__); snd_hda_apply_pincfgs(codec, ae5_pincfgs); break; + case QUIRK_AE7: + codec_dbg(codec, "%s: QUIRK_AE7 applied.\n", __func__); + snd_hda_apply_pincfgs(codec, ae7_pincfgs); + break; default: break; } @@ -8615,6 +9681,7 @@ static void ca0132_config(struct hda_codec *codec) spec->dig_in = 0x09; break; case QUIRK_AE5: + case QUIRK_AE7: spec->num_outputs = 2; spec->out_pins[0] = 0x0B; /* Line out */ spec->out_pins[1] = 0x11; /* Rear headphone out */ @@ -8813,6 +9880,10 @@ static int patch_ca0132(struct hda_codec *codec) spec->mixers[0] = desktop_mixer; snd_hda_codec_set_name(codec, "Sound BlasterX AE-5"); break; + case QUIRK_AE7: + spec->mixers[0] = desktop_mixer; + snd_hda_codec_set_name(codec, "Sound Blaster AE-7"); + break; default: spec->mixers[0] = ca0132_mixer; break; @@ -8823,6 +9894,7 @@ static int patch_ca0132(struct hda_codec *codec) case QUIRK_SBZ: case QUIRK_R3D: case QUIRK_AE5: + case QUIRK_AE7: case QUIRK_ZXR: spec->use_alt_controls = true; spec->use_alt_functions = true; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 402050088090..ccd1df059654 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2046,22 +2046,25 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int pinctl; int err = 0; + mutex_lock(&spec->pcm_lock); if (hinfo->nid) { pcm_idx = hinfo_to_pcm_index(codec, hinfo); - if (snd_BUG_ON(pcm_idx < 0)) - return -EINVAL; + if (snd_BUG_ON(pcm_idx < 0)) { + err = -EINVAL; + goto unlock; + } cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid); - if (snd_BUG_ON(cvt_idx < 0)) - return -EINVAL; + if (snd_BUG_ON(cvt_idx < 0)) { + err = -EINVAL; + goto unlock; + } per_cvt = get_cvt(spec, cvt_idx); - snd_BUG_ON(!per_cvt->assigned); per_cvt->assigned = 0; hinfo->nid = 0; azx_stream(get_azx_dev(substream))->stripe = 0; - mutex_lock(&spec->pcm_lock); snd_hda_spdif_ctls_unassign(codec, pcm_idx); clear_bit(pcm_idx, &spec->pcm_in_use); pin_idx = hinfo_to_pin_index(codec, hinfo); @@ -2091,10 +2094,11 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, per_pin->setup = false; per_pin->channels = 0; mutex_unlock(&per_pin->lock); - unlock: - mutex_unlock(&spec->pcm_lock); } +unlock: + mutex_unlock(&spec->pcm_lock); + return err; } @@ -2451,7 +2455,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec) spec->chmap.ops.get_chmap = hdmi_get_chmap; spec->chmap.ops.set_chmap = hdmi_set_chmap; spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; - spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc, + spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc; codec->spec = spec; hdmi_array_init(spec, 4); @@ -4269,6 +4273,7 @@ HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi), HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI", patch_i915_tgl_hdmi), +HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi), HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi), HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI", patch_i915_icl_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c521a1f17096..f2398721ac1e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1150,6 +1150,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) codec->single_adc_amp = 1; /* FIXME: do we need this for all Realtek codec models? */ codec->spdif_status_reset = 1; + codec->forced_resume = 1; codec->patch_ops = alc_patch_ops; err = alc_codec_rename_from_preset(codec); @@ -1929,6 +1930,8 @@ enum { ALC1220_FIXUP_CLEVO_P950, ALC1220_FIXUP_CLEVO_PB51ED, ALC1220_FIXUP_CLEVO_PB51ED_PINS, + ALC887_FIXUP_ASUS_AUDIO, + ALC887_FIXUP_ASUS_HMIC, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -2141,6 +2144,31 @@ static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec, alc_fixup_headset_mode_no_hp_mic(codec, fix, action); } +static void alc887_asus_hp_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + unsigned int vref; + + snd_hda_gen_hp_automute(codec, jack); + + if (spec->gen.hp_jack_present) + vref = AC_PINCTL_VREF_80; + else + vref = AC_PINCTL_VREF_HIZ; + snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref); +} + +static void alc887_fixup_asus_jack(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action != HDA_FIXUP_ACT_PROBE) + return; + snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP); + spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook; +} + static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { .type = HDA_FIXUP_PINS, @@ -2398,6 +2426,20 @@ static const struct hda_fixup alc882_fixups[] = { .chained = true, .chain_id = ALC1220_FIXUP_CLEVO_PB51ED, }, + [ALC887_FIXUP_ASUS_AUDIO] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */ + { 0x19, 0x22219420 }, + {} + }, + }, + [ALC887_FIXUP_ASUS_HMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc887_fixup_asus_jack, + .chained = true, + .chain_id = ALC887_FIXUP_ASUS_AUDIO, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2431,6 +2473,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), + SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), @@ -2475,7 +2518,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), - SND_PCI_QUIRK(0x1462, 0x9c37, "MSI X570-A PRO", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), @@ -3428,7 +3470,11 @@ static void alc256_shutup(struct hda_codec *codec) /* 3k pull low control for Headset jack. */ /* NOTE: call this before clearing the pin, otherwise codec stalls */ - alc_update_coef_idx(codec, 0x46, 0, 3 << 12); + /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly + * when booting with headset plugged. So skip setting it for the codec alc257 + */ + if (codec->core.vendor_id != 0x10ec0257) + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); if (!spec->no_shutup_pins) snd_hda_codec_write(codec, hp_pin, 0, @@ -5993,6 +6039,40 @@ static void alc_fixup_disable_mic_vref(struct hda_codec *codec, snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ); } + +static void alc294_gx502_toggle_output(struct hda_codec *codec, + struct hda_jack_callback *cb) +{ + /* The Windows driver sets the codec up in a very different way where + * it appears to leave 0x10 = 0x8a20 set. For Linux we need to toggle it + */ + if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT) + alc_write_coef_idx(codec, 0x10, 0x8a20); + else + alc_write_coef_idx(codec, 0x10, 0x0a20); +} + +static void alc294_fixup_gx502_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* Pin 0x21: headphones/headset mic */ + if (!is_jack_detectable(codec, 0x21)) + return; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_jack_detect_enable_callback(codec, 0x21, + alc294_gx502_toggle_output); + break; + case HDA_FIXUP_ACT_INIT: + /* Make sure to start in a correct state, i.e. if + * headphones have been plugged in before powering up the system + */ + alc294_gx502_toggle_output(codec, NULL); + break; + } +} + static void alc285_fixup_hp_gpio_amp_init(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -6017,6 +6097,7 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, #include "hp_x360_helper.c" enum { + ALC269_FIXUP_GPIO2, ALC269_FIXUP_SONY_VAIO, ALC275_FIXUP_SONY_VAIO_GPIO2, ALC269_FIXUP_DELL_M101Z, @@ -6173,6 +6254,9 @@ enum { ALC285_FIXUP_THINKPAD_HEADSET_JACK, ALC294_FIXUP_ASUS_HPE, ALC294_FIXUP_ASUS_COEF_1B, + ALC294_FIXUP_ASUS_GX502_HP, + ALC294_FIXUP_ASUS_GX502_PINS, + ALC294_FIXUP_ASUS_GX502_VERBS, ALC285_FIXUP_HP_GPIO_LED, ALC285_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED, @@ -6191,9 +6275,15 @@ enum { ALC269_FIXUP_LEMOTE_A1802, ALC269_FIXUP_LEMOTE_A190X, ALC256_FIXUP_INTEL_NUC8_RUGGED, + ALC255_FIXUP_XIAOMI_HEADSET_MIC, + ALC274_FIXUP_HP_MIC, }; static const struct hda_fixup alc269_fixups[] = { + [ALC269_FIXUP_GPIO2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_gpio2, + }, [ALC269_FIXUP_SONY_VAIO] = { .type = HDA_FIXUP_PINCTLS, .v.pins = (const struct hda_pintbl[]) { @@ -7013,6 +7103,8 @@ static const struct hda_fixup alc269_fixups[] = { [ALC233_FIXUP_LENOVO_MULTI_CODECS] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_alc662_fixup_lenovo_dual_codecs, + .chained = true, + .chain_id = ALC269_FIXUP_GPIO2 }, [ALC233_FIXUP_ACER_HEADSET_MIC] = { .type = HDA_FIXUP_VERBS, @@ -7338,6 +7430,33 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC }, + [ALC294_FIXUP_ASUS_GX502_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a11050 }, /* front HP mic */ + { 0x1a, 0x01a11830 }, /* rear external mic */ + { 0x21, 0x03211020 }, /* front HP out */ + { } + }, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_GX502_VERBS + }, + [ALC294_FIXUP_ASUS_GX502_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* set 0x15 to HP-OUT ctrl */ + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* unmute the 0x15 amp */ + { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, + { } + }, + .chained = true, + .chain_id = ALC294_FIXUP_ASUS_GX502_HP + }, + [ALC294_FIXUP_ASUS_GX502_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc294_fixup_gx502_hp, + }, [ALC294_FIXUP_ASUS_COEF_1B] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -7527,6 +7646,24 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE }, + [ALC255_FIXUP_XIAOMI_HEADSET_MIC] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 }, + { } + }, + .chained = true, + .chain_id = ALC289_FIXUP_ASUS_GA401 + }, + [ALC274_FIXUP_HP_MIC] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 }, + { } + }, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -7678,6 +7815,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), + SND_PCI_QUIRK(0x103c, 0x874e, "HP", ALC274_FIXUP_HP_MIC), + SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), @@ -7711,6 +7850,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), @@ -7823,6 +7963,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI), SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ + SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), @@ -8000,6 +8141,8 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"}, {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"}, {.id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc298-samsung-headphone"}, + {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"}, + {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"}, {} }; #define ALC225_STANDARD_PINS \ @@ -9534,6 +9677,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), + SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h index 42111562e9bc..cbed6d9a9f2e 100644 --- a/sound/pci/mixart/mixart.h +++ b/sound/pci/mixart/mixart.h @@ -69,7 +69,7 @@ struct mixart_mgr { u32 msg_fifo[MSG_FIFO_SIZE]; int msg_fifo_readptr; int msg_fifo_writeptr; - atomic_t msg_processed; /* number of messages to be processed in tasklet */ + atomic_t msg_processed; /* number of messages to be processed in irq thread */ struct mutex lock; /* interrupt lock */ struct mutex msg_lock; /* mailbox lock */ diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 098c69b3b7aa..fcc2073c5025 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -445,7 +445,6 @@ struct snd_riptide { union firmware_version firmware; spinlock_t lock; - struct tasklet_struct riptide_tq; struct snd_info_entry *proc_entry; unsigned long received_irqs; @@ -1070,9 +1069,9 @@ getmixer(struct cmdif *cif, short num, unsigned short *rval, return 0; } -static void riptide_handleirq(struct tasklet_struct *t) +static irqreturn_t riptide_handleirq(int irq, void *dev_id) { - struct snd_riptide *chip = from_tasklet(chip, t, riptide_tq); + struct snd_riptide *chip = dev_id; struct cmdif *cif = chip->cif; struct snd_pcm_substream *substream[PLAYBACK_SUBSTREAMS + 1]; struct snd_pcm_runtime *runtime; @@ -1083,7 +1082,7 @@ static void riptide_handleirq(struct tasklet_struct *t) unsigned int flag; if (!cif) - return; + return IRQ_HANDLED; for (i = 0; i < PLAYBACK_SUBSTREAMS; i++) substream[i] = chip->playback_substream[i]; @@ -1134,6 +1133,8 @@ static void riptide_handleirq(struct tasklet_struct *t) } } } + + return IRQ_HANDLED; } #ifdef CONFIG_PM_SLEEP @@ -1699,13 +1700,14 @@ snd_riptide_interrupt(int irq, void *dev_id) { struct snd_riptide *chip = dev_id; struct cmdif *cif = chip->cif; + irqreturn_t ret = IRQ_HANDLED; if (cif) { chip->received_irqs++; if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) || IS_EOCIRQ(cif->hwport)) { chip->handled_irqs++; - tasklet_schedule(&chip->riptide_tq); + ret = IRQ_WAKE_THREAD; } if (chip->rmidi && IS_MPUIRQ(cif->hwport)) { chip->handled_irqs++; @@ -1714,7 +1716,7 @@ snd_riptide_interrupt(int irq, void *dev_id) } SET_AIACK(cif->hwport); } - return IRQ_HANDLED; + return ret; } static void @@ -1843,7 +1845,6 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, chip->received_irqs = 0; chip->handled_irqs = 0; chip->cif = NULL; - tasklet_setup(&chip->riptide_tq, riptide_handleirq); if ((chip->res_port = request_region(chip->port, 64, "RIPTIDE")) == NULL) { @@ -1856,8 +1857,9 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, hwport = (struct riptideport *)chip->port; UNSET_AIE(hwport); - if (request_irq(pci->irq, snd_riptide_interrupt, IRQF_SHARED, - KBUILD_MODNAME, chip)) { + if (request_threaded_irq(pci->irq, snd_riptide_interrupt, + riptide_handleirq, IRQF_SHARED, + KBUILD_MODNAME, chip)) { snd_printk(KERN_ERR "Riptide: unable to grab IRQ %d\n", pci->irq); snd_riptide_free(chip); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index dda56ecfd33b..cea53a878c36 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -447,8 +447,8 @@ struct hdsp { struct snd_pcm_substream *capture_substream; struct snd_pcm_substream *playback_substream; struct hdsp_midi midi[2]; - struct tasklet_struct midi_tasklet; - int use_midi_tasklet; + struct work_struct midi_work; + int use_midi_work; int precise_ptr; u32 control_register; /* cached value */ u32 control2_register; /* cached value */ @@ -1385,7 +1385,6 @@ static void snd_hdsp_midi_input_trigger(struct snd_rawmidi_substream *substream, } } else { hdsp->control_register &= ~ie; - tasklet_kill(&hdsp->midi_tasklet); } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); @@ -2542,37 +2541,37 @@ static int snd_hdsp_put_precise_pointer(struct snd_kcontrol *kcontrol, struct sn return change; } -#define HDSP_USE_MIDI_TASKLET(xname, xindex) \ +#define HDSP_USE_MIDI_WORK(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_CARD, \ .name = xname, \ .index = xindex, \ - .info = snd_hdsp_info_use_midi_tasklet, \ - .get = snd_hdsp_get_use_midi_tasklet, \ - .put = snd_hdsp_put_use_midi_tasklet \ + .info = snd_hdsp_info_use_midi_work, \ + .get = snd_hdsp_get_use_midi_work, \ + .put = snd_hdsp_put_use_midi_work \ } -static int hdsp_set_use_midi_tasklet(struct hdsp *hdsp, int use_tasklet) +static int hdsp_set_use_midi_work(struct hdsp *hdsp, int use_work) { - if (use_tasklet) - hdsp->use_midi_tasklet = 1; + if (use_work) + hdsp->use_midi_work = 1; else - hdsp->use_midi_tasklet = 0; + hdsp->use_midi_work = 0; return 0; } -#define snd_hdsp_info_use_midi_tasklet snd_ctl_boolean_mono_info +#define snd_hdsp_info_use_midi_work snd_ctl_boolean_mono_info -static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_get_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); spin_lock_irq(&hdsp->lock); - ucontrol->value.integer.value[0] = hdsp->use_midi_tasklet; + ucontrol->value.integer.value[0] = hdsp->use_midi_work; spin_unlock_irq(&hdsp->lock); return 0; } -static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_put_use_midi_work(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); int change; @@ -2582,8 +2581,8 @@ static int snd_hdsp_put_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct s return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp->use_midi_tasklet; - hdsp_set_use_midi_tasklet(hdsp, val); + change = (int)val != hdsp->use_midi_work; + hdsp_set_use_midi_work(hdsp, val); spin_unlock_irq(&hdsp->lock); return change; } @@ -2950,7 +2949,7 @@ HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0), HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0), HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut), HDSP_PRECISE_POINTER("Precise Pointer", 0), -HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0), +HDSP_USE_MIDI_WORK("Use Midi Tasklet", 0), }; @@ -3370,7 +3369,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0)); snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1)); snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1)); - snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_tasklet ? "on" : "off"); + snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off"); snd_iprintf(buffer, "\n"); @@ -3791,9 +3790,9 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp) return 0; } -static void hdsp_midi_tasklet(struct tasklet_struct *t) +static void hdsp_midi_work(struct work_struct *work) { - struct hdsp *hdsp = from_tasklet(hdsp, t, midi_tasklet); + struct hdsp *hdsp = container_of(work, struct hdsp, midi_work); if (hdsp->midi[0].pending) snd_hdsp_midi_input_read (&hdsp->midi[0]); @@ -3838,7 +3837,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) } if (midi0 && midi0status) { - if (hdsp->use_midi_tasklet) { + if (hdsp->use_midi_work) { /* we disable interrupts for this input until processing is done */ hdsp->control_register &= ~HDSP_Midi0InterruptEnable; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); @@ -3849,7 +3848,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) } } if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) { - if (hdsp->use_midi_tasklet) { + if (hdsp->use_midi_work) { /* we disable interrupts for this input until processing is done */ hdsp->control_register &= ~HDSP_Midi1InterruptEnable; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); @@ -3859,8 +3858,8 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) snd_hdsp_midi_input_read (&hdsp->midi[1]); } } - if (hdsp->use_midi_tasklet && schedule) - tasklet_schedule(&hdsp->midi_tasklet); + if (hdsp->use_midi_work && schedule) + queue_work(system_highpri_wq, &hdsp->midi_work); return IRQ_HANDLED; } @@ -5182,7 +5181,7 @@ static int snd_hdsp_create(struct snd_card *card, spin_lock_init(&hdsp->lock); - tasklet_setup(&hdsp->midi_tasklet, hdsp_midi_tasklet); + INIT_WORK(&hdsp->midi_work, hdsp_midi_work); pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev); hdsp->firmware_rev &= 0xff; @@ -5235,7 +5234,7 @@ static int snd_hdsp_create(struct snd_card *card, hdsp->irq = pci->irq; card->sync_irq = hdsp->irq; hdsp->precise_ptr = 0; - hdsp->use_midi_tasklet = 1; + hdsp->use_midi_work = 1; hdsp->dds_value = 0; if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) @@ -5305,7 +5304,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) { if (hdsp->port) { /* stop the audio, and cancel all interrupts */ - tasklet_kill(&hdsp->midi_tasklet); + cancel_work_sync(&hdsp->midi_work); hdsp->control_register &= ~(HDSP_Start|HDSP_AudioInterruptEnable|HDSP_Midi0InterruptEnable|HDSP_Midi1InterruptEnable); hdsp_write (hdsp, HDSP_controlRegister, hdsp->control_register); } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 572350aaf18d..4a1f576dd9cf 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -997,7 +997,7 @@ struct hdspm { u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ struct hdspm_midi midi[4]; - struct tasklet_struct midi_tasklet; + struct work_struct midi_work; size_t period_bytes; unsigned char ss_in_channels; @@ -1217,7 +1217,7 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) return ret; } -/* round arbitary sample rates to commonly known rates */ +/* round arbitrary sample rates to commonly known rates */ static int hdspm_round_frequency(int rate) { if (rate < 38050) @@ -2169,9 +2169,9 @@ static int snd_hdspm_create_midi(struct snd_card *card, } -static void hdspm_midi_tasklet(struct tasklet_struct *t) +static void hdspm_midi_work(struct work_struct *work) { - struct hdspm *hdspm = from_tasklet(hdspm, t, midi_tasklet); + struct hdspm *hdspm = container_of(work, struct hdspm, midi_work); int i = 0; while (i < hdspm->midiPorts) { @@ -5449,7 +5449,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) } if (schedule) - tasklet_hi_schedule(&hdspm->midi_tasklet); + queue_work(system_highpri_wq, &hdspm->midi_work); } return IRQ_HANDLED; @@ -6538,6 +6538,7 @@ static int snd_hdspm_create(struct snd_card *card, hdspm->card = card; spin_lock_init(&hdspm->lock); + INIT_WORK(&hdspm->midi_work, hdspm_midi_work); pci_read_config_word(hdspm->pci, PCI_CLASS_REVISION, &hdspm->firmware_rev); @@ -6836,9 +6837,6 @@ static int snd_hdspm_create(struct snd_card *card, } - tasklet_setup(&hdspm->midi_tasklet, hdspm_midi_tasklet); - - if (hdspm->io_type != MADIface) { hdspm->serial = (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF; @@ -6873,6 +6871,7 @@ static int snd_hdspm_free(struct hdspm * hdspm) { if (hdspm->port) { + cancel_work_sync(&hdspm->midi_work); /* stop th audio, and cancel all interrupts */ hdspm->control_register &= diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index a591e7457d11..254f9d96e766 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1089,6 +1089,7 @@ static const struct snd_soc_dapm_route cs47l15_dapm_routes[] = { { "HPOUT1 Demux", NULL, "OUT1R" }, { "OUT1R", NULL, "HPOUT1 Mono Mux" }, + { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" }, { "HPOUTL", "HPOUT", "HPOUT1 Demux" }, { "HPOUTR", "HPOUT", "HPOUT1 Demux" }, @@ -1268,7 +1269,6 @@ static irqreturn_t cs47l15_adsp2_irq(int irq, void *data) static const struct snd_soc_dapm_route cs47l15_mono_routes[] = { { "HPOUT1 Mono Mux", "HPOUT", "OUT1L" }, - { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" }, }; static int cs47l15_component_probe(struct snd_soc_component *component) diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index 7f5dd01f40c9..e967609da8a3 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1305,6 +1305,7 @@ static const struct snd_soc_dapm_route cs47l35_dapm_routes[] = { { "SPKOUTP", NULL, "OUT4L" }, { "OUT1R", NULL, "HPOUT1 Mono Mux" }, + { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" }, { "HPOUTL", "HPOUT", "HPOUT1 Demux" }, { "HPOUTR", "HPOUT", "HPOUT1 Demux" }, @@ -1550,7 +1551,6 @@ static irqreturn_t cs47l35_adsp2_irq(int irq, void *data) static const struct snd_soc_dapm_route cs47l35_mono_routes[] = { { "HPOUT1 Mono Mux", "HPOUT", "OUT1L" }, - { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" }, }; static int cs47l35_component_probe(struct snd_soc_component *component) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 49e6f23fc766..390dd6c7f6a5 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -481,6 +481,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) snd_hdac_display_power(hdev->bus, HDA_CODEC_IDX_CONTROLLER, false); + /* match for forbid call in snd_hda_codec_device_new() */ + pm_runtime_allow(&hdev->dev); + /* * hdac_device core already sets the state to active and calls * get_noresume. So enable runtime and set the device to suspend. diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index c1bd320633ad..fa589d834f9a 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -15,6 +15,7 @@ #include <linux/of.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> #include "max98373.h" #include "max98373-sdw.h" @@ -285,11 +286,13 @@ static const struct dev_pm_ops max98373_pm = { static int max98373_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + /* BITMAP: 00001000 Dataport 3 is active */ prop->source_ports = BIT(3); /* BITMAP: 00000010 Dataport 1 is active */ @@ -298,7 +301,6 @@ static int max98373_read_prop(struct sdw_slave *slave) prop->clk_stop_timeout = 20; nval = hweight32(prop->source_ports); - num_of_ports = nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->src_dpn_prop), GFP_KERNEL); @@ -318,7 +320,6 @@ static int max98373_read_prop(struct sdw_slave *slave) /* do this again for sink now */ nval = hweight32(prop->sink_ports); - num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->sink_dpn_prop), GFP_KERNEL); @@ -336,17 +337,6 @@ static int max98373_read_prop(struct sdw_slave *slave) i++; } - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index b288e1a7d956..c2621b0afe6c 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -118,11 +118,14 @@ static int rt1308_clock_config(struct device *dev) static int rt1308_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports = 1; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->paging_support = true; /* first we need to allocate memory for set bits in port lists */ @@ -131,7 +134,6 @@ static int rt1308_read_prop(struct sdw_slave *slave) /* for sink */ nval = hweight32(prop->sink_ports); - num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->sink_dpn_prop), GFP_KERNEL); @@ -149,17 +151,6 @@ static int rt1308_read_prop(struct sdw_slave *slave) i++; } - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index b0386f592290..58fb13132602 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -19,6 +19,7 @@ #include <linux/mutex.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -537,11 +538,15 @@ static int rt5682_update_status(struct sdw_slave *slave, static int rt5682_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports = 1; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ @@ -549,7 +554,6 @@ static int rt5682_read_prop(struct sdw_slave *slave) prop->sink_ports = 0x2; /* BITMAP: 00000010 */ nval = hweight32(prop->source_ports); - num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->src_dpn_prop), GFP_KERNEL); @@ -569,7 +573,6 @@ static int rt5682_read_prop(struct sdw_slave *slave) /* do this again for sink now */ nval = hweight32(prop->sink_ports); - num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->sink_dpn_prop), GFP_KERNEL); @@ -587,17 +590,6 @@ static int rt5682_read_prop(struct sdw_slave *slave) i++; } - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index c7deb4e4fcf1..fb77e77a4ebd 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -11,6 +11,7 @@ #include <linux/mod_devicetable.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> #include <linux/module.h> #include <linux/regmap.h> #include <sound/soc.h> @@ -333,11 +334,15 @@ static int rt700_update_status(struct sdw_slave *slave, static int rt700_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports = 1; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ @@ -345,7 +350,6 @@ static int rt700_read_prop(struct sdw_slave *slave) prop->sink_ports = 0xA; /* BITMAP: 00001010 */ nval = hweight32(prop->source_ports); - num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->src_dpn_prop), GFP_KERNEL); @@ -365,7 +369,6 @@ static int rt700_read_prop(struct sdw_slave *slave) /* do this again for sink now */ nval = hweight32(prop->sink_ports); - num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->sink_dpn_prop), GFP_KERNEL); @@ -383,17 +386,6 @@ static int rt700_read_prop(struct sdw_slave *slave) i++; } - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 3a8ca600d1cf..f0a0691bd31c 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -11,6 +11,7 @@ #include <linux/mod_devicetable.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> #include <linux/module.h> #include <linux/regmap.h> #include <sound/soc.h> @@ -337,11 +338,15 @@ static int rt711_update_status(struct sdw_slave *slave, static int rt711_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports = 1; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ @@ -349,7 +354,6 @@ static int rt711_read_prop(struct sdw_slave *slave) prop->sink_ports = 0x8; /* BITMAP: 00001000 */ nval = hweight32(prop->source_ports); - num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->src_dpn_prop), GFP_KERNEL); @@ -369,7 +373,6 @@ static int rt711_read_prop(struct sdw_slave *slave) /* do this again for sink now */ nval = hweight32(prop->sink_ports); - num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->sink_dpn_prop), GFP_KERNEL); @@ -387,17 +390,6 @@ static int rt711_read_prop(struct sdw_slave *slave) i++; } - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index a5fd31c98221..8f0aa1e8a273 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -12,6 +12,7 @@ #include <linux/mod_devicetable.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> #include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> @@ -431,11 +432,15 @@ static int rt715_update_status(struct sdw_slave *slave, static int rt715_read_prop(struct sdw_slave *slave) { struct sdw_slave_prop *prop = &slave->prop; - int nval, i, num_of_ports = 1; + int nval, i; u32 bit; unsigned long addr; struct sdw_dpn_prop *dpn; + prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ @@ -443,7 +448,6 @@ static int rt715_read_prop(struct sdw_slave *slave) prop->sink_ports = 0x0; /* BITMAP: 00000000 */ nval = hweight32(prop->source_ports); - num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, sizeof(*prop->src_dpn_prop), GFP_KERNEL); @@ -460,36 +464,6 @@ static int rt715_read_prop(struct sdw_slave *slave) i++; } - /* do this again for sink now */ - nval = hweight32(prop->sink_ports); - num_of_ports += nval; - prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), - GFP_KERNEL); - if (!prop->sink_dpn_prop) - return -ENOMEM; - - dpn = prop->sink_dpn_prop; - i = 0; - addr = prop->sink_ports; - for_each_set_bit(bit, &addr, 32) { - dpn[i].num = bit; - dpn[i].simple_ch_prep_sm = true; - dpn[i].ch_prep_timeout = 10; - i++; - } - - /* Allocate port_ready based on num_of_ports */ - slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); - if (!slave->port_ready) - return -ENOMEM; - - /* Initialize completion */ - for (i = 0; i < num_of_ports; i++) - init_completion(&slave->port_ready[i]); - /* set the timeout values */ prop->clk_stop_timeout = 20; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 4ff0c6cfa32d..bcf18bf15a02 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2049,6 +2049,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, { struct wm_coeff_ctl *ctl; struct snd_kcontrol *kcontrol; + char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ret; ctl = wm_adsp_get_ctl(dsp, name, type, alg); @@ -2059,8 +2060,25 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, return -EINVAL; ret = wm_coeff_write_ctrl(ctl, buf, len); + if (ret) + return ret; + + if (ctl->flags & WMFW_CTL_FLAG_SYS) + return 0; + + if (dsp->component->name_prefix) + snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s", + dsp->component->name_prefix, ctl->name); + else + snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s", + ctl->name); + + kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name); + if (!kcontrol) { + adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name); + return -EINVAL; + } - kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name); snd_ctl_notify(dsp->component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index 5456124457a7..4530b74f5921 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1114,6 +1114,7 @@ static int wsa881x_probe(struct sdw_slave *pdev, wsa881x->sconfig.type = SDW_STREAM_PDM; pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0); pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; + pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; gpiod_direction_output(wsa881x->sd_n, 1); wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5117c1cd5682..3e5c1eaccd5e 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -725,7 +725,7 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } -static struct snd_soc_dai_driver fsl_sai_dai = { +static struct snd_soc_dai_driver fsl_sai_dai_template = { .probe = fsl_sai_dai_probe, .playback = { .stream_name = "CPU-Playback", @@ -1062,12 +1062,15 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; } + memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, + sizeof(fsl_sai_dai_template)); + /* Sync Tx with Rx as default by following old DT binding */ sai->synchronous[RX] = true; sai->synchronous[TX] = false; - fsl_sai_dai.symmetric_rates = 1; - fsl_sai_dai.symmetric_channels = 1; - fsl_sai_dai.symmetric_samplebits = 1; + sai->cpu_dai_drv.symmetric_rates = 1; + sai->cpu_dai_drv.symmetric_channels = 1; + sai->cpu_dai_drv.symmetric_samplebits = 1; if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && of_find_property(np, "fsl,sai-asynchronous", NULL)) { @@ -1084,9 +1087,9 @@ static int fsl_sai_probe(struct platform_device *pdev) /* Discard all settings for asynchronous mode */ sai->synchronous[RX] = false; sai->synchronous[TX] = false; - fsl_sai_dai.symmetric_rates = 0; - fsl_sai_dai.symmetric_channels = 0; - fsl_sai_dai.symmetric_samplebits = 0; + sai->cpu_dai_drv.symmetric_rates = 0; + sai->cpu_dai_drv.symmetric_channels = 0; + sai->cpu_dai_drv.symmetric_samplebits = 0; } if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && @@ -1128,7 +1131,7 @@ static int fsl_sai_probe(struct platform_device *pdev) regcache_cache_only(sai->regmap, true); ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, - &fsl_sai_dai, 1); + &sai->cpu_dai_drv, 1); if (ret) goto err_pm_disable; diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index ba7425a9e217..4bbcd0dbe8f1 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -267,6 +267,7 @@ struct fsl_sai { unsigned int bclk_ratio; const struct fsl_sai_soc_data *soc_data; + struct snd_soc_dai_driver cpu_dai_drv; struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; struct fsl_sai_verid verid; diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 9630637b8ab9..26e7d9a7198f 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -715,7 +715,7 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) if (card == &mt8183_da7219_max98357_card) { dai_link->be_hw_params_fixup = mt8183_i2s_hw_params_fixup; - dai_link->ops = &mt8183_mt6358_i2s_ops; + dai_link->ops = &mt8183_da7219_i2s_ops; dai_link->cpus = i2s3_max98357a_cpus; dai_link->num_cpus = ARRAY_SIZE(i2s3_max98357a_cpus); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 1431be4ed054..a2221ebb1b6a 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM help diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index edfa9d11d2e5..81f416ac457e 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -19,9 +19,6 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/gpio-samsung.h> -#include <plat/gpio-cfg.h> - #include "dma.h" #include "regs-i2s-v2.h" #include "s3c2412-i2s.h" @@ -70,10 +67,6 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) if (ret) goto err; - /* Configure the I2S pins (GPE0...GPE4) in correct mode */ - s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), - S3C_GPIO_PULL_NONE); - return 0; err: diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 60bfaed5f7a6..50c08008aacb 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -18,10 +18,7 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/gpio-samsung.h> -#include <plat/gpio-cfg.h> #include "regs-iis.h" - #include "dma.h" #include "s3c24xx-i2s.h" @@ -348,10 +345,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) if (ret) return ret; - /* Configure the I2S pins (GPE0...GPE4) in correct mode */ - s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), - S3C_GPIO_PULL_NONE); - writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_snd_txctrl(0); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 913adc8568d5..5a6fb66dd118 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -620,7 +620,7 @@ A circular command buffer is used here. A new command is being added while another can be executed. The scheme works by adding two WAIT commands after each sent batch of commands. When the next batch is prepared it is added after the WAIT commands then the WAITs are replaced with single JUMP -command to the new batch. The the DBRI is forced to reread the last WAIT +command to the new batch. Then the DBRI is forced to reread the last WAIT command (replaced by the JUMP by then). If the DBRI is still executing previous commands the request to reread the WAIT command is ignored. diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 69137c14d0dc..8981e61f2da4 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -158,29 +158,17 @@ static int usb6fire_fw_ihex_init(const struct firmware *fw, static int usb6fire_fw_ezusb_write(struct usb_device *device, int type, int value, char *data, int len) { - int ret; - - ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, data, len, HZ); - if (ret < 0) - return ret; - else if (ret != len) - return -EIO; - return 0; + return usb_control_msg_send(device, 0, type, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, data, len, HZ, GFP_KERNEL); } static int usb6fire_fw_ezusb_read(struct usb_device *device, int type, int value, char *data, int len) { - int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, - 0, data, len, HZ); - if (ret < 0) - return ret; - else if (ret != len) - return -EIO; - return 0; + return usb_control_msg_recv(device, 0, type, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, 0, data, len, HZ, GFP_KERNEL); } static int usb6fire_fw_fpga_write(struct usb_device *device, @@ -230,7 +218,7 @@ static int usb6fire_fw_ezusb_upload( /* upload firmware image */ data = 0x01; /* stop ezusb cpu */ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); - if (ret < 0) { + if (ret) { kfree(rec); release_firmware(fw); dev_err(&intf->dev, @@ -242,7 +230,7 @@ static int usb6fire_fw_ezusb_upload( while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */ ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address, rec->data, rec->len); - if (ret < 0) { + if (ret) { kfree(rec); release_firmware(fw); dev_err(&intf->dev, @@ -257,7 +245,7 @@ static int usb6fire_fw_ezusb_upload( if (postdata) { /* write data after firmware has been uploaded */ ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr, postdata, postlen); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload ezusb firmware %s: post urb.\n", fwname); @@ -267,7 +255,7 @@ static int usb6fire_fw_ezusb_upload( data = 0x00; /* resume ezusb cpu */ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload ezusb firmware %s: end message.\n", fwname); @@ -302,7 +290,7 @@ static int usb6fire_fw_fpga_upload( end = fw->data + fw->size; ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0); - if (ret < 0) { + if (ret) { kfree(buffer); release_firmware(fw); dev_err(&intf->dev, @@ -327,7 +315,7 @@ static int usb6fire_fw_fpga_upload( kfree(buffer); ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to upload fpga firmware: end urb.\n"); return ret; @@ -363,7 +351,7 @@ int usb6fire_fw_init(struct usb_interface *intf) u8 buffer[12]; ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8); - if (ret < 0) { + if (ret) { dev_err(&intf->dev, "unable to receive device firmware state.\n"); return ret; diff --git a/sound/usb/card.c b/sound/usb/card.c index 696e788c5d31..fa764b61fe9c 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -333,6 +333,106 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) } /* + * Profile name preset table + */ +struct usb_audio_device_name { + u32 id; + const char *vendor_name; + const char *product_name; + const char *profile_name; /* override card->longname */ +}; + +#define PROFILE_NAME(vid, pid, vendor, product, profile) \ + { .id = USB_ID(vid, pid), .vendor_name = (vendor), \ + .product_name = (product), .profile_name = (profile) } +#define DEVICE_NAME(vid, pid, vendor, product) \ + PROFILE_NAME(vid, pid, vendor, product, NULL) + +/* vendor/product and profile name presets, sorted in device id order */ +static const struct usb_audio_device_name usb_audio_names[] = { + /* HP Thunderbolt Dock Audio Headset */ + PROFILE_NAME(0x03f0, 0x0269, "HP", "Thunderbolt Dock Audio Headset", + "HP-Thunderbolt-Dock-Audio-Headset"), + /* HP Thunderbolt Dock Audio Module */ + PROFILE_NAME(0x03f0, 0x0567, "HP", "Thunderbolt Dock Audio Module", + "HP-Thunderbolt-Dock-Audio-Module"), + + /* Two entries for Gigabyte TRX40 Aorus Master: + * TRX40 Aorus Master has two USB-audio devices, one for the front + * headphone with ESS SABRE9218 DAC chip, while another for the rest + * I/O (the rear panel and the front mic) with Realtek ALC1220-VB. + * Here we provide two distinct names for making UCM profiles easier. + */ + PROFILE_NAME(0x0414, 0xa000, "Gigabyte", "Aorus Master Front Headphone", + "Gigabyte-Aorus-Master-Front-Headphone"), + PROFILE_NAME(0x0414, 0xa001, "Gigabyte", "Aorus Master Main Audio", + "Gigabyte-Aorus-Master-Main-Audio"), + + /* Gigabyte TRX40 Aorus Pro WiFi */ + PROFILE_NAME(0x0414, 0xa002, + "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), + + /* Creative/E-Mu devices */ + DEVICE_NAME(0x041e, 0x3010, "Creative Labs", "Sound Blaster MP3+"), + /* Creative/Toshiba Multimedia Center SB-0500 */ + DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"), + + DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"), + + /* Dell WD15 Dock */ + PROFILE_NAME(0x0bda, 0x4014, "Dell", "WD15 Dock", "Dell-WD15-Dock"), + /* Dell WD19 Dock */ + PROFILE_NAME(0x0bda, 0x402e, "Dell", "WD19 Dock", "Dell-WD15-Dock"), + + DEVICE_NAME(0x0ccd, 0x0028, "TerraTec", "Aureon5.1MkII"), + + /* + * The original product_name is "USB Sound Device", however this name + * is also used by the CM106 based cards, so make it unique. + */ + DEVICE_NAME(0x0d8c, 0x0102, NULL, "ICUSBAUDIO7D"), + DEVICE_NAME(0x0d8c, 0x0103, NULL, "Audio Advantage MicroII"), + + /* MSI TRX40 Creator */ + PROFILE_NAME(0x0db0, 0x0d64, + "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), + /* MSI TRX40 */ + PROFILE_NAME(0x0db0, 0x543d, + "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), + + /* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ + DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"), + DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"), + + /* aka. Serato Scratch Live DJ Box */ + DEVICE_NAME(0x13e5, 0x0001, "Rane", "SL-1"), + + /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */ + PROFILE_NAME(0x17aa, 0x1046, "Lenovo", "ThinkStation P620 Rear", + "Lenovo-ThinkStation-P620-Rear"), + /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */ + PROFILE_NAME(0x17aa, 0x104d, "Lenovo", "ThinkStation P620 Main", + "Lenovo-ThinkStation-P620-Main"), + + /* Asrock TRX40 Creator */ + PROFILE_NAME(0x26ce, 0x0a01, + "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), + + { } /* terminator */ +}; + +static const struct usb_audio_device_name * +lookup_device_name(u32 id) +{ + static const struct usb_audio_device_name *p; + + for (p = usb_audio_names; p->id; p++) + if (p->id == id) + return p; + return NULL; +} + +/* * free the chip instance * * here we have to do not much, since pcm and controls are already freed @@ -357,10 +457,16 @@ static void usb_audio_make_shortname(struct usb_device *dev, const struct snd_usb_audio_quirk *quirk) { struct snd_card *card = chip->card; - - if (quirk && quirk->product_name && *quirk->product_name) { - strlcpy(card->shortname, quirk->product_name, - sizeof(card->shortname)); + const struct usb_audio_device_name *preset; + const char *s = NULL; + + preset = lookup_device_name(chip->usb_id); + if (preset && preset->product_name) + s = preset->product_name; + else if (quirk && quirk->product_name) + s = quirk->product_name; + if (s && *s) { + strlcpy(card->shortname, s, sizeof(card->shortname)); return; } @@ -382,17 +488,26 @@ static void usb_audio_make_longname(struct usb_device *dev, const struct snd_usb_audio_quirk *quirk) { struct snd_card *card = chip->card; + const struct usb_audio_device_name *preset; + const char *s = NULL; int len; + preset = lookup_device_name(chip->usb_id); + /* shortcut - if any pre-defined string is given, use it */ - if (quirk && quirk->profile_name && *quirk->profile_name) { - strlcpy(card->longname, quirk->profile_name, - sizeof(card->longname)); + if (preset && preset->profile_name) + s = preset->profile_name; + if (s && *s) { + strlcpy(card->longname, s, sizeof(card->longname)); return; } - if (quirk && quirk->vendor_name && *quirk->vendor_name) { - len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); + if (preset && preset->vendor_name) + s = preset->vendor_name; + else if (quirk && quirk->vendor_name) + s = quirk->vendor_name; + if (s && *s) { + len = strlcpy(card->longname, s, sizeof(card->longname)); } else { /* retrieve the vendor and device strings as longname */ if (dev->descriptor.iManufacturer) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 5fbc8dd2f409..e2f9ce2f5b8b 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -318,7 +318,7 @@ static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, /* * Send output urbs that have been prepared previously. URBs are dequeued - * from ep->ready_playback_urbs and in case there there aren't any available + * from ep->ready_playback_urbs and in case there aren't any available * or there are no packets that have been prepared, this function does * nothing. * diff --git a/sound/usb/format.c b/sound/usb/format.c index 1b28d01d1f4c..3bfead393aa3 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -406,6 +406,7 @@ static int line6_parse_audio_format_rates_quirk(struct snd_usb_audio *chip, case USB_ID(0x0e41, 0x4242): /* Line6 Helix Rack */ case USB_ID(0x0e41, 0x4244): /* Line6 Helix LT */ case USB_ID(0x0e41, 0x4246): /* Line6 HX-Stomp */ + case USB_ID(0x0e41, 0x4247): /* Line6 Pod Go */ case USB_ID(0x0e41, 0x4248): /* Line6 Helix >= fw 2.82 */ case USB_ID(0x0e41, 0x4249): /* Line6 Helix Rack >= fw 2.82 */ case USB_ID(0x0e41, 0x424a): /* Line6 Helix LT >= fw 2.82 */ diff --git a/sound/usb/helper.c b/sound/usb/helper.c index 4c12cc5b53fd..cf92d7110773 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -63,20 +63,6 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype return NULL; } -/* check the validity of pipe and EP types */ -int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe) -{ - static const int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; - struct usb_host_endpoint *ep; - - ep = usb_pipe_endpoint(dev, pipe); - if (!ep || usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) - return -EINVAL; - return 0; -} - /* * Wrapper for usb_control_msg(). * Allocates a temp buffer to prevent dmaing from/to the stack. @@ -89,7 +75,7 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, void *buf = NULL; int timeout; - if (snd_usb_pipe_sanity_check(dev, pipe)) + if (usb_pipe_type_check(dev, pipe)) return -EINVAL; if (size > 0) { diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 5e8a18b4e7b9..f5b4c6647e4d 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -7,7 +7,6 @@ unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size); void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype); void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype); -int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe); int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index a148caa5f48e..d942179ca095 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -156,16 +156,14 @@ static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) * This control message doesn't have any ack from the * other side */ - ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), - HIFACE_SET_RATE_REQUEST, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - rate_value, 0, NULL, 0, 100); - if (ret < 0) { + ret = usb_control_msg_send(device, 0, + HIFACE_SET_RATE_REQUEST, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + rate_value, 0, NULL, 0, 100, GFP_KERNEL); + if (ret) dev_err(&device->dev, "Error setting samplerate %d.\n", rate); - return ret; - } - return 0; + return ret; } static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 60674ce4879b..a030dd65eb28 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -337,23 +337,18 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, { struct usb_device *usbdev = line6->usbdev; int ret; - unsigned char *len; + u8 len; unsigned count; if (address > 0xffff || datalen > 0xff) return -EINVAL; - len = kmalloc(1, GFP_KERNEL); - if (!len) - return -ENOMEM; - /* query the serial number: */ - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - (datalen << 8) | 0x21, address, - NULL, 0, LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + (datalen << 8) | 0x21, address, NULL, 0, + LINE6_TIMEOUT * HZ, GFP_KERNEL); + if (ret) { dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); goto exit; } @@ -362,45 +357,42 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data, for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { mdelay(LINE6_READ_WRITE_STATUS_DELAY); - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, len, 1, - LINE6_TIMEOUT * HZ); - if (ret < 0) { + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0012, 0x0000, &len, 1, + LINE6_TIMEOUT * HZ, GFP_KERNEL); + if (ret) { dev_err(line6->ifcdev, "receive length failed (error %d)\n", ret); goto exit; } - if (*len != 0xff) + if (len != 0xff) break; } ret = -EIO; - if (*len == 0xff) { + if (len == 0xff) { dev_err(line6->ifcdev, "read failed after %d retries\n", count); goto exit; - } else if (*len != datalen) { + } else if (len != datalen) { /* should be equal or something went wrong */ dev_err(line6->ifcdev, "length mismatch (expected %d, got %d)\n", - (int)datalen, (int)*len); + (int)datalen, len); goto exit; } /* receive the result: */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0013, 0x0000, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0013, 0x0000, data, datalen, LINE6_TIMEOUT * HZ, + GFP_KERNEL); + if (ret) dev_err(line6->ifcdev, "read failed (error %d)\n", ret); exit: - kfree(len); return ret; } EXPORT_SYMBOL_GPL(line6_read_data); @@ -423,12 +415,11 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, if (!status) return -ENOMEM; - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0022, address, data, datalen, - LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0022, address, data, datalen, LINE6_TIMEOUT * HZ, + GFP_KERNEL); + if (ret) { dev_err(line6->ifcdev, "write request failed (error %d)\n", ret); goto exit; @@ -437,14 +428,11 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { mdelay(LINE6_READ_WRITE_STATUS_DELAY); - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | - USB_DIR_IN, - 0x0012, 0x0000, - status, 1, LINE6_TIMEOUT * HZ); - - if (ret < 0) { + ret = usb_control_msg_recv(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0x0012, 0x0000, status, 1, LINE6_TIMEOUT * HZ, + GFP_KERNEL); + if (ret) { dev_err(line6->ifcdev, "receiving status failed (error %d)\n", ret); goto exit; diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index eef45f7fef0d..28794a35949d 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -183,29 +183,25 @@ static const struct attribute_group podhd_dev_attr_group = { static int podhd_dev_start(struct usb_line6_podhd *pod) { int ret; - u8 *init_bytes; + u8 init_bytes[8]; int i; struct usb_device *usbdev = pod->line6.usbdev; - init_bytes = kmalloc(8, GFP_KERNEL); - if (!init_bytes) - return -ENOMEM; - - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), + ret = usb_control_msg_send(usbdev, 0, 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x11, 0, - NULL, 0, LINE6_TIMEOUT * HZ); - if (ret < 0) { + NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL); + if (ret) { dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret); goto exit; } /* NOTE: looks like some kind of ping message */ - ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, + ret = usb_control_msg_recv(usbdev, 0, 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x11, 0x0, - init_bytes, 3, LINE6_TIMEOUT * HZ); - if (ret < 0) { + init_bytes, 3, LINE6_TIMEOUT * HZ, GFP_KERNEL); + if (ret) { dev_err(pod->line6.ifcdev, "receive length failed (error %d)\n", ret); goto exit; @@ -220,13 +216,12 @@ static int podhd_dev_start(struct usb_line6_podhd *pod) goto exit; } - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), + ret = usb_control_msg_send(usbdev, 0, USB_REQ_SET_FEATURE, USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT, 1, 0, - NULL, 0, LINE6_TIMEOUT * HZ); + NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL); exit: - kfree(init_bytes); return ret; } diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 94dd5e7ab2e6..4e5693c97aa4 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -126,11 +126,12 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) { int ret; - ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); + ret = usb_control_msg_send(usbdev, 0, 0x67, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ, + GFP_KERNEL); - if (ret < 0) { + if (ret) { dev_err(&usbdev->dev, "send failed (error %d)\n", ret); return ret; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index e8287a05e36b..c8213652470c 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -142,7 +142,7 @@ struct snd_usb_midi_out_endpoint { unsigned int active_urbs; unsigned int drain_urbs; int max_transfer; /* size of urb buffer */ - struct tasklet_struct tasklet; + struct work_struct work; unsigned int next_urb; spinlock_t buffer_lock; @@ -344,9 +344,10 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep) spin_unlock_irqrestore(&ep->buffer_lock, flags); } -static void snd_usbmidi_out_tasklet(struct tasklet_struct *t) +static void snd_usbmidi_out_work(struct work_struct *work) { - struct snd_usb_midi_out_endpoint *ep = from_tasklet(ep, t, tasklet); + struct snd_usb_midi_out_endpoint *ep = + container_of(work, struct snd_usb_midi_out_endpoint, work); snd_usbmidi_do_output(ep); } @@ -1177,7 +1178,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, snd_rawmidi_proceed(substream); return; } - tasklet_schedule(&port->ep->tasklet); + queue_work(system_highpri_wq, &port->ep->work); } } @@ -1440,7 +1441,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi, } spin_lock_init(&ep->buffer_lock); - tasklet_setup(&ep->tasklet, snd_usbmidi_out_tasklet); + INIT_WORK(&ep->work, snd_usbmidi_out_work); init_waitqueue_head(&ep->drain_wait); for (i = 0; i < 0x10; ++i) @@ -1503,7 +1504,7 @@ void snd_usbmidi_disconnect(struct list_head *p) for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint *ep = &umidi->endpoints[i]; if (ep->out) - tasklet_kill(&ep->out->tasklet); + cancel_work_sync(&ep->out->work); if (ep->out) { for (j = 0; j < OUTPUT_URBS; ++j) usb_kill_urb(ep->out->urbs[j].urb); diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 3b2dce1043f5..6b30155964ec 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -96,7 +96,7 @@ struct ua101 { u8 rate_feedback[MAX_QUEUE_LENGTH]; struct list_head ready_playback_urbs; - struct tasklet_struct playback_tasklet; + struct work_struct playback_work; wait_queue_head_t alsa_capture_wait; wait_queue_head_t rate_feedback_wait; wait_queue_head_t alsa_playback_wait; @@ -188,7 +188,7 @@ static void playback_urb_complete(struct urb *usb_urb) spin_lock_irqsave(&ua->lock, flags); list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); if (ua->rate_feedback_count > 0) - tasklet_schedule(&ua->playback_tasklet); + queue_work(system_highpri_wq, &ua->playback_work); ua->playback.substream->runtime->delay -= urb->urb.iso_frame_desc[0].length / ua->playback.frame_bytes; @@ -247,9 +247,9 @@ static inline void add_with_wraparound(struct ua101 *ua, *value -= ua->playback.queue_length; } -static void playback_tasklet(struct tasklet_struct *t) +static void playback_work(struct work_struct *work) { - struct ua101 *ua = from_tasklet(ua, t, playback_tasklet); + struct ua101 *ua = container_of(work, struct ua101, playback_work); unsigned long flags; unsigned int frames; struct ua101_urb *urb; @@ -401,7 +401,7 @@ static void capture_urb_complete(struct urb *urb) } if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && !list_empty(&ua->ready_playback_urbs)) - tasklet_schedule(&ua->playback_tasklet); + queue_work(system_highpri_wq, &ua->playback_work); } spin_unlock_irqrestore(&ua->lock, flags); @@ -532,7 +532,7 @@ static void stop_usb_playback(struct ua101 *ua) kill_stream_urbs(&ua->playback); - tasklet_kill(&ua->playback_tasklet); + cancel_work_sync(&ua->playback_work); disable_iso_interface(ua, INTF_PLAYBACK); } @@ -550,7 +550,7 @@ static int start_usb_playback(struct ua101 *ua) return 0; kill_stream_urbs(&ua->playback); - tasklet_kill(&ua->playback_tasklet); + cancel_work_sync(&ua->playback_work); err = enable_iso_interface(ua, INTF_PLAYBACK); if (err < 0) @@ -1218,7 +1218,7 @@ static int ua101_probe(struct usb_interface *interface, spin_lock_init(&ua->lock); mutex_init(&ua->mutex); INIT_LIST_HEAD(&ua->ready_playback_urbs); - tasklet_setup(&ua->playback_tasklet, playback_tasklet); + INIT_WORK(&ua->playback_work, playback_work); init_waitqueue_head(&ua->alsa_capture_wait); init_waitqueue_head(&ua->rate_feedback_wait); init_waitqueue_head(&ua->alsa_playback_wait); diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 5b43e9e40e49..c369c81e74c4 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -371,7 +371,6 @@ static const struct usbmix_name_map asus_rog_map[] = { }; static const struct usbmix_name_map lenovo_p620_rear_map[] = { - { 19, NULL, 2 }, /* FU, Volume */ { 19, NULL, 12 }, /* FU, Input Gain Pad */ {} }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 199cdbfdc761..df036a359f2f 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2602,6 +2602,216 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) return 0; } +/* + * Pioneer DJ DJM-250MK2 and maybe other DJM models + * + * For playback, no duplicate mapping should be set. + * There are three mixer stereo channels (CH1, CH2, AUX) + * and three stereo sources (Playback 1-2, Playback 3-4, Playback 5-6). + * Each channel should be mapped just once to one source. + * If mapped multiple times, only one source will play on given channel + * (sources are not mixed together). + * + * For recording, duplicate mapping is OK. We will get the same signal multiple times. + * + * Channels 7-8 are in both directions fixed to FX SEND / FX RETURN. + * + * See also notes in the quirks-table.h file. + */ + +struct snd_pioneer_djm_option { + const u16 wIndex; + const u16 wValue; + const char *name; +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_level[] = { + { .name = "-5 dB", .wValue = 0x0300, .wIndex = 0x8003 }, + { .name = "-10 dB", .wValue = 0x0200, .wIndex = 0x8003 }, + { .name = "-15 dB", .wValue = 0x0100, .wIndex = 0x8003 }, + { .name = "-19 dB", .wValue = 0x0000, .wIndex = 0x8003 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch12[] = { + { .name = "CH1 Control Tone PHONO", .wValue = 0x0103, .wIndex = 0x8002 }, + { .name = "CH1 Control Tone LINE", .wValue = 0x0100, .wIndex = 0x8002 }, + { .name = "Post CH1 Fader", .wValue = 0x0106, .wIndex = 0x8002 }, + { .name = "Cross Fader A", .wValue = 0x0107, .wIndex = 0x8002 }, + { .name = "Cross Fader B", .wValue = 0x0108, .wIndex = 0x8002 }, + { .name = "MIC", .wValue = 0x0109, .wIndex = 0x8002 }, + { .name = "AUX", .wValue = 0x010d, .wIndex = 0x8002 }, + { .name = "REC OUT", .wValue = 0x010a, .wIndex = 0x8002 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch34[] = { + { .name = "CH2 Control Tone PHONO", .wValue = 0x0203, .wIndex = 0x8002 }, + { .name = "CH2 Control Tone LINE", .wValue = 0x0200, .wIndex = 0x8002 }, + { .name = "Post CH2 Fader", .wValue = 0x0206, .wIndex = 0x8002 }, + { .name = "Cross Fader A", .wValue = 0x0207, .wIndex = 0x8002 }, + { .name = "Cross Fader B", .wValue = 0x0208, .wIndex = 0x8002 }, + { .name = "MIC", .wValue = 0x0209, .wIndex = 0x8002 }, + { .name = "AUX", .wValue = 0x020d, .wIndex = 0x8002 }, + { .name = "REC OUT", .wValue = 0x020a, .wIndex = 0x8002 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_capture_ch56[] = { + { .name = "REC OUT", .wValue = 0x030a, .wIndex = 0x8002 }, + { .name = "Post CH1 Fader", .wValue = 0x0311, .wIndex = 0x8002 }, + { .name = "Post CH2 Fader", .wValue = 0x0312, .wIndex = 0x8002 }, + { .name = "Cross Fader A", .wValue = 0x0307, .wIndex = 0x8002 }, + { .name = "Cross Fader B", .wValue = 0x0308, .wIndex = 0x8002 }, + { .name = "MIC", .wValue = 0x0309, .wIndex = 0x8002 }, + { .name = "AUX", .wValue = 0x030d, .wIndex = 0x8002 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_12[] = { + { .name = "CH1", .wValue = 0x0100, .wIndex = 0x8016 }, + { .name = "CH2", .wValue = 0x0101, .wIndex = 0x8016 }, + { .name = "AUX", .wValue = 0x0104, .wIndex = 0x8016 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_34[] = { + { .name = "CH1", .wValue = 0x0200, .wIndex = 0x8016 }, + { .name = "CH2", .wValue = 0x0201, .wIndex = 0x8016 }, + { .name = "AUX", .wValue = 0x0204, .wIndex = 0x8016 } +}; + +static const struct snd_pioneer_djm_option snd_pioneer_djm_options_playback_56[] = { + { .name = "CH1", .wValue = 0x0300, .wIndex = 0x8016 }, + { .name = "CH2", .wValue = 0x0301, .wIndex = 0x8016 }, + { .name = "AUX", .wValue = 0x0304, .wIndex = 0x8016 } +}; + +struct snd_pioneer_djm_option_group { + const char *name; + const struct snd_pioneer_djm_option *options; + const size_t count; + const u16 default_value; +}; + +#define snd_pioneer_djm_option_group_item(_name, suffix, _default_value) { \ + .name = _name, \ + .options = snd_pioneer_djm_options_##suffix, \ + .count = ARRAY_SIZE(snd_pioneer_djm_options_##suffix), \ + .default_value = _default_value } + +static const struct snd_pioneer_djm_option_group snd_pioneer_djm_option_groups[] = { + snd_pioneer_djm_option_group_item("Master Capture Level Capture Switch", capture_level, 0), + snd_pioneer_djm_option_group_item("Capture 1-2 Capture Switch", capture_ch12, 2), + snd_pioneer_djm_option_group_item("Capture 3-4 Capture Switch", capture_ch34, 2), + snd_pioneer_djm_option_group_item("Capture 5-6 Capture Switch", capture_ch56, 0), + snd_pioneer_djm_option_group_item("Playback 1-2 Playback Switch", playback_12, 0), + snd_pioneer_djm_option_group_item("Playback 3-4 Playback Switch", playback_34, 1), + snd_pioneer_djm_option_group_item("Playback 5-6 Playback Switch", playback_56, 2) +}; + +// layout of the kcontrol->private_value: +#define SND_PIONEER_DJM_VALUE_MASK 0x0000ffff +#define SND_PIONEER_DJM_GROUP_MASK 0xffff0000 +#define SND_PIONEER_DJM_GROUP_SHIFT 16 + +static int snd_pioneer_djm_controls_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info) +{ + u16 group_index = kctl->private_value >> SND_PIONEER_DJM_GROUP_SHIFT; + size_t count; + const char *name; + const struct snd_pioneer_djm_option_group *group; + + if (group_index >= ARRAY_SIZE(snd_pioneer_djm_option_groups)) + return -EINVAL; + + group = &snd_pioneer_djm_option_groups[group_index]; + count = group->count; + if (info->value.enumerated.item >= count) + info->value.enumerated.item = count - 1; + name = group->options[info->value.enumerated.item].name; + strlcpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name)); + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = count; + return 0; +} + +static int snd_pioneer_djm_controls_update(struct usb_mixer_interface *mixer, u16 group, u16 value) +{ + int err; + + if (group >= ARRAY_SIZE(snd_pioneer_djm_option_groups) + || value >= snd_pioneer_djm_option_groups[group].count) + return -EINVAL; + + err = snd_usb_lock_shutdown(mixer->chip); + if (err) + return err; + + err = snd_usb_ctl_msg( + mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), + USB_REQ_SET_FEATURE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + snd_pioneer_djm_option_groups[group].options[value].wValue, + snd_pioneer_djm_option_groups[group].options[value].wIndex, + NULL, 0); + + snd_usb_unlock_shutdown(mixer->chip); + return err; +} + +static int snd_pioneer_djm_controls_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem) +{ + elem->value.enumerated.item[0] = kctl->private_value & SND_PIONEER_DJM_VALUE_MASK; + return 0; +} + +static int snd_pioneer_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); + struct usb_mixer_interface *mixer = list->mixer; + unsigned long private_value = kctl->private_value; + u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT; + u16 value = elem->value.enumerated.item[0]; + + kctl->private_value = (group << SND_PIONEER_DJM_GROUP_SHIFT) | value; + + return snd_pioneer_djm_controls_update(mixer, group, value); +} + +static int snd_pioneer_djm_controls_resume(struct usb_mixer_elem_list *list) +{ + unsigned long private_value = list->kctl->private_value; + u16 group = (private_value & SND_PIONEER_DJM_GROUP_MASK) >> SND_PIONEER_DJM_GROUP_SHIFT; + u16 value = (private_value & SND_PIONEER_DJM_VALUE_MASK); + + return snd_pioneer_djm_controls_update(list->mixer, group, value); +} + +static int snd_pioneer_djm_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i; + const struct snd_pioneer_djm_option_group *group; + struct snd_kcontrol_new knew = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .index = 0, + .info = snd_pioneer_djm_controls_info, + .get = snd_pioneer_djm_controls_get, + .put = snd_pioneer_djm_controls_put + }; + + for (i = 0; i < ARRAY_SIZE(snd_pioneer_djm_option_groups); i++) { + group = &snd_pioneer_djm_option_groups[i]; + knew.name = group->name; + knew.private_value = (i << SND_PIONEER_DJM_GROUP_SHIFT) | group->default_value; + err = snd_pioneer_djm_controls_update(mixer, i, group->default_value); + if (err) + return err; + err = add_single_ctl_with_resume(mixer, 0, snd_pioneer_djm_controls_resume, + &knew, NULL); + if (err) + return err; + } + return 0; +} + int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; @@ -2706,6 +2916,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ err = snd_bbfpro_controls_create(mixer); break; + case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ + err = snd_pioneer_djm_controls_create(mixer); + break; } return err; diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 0ffff7640892..4bbec56c7df3 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1946,7 +1946,7 @@ static void scarlett2_mixer_interrupt(struct urb *urb) goto requeue; if (len == 8) { - data = le32_to_cpu(*(u32 *)urb->transfer_buffer); + data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); if (data & SCARLETT2_USB_INTERRUPT_VOL_CHANGE) scarlett2_mixer_interrupt_vol_change(mixer); if (data & SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE) @@ -1978,7 +1978,7 @@ static int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) return 0; } - if (snd_usb_pipe_sanity_check(dev, pipe)) + if (usb_pipe_type_check(dev, pipe)) return -EINVAL; mixer->urb = usb_alloc_urb(0, GFP_KERNEL); diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c index a4d4d71db55b..92b1a6d9c931 100644 --- a/sound/usb/mixer_us16x08.c +++ b/sound/usb/mixer_us16x08.c @@ -1109,7 +1109,7 @@ static const struct snd_us16x08_control_params eq_controls[] = { .control_id = SND_US16X08_ID_EQLOWFREQ, .type = USB_MIXER_U8, .num_channels = 16, - .name = "EQ Low Frequence", + .name = "EQ Low Frequency", }, { /* EQ mid low gain */ .kcontrol_new = &snd_us16x08_eq_gain_ctl, @@ -1123,7 +1123,7 @@ static const struct snd_us16x08_control_params eq_controls[] = { .control_id = SND_US16X08_ID_EQLOWMIDFREQ, .type = USB_MIXER_U8, .num_channels = 16, - .name = "EQ MidLow Frequence", + .name = "EQ MidLow Frequency", }, { /* EQ mid low Q */ .kcontrol_new = &snd_us16x08_eq_mid_width_ctl, @@ -1144,7 +1144,7 @@ static const struct snd_us16x08_control_params eq_controls[] = { .control_id = SND_US16X08_ID_EQHIGHMIDFREQ, .type = USB_MIXER_U8, .num_channels = 16, - .name = "EQ MidHigh Frequence", + .name = "EQ MidHigh Frequency", }, { /* EQ mid high Q */ .kcontrol_new = &snd_us16x08_eq_mid_width_ctl, @@ -1165,7 +1165,7 @@ static const struct snd_us16x08_control_params eq_controls[] = { .control_id = SND_US16X08_ID_EQHIGHFREQ, .type = USB_MIXER_U8, .num_channels = 16, - .name = "EQ High Frequence", + .name = "EQ High Frequency", }, }; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 23eafd50126f..3c1697f6b60c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -25,33 +25,16 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC -#define QUIRK_RENAME_DEVICE(_vendor, _device) \ - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \ - .vendor_name = _vendor, \ - .product_name = _device, \ - .ifnum = QUIRK_NO_INTERFACE \ - } - -#define QUIRK_DEVICE_PROFILE(_vendor, _device, _profile) \ - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { \ - .vendor_name = _vendor, \ - .product_name = _device, \ - .profile_name = _profile, \ - .ifnum = QUIRK_NO_INTERFACE \ - } +/* A standard entry matching with vid/pid and the audio class/subclass */ +#define USB_AUDIO_DEVICE(vend, prod) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_SUBCLASS, \ + .idVendor = vend, \ + .idProduct = prod, \ + .bInterfaceClass = USB_CLASS_AUDIO, \ + .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -/* HP Thunderbolt Dock Audio Headset */ -{ - USB_DEVICE(0x03f0, 0x0269), - QUIRK_DEVICE_PROFILE("HP", "Thunderbolt Dock Audio Headset", - "HP-Thunderbolt-Dock-Audio-Headset"), -}, -/* HP Thunderbolt Dock Audio Module */ -{ - USB_DEVICE(0x03f0, 0x0567), - QUIRK_DEVICE_PROFILE("HP", "Thunderbolt Dock Audio Module", - "HP-Thunderbolt-Dock-Audio-Module"), -}, /* FTDI devices */ { USB_DEVICE(0x0403, 0xb8d8), @@ -85,44 +68,14 @@ } }, -/* Creative/E-Mu devices */ -{ - USB_DEVICE(0x041e, 0x3010), - QUIRK_RENAME_DEVICE("Creative Labs", "Sound Blaster MP3+") -}, -/* Creative/Toshiba Multimedia Center SB-0500 */ -{ - USB_DEVICE(0x041e, 0x3048), - QUIRK_RENAME_DEVICE("Toshiba", "SB-0500") -}, -{ - /* E-Mu 0202 USB */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f02, - .bInterfaceClass = USB_CLASS_AUDIO, -}, -{ - /* E-Mu 0404 USB */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f04, - .bInterfaceClass = USB_CLASS_AUDIO, -}, -{ - /* E-Mu Tracker Pre */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f0a, - .bInterfaceClass = USB_CLASS_AUDIO, -}, -{ - /* E-Mu 0204 USB */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x041e, - .idProduct = 0x3f19, - .bInterfaceClass = USB_CLASS_AUDIO, -}, +/* E-Mu 0202 USB */ +{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f02) }, +/* E-Mu 0404 USB */ +{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f04) }, +/* E-Mu Tracker Pre */ +{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f0a) }, +/* E-Mu 0204 USB */ +{ USB_DEVICE_VENDOR_SPEC(0x041e, 0x3f19) }, /* * HP Wireless Audio @@ -164,70 +117,13 @@ * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface * class matches do not take effect without an explicit ID match. */ -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x0850, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x08ae, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x08c6, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x08f0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x08f5, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x08f6, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL -}, -{ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x046d, - .idProduct = 0x0990, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, - QUIRK_RENAME_DEVICE("Logitech, Inc.", "QuickCam Pro 9000") -}, +{ USB_AUDIO_DEVICE(0x046d, 0x0850) }, +{ USB_AUDIO_DEVICE(0x046d, 0x08ae) }, +{ USB_AUDIO_DEVICE(0x046d, 0x08c6) }, +{ USB_AUDIO_DEVICE(0x046d, 0x08f0) }, +{ USB_AUDIO_DEVICE(0x046d, 0x08f5) }, +{ USB_AUDIO_DEVICE(0x046d, 0x08f6) }, +{ USB_AUDIO_DEVICE(0x046d, 0x0990) }, /* * Yamaha devices @@ -2610,10 +2506,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0ccd, 0x0028), - QUIRK_RENAME_DEVICE("TerraTec", "Aureon5.1MkII") -}, -{ USB_DEVICE(0x0ccd, 0x0035), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { .vendor_name = "Miditech", @@ -2623,16 +2515,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, -/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ -{ - USB_DEVICE(0x103d, 0x0100), - QUIRK_RENAME_DEVICE("Stanton", "ScratchAmp") -}, -{ - USB_DEVICE(0x103d, 0x0101), - QUIRK_RENAME_DEVICE("Stanton", "ScratchAmp") -}, - /* Novation EMS devices */ { USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), @@ -2817,20 +2699,10 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, -/* */ -{ - /* aka. Serato Scratch Live DJ Box */ - USB_DEVICE(0x13e5, 0x0001), - QUIRK_RENAME_DEVICE("Rane", "SL-1") -}, - /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */ { USB_DEVICE(0x17aa, 0x1046), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Lenovo", - .product_name = "ThinkStation P620 Rear", - .profile_name = "Lenovo-ThinkStation-P620-Rear", .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND } @@ -2839,9 +2711,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), { USB_DEVICE(0x17aa, 0x104d), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Lenovo", - .product_name = "ThinkStation P620 Main", - .profile_name = "Lenovo-ThinkStation-P620-Main", .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_SETUP_DISABLE_AUTOSUSPEND } @@ -2879,10 +2748,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, /* KeithMcMillen Stringport */ -{ - USB_DEVICE(0x1f38, 0x0001), - .bInterfaceClass = USB_CLASS_AUDIO, -}, +{ USB_DEVICE(0x1f38, 0x0001) }, /* FIXME: should be more restrictive matching */ /* Miditech devices */ { @@ -2913,13 +2779,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), */ #define AU0828_DEVICE(vid, pid, vname, pname) { \ - .idVendor = vid, \ - .idProduct = pid, \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS | \ - USB_DEVICE_ID_MATCH_INT_SUBCLASS, \ - .bInterfaceClass = USB_CLASS_AUDIO, \ - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, \ + USB_AUDIO_DEVICE(vid, pid), \ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { \ .vendor_name = vname, \ .product_name = pname, \ @@ -2949,13 +2809,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), /* Syntek STK1160 */ { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x05e1, - .idProduct = 0x0408, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + USB_AUDIO_DEVICE(0x05e1, 0x0408), .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { .vendor_name = "Syntek", .product_name = "STK1160", @@ -3117,10 +2971,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), }, { /* Tascam US122 MKII - playback-only support */ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x0644, - .idProduct = 0x8021, - .bInterfaceClass = USB_CLASS_AUDIO, + USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021), .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { .vendor_name = "TASCAM", .product_name = "US122 MKII", @@ -3305,19 +3156,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, -/* - * The original product_name is "USB Sound Device", however this name - * is also used by the CM106 based cards, so make it unique. - */ -{ - USB_DEVICE(0x0d8c, 0x0102), - QUIRK_RENAME_DEVICE(NULL, "ICUSBAUDIO7D") -}, -{ - USB_DEVICE(0x0d8c, 0x0103), - QUIRK_RENAME_DEVICE(NULL, "Audio Advantage MicroII") -}, - /* disabled due to regression for other devices; * see https://bugzilla.kernel.org/show_bug.cgi?id=199905 */ @@ -3418,18 +3256,10 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, -/* Dell WD15 Dock */ -{ - USB_DEVICE(0x0bda, 0x4014), - QUIRK_DEVICE_PROFILE("Dell", "WD15 Dock", "Dell-WD15-Dock") -}, /* Dell WD19 Dock */ { USB_DEVICE(0x0bda, 0x402e), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Dell", - .product_name = "WD19 Dock", - .profile_name = "Dell-WD15-Dock", .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_SETUP_FMT_AFTER_RESUME } @@ -3701,33 +3531,6 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, -#define ALC1220_VB_DESKTOP(vend, prod) { \ - USB_DEVICE(vend, prod), \ - QUIRK_DEVICE_PROFILE("Realtek", "ALC1220-VB-DT", \ - "Realtek-ALC1220-VB-Desktop") \ -} -ALC1220_VB_DESKTOP(0x0414, 0xa002), /* Gigabyte TRX40 Aorus Pro WiFi */ -ALC1220_VB_DESKTOP(0x0db0, 0x0d64), /* MSI TRX40 Creator */ -ALC1220_VB_DESKTOP(0x0db0, 0x543d), /* MSI TRX40 */ -ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */ -#undef ALC1220_VB_DESKTOP - -/* Two entries for Gigabyte TRX40 Aorus Master: - * TRX40 Aorus Master has two USB-audio devices, one for the front headphone - * with ESS SABRE9218 DAC chip, while another for the rest I/O (the rear - * panel and the front mic) with Realtek ALC1220-VB. - * Here we provide two distinct names for making UCM profiles easier. - */ -{ - USB_DEVICE(0x0414, 0xa000), - QUIRK_DEVICE_PROFILE("Gigabyte", "Aorus Master Front Headphone", - "Gigabyte-Aorus-Master-Front-Headphone") -}, -{ - USB_DEVICE(0x0414, 0xa001), - QUIRK_DEVICE_PROFILE("Gigabyte", "Aorus Master Main Audio", - "Gigabyte-Aorus-Master-Main-Audio") -}, { /* * Pioneer DJ DJM-900NXS2 @@ -3804,13 +3607,7 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */ * channels to be swapped and out of phase, which is dealt with in quirks.c. */ { - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .idVendor = 0x534d, - .idProduct = 0x2109, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, + USB_AUDIO_DEVICE(0x534d, 0x2109), .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { .vendor_name = "MacroSilicon", .product_name = "MS2109", @@ -3851,3 +3648,4 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */ }, #undef USB_DEVICE_VENDOR_SPEC +#undef USB_AUDIO_DEVICE diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 75bbdc691243..b4fa80ef730d 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -856,7 +856,7 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; void *buf; - if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x05))) + if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x05))) return -EINVAL; buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); if (!buf) @@ -885,8 +885,6 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) { int ret; - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, 0, NULL, 0, 1000); @@ -994,8 +992,6 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n"); - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; /* If the Axe-Fx III has not fully booted, it will timeout when trying * to enable the audio streaming interface. A more generous timeout is * used here to detect when the Axe-Fx III has finished booting as the @@ -1028,7 +1024,7 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf, { int err, actual_length; - if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x01))) + if (usb_pipe_type_check(dev, usb_sndintpipe(dev, 0x01))) return -EINVAL; err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length, &actual_length, 1000); @@ -1040,7 +1036,7 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf, memset(buf, 0, buf_size); - if (snd_usb_pipe_sanity_check(dev, usb_rcvintpipe(dev, 0x82))) + if (usb_pipe_type_check(dev, usb_rcvintpipe(dev, 0x82))) return -EINVAL; err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size, &actual_length, 1000); @@ -1127,8 +1123,6 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev) { int ret; - if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0))) - return -EINVAL; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 1, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0, 0, NULL, 0, 1000); @@ -1678,12 +1672,13 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) msleep(20); - /* Zoom R16/24, Logitech H650e, Jabra 550a, Kingston HyperX needs a tiny - * delay here, otherwise requests like get/set frequency return as - * failed despite actually succeeding. + /* Zoom R16/24, Logitech H650e/H570e, Jabra 550a, Kingston HyperX + * needs a tiny delay here, otherwise requests like get/set + * frequency return as failed despite actually succeeding. */ if ((chip->usb_id == USB_ID(0x1686, 0x00dd) || chip->usb_id == USB_ID(0x046d, 0x0a46) || + chip->usb_id == USB_ID(0x046d, 0x0a56) || chip->usb_id == USB_ID(0x0b0e, 0x0349) || chip->usb_id == USB_ID(0x0951, 0x16ad)) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 6839915a0128..0805b7f21272 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -110,7 +110,6 @@ enum quirk_type { struct snd_usb_audio_quirk { const char *vendor_name; const char *product_name; - const char *profile_name; /* override the card->longname */ int16_t ifnum; uint16_t type; bool shares_media_device; diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index f86f7a61fb36..6e1bfe894dd5 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -82,40 +82,13 @@ static int us144_create_usbmidi(struct snd_card *card) &US122L(card)->midi_list, &quirk); } -/* - * Wrapper for usb_control_msg(). - * Allocates a temp buffer to prevent dmaing from/to the stack. - */ -static int us122l_ctl_msg(struct usb_device *dev, unsigned int pipe, - __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, - __u16 size, int timeout) -{ - int err; - void *buf = NULL; - - if (size > 0) { - buf = kmemdup(data, size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - } - err = usb_control_msg(dev, pipe, request, requesttype, - value, index, buf, size, timeout); - if (size > 0) { - memcpy(data, buf, size); - kfree(buf); - } - return err; -} - static void pt_info_set(struct usb_device *dev, u8 v) { int ret; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 'I', - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - v, 0, NULL, 0, 1000); + ret = usb_control_msg_send(dev, 0, 'I', + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + v, 0, NULL, 0, 1000, GFP_NOIO); snd_printdd(KERN_DEBUG "%i\n", ret); } @@ -305,10 +278,11 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate) data[0] = rate; data[1] = rate >> 8; data[2] = rate >> 16; - err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000); - if (err < 0) + err = usb_control_msg_send(dev, 0, UAC_SET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, + 1000, GFP_NOIO); + if (err) snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", dev->devnum, rate, ep); return err; |