summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/core/control.c1
-rw-r--r--sound/core/hwdep.c1
-rw-r--r--sound/core/oss/pcm_oss.c1
-rw-r--r--sound/core/pcm_lib.c1
-rw-r--r--sound/core/pcm_native.c16
-rw-r--r--sound/core/rawmidi.c4
-rw-r--r--sound/core/seq/oss/seq_oss_device.h2
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c1
-rw-r--r--sound/core/seq/seq_fifo.c5
-rw-r--r--sound/core/seq/seq_memory.c10
-rw-r--r--sound/core/seq/seq_queue.c33
-rw-r--r--sound/core/seq/seq_virmidi.c4
-rw-r--r--sound/core/timer.c19
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c4
-rw-r--r--sound/drivers/mtpav.c4
-rw-r--r--sound/drivers/mts64.c4
-rw-r--r--sound/drivers/portman2x4.c4
-rw-r--r--sound/drivers/serial-u16550.c4
-rw-r--r--sound/drivers/vx/vx_pcm.c8
-rw-r--r--sound/firewire/Kconfig1
-rw-r--r--sound/firewire/bebob/bebob.h1
-rw-r--r--sound/firewire/bebob/bebob_hwdep.c17
-rw-r--r--sound/firewire/bebob/bebob_midi.c26
-rw-r--r--sound/firewire/bebob/bebob_pcm.c51
-rw-r--r--sound/firewire/dice/dice-interface.h1
-rw-r--r--sound/firewire/dice/dice-midi.c22
-rw-r--r--sound/firewire/dice/dice-stream.c12
-rw-r--r--sound/firewire/dice/dice.h1
-rw-r--r--sound/firewire/digi00x/digi00x-hwdep.c17
-rw-r--r--sound/firewire/digi00x/digi00x-midi.c52
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c52
-rw-r--r--sound/firewire/digi00x/digi00x.h1
-rw-r--r--sound/firewire/fireworks/fireworks.h1
-rw-r--r--sound/firewire/fireworks/fireworks_hwdep.c19
-rw-r--r--sound/firewire/fireworks/fireworks_midi.c26
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c52
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c26
-rw-r--r--sound/firewire/oxfw/oxfw-scs1x.c14
-rw-r--r--sound/firewire/oxfw/oxfw.c1
-rw-r--r--sound/firewire/oxfw/oxfw.h1
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c17
-rw-r--r--sound/firewire/tascam/tascam-midi.c26
-rw-r--r--sound/firewire/tascam/tascam-pcm.c52
-rw-r--r--sound/firewire/tascam/tascam.h1
-rw-r--r--sound/isa/gus/gus_pcm.c2
-rw-r--r--sound/isa/gus/gus_uart.c4
-rw-r--r--sound/isa/msnd/msnd.c1
-rw-r--r--sound/isa/msnd/msnd_midi.c2
-rw-r--r--sound/isa/sb/emu8000.c2
-rw-r--r--sound/isa/sb/emu8000_patch.c2
-rw-r--r--sound/isa/sb/emu8000_pcm.c2
-rw-r--r--sound/isa/sb/sb8_midi.c4
-rw-r--r--sound/isa/wavefront/wavefront_midi.c4
-rw-r--r--sound/isa/wavefront/wavefront_synth.c1
-rw-r--r--sound/mips/hal2.c4
-rw-r--r--sound/oss/ad1848.c7
-rw-r--r--sound/oss/dmabuf.c2
-rw-r--r--sound/oss/dmasound/dmasound_core.c1
-rw-r--r--sound/oss/midibuf.c2
-rw-r--r--sound/oss/msnd_pinnacle.c2
-rw-r--r--sound/oss/sound_config.h1
-rw-r--r--sound/oss/swarm_cs4297a.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c2
-rw-r--r--sound/pci/ca0106/ca_midi.c4
-rw-r--r--sound/pci/cs4281.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_dsp_task_types.h2
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c44
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c4
-rw-r--r--sound/pci/ctxfi/cthw20k1.c19
-rw-r--r--sound/pci/ctxfi/cthw20k2.c19
-rw-r--r--sound/pci/echoaudio/midi.c4
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c2
-rw-r--r--sound/pci/emu10k1/emu10k1x.c4
-rw-r--r--sound/pci/emu10k1/emumpu401.c4
-rw-r--r--sound/pci/ens1370.c4
-rw-r--r--sound/pci/hda/hda_codec.c76
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/hda_controller.c4
-rw-r--r--sound/pci/hda/hda_controller.h1
-rw-r--r--sound/pci/hda/hda_intel.c38
-rw-r--r--sound/pci/hda/patch_ca0132.c5
-rw-r--r--sound/pci/hda/patch_hdmi.c247
-rw-r--r--sound/pci/hda/patch_realtek.c45
-rw-r--r--sound/pci/hda/patch_sigmatel.c30
-rw-r--r--sound/pci/ice1712/ice1724.c4
-rw-r--r--sound/pci/ice1712/wm8766.c2
-rw-r--r--sound/pci/ice1712/wm8776.c2
-rw-r--r--sound/pci/korg1212/korg1212.c4
-rw-r--r--sound/pci/mixart/mixart.h2
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c2
-rw-r--r--sound/pci/rme9652/hdsp.c4
-rw-r--r--sound/pci/rme9652/hdspm.c4
-rw-r--r--sound/pci/vx222/vx222_ops.c12
-rw-r--r--sound/pcmcia/vx/vxp_ops.c14
-rw-r--r--sound/ppc/snd_ps3.c2
-rw-r--r--sound/soc/amd/acp-pcm-dma.c2
-rw-r--r--sound/soc/atmel/atmel-classd.c2
-rw-r--r--sound/soc/codecs/hdac_hdmi.c16
-rw-r--r--sound/soc/codecs/wm_adsp.c9
-rw-r--r--sound/soc/codecs/wm_hubs.c2
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/intel/skylake/skl-topology.c2
-rw-r--r--sound/soc/qcom/lpass.h2
-rw-r--r--sound/soc/sh/rcar/cmd.c36
-rw-r--r--sound/soc/sh/rcar/dma.c18
-rw-r--r--sound/soc/sh/rcar/ssiu.c6
-rw-r--r--sound/soc/soc-core.c10
-rw-r--r--sound/soc/soc-topology.c4
-rw-r--r--sound/synth/emux/emux_seq.c14
-rw-r--r--sound/usb/6fire/midi.c4
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/bcd2000/bcd2000.c4
-rw-r--r--sound/usb/caiaq/midi.c4
-rw-r--r--sound/usb/line6/driver.c49
-rw-r--r--sound/usb/line6/midi.c4
-rw-r--r--sound/usb/midi.c4
-rw-r--r--sound/usb/mixer_quirks.c5
-rw-r--r--sound/usb/mixer_us16x08.c1419
-rw-r--r--sound/usb/mixer_us16x08.h121
-rw-r--r--sound/usb/quirks.c15
-rw-r--r--sound/usb/usx2y/us122l.c5
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c7
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c5
-rw-r--r--sound/x86/Kconfig16
-rw-r--r--sound/x86/Makefile4
-rw-r--r--sound/x86/intel_hdmi_audio.c1867
-rw-r--r--sound/x86/intel_hdmi_audio.h136
-rw-r--r--sound/x86/intel_hdmi_lpe_audio.h328
130 files changed, 4847 insertions, 558 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 5a240e050ae6..ee2e69a9ecd1 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -108,6 +108,8 @@ source "sound/parisc/Kconfig"
source "sound/soc/Kconfig"
+source "sound/x86/Kconfig"
+
endif # SND
menuconfig SOUND_PRIME
diff --git a/sound/Makefile b/sound/Makefile
index c41bdf5fdf24..6de45d2c32f7 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
- firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
+ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/core/control.c b/sound/core/control.c
index fb096cb20a80..c109b82eef4b 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 36d2416f90d9..9602a7e38d8a 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -25,6 +25,7 @@
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/minors.h>
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 698a01419515..36baf962f9b0 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index bb1261591a1f..5088d4b8db22 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -21,6 +21,7 @@
*/
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/export.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 9d33c1e85c79..13dec5ec93f2 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/file.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/pm_qos.h>
#include <linux/io.h>
@@ -3245,10 +3246,9 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
/*
* mmap status record
*/
-static int snd_pcm_mmap_status_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_status_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
if (substream == NULL)
@@ -3282,10 +3282,9 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
/*
* mmap control record
*/
-static int snd_pcm_mmap_control_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_control_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
if (substream == NULL)
@@ -3341,10 +3340,9 @@ snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
/*
* fault callback for mmapping a RAM page
*/
-static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_data_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
unsigned long offset;
struct page * page;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 2096bb0835c8..ab890336175f 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -22,7 +22,7 @@
#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
@@ -1749,7 +1749,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
* Sets the rawmidi operators for the given stream direction.
*/
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
- struct snd_rawmidi_ops *ops)
+ const struct snd_rawmidi_ops *ops)
{
struct snd_rawmidi_substream *substream;
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index d7b4d016b547..afa007c0cc2d 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -24,7 +24,7 @@
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/seq_oss.h>
#include <sound/rawmidi.h>
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
index 1f6788a18444..5e04f4df10e4 100644
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -28,6 +28,7 @@
#include "../seq_clientmgr.h"
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
/*
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 1d5acbe0c08b..448efd4e980e 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -21,6 +21,8 @@
#include <sound/core.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
+
#include "seq_fifo.h"
#include "seq_lock.h"
@@ -135,6 +137,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
f->tail = cell;
if (f->head == NULL)
f->head = cell;
+ cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
@@ -214,6 +217,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
spin_lock_irqsave(&f->lock, flags);
cell->next = f->head;
f->head = cell;
+ if (!f->tail)
+ f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
}
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index c850345c43b5..1a1acf3ddda4 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/export.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
@@ -419,7 +420,6 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
{
unsigned long flags;
struct snd_seq_event_cell *ptr;
- int max_count = 5 * HZ;
if (snd_BUG_ON(!pool))
return -EINVAL;
@@ -432,14 +432,8 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
if (waitqueue_active(&pool->output_sleep))
wake_up(&pool->output_sleep);
- while (atomic_read(&pool->counter) > 0) {
- if (max_count == 0) {
- pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
- break;
- }
+ while (atomic_read(&pool->counter) > 0)
schedule_timeout_uninterruptible(1);
- max_count--;
- }
/* release all resources */
spin_lock_irqsave(&pool->lock, flags);
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 0bec02e89d51..450c5187eecb 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -181,6 +181,8 @@ void __exit snd_seq_queues_delete(void)
}
}
+static void queue_use(struct snd_seq_queue *queue, int client, int use);
+
/* allocate a new queue -
* return queue index value or negative value for error
*/
@@ -192,11 +194,11 @@ int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
if (q == NULL)
return -ENOMEM;
q->info_flags = info_flags;
+ queue_use(q, client, 1);
if (queue_list_add(q) < 0) {
queue_delete(q);
return -ENOMEM;
}
- snd_seq_queue_use(q->queue, client, 1); /* use this queue */
return q->queue;
}
@@ -502,19 +504,9 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client,
return result;
}
-
-/* use or unuse this queue -
- * if it is the first client, starts the timer.
- * if it is not longer used by any clients, stop the timer.
- */
-int snd_seq_queue_use(int queueid, int client, int use)
+/* use or unuse this queue */
+static void queue_use(struct snd_seq_queue *queue, int client, int use)
{
- struct snd_seq_queue *queue;
-
- queue = queueptr(queueid);
- if (queue == NULL)
- return -EINVAL;
- mutex_lock(&queue->timer_mutex);
if (use) {
if (!test_and_set_bit(client, queue->clients_bitmap))
queue->clients++;
@@ -529,6 +521,21 @@ int snd_seq_queue_use(int queueid, int client, int use)
} else {
snd_seq_timer_close(queue);
}
+}
+
+/* use or unuse this queue -
+ * if it is the first client, starts the timer.
+ * if it is not longer used by any clients, stop the timer.
+ */
+int snd_seq_queue_use(int queueid, int client, int use)
+{
+ struct snd_seq_queue *queue;
+
+ queue = queueptr(queueid);
+ if (queue == NULL)
+ return -EINVAL;
+ mutex_lock(&queue->timer_mutex);
+ queue_use(queue, client, use);
mutex_unlock(&queue->timer_mutex);
queuefree(queue);
return 0;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index c82ed3e70506..52f31f1498f9 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -349,13 +349,13 @@ static int snd_virmidi_unuse(void *private_data,
* Register functions
*/
-static struct snd_rawmidi_ops snd_virmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_input_ops = {
.open = snd_virmidi_input_open,
.close = snd_virmidi_input_close,
.trigger = snd_virmidi_input_trigger,
};
-static struct snd_rawmidi_ops snd_virmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_output_ops = {
.open = snd_virmidi_output_open,
.close = snd_virmidi_output_close,
.trigger = snd_virmidi_output_trigger,
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fc144f43faa6..6d4fbc439246 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -27,6 +27,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/control.h>
@@ -1702,9 +1703,21 @@ static int snd_timer_user_params(struct file *file,
return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
- if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
- err = -EINVAL;
- goto _end;
+ if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
+ u64 resolution;
+
+ if (params.ticks < 1) {
+ err = -EINVAL;
+ goto _end;
+ }
+
+ /* Don't allow resolution less than 1ms */
+ resolution = snd_timer_resolution(tu->timeri);
+ resolution *= params.ticks;
+ if (resolution < 1000000) {
+ err = -EINVAL;
+ goto _end;
+ }
}
if (params.queue_size > 0 &&
(params.queue_size < 32 || params.queue_size > 1024)) {
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 776596b5ee05..3a7c317ae012 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -481,14 +481,14 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
*/
-static struct snd_rawmidi_ops snd_mpu401_uart_output =
+static const struct snd_rawmidi_ops snd_mpu401_uart_output =
{
.open = snd_mpu401_uart_output_open,
.close = snd_mpu401_uart_output_close,
.trigger = snd_mpu401_uart_output_trigger,
};
-static struct snd_rawmidi_ops snd_mpu401_uart_input =
+static const struct snd_rawmidi_ops snd_mpu401_uart_input =
{
.open = snd_mpu401_uart_input_open,
.close = snd_mpu401_uart_input_close,
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 30e8a1d5bc87..00b31f92c504 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -600,13 +600,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard)
/*
*/
-static struct snd_rawmidi_ops snd_mtpav_output = {
+static const struct snd_rawmidi_ops snd_mtpav_output = {
.open = snd_mtpav_output_open,
.close = snd_mtpav_output_close,
.trigger = snd_mtpav_output_trigger,
};
-static struct snd_rawmidi_ops snd_mtpav_input = {
+static const struct snd_rawmidi_ops snd_mtpav_input = {
.open = snd_mtpav_input_open,
.close = snd_mtpav_input_close,
.trigger = snd_mtpav_input_trigger,
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index fd4d18df84d3..f32e81342247 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -749,13 +749,13 @@ static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&mts->lock, flags);
}
-static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
.open = snd_mts64_rawmidi_open,
.close = snd_mts64_rawmidi_close,
.trigger = snd_mts64_rawmidi_output_trigger
};
-static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
.open = snd_mts64_rawmidi_open,
.close = snd_mts64_rawmidi_close,
.trigger = snd_mts64_rawmidi_input_trigger
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 189e3e7028af..ec8a94325ef6 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -546,13 +546,13 @@ static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&pm->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_portman_midi_output = {
+static const struct snd_rawmidi_ops snd_portman_midi_output = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_portman_midi_input = {
+static const struct snd_rawmidi_ops snd_portman_midi_input = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_input_trigger,
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 1927b89e1d1f..60d51ac4ccfe 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -752,14 +752,14 @@ static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream
snd_uart16550_output_write(substream);
}
-static struct snd_rawmidi_ops snd_uart16550_output =
+static const struct snd_rawmidi_ops snd_uart16550_output =
{
.open = snd_uart16550_output_open,
.close = snd_uart16550_output_close,
.trigger = snd_uart16550_output_trigger,
};
-static struct snd_rawmidi_ops snd_uart16550_input =
+static const struct snd_rawmidi_ops snd_uart16550_input =
{
.open = snd_uart16550_input_open,
.close = snd_uart16550_input_close,
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 11467272089e..ea7b377f0378 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -1015,7 +1015,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
int size, space, count;
struct snd_pcm_runtime *runtime = subs->runtime;
- if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
+ if (!pipe->running || (chip->chip_status & VX_STAT_IS_STALE))
return;
size = runtime->buffer_size - snd_pcm_capture_avail(runtime);
@@ -1048,8 +1048,10 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
/* ok, let's accelerate! */
int align = pipe->align * 3;
space = (count / align) * align;
- vx_pseudo_dma_read(chip, runtime, pipe, space);
- count -= space;
+ if (space > 0) {
+ vx_pseudo_dma_read(chip, runtime, pipe, space);
+ count -= space;
+ }
}
/* read the rest of bytes */
while (count > 0) {
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index ab894ed1ff67..9f00696c4e4a 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -34,6 +34,7 @@ config SND_OXFW
* LaCie Firewire Speakers
* Behringer F-Control Audio 202
* Mackie(Loud) Onyx-i series (former models)
+ * Mackie(Loud) Onyx 1640i (former model)
* Mackie(Loud) Onyx Satellite
* Mackie(Loud) Tapco Link.Firewire
* Mackie(Loud) d.2 pro/d.4 pro
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index 175da875162d..17678d6ab5a2 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -17,6 +17,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c
index ce731f4d8b4f..2b367c21b80c 100644
--- a/sound/firewire/bebob/bebob_hwdep.c
+++ b/sound/firewire/bebob/bebob_hwdep.c
@@ -172,16 +172,15 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -190,7 +189,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
goto end;
strcpy(hwdep->name, "BeBoB");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = bebob;
hwdep->exclusive = true;
end:
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c
index 868eb0decbec..3befa3eca6ef 100644
--- a/sound/firewire/bebob/bebob_midi.c
+++ b/sound/firewire/bebob/bebob_midi.c
@@ -106,18 +106,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&bebob->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_bebob *bebob,
struct snd_rawmidi_str *str)
{
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -151,7 +149,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -162,7 +160,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index 5d7b9343fa85..9e27eb8e1dd4 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -359,32 +359,31 @@ pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&bebob->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -395,8 +394,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
pcm->private_data = bebob;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", bebob->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
end:
return err;
}
diff --git a/sound/firewire/dice/dice-interface.h b/sound/firewire/dice/dice-interface.h
index 27b044f84c81..47f2c0a6f5d9 100644
--- a/sound/firewire/dice/dice-interface.h
+++ b/sound/firewire/dice/dice-interface.h
@@ -251,6 +251,7 @@
/*
* The speed at which the packets are sent, SCODE_100-_400; read/write.
+ * SCODE_800 is only available in Dice III.
*/
#define TX_SPEED 0x014
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
index a040617505a7..8ff6da3c51f7 100644
--- a/sound/firewire/dice/dice-midi.c
+++ b/sound/firewire/dice/dice-midi.c
@@ -78,18 +78,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&dice->lock, flags);
}
-static struct snd_rawmidi_ops capture_ops = {
- .open = midi_open,
- .close = midi_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops playback_ops = {
- .open = midi_open,
- .close = midi_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_dice *dice,
struct snd_rawmidi_str *str)
{
@@ -103,6 +91,16 @@ static void set_midi_substream_names(struct snd_dice *dice,
int snd_dice_create_midi(struct snd_dice *dice)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_playback_trigger,
+ };
__be32 reg;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index ec4db3a514fc..8573289c381e 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -195,6 +195,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
unsigned int i, pcm_chs, midi_ports;
struct amdtp_stream *streams;
struct fw_iso_resources *resources;
+ struct fw_device *fw_dev = fw_parent_device(dice->unit);
int err = 0;
if (dir == AMDTP_IN_STREAM) {
@@ -237,8 +238,17 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
if (err < 0)
return err;
+ if (dir == AMDTP_IN_STREAM) {
+ reg[0] = cpu_to_be32(fw_dev->max_speed);
+ err = snd_dice_transaction_write_tx(dice,
+ params->size * i + TX_SPEED,
+ reg, sizeof(reg[0]));
+ if (err < 0)
+ return err;
+ }
+
err = amdtp_stream_start(&streams[i], resources[i].channel,
- fw_parent_device(dice->unit)->max_speed);
+ fw_dev->max_speed);
if (err < 0)
return err;
}
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index e6c07857f475..da00e75e09d4 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/sched/signal.h>
#include <sound/control.h>
#include <sound/core.h>
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
index f188e4758fd2..463c6b8e864d 100644
--- a/sound/firewire/digi00x/digi00x-hwdep.c
+++ b/sound/firewire/digi00x/digi00x-hwdep.c
@@ -173,16 +173,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -192,7 +191,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
strcpy(hwdep->name, "Digi00x");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = dg00x;
hwdep->exclusive = true;
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 1a72a382b384..915d2a21223e 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -76,18 +76,6 @@ static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&dg00x->lock, flags);
}
-static struct snd_rawmidi_ops midi_phys_capture_ops = {
- .open = midi_phys_open,
- .close = midi_phys_close,
- .trigger = midi_phys_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_phys_playback_ops = {
- .open = midi_phys_open,
- .close = midi_phys_close,
- .trigger = midi_phys_playback_trigger,
-};
-
static int midi_ctl_open(struct snd_rawmidi_substream *substream)
{
/* Do nothing. */
@@ -139,18 +127,6 @@ static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&dg00x->lock, flags);
}
-static struct snd_rawmidi_ops midi_ctl_capture_ops = {
- .open = midi_ctl_open,
- .close = midi_ctl_capture_close,
- .trigger = midi_ctl_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_ctl_playback_ops = {
- .open = midi_ctl_open,
- .close = midi_ctl_playback_close,
- .trigger = midi_ctl_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_dg00x *dg00x,
struct snd_rawmidi_str *str,
bool is_ctl)
@@ -172,6 +148,26 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x,
int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
{
+ static const struct snd_rawmidi_ops phys_capture_ops = {
+ .open = midi_phys_open,
+ .close = midi_phys_close,
+ .trigger = midi_phys_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops phys_playback_ops = {
+ .open = midi_phys_open,
+ .close = midi_phys_close,
+ .trigger = midi_phys_playback_trigger,
+ };
+ static const struct snd_rawmidi_ops ctl_capture_ops = {
+ .open = midi_ctl_open,
+ .close = midi_ctl_capture_close,
+ .trigger = midi_ctl_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops ctl_playback_ops = {
+ .open = midi_ctl_open,
+ .close = midi_ctl_playback_close,
+ .trigger = midi_ctl_playback_trigger,
+ };
struct snd_rawmidi *rmidi[2];
struct snd_rawmidi_str *str;
unsigned int i;
@@ -187,9 +183,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
"%s MIDI", dg00x->card->shortname);
snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_phys_capture_ops);
+ &phys_capture_ops);
snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_phys_playback_ops);
+ &phys_playback_ops);
/* Add a pair of control midi ports. */
err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1,
@@ -201,9 +197,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
"%s control", dg00x->card->shortname);
snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_ctl_capture_ops);
+ &ctl_capture_ops);
snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_ctl_playback_ops);
+ &ctl_playback_ops);
for (i = 0; i < ARRAY_SIZE(rmidi); i++) {
rmidi[i]->private_data = dg00x;
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index 613f05872770..68d1c52db051 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -329,33 +329,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -366,8 +364,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
pcm->private_data = dg00x;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", dg00x->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
return 0;
}
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 2cd465c0caae..9dc761bdacca 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -16,6 +16,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index d73c12b8753d..9b19c7f05d57 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -17,6 +17,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index 2e1d9a23920c..a3a3a16f5e08 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -303,17 +303,16 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .write = hwdep_write,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_efw_create_hwdep_device(struct snd_efw *efw)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .write = hwdep_write,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -322,7 +321,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw)
goto end;
strcpy(hwdep->name, "Fireworks");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = efw;
hwdep->exclusive = true;
end:
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index 3e8c4cf9fe1e..f5da2cd4ce42 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -107,18 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&efw->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_efw *efw,
struct snd_rawmidi_str *str)
{
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_efw *efw,
int snd_efw_create_midi_devices(struct snd_efw *efw)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -151,7 +149,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -162,7 +160,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index f4fbf75ed198..9171702f7d0b 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -383,33 +383,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&efw->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_efw_create_pcm_devices(struct snd_efw *efw)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -419,8 +417,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
pcm->private_data = efw;
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
end:
return err;
}
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
index 8665e1043d41..b7bbd77dfff1 100644
--- a/sound/firewire/oxfw/oxfw-midi.c
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -116,18 +116,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&oxfw->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_oxfw *oxfw,
struct snd_rawmidi_str *str)
{
@@ -142,6 +130,16 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -164,7 +162,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -175,7 +173,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c
index f897c9831077..93209ebd9121 100644
--- a/sound/firewire/oxfw/oxfw-scs1x.c
+++ b/sound/firewire/oxfw/oxfw-scs1x.c
@@ -297,7 +297,7 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
}
}
-static struct snd_rawmidi_ops midi_capture_ops = {
+static const struct snd_rawmidi_ops midi_capture_ops = {
.open = midi_capture_open,
.close = midi_capture_close,
.trigger = midi_capture_trigger,
@@ -338,12 +338,6 @@ static void midi_playback_drain(struct snd_rawmidi_substream *stream)
wait_event(scs->idle_wait, scs->output_idle);
}
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
- .drain = midi_playback_drain,
-};
static int register_address(struct snd_oxfw *oxfw)
{
struct fw_scs1x *scs = oxfw->spec;
@@ -369,6 +363,12 @@ void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw)
int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
{
+ static const struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ .drain = midi_playback_drain,
+ };
struct snd_rawmidi *rmidi;
struct fw_scs1x *scs;
int err;
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index e629b88f7d93..74d7fb6efce6 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -43,6 +43,7 @@ static bool detect_loud_models(struct fw_unit *unit)
const char *const models[] = {
"Onyxi",
"Onyx-i",
+ "Onyx 1640i",
"d.Pro",
"Mackie Onyx Satellite",
"Tapco LINK.firewire 4x6",
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 2047dcb27625..d54d4a9ac4a1 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
+#include <linux/sched/signal.h>
#include <sound/control.h>
#include <sound/core.h>
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 106406cbfaa3..8c4437d0051d 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -163,16 +163,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -182,7 +181,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
strcpy(hwdep->name, "Tascam");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = tscm;
hwdep->exclusive = true;
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c
index 41f842079d9d..df4f95d65925 100644
--- a/sound/firewire/tascam/tascam-midi.c
+++ b/sound/firewire/tascam/tascam-midi.c
@@ -68,20 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&tscm->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *stream;
struct snd_rawmidi_substream *subs;
@@ -100,7 +98,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
/* Set port names for MIDI input. */
@@ -116,7 +114,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
/* Set port names for MIDI ourput. */
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index 79db1b651f5c..f5dd6ce6b6f1 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -268,33 +268,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&tscm->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -305,8 +303,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
pcm->private_data = tscm;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", tscm->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
return 0;
}
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index 1f61011579a7..d3cd4065722b 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 25f6788ccef3..06505999155f 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -27,6 +27,8 @@
#include <asm/dma.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
+
#include <sound/core.h>
#include <sound/control.h>
#include <sound/gus.h>
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index 3992912743f5..ac5f5687d1a3 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -227,14 +227,14 @@ static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
}
-static struct snd_rawmidi_ops snd_gf1_uart_output =
+static const struct snd_rawmidi_ops snd_gf1_uart_output =
{
.open = snd_gf1_uart_output_open,
.close = snd_gf1_uart_output_close,
.trigger = snd_gf1_uart_output_trigger,
};
-static struct snd_rawmidi_ops snd_gf1_uart_input =
+static const struct snd_rawmidi_ops snd_gf1_uart_input =
{
.open = snd_gf1_uart_input_open,
.close = snd_gf1_uart_input_close,
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
index 835d4aa26761..8109ab3d29d1 100644
--- a/sound/isa/msnd/msnd.c
+++ b/sound/isa/msnd/msnd.c
@@ -36,6 +36,7 @@
********************************************************************/
#include <linux/kernel.h>
+#include <linux/sched/signal.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
index ffc67fd80c23..912b5a9ccbab 100644
--- a/sound/isa/msnd/msnd_midi.c
+++ b/sound/isa/msnd/msnd_midi.c
@@ -142,7 +142,7 @@ void snd_msndmidi_input_read(void *mpuv)
}
EXPORT_SYMBOL(snd_msndmidi_input_read);
-static struct snd_rawmidi_ops snd_msndmidi_input = {
+static const struct snd_rawmidi_ops snd_msndmidi_input = {
.open = snd_msndmidi_input_open,
.close = snd_msndmidi_input_close,
.trigger = snd_msndmidi_input_trigger,
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 94c411299e5a..ec180708f160 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -21,7 +21,7 @@
*/
#include <linux/wait.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/export.h>
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 71d13c0bb746..c2e41d2762f7 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -20,6 +20,8 @@
*/
#include "emu8000_local.h"
+
+#include <linux/sched/signal.h>
#include <linux/uaccess.h>
#include <linux/moduleparam.h>
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index 250fd0006b53..32f234f494e5 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -19,6 +19,8 @@
*/
#include "emu8000_local.h"
+
+#include <linux/sched/signal.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/initval.h>
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index d551c50e549f..bd672abb4854 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -247,14 +247,14 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_sb8dsp_midi_output_write(substream);
}
-static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_output =
{
.open = snd_sb8dsp_midi_output_open,
.close = snd_sb8dsp_midi_output_close,
.trigger = snd_sb8dsp_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_sb8dsp_midi_input =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_input =
{
.open = snd_sb8dsp_midi_input_open,
.close = snd_sb8dsp_midi_input_close,
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 8a80fc6a616b..2aa05f3aaa38 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -559,14 +559,14 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
return 0;
}
-struct snd_rawmidi_ops snd_wavefront_midi_output =
+const struct snd_rawmidi_ops snd_wavefront_midi_output =
{
.open = snd_wavefront_midi_output_open,
.close = snd_wavefront_midi_output_close,
.trigger = snd_wavefront_midi_output_trigger,
};
-struct snd_rawmidi_ops snd_wavefront_midi_input =
+const struct snd_rawmidi_ops snd_wavefront_midi_input =
{
.open = snd_wavefront_midi_input_open,
.close = snd_wavefront_midi_input_close,
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 718d5e3b7806..4dae9ff9ef5a 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/wait.h>
+#include <linux/sched/signal.h>
#include <linux/firmware.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
index ede449f0b50d..00fc9241d266 100644
--- a/sound/mips/hal2.c
+++ b/sound/mips/hal2.c
@@ -219,6 +219,8 @@ static int hal2_gain_get(struct snd_kcontrol *kcontrol,
l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15;
r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15;
break;
+ default:
+ return -EINVAL;
}
ucontrol->value.integer.value[0] = l;
ucontrol->value.integer.value[1] = r;
@@ -256,6 +258,8 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol,
new |= (r << H2I_C2_R_GAIN_SHIFT);
hal2_i_write32(hal2, H2I_ADC_C2, new);
break;
+ default:
+ return -EINVAL;
}
return old != new;
}
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 6368e5c7d0ba..f6156d8169d0 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -121,11 +121,6 @@ static bool deskpro_xl;
static bool deskpro_m;
static bool soundpro;
-static volatile signed char irq2dev[17] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1
-};
-
#ifndef EXCLUDE_TIMERS
static int timer_installed = -1;
#endif
@@ -2060,7 +2055,7 @@ int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback,
else
devc->irq_ok = 1; /* Couldn't test. assume it's OK */
} else if (irq < 0)
- irq2dev[-irq] = devc->dev_no = my_dev;
+ devc->dev_no = my_dev;
#ifndef EXCLUDE_TIMERS
if ((capabilities[devc->model].flags & CAP_F_TIMER) &&
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index e3f29132d3ac..c5dd396c66a2 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -27,6 +27,8 @@
#include <linux/mm.h>
#include <linux/gfp.h>
+#include <linux/sched/signal.h>
+
#include "sound_config.h"
#include "sleep.h"
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index 5f248fb41bea..fb3bbceb1fef 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -182,6 +182,7 @@
#include <linux/soundcard.h>
#include <linux/poll.h>
#include <linux/mutex.h>
+#include <linux/sched/signal.h>
#include <linux/uaccess.h>
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index 8f45cd999965..701c7625c971 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -16,6 +16,8 @@
#include <linux/stddef.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
+#include <linux/sched/signal.h>
+
#define MIDIBUF_C
#include "sound_config.h"
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index a8bb4a06ba6f..f34ec01d2239 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -41,6 +41,8 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/gfp.h>
+#include <linux/sched/signal.h>
+
#include <asm/irq.h>
#include <asm/io.h>
#include "sound_config.h"
diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h
index f2554ab78f5e..5253b0a70437 100644
--- a/sound/oss/sound_config.h
+++ b/sound/oss/sound_config.h
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/sound.h>
+#include <linux/sched/signal.h>
#include "os.h"
#include "soundvers.h"
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index f3af63e58b36..97899352b15f 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -64,7 +64,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index f4234edb878c..8cf0dc7a07a4 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -3093,7 +3093,7 @@ static int patch_cm9739(struct snd_ac97 * ac97)
/* set-up multi channel */
/* bit 14: 0 = SPDIF, 1 = EAPD */
/* bit 13: enable internal vref output for mic */
- /* bit 12: disable center/lfe (swithable) */
+ /* bit 12: disable center/lfe (switchable) */
/* bit 10: disable surround/line (switchable) */
/* bit 9: mix 2 surround off */
/* bit 4: undocumented; 0 mutes the CM9739A, which defaults to 1 */
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index b91c7f6d19f9..4d4d385205eb 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -255,14 +255,14 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int
}
}
-static struct snd_rawmidi_ops ca_midi_output =
+static const struct snd_rawmidi_ops ca_midi_output =
{
.open = ca_midi_output_open,
.close = ca_midi_output_close,
.trigger = ca_midi_output_trigger,
};
-static struct snd_rawmidi_ops ca_midi_input =
+static const struct snd_rawmidi_ops ca_midi_input =
{
.open = ca_midi_input_open,
.close = ca_midi_input_close,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 8f0f5f24e40e..fa7c51684dd2 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1767,14 +1767,14 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_cs4281_midi_output =
+static const struct snd_rawmidi_ops snd_cs4281_midi_output =
{
.open = snd_cs4281_midi_output_open,
.close = snd_cs4281_midi_output_close,
.trigger = snd_cs4281_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_cs4281_midi_input =
+static const struct snd_rawmidi_ops snd_cs4281_midi_input =
{
.open = snd_cs4281_midi_input_open,
.close = snd_cs4281_midi_input_close,
diff --git a/sound/pci/cs46xx/cs46xx_dsp_task_types.h b/sound/pci/cs46xx/cs46xx_dsp_task_types.h
index 5cf920bfda27..be5694718546 100644
--- a/sound/pci/cs46xx/cs46xx_dsp_task_types.h
+++ b/sound/pci/cs46xx/cs46xx_dsp_task_types.h
@@ -203,7 +203,7 @@ struct dsp_task_tree_context_block {
u32 saverfe;
- /* Value may be overwriten by stack save algorithm.
+ /* Value may be overwritten by stack save algorithm.
Retain the size of the stack data saved here if used */
___DSP_DUAL_16BIT_ALLOC(
reserved1,
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index fde3cd48258c..e4cf3187b4dd 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -72,18 +72,18 @@
static void amp_voyetra(struct snd_cs46xx *chip, int change);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
#endif
-static struct snd_pcm_ops snd_cs46xx_playback_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
unsigned short reg,
@@ -1654,7 +1654,7 @@ static int snd_cs46xx_capture_close(struct snd_pcm_substream *substream)
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
.open = snd_cs46xx_playback_open_rear,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1665,7 +1665,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
.open = snd_cs46xx_playback_open_rear,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1677,7 +1677,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
.open = snd_cs46xx_playback_open_clfe,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1688,7 +1688,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
.open = snd_cs46xx_playback_open_clfe,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1700,7 +1700,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
.open = snd_cs46xx_playback_open_iec958,
.close = snd_cs46xx_playback_close_iec958,
.ioctl = snd_pcm_lib_ioctl,
@@ -1711,7 +1711,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
.open = snd_cs46xx_playback_open_iec958,
.close = snd_cs46xx_playback_close_iec958,
.ioctl = snd_pcm_lib_ioctl,
@@ -1725,7 +1725,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
#endif
-static struct snd_pcm_ops snd_cs46xx_playback_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_ops = {
.open = snd_cs46xx_playback_open,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1736,7 +1736,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
.open = snd_cs46xx_playback_open,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1748,7 +1748,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_capture_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_ops = {
.open = snd_cs46xx_capture_open,
.close = snd_cs46xx_capture_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1759,7 +1759,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_ops = {
.pointer = snd_cs46xx_capture_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
.open = snd_cs46xx_capture_open,
.close = snd_cs46xx_capture_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -2683,14 +2683,14 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_cs46xx_midi_output =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_output =
{
.open = snd_cs46xx_midi_output_open,
.close = snd_cs46xx_midi_output_close,
.trigger = snd_cs46xx_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_cs46xx_midi_input =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_input =
{
.open = snd_cs46xx_midi_input_open,
.close = snd_cs46xx_midi_input_close,
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index 06ac5d8da362..82bd10b68a77 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -55,7 +55,7 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
}
-static int snd_cs5535audio_suspend(struct device *dev)
+static int __maybe_unused snd_cs5535audio_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
@@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev)
return 0;
}
-static int snd_cs5535audio_resume(struct device *dev)
+static int __maybe_unused snd_cs5535audio_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 9667cbfb0ca2..ab4cdab5cfa5 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -27,12 +27,6 @@
#include "cthw20k1.h"
#include "ct20k1reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k1 {
struct hw hw;
spinlock_t reg_20k1_lock;
@@ -1904,19 +1898,18 @@ static int hw_card_start(struct hw *hw)
{
int err;
struct pci_dev *pci = hw->pci;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 6414ecf93efa..18ee7768b7c4 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -26,12 +26,6 @@
#include "cthw20k2.h"
#include "ct20k2reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k2 {
struct hw hw;
/* for i2c */
@@ -2029,19 +2023,18 @@ static int hw_card_start(struct hw *hw)
int err = 0;
struct pci_dev *pci = hw->pci;
unsigned int gctl;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index a8fe58335ddc..8c685ddb1a41 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -288,13 +288,13 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
-static struct snd_rawmidi_ops snd_echo_midi_input = {
+static const struct snd_rawmidi_ops snd_echo_midi_input = {
.open = snd_echo_midi_input_open,
.close = snd_echo_midi_input_close,
.trigger = snd_echo_midi_input_trigger,
};
-static struct snd_rawmidi_ops snd_echo_midi_output = {
+static const struct snd_rawmidi_ops snd_echo_midi_output = {
.open = snd_echo_midi_output_open,
.close = snd_echo_midi_output_close,
.trigger = snd_echo_midi_output_trigger,
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index d2c7ea3a7610..aa2cc27b8491 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -61,7 +61,7 @@ static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
/*
* set up operators
*/
-static struct snd_emux_operators emu10k1_ops = {
+static const struct snd_emux_operators emu10k1_ops = {
.owner = THIS_MODULE,
.get_voice = get_voice,
.prepare = start_voice,
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 921037ed8468..32842734ada6 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1486,14 +1486,14 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
*/
-static struct snd_rawmidi_ops snd_emu10k1x_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_output =
{
.open = snd_emu10k1x_midi_output_open,
.close = snd_emu10k1x_midi_output_close,
.trigger = snd_emu10k1x_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_emu10k1x_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_input =
{
.open = snd_emu10k1x_midi_input_open,
.close = snd_emu10k1x_midi_input_close,
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index fdf2b0ada489..b6650f5c1621 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -308,14 +308,14 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
*/
-static struct snd_rawmidi_ops snd_emu10k1_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_output =
{
.open = snd_emu10k1_midi_output_open,
.close = snd_emu10k1_midi_output_close,
.trigger = snd_emu10k1_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_emu10k1_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_input =
{
.open = snd_emu10k1_midi_input_open,
.close = snd_emu10k1_midi_input_close,
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 51736c2b5a00..164adad91650 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -2317,14 +2317,14 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_ensoniq_midi_output =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_output =
{
.open = snd_ensoniq_midi_output_open,
.close = snd_ensoniq_midi_output_close,
.trigger = snd_ensoniq_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_ensoniq_midi_input =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_input =
{
.open = snd_ensoniq_midi_input_open,
.close = snd_ensoniq_midi_input_close,
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 9913be8532ab..8fd745cb3f36 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -311,9 +311,15 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
}
EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
-
-/* return DEVLIST_LEN parameter of the given widget */
-static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
+/**
+ * snd_hda_get_num_devices - get DEVLIST_LEN parameter of the given widget
+ * @codec: the HDA codec
+ * @nid: NID of the pin to parse
+ *
+ * Get the device entry number on the given widget. This is a feature of
+ * DP MST audio. Each pin can have several device entries in it.
+ */
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int wcaps = get_wcaps(codec, nid);
unsigned int parm;
@@ -327,6 +333,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
parm = 0;
return parm & AC_DEV_LIST_LEN_MASK;
}
+EXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
/**
* snd_hda_get_devices - copy device list without cache
@@ -344,7 +351,7 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
int i, dev_len, devices;
- parm = get_num_devices(codec, nid);
+ parm = snd_hda_get_num_devices(codec, nid);
if (!parm) /* not multi-stream capable */
return 0;
@@ -368,6 +375,63 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
return devices;
}
+/**
+ * snd_hda_get_dev_select - get device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to get device entry select
+ *
+ * Get the devcie entry select on the pin. Return the device entry
+ * id selected on the pin. Return 0 means the first device entry
+ * is selected or MST is not supported.
+ */
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid)
+{
+ /* not support dp_mst will always return 0, using first dev_entry */
+ if (!codec->dp_mst)
+ return 0;
+
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_dev_select);
+
+/**
+ * snd_hda_set_dev_select - set device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to set device entry select
+ * @dev_id: device entry id to be set
+ *
+ * Set the device entry select on the pin nid.
+ */
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id)
+{
+ int ret, num_devices;
+
+ /* not support dp_mst will always return 0, using first dev_entry */
+ if (!codec->dp_mst)
+ return 0;
+
+ /* AC_PAR_DEVLIST_LEN is 0 based. */
+ num_devices = snd_hda_get_num_devices(codec, nid) + 1;
+ /* If Device List Length is 0 (num_device = 1),
+ * the pin is not multi stream capable.
+ * Do nothing in this case.
+ */
+ if (num_devices == 1)
+ return 0;
+
+ /* Behavior of setting index being equal to or greater than
+ * Device List Length is not predictable
+ */
+ if (num_devices <= dev_id)
+ return -EINVAL;
+
+ ret = snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_DEVICE_SEL, dev_id);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_set_dev_select);
+
/*
* read widget caps for each widget and store in cache
*/
@@ -403,6 +467,10 @@ static int read_pin_defaults(struct hda_codec *codec)
pin->nid = nid;
pin->cfg = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0);
+ /*
+ * all device entries are the same widget control so far
+ * fixme: if any codec is different, need fix here
+ */
pin->ctrl = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL,
0);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 373fcad840ea..f17f25245e52 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -347,8 +347,11 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid, int recursive);
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
u8 *dev_list, int max_devices);
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id);
struct hda_verb {
hda_nid_t nid;
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 500878556578..3715a5725613 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -861,6 +861,10 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
return -EIO;
}
+ /* no fallback mechanism? */
+ if (!chip->fallback_to_single_cmd)
+ return -EIO;
+
/* a fatal communication error; need either to reset or to fallback
* to the single_cmd mode
*/
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index a50e0532622a..35a9ab2cac46 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -150,6 +150,7 @@ struct azx {
int bdl_pos_adj;
int poll_count;
unsigned int running:1;
+ unsigned int fallback_to_single_cmd:1;
unsigned int single_cmd:1;
unsigned int polling_mode:1;
unsigned int msi:1;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c64d986009a9..c8256a89375a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -128,7 +128,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS];
static int jackpoll_ms[SNDRV_CARDS];
-static bool single_cmd;
+static int single_cmd = -1;
static int enable_msi = -1;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
@@ -157,7 +157,7 @@ module_param_array(probe_only, int, NULL, 0444);
MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
module_param_array(jackpoll_ms, int, NULL, 0444);
MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
-module_param(single_cmd, bool, 0444);
+module_param(single_cmd, bint, 0444);
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
"(for debugging only).");
module_param(enable_msi, bint, 0444);
@@ -1596,7 +1596,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
check_probe_mask(chip, dev);
- chip->single_cmd = single_cmd;
+ if (single_cmd < 0) /* allow fallback to single_cmd at errors */
+ chip->fallback_to_single_cmd = 1;
+ else /* explicitly set to single_cmd or not */
+ chip->single_cmd = single_cmd;
+
azx_check_snoop_available(chip);
if (bdl_pos_adj[dev] < 0)
@@ -1774,6 +1778,14 @@ static int azx_first_init(struct azx *chip)
chip->playback_index_offset = chip->capture_streams;
chip->num_streams = chip->playback_streams + chip->capture_streams;
+ /* sanity check for the SDxCTL.STRM field overflow */
+ if (chip->num_streams > 15 &&
+ (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) {
+ dev_warn(chip->card->dev, "number of I/O streams is %d, "
+ "forcing separate stream tags", chip->num_streams);
+ chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG;
+ }
+
/* initialize streams */
err = azx_init_streams(chip);
if (err < 0)
@@ -2155,7 +2167,20 @@ static void azx_remove(struct pci_dev *pci)
/* cancel the pending probing work */
chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip);
+ /* FIXME: below is an ugly workaround.
+ * Both device_release_driver() and driver_probe_device()
+ * take *both* the device's and its parent's lock before
+ * calling the remove() and probe() callbacks. The codec
+ * probe takes the locks of both the codec itself and its
+ * parent, i.e. the PCI controller dev. Meanwhile, when
+ * the PCI controller is unbound, it takes its lock, too
+ * ==> ouch, a deadlock!
+ * As a workaround, we unlock temporarily here the controller
+ * device during cancel_work_sync() call.
+ */
+ device_unlock(&pci->dev);
cancel_work_sync(&hda->probe_work);
+ device_lock(&pci->dev);
snd_card_free(card);
}
@@ -2197,9 +2222,9 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lewisburg */
{ PCI_DEVICE(0x8086, 0xa1f0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
{ PCI_DEVICE(0x8086, 0xa270),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -2230,6 +2255,9 @@ static const struct pci_device_id azx_ids[] = {
/* Broxton-T */
{ PCI_DEVICE(0x8086, 0x1a98),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
+ /* Gemini-Lake */
+ { PCI_DEVICE(0x8086, 0x3198),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 11b9b2f17a2e..07a9deb17477 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -1482,6 +1482,9 @@ static int dspio_scp(struct hda_codec *codec,
} else if (ret_size != reply_data_size) {
codec_dbg(codec, "RetLen and HdrLen .NE.\n");
return -EINVAL;
+ } else if (!reply) {
+ codec_dbg(codec, "NULL reply\n");
+ return -EINVAL;
} else {
*reply_len = ret_size*sizeof(unsigned int);
memcpy(reply, scp_reply.data, *reply_len);
@@ -2863,7 +2866,7 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
#define CA0132_CODEC_MUTE(xname, nid, dir) \
CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir)
-/* The followings are for tuning of products */
+/* The following are for tuning of products */
#ifdef ENABLE_TUNING_CONTROLS
static unsigned int voice_focus_vals_lookup[] = {
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index cf9bc042fe96..1461ef8eb749 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -76,6 +76,7 @@ struct hdmi_spec_per_cvt {
struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
+ int dev_id;
/* pin idx, different device entries on the same pin use the same idx */
int pin_nid_idx;
int num_mux_nids;
@@ -130,7 +131,23 @@ struct hdmi_spec {
struct snd_array cvts; /* struct hdmi_spec_per_cvt */
hda_nid_t cvt_nids[4]; /* only for haswell fix */
+ /*
+ * num_pins is the number of virtual pins
+ * for example, there are 3 pins, and each pin
+ * has 4 device entries, then the num_pins is 12
+ */
int num_pins;
+ /*
+ * num_nids is the number of real pins
+ * In the above example, num_nids is 3
+ */
+ int num_nids;
+ /*
+ * dev_num is the number of device entries
+ * on each pin.
+ * In the above example, dev_num is 4
+ */
+ int dev_num;
struct snd_array pins; /* struct hdmi_spec_per_pin */
struct hdmi_pcm pcm_rec[16];
struct mutex pcm_lock;
@@ -217,14 +234,26 @@ union audio_infoframe {
/* obtain hda_pcm object assigned to idx */
#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
-static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
+static int pin_id_to_pin_index(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id)
{
struct hdmi_spec *spec = codec->spec;
int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
+
+ /*
+ * (dev_id == -1) means it is NON-MST pin
+ * return the first virtual pin on this port
+ */
+ if (dev_id == -1)
+ dev_id = 0;
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
- if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = get_pin(spec, pin_idx);
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
return pin_idx;
+ }
codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
return -EINVAL;
@@ -724,10 +753,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
-static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
+static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
+ int dev_id)
{
struct hdmi_spec *spec = codec->spec;
- int pin_idx = pin_nid_to_pin_index(codec, nid);
+ int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
if (pin_idx < 0)
return;
@@ -738,7 +768,8 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
static void jack_callback(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
- check_presence_and_report(codec, jack->nid);
+ /* hda_jack don't support DP MST */
+ check_presence_and_report(codec, jack->nid, 0);
}
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -747,6 +778,12 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
struct hda_jack_tbl *jack;
int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
+ /*
+ * assume DP MST uses dyn_pcm_assign and acomp and
+ * never comes here
+ * if DP MST supports unsol event, below code need
+ * consider dev_entry
+ */
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!jack)
return;
@@ -757,7 +794,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
- check_presence_and_report(codec, jack->nid);
+ /* hda_jack don't support DP MST */
+ check_presence_and_report(codec, jack->nid, 0);
}
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -970,28 +1008,60 @@ static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
* by any other pins.
*/
static void intel_not_share_assigned_cvt(struct hda_codec *codec,
- hda_nid_t pin_nid, int mux_idx)
+ hda_nid_t pin_nid,
+ int dev_id, int mux_idx)
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t nid;
int cvt_idx, curr;
struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx;
+
+ /* configure the pins connections */
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ int dev_id_saved;
+ int dev_num;
- /* configure all pins, including "no physical connection" ones */
- for_each_hda_codec_node(nid, codec) {
- unsigned int wid_caps = get_wcaps(codec, nid);
- unsigned int wid_type = get_wcaps_type(wid_caps);
+ per_pin = get_pin(spec, pin_idx);
+ /*
+ * pin not connected to monitor
+ * no need to operate on it
+ */
+ if (!per_pin->pcm)
+ continue;
- if (wid_type != AC_WID_PIN)
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
continue;
- if (nid == pin_nid)
+ /*
+ * if per_pin->dev_id >= dev_num,
+ * snd_hda_get_dev_select() will fail,
+ * and the following operation is unpredictable.
+ * So skip this situation.
+ */
+ dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
+ if (per_pin->dev_id >= dev_num)
continue;
+ nid = per_pin->pin_nid;
+
+ /*
+ * Calling this function should not impact
+ * on the device entry selection
+ * So let's save the dev id for each pin,
+ * and restore it when return
+ */
+ dev_id_saved = snd_hda_get_dev_select(codec, nid);
+ snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
curr = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_SEL, 0);
- if (curr != mux_idx)
+ if (curr != mux_idx) {
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
continue;
+ }
+
/* choose an unassigned converter. The conveters in the
* connection list are in the same order as in the codec.
@@ -1008,12 +1078,13 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
break;
}
}
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
}
}
/* A wrapper of intel_not_share_asigned_cvt() */
static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
- hda_nid_t pin_nid, hda_nid_t cvt_nid)
+ hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
{
int mux_idx;
struct hdmi_spec *spec = codec->spec;
@@ -1025,7 +1096,7 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
*/
mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
if (mux_idx >= 0)
- intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
+ intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
}
/* skeleton caller of pin_cvt_fixup ops */
@@ -1140,6 +1211,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_pin->cvt_nid = per_cvt->cvt_nid;
hinfo->nid = per_cvt->cvt_nid;
+ snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
per_pin->mux_idx);
@@ -1198,6 +1270,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
return -EINVAL;
}
+ /* all the device entries on the same pin have the same conn list */
per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
per_pin->mux_nids,
HDA_MAX_CONNECTIONS);
@@ -1215,13 +1288,13 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
return per_pin->pin_nid_idx;
/* have a second try; check the "reserved area" over num_pins */
- for (i = spec->num_pins; i < spec->pcm_used; i++) {
+ for (i = spec->num_nids; i < spec->pcm_used; i++) {
if (!test_bit(i, &spec->pcm_bitmap))
return i;
}
/* the last try; check the empty slots in pins */
- for (i = 0; i < spec->num_pins; i++) {
+ for (i = 0; i < spec->num_nids; i++) {
if (!test_bit(i, &spec->pcm_bitmap))
return i;
}
@@ -1296,10 +1369,13 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
per_pin->cvt_nid = hinfo->nid;
mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
- if (mux_idx < per_pin->num_mux_nids)
+ if (mux_idx < per_pin->num_mux_nids) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
mux_idx);
+ }
snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
@@ -1467,6 +1543,11 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
jack = spec->pcm_rec[per_pin->pcm_idx].jack;
else if (!spec->dyn_pcm_assign) {
+ /*
+ * jack tbl doesn't support DP MST
+ * DP MST will use dyn_pcm_assign,
+ * so DP MST will never come here
+ */
jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
if (jack_tbl)
jack = jack_tbl->jack;
@@ -1485,9 +1566,9 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
mutex_lock(&per_pin->lock);
eld->monitor_present = false;
- size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
- &eld->monitor_present, eld->eld_buffer,
- ELD_MAX_SIZE);
+ size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+ per_pin->dev_id, &eld->monitor_present,
+ eld->eld_buffer, ELD_MAX_SIZE);
if (size > 0) {
size = min(size, ELD_MAX_SIZE);
if (snd_hdmi_parse_eld(codec, &eld->info,
@@ -1565,38 +1646,81 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
int pin_idx;
struct hdmi_spec_per_pin *per_pin;
int err;
+ int dev_num, i;
caps = snd_hda_query_pin_caps(codec, pin_nid);
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
return 0;
+ /*
+ * For DP MST audio, Configuration Default is the same for
+ * all device entries on the same pin
+ */
config = snd_hda_codec_get_pincfg(codec, pin_nid);
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
return 0;
- if (is_haswell_plus(codec))
- intel_haswell_fixup_connect_list(codec, pin_nid);
-
- pin_idx = spec->num_pins;
- per_pin = snd_array_new(&spec->pins);
- if (!per_pin)
- return -ENOMEM;
-
- per_pin->pin_nid = pin_nid;
- per_pin->non_pcm = false;
- if (spec->dyn_pcm_assign)
- per_pin->pcm_idx = -1;
- else {
- per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
- per_pin->pcm_idx = pin_idx;
+ /*
+ * To simplify the implementation, malloc all
+ * the virtual pins in the initialization statically
+ */
+ if (is_haswell_plus(codec)) {
+ /*
+ * On Intel platforms, device entries number is
+ * changed dynamically. If there is a DP MST
+ * hub connected, the device entries number is 3.
+ * Otherwise, it is 1.
+ * Here we manually set dev_num to 3, so that
+ * we can initialize all the device entries when
+ * bootup statically.
+ */
+ dev_num = 3;
+ spec->dev_num = 3;
+ } else if (spec->dyn_pcm_assign && codec->dp_mst) {
+ dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
+ /*
+ * spec->dev_num is the maxinum number of device entries
+ * among all the pins
+ */
+ spec->dev_num = (spec->dev_num > dev_num) ?
+ spec->dev_num : dev_num;
+ } else {
+ /*
+ * If the platform doesn't support DP MST,
+ * manually set dev_num to 1. This means
+ * the pin has only one device entry.
+ */
+ dev_num = 1;
+ spec->dev_num = 1;
}
- per_pin->pin_nid_idx = pin_idx;
- err = hdmi_read_pin_conn(codec, pin_idx);
- if (err < 0)
- return err;
+ for (i = 0; i < dev_num; i++) {
+ pin_idx = spec->num_pins;
+ per_pin = snd_array_new(&spec->pins);
- spec->num_pins++;
+ if (!per_pin)
+ return -ENOMEM;
+
+ if (spec->dyn_pcm_assign) {
+ per_pin->pcm = NULL;
+ per_pin->pcm_idx = -1;
+ } else {
+ per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
+ per_pin->pcm_idx = pin_idx;
+ }
+ per_pin->pin_nid = pin_nid;
+ per_pin->pin_nid_idx = spec->num_nids;
+ per_pin->dev_id = i;
+ per_pin->non_pcm = false;
+ snd_hda_set_dev_select(codec, pin_nid, i);
+ if (is_haswell_plus(codec))
+ intel_haswell_fixup_connect_list(codec, pin_nid);
+ err = hdmi_read_pin_conn(codec, pin_idx);
+ if (err < 0)
+ return err;
+ spec->num_pins++;
+ }
+ spec->num_nids++;
return 0;
}
@@ -1744,7 +1868,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
/* Todo: add DP1.2 MST audio support later */
if (codec_has_acomp(codec))
- snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
+ snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id,
runtime->rate);
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
@@ -1762,6 +1886,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
pinctl | PIN_OUT);
}
+ /* snd_hda_set_dev_select() has been called before */
err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
stream_tag, format);
mutex_unlock(&spec->pcm_lock);
@@ -1897,17 +2022,23 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
static int generic_hdmi_build_pcms(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- int pin_idx;
+ int idx;
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ /*
+ * for non-mst mode, pcm number is the same as before
+ * for DP MST mode, pcm number is (nid number + dev_num - 1)
+ * dev_num is the device entry number in a pin
+ *
+ */
+ for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) {
struct hda_pcm *info;
struct hda_pcm_stream *pstr;
- info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
+ info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
if (!info)
return -ENOMEM;
- spec->pcm_rec[pin_idx].pcm = info;
+ spec->pcm_rec[idx].pcm = info;
spec->pcm_used++;
info->pcm_type = HDA_PCM_TYPE_HDMI;
info->own_chmap = true;
@@ -1915,6 +2046,9 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
pstr->substreams = 1;
pstr->ops = generic_ops;
+ /* pcm number is less than 16 */
+ if (spec->pcm_used >= 16)
+ break;
/* other pstr fields are set in open */
}
@@ -2070,7 +2204,9 @@ static int generic_hdmi_init(struct hda_codec *codec)
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
hdmi_init_pin(codec, pin_nid);
if (!codec_has_acomp(codec))
snd_hda_jack_detect_enable_callback(codec, pin_nid,
@@ -2178,6 +2314,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec)
return -ENOMEM;
spec->ops = generic_standard_hdmi_ops;
+ spec->dev_num = 1; /* initialize to 1 */
mutex_init(&spec->pcm_lock);
snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
@@ -2295,6 +2432,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
{
struct hda_codec *codec = audio_ptr;
int pin_nid;
+ int dev_id = pipe;
/* we assume only from port-B to port-D */
if (port < 1 || port > 3)
@@ -2321,7 +2459,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
return;
snd_hdac_i915_set_bclk(&codec->bus->core);
- check_presence_and_report(codec, pin_nid);
+ check_presence_and_report(codec, pin_nid, dev_id);
}
/* register i915 component pin_eld_notify callback */
@@ -2354,11 +2492,13 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
hda_nid_t cvt_nid)
{
if (per_pin) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
intel_verify_pin_cvt_connect(codec, per_pin);
intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
- per_pin->mux_idx);
+ per_pin->dev_id, per_pin->mux_idx);
} else {
- intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
+ intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
}
}
@@ -2378,6 +2518,8 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
if (err < 0)
return err;
spec = codec->spec;
+ codec->dp_mst = true;
+ spec->dyn_pcm_assign = true;
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
@@ -2389,7 +2531,6 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
codec->core.link_power_control = 1;
codec->patch_ops.set_power_state = haswell_set_power_state;
- codec->dp_mst = true;
codec->depop_delay = 0;
codec->auto_runtime_pm = 1;
@@ -3639,6 +3780,7 @@ HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
@@ -3658,6 +3800,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7d660ee1d5e8..4e112221d825 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0288:
case 0x10ec0295:
case 0x10ec0298:
+ case 0x10ec0299:
alc_update_coef_idx(codec, 0x10, 1<<9, 0);
break;
case 0x10ec0285:
@@ -379,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
break;
case 0x10ec0899:
case 0x10ec0900:
+ case 0x10ec1220:
alc_update_coef_idx(codec, 0x7, 1<<1, 0);
break;
}
@@ -912,6 +914,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
{ 0x10ec0256, 0x1028, 0, "ALC3246" },
{ 0x10ec0225, 0x1028, 0, "ALC3253" },
{ 0x10ec0295, 0x1028, 0, "ALC3254" },
+ { 0x10ec0299, 0x1028, 0, "ALC3271" },
{ 0x10ec0670, 0x1025, 0, "ALC669X" },
{ 0x10ec0676, 0x1025, 0, "ALC679X" },
{ 0x10ec0282, 0x1043, 0, "ALC3229" },
@@ -2309,6 +2312,7 @@ static int patch_alc882(struct hda_codec *codec)
case 0x10ec0882:
case 0x10ec0885:
case 0x10ec0900:
+ case 0x10ec1220:
break;
default:
/* ALC883 and variants */
@@ -3717,6 +3721,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0867:
@@ -3812,6 +3817,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
case 0x10ec0867:
alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
/* fallthru */
+ case 0x10ec0221:
case 0x10ec0662:
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -3824,6 +3830,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
alc_process_coef_fw(codec, coef0225);
@@ -3882,6 +3889,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
switch (codec->core.vendor_id) {
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0255:
@@ -3997,6 +4005,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0867:
@@ -4090,6 +4099,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
}
@@ -4174,6 +4184,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
msleep(800);
val = alc_read_coef_idx(codec, 0x46);
@@ -4401,7 +4412,7 @@ static void alc_no_shutup(struct hda_codec *codec)
static void alc_fixup_no_shutup(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ if (action == HDA_FIXUP_ACT_PROBE) {
struct alc_spec *spec = codec->spec;
spec->shutup = alc_no_shutup;
}
@@ -4857,6 +4868,8 @@ enum {
ALC292_FIXUP_TPT460,
ALC298_FIXUP_SPK_VOLUME,
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
+ ALC269_FIXUP_ATIV_BOOK_8,
+ ALC221_FIXUP_HP_MIC_NO_PRESENCE,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5529,6 +5542,22 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
},
+ [ALC269_FIXUP_ATIV_BOOK_8] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_auto_mute_via_amp,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_NO_SHUTUP
+ },
+ [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MODE
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5577,6 +5606,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
+ SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5639,6 +5669,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
+ SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5665,6 +5697,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
@@ -5692,6 +5725,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
@@ -6065,6 +6099,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170150}),
+ SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
+ {0x12, 0xb7a60140},
+ {0x13, 0xb7a60150},
+ {0x17, 0x90170110},
+ {0x1a, 0x03011020},
+ {0x21, 0x03211030}),
{}
};
@@ -6212,6 +6252,7 @@ static int patch_alc269(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
spec->codec_variant = ALC269_TYPE_ALC225;
break;
case 0x10ec0234:
@@ -7250,6 +7291,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
+ HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
@@ -7281,6 +7323,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+ HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 37b70f8e878f..faa3d38bac0b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -166,6 +166,7 @@ enum {
STAC_D965_VERBS,
STAC_DELL_3ST,
STAC_DELL_BIOS,
+ STAC_NEMO_DEFAULT,
STAC_DELL_BIOS_AMIC,
STAC_DELL_BIOS_SPDIF,
STAC_927X_DELL_DMIC,
@@ -1360,6 +1361,27 @@ static const struct hda_pintbl oqo9200_pin_configs[] = {
{}
};
+/*
+ * STAC 92HD700
+ * 18881000 Amigaone X1000
+ */
+static const struct hda_pintbl nemo_pin_configs[] = {
+ { 0x0a, 0x02214020 }, /* Front panel HP socket */
+ { 0x0b, 0x02a19080 }, /* Front Mic */
+ { 0x0c, 0x0181304e }, /* Line in */
+ { 0x0d, 0x01014010 }, /* Line out */
+ { 0x0e, 0x01a19040 }, /* Rear Mic */
+ { 0x0f, 0x01011012 }, /* Rear speakers */
+ { 0x10, 0x01016011 }, /* Center speaker */
+ { 0x11, 0x01012014 }, /* Side speakers (7.1) */
+ { 0x12, 0x103301f0 }, /* Motherboard CD line in connector */
+ { 0x13, 0x411111f0 }, /* Unused */
+ { 0x14, 0x411111f0 }, /* Unused */
+ { 0x21, 0x01442170 }, /* S/PDIF line out */
+ { 0x22, 0x411111f0 }, /* Unused */
+ { 0x23, 0x411111f0 }, /* Unused */
+ {}
+};
static void stac9200_fixup_panasonic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -3883,6 +3905,10 @@ static const struct hda_fixup stac927x_fixups[] = {
.type = HDA_FIXUP_PINS,
.v.pins = d965_5st_no_fp_pin_configs,
},
+ [STAC_NEMO_DEFAULT] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = nemo_pin_configs,
+ },
[STAC_DELL_3ST] = {
.type = HDA_FIXUP_PINS,
.v.pins = dell_3st_pin_configs,
@@ -3939,6 +3965,7 @@ static const struct hda_model_fixup stac927x_models[] = {
{ .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
{ .id = STAC_DELL_3ST, .name = "dell-3stack" },
{ .id = STAC_DELL_BIOS, .name = "dell-bios" },
+ { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" },
{ .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
{ .id = STAC_927X_VOLKNOB, .name = "volknob" },
{}
@@ -3977,6 +4004,8 @@ static const struct snd_pci_quirk stac927x_fixup_tbl[] = {
"Intel D965", STAC_D965_5ST),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
"Intel D965", STAC_D965_5ST),
+ /* Nemo */
+ SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT),
/* volume-knob fixes */
SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
{} /* terminator */
@@ -5036,6 +5065,7 @@ static const struct hda_device_id snd_hda_id_sigmatel[] = {
HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
+ HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index e5c52ed9b674..842744e7a139 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -367,7 +367,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
} while (time_after(timeout, jiffies));
}
-static struct snd_rawmidi_ops vt1724_midi_output_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_output_ops = {
.open = vt1724_midi_output_open,
.close = vt1724_midi_output_close,
.trigger = vt1724_midi_output_trigger,
@@ -402,7 +402,7 @@ static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
spin_unlock_irqrestore(&ice->reg_lock, flags);
}
-static struct snd_rawmidi_ops vt1724_midi_input_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_input_ops = {
.open = vt1724_midi_input_open,
.close = vt1724_midi_input_close,
.trigger = vt1724_midi_input_trigger,
diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c
index f7ac8d5e862c..27c03e40c9b1 100644
--- a/sound/pci/ice1712/wm8766.c
+++ b/sound/pci/ice1712/wm8766.c
@@ -254,7 +254,7 @@ static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol,
int n = kcontrol->private_value;
u16 val, regval1, regval2;
- /* this also works for enum because value is an union */
+ /* this also works for enum because value is a union */
regval1 = ucontrol->value.integer.value[0];
regval2 = ucontrol->value.integer.value[1];
if (wm->ctl[n].flags & WM8766_FLAG_INVERT) {
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index ebd2fe4b4a57..553669b103c2 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -528,7 +528,7 @@ static int snd_wm8776_ctl_put(struct snd_kcontrol *kcontrol,
int n = kcontrol->private_value;
u16 val, regval1, regval2;
- /* this also works for enum because value is an union */
+ /* this also works for enum because value is a union */
regval1 = ucontrol->value.integer.value[0];
regval2 = ucontrol->value.integer.value[1];
if (wm->ctl[n].flags & WM8776_FLAG_INVERT) {
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 565f7f55c3ca..1e25095fd144 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2051,7 +2051,7 @@ static void snd_korg1212_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, korg1212->card->longname);
snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1);
snd_iprintf(buffer, "\nGeneral settings\n");
- snd_iprintf(buffer, " period size: %Zd bytes\n", K1212_PERIOD_BYTES);
+ snd_iprintf(buffer, " period size: %zd bytes\n", K1212_PERIOD_BYTES);
snd_iprintf(buffer, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] );
snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens );
snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens );
@@ -2276,7 +2276,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
sizeof(struct KorgSharedBuffer), &korg1212->dma_shared) < 0) {
- snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%Zd bytes)\n", sizeof(struct KorgSharedBuffer));
+ snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%zd bytes)\n", sizeof(struct KorgSharedBuffer));
snd_korg1212_free(korg1212);
return -ENOMEM;
}
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
index 0cc17e0ea34a..426743871540 100644
--- a/sound/pci/mixart/mixart.h
+++ b/sound/pci/mixart/mixart.h
@@ -86,7 +86,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 takslet */
+ atomic_t msg_processed; /* number of messages to be processed in tasklet */
struct mutex lock; /* interrupt lock */
struct mutex msg_lock; /* mailbox lock */
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 80633055e17e..a99808ab01fe 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -292,7 +292,7 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
int err, card_index;
dev_dbg(&mgr->pci->dev,
- "loading dsp [%d] size = %Zd\n", index, dsp->size);
+ "loading dsp [%d] size = %zd\n", index, dsp->size);
switch (index) {
case PCXHR_FIRMWARE_XLX_INT_INDEX:
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index b94fc6357139..fc0face6cdc6 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1510,14 +1510,14 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
return 0;
}
-static struct snd_rawmidi_ops snd_hdsp_midi_output =
+static const struct snd_rawmidi_ops snd_hdsp_midi_output =
{
.open = snd_hdsp_midi_output_open,
.close = snd_hdsp_midi_output_close,
.trigger = snd_hdsp_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_hdsp_midi_input =
+static const struct snd_rawmidi_ops snd_hdsp_midi_input =
{
.open = snd_hdsp_midi_input_open,
.close = snd_hdsp_midi_input_close,
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 14bbf55c1ef9..c48acdb0e186 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -2043,14 +2043,14 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
return 0;
}
-static struct snd_rawmidi_ops snd_hdspm_midi_output =
+static const struct snd_rawmidi_ops snd_hdspm_midi_output =
{
.open = snd_hdspm_midi_output_open,
.close = snd_hdspm_midi_output_close,
.trigger = snd_hdspm_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_hdspm_midi_input =
+static const struct snd_rawmidi_ops snd_hdspm_midi_input =
{
.open = snd_hdspm_midi_input_open,
.close = snd_hdspm_midi_input_close,
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index af83b3b38052..8e457ea27f89 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -269,12 +269,12 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
/* Transfer using pseudo-dma.
*/
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0) {
+ for (; length > 0; length--) {
outl(cpu_to_le32(*addr), port);
addr++;
}
@@ -284,7 +284,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0) {
+ for (; count > 0; count--) {
outl(cpu_to_le32(*addr), port);
addr++;
}
@@ -307,12 +307,12 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
vx2_setup_pseudo_dma(chip, 0);
/* Transfer using pseudo-dma.
*/
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0)
+ for (; length > 0; length--)
*addr++ = le32_to_cpu(inl(port));
addr = (u32 *)runtime->dma_area;
pipe->hw_ptr = 0;
@@ -320,7 +320,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0)
+ for (; count > 0; count--)
*addr++ = le32_to_cpu(inl(port));
vx2_release_pseudo_dma(chip);
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 281972913c32..5f97791f00d7 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -201,7 +201,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
c |= (int)vx_inb(chip, RXM) << 8;
c |= vx_inb(chip, RXL);
- snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size);
+ snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);
vx_outb(chip, ICR, ICR_HF0);
@@ -369,12 +369,12 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
vx_setup_pseudo_dma(chip, 1);
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0) {
+ for (; length > 0; length--) {
outw(cpu_to_le16(*addr), port);
addr++;
}
@@ -384,7 +384,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0) {
+ for (; count > 0; count--) {
outw(cpu_to_le16(*addr), port);
addr++;
}
@@ -411,12 +411,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
if (snd_BUG_ON(count % 2))
return;
vx_setup_pseudo_dma(chip, 0);
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0)
+ for (; length > 0; length--)
*addr++ = le16_to_cpu(inw(port));
addr = (unsigned short *)runtime->dma_area;
pipe->hw_ptr = 0;
@@ -424,7 +424,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 1)
+ for (; count > 1; count--)
*addr++ = le16_to_cpu(inw(port));
/* Disable DMA */
pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index b84d7d34f188..cdd44abfc9e0 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -883,7 +883,7 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
{
/*
- * avsetting driver seems to never change the followings
+ * avsetting driver seems to never change the following
* so, init them here once
*/
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 818b052377f3..ec1067a679da 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -506,7 +506,7 @@ static int acp_init(void __iomem *acp_mmio)
return 0;
}
-/* Deintialize ACP */
+/* Deinitialize ACP */
static int acp_deinit(void __iomem *acp_mmio)
{
u32 val;
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 89ac5f5a93eb..7ae46c2647d4 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -349,7 +349,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
}
#define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
-#define CLASSD_ACLK_RATE_12M288_MPY_8 (12228 * 1000 * 8)
+#define CLASSD_ACLK_RATE_12M288_MPY_8 (12288 * 1000 * 8)
static struct {
int rate;
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 78fca8acd3ec..fd272a40485b 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1534,21 +1534,20 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
pin->mst_capable = false;
/* if not MST, default is port[0] */
hport = &pin->ports[0];
- goto out;
} else {
for (i = 0; i < pin->num_ports; i++) {
pin->mst_capable = true;
if (pin->ports[i].id == pipe) {
hport = &pin->ports[i];
- goto out;
+ break;
}
}
}
+
+ if (hport)
+ hdac_hdmi_present_sense(pin, hport);
}
-out:
- if (pin && hport)
- hdac_hdmi_present_sense(pin, hport);
}
static struct i915_audio_component_audio_ops aops = {
@@ -1998,7 +1997,7 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
struct hdac_hdmi_pcm *pcm, *pcm_next;
- struct hdac_hdmi_port *port;
+ struct hdac_hdmi_port *port, *port_next;
int i;
snd_soc_unregister_codec(&edev->hdac.dev);
@@ -2008,8 +2007,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
if (list_empty(&pcm->port_list))
continue;
- list_for_each_entry(port, &pcm->port_list, head)
- port = NULL;
+ list_for_each_entry_safe(port, port_next,
+ &pcm->port_list, head)
+ list_del(&port->head);
list_del(&pcm->head);
kfree(pcm);
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index d151224ffcca..bbdb72f73df1 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -899,7 +899,10 @@ static int wm_coeff_put(struct snd_kcontrol *kctl,
mutex_lock(&ctl->dsp->pwr_lock);
- memcpy(ctl->cache, p, ctl->len);
+ if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ ret = -EPERM;
+ else
+ memcpy(ctl->cache, p, ctl->len);
ctl->set = 1;
if (ctl->enabled && ctl->dsp->running)
@@ -926,6 +929,8 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl,
ctl->set = 1;
if (ctl->enabled && ctl->dsp->running)
ret = wm_coeff_write_control(ctl, ctl->cache, size);
+ else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE)
+ ret = -EPERM;
}
mutex_unlock(&ctl->dsp->pwr_lock);
@@ -947,7 +952,7 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
mutex_lock(&ctl->dsp->pwr_lock);
- if (ctl->enabled)
+ if (ctl->enabled && ctl->dsp->running)
ret = wm_coeff_write_acked_control(ctl, val);
else
ret = -EPERM;
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 624b3b9cb079..63b2745f8169 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -1269,7 +1269,7 @@ void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_ON:
- /* Turn off any unneded single ended outputs */
+ /* Turn off any unneeded single ended outputs */
val = 0;
mask = 0;
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 1d82f68305c3..8cfffa70c144 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -368,7 +368,7 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair)
fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD,
ASRC_INPUTFIFO_THRESHOLD);
- /* Configure the followings only for Ideal Ratio mode */
+ /* Configure the following only for Ideal Ratio mode */
if (!ideal)
return 0;
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index ed58b5b3555a..2dbfb1b24ef4 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -512,7 +512,7 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
if (bc->set_params != SKL_PARAM_INIT)
continue;
- mconfig->formats_config.caps = (u32 *)&bc->params;
+ mconfig->formats_config.caps = (u32 *)bc->params;
mconfig->formats_config.caps_size = bc->size;
break;
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 924971b6ded5..9b031352ea3c 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -82,7 +82,7 @@ struct lpass_variant {
**/
u32 dmactl_audif_start;
u32 wrdma_channel_start;
- /* SOC specific intialization like clocks */
+ /* SOC specific initialization like clocks */
int (*init)(struct platform_device *pdev);
int (*exit)(struct platform_device *pdev);
int (*alloc_dma_channel)(struct lpass_data *data, int direction);
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index abb5eaac854a..7d92a24b7cfa 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -31,23 +31,24 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
struct device *dev = rsnd_priv_to_dev(priv);
u32 data;
+ u32 path[] = {
+ [1] = 1 << 0,
+ [5] = 1 << 8,
+ [6] = 1 << 12,
+ [9] = 1 << 15,
+ };
if (!mix && !dvc)
return 0;
+ if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
+ return -ENXIO;
+
if (mix) {
struct rsnd_dai *rdai;
struct rsnd_mod *src;
struct rsnd_dai_stream *tio;
int i;
- u32 path[] = {
- [0] = 0,
- [1] = 1 << 0,
- [2] = 0,
- [3] = 0,
- [4] = 0,
- [5] = 1 << 8
- };
/*
* it is assuming that integrater is well understanding about
@@ -70,16 +71,19 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
} else {
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
- u32 path[] = {
- [0] = 0x30000,
- [1] = 0x30001,
- [2] = 0x40000,
- [3] = 0x10000,
- [4] = 0x20000,
- [5] = 0x40100
+ u8 cmd_case[] = {
+ [0] = 0x3,
+ [1] = 0x3,
+ [2] = 0x4,
+ [3] = 0x1,
+ [4] = 0x2,
+ [5] = 0x4,
+ [6] = 0x1,
+ [9] = 0x2,
};
- data = path[rsnd_mod_id(src)];
+ data = path[rsnd_mod_id(src)] |
+ cmd_case[rsnd_mod_id(src)] << 16;
}
dev_dbg(dev, "ctu/mix path = 0x%08x", data);
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 1f405c833867..241cb3b08a07 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -454,6 +454,20 @@ static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg)
return ioread32(rsnd_dmapp_addr(dmac, dma, reg));
}
+static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg)
+{
+ struct rsnd_mod *mod = rsnd_mod_get(dma);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+ void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg);
+ u32 val = ioread32(addr);
+
+ val &= ~mask;
+ val |= (data & mask);
+
+ iowrite32(val, addr);
+}
+
static int rsnd_dmapp_stop(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -461,10 +475,10 @@ static int rsnd_dmapp_stop(struct rsnd_mod *mod,
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
int i;
- rsnd_dmapp_write(dma, 0, PDMACHCR);
+ rsnd_dmapp_bset(dma, 0, PDMACHCR_DE, PDMACHCR);
for (i = 0; i < 1024; i++) {
- if (0 == rsnd_dmapp_read(dma, PDMACHCR))
+ if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE))
return 0;
udelay(1);
}
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 4e817c8a18c0..14fafdaf1395 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -64,7 +64,11 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod,
mask1 = (1 << 4) | (1 << 20); /* mask sync bit */
mask2 = (1 << 4); /* mask sync bit */
val1 = val2 = 0;
- if (rsnd_ssi_is_pin_sharing(io)) {
+ if (id == 8) {
+ /*
+ * SSI8 pin is sharing with SSI7, nothing to do.
+ */
+ } else if (rsnd_ssi_is_pin_sharing(io)) {
int shift = -1;
switch (id) {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a110d3987d4a..2722bb0c5573 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3041,7 +3041,7 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
unsigned int i;
int ret;
- dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
+ dev_dbg(dev, "ASoC: dai register %s #%zu\n", dev_name(dev), count);
component->dai_drv = dai_drv;
@@ -3326,7 +3326,10 @@ static int snd_soc_platform_drv_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_platform *platform = rtd->platform;
- return platform->driver->pcm_new(rtd);
+ if (platform->driver->pcm_new)
+ return platform->driver->pcm_new(rtd);
+ else
+ return 0;
}
static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm)
@@ -3334,7 +3337,8 @@ static void snd_soc_platform_drv_pcm_free(struct snd_pcm *pcm)
struct snd_soc_pcm_runtime *rtd = pcm->private_data;
struct snd_soc_platform *platform = rtd->platform;
- platform->driver->pcm_free(pcm);
+ if (platform->driver->pcm_free)
+ platform->driver->pcm_free(pcm);
}
/**
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index aff3d8129ac9..3e9b1c0bb1ce 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -344,7 +344,7 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
return 0;
}
-/* pass DAI configurations to component driver for extra intialization */
+/* pass DAI configurations to component driver for extra initialization */
static int soc_tplg_dai_load(struct soc_tplg *tplg,
struct snd_soc_dai_driver *dai_drv)
{
@@ -354,7 +354,7 @@ static int soc_tplg_dai_load(struct soc_tplg *tplg,
return 0;
}
-/* pass link configurations to component driver for extra intialization */
+/* pass link configurations to component driver for extra initialization */
static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
struct snd_soc_dai_link *link)
{
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index a0209204ae48..55579f6b8cb2 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -33,13 +33,13 @@ static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *inf
* MIDI emulation operators
*/
static struct snd_midi_op emux_ops = {
- snd_emux_note_on,
- snd_emux_note_off,
- snd_emux_key_press,
- snd_emux_terminate_note,
- snd_emux_control,
- snd_emux_nrpn,
- snd_emux_sysex,
+ .note_on = snd_emux_note_on,
+ .note_off = snd_emux_note_off,
+ .key_press = snd_emux_key_press,
+ .note_terminate = snd_emux_terminate_note,
+ .control = snd_emux_control,
+ .nrpn = snd_emux_nrpn,
+ .sysex = snd_emux_sysex,
};
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
index 3d410969553e..aa5adbb6eb5d 100644
--- a/sound/usb/6fire/midi.c
+++ b/sound/usb/6fire/midi.c
@@ -139,14 +139,14 @@ static void usb6fire_midi_in_trigger(
spin_unlock_irqrestore(&rt->in_lock, flags);
}
-static struct snd_rawmidi_ops out_ops = {
+static const struct snd_rawmidi_ops out_ops = {
.open = usb6fire_midi_out_open,
.close = usb6fire_midi_out_close,
.trigger = usb6fire_midi_out_trigger,
.drain = usb6fire_midi_out_drain
};
-static struct snd_rawmidi_ops in_ops = {
+static const struct snd_rawmidi_ops in_ops = {
.open = usb6fire_midi_in_open,
.close = usb6fire_midi_in_close,
.trigger = usb6fire_midi_in_trigger
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2d2d122b069f..42cb33b94f6a 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -10,6 +10,7 @@ snd-usb-audio-objs := card.o \
mixer.o \
mixer_quirks.o \
mixer_scarlett.o \
+ mixer_us16x08.o \
pcm.o \
proc.o \
quirks.o \
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
index d060dddcc52d..2ff9d578753a 100644
--- a/sound/usb/bcd2000/bcd2000.c
+++ b/sound/usb/bcd2000/bcd2000.c
@@ -252,13 +252,13 @@ static void bcd2000_input_complete(struct urb *urb)
__func__, ret);
}
-static struct snd_rawmidi_ops bcd2000_midi_output = {
+static const struct snd_rawmidi_ops bcd2000_midi_output = {
.open = bcd2000_midi_output_open,
.close = bcd2000_midi_output_close,
.trigger = bcd2000_midi_output_trigger,
};
-static struct snd_rawmidi_ops bcd2000_midi_input = {
+static const struct snd_rawmidi_ops bcd2000_midi_input = {
.open = bcd2000_midi_input_open,
.close = bcd2000_midi_input_close,
.trigger = bcd2000_midi_input_trigger,
diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c
index 2d7588461b33..f8e5b1b57c4f 100644
--- a/sound/usb/caiaq/midi.c
+++ b/sound/usb/caiaq/midi.c
@@ -102,14 +102,14 @@ static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *subs
}
-static struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
+static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
{
.open = snd_usb_caiaq_midi_output_open,
.close = snd_usb_caiaq_midi_output_close,
.trigger = snd_usb_caiaq_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
+static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
{
.open = snd_usb_caiaq_midi_input_open,
.close = snd_usb_caiaq_midi_input_close,
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 90009c0b3a92..0ff5a7d2e19f 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -492,42 +492,46 @@ static void line6_destruct(struct snd_card *card)
usb_put_dev(usbdev);
}
-/* get data from endpoint descriptor (see usb_maxpacket): */
-static void line6_get_interval(struct usb_line6 *line6)
+static void line6_get_usb_properties(struct usb_line6 *line6)
{
struct usb_device *usbdev = line6->usbdev;
const struct line6_properties *properties = line6->properties;
int pipe;
- struct usb_host_endpoint *ep;
+ struct usb_host_endpoint *ep = NULL;
- if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
- pipe =
- usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r);
- } else {
- pipe =
- usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r);
+ if (properties->capabilities & LINE6_CAP_CONTROL) {
+ if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+ pipe = usb_rcvintpipe(line6->usbdev,
+ line6->properties->ep_ctrl_r);
+ } else {
+ pipe = usb_rcvbulkpipe(line6->usbdev,
+ line6->properties->ep_ctrl_r);
+ }
+ ep = usbdev->ep_in[usb_pipeendpoint(pipe)];
}
- ep = usbdev->ep_in[usb_pipeendpoint(pipe)];
+ /* Control data transfer properties */
if (ep) {
line6->interval = ep->desc.bInterval;
- if (usbdev->speed == USB_SPEED_LOW) {
- line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
- line6->iso_buffers = USB_LOW_ISO_BUFFERS;
- } else {
- line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
- line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
- }
-
line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
} else {
- dev_err(line6->ifcdev,
- "endpoint not available, using fallback values");
+ if (properties->capabilities & LINE6_CAP_CONTROL) {
+ dev_err(line6->ifcdev,
+ "endpoint not available, using fallback values");
+ }
line6->interval = LINE6_FALLBACK_INTERVAL;
line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
}
-}
+ /* Isochronous transfer properties */
+ if (usbdev->speed == USB_SPEED_LOW) {
+ line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
+ line6->iso_buffers = USB_LOW_ISO_BUFFERS;
+ } else {
+ line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
+ line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
+ }
+}
/* Enable buffering of incoming messages, flush the buffer */
static int line6_hwdep_open(struct snd_hwdep *hw, struct file *file)
@@ -754,8 +758,9 @@ int line6_probe(struct usb_interface *interface,
goto error;
}
+ line6_get_usb_properties(line6);
+
if (properties->capabilities & LINE6_CAP_CONTROL) {
- line6_get_interval(line6);
ret = line6_init_cap_control(line6);
if (ret < 0)
goto error;
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
index d0fb2f205bd9..1d3a23b02d68 100644
--- a/sound/usb/line6/midi.c
+++ b/sound/usb/line6/midi.c
@@ -200,14 +200,14 @@ static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
line6->line6midi->substream_receive = NULL;
}
-static struct snd_rawmidi_ops line6_midi_output_ops = {
+static const struct snd_rawmidi_ops line6_midi_output_ops = {
.open = line6_midi_output_open,
.close = line6_midi_output_close,
.trigger = line6_midi_output_trigger,
.drain = line6_midi_output_drain,
};
-static struct snd_rawmidi_ops line6_midi_input_ops = {
+static const struct snd_rawmidi_ops line6_midi_input_ops = {
.open = line6_midi_input_open,
.close = line6_midi_input_close,
.trigger = line6_midi_input_trigger,
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 7ba92921bf28..6e763bc8d7db 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1234,14 +1234,14 @@ static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream,
clear_bit(substream->number, &umidi->input_triggered);
}
-static struct snd_rawmidi_ops snd_usbmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_usbmidi_output_ops = {
.open = snd_usbmidi_output_open,
.close = snd_usbmidi_output_close,
.trigger = snd_usbmidi_output_trigger,
.drain = snd_usbmidi_output_drain,
};
-static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_usbmidi_input_ops = {
.open = snd_usbmidi_input_open,
.close = snd_usbmidi_input_close,
.trigger = snd_usbmidi_input_trigger
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 04991b009132..4fa0053a40af 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -43,6 +43,7 @@
#include "mixer.h"
#include "mixer_quirks.h"
#include "mixer_scarlett.h"
+#include "mixer_us16x08.h"
#include "helper.h"
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
@@ -1729,6 +1730,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
return err;
switch (mixer->chip->usb_id) {
+ /* Tascam US-16x08 */
+ case USB_ID(0x0644, 0x8047):
+ err = snd_us16x08_controls_create(mixer);
+ break;
case USB_ID(0x041e, 0x3020):
case USB_ID(0x041e, 0x3040):
case USB_ID(0x041e, 0x3042):
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
new file mode 100644
index 000000000000..dc48eedea92e
--- /dev/null
+++ b/sound/usb/mixer_us16x08.c
@@ -0,0 +1,1419 @@
+/*
+ * Tascam US-16x08 ALSA driver
+ *
+ * Copyright (c) 2016 by Detlef Urban (onkel@paraair.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+
+#include "mixer_us16x08.h"
+
+/* USB control message templates */
+static const char route_msg[] = {
+ 0x61,
+ 0x02,
+ 0x03, /* input from master (0x02) or input from computer bus (0x03) */
+ 0x62,
+ 0x02,
+ 0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */
+ 0x41,
+ 0x01,
+ 0x61,
+ 0x02,
+ 0x01,
+ 0x62,
+ 0x02,
+ 0x01, /* output index (0x01-0x08) */
+ 0x42,
+ 0x01,
+ 0x43,
+ 0x01,
+ 0x00,
+ 0x00
+};
+
+static const char mix_init_msg1[] = {
+ 0x71, 0x01, 0x00, 0x00
+};
+
+static const char mix_init_msg2[] = {
+ 0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00
+};
+
+static const char mix_msg_in[] = {
+ /* default message head, equal to all mixers */
+ 0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+ 0x81, /* 0x06: Controller ID */
+ 0x02, /* 0x07: */
+ 0x00, /* 0x08: Value of common mixer */
+ 0x00,
+ 0x00
+};
+
+static const char mix_msg_out[] = {
+ /* default message head, equal to all mixers */
+ 0x61, 0x02, 0x02, 0x62, 0x02, 0x01,
+ 0x81, /* 0x06: Controller ID */
+ 0x02, /* 0x07: */
+ 0x00, /* 0x08: Value of common mixer */
+ 0x00,
+ 0x00
+};
+
+static const char bypass_msg_out[] = {
+ 0x45,
+ 0x02,
+ 0x01, /* on/off flag */
+ 0x00,
+ 0x00
+};
+
+static const char bus_msg_out[] = {
+ 0x44,
+ 0x02,
+ 0x01, /* on/off flag */
+ 0x00,
+ 0x00
+};
+
+static const char comp_msg[] = {
+ /* default message head, equal to all mixers */
+ 0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+ 0x91,
+ 0x02,
+ 0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */
+ 0x92,
+ 0x02,
+ 0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff) */
+ 0x93,
+ 0x02,
+ 0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */
+ 0x94,
+ 0x02,
+ 0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10 */
+ 0x95,
+ 0x02,
+ 0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */
+ 0x96,
+ 0x02,
+ 0x01,
+ 0x97,
+ 0x02,
+ 0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */
+ 0x00,
+ 0x00
+};
+
+static const char eqs_msq[] = {
+ /* default message head, equal to all mixers */
+ 0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+ 0x51, /* 0x06: Controller ID */
+ 0x02,
+ 0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */
+ 0x52,
+ 0x02,
+ 0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db) x-6 */
+ 0x53,
+ 0x02,
+ 0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */
+ 0x54,
+ 0x02,
+ 0x02, /* 0x11: band width (0-6) (Q16-Q0.25) 2^x/4 (EQ xxMID only) */
+ 0x55,
+ 0x02,
+ 0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */
+ 0x00,
+ 0x00
+};
+
+/* compressor ratio map */
+static const char ratio_map[] = {
+ 0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e,
+ 0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff
+};
+
+/* route enumeration names */
+static const char *const route_names[] = {
+ "Master Left", "Master Right", "Output 1", "Output 2", "Output 3",
+ "Output 4", "Output 5", "Output 6", "Output 7", "Output 8",
+};
+
+static int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
+ unsigned char *buf, int size)
+{
+
+ mutex_lock(&chip->mutex);
+ snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
+ SND_US16X08_URB_METER_REQUEST,
+ SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+/* wrapper function to send prepared URB buffer to usb device. Return an error
+ * code if something went wrong
+ */
+static int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
+{
+ return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+ SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE,
+ 0, 0, buf, size);
+}
+
+static int snd_us16x08_route_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ return snd_ctl_enum_info(uinfo, 1, 10, route_names);
+}
+
+static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ int index = ucontrol->id.index;
+
+ /* route has no bias */
+ ucontrol->value.enumerated.item[0] = elem->cache_val[index];
+
+ return 0;
+}
+
+static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ int index = ucontrol->id.index;
+ char buf[sizeof(route_msg)];
+ int val, val_org, err;
+
+ /* get the new value (no bias for routes) */
+ val = ucontrol->value.enumerated.item[0];
+
+ /* sanity check */
+ if (val < 0 || val > 9)
+ return -EINVAL;
+
+ /* prepare the message buffer from template */
+ memcpy(buf, route_msg, sizeof(route_msg));
+
+ if (val < 2) {
+ /* input comes from a master channel */
+ val_org = val;
+ buf[2] = 0x02;
+ } else {
+ /* input comes from a computer channel */
+ buf[2] = 0x03;
+ val_org = val - 2;
+ }
+
+ /* place new route selection in URB message */
+ buf[5] = (unsigned char) (val_org & 0x0f) + 1;
+ /* place route selector in URB message */
+ buf[13] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
+
+ if (err > 0) {
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err);
+ }
+
+ return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+ uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+ uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+ return 0;
+}
+
+static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ int index = ucontrol->id.index;
+
+ ucontrol->value.integer.value[0] = elem->cache_val[index];
+
+ return 0;
+}
+
+static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ char buf[sizeof(mix_msg_out)];
+ int val, err;
+ int index = ucontrol->id.index;
+
+ /* new control value incl. bias*/
+ val = ucontrol->value.integer.value[0];
+
+ /* sanity check */
+ if (val < SND_US16X08_KCMIN(kcontrol)
+ || val > SND_US16X08_KCMAX(kcontrol))
+ return -EINVAL;
+
+ /* prepare the message buffer from template */
+ memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
+
+ buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+ buf[6] = elem->head.id;
+
+ /* place channel selector in URB message */
+ buf[5] = index + 1;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
+
+ if (err > 0) {
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set master, err:%d\n", err);
+ }
+
+ return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ char buf[sizeof(mix_msg_out)];
+ int val, err = 0;
+
+ val = ucontrol->value.integer.value[0];
+
+ /* prepare the message buffer from template */
+ switch (elem->head.id) {
+ case SND_US16X08_ID_BYPASS:
+ memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out));
+ buf[2] = val;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out));
+ break;
+ case SND_US16X08_ID_BUSS_OUT:
+ memcpy(buf, bus_msg_out, sizeof(bus_msg_out));
+ buf[2] = val;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out));
+ break;
+ case SND_US16X08_ID_MUTE:
+ memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
+ buf[8] = val;
+ buf[6] = elem->head.id;
+ buf[5] = 1;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
+ break;
+ }
+
+ if (err > 0) {
+ elem->cached |= 1;
+ elem->cache_val[0] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set buss param, err:%d\n", err);
+ }
+
+ return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+
+ switch (elem->head.id) {
+ case SND_US16X08_ID_BUSS_OUT:
+ ucontrol->value.integer.value[0] = elem->cache_val[0];
+ break;
+ case SND_US16X08_ID_BYPASS:
+ ucontrol->value.integer.value[0] = elem->cache_val[0];
+ break;
+ case SND_US16X08_ID_MUTE:
+ ucontrol->value.integer.value[0] = elem->cache_val[0];
+ break;
+ }
+
+ return 0;
+}
+
+/* gets a current mixer value from common store */
+static int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ int index = ucontrol->id.index;
+
+ ucontrol->value.integer.value[0] = elem->cache_val[index];
+
+ return 0;
+}
+
+static int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ char buf[sizeof(mix_msg_in)];
+ int val, err;
+ int index = ucontrol->id.index;
+
+ val = ucontrol->value.integer.value[0];
+
+ /* sanity check */
+ if (val < SND_US16X08_KCMIN(kcontrol)
+ || val > SND_US16X08_KCMAX(kcontrol))
+ return -EINVAL;
+
+ /* prepare URB message from template */
+ memcpy(buf, mix_msg_in, sizeof(mix_msg_in));
+
+ /* add the bias to the new value */
+ buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+ buf[6] = elem->head.id;
+ buf[5] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
+
+ if (err > 0) {
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err);
+ }
+
+ return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+ uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+ uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+ return 0;
+}
+
+static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_comp_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+ int val_idx = COMP_STORE_IDX(elem->head.id);
+
+ ucontrol->value.integer.value[0] = store->val[val_idx][index];
+
+ return 0;
+}
+
+static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_comp_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+ char buf[sizeof(comp_msg)];
+ int val_idx, val;
+ int err;
+
+ val = ucontrol->value.integer.value[0];
+
+ /* sanity check */
+ if (val < SND_US16X08_KCMIN(kcontrol)
+ || val > SND_US16X08_KCMAX(kcontrol))
+ return -EINVAL;
+
+ /* new control value incl. bias*/
+ val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE;
+
+ store->val[val_idx][index] = ucontrol->value.integer.value[0];
+
+ /* prepare compressor URB message from template */
+ memcpy(buf, comp_msg, sizeof(comp_msg));
+
+ /* place comp values in message buffer watch bias! */
+ buf[8] = store->val[
+ COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index]
+ - SND_US16X08_COMP_THRESHOLD_BIAS;
+ buf[11] = ratio_map[store->val[
+ COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]];
+ buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index]
+ + SND_US16X08_COMP_ATTACK_BIAS;
+ buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index]
+ + SND_US16X08_COMP_RELEASE_BIAS;
+ buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
+ buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index];
+
+ /* place channel selector in message buffer */
+ buf[5] = index + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
+
+ if (err > 0) {
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err);
+ }
+
+ return 1;
+}
+
+static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_eq_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+
+ /* get low switch from cache is enough, cause all bands are together */
+ val = store->val[EQ_STORE_BAND_IDX(elem->head.id)]
+ [EQ_STORE_PARAM_IDX(elem->head.id)][index];
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_eq_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+ char buf[sizeof(eqs_msq)];
+ int val, err = 0;
+ int b_idx;
+
+ /* new control value incl. bias*/
+ val = ucontrol->value.integer.value[0] + SND_US16X08_KCBIAS(kcontrol);
+
+ /* prepare URB message from EQ template */
+ memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+ /* place channel index in URB message */
+ buf[5] = index + 1;
+ for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
+ /* all four EQ bands have to be enabled/disabled in once */
+ buf[20] = val;
+ buf[17] = store->val[b_idx][2][index];
+ buf[14] = store->val[b_idx][1][index];
+ buf[11] = store->val[b_idx][0][index];
+ buf[8] = b_idx + 1;
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+ if (err < 0)
+ break;
+ store->val[b_idx][3][index] = val;
+ msleep(15);
+ }
+
+ if (err > 0) {
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err);
+ }
+
+ return 1;
+}
+
+static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int val;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_eq_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+ int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
+ int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
+
+ val = store->val[b_idx][p_idx][index];
+
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+
+static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_eq_store *store = elem->private_data;
+ int index = ucontrol->id.index;
+ char buf[sizeof(eqs_msq)];
+ int val, err;
+ int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
+ int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
+
+ val = ucontrol->value.integer.value[0];
+
+ /* sanity check */
+ if (val < SND_US16X08_KCMIN(kcontrol)
+ || val > SND_US16X08_KCMAX(kcontrol))
+ return -EINVAL;
+
+ /* copy URB buffer from EQ template */
+ memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+ store->val[b_idx][p_idx][index] = val;
+ buf[20] = store->val[b_idx][3][index];
+ buf[17] = store->val[b_idx][2][index];
+ buf[14] = store->val[b_idx][1][index];
+ buf[11] = store->val[b_idx][0][index];
+
+ /* place channel index in URB buffer */
+ buf[5] = index + 1;
+
+ /* place EQ band in URB buffer */
+ buf[8] = b_idx + 1;
+
+ err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+ if (err > 0) {
+ /* store new value in EQ band cache */
+ elem->cached |= 1 << index;
+ elem->cache_val[index] = val;
+ } else {
+ usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err);
+ }
+
+ return 1;
+}
+
+static int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->count = 1;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.max = 0x7FFF;
+ uinfo->value.integer.min = 0;
+
+ return 0;
+}
+
+/* calculate compressor index for reduction level request */
+static int snd_get_meter_comp_index(struct snd_us16x08_meter_store *store)
+{
+ int ret;
+
+ /* any channel active */
+ if (store->comp_active_index) {
+ /* check for stereo link */
+ if (store->comp_active_index & 0x20) {
+ /* reset comp_index to left channel*/
+ if (store->comp_index -
+ store->comp_active_index > 1)
+ store->comp_index =
+ store->comp_active_index;
+
+ ret = store->comp_index++ & 0x1F;
+ } else {
+ /* no stereo link */
+ ret = store->comp_active_index;
+ }
+ } else {
+ /* skip channels with no compressor active */
+ while (!store->comp_store->val[
+ COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)]
+ [store->comp_index - 1]
+ && store->comp_index <= SND_US16X08_MAX_CHANNELS) {
+ store->comp_index++;
+ }
+ ret = store->comp_index++;
+ if (store->comp_index > SND_US16X08_MAX_CHANNELS)
+ store->comp_index = 1;
+ }
+ return ret;
+}
+
+/* retrieve the meter level values from URB message */
+static void get_meter_levels_from_urb(int s,
+ struct snd_us16x08_meter_store *store,
+ u8 *meter_urb)
+{
+ int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8);
+
+ if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
+ MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) {
+ if (MUC0(meter_urb, s) == 0x72)
+ store->meter_level[MUB2(meter_urb, s) - 1] = val;
+ if (MUC0(meter_urb, s) == 0xb2)
+ store->comp_level[MUB2(meter_urb, s) - 1] = val;
+ }
+ if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
+ MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62)
+ store->master_level[MUB2(meter_urb, s) - 1] = val;
+}
+
+/* Function to retrieve current meter values from the device.
+ *
+ * The device needs to be polled for meter values with an initial
+ * requests. It will return with a sequence of different meter value
+ * packages. The first request (case 0:) initiate this meter response sequence.
+ * After the third response, an additional request can be placed,
+ * to retrieve compressor reduction level value for given channel. This round
+ * trip channel selector will skip all inactive compressors.
+ * A mixer can interrupt this round-trip by selecting one ore two (stereo-link)
+ * specific channels.
+ */
+static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i, set;
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ struct snd_us16x08_meter_store *store = elem->private_data;
+ u8 meter_urb[64];
+ char tmp[sizeof(mix_init_msg2)] = {0};
+
+ switch (kcontrol->private_value) {
+ case 0:
+ snd_us16x08_send_urb(chip, (char *)mix_init_msg1,
+ sizeof(mix_init_msg1));
+ snd_us16x08_recv_urb(chip, meter_urb,
+ sizeof(meter_urb));
+ kcontrol->private_value++;
+ break;
+ case 1:
+ snd_us16x08_recv_urb(chip, meter_urb,
+ sizeof(meter_urb));
+ kcontrol->private_value++;
+ break;
+ case 2:
+ snd_us16x08_recv_urb(chip, meter_urb,
+ sizeof(meter_urb));
+ kcontrol->private_value++;
+ break;
+ case 3:
+ memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2));
+ tmp[2] = snd_get_meter_comp_index(store);
+ snd_us16x08_send_urb(chip, tmp, sizeof(mix_init_msg2));
+ snd_us16x08_recv_urb(chip, meter_urb,
+ sizeof(meter_urb));
+ kcontrol->private_value = 0;
+ break;
+ }
+
+ for (set = 0; set < 6; set++)
+ get_meter_levels_from_urb(set, store, meter_urb);
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ ucontrol->value.integer.value[i] =
+ store ? store->meter_level[i] : 0;
+ }
+
+ ucontrol->value.integer.value[i++] = store ? store->master_level[0] : 0;
+ ucontrol->value.integer.value[i++] = store ? store->master_level[1] : 0;
+
+ for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++)
+ ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] =
+ store ? store->comp_level[i - 2] : 0;
+
+ return 1;
+}
+
+static int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kcontrol->private_data;
+ struct snd_us16x08_meter_store *store = elem->private_data;
+ int val;
+
+ val = ucontrol->value.integer.value[0];
+
+ /* sanity check */
+ if (val < 0 || val >= SND_US16X08_MAX_CHANNELS)
+ return -EINVAL;
+
+ store->comp_active_index = val;
+ store->comp_index = val;
+
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_us16x08_ch_boolean_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_channel_get,
+ .put = snd_us16x08_channel_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_ch_int_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_channel_get,
+ .put = snd_us16x08_channel_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
+};
+
+static struct snd_kcontrol_new snd_us16x08_pan_int_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_channel_get,
+ .put = snd_us16x08_channel_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 255)
+};
+
+static struct snd_kcontrol_new snd_us16x08_master_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_master_info,
+ .get = snd_us16x08_master_get,
+ .put = snd_us16x08_master_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
+};
+
+static struct snd_kcontrol_new snd_us16x08_route_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 8,
+ .info = snd_us16x08_route_info,
+ .get = snd_us16x08_route_get,
+ .put = snd_us16x08_route_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9)
+};
+
+static struct snd_kcontrol_new snd_us16x08_bus_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_bus_get,
+ .put = snd_us16x08_bus_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_compswitch_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_COMP_THRESHOLD_BIAS, 1,
+ 0, 0x20)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0,
+ sizeof(ratio_map) - 1), /*max*/
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6),
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_release_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_comp_get,
+ .put = snd_us16x08_comp_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_gain_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_low_freq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_mid_freq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_mid_width_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_high_freq_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_mix_info,
+ .get = snd_us16x08_eq_get,
+ .put = snd_us16x08_eq_put,
+ .private_value =
+ SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_switch_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 16,
+ .info = snd_us16x08_switch_info,
+ .get = snd_us16x08_eqswitch_get,
+ .put = snd_us16x08_eqswitch_put,
+ .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_meter_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .count = 1,
+ .info = snd_us16x08_meter_info,
+ .get = snd_us16x08_meter_get,
+ .put = snd_us16x08_meter_put
+};
+
+/* control store preparation */
+
+/* setup compressor store and assign default value */
+static struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
+{
+ int i;
+ struct snd_us16x08_comp_store *tmp;
+
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return NULL;
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][i]
+ = 0x20;
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][i] = 0x00;
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][i] = 0x00;
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][i] = 0x00;
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][i] = 0x00;
+ tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][i] = 0x00;
+ }
+ return tmp;
+}
+
+/* setup EQ store and assign default values */
+static struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(void)
+{
+ int i, b_idx;
+ struct snd_us16x08_eq_store *tmp;
+
+ tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return NULL;
+
+ for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+ for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
+ tmp->val[b_idx][0][i] = 0x0c;
+ tmp->val[b_idx][3][i] = 0x00;
+ switch (b_idx) {
+ case 0: /* EQ Low */
+ tmp->val[b_idx][1][i] = 0x05;
+ tmp->val[b_idx][2][i] = 0xff;
+ break;
+ case 1: /* EQ Mid low */
+ tmp->val[b_idx][1][i] = 0x0e;
+ tmp->val[b_idx][2][i] = 0x02;
+ break;
+ case 2: /* EQ Mid High */
+ tmp->val[b_idx][1][i] = 0x1b;
+ tmp->val[b_idx][2][i] = 0x02;
+ break;
+ case 3: /* EQ High */
+ tmp->val[b_idx][1][i] = 0x2f
+ - SND_US16X08_EQ_HIGHFREQ_BIAS;
+ tmp->val[b_idx][2][i] = 0xff;
+ break;
+ }
+ }
+ }
+ return tmp;
+}
+
+static struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
+{
+ struct snd_us16x08_meter_store *tmp;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return NULL;
+ tmp->comp_index = 1;
+ tmp->comp_active_index = 0;
+ return tmp;
+}
+
+/* release elem->private_free as well; called only once for each *_store */
+static void elem_private_free(struct snd_kcontrol *kctl)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ if (elem)
+ kfree(elem->private_data);
+ kfree(elem);
+ kctl->private_data = NULL;
+}
+
+static int add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ int index, int val_type, int channels,
+ const char *name, void *opt,
+ bool do_private_free,
+ struct usb_mixer_elem_info **elem_ret)
+{
+ struct snd_kcontrol *kctl;
+ struct usb_mixer_elem_info *elem;
+ int err;
+
+ usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name);
+
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->head.mixer = mixer;
+ elem->head.resume = NULL;
+ elem->control = 0;
+ elem->idx_off = 0;
+ elem->head.id = index;
+ elem->val_type = val_type;
+ elem->channels = channels;
+ elem->private_data = opt;
+
+ kctl = snd_ctl_new1(ncontrol, elem);
+ if (!kctl) {
+ kfree(elem);
+ return -ENOMEM;
+ }
+
+ if (do_private_free)
+ kctl->private_free = elem_private_free;
+ else
+ kctl->private_free = snd_usb_mixer_elem_free;
+
+ strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+ err = snd_usb_mixer_add_control(&elem->head, kctl);
+ if (err < 0)
+ return err;
+
+ if (elem_ret)
+ *elem_ret = elem;
+
+ return 0;
+}
+
+/* table of EQ controls */
+static const struct snd_us16x08_control_params eq_controls[] = {
+ { /* EQ switch */
+ .kcontrol_new = &snd_us16x08_eq_switch_ctl,
+ .control_id = SND_US16X08_ID_EQENABLE,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "EQ Switch",
+ },
+ { /* EQ low gain */
+ .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+ .control_id = SND_US16X08_ID_EQLOWLEVEL,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ Low Volume",
+ },
+ { /* EQ low freq */
+ .kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
+ .control_id = SND_US16X08_ID_EQLOWFREQ,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ Low Frequence",
+ },
+ { /* EQ mid low gain */
+ .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+ .control_id = SND_US16X08_ID_EQLOWMIDLEVEL,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidLow Volume",
+ },
+ { /* EQ mid low freq */
+ .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
+ .control_id = SND_US16X08_ID_EQLOWMIDFREQ,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidLow Frequence",
+ },
+ { /* EQ mid low Q */
+ .kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
+ .control_id = SND_US16X08_ID_EQLOWMIDWIDTH,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidQLow Q",
+ },
+ { /* EQ mid high gain */
+ .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+ .control_id = SND_US16X08_ID_EQHIGHMIDLEVEL,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidHigh Volume",
+ },
+ { /* EQ mid high freq */
+ .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
+ .control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidHigh Frequence",
+ },
+ { /* EQ mid high Q */
+ .kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
+ .control_id = SND_US16X08_ID_EQHIGHMIDWIDTH,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ MidHigh Q",
+ },
+ { /* EQ high gain */
+ .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+ .control_id = SND_US16X08_ID_EQHIGHLEVEL,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ High Volume",
+ },
+ { /* EQ low freq */
+ .kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
+ .control_id = SND_US16X08_ID_EQHIGHFREQ,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "EQ High Frequence",
+ },
+};
+
+/* table of compressor controls */
+static const struct snd_us16x08_control_params comp_controls[] = {
+ { /* Comp enable */
+ .kcontrol_new = &snd_us16x08_compswitch_ctl,
+ .control_id = SND_US16X08_ID_COMP_SWITCH,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "Compressor Switch",
+ },
+ { /* Comp threshold */
+ .kcontrol_new = &snd_us16x08_comp_threshold_ctl,
+ .control_id = SND_US16X08_ID_COMP_THRESHOLD,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Compressor Threshold Volume",
+ },
+ { /* Comp ratio */
+ .kcontrol_new = &snd_us16x08_comp_ratio_ctl,
+ .control_id = SND_US16X08_ID_COMP_RATIO,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Compressor Ratio",
+ },
+ { /* Comp attack */
+ .kcontrol_new = &snd_us16x08_comp_attack_ctl,
+ .control_id = SND_US16X08_ID_COMP_ATTACK,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Compressor Attack",
+ },
+ { /* Comp release */
+ .kcontrol_new = &snd_us16x08_comp_release_ctl,
+ .control_id = SND_US16X08_ID_COMP_RELEASE,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Compressor Release",
+ },
+ { /* Comp gain */
+ .kcontrol_new = &snd_us16x08_comp_gain_ctl,
+ .control_id = SND_US16X08_ID_COMP_GAIN,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Compressor Volume",
+ },
+};
+
+/* table of channel controls */
+static const struct snd_us16x08_control_params channel_controls[] = {
+ { /* Phase */
+ .kcontrol_new = &snd_us16x08_ch_boolean_ctl,
+ .control_id = SND_US16X08_ID_PHASE,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "Phase Switch",
+ .default_val = 0
+ },
+ { /* Fader */
+ .kcontrol_new = &snd_us16x08_ch_int_ctl,
+ .control_id = SND_US16X08_ID_FADER,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Line Volume",
+ .default_val = 127
+ },
+ { /* Mute */
+ .kcontrol_new = &snd_us16x08_ch_boolean_ctl,
+ .control_id = SND_US16X08_ID_MUTE,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "Mute Switch",
+ .default_val = 0
+ },
+ { /* Pan */
+ .kcontrol_new = &snd_us16x08_pan_int_ctl,
+ .control_id = SND_US16X08_ID_PAN,
+ .type = USB_MIXER_U16,
+ .num_channels = 16,
+ .name = "Pan Left-Right Volume",
+ .default_val = 127
+ },
+};
+
+/* table of master controls */
+static const struct snd_us16x08_control_params master_controls[] = {
+ { /* Master */
+ .kcontrol_new = &snd_us16x08_master_ctl,
+ .control_id = SND_US16X08_ID_FADER,
+ .type = USB_MIXER_U8,
+ .num_channels = 16,
+ .name = "Master Volume",
+ .default_val = 127
+ },
+ { /* Bypass */
+ .kcontrol_new = &snd_us16x08_bus_ctl,
+ .control_id = SND_US16X08_ID_BYPASS,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "DSP Bypass Switch",
+ .default_val = 0
+ },
+ { /* Buss out */
+ .kcontrol_new = &snd_us16x08_bus_ctl,
+ .control_id = SND_US16X08_ID_BUSS_OUT,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "Buss Out Switch",
+ .default_val = 0
+ },
+ { /* Master mute */
+ .kcontrol_new = &snd_us16x08_bus_ctl,
+ .control_id = SND_US16X08_ID_MUTE,
+ .type = USB_MIXER_BOOLEAN,
+ .num_channels = 16,
+ .name = "Master Mute Switch",
+ .default_val = 0
+ },
+
+};
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
+{
+ int i, j;
+ int err;
+ struct usb_mixer_elem_info *elem;
+ struct snd_us16x08_comp_store *comp_store;
+ struct snd_us16x08_meter_store *meter_store;
+ struct snd_us16x08_eq_store *eq_store;
+
+ /* just check for non-MIDI interface */
+ if (mixer->hostif->desc.bInterfaceNumber == 3) {
+
+ /* add routing control */
+ err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
+ SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
+ NULL, false, &elem);
+ if (err < 0) {
+ usb_audio_dbg(mixer->chip,
+ "Failed to create route control, err:%d\n",
+ err);
+ return err;
+ }
+ for (i = 0; i < 8; i++)
+ elem->cache_val[i] = i < 2 ? i : i + 2;
+ elem->cached = 0xff;
+
+ /* create compressor mixer elements */
+ comp_store = snd_us16x08_create_comp_store();
+ if (!comp_store)
+ return -ENOMEM;
+
+ /* add master controls */
+ for (i = 0; i < ARRAY_SIZE(master_controls); i++) {
+
+ err = add_new_ctl(mixer,
+ master_controls[i].kcontrol_new,
+ master_controls[i].control_id,
+ master_controls[i].type,
+ master_controls[i].num_channels,
+ master_controls[i].name,
+ comp_store,
+ i == 0, /* release comp_store only once */
+ &elem);
+ if (err < 0)
+ return err;
+ elem->cache_val[0] = master_controls[i].default_val;
+ elem->cached = 1;
+ }
+
+ /* add channel controls */
+ for (i = 0; i < ARRAY_SIZE(channel_controls); i++) {
+
+ err = add_new_ctl(mixer,
+ channel_controls[i].kcontrol_new,
+ channel_controls[i].control_id,
+ channel_controls[i].type,
+ channel_controls[i].num_channels,
+ channel_controls[i].name,
+ comp_store,
+ false, &elem);
+ if (err < 0)
+ return err;
+ for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
+ elem->cache_val[j] =
+ channel_controls[i].default_val;
+ }
+ elem->cached = 0xffff;
+ }
+
+ /* create eq store */
+ eq_store = snd_us16x08_create_eq_store();
+ if (!eq_store)
+ return -ENOMEM;
+
+ /* add EQ controls */
+ for (i = 0; i < ARRAY_SIZE(eq_controls); i++) {
+
+ err = add_new_ctl(mixer,
+ eq_controls[i].kcontrol_new,
+ eq_controls[i].control_id,
+ eq_controls[i].type,
+ eq_controls[i].num_channels,
+ eq_controls[i].name,
+ eq_store,
+ i == 0, /* release eq_store only once */
+ NULL);
+ if (err < 0)
+ return err;
+ }
+
+ /* add compressor controls */
+ for (i = 0; i < ARRAY_SIZE(comp_controls); i++) {
+
+ err = add_new_ctl(mixer,
+ comp_controls[i].kcontrol_new,
+ comp_controls[i].control_id,
+ comp_controls[i].type,
+ comp_controls[i].num_channels,
+ comp_controls[i].name,
+ comp_store,
+ false, NULL);
+ if (err < 0)
+ return err;
+ }
+
+ /* create meters store */
+ meter_store = snd_us16x08_create_meter_store();
+ if (!meter_store)
+ return -ENOMEM;
+
+ /* meter function 'get' must access to compressor store
+ * so place a reference here
+ */
+ meter_store->comp_store = comp_store;
+ err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
+ SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
+ meter_store, true, NULL);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
diff --git a/sound/usb/mixer_us16x08.h b/sound/usb/mixer_us16x08.h
new file mode 100644
index 000000000000..a6312fb0f962
--- /dev/null
+++ b/sound/usb/mixer_us16x08.h
@@ -0,0 +1,121 @@
+#ifndef __USB_MIXER_US16X08_H
+#define __USB_MIXER_US16X08_H
+
+#define SND_US16X08_MAX_CHANNELS 16
+
+/* define some bias, cause some alsa-mixers wont work with
+ * negative ranges or if mixer-min != 0
+ */
+#define SND_US16X08_NO_BIAS 0
+#define SND_US16X08_FADER_BIAS 127
+#define SND_US16X08_EQ_HIGHFREQ_BIAS 0x20
+#define SND_US16X08_COMP_THRESHOLD_BIAS 0x20
+#define SND_US16X08_COMP_ATTACK_BIAS 2
+#define SND_US16X08_COMP_RELEASE_BIAS 1
+
+/* get macro for components of kcontrol private_value */
+#define SND_US16X08_KCBIAS(x) (((x)->private_value >> 24) & 0xff)
+#define SND_US16X08_KCSTEP(x) (((x)->private_value >> 16) & 0xff)
+#define SND_US16X08_KCMIN(x) (((x)->private_value >> 8) & 0xff)
+#define SND_US16X08_KCMAX(x) (((x)->private_value >> 0) & 0xff)
+/* set macro for kcontrol private_value */
+#define SND_US16X08_KCSET(bias, step, min, max) \
+ (((bias) << 24) | ((step) << 16) | ((min) << 8) | (max))
+
+/* the URB request/type to control Tascam mixers */
+#define SND_US16X08_URB_REQUEST 0x1D
+#define SND_US16X08_URB_REQUESTTYPE 0x40
+
+/* the URB params to retrieve meter ranges */
+#define SND_US16X08_URB_METER_REQUEST 0x1e
+#define SND_US16X08_URB_METER_REQUESTTYPE 0xc0
+
+#define MUA0(x, y) ((x)[(y) * 10 + 4])
+#define MUA1(x, y) ((x)[(y) * 10 + 5])
+#define MUA2(x, y) ((x)[(y) * 10 + 6])
+#define MUB0(x, y) ((x)[(y) * 10 + 7])
+#define MUB1(x, y) ((x)[(y) * 10 + 8])
+#define MUB2(x, y) ((x)[(y) * 10 + 9])
+#define MUC0(x, y) ((x)[(y) * 10 + 10])
+#define MUC1(x, y) ((x)[(y) * 10 + 11])
+#define MUC2(x, y) ((x)[(y) * 10 + 12])
+#define MUC3(x, y) ((x)[(y) * 10 + 13])
+
+/* Common Channel control IDs */
+#define SND_US16X08_ID_BYPASS 0x45
+#define SND_US16X08_ID_BUSS_OUT 0x44
+#define SND_US16X08_ID_PHASE 0x85
+#define SND_US16X08_ID_MUTE 0x83
+#define SND_US16X08_ID_FADER 0x81
+#define SND_US16X08_ID_PAN 0x82
+#define SND_US16X08_ID_METER 0xB1
+
+#define SND_US16X08_ID_EQ_BAND_COUNT 4
+#define SND_US16X08_ID_EQ_PARAM_COUNT 4
+
+/* EQ level IDs */
+#define SND_US16X08_ID_EQLOWLEVEL 0x01
+#define SND_US16X08_ID_EQLOWMIDLEVEL 0x02
+#define SND_US16X08_ID_EQHIGHMIDLEVEL 0x03
+#define SND_US16X08_ID_EQHIGHLEVEL 0x04
+
+/* EQ frequence IDs */
+#define SND_US16X08_ID_EQLOWFREQ 0x11
+#define SND_US16X08_ID_EQLOWMIDFREQ 0x12
+#define SND_US16X08_ID_EQHIGHMIDFREQ 0x13
+#define SND_US16X08_ID_EQHIGHFREQ 0x14
+
+/* EQ width IDs */
+#define SND_US16X08_ID_EQLOWMIDWIDTH 0x22
+#define SND_US16X08_ID_EQHIGHMIDWIDTH 0x23
+
+#define SND_US16X08_ID_EQENABLE 0x30
+
+#define EQ_STORE_BAND_IDX(x) ((x) & 0xf)
+#define EQ_STORE_PARAM_IDX(x) (((x) & 0xf0) >> 4)
+
+#define SND_US16X08_ID_ROUTE 0x00
+
+/* Compressor Ids */
+#define SND_US16X08_ID_COMP_BASE 0x32
+#define SND_US16X08_ID_COMP_THRESHOLD SND_US16X08_ID_COMP_BASE
+#define SND_US16X08_ID_COMP_RATIO (SND_US16X08_ID_COMP_BASE + 1)
+#define SND_US16X08_ID_COMP_ATTACK (SND_US16X08_ID_COMP_BASE + 2)
+#define SND_US16X08_ID_COMP_RELEASE (SND_US16X08_ID_COMP_BASE + 3)
+#define SND_US16X08_ID_COMP_GAIN (SND_US16X08_ID_COMP_BASE + 4)
+#define SND_US16X08_ID_COMP_SWITCH (SND_US16X08_ID_COMP_BASE + 5)
+#define SND_US16X08_ID_COMP_COUNT 6
+
+#define COMP_STORE_IDX(x) ((x) - SND_US16X08_ID_COMP_BASE)
+
+struct snd_us16x08_eq_store {
+ u8 val[SND_US16X08_ID_EQ_BAND_COUNT][SND_US16X08_ID_EQ_PARAM_COUNT]
+ [SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_comp_store {
+ u8 val[SND_US16X08_ID_COMP_COUNT][SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_meter_store {
+ int meter_level[SND_US16X08_MAX_CHANNELS];
+ int master_level[2]; /* level of meter for master output */
+ int comp_index; /* round trip channel selector */
+ int comp_active_index; /* channel select from user space mixer */
+ int comp_level[16]; /* compressor reduction level */
+ struct snd_us16x08_comp_store *comp_store;
+};
+
+struct snd_us16x08_control_params {
+ struct snd_kcontrol_new *kcontrol_new;
+ int control_id;
+ int type;
+ int num_channels;
+ const char *name;
+ int default_val;
+};
+
+#define snd_us16x08_switch_info snd_ctl_boolean_mono_info
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer);
+#endif /* __USB_MIXER_US16X08_H */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index eb4b9f7a571e..01eff6ce6401 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1360,6 +1360,21 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
if (fp->altsetting == 3)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
+
+ /* Amanero Combo384 USB interface with native DSD support */
+ case USB_ID(0x16d0, 0x071a):
+ if (fp->altsetting == 2) {
+ switch (chip->dev->descriptor.bcdDevice) {
+ case 0x199:
+ return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+ case 0x19b:
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+ default:
+ break;
+ }
+ }
+ break;
+
default:
break;
}
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index cf5dc33f4a6d..cf45bf1f7ee0 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -137,13 +137,12 @@ static void usb_stream_hwdep_vm_open(struct vm_area_struct *area)
snd_printdd(KERN_DEBUG "%i\n", atomic_read(&us122l->mmap_count));
}
-static int usb_stream_hwdep_vm_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int usb_stream_hwdep_vm_fault(struct vm_fault *vmf)
{
unsigned long offset;
struct page *page;
void *vaddr;
- struct us122l *us122l = area->vm_private_data;
+ struct us122l *us122l = vmf->vma->vm_private_data;
struct usb_stream *s;
mutex_lock(&us122l->mutex);
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 0b34dbc8f302..605e1047c01d 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -31,19 +31,18 @@
#include "usbusx2y.h"
#include "usX2Yhwdep.h"
-static int snd_us428ctls_vm_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_us428ctls_vm_fault(struct vm_fault *vmf)
{
unsigned long offset;
struct page * page;
void *vaddr;
snd_printdd("ENTER, start %lXh, pgoff %ld\n",
- area->vm_start,
+ vmf->vma->vm_start,
vmf->pgoff);
offset = vmf->pgoff << PAGE_SHIFT;
- vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset;
+ vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->us428ctls_sharedmem + offset;
page = virt_to_page(vaddr);
get_page(page);
vmf->page = page;
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 90766a92e7fd..f95164b91152 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -652,14 +652,13 @@ static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
}
-static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_fault *vmf)
{
unsigned long offset;
void *vaddr;
offset = vmf->pgoff << PAGE_SHIFT;
- vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
+ vaddr = (char *)((struct usX2Ydev *)vmf->vma->vm_private_data)->hwdep_pcm_shm + offset;
vmf->page = virt_to_page(vaddr);
get_page(vmf->page);
return 0;
diff --git a/sound/x86/Kconfig b/sound/x86/Kconfig
new file mode 100644
index 000000000000..84c8f8fc597c
--- /dev/null
+++ b/sound/x86/Kconfig
@@ -0,0 +1,16 @@
+menuconfig SND_X86
+ tristate "X86 sound devices"
+ depends on X86
+ ---help---
+ X86 sound devices that don't fall under SoC or PCI categories
+
+if SND_X86
+
+config HDMI_LPE_AUDIO
+ tristate "HDMI audio without HDaudio on Intel Atom platforms"
+ depends on DRM_I915
+ select SND_PCM
+ help
+ Choose this option to support HDMI LPE Audio mode
+
+endif # SND_X86
diff --git a/sound/x86/Makefile b/sound/x86/Makefile
new file mode 100644
index 000000000000..7ff919808320
--- /dev/null
+++ b/sound/x86/Makefile
@@ -0,0 +1,4 @@
+snd-hdmi-lpe-audio-objs += \
+ intel_hdmi_audio.o
+
+obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
new file mode 100644
index 000000000000..c505b019e09c
--- /dev/null
+++ b/sound/x86/intel_hdmi_audio.c
@@ -0,0 +1,1867 @@
+/*
+ * intel_hdmi_audio.c - Intel HDMI audio driver
+ *
+ * Copyright (C) 2016 Intel Corp
+ * Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ * Ramesh Babu K V <ramesh.babu@intel.com>
+ * Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ * Jerome Anand <jerome.anand@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel HDMI audio
+ */
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+#include <sound/core.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/jack.h>
+#include <drm/drm_edid.h>
+#include <drm/intel_lpe_audio.h>
+#include "intel_hdmi_audio.h"
+
+/*standard module options for ALSA. This module supports only one card*/
+static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
+static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
+
+module_param_named(index, hdmi_card_index, int, 0444);
+MODULE_PARM_DESC(index,
+ "Index value for INTEL Intel HDMI Audio controller.");
+module_param_named(id, hdmi_card_id, charp, 0444);
+MODULE_PARM_DESC(id,
+ "ID string for INTEL Intel HDMI Audio controller.");
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static const int eld_speaker_allocation_bits[] = {
+ [0] = FL | FR,
+ [1] = LFE,
+ [2] = FC,
+ [3] = RL | RR,
+ [4] = RC,
+ [5] = FLC | FRC,
+ [6] = RLC | RRC,
+ /* the following are not defined in ELD yet */
+ [7] = 0,
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/* channel: 7 6 5 4 3 2 1 0 */
+{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } },
+ /* 2.1 */
+{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } },
+ /* Dolby Surround */
+{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } },
+ /* surround40 */
+{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } },
+ /* surround41 */
+{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } },
+ /* surround50 */
+{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } },
+ /* surround51 */
+{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } },
+ /* 6.1 */
+{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } },
+ /* surround71 */
+{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } },
+
+{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } },
+{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } },
+{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } },
+{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } },
+{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } },
+{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } },
+{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } },
+{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } },
+{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } },
+{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } },
+{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } },
+{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } },
+{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } },
+{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } },
+{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } },
+{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } },
+{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } },
+};
+
+static const struct channel_map_table map_tables[] = {
+ { SNDRV_CHMAP_FL, 0x00, FL },
+ { SNDRV_CHMAP_FR, 0x01, FR },
+ { SNDRV_CHMAP_RL, 0x04, RL },
+ { SNDRV_CHMAP_RR, 0x05, RR },
+ { SNDRV_CHMAP_LFE, 0x02, LFE },
+ { SNDRV_CHMAP_FC, 0x03, FC },
+ { SNDRV_CHMAP_RLC, 0x06, RLC },
+ { SNDRV_CHMAP_RRC, 0x07, RRC },
+ {} /* terminator */
+};
+
+/* hardware capability structure */
+static const struct snd_pcm_hardware had_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+ .rate_min = HAD_MIN_RATE,
+ .rate_max = HAD_MAX_RATE,
+ .channels_min = HAD_MIN_CHANNEL,
+ .channels_max = HAD_MAX_CHANNEL,
+ .buffer_bytes_max = HAD_MAX_BUFFER,
+ .period_bytes_min = HAD_MIN_PERIOD_BYTES,
+ .period_bytes_max = HAD_MAX_PERIOD_BYTES,
+ .periods_min = HAD_MIN_PERIODS,
+ .periods_max = HAD_MAX_PERIODS,
+ .fifo_size = HAD_FIFO_SIZE,
+};
+
+/* Get the active PCM substream;
+ * Call had_substream_put() for unreferecing.
+ * Don't call this inside had_spinlock, as it takes by itself
+ */
+static struct snd_pcm_substream *
+had_substream_get(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+ unsigned long flags;
+
+ spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+ substream = intelhaddata->stream_info.substream;
+ if (substream)
+ intelhaddata->stream_info.substream_refcount++;
+ spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+ return substream;
+}
+
+/* Unref the active PCM substream;
+ * Don't call this inside had_spinlock, as it takes by itself
+ */
+static void had_substream_put(struct snd_intelhad *intelhaddata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+ intelhaddata->stream_info.substream_refcount--;
+ spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+}
+
+/* Register access functions */
+static u32 had_read_register_raw(struct snd_intelhad *ctx, u32 reg)
+{
+ return ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
+}
+
+static void had_write_register_raw(struct snd_intelhad *ctx, u32 reg, u32 val)
+{
+ iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
+}
+
+static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
+{
+ if (!ctx->connected)
+ *val = 0;
+ else
+ *val = had_read_register_raw(ctx, reg);
+}
+
+static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
+{
+ if (ctx->connected)
+ had_write_register_raw(ctx, reg, val);
+}
+
+/*
+ * enable / disable audio configuration
+ *
+ * The normal read/modify should not directly be used on VLV2 for
+ * updating AUD_CONFIG register.
+ * This is because:
+ * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2
+ * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always
+ * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the
+ * register. This field should be 1xy binary for configuration with 6 or
+ * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio)
+ * causes the "channels" field to be updated as 0xy binary resulting in
+ * bad audio. The fix is to always write the AUD_CONFIG[6:4] with
+ * appropriate value when doing read-modify of AUD_CONFIG register.
+ */
+static void had_enable_audio(struct snd_intelhad *intelhaddata,
+ bool enable)
+{
+ /* update the cached value */
+ intelhaddata->aud_config.regx.aud_en = enable;
+ had_write_register(intelhaddata, AUD_CONFIG,
+ intelhaddata->aud_config.regval);
+}
+
+/* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */
+static void had_ack_irqs(struct snd_intelhad *ctx)
+{
+ u32 status_reg;
+
+ if (!ctx->connected)
+ return;
+ had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
+ status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
+ had_write_register(ctx, AUD_HDMI_STATUS, status_reg);
+ had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
+}
+
+/* Reset buffer pointers */
+static void had_reset_audio(struct snd_intelhad *intelhaddata)
+{
+ had_write_register(intelhaddata, AUD_HDMI_STATUS,
+ AUD_HDMI_STATUSG_MASK_FUNCRST);
+ had_write_register(intelhaddata, AUD_HDMI_STATUS, 0);
+}
+
+/*
+ * initialize audio channel status registers
+ * This function is called in the prepare callback
+ */
+static int had_prog_status_reg(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ union aud_cfg cfg_val = {.regval = 0};
+ union aud_ch_status_0 ch_stat0 = {.regval = 0};
+ union aud_ch_status_1 ch_stat1 = {.regval = 0};
+
+ ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits &
+ IEC958_AES0_NONAUDIO) >> 1;
+ ch_stat0.regx.clk_acc = (intelhaddata->aes_bits &
+ IEC958_AES3_CON_CLOCK) >> 4;
+ cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id;
+
+ switch (substream->runtime->rate) {
+ case AUD_SAMPLE_RATE_32:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ;
+ break;
+
+ case AUD_SAMPLE_RATE_44_1:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ;
+ break;
+ case AUD_SAMPLE_RATE_48:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ;
+ break;
+ case AUD_SAMPLE_RATE_88_2:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ;
+ break;
+ case AUD_SAMPLE_RATE_96:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ;
+ break;
+ case AUD_SAMPLE_RATE_176_4:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ;
+ break;
+ case AUD_SAMPLE_RATE_192:
+ ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ;
+ break;
+
+ default:
+ /* control should never come here */
+ return -EINVAL;
+ }
+
+ had_write_register(intelhaddata,
+ AUD_CH_STATUS_0, ch_stat0.regval);
+
+ switch (substream->runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20;
+ ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
+ ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24;
+ ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ had_write_register(intelhaddata,
+ AUD_CH_STATUS_1, ch_stat1.regval);
+ return 0;
+}
+
+/*
+ * function to initialize audio
+ * registers and buffer confgiuration registers
+ * This function is called in the prepare callback
+ */
+static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ union aud_cfg cfg_val = {.regval = 0};
+ union aud_buf_config buf_cfg = {.regval = 0};
+ u8 channels;
+
+ had_prog_status_reg(substream, intelhaddata);
+
+ buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD;
+ buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
+ buf_cfg.regx.aud_delay = 0;
+ had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval);
+
+ channels = substream->runtime->channels;
+ cfg_val.regx.num_ch = channels - 2;
+ if (channels <= 2)
+ cfg_val.regx.layout = LAYOUT0;
+ else
+ cfg_val.regx.layout = LAYOUT1;
+
+ if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
+ cfg_val.regx.packet_mode = 1;
+
+ if (substream->runtime->format == SNDRV_PCM_FORMAT_S32_LE)
+ cfg_val.regx.left_align = 1;
+
+ cfg_val.regx.val_bit = 1;
+
+ /* fix up the DP bits */
+ if (intelhaddata->dp_output) {
+ cfg_val.regx.dp_modei = 1;
+ cfg_val.regx.set = 1;
+ }
+
+ had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval);
+ intelhaddata->aud_config = cfg_val;
+ return 0;
+}
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+ int i, j;
+ struct cea_channel_speaker_allocation *p;
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ p = channel_allocations + i;
+ p->channels = 0;
+ p->spk_mask = 0;
+ for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+ if (p->speakers[j]) {
+ p->channels++;
+ p->spk_mask |= p->speakers[j];
+ }
+ }
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ * spk_mask => (channel_allocations[]) => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+ */
+static int had_channel_allocation(struct snd_intelhad *intelhaddata,
+ int channels)
+{
+ int i;
+ int ca = 0;
+ int spk_mask = 0;
+
+ /*
+ * CA defaults to 0 for basic stereo audio
+ */
+ if (channels <= 2)
+ return 0;
+
+ /*
+ * expand ELD's speaker allocation mask
+ *
+ * ELD tells the speaker mask in a compact(paired) form,
+ * expand ELD's notions to match the ones used by Audio InfoFrame.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+ if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
+ spk_mask |= eld_speaker_allocation_bits[i];
+ }
+
+ /* search for the first working match in the CA table */
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (channels == channel_allocations[i].channels &&
+ (spk_mask & channel_allocations[i].spk_mask) ==
+ channel_allocations[i].spk_mask) {
+ ca = channel_allocations[i].ca_index;
+ break;
+ }
+ }
+
+ dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);
+
+ return ca;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+ const struct channel_map_table *t = map_tables;
+
+ for (; t->map; t++) {
+ if (t->spk_mask == spk)
+ return t->map;
+ }
+ return 0;
+}
+
+static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
+{
+ int i, c;
+ int spk_mask = 0;
+ struct snd_pcm_chmap_elem *chmap;
+ u8 eld_high, eld_high_mask = 0xF0;
+ u8 high_msb;
+
+ kfree(intelhaddata->chmap->chmap);
+ intelhaddata->chmap->chmap = NULL;
+
+ chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
+ if (!chmap)
+ return;
+
+ dev_dbg(intelhaddata->dev, "eld speaker = %x\n",
+ intelhaddata->eld[DRM_ELD_SPEAKER]);
+
+ /* WA: Fix the max channel supported to 8 */
+
+ /*
+ * Sink may support more than 8 channels, if eld_high has more than
+ * one bit set. SOC supports max 8 channels.
+ * Refer eld_speaker_allocation_bits, for sink speaker allocation
+ */
+
+ /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
+ eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask;
+ if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
+ /* eld_high & (eld_high-1): if more than 1 bit set */
+ /* 0x1F: 7 channels */
+ for (i = 1; i < 4; i++) {
+ high_msb = eld_high & (0x80 >> i);
+ if (high_msb) {
+ intelhaddata->eld[DRM_ELD_SPEAKER] &=
+ high_msb | 0xF;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+ if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
+ spk_mask |= eld_speaker_allocation_bits[i];
+ }
+
+ for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+ if (spk_mask == channel_allocations[i].spk_mask) {
+ for (c = 0; c < channel_allocations[i].channels; c++) {
+ chmap->map[c] = spk_to_chmap(
+ channel_allocations[i].speakers[
+ (MAX_SPEAKERS - 1) - c]);
+ }
+ chmap->channels = channel_allocations[i].channels;
+ intelhaddata->chmap->chmap = chmap;
+ break;
+ }
+ }
+ if (i >= ARRAY_SIZE(channel_allocations))
+ kfree(chmap);
+}
+
+/*
+ * ALSA API channel-map control callbacks
+ */
+static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = HAD_MAX_CHANNEL;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+ return 0;
+}
+
+static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct snd_intelhad *intelhaddata = info->private_data;
+ int i;
+ const struct snd_pcm_chmap_elem *chmap;
+
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(long) * HAD_MAX_CHANNEL);
+ mutex_lock(&intelhaddata->mutex);
+ if (!intelhaddata->chmap->chmap) {
+ mutex_unlock(&intelhaddata->mutex);
+ return 0;
+ }
+
+ chmap = intelhaddata->chmap->chmap;
+ for (i = 0; i < chmap->channels; i++)
+ ucontrol->value.integer.value[i] = chmap->map[i];
+ mutex_unlock(&intelhaddata->mutex);
+
+ return 0;
+}
+
+static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
+ struct snd_pcm *pcm)
+{
+ int err;
+
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 0, (unsigned long)intelhaddata,
+ &intelhaddata->chmap);
+ if (err < 0)
+ return err;
+
+ intelhaddata->chmap->private_data = intelhaddata;
+ intelhaddata->chmap->kctl->info = had_chmap_ctl_info;
+ intelhaddata->chmap->kctl->get = had_chmap_ctl_get;
+ intelhaddata->chmap->chmap = NULL;
+ return 0;
+}
+
+/*
+ * Initialize Data Island Packets registers
+ * This function is called in the prepare callback
+ */
+static void had_prog_dip(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ int i;
+ union aud_ctrl_st ctrl_state = {.regval = 0};
+ union aud_info_frame2 frame2 = {.regval = 0};
+ union aud_info_frame3 frame3 = {.regval = 0};
+ u8 checksum = 0;
+ u32 info_frame;
+ int channels;
+ int ca;
+
+ channels = substream->runtime->channels;
+
+ had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
+
+ ca = had_channel_allocation(intelhaddata, channels);
+ if (intelhaddata->dp_output) {
+ info_frame = DP_INFO_FRAME_WORD1;
+ frame2.regval = (substream->runtime->channels - 1) | (ca << 24);
+ } else {
+ info_frame = HDMI_INFO_FRAME_WORD1;
+ frame2.regx.chnl_cnt = substream->runtime->channels - 1;
+ frame3.regx.chnl_alloc = ca;
+
+ /* Calculte the byte wide checksum for all valid DIP words */
+ for (i = 0; i < BYTES_PER_WORD; i++)
+ checksum += (info_frame >> (i * 8)) & 0xff;
+ for (i = 0; i < BYTES_PER_WORD; i++)
+ checksum += (frame2.regval >> (i * 8)) & 0xff;
+ for (i = 0; i < BYTES_PER_WORD; i++)
+ checksum += (frame3.regval >> (i * 8)) & 0xff;
+
+ frame2.regx.chksum = -(checksum);
+ }
+
+ had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame);
+ had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval);
+ had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval);
+
+ /* program remaining DIP words with zero */
+ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
+ had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0);
+
+ ctrl_state.regx.dip_freq = 1;
+ ctrl_state.regx.dip_en_sta = 1;
+ had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
+}
+
+static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
+{
+ u32 maud_val;
+
+ /* Select maud according to DP 1.2 spec */
+ if (link_rate == DP_2_7_GHZ) {
+ switch (aud_samp_freq) {
+ case AUD_SAMPLE_RATE_32:
+ maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_44_1:
+ maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_48:
+ maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_88_2:
+ maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_96:
+ maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_176_4:
+ maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
+ break;
+
+ case HAD_MAX_RATE:
+ maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
+ break;
+
+ default:
+ maud_val = -EINVAL;
+ break;
+ }
+ } else if (link_rate == DP_1_62_GHZ) {
+ switch (aud_samp_freq) {
+ case AUD_SAMPLE_RATE_32:
+ maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_44_1:
+ maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_48:
+ maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_88_2:
+ maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_96:
+ maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
+ break;
+
+ case AUD_SAMPLE_RATE_176_4:
+ maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
+ break;
+
+ case HAD_MAX_RATE:
+ maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
+ break;
+
+ default:
+ maud_val = -EINVAL;
+ break;
+ }
+ } else
+ maud_val = -EINVAL;
+
+ return maud_val;
+}
+
+/*
+ * Program HDMI audio CTS value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @tmds: sampling frequency of the display data
+ * @link_rate: DP link rate
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata: substream private data
+ *
+ * Program CTS register based on the audio and display sampling frequency
+ */
+static void had_prog_cts(u32 aud_samp_freq, u32 tmds, u32 link_rate,
+ u32 n_param, struct snd_intelhad *intelhaddata)
+{
+ u32 cts_val;
+ u64 dividend, divisor;
+
+ if (intelhaddata->dp_output) {
+ /* Substitute cts_val with Maud according to DP 1.2 spec*/
+ cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
+ } else {
+ /* Calculate CTS according to HDMI 1.3a spec*/
+ dividend = (u64)tmds * n_param*1000;
+ divisor = 128 * aud_samp_freq;
+ cts_val = div64_u64(dividend, divisor);
+ }
+ dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n",
+ tmds, n_param, cts_val);
+ had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val));
+}
+
+static int had_calculate_n_value(u32 aud_samp_freq)
+{
+ int n_val;
+
+ /* Select N according to HDMI 1.3a spec*/
+ switch (aud_samp_freq) {
+ case AUD_SAMPLE_RATE_32:
+ n_val = 4096;
+ break;
+
+ case AUD_SAMPLE_RATE_44_1:
+ n_val = 6272;
+ break;
+
+ case AUD_SAMPLE_RATE_48:
+ n_val = 6144;
+ break;
+
+ case AUD_SAMPLE_RATE_88_2:
+ n_val = 12544;
+ break;
+
+ case AUD_SAMPLE_RATE_96:
+ n_val = 12288;
+ break;
+
+ case AUD_SAMPLE_RATE_176_4:
+ n_val = 25088;
+ break;
+
+ case HAD_MAX_RATE:
+ n_val = 24576;
+ break;
+
+ default:
+ n_val = -EINVAL;
+ break;
+ }
+ return n_val;
+}
+
+/*
+ * Program HDMI audio N value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata: substream private data
+ *
+ * This function is called in the prepare callback.
+ * It programs based on the audio and display sampling frequency
+ */
+static int had_prog_n(u32 aud_samp_freq, u32 *n_param,
+ struct snd_intelhad *intelhaddata)
+{
+ int n_val;
+
+ if (intelhaddata->dp_output) {
+ /*
+ * According to DP specs, Maud and Naud values hold
+ * a relationship, which is stated as:
+ * Maud/Naud = 512 * fs / f_LS_Clk
+ * where, fs is the sampling frequency of the audio stream
+ * and Naud is 32768 for Async clock.
+ */
+
+ n_val = DP_NAUD_VAL;
+ } else
+ n_val = had_calculate_n_value(aud_samp_freq);
+
+ if (n_val < 0)
+ return n_val;
+
+ had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val));
+ *n_param = n_val;
+ return 0;
+}
+
+/*
+ * PCM ring buffer handling
+ *
+ * The hardware provides a ring buffer with the fixed 4 buffer descriptors
+ * (BDs). The driver maps these 4 BDs onto the PCM ring buffer. The mapping
+ * moves at each period elapsed. The below illustrates how it works:
+ *
+ * At time=0
+ * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ * BD | 0 | 1 | 2 | 3 |
+ *
+ * At time=1 (period elapsed)
+ * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ * BD | 1 | 2 | 3 | 0 |
+ *
+ * At time=2 (second period elapsed)
+ * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ * BD | 2 | 3 | 0 | 1 |
+ *
+ * The bd_head field points to the index of the BD to be read. It's also the
+ * position to be filled at next. The pcm_head and the pcm_filled fields
+ * point to the indices of the current position and of the next position to
+ * be filled, respectively. For PCM buffer there are both _head and _filled
+ * because they may be difference when nperiods > 4. For example, in the
+ * example above at t=1, bd_head=1 and pcm_head=1 while pcm_filled=5:
+ *
+ * pcm_head (=1) --v v-- pcm_filled (=5)
+ * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ * BD | 1 | 2 | 3 | 0 |
+ * bd_head (=1) --^ ^-- next to fill (= bd_head)
+ *
+ * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that
+ * the hardware skips those BDs in the loop.
+ *
+ * An exceptional setup is the case with nperiods=1. Since we have to update
+ * BDs after finishing one BD processing, we'd need at least two BDs, where
+ * both BDs point to the same content, the same address, the same size of the
+ * whole PCM buffer.
+ */
+
+#define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH)
+#define AUD_BUF_LEN(x) (AUD_BUF_A_LENGTH + (x) * HAD_REG_WIDTH)
+
+/* Set up a buffer descriptor at the "filled" position */
+static void had_prog_bd(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ int idx = intelhaddata->bd_head;
+ int ofs = intelhaddata->pcmbuf_filled * intelhaddata->period_bytes;
+ u32 addr = substream->runtime->dma_addr + ofs;
+
+ addr |= AUD_BUF_VALID;
+ if (!substream->runtime->no_period_wakeup)
+ addr |= AUD_BUF_INTR_EN;
+ had_write_register(intelhaddata, AUD_BUF_ADDR(idx), addr);
+ had_write_register(intelhaddata, AUD_BUF_LEN(idx),
+ intelhaddata->period_bytes);
+
+ /* advance the indices to the next */
+ intelhaddata->bd_head++;
+ intelhaddata->bd_head %= intelhaddata->num_bds;
+ intelhaddata->pcmbuf_filled++;
+ intelhaddata->pcmbuf_filled %= substream->runtime->periods;
+}
+
+/* invalidate a buffer descriptor with the given index */
+static void had_invalidate_bd(struct snd_intelhad *intelhaddata,
+ int idx)
+{
+ had_write_register(intelhaddata, AUD_BUF_ADDR(idx), 0);
+ had_write_register(intelhaddata, AUD_BUF_LEN(idx), 0);
+}
+
+/* Initial programming of ring buffer */
+static void had_init_ringbuf(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int i, num_periods;
+
+ num_periods = runtime->periods;
+ intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS);
+ /* set the minimum 2 BDs for num_periods=1 */
+ intelhaddata->num_bds = max(intelhaddata->num_bds, 2U);
+ intelhaddata->period_bytes =
+ frames_to_bytes(runtime, runtime->period_size);
+ WARN_ON(intelhaddata->period_bytes & 0x3f);
+
+ intelhaddata->bd_head = 0;
+ intelhaddata->pcmbuf_head = 0;
+ intelhaddata->pcmbuf_filled = 0;
+
+ for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) {
+ if (i < intelhaddata->num_bds)
+ had_prog_bd(substream, intelhaddata);
+ else /* invalidate the rest */
+ had_invalidate_bd(intelhaddata, i);
+ }
+
+ intelhaddata->bd_head = 0; /* reset at head again before starting */
+}
+
+/* process a bd, advance to the next */
+static void had_advance_ringbuf(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ int num_periods = substream->runtime->periods;
+
+ /* reprogram the next buffer */
+ had_prog_bd(substream, intelhaddata);
+
+ /* proceed to next */
+ intelhaddata->pcmbuf_head++;
+ intelhaddata->pcmbuf_head %= num_periods;
+}
+
+/* process the current BD(s);
+ * returns the current PCM buffer byte position, or -EPIPE for underrun.
+ */
+static int had_process_ringbuf(struct snd_pcm_substream *substream,
+ struct snd_intelhad *intelhaddata)
+{
+ int len, processed;
+ unsigned long flags;
+
+ processed = 0;
+ spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+ for (;;) {
+ /* get the remaining bytes on the buffer */
+ had_read_register(intelhaddata,
+ AUD_BUF_LEN(intelhaddata->bd_head),
+ &len);
+ if (len < 0 || len > intelhaddata->period_bytes) {
+ dev_dbg(intelhaddata->dev, "Invalid buf length %d\n",
+ len);
+ len = -EPIPE;
+ goto out;
+ }
+
+ if (len > 0) /* OK, this is the current buffer */
+ break;
+
+ /* len=0 => already empty, check the next buffer */
+ if (++processed >= intelhaddata->num_bds) {
+ len = -EPIPE; /* all empty? - report underrun */
+ goto out;
+ }
+ had_advance_ringbuf(substream, intelhaddata);
+ }
+
+ len = intelhaddata->period_bytes - len;
+ len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head;
+ out:
+ spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+ return len;
+}
+
+/* called from irq handler */
+static void had_process_buffer_done(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+
+ substream = had_substream_get(intelhaddata);
+ if (!substream)
+ return; /* no stream? - bail out */
+
+ if (!intelhaddata->connected) {
+ snd_pcm_stop_xrun(substream);
+ goto out; /* disconnected? - bail out */
+ }
+
+ /* process or stop the stream */
+ if (had_process_ringbuf(substream, intelhaddata) < 0)
+ snd_pcm_stop_xrun(substream);
+ else
+ snd_pcm_period_elapsed(substream);
+
+ out:
+ had_substream_put(intelhaddata);
+}
+
+/*
+ * The interrupt status 'sticky' bits might not be cleared by
+ * setting '1' to that bit once...
+ */
+static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < 100; i++) {
+ /* clear bit30, 31 AUD_HDMI_STATUS */
+ had_read_register(intelhaddata, AUD_HDMI_STATUS, &val);
+ if (!(val & AUD_HDMI_STATUS_MASK_UNDERRUN))
+ return;
+ udelay(100);
+ cond_resched();
+ had_write_register(intelhaddata, AUD_HDMI_STATUS, val);
+ }
+ dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n");
+}
+
+/* Perform some reset procedure but only when need_reset is set;
+ * this is called from prepare or hw_free callbacks once after trigger STOP
+ * or underrun has been processed in order to settle down the h/w state.
+ */
+static void had_do_reset(struct snd_intelhad *intelhaddata)
+{
+ if (!intelhaddata->need_reset || !intelhaddata->connected)
+ return;
+
+ /* Reset buffer pointers */
+ had_reset_audio(intelhaddata);
+ wait_clear_underrun_bit(intelhaddata);
+ intelhaddata->need_reset = false;
+}
+
+/* called from irq handler */
+static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+
+ /* Report UNDERRUN error to above layers */
+ substream = had_substream_get(intelhaddata);
+ if (substream) {
+ snd_pcm_stop_xrun(substream);
+ had_substream_put(intelhaddata);
+ }
+ intelhaddata->need_reset = true;
+}
+
+/*
+ * ALSA PCM open callback
+ */
+static int had_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_intelhad *intelhaddata;
+ struct snd_pcm_runtime *runtime;
+ int retval;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+ runtime = substream->runtime;
+
+ pm_runtime_get_sync(intelhaddata->dev);
+
+ /* set the runtime hw parameter with local snd_pcm_hardware struct */
+ runtime->hw = had_pcm_hardware;
+
+ retval = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (retval < 0)
+ goto error;
+
+ /* Make sure, that the period size is always aligned
+ * 64byte boundary
+ */
+ retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+ if (retval < 0)
+ goto error;
+
+ retval = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+ if (retval < 0)
+ goto error;
+
+ /* expose PCM substream */
+ spin_lock_irq(&intelhaddata->had_spinlock);
+ intelhaddata->stream_info.substream = substream;
+ intelhaddata->stream_info.substream_refcount++;
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+
+ return retval;
+ error:
+ pm_runtime_mark_last_busy(intelhaddata->dev);
+ pm_runtime_put_autosuspend(intelhaddata->dev);
+ return retval;
+}
+
+/*
+ * ALSA PCM close callback
+ */
+static int had_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_intelhad *intelhaddata;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+
+ /* unreference and sync with the pending PCM accesses */
+ spin_lock_irq(&intelhaddata->had_spinlock);
+ intelhaddata->stream_info.substream = NULL;
+ intelhaddata->stream_info.substream_refcount--;
+ while (intelhaddata->stream_info.substream_refcount > 0) {
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+ cpu_relax();
+ spin_lock_irq(&intelhaddata->had_spinlock);
+ }
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+
+ pm_runtime_mark_last_busy(intelhaddata->dev);
+ pm_runtime_put_autosuspend(intelhaddata->dev);
+ return 0;
+}
+
+/*
+ * ALSA PCM hw_params callback
+ */
+static int had_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_intelhad *intelhaddata;
+ unsigned long addr;
+ int pages, buf_size, retval;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+ buf_size = params_buffer_bytes(hw_params);
+ retval = snd_pcm_lib_malloc_pages(substream, buf_size);
+ if (retval < 0)
+ return retval;
+ dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
+ __func__, buf_size);
+ /* mark the pages as uncached region */
+ addr = (unsigned long) substream->runtime->dma_area;
+ pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ retval = set_memory_uc(addr, pages);
+ if (retval) {
+ dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
+ retval);
+ return retval;
+ }
+ memset(substream->runtime->dma_area, 0, buf_size);
+
+ return retval;
+}
+
+/*
+ * ALSA PCM hw_free callback
+ */
+static int had_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_intelhad *intelhaddata;
+ unsigned long addr;
+ u32 pages;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+ had_do_reset(intelhaddata);
+
+ /* mark back the pages as cached/writeback region before the free */
+ if (substream->runtime->dma_area != NULL) {
+ addr = (unsigned long) substream->runtime->dma_area;
+ pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
+ PAGE_SIZE;
+ set_memory_wb(addr, pages);
+ return snd_pcm_lib_free_pages(substream);
+ }
+ return 0;
+}
+
+/*
+ * ALSA PCM trigger callback
+ */
+static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int retval = 0;
+ struct snd_intelhad *intelhaddata;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+
+ spin_lock(&intelhaddata->had_spinlock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ /* Enable Audio */
+ had_ack_irqs(intelhaddata); /* FIXME: do we need this? */
+ had_enable_audio(intelhaddata, true);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ /* Disable Audio */
+ had_enable_audio(intelhaddata, false);
+ intelhaddata->need_reset = true;
+ break;
+
+ default:
+ retval = -EINVAL;
+ }
+ spin_unlock(&intelhaddata->had_spinlock);
+ return retval;
+}
+
+/*
+ * ALSA PCM prepare callback
+ */
+static int had_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int retval;
+ u32 disp_samp_freq, n_param;
+ u32 link_rate = 0;
+ struct snd_intelhad *intelhaddata;
+ struct snd_pcm_runtime *runtime;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+ runtime = substream->runtime;
+
+ dev_dbg(intelhaddata->dev, "period_size=%d\n",
+ (int)frames_to_bytes(runtime, runtime->period_size));
+ dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods);
+ dev_dbg(intelhaddata->dev, "buffer_size=%d\n",
+ (int)snd_pcm_lib_buffer_bytes(substream));
+ dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate);
+ dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels);
+
+ had_do_reset(intelhaddata);
+
+ /* Get N value in KHz */
+ disp_samp_freq = intelhaddata->tmds_clock_speed;
+
+ retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
+ if (retval) {
+ dev_err(intelhaddata->dev,
+ "programming N value failed %#x\n", retval);
+ goto prep_end;
+ }
+
+ if (intelhaddata->dp_output)
+ link_rate = intelhaddata->link_rate;
+
+ had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
+ n_param, intelhaddata);
+
+ had_prog_dip(substream, intelhaddata);
+
+ retval = had_init_audio_ctrl(substream, intelhaddata);
+
+ /* Prog buffer address */
+ had_init_ringbuf(substream, intelhaddata);
+
+ /*
+ * Program channel mapping in following order:
+ * FL, FR, C, LFE, RL, RR
+ */
+
+ had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
+
+prep_end:
+ return retval;
+}
+
+/*
+ * ALSA PCM pointer callback
+ */
+static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_intelhad *intelhaddata;
+ int len;
+
+ intelhaddata = snd_pcm_substream_chip(substream);
+
+ if (!intelhaddata->connected)
+ return SNDRV_PCM_POS_XRUN;
+
+ len = had_process_ringbuf(substream, intelhaddata);
+ if (len < 0)
+ return SNDRV_PCM_POS_XRUN;
+ len = bytes_to_frames(substream->runtime, len);
+ /* wrapping may happen when periods=1 */
+ len %= substream->runtime->buffer_size;
+ return len;
+}
+
+/*
+ * ALSA PCM mmap callback
+ */
+static int had_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ return remap_pfn_range(vma, vma->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+/*
+ * ALSA PCM ops
+ */
+static const struct snd_pcm_ops had_pcm_ops = {
+ .open = had_pcm_open,
+ .close = had_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = had_pcm_hw_params,
+ .hw_free = had_pcm_hw_free,
+ .prepare = had_pcm_prepare,
+ .trigger = had_pcm_trigger,
+ .pointer = had_pcm_pointer,
+ .mmap = had_pcm_mmap,
+};
+
+/* process mode change of the running stream; called in mutex */
+static int had_process_mode_change(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+ int retval = 0;
+ u32 disp_samp_freq, n_param;
+ u32 link_rate = 0;
+
+ substream = had_substream_get(intelhaddata);
+ if (!substream)
+ return 0;
+
+ /* Disable Audio */
+ had_enable_audio(intelhaddata, false);
+
+ /* Update CTS value */
+ disp_samp_freq = intelhaddata->tmds_clock_speed;
+
+ retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
+ if (retval) {
+ dev_err(intelhaddata->dev,
+ "programming N value failed %#x\n", retval);
+ goto out;
+ }
+
+ if (intelhaddata->dp_output)
+ link_rate = intelhaddata->link_rate;
+
+ had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
+ n_param, intelhaddata);
+
+ /* Enable Audio */
+ had_enable_audio(intelhaddata, true);
+
+out:
+ had_substream_put(intelhaddata);
+ return retval;
+}
+
+/* process hot plug, called from wq with mutex locked */
+static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+
+ spin_lock_irq(&intelhaddata->had_spinlock);
+ if (intelhaddata->connected) {
+ dev_dbg(intelhaddata->dev, "Device already connected\n");
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+ return;
+ }
+
+ intelhaddata->connected = true;
+ dev_dbg(intelhaddata->dev,
+ "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
+ __func__, __LINE__);
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+
+ had_build_channel_allocation_map(intelhaddata);
+
+ /* Report to above ALSA layer */
+ substream = had_substream_get(intelhaddata);
+ if (substream) {
+ snd_pcm_stop_xrun(substream);
+ had_substream_put(intelhaddata);
+ }
+
+ snd_jack_report(intelhaddata->jack, SND_JACK_AVOUT);
+}
+
+/* process hot unplug, called from wq with mutex locked */
+static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
+{
+ struct snd_pcm_substream *substream;
+
+ spin_lock_irq(&intelhaddata->had_spinlock);
+ if (!intelhaddata->connected) {
+ dev_dbg(intelhaddata->dev, "Device already disconnected\n");
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+ return;
+
+ }
+
+ /* Disable Audio */
+ had_enable_audio(intelhaddata, false);
+
+ intelhaddata->connected = false;
+ dev_dbg(intelhaddata->dev,
+ "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n",
+ __func__, __LINE__);
+ spin_unlock_irq(&intelhaddata->had_spinlock);
+
+ kfree(intelhaddata->chmap->chmap);
+ intelhaddata->chmap->chmap = NULL;
+
+ /* Report to above ALSA layer */
+ substream = had_substream_get(intelhaddata);
+ if (substream) {
+ snd_pcm_stop_xrun(substream);
+ had_substream_put(intelhaddata);
+ }
+
+ snd_jack_report(intelhaddata->jack, 0);
+}
+
+/*
+ * ALSA iec958 and ELD controls
+ */
+
+static int had_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int had_iec958_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&intelhaddata->mutex);
+ ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
+ ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
+ ucontrol->value.iec958.status[2] =
+ (intelhaddata->aes_bits >> 16) & 0xff;
+ ucontrol->value.iec958.status[3] =
+ (intelhaddata->aes_bits >> 24) & 0xff;
+ mutex_unlock(&intelhaddata->mutex);
+ return 0;
+}
+
+static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.iec958.status[0] = 0xff;
+ ucontrol->value.iec958.status[1] = 0xff;
+ ucontrol->value.iec958.status[2] = 0xff;
+ ucontrol->value.iec958.status[3] = 0xff;
+ return 0;
+}
+
+static int had_iec958_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned int val;
+ struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+ val = (ucontrol->value.iec958.status[0] << 0) |
+ (ucontrol->value.iec958.status[1] << 8) |
+ (ucontrol->value.iec958.status[2] << 16) |
+ (ucontrol->value.iec958.status[3] << 24);
+ mutex_lock(&intelhaddata->mutex);
+ if (intelhaddata->aes_bits != val) {
+ intelhaddata->aes_bits = val;
+ changed = 1;
+ }
+ mutex_unlock(&intelhaddata->mutex);
+ return changed;
+}
+
+static int had_ctl_eld_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = HDMI_MAX_ELD_BYTES;
+ return 0;
+}
+
+static int had_ctl_eld_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&intelhaddata->mutex);
+ memcpy(ucontrol->value.bytes.data, intelhaddata->eld,
+ HDMI_MAX_ELD_BYTES);
+ mutex_unlock(&intelhaddata->mutex);
+ return 0;
+}
+
+static const struct snd_kcontrol_new had_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+ .info = had_iec958_info, /* shared */
+ .get = had_iec958_mask_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = had_iec958_info,
+ .get = had_iec958_get,
+ .put = had_iec958_put,
+ },
+ {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "ELD",
+ .info = had_ctl_eld_info,
+ .get = had_ctl_eld_get,
+ },
+};
+
+/*
+ * audio interrupt handler
+ */
+static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
+{
+ struct snd_intelhad *ctx = dev_id;
+ u32 audio_stat;
+
+ /* use raw register access to ack IRQs even while disconnected */
+ audio_stat = had_read_register_raw(ctx, AUD_HDMI_STATUS);
+
+ if (audio_stat & HDMI_AUDIO_UNDERRUN) {
+ had_write_register_raw(ctx, AUD_HDMI_STATUS,
+ HDMI_AUDIO_UNDERRUN);
+ had_process_buffer_underrun(ctx);
+ }
+
+ if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
+ had_write_register_raw(ctx, AUD_HDMI_STATUS,
+ HDMI_AUDIO_BUFFER_DONE);
+ had_process_buffer_done(ctx);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * monitor plug/unplug notification from i915; just kick off the work
+ */
+static void notify_audio_lpe(struct platform_device *pdev)
+{
+ struct snd_intelhad *ctx = platform_get_drvdata(pdev);
+
+ schedule_work(&ctx->hdmi_audio_wq);
+}
+
+/* the work to handle monitor hot plug/unplug */
+static void had_audio_wq(struct work_struct *work)
+{
+ struct snd_intelhad *ctx =
+ container_of(work, struct snd_intelhad, hdmi_audio_wq);
+ struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
+
+ pm_runtime_get_sync(ctx->dev);
+ mutex_lock(&ctx->mutex);
+ if (!pdata->hdmi_connected) {
+ dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
+ __func__);
+ memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
+ had_process_hot_unplug(ctx);
+ } else {
+ struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
+
+ dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
+ __func__, eld->port_id, pdata->tmds_clock_speed);
+
+ switch (eld->pipe_id) {
+ case 0:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+ break;
+ case 1:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
+ break;
+ case 2:
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
+ break;
+ default:
+ dev_dbg(ctx->dev, "Invalid pipe %d\n",
+ eld->pipe_id);
+ break;
+ }
+
+ memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld));
+
+ ctx->dp_output = pdata->dp_output;
+ ctx->tmds_clock_speed = pdata->tmds_clock_speed;
+ ctx->link_rate = pdata->link_rate;
+
+ had_process_hot_plug(ctx);
+
+ /* Process mode change if stream is active */
+ had_process_mode_change(ctx);
+ }
+ mutex_unlock(&ctx->mutex);
+ pm_runtime_mark_last_busy(ctx->dev);
+ pm_runtime_put_autosuspend(ctx->dev);
+}
+
+/*
+ * Jack interface
+ */
+static int had_create_jack(struct snd_intelhad *ctx)
+{
+ int err;
+
+ err = snd_jack_new(ctx->card, "HDMI/DP", SND_JACK_AVOUT, &ctx->jack,
+ true, false);
+ if (err < 0)
+ return err;
+ ctx->jack->private_data = ctx;
+ return 0;
+}
+
+/*
+ * PM callbacks
+ */
+
+static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
+{
+ struct snd_intelhad *ctx = dev_get_drvdata(dev);
+ struct snd_pcm_substream *substream;
+
+ substream = had_substream_get(ctx);
+ if (substream) {
+ snd_pcm_suspend(substream);
+ had_substream_put(ctx);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
+{
+ struct snd_intelhad *ctx = dev_get_drvdata(dev);
+ int err;
+
+ err = hdmi_lpe_audio_runtime_suspend(dev);
+ if (!err)
+ snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot);
+ return err;
+}
+
+static int hdmi_lpe_audio_runtime_resume(struct device *dev)
+{
+ pm_runtime_mark_last_busy(dev);
+ return 0;
+}
+
+static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev)
+{
+ struct snd_intelhad *ctx = dev_get_drvdata(dev);
+
+ hdmi_lpe_audio_runtime_resume(dev);
+ snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+
+/* release resources */
+static void hdmi_lpe_audio_free(struct snd_card *card)
+{
+ struct snd_intelhad *ctx = card->private_data;
+
+ cancel_work_sync(&ctx->hdmi_audio_wq);
+
+ if (ctx->mmio_start)
+ iounmap(ctx->mmio_start);
+ if (ctx->irq >= 0)
+ free_irq(ctx->irq, ctx);
+}
+
+/*
+ * hdmi_lpe_audio_probe - start bridge with i915
+ *
+ * This function is called when the i915 driver creates the
+ * hdmi-lpe-audio platform device.
+ */
+static int hdmi_lpe_audio_probe(struct platform_device *pdev)
+{
+ struct snd_card *card;
+ struct snd_intelhad *ctx;
+ struct snd_pcm *pcm;
+ struct intel_hdmi_lpe_audio_pdata *pdata;
+ int irq;
+ struct resource *res_mmio;
+ int i, ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* get resources */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Could not get irq resource\n");
+ return -ENODEV;
+ }
+
+ res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mmio) {
+ dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
+ return -ENXIO;
+ }
+
+ /* create a card instance with ALSA framework */
+ ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id,
+ THIS_MODULE, sizeof(*ctx), &card);
+ if (ret)
+ return ret;
+
+ ctx = card->private_data;
+ spin_lock_init(&ctx->had_spinlock);
+ mutex_init(&ctx->mutex);
+ ctx->connected = false;
+ ctx->dev = &pdev->dev;
+ ctx->card = card;
+ ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
+ strcpy(card->driver, INTEL_HAD);
+ strcpy(card->shortname, "Intel HDMI/DP LPE Audio");
+ strcpy(card->longname, "Intel HDMI/DP LPE Audio");
+
+ ctx->irq = -1;
+ ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
+ INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
+
+ card->private_free = hdmi_lpe_audio_free;
+
+ /* assume pipe A as default */
+ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+
+ platform_set_drvdata(pdev, ctx);
+
+ dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
+ __func__, (unsigned int)res_mmio->start,
+ (unsigned int)res_mmio->end);
+
+ ctx->mmio_start = ioremap_nocache(res_mmio->start,
+ (size_t)(resource_size(res_mmio)));
+ if (!ctx->mmio_start) {
+ dev_err(&pdev->dev, "Could not get ioremap\n");
+ ret = -EACCES;
+ goto err;
+ }
+
+ /* setup interrupt handler */
+ ret = request_irq(irq, display_pipe_interrupt_handler, 0,
+ pdev->name, ctx);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto err;
+ }
+
+ ctx->irq = irq;
+
+ ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
+ MAX_CAP_STREAMS, &pcm);
+ if (ret)
+ goto err;
+
+ /* setup private data which can be retrieved when required */
+ pcm->private_data = ctx;
+ pcm->info_flags = 0;
+ strncpy(pcm->name, card->shortname, strlen(card->shortname));
+ /* setup the ops for playabck */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
+
+ /* only 32bit addressable */
+ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+ /* allocate dma pages;
+ * try to allocate 600k buffer as default which is large enough
+ */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV, NULL,
+ HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER);
+
+ /* create controls */
+ for (i = 0; i < ARRAY_SIZE(had_controls); i++) {
+ ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx));
+ if (ret < 0)
+ goto err;
+ }
+
+ init_channel_allocations();
+
+ /* Register channel map controls */
+ ret = had_register_chmap_ctls(ctx, pcm);
+ if (ret < 0)
+ goto err;
+
+ ret = had_create_jack(ctx);
+ if (ret < 0)
+ goto err;
+
+ ret = snd_card_register(card);
+ if (ret)
+ goto err;
+
+ spin_lock_irq(&pdata->lpe_audio_slock);
+ pdata->notify_audio_lpe = notify_audio_lpe;
+ pdata->notify_pending = false;
+ spin_unlock_irq(&pdata->lpe_audio_slock);
+
+ /* runtime PM isn't enabled as default, since it won't save much on
+ * BYT/CHT devices; user who want the runtime PM should adjust the
+ * power/ontrol and power/autosuspend_delay_ms sysfs entries instead
+ */
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+
+ dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
+ schedule_work(&ctx->hdmi_audio_wq);
+
+ return 0;
+
+err:
+ snd_card_free(card);
+ return ret;
+}
+
+/*
+ * hdmi_lpe_audio_remove - stop bridge with i915
+ *
+ * This function is called when the platform device is destroyed.
+ */
+static int hdmi_lpe_audio_remove(struct platform_device *pdev)
+{
+ struct snd_intelhad *ctx = platform_get_drvdata(pdev);
+
+ snd_card_free(ctx->card);
+ return 0;
+}
+
+static const struct dev_pm_ops hdmi_lpe_audio_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
+ SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend,
+ hdmi_lpe_audio_runtime_resume, NULL)
+};
+
+static struct platform_driver hdmi_lpe_audio_driver = {
+ .driver = {
+ .name = "hdmi-lpe-audio",
+ .pm = &hdmi_lpe_audio_pm,
+ },
+ .probe = hdmi_lpe_audio_probe,
+ .remove = hdmi_lpe_audio_remove,
+};
+
+module_platform_driver(hdmi_lpe_audio_driver);
+MODULE_ALIAS("platform:hdmi_lpe_audio");
+
+MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
+MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
+MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
+MODULE_AUTHOR("Jerome Anand <jerome.anand@intel.com>");
+MODULE_DESCRIPTION("Intel HDMI Audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
new file mode 100644
index 000000000000..2d3e389f76b3
--- /dev/null
+++ b/sound/x86/intel_hdmi_audio.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 Intel Corporation
+ * Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ * Ramesh Babu K V <ramesh.babu@intel.com>
+ * Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ * Jerome Anand <jerome.anand@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _INTEL_HDMI_AUDIO_H_
+#define _INTEL_HDMI_AUDIO_H_
+
+#include "intel_hdmi_lpe_audio.h"
+
+#define PCM_INDEX 0
+#define MAX_PB_STREAMS 1
+#define MAX_CAP_STREAMS 0
+#define BYTES_PER_WORD 0x4
+#define INTEL_HAD "HdmiLpeAudio"
+
+/*
+ * CEA speaker placement:
+ *
+ * FL FLC FC FRC FR
+ *
+ * LFE
+ *
+ * RL RLC RC RRC RR
+ *
+ * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M
+ * corresponds to CEA RL/RR; The SMPTE channel _assignment_ C/LFE is
+ * swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+ FL = (1 << 0), /* Front Left */
+ FC = (1 << 1), /* Front Center */
+ FR = (1 << 2), /* Front Right */
+ FLC = (1 << 3), /* Front Left Center */
+ FRC = (1 << 4), /* Front Right Center */
+ RL = (1 << 5), /* Rear Left */
+ RC = (1 << 6), /* Rear Center */
+ RR = (1 << 7), /* Rear Right */
+ RLC = (1 << 8), /* Rear Left Center */
+ RRC = (1 << 9), /* Rear Right Center */
+ LFE = (1 << 10), /* Low Frequency Effect */
+};
+
+struct cea_channel_speaker_allocation {
+ int ca_index;
+ int speakers[8];
+
+ /* derived values, just for convenience */
+ int channels;
+ int spk_mask;
+};
+
+struct channel_map_table {
+ unsigned char map; /* ALSA API channel map position */
+ unsigned char cea_slot; /* CEA slot value */
+ int spk_mask; /* speaker position bit mask */
+};
+
+struct pcm_stream_info {
+ struct snd_pcm_substream *substream;
+ int substream_refcount;
+};
+
+/*
+ * struct snd_intelhad - intelhad driver structure
+ *
+ * @card: ptr to hold card details
+ * @connected: the monitor connection status
+ * @stream_info: stream information
+ * @eld: holds ELD info
+ * @curr_buf: pointer to hold current active ring buf
+ * @valid_buf_cnt: ring buffer count for stream
+ * @had_spinlock: driver lock
+ * @aes_bits: IEC958 status bits
+ * @buff_done: id of current buffer done intr
+ * @dev: platoform device handle
+ * @chmap: holds channel map info
+ */
+struct snd_intelhad {
+ struct snd_card *card;
+ bool connected;
+ struct pcm_stream_info stream_info;
+ unsigned char eld[HDMI_MAX_ELD_BYTES];
+ bool dp_output;
+ unsigned int aes_bits;
+ spinlock_t had_spinlock;
+ struct device *dev;
+ struct snd_pcm_chmap *chmap;
+ int tmds_clock_speed;
+ int link_rate;
+
+ /* ring buffer (BD) position index */
+ unsigned int bd_head;
+ /* PCM buffer position indices */
+ unsigned int pcmbuf_head; /* being processed */
+ unsigned int pcmbuf_filled; /* to be filled */
+
+ unsigned int num_bds; /* number of BDs */
+ unsigned int period_bytes; /* PCM period size in bytes */
+
+ /* internal stuff */
+ int irq;
+ void __iomem *mmio_start;
+ unsigned int had_config_offset;
+ union aud_cfg aud_config; /* AUD_CONFIG reg value cache */
+ struct work_struct hdmi_audio_wq;
+ struct mutex mutex; /* for protecting chmap and eld */
+ bool need_reset;
+ struct snd_jack *jack;
+};
+
+#endif /* _INTEL_HDMI_AUDIO_ */
diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h
new file mode 100644
index 000000000000..477e5153307c
--- /dev/null
+++ b/sound/x86/intel_hdmi_lpe_audio.h
@@ -0,0 +1,328 @@
+/*
+ * intel_hdmi_lpe_audio.h - Intel HDMI LPE audio driver
+ *
+ * Copyright (C) 2016 Intel Corp
+ * Authors: Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ * Ramesh Babu K V <ramesh.babu@intel.com>
+ * Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ * Jerome Anand <jerome.anand@intel.com>
+ * Aravind Siddappaji <aravindx.siddappaji@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __INTEL_HDMI_LPE_AUDIO_H
+#define __INTEL_HDMI_LPE_AUDIO_H
+
+#define HAD_MIN_CHANNEL 2
+#define HAD_MAX_CHANNEL 8
+#define HAD_NUM_OF_RING_BUFS 4
+
+/* max 20bit address, aligned to 64 */
+#define HAD_MAX_BUFFER ((1024 * 1024 - 1) & ~0x3f)
+#define HAD_DEFAULT_BUFFER (600 * 1024) /* default prealloc size */
+#define HAD_MAX_PERIODS 256 /* arbitrary, but should suffice */
+#define HAD_MIN_PERIODS 1
+#define HAD_MAX_PERIOD_BYTES ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f)
+#define HAD_MIN_PERIOD_BYTES 1024 /* might be smaller */
+#define HAD_FIFO_SIZE 0 /* fifo not being used */
+#define MAX_SPEAKERS 8
+
+#define AUD_SAMPLE_RATE_32 32000
+#define AUD_SAMPLE_RATE_44_1 44100
+#define AUD_SAMPLE_RATE_48 48000
+#define AUD_SAMPLE_RATE_88_2 88200
+#define AUD_SAMPLE_RATE_96 96000
+#define AUD_SAMPLE_RATE_176_4 176400
+#define AUD_SAMPLE_RATE_192 192000
+
+#define HAD_MIN_RATE AUD_SAMPLE_RATE_32
+#define HAD_MAX_RATE AUD_SAMPLE_RATE_192
+
+#define DIS_SAMPLE_RATE_25_2 25200
+#define DIS_SAMPLE_RATE_27 27000
+#define DIS_SAMPLE_RATE_54 54000
+#define DIS_SAMPLE_RATE_74_25 74250
+#define DIS_SAMPLE_RATE_148_5 148500
+#define HAD_REG_WIDTH 0x08
+#define HAD_MAX_DIP_WORDS 16
+
+/* DP Link Rates */
+#define DP_2_7_GHZ 270000
+#define DP_1_62_GHZ 162000
+
+/* Maud Values */
+#define AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL 1988
+#define AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL 2740
+#define AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL 2982
+#define AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL 5480
+#define AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL 5965
+#define AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL 10961
+#define HAD_MAX_RATE_DP_2_7_MAUD_VAL 11930
+#define AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL 3314
+#define AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL 4567
+#define AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL 4971
+#define AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL 9134
+#define AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL 9942
+#define AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL 18268
+#define HAD_MAX_RATE_DP_1_62_MAUD_VAL 19884
+
+/* Naud Value */
+#define DP_NAUD_VAL 32768
+
+/* HDMI Controller register offsets - audio domain common */
+/* Base address for below regs = 0x65000 */
+enum hdmi_ctrl_reg_offset_common {
+ AUDIO_HDMI_CONFIG_A = 0x000,
+ AUDIO_HDMI_CONFIG_B = 0x800,
+ AUDIO_HDMI_CONFIG_C = 0x900,
+};
+/* HDMI controller register offsets */
+enum hdmi_ctrl_reg_offset {
+ AUD_CONFIG = 0x0,
+ AUD_CH_STATUS_0 = 0x08,
+ AUD_CH_STATUS_1 = 0x0C,
+ AUD_HDMI_CTS = 0x10,
+ AUD_N_ENABLE = 0x14,
+ AUD_SAMPLE_RATE = 0x18,
+ AUD_BUF_CONFIG = 0x20,
+ AUD_BUF_CH_SWAP = 0x24,
+ AUD_BUF_A_ADDR = 0x40,
+ AUD_BUF_A_LENGTH = 0x44,
+ AUD_BUF_B_ADDR = 0x48,
+ AUD_BUF_B_LENGTH = 0x4c,
+ AUD_BUF_C_ADDR = 0x50,
+ AUD_BUF_C_LENGTH = 0x54,
+ AUD_BUF_D_ADDR = 0x58,
+ AUD_BUF_D_LENGTH = 0x5c,
+ AUD_CNTL_ST = 0x60,
+ AUD_HDMI_STATUS = 0x64, /* v2 */
+ AUD_HDMIW_INFOFR = 0x68, /* v2 */
+};
+
+/* Audio configuration */
+union aud_cfg {
+ struct {
+ u32 aud_en:1;
+ u32 layout:1; /* LAYOUT[01], see below */
+ u32 fmt:2;
+ u32 num_ch:3;
+ u32 set:1;
+ u32 flat:1;
+ u32 val_bit:1;
+ u32 user_bit:1;
+ u32 underrun:1; /* 0: send null packets,
+ * 1: send silence stream
+ */
+ u32 packet_mode:1; /* 0: 32bit container, 1: 16bit */
+ u32 left_align:1; /* 0: MSB bits 0-23, 1: bits 8-31 */
+ u32 bogus_sample:1; /* bogus sample for odd channels */
+ u32 dp_modei:1; /* 0: HDMI, 1: DP */
+ u32 rsvd:16;
+ } regx;
+ u32 regval;
+};
+
+#define AUD_CONFIG_VALID_BIT (1 << 9)
+#define AUD_CONFIG_DP_MODE (1 << 15)
+#define AUD_CONFIG_CH_MASK 0x70
+#define LAYOUT0 0 /* interleaved stereo */
+#define LAYOUT1 1 /* for channels > 2 */
+
+/* Audio Channel Status 0 Attributes */
+union aud_ch_status_0 {
+ struct {
+ u32 ch_status:1;
+ u32 lpcm_id:1;
+ u32 cp_info:1;
+ u32 format:3;
+ u32 mode:2;
+ u32 ctg_code:8;
+ u32 src_num:4;
+ u32 ch_num:4;
+ u32 samp_freq:4; /* CH_STATUS_MAP_XXX */
+ u32 clk_acc:2;
+ u32 rsvd:2;
+ } regx;
+ u32 regval;
+};
+
+/* samp_freq values - Sampling rate as per IEC60958 Ver 3 */
+#define CH_STATUS_MAP_32KHZ 0x3
+#define CH_STATUS_MAP_44KHZ 0x0
+#define CH_STATUS_MAP_48KHZ 0x2
+#define CH_STATUS_MAP_88KHZ 0x8
+#define CH_STATUS_MAP_96KHZ 0xA
+#define CH_STATUS_MAP_176KHZ 0xC
+#define CH_STATUS_MAP_192KHZ 0xE
+
+/* Audio Channel Status 1 Attributes */
+union aud_ch_status_1 {
+ struct {
+ u32 max_wrd_len:1;
+ u32 wrd_len:3;
+ u32 rsvd:28;
+ } regx;
+ u32 regval;
+};
+
+#define MAX_SMPL_WIDTH_20 0x0
+#define MAX_SMPL_WIDTH_24 0x1
+#define SMPL_WIDTH_16BITS 0x1
+#define SMPL_WIDTH_24BITS 0x5
+
+/* CTS register */
+union aud_hdmi_cts {
+ struct {
+ u32 cts_val:24;
+ u32 en_cts_prog:1;
+ u32 rsvd:7;
+ } regx;
+ u32 regval;
+};
+
+/* N register */
+union aud_hdmi_n_enable {
+ struct {
+ u32 n_val:24;
+ u32 en_n_prog:1;
+ u32 rsvd:7;
+ } regx;
+ u32 regval;
+};
+
+/* Audio Buffer configurations */
+union aud_buf_config {
+ struct {
+ u32 audio_fifo_watermark:8;
+ u32 dma_fifo_watermark:3;
+ u32 rsvd0:5;
+ u32 aud_delay:8;
+ u32 rsvd1:8;
+ } regx;
+ u32 regval;
+};
+
+#define FIFO_THRESHOLD 0xFE
+#define DMA_FIFO_THRESHOLD 0x7
+
+/* Audio Sample Swapping offset */
+union aud_buf_ch_swap {
+ struct {
+ u32 first_0:3;
+ u32 second_0:3;
+ u32 first_1:3;
+ u32 second_1:3;
+ u32 first_2:3;
+ u32 second_2:3;
+ u32 first_3:3;
+ u32 second_3:3;
+ u32 rsvd:8;
+ } regx;
+ u32 regval;
+};
+
+#define SWAP_LFE_CENTER 0x00fac4c8 /* octal 76543210 */
+
+/* Address for Audio Buffer */
+union aud_buf_addr {
+ struct {
+ u32 valid:1;
+ u32 intr_en:1;
+ u32 rsvd:4;
+ u32 addr:26;
+ } regx;
+ u32 regval;
+};
+
+#define AUD_BUF_VALID (1U << 0)
+#define AUD_BUF_INTR_EN (1U << 1)
+
+/* Length of Audio Buffer */
+union aud_buf_len {
+ struct {
+ u32 buf_len:20;
+ u32 rsvd:12;
+ } regx;
+ u32 regval;
+};
+
+/* Audio Control State Register offset */
+union aud_ctrl_st {
+ struct {
+ u32 ram_addr:4;
+ u32 eld_ack:1;
+ u32 eld_addr:4;
+ u32 eld_buf_size:5;
+ u32 eld_valid:1;
+ u32 cp_ready:1;
+ u32 dip_freq:2;
+ u32 dip_idx:3;
+ u32 dip_en_sta:4;
+ u32 rsvd:7;
+ } regx;
+ u32 regval;
+};
+
+/* Audio HDMI Widget Data Island Packet offset */
+union aud_info_frame1 {
+ struct {
+ u32 pkt_type:8;
+ u32 ver_num:8;
+ u32 len:5;
+ u32 rsvd:11;
+ } regx;
+ u32 regval;
+};
+
+#define HDMI_INFO_FRAME_WORD1 0x000a0184
+#define DP_INFO_FRAME_WORD1 0x00441b84
+
+/* DIP frame 2 */
+union aud_info_frame2 {
+ struct {
+ u32 chksum:8;
+ u32 chnl_cnt:3;
+ u32 rsvd0:1;
+ u32 coding_type:4;
+ u32 smpl_size:2;
+ u32 smpl_freq:3;
+ u32 rsvd1:3;
+ u32 format:8;
+ } regx;
+ u32 regval;
+};
+
+/* DIP frame 3 */
+union aud_info_frame3 {
+ struct {
+ u32 chnl_alloc:8;
+ u32 rsvd0:3;
+ u32 lsv:4;
+ u32 dm_inh:1;
+ u32 rsvd1:16;
+ } regx;
+ u32 regval;
+};
+
+#define VALID_DIP_WORDS 3
+
+/* AUD_HDMI_STATUS bits */
+#define HDMI_AUDIO_UNDERRUN (1U << 31)
+#define HDMI_AUDIO_BUFFER_DONE (1U << 29)
+
+/* AUD_HDMI_STATUS register mask */
+#define AUD_HDMI_STATUS_MASK_UNDERRUN 0xC0000000
+#define AUD_HDMI_STATUS_MASK_SRDBG 0x00000002
+#define AUD_HDMI_STATUSG_MASK_FUNCRST 0x00000001
+
+#endif