summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/hda_register.h22
-rw-r--r--include/sound/hdaudio.h28
-rw-r--r--include/uapi/sound/asound.h3
-rw-r--r--include/uapi/sound/firewire.h10
-rw-r--r--sound/core/timer.c19
-rw-r--r--sound/drivers/vx/vx_core.c4
-rw-r--r--sound/firewire/Kconfig12
-rw-r--r--sound/firewire/Makefile1
-rw-r--r--sound/firewire/amdtp-stream.c36
-rw-r--r--sound/firewire/amdtp-stream.h9
-rw-r--r--sound/firewire/motu/Makefile4
-rw-r--r--sound/firewire/motu/amdtp-motu.c388
-rw-r--r--sound/firewire/motu/motu-hwdep.c198
-rw-r--r--sound/firewire/motu/motu-midi.c169
-rw-r--r--sound/firewire/motu/motu-pcm.c398
-rw-r--r--sound/firewire/motu/motu-proc.c118
-rw-r--r--sound/firewire/motu/motu-protocol-v2.c237
-rw-r--r--sound/firewire/motu/motu-protocol-v3.c312
-rw-r--r--sound/firewire/motu/motu-stream.c381
-rw-r--r--sound/firewire/motu/motu-transaction.c137
-rw-r--r--sound/firewire/motu/motu.c264
-rw-r--r--sound/firewire/motu/motu.h161
-rw-r--r--sound/hda/hdac_controller.c2
-rw-r--r--sound/hda/hdac_stream.c4
-rw-r--r--sound/isa/es1688/es1688_lib.c2
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c2
-rw-r--r--sound/pci/au88x0/au88x0_core.c3
-rw-r--r--sound/pci/au88x0/au88x0_eq.c6
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c2
-rw-r--r--sound/pci/aw2/aw2-alsa.c2
-rw-r--r--sound/pci/bt87x.c6
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c4
-rw-r--r--sound/pci/cmipci.c6
-rw-r--r--sound/pci/cs4281.c4
-rw-r--r--sound/pci/echoaudio/echoaudio.c26
-rw-r--r--sound/pci/emu10k1/emu10k1x.c6
-rw-r--r--sound/pci/emu10k1/emumixer.c30
-rw-r--r--sound/pci/emu10k1/emupcm.c2
-rw-r--r--sound/pci/ens1370.c4
-rw-r--r--sound/pci/hda/hda_codec.c4
-rw-r--r--sound/pci/hda/hda_intel.c40
-rw-r--r--sound/pci/hda/patch_ca0132.c10
-rw-r--r--sound/pci/hda/patch_hdmi.c2
-rw-r--r--sound/pci/hda/patch_realtek.c101
-rw-r--r--sound/pci/ice1712/delta.c2
-rw-r--r--sound/pci/ice1712/ews.c4
-rw-r--r--sound/pci/ice1712/ice1712.c30
-rw-r--r--sound/pci/ice1712/ice1724.c20
-rw-r--r--sound/pci/lola/lola_mixer.c2
-rw-r--r--sound/pci/lx6464es/lx6464es.c2
-rw-r--r--sound/pci/mixart/mixart_mixer.c6
-rw-r--r--sound/pci/oxygen/oxygen.c6
-rw-r--r--sound/pci/pcxhr/pcxhr_mix22.c6
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c22
-rw-r--r--sound/pci/trident/trident_main.c22
-rw-r--r--sound/pci/via82xx.c6
-rw-r--r--sound/pci/vx222/vx222_ops.c4
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c14
-rw-r--r--sound/soc/intel/skylake/skl.h21
-rw-r--r--sound/synth/emux/emux_oss.c4
-rw-r--r--sound/usb/card.c6
-rw-r--r--sound/usb/mixer_scarlett.c12
62 files changed, 3158 insertions, 210 deletions
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index 0013063db7f2..1251ff41c9d3 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -106,8 +106,26 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_HSW_EM4 0x100c
#define AZX_REG_HSW_EM5 0x1010
-/* Skylake/Broxton display HD-A controller Extended Mode registers */
-#define AZX_REG_SKL_EM4L 0x1040
+/* Skylake/Broxton vendor-specific registers */
+#define AZX_REG_VS_EM1 0x1000
+#define AZX_REG_VS_INRC 0x1004
+#define AZX_REG_VS_OUTRC 0x1008
+#define AZX_REG_VS_FIFOTRK 0x100C
+#define AZX_REG_VS_FIFOTRK2 0x1010
+#define AZX_REG_VS_EM2 0x1030
+#define AZX_REG_VS_EM3L 0x1038
+#define AZX_REG_VS_EM3U 0x103C
+#define AZX_REG_VS_EM4L 0x1040
+#define AZX_REG_VS_EM4U 0x1044
+#define AZX_REG_VS_LTRC 0x1048
+#define AZX_REG_VS_D0I3C 0x104A
+#define AZX_REG_VS_PCE 0x104B
+#define AZX_REG_VS_L2MAGC 0x1050
+#define AZX_REG_VS_L2LAHPT 0x1054
+#define AZX_REG_VS_SDXDPIB_XBASE 0x1084
+#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20
+#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
+#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
/* PCI space */
#define AZX_PCIREG_TCSEL 0x44
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h
index 56004ec8d441..96546b30e900 100644
--- a/include/sound/hdaudio.h
+++ b/include/sound/hdaudio.h
@@ -368,24 +368,32 @@ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
/*
* macros for easy use
*/
-#define _snd_hdac_chip_write(type, chip, reg, value) \
- ((chip)->io_ops->reg_write ## type(value, (chip)->remap_addr + (reg)))
-#define _snd_hdac_chip_read(type, chip, reg) \
- ((chip)->io_ops->reg_read ## type((chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_writeb(chip, reg, value) \
+ ((chip)->io_ops->reg_writeb(value, (chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_readb(chip, reg) \
+ ((chip)->io_ops->reg_readb((chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_writew(chip, reg, value) \
+ ((chip)->io_ops->reg_writew(value, (chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_readw(chip, reg) \
+ ((chip)->io_ops->reg_readw((chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_writel(chip, reg, value) \
+ ((chip)->io_ops->reg_writel(value, (chip)->remap_addr + (reg)))
+#define _snd_hdac_chip_readl(chip, reg) \
+ ((chip)->io_ops->reg_readl((chip)->remap_addr + (reg)))
/* read/write a register, pass without AZX_REG_ prefix */
#define snd_hdac_chip_writel(chip, reg, value) \
- _snd_hdac_chip_write(l, chip, AZX_REG_ ## reg, value)
+ _snd_hdac_chip_writel(chip, AZX_REG_ ## reg, value)
#define snd_hdac_chip_writew(chip, reg, value) \
- _snd_hdac_chip_write(w, chip, AZX_REG_ ## reg, value)
+ _snd_hdac_chip_writew(chip, AZX_REG_ ## reg, value)
#define snd_hdac_chip_writeb(chip, reg, value) \
- _snd_hdac_chip_write(b, chip, AZX_REG_ ## reg, value)
+ _snd_hdac_chip_writeb(chip, AZX_REG_ ## reg, value)
#define snd_hdac_chip_readl(chip, reg) \
- _snd_hdac_chip_read(l, chip, AZX_REG_ ## reg)
+ _snd_hdac_chip_readl(chip, AZX_REG_ ## reg)
#define snd_hdac_chip_readw(chip, reg) \
- _snd_hdac_chip_read(w, chip, AZX_REG_ ## reg)
+ _snd_hdac_chip_readw(chip, AZX_REG_ ## reg)
#define snd_hdac_chip_readb(chip, reg) \
- _snd_hdac_chip_read(b, chip, AZX_REG_ ## reg)
+ _snd_hdac_chip_readb(chip, AZX_REG_ ## reg)
/* update a register, pass without AZX_REG_ prefix */
#define snd_hdac_chip_updatel(chip, reg, mask, val) \
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index be353a78c303..fd7b561af768 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -107,9 +107,10 @@ enum {
SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */
SNDRV_HWDEP_IFACE_FW_TASCAM, /* TASCAM FireWire series */
SNDRV_HWDEP_IFACE_LINE6, /* Line6 USB processors */
+ SNDRV_HWDEP_IFACE_FW_MOTU, /* MOTU FireWire series */
/* Don't forget to change the following: */
- SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LINE6
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_MOTU
};
struct snd_hwdep_info {
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
index db79a12fcc78..29afc5eab42d 100644
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -10,6 +10,7 @@
#define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e
#define SNDRV_FIREWIRE_EVENT_EFW_RESPONSE 0x4e617475
#define SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE 0x746e736c
+#define SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION 0x64776479
struct snd_firewire_event_common {
unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */
@@ -46,12 +47,18 @@ struct snd_firewire_event_digi00x_message {
__u32 message; /* Digi00x-specific message */
};
+struct snd_firewire_event_motu_notification {
+ unsigned int type;
+ __u32 message; /* MOTU-specific bits. */
+};
+
union snd_firewire_event {
struct snd_firewire_event_common common;
struct snd_firewire_event_lock_status lock_status;
struct snd_firewire_event_dice_notification dice_notification;
struct snd_firewire_event_efw_response efw_response;
struct snd_firewire_event_digi00x_message digi00x_message;
+ struct snd_firewire_event_motu_notification motu_notification;
};
@@ -65,7 +72,8 @@ union snd_firewire_event {
#define SNDRV_FIREWIRE_TYPE_OXFW 4
#define SNDRV_FIREWIRE_TYPE_DIGI00X 5
#define SNDRV_FIREWIRE_TYPE_TASCAM 6
-/* RME, MOTU, ... */
+#define SNDRV_FIREWIRE_TYPE_MOTU 7
+/* RME... */
struct snd_firewire_get_info {
unsigned int type; /* SNDRV_FIREWIRE_TYPE_xxx */
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 6d4fbc439246..2f836ca09860 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1277,6 +1277,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
struct timespec tstamp;
int prev, append = 0;
+ memset(&r1, 0, sizeof(r1));
memset(&tstamp, 0, sizeof(tstamp));
spin_lock(&tu->qlock);
if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
@@ -1292,7 +1293,6 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
}
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
tu->last_resolution != resolution) {
- memset(&r1, 0, sizeof(r1));
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
r1.tstamp = tstamp;
r1.val = resolution;
@@ -1430,18 +1430,13 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
if (id.card < 0) {
id.card = 0;
} else {
- if (id.card < 0) {
- id.card = 0;
+ if (id.device < 0) {
+ id.device = 0;
} else {
- if (id.device < 0) {
- id.device = 0;
- } else {
- if (id.subdevice < 0) {
- id.subdevice = 0;
- } else {
- id.subdevice++;
- }
- }
+ if (id.subdevice < 0)
+ id.subdevice = 0;
+ else
+ id.subdevice++;
}
}
list_for_each(p, &snd_timer_list) {
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 289f041706cd..f684fffd1397 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -795,10 +795,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
return NULL;
chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL);
- if (! chip) {
- snd_printk(KERN_ERR "vx_core: no memory\n");
+ if (! chip)
return NULL;
- }
mutex_init(&chip->lock);
chip->irq = -1;
chip->hw = hw;
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 9f00696c4e4a..6acfacf75daf 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -140,4 +140,16 @@ config SND_FIREWIRE_TASCAM
To compile this driver as a module, choose M here: the module
will be called snd-firewire-tascam.
+config SND_FIREWIRE_MOTU
+ tristate "Mark of the unicorn FireWire series support"
+ select SND_FIREWIRE_LIB
+ select SND_HWDEP
+ help
+ Say Y here to enable support for FireWire devices which MOTU produced:
+ * 828mk2
+ * 828mk3
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-firewire-motu.
+
endif # SND_FIREWIRE
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index 0ee1fb115d88..9388ded69468 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SND_FIREWORKS) += fireworks/
obj-$(CONFIG_SND_BEBOB) += bebob/
obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/
obj-$(CONFIG_SND_FIREWIRE_TASCAM) += tascam/
+obj-$(CONFIG_SND_FIREWIRE_MOTU) += motu/
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 00060c4a9deb..112ad039ed25 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -37,6 +37,8 @@
#define CIP_SID_MASK 0x3f000000
#define CIP_DBS_MASK 0x00ff0000
#define CIP_DBS_SHIFT 16
+#define CIP_SPH_MASK 0x00000400
+#define CIP_SPH_SHIFT 10
#define CIP_DBC_MASK 0x000000ff
#define CIP_FMT_SHIFT 24
#define CIP_FMT_MASK 0x3f000000
@@ -424,15 +426,22 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int cycle,
data_blocks = calculate_data_blocks(s, syt);
pcm_frames = s->process_data_blocks(s, buffer + 2, data_blocks, &syt);
+ if (s->flags & CIP_DBC_IS_END_EVENT)
+ s->data_block_counter =
+ (s->data_block_counter + data_blocks) & 0xff;
+
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
(s->data_block_quadlets << CIP_DBS_SHIFT) |
+ ((s->sph << CIP_SPH_SHIFT) & CIP_SPH_MASK) |
s->data_block_counter);
buffer[1] = cpu_to_be32(CIP_EOH |
((s->fmt << CIP_FMT_SHIFT) & CIP_FMT_MASK) |
((s->fdf << CIP_FDF_SHIFT) & CIP_FDF_MASK) |
(syt & CIP_SYT_MASK));
- s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+ if (!(s->flags & CIP_DBC_IS_END_EVENT))
+ s->data_block_counter =
+ (s->data_block_counter + data_blocks) & 0xff;
payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
trace_out_packet(s, cycle, buffer, payload_length, index);
@@ -454,7 +463,7 @@ static int handle_in_packet(struct amdtp_stream *s,
{
__be32 *buffer;
u32 cip_header[2];
- unsigned int fmt, fdf, syt;
+ unsigned int sph, fmt, fdf, syt;
unsigned int data_block_quadlets, data_block_counter, dbc_interval;
unsigned int data_blocks;
struct snd_pcm_substream *pcm;
@@ -471,8 +480,9 @@ static int handle_in_packet(struct amdtp_stream *s,
* This module supports 'Two-quadlet CIP header with SYT field'.
* For convenience, also check FMT field is AM824 or not.
*/
- if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
- ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) {
+ if ((((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) ||
+ ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) &&
+ (!(s->flags & CIP_HEADER_WITHOUT_EOH))) {
dev_info_ratelimited(&s->unit->device,
"Invalid CIP header for AMDTP: %08X:%08X\n",
cip_header[0], cip_header[1]);
@@ -482,8 +492,9 @@ static int handle_in_packet(struct amdtp_stream *s,
}
/* Check valid protocol or not. */
+ sph = (cip_header[0] & CIP_SPH_MASK) >> CIP_SPH_SHIFT;
fmt = (cip_header[1] & CIP_FMT_MASK) >> CIP_FMT_SHIFT;
- if (fmt != s->fmt) {
+ if (sph != s->sph || fmt != s->fmt) {
dev_info_ratelimited(&s->unit->device,
"Detect unexpected protocol: %08x %08x\n",
cip_header[0], cip_header[1]);
@@ -671,6 +682,8 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
+ u32 cycle;
+ unsigned int packets;
/*
* For in-stream, first packet has come.
@@ -679,10 +692,19 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
s->callbacked = true;
wake_up(&s->callback_wait);
- if (s->direction == AMDTP_IN_STREAM)
+ cycle = compute_cycle_count(tstamp);
+
+ if (s->direction == AMDTP_IN_STREAM) {
+ packets = header_length / IN_PACKET_HEADER_SIZE;
+ cycle = decrement_cycle_count(cycle, packets);
context->callback.sc = in_stream_callback;
- else
+ } else {
+ packets = header_length / 4;
+ cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
context->callback.sc = out_stream_callback;
+ }
+
+ s->start_cycle = cycle;
context->callback.sc(context, tstamp, header_length, header, s);
}
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index c1bc7fad056e..a31dfd849821 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -18,8 +18,8 @@
* SYT_INTERVAL samples, with these two types alternating so that
* the overall sample rate comes out right.
* @CIP_EMPTY_WITH_TAG0: Only for in-stream. Empty in-packets have TAG0.
- * @CIP_DBC_IS_END_EVENT: Only for in-stream. The value of dbc in an in-packet
- * corresponds to the end of event in the packet. Out of IEC 61883.
+ * @CIP_DBC_IS_END_EVENT: The value of dbc in an packet corresponds to the end
+ * of event in the packet. Out of IEC 61883.
* @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets.
* The value of data_block_quadlets is used instead of reported value.
* @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
@@ -29,6 +29,8 @@
* @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an
* packet is larger than IEC 61883-6 defines. Current implementation
* allows 5 times as large as IEC 61883-6 defines.
+ * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include
+ * valid EOH.
*/
enum cip_flags {
CIP_NONBLOCKING = 0x00,
@@ -39,6 +41,7 @@ enum cip_flags {
CIP_SKIP_DBC_ZERO_CHECK = 0x10,
CIP_EMPTY_HAS_WRONG_DBC = 0x20,
CIP_JUMBO_PAYLOAD = 0x40,
+ CIP_HEADER_WITHOUT_EOH = 0x80,
};
/**
@@ -106,6 +109,7 @@ struct amdtp_stream {
unsigned int source_node_id_field;
unsigned int data_block_quadlets;
unsigned int data_block_counter;
+ unsigned int sph;
unsigned int fmt;
unsigned int fdf;
/* quirk: fixed interval of dbc between previos/current packets. */
@@ -130,6 +134,7 @@ struct amdtp_stream {
/* To wait for first packet. */
bool callbacked;
wait_queue_head_t callback_wait;
+ u32 start_cycle;
/* For backends to process data blocks. */
void *protocol;
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
new file mode 100644
index 000000000000..ae84ae61d274
--- /dev/null
+++ b/sound/firewire/motu/Makefile
@@ -0,0 +1,4 @@
+snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
+ motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
+ motu-protocol-v2.o motu-protocol-v3.o
+obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c
new file mode 100644
index 000000000000..08bd1760b1b4
--- /dev/null
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -0,0 +1,388 @@
+/*
+ * amdtp-motu.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include "motu.h"
+
+#define CIP_FMT_MOTU 0x02
+#define CIP_FMT_MOTU_TX_V3 0x22
+#define MOTU_FDF_AM824 0x22
+
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND 3093
+
+struct amdtp_motu {
+ /* For timestamp processing. */
+ unsigned int quotient_ticks_per_event;
+ unsigned int remainder_ticks_per_event;
+ unsigned int next_ticks;
+ unsigned int next_accumulated;
+ unsigned int next_cycles;
+ unsigned int next_seconds;
+
+ unsigned int pcm_chunks;
+ unsigned int pcm_byte_offset;
+
+ struct snd_rawmidi_substream *midi;
+ unsigned int midi_ports;
+ unsigned int midi_flag_offset;
+ unsigned int midi_byte_offset;
+
+ int midi_db_count;
+ unsigned int midi_db_interval;
+};
+
+int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
+ unsigned int midi_ports,
+ struct snd_motu_packet_format *formats)
+{
+ static const struct {
+ unsigned int quotient_ticks_per_event;
+ unsigned int remainder_ticks_per_event;
+ } params[] = {
+ [CIP_SFC_44100] = { 557, 123 },
+ [CIP_SFC_48000] = { 512, 0 },
+ [CIP_SFC_88200] = { 278, 282 },
+ [CIP_SFC_96000] = { 256, 0 },
+ [CIP_SFC_176400] = { 139, 141 },
+ [CIP_SFC_192000] = { 128, 0 },
+ };
+ struct amdtp_motu *p = s->protocol;
+ unsigned int pcm_chunks, data_chunks, data_block_quadlets;
+ unsigned int delay;
+ unsigned int mode;
+ int i, err;
+
+ if (amdtp_stream_running(s))
+ return -EBUSY;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ if (snd_motu_clock_rates[i] == rate) {
+ mode = i >> 1;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(snd_motu_clock_rates))
+ return -EINVAL;
+
+ pcm_chunks = formats->fixed_part_pcm_chunks[mode] +
+ formats->differed_part_pcm_chunks[mode];
+ data_chunks = formats->msg_chunks + pcm_chunks;
+
+ /*
+ * Each data block includes SPH in its head. Data chunks follow with
+ * 3 byte alignment. Padding follows with zero to conform to quadlet
+ * alignment.
+ */
+ data_block_quadlets = 1 + DIV_ROUND_UP(data_chunks * 3, 4);
+
+ err = amdtp_stream_set_parameters(s, rate, data_block_quadlets);
+ if (err < 0)
+ return err;
+
+ p->pcm_chunks = pcm_chunks;
+ p->pcm_byte_offset = formats->pcm_byte_offset;
+
+ p->midi_ports = midi_ports;
+ p->midi_flag_offset = formats->midi_flag_offset;
+ p->midi_byte_offset = formats->midi_byte_offset;
+
+ p->midi_db_count = 0;
+ p->midi_db_interval = rate / MIDI_BYTES_PER_SECOND;
+
+ /* IEEE 1394 bus requires. */
+ delay = 0x2e00;
+
+ /* For no-data or empty packets to adjust PCM sampling frequency. */
+ delay += 8000 * 3072 * s->syt_interval / rate;
+
+ p->next_seconds = 0;
+ p->next_cycles = delay / 3072;
+ p->quotient_ticks_per_event = params[s->sfc].quotient_ticks_per_event;
+ p->remainder_ticks_per_event = params[s->sfc].remainder_ticks_per_event;
+ p->next_ticks = delay % 3072;
+ p->next_accumulated = 0;
+
+ return 0;
+}
+
+static void read_pcm_s32(struct amdtp_stream *s,
+ struct snd_pcm_runtime *runtime,
+ __be32 *buffer, unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ unsigned int channels, remaining_frames, i, c;
+ u8 *byte;
+ u32 *dst;
+
+ channels = p->pcm_chunks;
+ dst = (void *)runtime->dma_area +
+ frames_to_bytes(runtime, s->pcm_buffer_pointer);
+ remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+ for (i = 0; i < data_blocks; ++i) {
+ byte = (u8 *)buffer + p->pcm_byte_offset;
+
+ for (c = 0; c < channels; ++c) {
+ *dst = (byte[0] << 24) | (byte[1] << 16) | byte[2];
+ byte += 3;
+ dst++;
+ }
+ buffer += s->data_block_quadlets;
+ if (--remaining_frames == 0)
+ dst = (void *)runtime->dma_area;
+ }
+}
+
+static void write_pcm_s32(struct amdtp_stream *s,
+ struct snd_pcm_runtime *runtime,
+ __be32 *buffer, unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ unsigned int channels, remaining_frames, i, c;
+ u8 *byte;
+ const u32 *src;
+
+ channels = p->pcm_chunks;
+ src = (void *)runtime->dma_area +
+ frames_to_bytes(runtime, s->pcm_buffer_pointer);
+ remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+
+ for (i = 0; i < data_blocks; ++i) {
+ byte = (u8 *)buffer + p->pcm_byte_offset;
+
+ for (c = 0; c < channels; ++c) {
+ byte[0] = (*src >> 24) & 0xff;
+ byte[1] = (*src >> 16) & 0xff;
+ byte[2] = (*src >> 8) & 0xff;
+ byte += 3;
+ src++;
+ }
+
+ buffer += s->data_block_quadlets;
+ if (--remaining_frames == 0)
+ src = (void *)runtime->dma_area;
+ }
+}
+
+static void write_pcm_silence(struct amdtp_stream *s, __be32 *buffer,
+ unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ unsigned int channels, i, c;
+ u8 *byte;
+
+ channels = p->pcm_chunks;
+
+ for (i = 0; i < data_blocks; ++i) {
+ byte = (u8 *)buffer + p->pcm_byte_offset;
+
+ for (c = 0; c < channels; ++c) {
+ byte[0] = 0;
+ byte[1] = 0;
+ byte[2] = 0;
+ byte += 3;
+ }
+
+ buffer += s->data_block_quadlets;
+ }
+}
+
+int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
+ struct snd_pcm_runtime *runtime)
+{
+ int err;
+
+ /* TODO: how to set an constraint for exactly 24bit PCM sample? */
+ err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+ if (err < 0)
+ return err;
+
+ return amdtp_stream_add_pcm_hw_constraints(s, runtime);
+}
+
+void amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port,
+ struct snd_rawmidi_substream *midi)
+{
+ struct amdtp_motu *p = s->protocol;
+
+ if (port < p->midi_ports)
+ WRITE_ONCE(p->midi, midi);
+}
+
+static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+ unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ struct snd_rawmidi_substream *midi = READ_ONCE(p->midi);
+ u8 *b;
+ int i;
+
+ for (i = 0; i < data_blocks; i++) {
+ b = (u8 *)buffer;
+
+ if (midi && p->midi_db_count == 0 &&
+ snd_rawmidi_transmit(midi, b + p->midi_byte_offset, 1) == 1) {
+ b[p->midi_flag_offset] = 0x01;
+ } else {
+ b[p->midi_byte_offset] = 0x00;
+ b[p->midi_flag_offset] = 0x00;
+ }
+
+ buffer += s->data_block_quadlets;
+
+ if (--p->midi_db_count < 0)
+ p->midi_db_count = p->midi_db_interval;
+ }
+}
+
+static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer,
+ unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ struct snd_rawmidi_substream *midi;
+ u8 *b;
+ int i;
+
+ for (i = 0; i < data_blocks; i++) {
+ b = (u8 *)buffer;
+ midi = READ_ONCE(p->midi);
+
+ if (midi && (b[p->midi_flag_offset] & 0x01))
+ snd_rawmidi_receive(midi, b + p->midi_byte_offset, 1);
+
+ buffer += s->data_block_quadlets;
+ }
+}
+
+static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
+ __be32 *buffer, unsigned int data_blocks,
+ unsigned int *syt)
+{
+ struct amdtp_motu *p = s->protocol;
+ struct snd_pcm_substream *pcm;
+
+ if (p->midi_ports)
+ read_midi_messages(s, buffer, data_blocks);
+
+ pcm = ACCESS_ONCE(s->pcm);
+ if (data_blocks > 0 && pcm)
+ read_pcm_s32(s, pcm->runtime, buffer, data_blocks);
+
+ return data_blocks;
+}
+
+static inline void compute_next_elapse_from_start(struct amdtp_motu *p)
+{
+ p->next_accumulated += p->remainder_ticks_per_event;
+ if (p->next_accumulated >= 441) {
+ p->next_accumulated -= 441;
+ p->next_ticks++;
+ }
+
+ p->next_ticks += p->quotient_ticks_per_event;
+ if (p->next_ticks >= 3072) {
+ p->next_ticks -= 3072;
+ p->next_cycles++;
+ }
+
+ if (p->next_cycles >= 8000) {
+ p->next_cycles -= 8000;
+ p->next_seconds++;
+ }
+
+ if (p->next_seconds >= 128)
+ p->next_seconds -= 128;
+}
+
+static void write_sph(struct amdtp_stream *s, __be32 *buffer,
+ unsigned int data_blocks)
+{
+ struct amdtp_motu *p = s->protocol;
+ unsigned int next_cycles;
+ unsigned int i;
+ u32 sph;
+
+ for (i = 0; i < data_blocks; i++) {
+ next_cycles = (s->start_cycle + p->next_cycles) % 8000;
+ sph = ((next_cycles << 12) | p->next_ticks) & 0x01ffffff;
+ *buffer = cpu_to_be32(sph);
+
+ compute_next_elapse_from_start(p);
+
+ buffer += s->data_block_quadlets;
+ }
+}
+
+static unsigned int process_rx_data_blocks(struct amdtp_stream *s,
+ __be32 *buffer, unsigned int data_blocks,
+ unsigned int *syt)
+{
+ struct amdtp_motu *p = (struct amdtp_motu *)s->protocol;
+ struct snd_pcm_substream *pcm;
+
+ /* Not used. */
+ *syt = 0xffff;
+
+ /* TODO: how to interact control messages between userspace? */
+
+ if (p->midi_ports)
+ write_midi_messages(s, buffer, data_blocks);
+
+ pcm = ACCESS_ONCE(s->pcm);
+ if (pcm)
+ write_pcm_s32(s, pcm->runtime, buffer, data_blocks);
+ else
+ write_pcm_silence(s, buffer, data_blocks);
+
+ write_sph(s, buffer, data_blocks);
+
+ return data_blocks;
+}
+
+int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
+ enum amdtp_stream_direction dir,
+ const struct snd_motu_protocol *const protocol)
+{
+ amdtp_stream_process_data_blocks_t process_data_blocks;
+ int fmt = CIP_FMT_MOTU;
+ int flags = CIP_BLOCKING;
+ int err;
+
+ if (dir == AMDTP_IN_STREAM) {
+ process_data_blocks = process_tx_data_blocks;
+
+ /*
+ * Units of version 3 transmits packets with invalid CIP header
+ * against IEC 61883-1.
+ */
+ if (protocol == &snd_motu_protocol_v3) {
+ flags |= CIP_WRONG_DBS |
+ CIP_SKIP_DBC_ZERO_CHECK |
+ CIP_HEADER_WITHOUT_EOH;
+ fmt = CIP_FMT_MOTU_TX_V3;
+ }
+ } else {
+ process_data_blocks = process_rx_data_blocks;
+ flags |= CIP_DBC_IS_END_EVENT;
+ }
+
+ err = amdtp_stream_init(s, unit, dir, flags, fmt, process_data_blocks,
+ sizeof(struct amdtp_motu));
+ if (err < 0)
+ return err;
+
+ s->sph = 1;
+ s->fdf = MOTU_FDF_AM824;
+
+ return 0;
+}
diff --git a/sound/firewire/motu/motu-hwdep.c b/sound/firewire/motu/motu-hwdep.c
new file mode 100644
index 000000000000..b87ccb69d597
--- /dev/null
+++ b/sound/firewire/motu/motu-hwdep.c
@@ -0,0 +1,198 @@
+/*
+ * motu-hwdep.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes have five functionalities.
+ *
+ * 1.get information about firewire node
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock streaming
+ *
+ */
+
+#include "motu.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
+ loff_t *offset)
+{
+ struct snd_motu *motu = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&motu->lock);
+
+ while (!motu->dev_lock_changed && motu->msg == 0) {
+ prepare_to_wait(&motu->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&motu->lock);
+ schedule();
+ finish_wait(&motu->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&motu->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (motu->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = (motu->dev_lock_count > 0);
+ motu->dev_lock_changed = false;
+
+ count = min_t(long, count, sizeof(event.lock_status));
+ } else {
+ event.motu_notification.type = SNDRV_FIREWIRE_EVENT_MOTU_NOTIFICATION;
+ event.motu_notification.message = motu->msg;
+ motu->msg = 0;
+
+ count = min_t(long, count, sizeof(event.motu_notification));
+ }
+
+ spin_unlock_irq(&motu->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct snd_motu *motu = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &motu->hwdep_wait, wait);
+
+ spin_lock_irq(&motu->lock);
+ if (motu->dev_lock_changed || motu->msg)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&motu->lock);
+
+ return events | POLLOUT;
+}
+
+static int hwdep_get_info(struct snd_motu *motu, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(motu->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_MOTU;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int hwdep_lock(struct snd_motu *motu)
+{
+ int err;
+
+ spin_lock_irq(&motu->lock);
+
+ if (motu->dev_lock_count == 0) {
+ motu->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&motu->lock);
+
+ return err;
+}
+
+static int hwdep_unlock(struct snd_motu *motu)
+{
+ int err;
+
+ spin_lock_irq(&motu->lock);
+
+ if (motu->dev_lock_count == -1) {
+ motu->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&motu->lock);
+
+ return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct snd_motu *motu = hwdep->private_data;
+
+ spin_lock_irq(&motu->lock);
+ if (motu->dev_lock_count == -1)
+ motu->dev_lock_count = 0;
+ spin_unlock_irq(&motu->lock);
+
+ return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct snd_motu *motu = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return hwdep_get_info(motu, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return hwdep_lock(motu);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return hwdep_unlock(motu);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+int snd_motu_create_hwdep_device(struct snd_motu *motu)
+{
+ 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;
+
+ err = snd_hwdep_new(motu->card, motu->card->driver, 0, &hwdep);
+ if (err < 0)
+ return err;
+
+ strcpy(hwdep->name, "MOTU");
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_MOTU;
+ hwdep->ops = ops;
+ hwdep->private_data = motu;
+ hwdep->exclusive = true;
+
+ return 0;
+}
diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c
new file mode 100644
index 000000000000..e3acfcc53f4e
--- /dev/null
+++ b/sound/firewire/motu/motu-midi.c
@@ -0,0 +1,169 @@
+/*
+ * motu-midi.h - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+#include "motu.h"
+
+static int midi_capture_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_motu *motu = substream->rmidi->private_data;
+ int err;
+
+ err = snd_motu_stream_lock_try(motu);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&motu->mutex);
+
+ motu->capture_substreams++;
+ err = snd_motu_stream_start_duplex(motu, 0);
+
+ mutex_unlock(&motu->mutex);
+
+ if (err < 0)
+ snd_motu_stream_lock_release(motu);
+
+ return err;
+}
+
+static int midi_playback_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_motu *motu = substream->rmidi->private_data;
+ int err;
+
+ err = snd_motu_stream_lock_try(motu);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&motu->mutex);
+
+ motu->playback_substreams++;
+ err = snd_motu_stream_start_duplex(motu, 0);
+
+ mutex_unlock(&motu->mutex);
+
+ if (err < 0)
+ snd_motu_stream_lock_release(motu);
+
+ return err;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_motu *motu = substream->rmidi->private_data;
+
+ mutex_lock(&motu->mutex);
+
+ motu->capture_substreams--;
+ snd_motu_stream_stop_duplex(motu);
+
+ mutex_unlock(&motu->mutex);
+
+ snd_motu_stream_lock_release(motu);
+ return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_motu *motu = substream->rmidi->private_data;
+
+ mutex_lock(&motu->mutex);
+
+ motu->playback_substreams--;
+ snd_motu_stream_stop_duplex(motu);
+
+ mutex_unlock(&motu->mutex);
+
+ snd_motu_stream_lock_release(motu);
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_motu *motu = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&motu->lock, flags);
+
+ if (up)
+ amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
+ substrm);
+ else
+ amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
+ NULL);
+
+ spin_unlock_irqrestore(&motu->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_motu *motu = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&motu->lock, flags);
+
+ if (up)
+ amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
+ substrm);
+ else
+ amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
+ NULL);
+
+ spin_unlock_irqrestore(&motu->lock, flags);
+}
+
+static void set_midi_substream_names(struct snd_motu *motu,
+ struct snd_rawmidi_str *str)
+{
+ struct snd_rawmidi_substream *subs;
+
+ list_for_each_entry(subs, &str->substreams, list) {
+ snprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", motu->card->shortname, subs->number + 1);
+ }
+}
+
+int snd_motu_create_midi_devices(struct snd_motu *motu)
+{
+ static struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static 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;
+
+ /* create midi ports */
+ err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", motu->card->shortname);
+ rmidi->private_data = motu;
+
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &capture_ops);
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+ set_midi_substream_names(motu, str);
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &playback_ops);
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+ set_midi_substream_names(motu, str);
+
+ return 0;
+}
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
new file mode 100644
index 000000000000..94558f3d218b
--- /dev/null
+++ b/sound/firewire/motu/motu-pcm.c
@@ -0,0 +1,398 @@
+/*
+ * motu-pcm.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <sound/pcm_params.h>
+#include "motu.h"
+
+static int motu_rate_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_motu_packet_format *formats = rule->private;
+
+ const struct snd_interval *c =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval rates = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, pcm_channels, rate, mode;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ rate = snd_motu_clock_rates[i];
+ mode = i / 2;
+
+ pcm_channels = formats->fixed_part_pcm_chunks[mode] +
+ formats->differed_part_pcm_chunks[mode];
+ if (!snd_interval_test(c, pcm_channels))
+ continue;
+
+ rates.min = min(rates.min, rate);
+ rates.max = max(rates.max, rate);
+ }
+
+ return snd_interval_refine(r, &rates);
+}
+
+static int motu_channels_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_motu_packet_format *formats = rule->private;
+
+ const struct snd_interval *r =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval channels = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, pcm_channels, rate, mode;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ rate = snd_motu_clock_rates[i];
+ mode = i / 2;
+
+ if (!snd_interval_test(r, rate))
+ continue;
+
+ pcm_channels = formats->fixed_part_pcm_chunks[mode] +
+ formats->differed_part_pcm_chunks[mode];
+ channels.min = min(channels.min, pcm_channels);
+ channels.max = max(channels.max, pcm_channels);
+ }
+
+ return snd_interval_refine(c, &channels);
+}
+
+static void limit_channels_and_rates(struct snd_motu *motu,
+ struct snd_pcm_runtime *runtime,
+ struct snd_motu_packet_format *formats)
+{
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ unsigned int i, pcm_channels, rate, mode;
+
+ hw->channels_min = UINT_MAX;
+ hw->channels_max = 0;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ rate = snd_motu_clock_rates[i];
+ mode = i / 2;
+
+ pcm_channels = formats->fixed_part_pcm_chunks[mode] +
+ formats->differed_part_pcm_chunks[mode];
+ if (pcm_channels == 0)
+ continue;
+
+ hw->rates |= snd_pcm_rate_to_rate_bit(rate);
+ hw->channels_min = min(hw->channels_min, pcm_channels);
+ hw->channels_max = max(hw->channels_max, pcm_channels);
+ }
+
+ snd_pcm_limit_hw_rates(runtime);
+}
+
+static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
+{
+ hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
+ hw->periods_max = UINT_MAX;
+
+ hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */
+
+ /* Just to prevent from allocating much pages. */
+ hw->period_bytes_max = hw->period_bytes_min * 2048;
+ hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
+}
+
+static int init_hw_info(struct snd_motu *motu,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ struct amdtp_stream *stream;
+ struct snd_motu_packet_format *formats;
+ int err;
+
+ hw->info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ hw->formats = SNDRV_PCM_FMTBIT_S32;
+ stream = &motu->tx_stream;
+ formats = &motu->tx_packet_formats;
+ } else {
+ hw->formats = SNDRV_PCM_FMTBIT_S32;
+ stream = &motu->rx_stream;
+ formats = &motu->rx_packet_formats;
+ }
+
+ limit_channels_and_rates(motu, runtime, formats);
+ limit_period_and_buffer(hw);
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ motu_rate_constraint, formats,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ motu_channels_constraint, formats,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ return err;
+
+ return amdtp_motu_add_pcm_hw_constraints(stream, runtime);
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+ const struct snd_motu_protocol *const protocol = motu->spec->protocol;
+ enum snd_motu_clock_source src;
+ unsigned int rate;
+ int err;
+
+ err = snd_motu_stream_lock_try(motu);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&motu->mutex);
+
+ err = protocol->cache_packet_formats(motu);
+ if (err < 0)
+ goto err_locked;
+
+ err = init_hw_info(motu, substream);
+ if (err < 0)
+ goto err_locked;
+
+ /*
+ * When source of clock is not internal or any PCM streams are running,
+ * available sampling rate is limited at current sampling rate.
+ */
+ err = protocol->get_clock_source(motu, &src);
+ if (err < 0)
+ goto err_locked;
+ if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL ||
+ amdtp_stream_pcm_running(&motu->tx_stream) ||
+ amdtp_stream_pcm_running(&motu->rx_stream)) {
+ err = protocol->get_clock_rate(motu, &rate);
+ if (err < 0)
+ goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+ }
+
+ snd_pcm_set_sync(substream);
+
+ mutex_unlock(&motu->mutex);
+
+ return err;
+err_locked:
+ mutex_unlock(&motu->mutex);
+ snd_motu_stream_lock_release(motu);
+ return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ snd_motu_stream_lock_release(motu);
+
+ return 0;
+}
+
+static int capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_motu *motu = substream->private_data;
+ int err;
+
+ err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&motu->mutex);
+ motu->capture_substreams++;
+ mutex_unlock(&motu->mutex);
+ }
+
+ return 0;
+}
+static int playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_motu *motu = substream->private_data;
+ int err;
+
+ err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&motu->mutex);
+ motu->playback_substreams++;
+ mutex_unlock(&motu->mutex);
+ }
+
+ return 0;
+}
+
+static int capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ mutex_lock(&motu->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ motu->capture_substreams--;
+
+ snd_motu_stream_stop_duplex(motu);
+
+ mutex_unlock(&motu->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ mutex_lock(&motu->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ motu->playback_substreams--;
+
+ snd_motu_stream_stop_duplex(motu);
+
+ mutex_unlock(&motu->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+ int err;
+
+ mutex_lock(&motu->mutex);
+ err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ mutex_unlock(&motu->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&motu->tx_stream);
+
+ return 0;
+}
+static int playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+ int err;
+
+ mutex_lock(&motu->mutex);
+ err = snd_motu_stream_start_duplex(motu, substream->runtime->rate);
+ mutex_unlock(&motu->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&motu->rx_stream);
+
+ return err;
+}
+
+static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&motu->tx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&motu->tx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&motu->rx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&motu->rx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&motu->tx_stream);
+}
+static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_motu *motu = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&motu->rx_stream);
+}
+
+int snd_motu_create_pcm_devices(struct snd_motu *motu)
+{
+ static struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = capture_hw_params,
+ .hw_free = capture_hw_free,
+ .prepare = capture_prepare,
+ .trigger = capture_trigger,
+ .pointer = capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ static struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = playback_hw_params,
+ .hw_free = playback_hw_free,
+ .prepare = playback_prepare,
+ .trigger = playback_trigger,
+ .pointer = playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(motu->card, motu->card->driver, 0, 1, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = motu;
+ strcpy(pcm->name, motu->card->shortname);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+
+ return 0;
+}
diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c
new file mode 100644
index 000000000000..4edc064999ed
--- /dev/null
+++ b/sound/firewire/motu/motu-proc.c
@@ -0,0 +1,118 @@
+/*
+ * motu-proc.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./motu.h"
+
+static const char *const clock_names[] = {
+ [SND_MOTU_CLOCK_SOURCE_INTERNAL] = "Internal",
+ [SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB] = "ADAT on Dsub-9pin interface",
+ [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT] = "ADAT on optical interface",
+ [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A] = "ADAT on optical interface A",
+ [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B] = "ADAT on optical interface B",
+ [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface",
+ [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A",
+ [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B",
+ [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PCIF on coaxial interface",
+ [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface",
+ [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface",
+};
+
+static void proc_read_clock(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+
+ struct snd_motu *motu = entry->private_data;
+ const struct snd_motu_protocol *const protocol = motu->spec->protocol;
+ unsigned int rate;
+ enum snd_motu_clock_source source;
+
+ if (protocol->get_clock_rate(motu, &rate) < 0)
+ return;
+ if (protocol->get_clock_source(motu, &source) < 0)
+ return;
+
+ snd_iprintf(buffer, "Rate:\t%d\n", rate);
+ snd_iprintf(buffer, "Source:\t%s\n", clock_names[source]);
+}
+
+static void proc_read_format(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_motu *motu = entry->private_data;
+ const struct snd_motu_protocol *const protocol = motu->spec->protocol;
+ unsigned int mode;
+ struct snd_motu_packet_format *formats;
+ int i;
+
+ if (protocol->cache_packet_formats(motu) < 0)
+ return;
+
+ snd_iprintf(buffer, "tx:\tmsg\tfixed\tdiffered\n");
+ for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) {
+ mode = i >> 1;
+
+ formats = &motu->tx_packet_formats;
+ snd_iprintf(buffer,
+ "%u:\t%u\t%u\t%u\n",
+ snd_motu_clock_rates[i],
+ formats->msg_chunks,
+ formats->fixed_part_pcm_chunks[mode],
+ formats->differed_part_pcm_chunks[mode]);
+ }
+
+ snd_iprintf(buffer, "rx:\tmsg\tfixed\tdiffered\n");
+ for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) {
+ mode = i >> 1;
+
+ formats = &motu->rx_packet_formats;
+ snd_iprintf(buffer,
+ "%u:\t%u\t%u\t%u\n",
+ snd_motu_clock_rates[i],
+ formats->msg_chunks,
+ formats->fixed_part_pcm_chunks[mode],
+ formats->differed_part_pcm_chunks[mode]);
+ }
+}
+
+static void add_node(struct snd_motu *motu, struct snd_info_entry *root,
+ const char *name,
+ void (*op)(struct snd_info_entry *e,
+ struct snd_info_buffer *b))
+{
+ struct snd_info_entry *entry;
+
+ entry = snd_info_create_card_entry(motu->card, name, root);
+ if (entry == NULL)
+ return;
+
+ snd_info_set_text_ops(entry, motu, op);
+ if (snd_info_register(entry) < 0)
+ snd_info_free_entry(entry);
+}
+
+void snd_motu_proc_init(struct snd_motu *motu)
+{
+ struct snd_info_entry *root;
+
+ /*
+ * All nodes are automatically removed at snd_card_disconnect(),
+ * by following to link list.
+ */
+ root = snd_info_create_card_entry(motu->card, "firewire",
+ motu->card->proc_root);
+ if (root == NULL)
+ return;
+ root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ if (snd_info_register(root) < 0) {
+ snd_info_free_entry(root);
+ return;
+ }
+
+ add_node(motu, root, "clock", proc_read_clock);
+ add_node(motu, root, "format", proc_read_format);
+}
diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c
new file mode 100644
index 000000000000..05b5d287c2f3
--- /dev/null
+++ b/sound/firewire/motu/motu-protocol-v2.c
@@ -0,0 +1,237 @@
+/*
+ * motu-protocol-v2.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "motu.h"
+
+#define V2_CLOCK_STATUS_OFFSET 0x0b14
+#define V2_CLOCK_RATE_MASK 0x00000038
+#define V2_CLOCK_RATE_SHIFT 3
+#define V2_CLOCK_SRC_MASK 0x00000007
+#define V2_CLOCK_SRC_SHIFT 0
+
+#define V2_IN_OUT_CONF_OFFSET 0x0c04
+#define V2_OPT_OUT_IFACE_MASK 0x00000c00
+#define V2_OPT_OUT_IFACE_SHIFT 10
+#define V2_OPT_IN_IFACE_MASK 0x00000300
+#define V2_OPT_IN_IFACE_SHIFT 8
+#define V2_OPT_IFACE_MODE_NONE 0
+#define V2_OPT_IFACE_MODE_ADAT 1
+#define V2_OPT_IFACE_MODE_SPDIF 2
+
+static int v2_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
+{
+ __be32 reg;
+ unsigned int index;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+
+ index = (be32_to_cpu(reg) & V2_CLOCK_RATE_MASK) >> V2_CLOCK_RATE_SHIFT;
+ if (index >= ARRAY_SIZE(snd_motu_clock_rates))
+ return -EIO;
+
+ *rate = snd_motu_clock_rates[index];
+
+ return 0;
+}
+
+static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
+{
+ __be32 reg;
+ u32 data;
+ int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ if (snd_motu_clock_rates[i] == rate)
+ break;
+ }
+ if (i == ARRAY_SIZE(snd_motu_clock_rates))
+ return -EINVAL;
+
+ err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ data &= ~V2_CLOCK_RATE_MASK;
+ data |= i << V2_CLOCK_RATE_SHIFT;
+
+ reg = cpu_to_be32(data);
+ return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+}
+
+static int v2_get_clock_source(struct snd_motu *motu,
+ enum snd_motu_clock_source *src)
+{
+ __be32 reg;
+ unsigned int index;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+
+ index = be32_to_cpu(reg) & V2_CLOCK_SRC_MASK;
+ if (index > 5)
+ return -EIO;
+
+ /* To check the configuration of optical interface. */
+ err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+
+ switch (index) {
+ case 0:
+ *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
+ break;
+ case 1:
+ if (be32_to_cpu(reg) & 0x00000200)
+ *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT;
+ else
+ *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT;
+ break;
+ case 2:
+ *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
+ break;
+ case 4:
+ *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
+ break;
+ case 5:
+ *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB;
+ break;
+ default:
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
+{
+ /* V2 protocol doesn't have this feature. */
+ return 0;
+}
+
+static void calculate_fixed_part(struct snd_motu_packet_format *formats,
+ enum amdtp_stream_direction dir,
+ enum snd_motu_spec_flags flags,
+ unsigned char analog_ports)
+{
+ unsigned char pcm_chunks[3] = {0, 0, 0};
+
+ formats->msg_chunks = 2;
+
+ pcm_chunks[0] = analog_ports;
+ pcm_chunks[1] = analog_ports;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ pcm_chunks[2] = analog_ports;
+
+ if (dir == AMDTP_IN_STREAM) {
+ if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+ if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+ } else {
+ /*
+ * Packets to v2 units transfer main-out-1/2 and phone-out-1/2.
+ */
+ pcm_chunks[0] += 4;
+ pcm_chunks[1] += 4;
+ }
+
+ /*
+ * All of v2 models have a pair of coaxial interfaces for digital in/out
+ * port. At 44.1/48.0/88.2/96.0 kHz, packets includes PCM from these
+ * ports.
+ */
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+
+ /* This part should be multiples of 4. */
+ formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2;
+ formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ formats->fixed_part_pcm_chunks[2] =
+ round_up(2 + pcm_chunks[2], 4) - 2;
+}
+
+static void calculate_differed_part(struct snd_motu_packet_format *formats,
+ enum snd_motu_spec_flags flags,
+ u32 data, u32 mask, u32 shift)
+{
+ unsigned char pcm_chunks[3] = {0, 0};
+
+ /*
+ * When optical interfaces are configured for S/PDIF (TOSLINK),
+ * the above PCM frames come from them, instead of coaxial
+ * interfaces.
+ */
+ data = (data & mask) >> shift;
+ if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) &&
+ data == V2_OPT_IFACE_MODE_ADAT) {
+ pcm_chunks[0] += 8;
+ pcm_chunks[1] += 4;
+ }
+
+ /* At mode x4, no data chunks are supported in this part. */
+ formats->differed_part_pcm_chunks[0] = pcm_chunks[0];
+ formats->differed_part_pcm_chunks[1] = pcm_chunks[1];
+}
+
+static int v2_cache_packet_formats(struct snd_motu *motu)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V2_IN_OUT_CONF_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM,
+ motu->spec->flags, motu->spec->analog_in_ports);
+ calculate_differed_part(&motu->tx_packet_formats, motu->spec->flags,
+ data, V2_OPT_IN_IFACE_MASK, V2_OPT_IN_IFACE_SHIFT);
+
+ calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM,
+ motu->spec->flags, motu->spec->analog_out_ports);
+ calculate_differed_part(&motu->rx_packet_formats, motu->spec->flags,
+ data, V2_OPT_OUT_IFACE_MASK, V2_OPT_OUT_IFACE_SHIFT);
+
+ motu->tx_packet_formats.midi_flag_offset = 4;
+ motu->tx_packet_formats.midi_byte_offset = 6;
+ motu->tx_packet_formats.pcm_byte_offset = 10;
+
+ motu->rx_packet_formats.midi_flag_offset = 4;
+ motu->rx_packet_formats.midi_byte_offset = 6;
+ motu->rx_packet_formats.pcm_byte_offset = 10;
+
+ return 0;
+}
+
+const struct snd_motu_protocol snd_motu_protocol_v2 = {
+ .get_clock_rate = v2_get_clock_rate,
+ .set_clock_rate = v2_set_clock_rate,
+ .get_clock_source = v2_get_clock_source,
+ .switch_fetching_mode = v2_switch_fetching_mode,
+ .cache_packet_formats = v2_cache_packet_formats,
+};
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c
new file mode 100644
index 000000000000..b463da99feb1
--- /dev/null
+++ b/sound/firewire/motu/motu-protocol-v3.c
@@ -0,0 +1,312 @@
+/*
+ * motu-protocol-v3.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/delay.h>
+#include "motu.h"
+
+#define V3_CLOCK_STATUS_OFFSET 0x0b14
+#define V3_FETCH_PCM_FRAMES 0x02000000
+#define V3_CLOCK_RATE_MASK 0x0000ff00
+#define V3_CLOCK_RATE_SHIFT 8
+#define V3_CLOCK_SOURCE_MASK 0x000000ff
+#define V3_CLOCK_SOURCE_SHIFT 8
+
+#define V3_OPT_IFACE_MODE_OFFSET 0x0c94
+#define V3_ENABLE_OPT_IN_IFACE_A 0x00000001
+#define V3_ENABLE_OPT_IN_IFACE_B 0x00000002
+#define V3_ENABLE_OPT_OUT_IFACE_A 0x00000100
+#define V3_ENABLE_OPT_OUT_IFACE_B 0x00000200
+#define V3_NO_ADAT_OPT_IN_IFACE_A 0x00010000
+#define V3_NO_ADAT_OPT_IN_IFACE_B 0x00100000
+#define V3_NO_ADAT_OPT_OUT_IFACE_A 0x00040000
+#define V3_NO_ADAT_OPT_OUT_IFACE_B 0x00400000
+
+static int v3_get_clock_rate(struct snd_motu *motu, unsigned int *rate)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ data = (data & V3_CLOCK_RATE_MASK) >> V3_CLOCK_RATE_SHIFT;
+ if (data >= ARRAY_SIZE(snd_motu_clock_rates))
+ return -EIO;
+
+ *rate = snd_motu_clock_rates[data];
+
+ return 0;
+}
+
+static int v3_set_clock_rate(struct snd_motu *motu, unsigned int rate)
+{
+ __be32 reg;
+ u32 data;
+ bool need_to_wait;
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_motu_clock_rates); ++i) {
+ if (snd_motu_clock_rates[i] == rate)
+ break;
+ }
+ if (i == ARRAY_SIZE(snd_motu_clock_rates))
+ return -EINVAL;
+
+ err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ data &= ~(V3_CLOCK_RATE_MASK | V3_FETCH_PCM_FRAMES);
+ data |= i << V3_CLOCK_RATE_SHIFT;
+
+ need_to_wait = data != be32_to_cpu(reg);
+
+ reg = cpu_to_be32(data);
+ err = snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+
+ if (need_to_wait) {
+ /* Cost expensive. */
+ if (msleep_interruptible(4000) > 0)
+ return -EINTR;
+ }
+
+ return 0;
+}
+
+static int v3_get_clock_source(struct snd_motu *motu,
+ enum snd_motu_clock_source *src)
+{
+ __be32 reg;
+ u32 data;
+ unsigned int val;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ val = (data & V3_CLOCK_SOURCE_MASK) >> V3_CLOCK_SOURCE_SHIFT;
+ if (val == 0x00) {
+ *src = SND_MOTU_CLOCK_SOURCE_INTERNAL;
+ } else if (val == 0x01) {
+ *src = SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC;
+ } else if (val == 0x10) {
+ *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX;
+ } else if (val == 0x18 || val == 0x19) {
+ err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET,
+ &reg, sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ if (val == 0x18) {
+ if (data & V3_NO_ADAT_OPT_IN_IFACE_A)
+ *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A;
+ else
+ *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A;
+ } else {
+ if (data & V3_NO_ADAT_OPT_IN_IFACE_B)
+ *src = SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B;
+ else
+ *src = SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B;
+ }
+ } else {
+ *src = SND_MOTU_CLOCK_SOURCE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int v3_switch_fetching_mode(struct snd_motu *motu, bool enable)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return 0;
+ data = be32_to_cpu(reg);
+
+ if (enable)
+ data |= V3_FETCH_PCM_FRAMES;
+ else
+ data &= ~V3_FETCH_PCM_FRAMES;
+
+ reg = cpu_to_be32(data);
+ return snd_motu_transaction_write(motu, V3_CLOCK_STATUS_OFFSET, &reg,
+ sizeof(reg));
+}
+
+static void calculate_fixed_part(struct snd_motu_packet_format *formats,
+ enum amdtp_stream_direction dir,
+ enum snd_motu_spec_flags flags,
+ unsigned char analog_ports)
+{
+ unsigned char pcm_chunks[3] = {0, 0, 0};
+
+ formats->msg_chunks = 2;
+
+ pcm_chunks[0] = analog_ports;
+ pcm_chunks[1] = analog_ports;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ pcm_chunks[2] = analog_ports;
+
+ if (dir == AMDTP_IN_STREAM) {
+ if (flags & SND_MOTU_SPEC_TX_MICINST_CHUNK) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ pcm_chunks[2] += 2;
+ }
+
+ if (flags & SND_MOTU_SPEC_TX_RETURN_CHUNK) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ pcm_chunks[2] += 2;
+ }
+
+ if (flags & SND_MOTU_SPEC_TX_REVERB_CHUNK) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+ } else {
+ /*
+ * Packets to v2 units transfer main-out-1/2 and phone-out-1/2.
+ */
+ pcm_chunks[0] += 4;
+ pcm_chunks[1] += 4;
+ }
+
+ /*
+ * At least, packets have two data chunks for S/PDIF on coaxial
+ * interface.
+ */
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+
+ /*
+ * Fixed part consists of PCM chunks multiple of 4, with msg chunks. As
+ * a result, this part can includes empty data chunks.
+ */
+ formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2;
+ formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2;
+ if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
+ formats->fixed_part_pcm_chunks[2] =
+ round_up(2 + pcm_chunks[2], 4) - 2;
+}
+
+static void calculate_differed_part(struct snd_motu_packet_format *formats,
+ enum snd_motu_spec_flags flags, u32 data,
+ u32 a_enable_mask, u32 a_no_adat_mask,
+ u32 b_enable_mask, u32 b_no_adat_mask)
+{
+ unsigned char pcm_chunks[3] = {0, 0, 0};
+ int i;
+
+ if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_A) && (data & a_enable_mask)) {
+ if (data & a_no_adat_mask) {
+ /*
+ * Additional two data chunks for S/PDIF on optical
+ * interface A. This includes empty data chunks.
+ */
+ pcm_chunks[0] += 4;
+ pcm_chunks[1] += 4;
+ } else {
+ /*
+ * Additional data chunks for ADAT on optical interface
+ * A.
+ */
+ pcm_chunks[0] += 8;
+ pcm_chunks[1] += 4;
+ }
+ }
+
+ if ((flags & SND_MOTU_SPEC_HAS_OPT_IFACE_B) && (data & b_enable_mask)) {
+ if (data & b_no_adat_mask) {
+ /*
+ * Additional two data chunks for S/PDIF on optical
+ * interface B. This includes empty data chunks.
+ */
+ pcm_chunks[0] += 4;
+ pcm_chunks[1] += 4;
+ } else {
+ /*
+ * Additional data chunks for ADAT on optical interface
+ * B.
+ */
+ pcm_chunks[0] += 8;
+ pcm_chunks[1] += 4;
+ }
+ }
+
+ for (i = 0; i < 3; ++i) {
+ if (pcm_chunks[i] > 0)
+ pcm_chunks[i] = round_up(pcm_chunks[i], 4);
+
+ formats->differed_part_pcm_chunks[i] = pcm_chunks[i];
+ }
+}
+
+static int v3_cache_packet_formats(struct snd_motu *motu)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_motu_transaction_read(motu, V3_OPT_IFACE_MODE_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ calculate_fixed_part(&motu->tx_packet_formats, AMDTP_IN_STREAM,
+ motu->spec->flags, motu->spec->analog_in_ports);
+ calculate_differed_part(&motu->tx_packet_formats,
+ motu->spec->flags, data,
+ V3_ENABLE_OPT_IN_IFACE_A, V3_NO_ADAT_OPT_IN_IFACE_A,
+ V3_ENABLE_OPT_IN_IFACE_B, V3_NO_ADAT_OPT_IN_IFACE_B);
+
+ calculate_fixed_part(&motu->rx_packet_formats, AMDTP_OUT_STREAM,
+ motu->spec->flags, motu->spec->analog_out_ports);
+ calculate_differed_part(&motu->rx_packet_formats,
+ motu->spec->flags, data,
+ V3_ENABLE_OPT_OUT_IFACE_A, V3_NO_ADAT_OPT_OUT_IFACE_A,
+ V3_ENABLE_OPT_OUT_IFACE_B, V3_NO_ADAT_OPT_OUT_IFACE_B);
+
+ motu->tx_packet_formats.midi_flag_offset = 8;
+ motu->tx_packet_formats.midi_byte_offset = 7;
+ motu->tx_packet_formats.pcm_byte_offset = 10;
+
+ motu->rx_packet_formats.midi_flag_offset = 8;
+ motu->rx_packet_formats.midi_byte_offset = 7;
+ motu->rx_packet_formats.pcm_byte_offset = 10;
+
+ return 0;
+}
+
+const struct snd_motu_protocol snd_motu_protocol_v3 = {
+ .get_clock_rate = v3_get_clock_rate,
+ .set_clock_rate = v3_set_clock_rate,
+ .get_clock_source = v3_get_clock_source,
+ .switch_fetching_mode = v3_switch_fetching_mode,
+ .cache_packet_formats = v3_cache_packet_formats,
+};
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
new file mode 100644
index 000000000000..bd458029099e
--- /dev/null
+++ b/sound/firewire/motu/motu-stream.c
@@ -0,0 +1,381 @@
+/*
+ * motu-stream.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "motu.h"
+
+#define CALLBACK_TIMEOUT 200
+
+#define ISOC_COMM_CONTROL_OFFSET 0x0b00
+#define ISOC_COMM_CONTROL_MASK 0xffff0000
+#define CHANGE_RX_ISOC_COMM_STATE 0x80000000
+#define RX_ISOC_COMM_IS_ACTIVATED 0x40000000
+#define RX_ISOC_COMM_CHANNEL_MASK 0x3f000000
+#define RX_ISOC_COMM_CHANNEL_SHIFT 24
+#define CHANGE_TX_ISOC_COMM_STATE 0x00800000
+#define TX_ISOC_COMM_IS_ACTIVATED 0x00400000
+#define TX_ISOC_COMM_CHANNEL_MASK 0x003f0000
+#define TX_ISOC_COMM_CHANNEL_SHIFT 16
+
+#define PACKET_FORMAT_OFFSET 0x0b10
+#define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080
+#define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
+#define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f
+
+static int start_both_streams(struct snd_motu *motu, unsigned int rate)
+{
+ unsigned int midi_ports = 0;
+ __be32 reg;
+ u32 data;
+ int err;
+
+ if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI)
+ midi_ports = 1;
+
+ /* Set packet formation to our packet streaming engine. */
+ err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports,
+ &motu->rx_packet_formats);
+ if (err < 0)
+ return err;
+
+ err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports,
+ &motu->tx_packet_formats);
+ if (err < 0)
+ return err;
+
+ /* Get isochronous resources on the bus. */
+ err = fw_iso_resources_allocate(&motu->rx_resources,
+ amdtp_stream_get_max_payload(&motu->rx_stream),
+ fw_parent_device(motu->unit)->max_speed);
+ if (err < 0)
+ return err;
+
+ err = fw_iso_resources_allocate(&motu->tx_resources,
+ amdtp_stream_get_max_payload(&motu->tx_stream),
+ fw_parent_device(motu->unit)->max_speed);
+ if (err < 0)
+ return err;
+
+ /* Configure the unit to start isochronous communication. */
+ err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
+
+ data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
+ (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
+ CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
+ (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
+
+ reg = cpu_to_be32(data);
+ return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
+ sizeof(reg));
+}
+
+static void stop_both_streams(struct snd_motu *motu)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = motu->spec->protocol->switch_fetching_mode(motu, false);
+ if (err < 0)
+ return;
+
+ err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return;
+ data = be32_to_cpu(reg);
+
+ data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
+ data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
+
+ reg = cpu_to_be32(data);
+ snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
+ sizeof(reg));
+
+ fw_iso_resources_free(&motu->tx_resources);
+ fw_iso_resources_free(&motu->rx_resources);
+}
+
+static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
+{
+ struct fw_iso_resources *resources;
+ int err;
+
+ if (stream == &motu->rx_stream)
+ resources = &motu->rx_resources;
+ else
+ resources = &motu->tx_resources;
+
+ err = amdtp_stream_start(stream, resources->channel,
+ fw_parent_device(motu->unit)->max_speed);
+ if (err < 0)
+ return err;
+
+ if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
+ amdtp_stream_stop(stream);
+ fw_iso_resources_free(resources);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
+{
+ struct fw_iso_resources *resources;
+
+ if (stream == &motu->rx_stream)
+ resources = &motu->rx_resources;
+ else
+ resources = &motu->tx_resources;
+
+ amdtp_stream_stop(stream);
+ fw_iso_resources_free(resources);
+}
+
+static int ensure_packet_formats(struct snd_motu *motu)
+{
+ __be32 reg;
+ u32 data;
+ int err;
+
+ err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
+ sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
+ RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
+ TX_PACKET_TRANSMISSION_SPEED_MASK);
+ if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0)
+ data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
+ if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0)
+ data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
+ data |= fw_parent_device(motu->unit)->max_speed;
+
+ reg = cpu_to_be32(data);
+ return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
+ sizeof(reg));
+}
+
+int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
+{
+ const struct snd_motu_protocol *protocol = motu->spec->protocol;
+ unsigned int curr_rate;
+ int err = 0;
+
+ if (motu->capture_substreams == 0 && motu->playback_substreams == 0)
+ return 0;
+
+ /* Some packet queueing errors. */
+ if (amdtp_streaming_error(&motu->rx_stream) ||
+ amdtp_streaming_error(&motu->tx_stream)) {
+ amdtp_stream_stop(&motu->rx_stream);
+ amdtp_stream_stop(&motu->tx_stream);
+ stop_both_streams(motu);
+ }
+
+ err = protocol->cache_packet_formats(motu);
+ if (err < 0)
+ return err;
+
+ /* Stop stream if rate is different. */
+ err = protocol->get_clock_rate(motu, &curr_rate);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to get sampling rate: %d\n", err);
+ return err;
+ }
+ if (rate == 0)
+ rate = curr_rate;
+ if (rate != curr_rate) {
+ amdtp_stream_stop(&motu->rx_stream);
+ amdtp_stream_stop(&motu->tx_stream);
+ stop_both_streams(motu);
+ }
+
+ if (!amdtp_stream_running(&motu->rx_stream)) {
+ err = protocol->set_clock_rate(motu, rate);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to set sampling rate: %d\n", err);
+ return err;
+ }
+
+ err = ensure_packet_formats(motu);
+ if (err < 0)
+ return err;
+
+ err = start_both_streams(motu, rate);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to start isochronous comm: %d\n", err);
+ stop_both_streams(motu);
+ return err;
+ }
+
+ err = start_isoc_ctx(motu, &motu->rx_stream);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to start IT context: %d\n", err);
+ stop_both_streams(motu);
+ return err;
+ }
+
+ err = protocol->switch_fetching_mode(motu, true);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to enable frame fetching: %d\n", err);
+ stop_both_streams(motu);
+ return err;
+ }
+ }
+
+ if (!amdtp_stream_running(&motu->tx_stream) &&
+ motu->capture_substreams > 0) {
+ err = start_isoc_ctx(motu, &motu->tx_stream);
+ if (err < 0) {
+ dev_err(&motu->unit->device,
+ "fail to start IR context: %d", err);
+ amdtp_stream_stop(&motu->rx_stream);
+ stop_both_streams(motu);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+void snd_motu_stream_stop_duplex(struct snd_motu *motu)
+{
+ if (motu->capture_substreams == 0) {
+ if (amdtp_stream_running(&motu->tx_stream))
+ stop_isoc_ctx(motu, &motu->tx_stream);
+
+ if (motu->playback_substreams == 0) {
+ if (amdtp_stream_running(&motu->rx_stream))
+ stop_isoc_ctx(motu, &motu->rx_stream);
+ stop_both_streams(motu);
+ }
+ }
+}
+
+static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir)
+{
+ int err;
+ struct amdtp_stream *stream;
+ struct fw_iso_resources *resources;
+
+ if (dir == AMDTP_IN_STREAM) {
+ stream = &motu->tx_stream;
+ resources = &motu->tx_resources;
+ } else {
+ stream = &motu->rx_stream;
+ resources = &motu->rx_resources;
+ }
+
+ err = fw_iso_resources_init(resources, motu->unit);
+ if (err < 0)
+ return err;
+
+ err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol);
+ if (err < 0) {
+ amdtp_stream_destroy(stream);
+ fw_iso_resources_destroy(resources);
+ }
+
+ return err;
+}
+
+static void destroy_stream(struct snd_motu *motu,
+ enum amdtp_stream_direction dir)
+{
+ struct amdtp_stream *stream;
+ struct fw_iso_resources *resources;
+
+ if (dir == AMDTP_IN_STREAM) {
+ stream = &motu->tx_stream;
+ resources = &motu->tx_resources;
+ } else {
+ stream = &motu->rx_stream;
+ resources = &motu->rx_resources;
+ }
+
+ amdtp_stream_destroy(stream);
+ fw_iso_resources_free(resources);
+}
+
+int snd_motu_stream_init_duplex(struct snd_motu *motu)
+{
+ int err;
+
+ err = init_stream(motu, AMDTP_IN_STREAM);
+ if (err < 0)
+ return err;
+
+ err = init_stream(motu, AMDTP_OUT_STREAM);
+ if (err < 0)
+ destroy_stream(motu, AMDTP_IN_STREAM);
+
+ return err;
+}
+
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
+void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
+{
+ destroy_stream(motu, AMDTP_IN_STREAM);
+ destroy_stream(motu, AMDTP_OUT_STREAM);
+
+ motu->playback_substreams = 0;
+ motu->capture_substreams = 0;
+}
+
+static void motu_lock_changed(struct snd_motu *motu)
+{
+ motu->dev_lock_changed = true;
+ wake_up(&motu->hwdep_wait);
+}
+
+int snd_motu_stream_lock_try(struct snd_motu *motu)
+{
+ int err;
+
+ spin_lock_irq(&motu->lock);
+
+ if (motu->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (motu->dev_lock_count++ == 0)
+ motu_lock_changed(motu);
+ err = 0;
+out:
+ spin_unlock_irq(&motu->lock);
+ return err;
+}
+
+void snd_motu_stream_lock_release(struct snd_motu *motu)
+{
+ spin_lock_irq(&motu->lock);
+
+ if (WARN_ON(motu->dev_lock_count <= 0))
+ goto out;
+
+ if (--motu->dev_lock_count == 0)
+ motu_lock_changed(motu);
+out:
+ spin_unlock_irq(&motu->lock);
+}
diff --git a/sound/firewire/motu/motu-transaction.c b/sound/firewire/motu/motu-transaction.c
new file mode 100644
index 000000000000..7fc30091e0de
--- /dev/null
+++ b/sound/firewire/motu/motu-transaction.c
@@ -0,0 +1,137 @@
+/*
+ * motu-transaction.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+
+#include "motu.h"
+
+#define SND_MOTU_ADDR_BASE 0xfffff0000000ULL
+#define ASYNC_ADDR_HI 0x0b04
+#define ASYNC_ADDR_LO 0x0b08
+
+int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
+ size_t size)
+{
+ int tcode;
+
+ if (size % sizeof(__be32) > 0 || size <= 0)
+ return -EINVAL;
+ if (size == sizeof(__be32))
+ tcode = TCODE_READ_QUADLET_REQUEST;
+ else
+ tcode = TCODE_READ_BLOCK_REQUEST;
+
+ return snd_fw_transaction(motu->unit, tcode,
+ SND_MOTU_ADDR_BASE + offset, reg, size, 0);
+}
+
+int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
+ size_t size)
+{
+ int tcode;
+
+ if (size % sizeof(__be32) > 0 || size <= 0)
+ return -EINVAL;
+ if (size == sizeof(__be32))
+ tcode = TCODE_WRITE_QUADLET_REQUEST;
+ else
+ tcode = TCODE_WRITE_BLOCK_REQUEST;
+
+ return snd_fw_transaction(motu->unit, tcode,
+ SND_MOTU_ADDR_BASE + offset, reg, size, 0);
+}
+
+static void handle_message(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, unsigned long long offset,
+ void *data, size_t length, void *callback_data)
+{
+ struct snd_motu *motu = callback_data;
+ __be32 *buf = (__be32 *)data;
+ unsigned long flags;
+
+ if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
+ fw_send_response(card, request, RCODE_COMPLETE);
+ return;
+ }
+
+ if (offset != motu->async_handler.offset || length != 4) {
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ return;
+ }
+
+ spin_lock_irqsave(&motu->lock, flags);
+ motu->msg = be32_to_cpu(*buf);
+ spin_unlock_irqrestore(&motu->lock, flags);
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+
+ wake_up(&motu->hwdep_wait);
+}
+
+int snd_motu_transaction_reregister(struct snd_motu *motu)
+{
+ struct fw_device *device = fw_parent_device(motu->unit);
+ __be32 data;
+ int err;
+
+ if (motu->async_handler.callback_data == NULL)
+ return -EINVAL;
+
+ /* Register messaging address. Block transaction is not allowed. */
+ data = cpu_to_be32((device->card->node_id << 16) |
+ (motu->async_handler.offset >> 32));
+ err = snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data,
+ sizeof(data));
+ if (err < 0)
+ return err;
+
+ data = cpu_to_be32(motu->async_handler.offset);
+ return snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data,
+ sizeof(data));
+}
+
+int snd_motu_transaction_register(struct snd_motu *motu)
+{
+ static const struct fw_address_region resp_register_region = {
+ .start = 0xffffe0000000ull,
+ .end = 0xffffe000ffffull,
+ };
+ int err;
+
+ /* Perhaps, 4 byte messages are transferred. */
+ motu->async_handler.length = 4;
+ motu->async_handler.address_callback = handle_message;
+ motu->async_handler.callback_data = motu;
+
+ err = fw_core_add_address_handler(&motu->async_handler,
+ &resp_register_region);
+ if (err < 0)
+ return err;
+
+ err = snd_motu_transaction_reregister(motu);
+ if (err < 0) {
+ fw_core_remove_address_handler(&motu->async_handler);
+ motu->async_handler.address_callback = NULL;
+ }
+
+ return err;
+}
+
+void snd_motu_transaction_unregister(struct snd_motu *motu)
+{
+ __be32 data;
+
+ if (motu->async_handler.address_callback != NULL)
+ fw_core_remove_address_handler(&motu->async_handler);
+ motu->async_handler.address_callback = NULL;
+
+ /* Unregister the address. */
+ data = cpu_to_be32(0x00000000);
+ snd_motu_transaction_write(motu, ASYNC_ADDR_HI, &data, sizeof(data));
+ snd_motu_transaction_write(motu, ASYNC_ADDR_LO, &data, sizeof(data));
+}
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
new file mode 100644
index 000000000000..bf779cfeef0d
--- /dev/null
+++ b/sound/firewire/motu/motu.c
@@ -0,0 +1,264 @@
+/*
+ * motu.c - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "motu.h"
+
+#define OUI_MOTU 0x0001f2
+
+MODULE_DESCRIPTION("MOTU FireWire driver");
+MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
+MODULE_LICENSE("GPL v2");
+
+const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = {
+ /* mode 0 */
+ [0] = 44100,
+ [1] = 48000,
+ /* mode 1 */
+ [2] = 88200,
+ [3] = 96000,
+ /* mode 2 */
+ [4] = 176400,
+ [5] = 192000,
+};
+
+static void name_card(struct snd_motu *motu)
+{
+ struct fw_device *fw_dev = fw_parent_device(motu->unit);
+ struct fw_csr_iterator it;
+ int key, val;
+ u32 version = 0;
+
+ fw_csr_iterator_init(&it, motu->unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &val)) {
+ switch (key) {
+ case CSR_VERSION:
+ version = val;
+ break;
+ }
+ }
+
+ strcpy(motu->card->driver, "FW-MOTU");
+ strcpy(motu->card->shortname, motu->spec->name);
+ strcpy(motu->card->mixername, motu->spec->name);
+ snprintf(motu->card->longname, sizeof(motu->card->longname),
+ "MOTU %s (version:%d), GUID %08x%08x at %s, S%d",
+ motu->spec->name, version,
+ fw_dev->config_rom[3], fw_dev->config_rom[4],
+ dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
+}
+
+static void motu_free(struct snd_motu *motu)
+{
+ snd_motu_transaction_unregister(motu);
+
+ snd_motu_stream_destroy_duplex(motu);
+ fw_unit_put(motu->unit);
+
+ mutex_destroy(&motu->mutex);
+ kfree(motu);
+}
+
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
+static void motu_card_free(struct snd_card *card)
+{
+ motu_free(card->private_data);
+}
+
+static void do_registration(struct work_struct *work)
+{
+ struct snd_motu *motu = container_of(work, struct snd_motu, dwork.work);
+ int err;
+
+ if (motu->registered)
+ return;
+
+ err = snd_card_new(&motu->unit->device, -1, NULL, THIS_MODULE, 0,
+ &motu->card);
+ if (err < 0)
+ return;
+
+ name_card(motu);
+
+ err = snd_motu_transaction_register(motu);
+ if (err < 0)
+ goto error;
+
+ err = snd_motu_stream_init_duplex(motu);
+ if (err < 0)
+ goto error;
+
+ snd_motu_proc_init(motu);
+
+ err = snd_motu_create_pcm_devices(motu);
+ if (err < 0)
+ goto error;
+
+ if (motu->spec->flags & SND_MOTU_SPEC_HAS_MIDI) {
+ err = snd_motu_create_midi_devices(motu);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_motu_create_hwdep_device(motu);
+ if (err < 0)
+ goto error;
+
+ err = snd_card_register(motu->card);
+ if (err < 0)
+ goto error;
+
+ /*
+ * After registered, motu instance can be released corresponding to
+ * releasing the sound card instance.
+ */
+ motu->card->private_free = motu_card_free;
+ motu->card->private_data = motu;
+ motu->registered = true;
+
+ return;
+error:
+ snd_motu_transaction_unregister(motu);
+ snd_card_free(motu->card);
+ dev_info(&motu->unit->device,
+ "Sound card registration failed: %d\n", err);
+}
+
+static int motu_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *entry)
+{
+ struct snd_motu *motu;
+
+ /* Allocate this independently of sound card instance. */
+ motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
+ if (motu == NULL)
+ return -ENOMEM;
+
+ motu->spec = (const struct snd_motu_spec *)entry->driver_data;
+ motu->unit = fw_unit_get(unit);
+ dev_set_drvdata(&unit->device, motu);
+
+ mutex_init(&motu->mutex);
+ spin_lock_init(&motu->lock);
+ init_waitqueue_head(&motu->hwdep_wait);
+
+ /* Allocate and register this sound card later. */
+ INIT_DEFERRABLE_WORK(&motu->dwork, do_registration);
+ snd_fw_schedule_registration(unit, &motu->dwork);
+
+ return 0;
+}
+
+static void motu_remove(struct fw_unit *unit)
+{
+ struct snd_motu *motu = dev_get_drvdata(&unit->device);
+
+ /*
+ * Confirm to stop the work for registration before the sound card is
+ * going to be released. The work is not scheduled again because bus
+ * reset handler is not called anymore.
+ */
+ cancel_delayed_work_sync(&motu->dwork);
+
+ if (motu->registered) {
+ /* No need to wait for releasing card object in this context. */
+ snd_card_free_when_closed(motu->card);
+ } else {
+ /* Don't forget this case. */
+ motu_free(motu);
+ }
+}
+
+static void motu_bus_update(struct fw_unit *unit)
+{
+ struct snd_motu *motu = dev_get_drvdata(&unit->device);
+
+ /* Postpone a workqueue for deferred registration. */
+ if (!motu->registered)
+ snd_fw_schedule_registration(unit, &motu->dwork);
+
+ /* The handler address register becomes initialized. */
+ snd_motu_transaction_reregister(motu);
+}
+
+static struct snd_motu_spec motu_828mk2 = {
+ .name = "828mk2",
+ .protocol = &snd_motu_protocol_v2,
+ .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
+ SND_MOTU_SPEC_TX_MICINST_CHUNK |
+ SND_MOTU_SPEC_TX_RETURN_CHUNK |
+ SND_MOTU_SPEC_HAS_OPT_IFACE_A |
+ SND_MOTU_SPEC_HAS_MIDI,
+
+ .analog_in_ports = 8,
+ .analog_out_ports = 8,
+};
+
+static struct snd_motu_spec motu_828mk3 = {
+ .name = "828mk3",
+ .protocol = &snd_motu_protocol_v3,
+ .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
+ SND_MOTU_SPEC_SUPPORT_CLOCK_X4 |
+ SND_MOTU_SPEC_TX_MICINST_CHUNK |
+ SND_MOTU_SPEC_TX_RETURN_CHUNK |
+ SND_MOTU_SPEC_TX_REVERB_CHUNK |
+ SND_MOTU_SPEC_HAS_OPT_IFACE_A |
+ SND_MOTU_SPEC_HAS_OPT_IFACE_B |
+ SND_MOTU_SPEC_HAS_MIDI,
+
+ .analog_in_ports = 8,
+ .analog_out_ports = 8,
+};
+
+#define SND_MOTU_DEV_ENTRY(model, data) \
+{ \
+ .match_flags = IEEE1394_MATCH_VENDOR_ID | \
+ IEEE1394_MATCH_MODEL_ID | \
+ IEEE1394_MATCH_SPECIFIER_ID, \
+ .vendor_id = OUI_MOTU, \
+ .model_id = model, \
+ .specifier_id = OUI_MOTU, \
+ .driver_data = (kernel_ulong_t)data, \
+}
+
+static const struct ieee1394_device_id motu_id_table[] = {
+ SND_MOTU_DEV_ENTRY(0x101800, &motu_828mk2),
+ SND_MOTU_DEV_ENTRY(0x106800, &motu_828mk3), /* FireWire only. */
+ SND_MOTU_DEV_ENTRY(0x100800, &motu_828mk3), /* Hybrid. */
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, motu_id_table);
+
+static struct fw_driver motu_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = motu_probe,
+ .update = motu_bus_update,
+ .remove = motu_remove,
+ .id_table = motu_id_table,
+};
+
+static int __init alsa_motu_init(void)
+{
+ return driver_register(&motu_driver.driver);
+}
+
+static void __exit alsa_motu_exit(void)
+{
+ driver_unregister(&motu_driver.driver);
+}
+
+module_init(alsa_motu_init);
+module_exit(alsa_motu_exit);
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
new file mode 100644
index 000000000000..8d6a4a3af9cc
--- /dev/null
+++ b/sound/firewire/motu/motu.h
@@ -0,0 +1,161 @@
+/*
+ * motu.h - a part of driver for MOTU FireWire series
+ *
+ * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef SOUND_FIREWIRE_MOTU_H_INCLUDED
+#define SOUND_FIREWIRE_MOTU_H_INCLUDED
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#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>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/rawmidi.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+
+#include "../lib.h"
+#include "../amdtp-stream.h"
+#include "../iso-resources.h"
+
+struct snd_motu_packet_format {
+ unsigned char midi_flag_offset;
+ unsigned char midi_byte_offset;
+ unsigned char pcm_byte_offset;
+
+ unsigned char msg_chunks;
+ unsigned char fixed_part_pcm_chunks[3];
+ unsigned char differed_part_pcm_chunks[3];
+};
+
+struct snd_motu {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ struct mutex mutex;
+ spinlock_t lock;
+
+ bool registered;
+ struct delayed_work dwork;
+
+ /* Model dependent information. */
+ const struct snd_motu_spec *spec;
+
+ /* For packet streaming */
+ struct snd_motu_packet_format tx_packet_formats;
+ struct snd_motu_packet_format rx_packet_formats;
+ struct amdtp_stream tx_stream;
+ struct amdtp_stream rx_stream;
+ struct fw_iso_resources tx_resources;
+ struct fw_iso_resources rx_resources;
+ unsigned int capture_substreams;
+ unsigned int playback_substreams;
+
+ /* For notification. */
+ struct fw_address_handler async_handler;
+ u32 msg;
+
+ /* For uapi */
+ int dev_lock_count;
+ bool dev_lock_changed;
+ wait_queue_head_t hwdep_wait;
+};
+
+enum snd_motu_spec_flags {
+ SND_MOTU_SPEC_SUPPORT_CLOCK_X2 = 0x0001,
+ SND_MOTU_SPEC_SUPPORT_CLOCK_X4 = 0x0002,
+ SND_MOTU_SPEC_TX_MICINST_CHUNK = 0x0004,
+ SND_MOTU_SPEC_TX_RETURN_CHUNK = 0x0008,
+ SND_MOTU_SPEC_TX_REVERB_CHUNK = 0x0010,
+ SND_MOTU_SPEC_TX_AESEBU_CHUNK = 0x0020,
+ SND_MOTU_SPEC_HAS_OPT_IFACE_A = 0x0040,
+ SND_MOTU_SPEC_HAS_OPT_IFACE_B = 0x0080,
+ SND_MOTU_SPEC_HAS_MIDI = 0x0100,
+};
+
+#define SND_MOTU_CLOCK_RATE_COUNT 6
+extern const unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT];
+
+enum snd_motu_clock_source {
+ SND_MOTU_CLOCK_SOURCE_INTERNAL,
+ SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB,
+ SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT,
+ SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A,
+ SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B,
+ SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT,
+ SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A,
+ SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B,
+ SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX,
+ SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR,
+ SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC,
+ SND_MOTU_CLOCK_SOURCE_UNKNOWN,
+};
+
+struct snd_motu_protocol {
+ int (*get_clock_rate)(struct snd_motu *motu, unsigned int *rate);
+ int (*set_clock_rate)(struct snd_motu *motu, unsigned int rate);
+ int (*get_clock_source)(struct snd_motu *motu,
+ enum snd_motu_clock_source *source);
+ int (*switch_fetching_mode)(struct snd_motu *motu, bool enable);
+ int (*cache_packet_formats)(struct snd_motu *motu);
+};
+
+struct snd_motu_spec {
+ const char *const name;
+ enum snd_motu_spec_flags flags;
+
+ unsigned char analog_in_ports;
+ unsigned char analog_out_ports;
+
+ const struct snd_motu_protocol *const protocol;
+};
+
+extern const struct snd_motu_protocol snd_motu_protocol_v2;
+extern const struct snd_motu_protocol snd_motu_protocol_v3;
+
+int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
+ enum amdtp_stream_direction dir,
+ const struct snd_motu_protocol *const protocol);
+int amdtp_motu_set_parameters(struct amdtp_stream *s, unsigned int rate,
+ unsigned int midi_ports,
+ struct snd_motu_packet_format *formats);
+int amdtp_motu_add_pcm_hw_constraints(struct amdtp_stream *s,
+ struct snd_pcm_runtime *runtime);
+void amdtp_motu_midi_trigger(struct amdtp_stream *s, unsigned int port,
+ struct snd_rawmidi_substream *midi);
+
+int snd_motu_transaction_read(struct snd_motu *motu, u32 offset, __be32 *reg,
+ size_t size);
+int snd_motu_transaction_write(struct snd_motu *motu, u32 offset, __be32 *reg,
+ size_t size);
+int snd_motu_transaction_register(struct snd_motu *motu);
+int snd_motu_transaction_reregister(struct snd_motu *motu);
+void snd_motu_transaction_unregister(struct snd_motu *motu);
+
+int snd_motu_stream_init_duplex(struct snd_motu *motu);
+void snd_motu_stream_destroy_duplex(struct snd_motu *motu);
+int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate);
+void snd_motu_stream_stop_duplex(struct snd_motu *motu);
+int snd_motu_stream_lock_try(struct snd_motu *motu);
+void snd_motu_stream_lock_release(struct snd_motu *motu);
+
+void snd_motu_proc_init(struct snd_motu *motu);
+
+int snd_motu_create_pcm_devices(struct snd_motu *motu);
+
+int snd_motu_create_midi_devices(struct snd_motu *motu);
+
+int snd_motu_create_hwdep_device(struct snd_motu *motu);
+#endif
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 043065867656..d15b653de0bf 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -272,7 +272,7 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
/* Lets walk the linked capabilities list */
do {
- cur_cap = _snd_hdac_chip_read(l, bus, offset);
+ cur_cap = _snd_hdac_chip_readl(bus, offset);
dev_dbg(bus->dev, "Capability version: 0x%x\n",
(cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index c6994ebb4567..e1472c7ab6c1 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -555,12 +555,12 @@ void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set,
if (!reg)
reg = AZX_REG_SSYNC;
- val = _snd_hdac_chip_read(l, bus, reg);
+ val = _snd_hdac_chip_readl(bus, reg);
if (set)
val |= streams;
else
val &= ~streams;
- _snd_hdac_chip_write(l, bus, reg, val);
+ _snd_hdac_chip_writel(bus, reg, val);
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_sync_trigger);
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index e2cf508841b1..81cf26fa28d6 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -742,7 +742,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)
pcm->private_data = chip;
pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
- sprintf(pcm->name, snd_es1688_chip_id(chip));
+ strcpy(pcm->name, snd_es1688_chip_id(chip));
chip->pcm = pcm;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index ab0f87312911..7a4558a70fb9 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -846,7 +846,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new vortex_a3d_kcontrol = {
+static const struct snd_kcontrol_new vortex_a3d_kcontrol = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Playback PCM advanced processing",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index e1af24f87566..c308a4f70550 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2279,6 +2279,9 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
} else {
int src[2], mix[2];
+ if (nr_ch < 1)
+ return -EINVAL;
+
/* Get SRC and MIXER hardware resources. */
for (i = 0; i < nr_ch; i++) {
if ((mix[i] =
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 9585c5c63b96..b566b44e4da7 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -757,7 +757,7 @@ snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol,
return 1; /* Allways changes */
}
-static struct snd_kcontrol_new vortex_eqtoggle_kcontrol = {
+static const struct snd_kcontrol_new vortex_eqtoggle_kcontrol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "EQ Enable",
.index = 0,
@@ -815,7 +815,7 @@ snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon
return changed;
}
-static struct snd_kcontrol_new vortex_eq_kcontrol = {
+static const struct snd_kcontrol_new vortex_eq_kcontrol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = " .",
.index = 0,
@@ -855,7 +855,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
return 0;
}
-static struct snd_kcontrol_new vortex_levels_kcontrol = {
+static const struct snd_kcontrol_new vortex_levels_kcontrol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "EQ Peaks",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index df5741a78fd2..335979a753fe 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -601,7 +601,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
-static struct snd_kcontrol_new snd_vortex_pcm_vol = {
+static const struct snd_kcontrol_new snd_vortex_pcm_vol = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PCM Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 57bbb87d0c62..8356180bfe0e 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -202,7 +202,7 @@ static const struct snd_pcm_ops snd_aw2_capture_ops = {
.pointer = snd_aw2_pcm_pointer_capture,
};
-static struct snd_kcontrol_new aw2_control = {
+static const struct snd_kcontrol_new aw2_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Capture Route",
.index = 0,
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index f2c0709d7441..099efb046b1c 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -598,7 +598,7 @@ static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_bt87x_capture_volume = {
+static const struct snd_kcontrol_new snd_bt87x_capture_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Volume",
.info = snd_bt87x_capture_volume_info,
@@ -634,7 +634,7 @@ static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_bt87x_capture_boost = {
+static const struct snd_kcontrol_new snd_bt87x_capture_boost = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Boost",
.info = snd_bt87x_capture_boost_info,
@@ -676,7 +676,7 @@ static int snd_bt87x_capture_source_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_bt87x_capture_source = {
+static const struct snd_kcontrol_new snd_bt87x_capture_source = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = snd_bt87x_capture_source_info,
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 025805cba779..b4d3415331f6 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -301,7 +301,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
+static const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Shared Mic/Line in Capture Switch",
@@ -310,7 +310,7 @@ static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
.put = snd_ca0106_capture_mic_line_in_put
};
-static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out =
+static const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Shared Line in/Side out Capture Switch",
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index aeedc270ed9b..227c9d3802b8 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -1045,7 +1045,7 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_cmipci_spdif_default =
+static const struct snd_kcontrol_new snd_cmipci_spdif_default =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1072,7 +1072,7 @@ static int snd_cmipci_spdif_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_cmipci_spdif_mask =
+static const struct snd_kcontrol_new snd_cmipci_spdif_mask =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1119,7 +1119,7 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_cmipci_spdif_stream =
+static const struct snd_kcontrol_new snd_cmipci_spdif_stream =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index fa7c51684dd2..f870697aca67 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1055,7 +1055,7 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);
-static struct snd_kcontrol_new snd_cs4281_fm_vol =
+static const struct snd_kcontrol_new snd_cs4281_fm_vol =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Synth Playback Volume",
@@ -1066,7 +1066,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol =
.tlv = { .p = db_scale_dsp },
};
-static struct snd_kcontrol_new snd_cs4281_pcm_vol =
+static const struct snd_kcontrol_new snd_cs4281_pcm_vol =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Stream Playback Volume",
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 937071760bc4..d15ecf9febbf 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1039,7 +1039,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
#ifdef ECHOCARD_HAS_LINE_OUT_GAIN
/* On the Mia this one controls the line-out volume */
-static struct snd_kcontrol_new snd_echo_line_output_gain = {
+static const struct snd_kcontrol_new snd_echo_line_output_gain = {
.name = "Line Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -1050,7 +1050,7 @@ static struct snd_kcontrol_new snd_echo_line_output_gain = {
.tlv = {.p = db_scale_output_gain},
};
#else
-static struct snd_kcontrol_new snd_echo_pcm_output_gain = {
+static const struct snd_kcontrol_new snd_echo_pcm_output_gain = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -1120,7 +1120,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0);
-static struct snd_kcontrol_new snd_echo_line_input_gain = {
+static const struct snd_kcontrol_new snd_echo_line_input_gain = {
.name = "Line Capture Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -1184,7 +1184,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_output_nominal_level = {
+static const struct snd_kcontrol_new snd_echo_output_nominal_level = {
.name = "Line Playback Switch (-10dBV)",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_echo_output_nominal_info,
@@ -1250,7 +1250,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_intput_nominal_level = {
+static const struct snd_kcontrol_new snd_echo_intput_nominal_level = {
.name = "Line Capture Switch (-10dBV)",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_echo_input_nominal_info,
@@ -1477,7 +1477,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_digital_mode_switch = {
+static const struct snd_kcontrol_new snd_echo_digital_mode_switch = {
.name = "Digital mode Switch",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = snd_echo_digital_mode_info,
@@ -1527,7 +1527,7 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_echo_spdif_mode_switch = {
+static const struct snd_kcontrol_new snd_echo_spdif_mode_switch = {
.name = "S/PDIF mode Switch",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = snd_echo_spdif_mode_info,
@@ -1600,7 +1600,7 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_clock_source_switch = {
+static const struct snd_kcontrol_new snd_echo_clock_source_switch = {
.name = "Sample Clock Source",
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.info = snd_echo_clock_source_info,
@@ -1643,7 +1643,7 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_phantom_power_switch = {
+static const struct snd_kcontrol_new snd_echo_phantom_power_switch = {
.name = "Phantom power Switch",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = snd_echo_phantom_power_info,
@@ -1686,7 +1686,7 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_echo_automute_switch = {
+static const struct snd_kcontrol_new snd_echo_automute_switch = {
.name = "Digital Capture Switch (automute)",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = snd_echo_automute_info,
@@ -1713,7 +1713,7 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static struct snd_kcontrol_new snd_echo_vumeters_switch = {
+static const struct snd_kcontrol_new snd_echo_vumeters_switch = {
.name = "VU-meters Switch",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.access = SNDRV_CTL_ELEM_ACCESS_WRITE,
@@ -1751,7 +1751,7 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_echo_vumeters = {
+static const struct snd_kcontrol_new snd_echo_vumeters = {
.name = "VU-meters",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READ |
@@ -1804,7 +1804,7 @@ static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_echo_channels_info = {
+static const struct snd_kcontrol_new snd_echo_channels_info = {
.name = "Channels info",
.iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 32842734ada6..77a4413f4564 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1112,7 +1112,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
+static const struct snd_kcontrol_new snd_emu10k1x_shared_spdif =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Analog/Digital Output Jack",
@@ -1171,7 +1171,7 @@ static int snd_emu10k1x_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control =
+static const struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1181,7 +1181,7 @@ static struct snd_kcontrol_new snd_emu10k1x_spdif_mask_control =
.get = snd_emu10k1x_spdif_get_mask
};
-static struct snd_kcontrol_new snd_emu10k1x_spdif_control =
+static const struct snd_kcontrol_new snd_emu10k1x_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 076b117009c5..b2219a73c17c 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -795,7 +795,7 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu1010_internal_clock =
+static const struct snd_kcontrol_new snd_emu1010_internal_clock =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -847,7 +847,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu1010_optical_out = {
+static const struct snd_kcontrol_new snd_emu1010_optical_out = {
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Optical Output Mode",
@@ -898,7 +898,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu1010_optical_in = {
+static const struct snd_kcontrol_new snd_emu1010_optical_in = {
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Optical Input Mode",
@@ -978,7 +978,7 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
+static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
@@ -1177,7 +1177,7 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
+static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1187,7 +1187,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
.get = snd_emu10k1_spdif_get_mask
};
-static struct snd_kcontrol_new snd_emu10k1_spdif_control =
+static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1293,7 +1293,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
+static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1364,7 +1364,7 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
+static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1429,7 +1429,7 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_attn_control =
+static const struct snd_kcontrol_new snd_emu10k1_attn_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1501,7 +1501,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
+static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1568,7 +1568,7 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
}
-static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
+static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1626,7 +1626,7 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
+static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1691,7 +1691,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_shared_spdif =
+static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SB Live Analog/Digital Output Jack",
@@ -1700,7 +1700,7 @@ static struct snd_kcontrol_new snd_emu10k1_shared_spdif =
.put = snd_emu10k1_shared_spdif_put
};
-static struct snd_kcontrol_new snd_audigy_shared_spdif =
+static const struct snd_kcontrol_new snd_audigy_shared_spdif =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Audigy Analog/Digital Output Jack",
@@ -1738,7 +1738,7 @@ static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
}
-static struct snd_kcontrol_new snd_audigy_capture_boost =
+static const struct snd_kcontrol_new snd_audigy_capture_boost =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mic Extra Boost",
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 37be1e14d756..ef1cf530c929 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1542,7 +1542,7 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st
return change;
}
-static struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = {
+static const struct snd_kcontrol_new snd_emu10k1_pcm_efx_voices_mask = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Captured FX8010 Outputs",
.info = snd_emu10k1_pcm_efx_voices_mask_info,
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 164adad91650..5d10349d11ce 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1530,7 +1530,7 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ens1373_rear =
+static const struct snd_kcontrol_new snd_ens1373_rear =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "AC97 2ch->4ch Copy Switch",
@@ -1575,7 +1575,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new snd_ens1373_line =
+static const struct snd_kcontrol_new snd_ens1373_line =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Line In->Rear Out Switch",
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8fd745cb3f36..70bb365a08d2 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1965,7 +1965,7 @@ static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static struct snd_kcontrol_new vmaster_mute_mode = {
+static const struct snd_kcontrol_new vmaster_mute_mode = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Mute-LED Mode",
.info = vmaster_mute_mode_info,
@@ -2705,7 +2705,7 @@ static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new spdif_share_sw = {
+static const struct snd_kcontrol_new spdif_share_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "IEC958 Default PCM Playback Switch",
.info = snd_ctl_boolean_mono_info,
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c8256a89375a..64db6698214c 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -77,6 +77,7 @@ enum {
POS_FIX_POSBUF,
POS_FIX_VIACOMBO,
POS_FIX_COMBO,
+ POS_FIX_SKL,
};
/* Defines for ATI HD Audio support in SB450 south bridge */
@@ -148,7 +149,7 @@ module_param_array(model, charp, NULL, 0444);
MODULE_PARM_DESC(model, "Use the given board model.");
module_param_array(position_fix, int, NULL, 0444);
MODULE_PARM_DESC(position_fix, "DMA pointer read method."
- "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+ "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+).");
module_param_array(bdl_pos_adj, int, NULL, 0644);
MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
module_param_array(probe_mask, int, NULL, 0444);
@@ -534,9 +535,9 @@ static void bxt_reduce_dma_latency(struct azx *chip)
{
u32 val;
- val = azx_readl(chip, SKL_EM4L);
+ val = azx_readl(chip, VS_EM4L);
val &= (0x3 << 20);
- azx_writel(chip, SKL_EM4L, val);
+ azx_writel(chip, VS_EM4L, val);
}
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
@@ -815,6 +816,31 @@ static unsigned int azx_via_get_position(struct azx *chip,
return bound_pos + mod_dma_pos;
}
+static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
+ struct azx_dev *azx_dev)
+{
+ return _snd_hdac_chip_readl(azx_bus(chip),
+ AZX_REG_VS_SDXDPIB_XBASE +
+ (AZX_REG_VS_SDXDPIB_XINTERVAL *
+ azx_dev->core.index));
+}
+
+/* get the current DMA position with correction on SKL+ chips */
+static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev)
+{
+ /* DPIB register gives a more accurate position for playback */
+ if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return azx_skl_get_dpib_pos(chip, azx_dev);
+
+ /* For capture, we need to read posbuf, but it requires a delay
+ * for the possible boundary overlap; the read of DPIB fetches the
+ * actual posbuf
+ */
+ udelay(20);
+ azx_skl_get_dpib_pos(chip, azx_dev);
+ return azx_get_pos_posbuf(chip, azx_dev);
+}
+
#ifdef CONFIG_PM
static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);
@@ -1351,6 +1377,7 @@ static int check_position_fix(struct azx *chip, int fix)
case POS_FIX_POSBUF:
case POS_FIX_VIACOMBO:
case POS_FIX_COMBO:
+ case POS_FIX_SKL:
return fix;
}
@@ -1371,6 +1398,10 @@ static int check_position_fix(struct azx *chip, int fix)
dev_dbg(chip->card->dev, "Using LPIB position fix\n");
return POS_FIX_LPIB;
}
+ if (IS_SKL_PLUS(chip->pci)) {
+ dev_dbg(chip->card->dev, "Using SKL position fix\n");
+ return POS_FIX_SKL;
+ }
return POS_FIX_AUTO;
}
@@ -1382,6 +1413,7 @@ static void assign_position_fix(struct azx *chip, int fix)
[POS_FIX_POSBUF] = azx_get_pos_posbuf,
[POS_FIX_VIACOMBO] = azx_via_get_position,
[POS_FIX_COMBO] = azx_get_pos_lpib,
+ [POS_FIX_SKL] = azx_get_pos_skl,
};
chip->get_position[0] = chip->get_position[1] = callbacks[fix];
@@ -1390,7 +1422,7 @@ static void assign_position_fix(struct azx *chip, int fix)
if (fix == POS_FIX_COMBO)
chip->get_position[1] = NULL;
- if (fix == POS_FIX_POSBUF &&
+ if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
(chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
chip->get_delay[0] = chip->get_delay[1] =
azx_get_delay_from_lpib;
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 07a9deb17477..a148176c16a9 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -857,7 +857,7 @@ static int chipio_write_address(struct hda_codec *codec,
chip_addx >> 16);
}
- spec->curr_chip_addx = (res < 0) ? ~0UL : chip_addx;
+ spec->curr_chip_addx = (res < 0) ? ~0U : chip_addx;
return res;
}
@@ -882,7 +882,7 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data)
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
- (spec->curr_chip_addx + 4) : ~0UL;
+ (spec->curr_chip_addx + 4) : ~0U;
return res;
}
@@ -933,7 +933,7 @@ static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
- (spec->curr_chip_addx + 4) : ~0UL;
+ (spec->curr_chip_addx + 4) : ~0U;
return res;
}
@@ -1168,7 +1168,7 @@ static int dspio_write_multiple(struct hda_codec *codec,
int status = 0;
unsigned int count;
- if ((buffer == NULL))
+ if (buffer == NULL)
return -EINVAL;
count = 0;
@@ -1210,7 +1210,7 @@ static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer,
unsigned int skip_count;
unsigned int dummy;
- if ((buffer == NULL))
+ if (buffer == NULL)
return -1;
count = 0;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 1461ef8eb749..37f11560186a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -383,7 +383,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new eld_bytes_ctl = {
+static const struct snd_kcontrol_new eld_bytes_ctl = {
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "ELD",
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 299835d1fbaa..9371f1a95b33 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -4833,6 +4833,8 @@ enum {
ALC290_FIXUP_SUBWOOFER_HSJACK,
ALC269_FIXUP_THINKPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
+ ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
ALC255_FIXUP_HEADSET_MODE,
@@ -4872,6 +4874,11 @@ enum {
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
ALC269_FIXUP_ATIV_BOOK_8,
ALC221_FIXUP_HP_MIC_NO_PRESENCE,
+ ALC256_FIXUP_ASUS_HEADSET_MODE,
+ ALC256_FIXUP_ASUS_MIC,
+ ALC256_FIXUP_ASUS_AIO_GPIO2,
+ ALC233_FIXUP_ASUS_MIC_NO_PRESENCE,
+ ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5289,6 +5296,24 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_THINKPAD_ACPI,
},
+ [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
+ [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
[ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -5579,6 +5604,50 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC256_FIXUP_ASUS_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode,
+ },
+ [ALC256_FIXUP_ASUS_MIC] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x13, 0x90a60160 }, /* use as internal mic */
+ { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+ },
+ [ALC256_FIXUP_ASUS_AIO_GPIO2] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Set up GPIO2 for the speaker amp */
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
+ {}
+ },
+ },
+ [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MIC
+ },
+ [ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Enables internal speaker */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x40},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x8800},
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5692,15 +5761,27 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
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, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
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, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
@@ -5875,6 +5956,18 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{0x21, 0x03211020}
static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+ {0x12, 0x90a601c0},
+ {0x14, 0x90171120},
+ {0x21, 0x02211030}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x03211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+ {0x1a, 0x90a70130},
+ {0x1b, 0x90170110},
+ {0x21, 0x03211020}),
SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC225_STANDARD_PINS,
{0x12, 0xb7a60130},
@@ -5995,6 +6088,14 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x21, 0x02211020}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC256_STANDARD_PINS),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x04211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+ {0x14, 0x90170110},
+ {0x1b, 0x90a70130},
+ {0x21, 0x03211020}),
SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
{0x12, 0x90a60130},
{0x14, 0x90170110},
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 3bfdc78cbc5f..da5f37b7fdd0 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -432,7 +432,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status =
+static const struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READ),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 5cb587cf360e..ec07136fc288 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -719,7 +719,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st
return ndata != data;
}
-static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
@@ -728,7 +728,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = {
.count = 8,
};
-static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = {
+static const struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Output Sensitivity Switch",
.info = snd_ice1712_ewx_io_sense_info,
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index b4aa4c1370a8..1d8612cabb9e 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -279,7 +279,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru
return val != nval;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mixer To AC97",
.info = snd_ice1712_digmix_route_ac97_info,
@@ -1410,7 +1410,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = {
.private_value = 10,
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH),
.info = snd_ice1712_pro_mixer_switch_info,
@@ -1432,7 +1432,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = {
.tlv = { .p = db_scale_playback }
};
-static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = {
+static const struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME),
.info = snd_ice1712_pro_mixer_volume_info,
@@ -1630,7 +1630,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_eeprom = {
+static const struct snd_kcontrol_new snd_ice1712_eeprom = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1712 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1666,7 +1666,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_default =
+static const struct snd_kcontrol_new snd_ice1712_spdif_default =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
@@ -1717,7 +1717,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_maskc =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskc =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1726,7 +1726,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc =
.get = snd_ice1712_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_ice1712_spdif_maskp =
+static const struct snd_kcontrol_new snd_ice1712_spdif_maskp =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1753,7 +1753,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_spdif_stream =
+static const struct snd_kcontrol_new snd_ice1712_spdif_stream =
{
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE),
@@ -1878,7 +1878,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_ice1712_pro_internal_clock_info,
@@ -1943,7 +1943,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = {
+static const struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock Default",
.info = snd_ice1712_pro_internal_clock_default_info,
@@ -1974,7 +1974,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_locking = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_locking = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_ice1712_pro_rate_locking_info,
@@ -2005,7 +2005,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_pro_rate_reset = {
+static const struct snd_kcontrol_new snd_ice1712_pro_rate_reset = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_ice1712_pro_rate_reset_info,
@@ -2173,7 +2173,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = {
.put = snd_ice1712_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
.info = snd_ice1712_pro_route_info,
@@ -2215,7 +2215,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Volume Rate",
.info = snd_ice1712_pro_volume_rate_info,
@@ -2248,7 +2248,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = {
+static const struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 842744e7a139..9cd6e55c0642 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -1598,7 +1598,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_eeprom = {
+static const struct snd_kcontrol_new snd_vt1724_eeprom = {
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "ICE1724 EEPROM",
.access = SNDRV_CTL_ELEM_ACCESS_READ,
@@ -1711,7 +1711,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol,
return val != old;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_default =
+static const struct snd_kcontrol_new snd_vt1724_spdif_default =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
@@ -1743,7 +1743,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_maskc =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskc =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1752,7 +1752,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc =
.get = snd_vt1724_spdif_maskc_get,
};
-static struct snd_kcontrol_new snd_vt1724_spdif_maskp =
+static const struct snd_kcontrol_new snd_vt1724_spdif_maskp =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1789,7 +1789,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol,
return old != val;
}
-static struct snd_kcontrol_new snd_vt1724_spdif_switch =
+static const struct snd_kcontrol_new snd_vt1724_spdif_switch =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* FIXME: the following conflict with IEC958 Playback Route */
@@ -1964,7 +1964,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol,
return old_rate != new_rate;
}
-static struct snd_kcontrol_new snd_vt1724_pro_internal_clock = {
+static const struct snd_kcontrol_new snd_vt1724_pro_internal_clock = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Internal Clock",
.info = snd_vt1724_pro_internal_clock_info,
@@ -1995,7 +1995,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_locking = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_locking = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Locking",
.info = snd_vt1724_pro_rate_locking_info,
@@ -2026,7 +2026,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_vt1724_pro_rate_reset = {
+static const struct snd_kcontrol_new snd_vt1724_pro_rate_reset = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Multi Track Rate Reset",
.info = snd_vt1724_pro_rate_reset_info,
@@ -2151,7 +2151,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route =
.put = snd_vt1724_pro_route_analog_put,
};
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route",
.info = snd_vt1724_pro_route_info,
@@ -2187,7 +2187,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = {
+static const struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index e7fe15dd5a90..cb25acf7bc49 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -645,7 +645,7 @@ static int lola_input_src_put(struct snd_kcontrol *kcontrol,
return lola_set_src_config(chip, mask, true);
}
-static struct snd_kcontrol_new lola_input_src_mixer = {
+static const struct snd_kcontrol_new lola_input_src_mixer = {
.name = "Digital SRC Capture Switch",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = lola_input_src_info,
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index c0f0c349c3ec..f9c3e86d55d5 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -899,7 +899,7 @@ static int lx_control_playback_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new lx_control_playback_switch = {
+static const struct snd_kcontrol_new lx_control_playback_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
.index = 0,
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 51e53497f0ad..4a4616aac787 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -448,7 +448,7 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
return changed;
}
-static struct snd_kcontrol_new mixart_control_output_switch = {
+static const struct snd_kcontrol_new mixart_control_output_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.info = mixart_sw_info, /* shared */
@@ -1024,7 +1024,7 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
return changed;
}
-static struct snd_kcontrol_new mixart_control_monitor_vol = {
+static const struct snd_kcontrol_new mixart_control_monitor_vol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -1091,7 +1091,7 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return (changed != 0);
}
-static struct snd_kcontrol_new mixart_control_monitor_sw = {
+static const struct snd_kcontrol_new mixart_control_monitor_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Monitoring Switch",
.info = mixart_sw_info, /* shared */
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index 74afb6b75976..e36ed8af55ad 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -767,6 +767,8 @@ static int get_oxygen_model(struct oxygen *chip,
[MODEL_FANTASIA] = "TempoTec HiFier Fantasia",
[MODEL_SERENADE] = "TempoTec HiFier Serenade",
[MODEL_HG2PCI] = "CMI8787-HG2PCI",
+ [MODEL_XONAR_DG] = "Xonar DG",
+ [MODEL_XONAR_DGX] = "Xonar DGX",
};
chip->model = model_generic;
@@ -829,12 +831,8 @@ static int get_oxygen_model(struct oxygen *chip,
chip->model.dac_channels_mixer = 2;
break;
case MODEL_XONAR_DG:
- chip->model = model_xonar_dg;
- chip->model.shortname = "Xonar DG";
- break;
case MODEL_XONAR_DGX:
chip->model = model_xonar_dg;
- chip->model.shortname = "Xonar DGX";
break;
}
if (id->driver_data == MODEL_MERIDIAN ||
diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c
index 6a56e5306a65..8b4d0282efb8 100644
--- a/sound/pci/pcxhr/pcxhr_mix22.c
+++ b/sound/pci/pcxhr/pcxhr_mix22.c
@@ -744,7 +744,7 @@ static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new hr222_control_mic_level = {
+static const struct snd_kcontrol_new hr222_control_mic_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -794,7 +794,7 @@ static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new hr222_control_mic_boost = {
+static const struct snd_kcontrol_new hr222_control_mic_boost = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -836,7 +836,7 @@ static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new hr222_phantom_power_switch = {
+static const struct snd_kcontrol_new hr222_phantom_power_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Phantom Power Switch",
.info = hr222_phantom_power_info,
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index 63136c4f3f3d..36875df30dbf 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -235,7 +235,7 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new pcxhr_control_output_switch = {
+static const struct snd_kcontrol_new pcxhr_control_output_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.info = pcxhr_sw_info, /* shared */
@@ -460,7 +460,7 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new pcxhr_control_pcm_switch = {
+static const struct snd_kcontrol_new pcxhr_control_pcm_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Switch",
.count = PCXHR_PLAYBACK_STREAMS,
@@ -509,7 +509,7 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new pcxhr_control_monitor_vol = {
+static const struct snd_kcontrol_new pcxhr_control_monitor_vol = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -562,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol,
return (changed != 0);
}
-static struct snd_kcontrol_new pcxhr_control_monitor_sw = {
+static const struct snd_kcontrol_new pcxhr_control_monitor_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Monitoring Playback Switch",
.info = pcxhr_sw_info, /* shared */
@@ -697,7 +697,7 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol,
return ret;
}
-static struct snd_kcontrol_new pcxhr_control_audio_src = {
+static const struct snd_kcontrol_new pcxhr_control_audio_src = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Source",
.info = pcxhr_audio_src_info,
@@ -798,7 +798,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
return ret;
}
-static struct snd_kcontrol_new pcxhr_control_clock_type = {
+static const struct snd_kcontrol_new pcxhr_control_clock_type = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Clock Mode",
.info = pcxhr_clock_type_info,
@@ -842,7 +842,7 @@ static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new pcxhr_control_clock_rate = {
+static const struct snd_kcontrol_new pcxhr_control_clock_rate = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "Clock Rates",
@@ -1017,14 +1017,14 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol,
return changed;
}
-static struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = {
+static const struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = pcxhr_iec958_info,
.get = pcxhr_iec958_mask_get
};
-static struct snd_kcontrol_new pcxhr_control_playback_iec958 = {
+static const struct snd_kcontrol_new pcxhr_control_playback_iec958 = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = pcxhr_iec958_info,
@@ -1033,14 +1033,14 @@ static struct snd_kcontrol_new pcxhr_control_playback_iec958 = {
.private_value = 0 /* playback */
};
-static struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = {
+static const struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK),
.info = pcxhr_iec958_info,
.get = pcxhr_iec958_mask_get
};
-static struct snd_kcontrol_new pcxhr_control_capture_iec958 = {
+static const struct snd_kcontrol_new pcxhr_control_capture_iec958 = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT),
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 92ad2d7a6bf8..64d3b8eba4bb 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2356,7 +2356,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_spdif_control =
+static const struct snd_kcontrol_new snd_trident_spdif_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
@@ -2419,7 +2419,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_spdif_default =
+static const struct snd_kcontrol_new snd_trident_spdif_default =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -2452,7 +2452,7 @@ static int snd_trident_spdif_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_trident_spdif_mask =
+static const struct snd_kcontrol_new snd_trident_spdif_mask =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -2514,7 +2514,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_spdif_stream =
+static const struct snd_kcontrol_new snd_trident_spdif_stream =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -2564,7 +2564,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_ac97_rear_control =
+static const struct snd_kcontrol_new snd_trident_ac97_rear_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Rear Path",
@@ -2622,7 +2622,7 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_vol_music_control =
+static const struct snd_kcontrol_new snd_trident_vol_music_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Music Playback Volume",
@@ -2633,7 +2633,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control =
.tlv = { .p = db_scale_gvol },
};
-static struct snd_kcontrol_new snd_trident_vol_wave_control =
+static const struct snd_kcontrol_new snd_trident_vol_wave_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Wave Playback Volume",
@@ -2700,7 +2700,7 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_pcm_vol_control =
+static const struct snd_kcontrol_new snd_trident_pcm_vol_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Front Playback Volume",
@@ -2764,7 +2764,7 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_pcm_pan_control =
+static const struct snd_kcontrol_new snd_trident_pcm_pan_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Pan Playback Control",
@@ -2821,7 +2821,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);
-static struct snd_kcontrol_new snd_trident_pcm_rvol_control =
+static const struct snd_kcontrol_new snd_trident_pcm_rvol_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Reverb Playback Volume",
@@ -2877,7 +2877,7 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_trident_pcm_cvol_control =
+static const struct snd_kcontrol_new snd_trident_pcm_cvol_control =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Chorus Playback Volume",
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 2d8c14e3f8d2..d078e86414c2 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1683,7 +1683,7 @@ static int snd_via8233_dxs3_spdif_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = {
+static const struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = {
.name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_via8233_dxs3_spdif_info,
@@ -1772,7 +1772,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1);
-static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = {
+static const struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
@@ -1783,7 +1783,7 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = {
.tlv = { .p = db_scale_dxs }
};
-static struct snd_kcontrol_new snd_via8233_dxs_volume_control = {
+static const struct snd_kcontrol_new snd_via8233_dxs_volume_control = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.device = 0,
/* .subdevice set later */
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 8e457ea27f89..7df1663ea510 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -945,7 +945,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
return 0;
}
-static struct snd_kcontrol_new vx_control_input_level = {
+static const struct snd_kcontrol_new vx_control_input_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
@@ -956,7 +956,7 @@ static struct snd_kcontrol_new vx_control_input_level = {
.tlv = { .p = db_scale_mic },
};
-static struct snd_kcontrol_new vx_control_mic_level = {
+static const struct snd_kcontrol_new vx_control_mic_level = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index ffee284898b3..fe4ba463b57c 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -1316,7 +1316,7 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ymfpci_spdif_default =
+static const struct snd_kcontrol_new snd_ymfpci_spdif_default =
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1344,7 +1344,7 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ymfpci_spdif_mask =
+static const struct snd_kcontrol_new snd_ymfpci_spdif_mask =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1391,7 +1391,7 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol,
return change;
}
-static struct snd_kcontrol_new snd_ymfpci_spdif_stream =
+static const struct snd_kcontrol_new snd_ymfpci_spdif_stream =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1439,7 +1439,7 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_
return reg != old_reg;
}
-static struct snd_kcontrol_new snd_ymfpci_drec_source = {
+static const struct snd_kcontrol_new snd_ymfpci_drec_source = {
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Direct Recording Source",
@@ -1609,7 +1609,7 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e
return change;
}
-static struct snd_kcontrol_new snd_ymfpci_dup4ch = {
+static const struct snd_kcontrol_new snd_ymfpci_dup4ch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "4ch Duplication",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -1712,7 +1712,7 @@ static int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
return 0;
}
-static struct snd_kcontrol_new snd_ymfpci_rear_shared = {
+static const struct snd_kcontrol_new snd_ymfpci_rear_shared = {
.name = "Shared Rear/Line-In Switch",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_ymfpci_gpio_sw_info,
@@ -1776,7 +1776,7 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static struct snd_kcontrol_new snd_ymfpci_pcm_volume = {
+static const struct snd_kcontrol_new snd_ymfpci_pcm_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "PCM Playback Volume",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index bbef77d2b917..8e2878012d53 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -27,27 +27,6 @@
#define SKL_SUSPEND_DELAY 2000
-/* Vendor Specific Registers */
-#define AZX_REG_VS_EM1 0x1000
-#define AZX_REG_VS_INRC 0x1004
-#define AZX_REG_VS_OUTRC 0x1008
-#define AZX_REG_VS_FIFOTRK 0x100C
-#define AZX_REG_VS_FIFOTRK2 0x1010
-#define AZX_REG_VS_EM2 0x1030
-#define AZX_REG_VS_EM3L 0x1038
-#define AZX_REG_VS_EM3U 0x103C
-#define AZX_REG_VS_EM4L 0x1040
-#define AZX_REG_VS_EM4U 0x1044
-#define AZX_REG_VS_LTRC 0x1048
-#define AZX_REG_VS_D0I3C 0x104A
-#define AZX_REG_VS_PCE 0x104B
-#define AZX_REG_VS_L2MAGC 0x1050
-#define AZX_REG_VS_L2LAHPT 0x1054
-#define AZX_REG_VS_SDXDPIB_XBASE 0x1084
-#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20
-#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
-#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
-
#define AZX_PCIREG_PGCTL 0x44
#define AZX_PGCTL_LSRMD_MASK (1 << 4)
#define AZX_PCIREG_CGCTL 0x48
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index ac75816ada7c..850fab4a8f3b 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -225,9 +225,9 @@ snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
struct soundfont_patch_info patch;
if (count < (int)sizeof(patch))
- rc = -EINVAL;
+ return -EINVAL;
if (copy_from_user(&patch, buf, sizeof(patch)))
- rc = -EFAULT;
+ return -EFAULT;
if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
patch.type <= SNDRV_SFNT_PROBE_DATA)
rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port));
diff --git a/sound/usb/card.c b/sound/usb/card.c
index f36cb068dad3..6640277a725b 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -332,6 +332,7 @@ static int snd_usb_audio_dev_free(struct snd_device *device)
static int snd_usb_audio_create(struct usb_interface *intf,
struct usb_device *dev, int idx,
const struct snd_usb_audio_quirk *quirk,
+ unsigned int usb_id,
struct snd_usb_audio **rchip)
{
struct snd_card *card;
@@ -381,8 +382,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
atomic_set(&chip->usage_count, 0);
atomic_set(&chip->shutdown, 0);
- chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
+ chip->usb_id = usb_id;
INIT_LIST_HEAD(&chip->pcm_list);
INIT_LIST_HEAD(&chip->ep_list);
INIT_LIST_HEAD(&chip->midi_list);
@@ -569,7 +569,7 @@ static int usb_audio_probe(struct usb_interface *intf,
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
(pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
err = snd_usb_audio_create(intf, dev, i, quirk,
- &chip);
+ id, &chip);
if (err < 0)
goto __error;
chip->pm_intf = intf;
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index 7438e7c4a842..c33e2378089d 100644
--- a/sound/usb/mixer_scarlett.c
+++ b/sound/usb/mixer_scarlett.c
@@ -477,7 +477,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
return 0;
}
-static struct snd_kcontrol_new usb_scarlett_ctl_switch = {
+static const struct snd_kcontrol_new usb_scarlett_ctl_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "",
.info = scarlett_ctl_switch_info,
@@ -487,7 +487,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_switch = {
static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
-static struct snd_kcontrol_new usb_scarlett_ctl = {
+static const struct snd_kcontrol_new usb_scarlett_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -499,7 +499,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl = {
.tlv = { .p = db_scale_scarlett_gain }
};
-static struct snd_kcontrol_new usb_scarlett_ctl_master = {
+static const struct snd_kcontrol_new usb_scarlett_ctl_master = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -511,7 +511,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_master = {
.tlv = { .p = db_scale_scarlett_gain }
};
-static struct snd_kcontrol_new usb_scarlett_ctl_enum = {
+static const struct snd_kcontrol_new usb_scarlett_ctl_enum = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "",
.info = scarlett_ctl_enum_info,
@@ -519,7 +519,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_enum = {
.put = scarlett_ctl_enum_put,
};
-static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
+static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "",
.info = scarlett_ctl_enum_dynamic_info,
@@ -527,7 +527,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
.put = scarlett_ctl_enum_put,
};
-static struct snd_kcontrol_new usb_scarlett_ctl_sync = {
+static const struct snd_kcontrol_new usb_scarlett_ctl_sync = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.name = "",