Merge branch 'topic/hda-dual-codecs' into for-next
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
index 3b693e9..12ba833 100644
--- a/sound/core/seq/seq_lock.c
+++ b/sound/core/seq/seq_lock.c
@@ -28,19 +28,16 @@
 /* wait until all locks are released */
 void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
 {
-	int max_count = 5 * HZ;
+	int warn_count = 5 * HZ;
 
 	if (atomic_read(lockp) < 0) {
 		pr_warn("ALSA: seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
 		return;
 	}
 	while (atomic_read(lockp) > 0) {
-		if (max_count == 0) {
-			pr_warn("ALSA: seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
-			break;
-		}
+		if (warn_count-- == 0)
+			pr_warn("ALSA: seq_lock: waiting [%d left] in %s:%d\n", atomic_read(lockp), file, line);
 		schedule_timeout_uninterruptible(1);
-		max_count--;
 	}
 }
 
diff --git a/sound/firewire/amdtp-stream-trace.h b/sound/firewire/amdtp-stream-trace.h
index 850b36e..ea0d486 100644
--- a/sound/firewire/amdtp-stream-trace.h
+++ b/sound/firewire/amdtp-stream-trace.h
@@ -101,6 +101,94 @@
 		__entry->index)
 );
 
+TRACE_EVENT(in_packet_without_header,
+	TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_quadlets, unsigned int data_blocks, unsigned int index),
+	TP_ARGS(s, cycles, payload_quadlets, data_blocks, index),
+	TP_STRUCT__entry(
+		__field(unsigned int, second)
+		__field(unsigned int, cycle)
+		__field(int, channel)
+		__field(int, src)
+		__field(int, dest)
+		__field(unsigned int, payload_quadlets)
+		__field(unsigned int, data_blocks)
+		__field(unsigned int, data_block_counter)
+		__field(unsigned int, packet_index)
+		__field(unsigned int, irq)
+		__field(unsigned int, index)
+	),
+	TP_fast_assign(
+		__entry->second = cycles / CYCLES_PER_SECOND;
+		__entry->cycle = cycles % CYCLES_PER_SECOND;
+		__entry->channel = s->context->channel;
+		__entry->src = fw_parent_device(s->unit)->node_id;
+		__entry->dest = fw_parent_device(s->unit)->card->node_id;
+		__entry->payload_quadlets = payload_quadlets;
+		__entry->data_blocks = data_blocks,
+		__entry->data_block_counter = s->data_block_counter,
+		__entry->packet_index = s->packet_index;
+		__entry->irq = !!in_interrupt();
+		__entry->index = index;
+	),
+	TP_printk(
+		"%02u %04u %04x %04x %02d %03u %3u %3u %02u %01u %02u",
+		__entry->second,
+		__entry->cycle,
+		__entry->src,
+		__entry->dest,
+		__entry->channel,
+		__entry->payload_quadlets,
+		__entry->data_blocks,
+		__entry->data_block_counter,
+		__entry->packet_index,
+		__entry->irq,
+		__entry->index)
+);
+
+TRACE_EVENT(out_packet_without_header,
+	TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
+	TP_ARGS(s, cycles, payload_length, data_blocks, index),
+	TP_STRUCT__entry(
+		__field(unsigned int, second)
+		__field(unsigned int, cycle)
+		__field(int, channel)
+		__field(int, src)
+		__field(int, dest)
+		__field(unsigned int, payload_quadlets)
+		__field(unsigned int, data_blocks)
+		__field(unsigned int, data_block_counter)
+		__field(unsigned int, packet_index)
+		__field(unsigned int, irq)
+		__field(unsigned int, index)
+	),
+	TP_fast_assign(
+		__entry->second = cycles / CYCLES_PER_SECOND;
+		__entry->cycle = cycles % CYCLES_PER_SECOND;
+		__entry->channel = s->context->channel;
+		__entry->src = fw_parent_device(s->unit)->card->node_id;
+		__entry->dest = fw_parent_device(s->unit)->node_id;
+		__entry->payload_quadlets = payload_length / 4;
+		__entry->data_blocks = data_blocks,
+		__entry->data_blocks = s->data_block_counter,
+		__entry->packet_index = s->packet_index;
+		__entry->irq = !!in_interrupt();
+		__entry->index = index;
+	),
+	TP_printk(
+		"%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
+		__entry->second,
+		__entry->cycle,
+		__entry->src,
+		__entry->dest,
+		__entry->channel,
+		__entry->payload_quadlets,
+		__entry->data_blocks,
+		__entry->data_block_counter,
+		__entry->packet_index,
+		__entry->irq,
+		__entry->index)
+);
+
 #endif
 
 #undef TRACE_INCLUDE_PATH
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index a03b37b..9e6f54f 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -412,8 +412,7 @@
 
 static inline int queue_in_packet(struct amdtp_stream *s)
 {
-	return queue_packet(s, IN_PACKET_HEADER_SIZE,
-			    amdtp_stream_get_max_payload(s));
+	return queue_packet(s, IN_PACKET_HEADER_SIZE, s->max_payload_length);
 }
 
 static int handle_out_packet(struct amdtp_stream *s,
@@ -479,6 +478,10 @@
 	s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
 
 	payload_length = data_blocks * 4 * s->data_block_quadlets;
+
+	trace_out_packet_without_header(s, cycle, payload_length, data_blocks,
+					index);
+
 	if (queue_out_packet(s, payload_length) < 0)
 		return -EIO;
 
@@ -617,6 +620,10 @@
 
 	buffer = s->buffer.packets[s->packet_index].buffer;
 	data_blocks = payload_quadlets / s->data_block_quadlets;
+
+	trace_in_packet_without_header(s, cycle, payload_quadlets, data_blocks,
+				       index);
+
 	pcm_frames = s->process_data_blocks(s, buffer, data_blocks, NULL);
 	s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
 
@@ -705,12 +712,12 @@
 	cycle = decrement_cycle_count(cycle, packets);
 
 	/* For buffer-over-run prevention. */
-	max_payload_length = amdtp_stream_get_max_payload(s);
+	max_payload_length = s->max_payload_length;
 
 	for (i = 0; i < packets; i++) {
 		cycle = increment_cycle_count(cycle, 1);
 
-		/* The number of quadlets in this packet */
+		/* The number of bytes in this packet */
 		payload_length =
 			(be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT);
 		if (payload_length > max_payload_length) {
@@ -743,6 +750,8 @@
 	u32 cycle;
 	unsigned int packets;
 
+	s->max_payload_length = amdtp_stream_get_max_payload(s);
+
 	/*
 	 * For in-stream, first packet has come.
 	 * For out-stream, prepared to transmit first packet
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h
index 2bd4de4..7e88317 100644
--- a/sound/firewire/amdtp-stream.h
+++ b/sound/firewire/amdtp-stream.h
@@ -110,6 +110,7 @@
 	int (*handle_packet)(struct amdtp_stream *s,
 			unsigned int payload_quadlets, unsigned int cycle,
 			unsigned int index);
+	unsigned int max_payload_length;
 
 	/* For CIP headers. */
 	unsigned int source_node_id_field;
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index d1b098f..dd6c8e8 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -21,7 +21,7 @@
 
 	if (rcode != RCODE_COMPLETE) {
 		/* Transfer the message again, immediately. */
-		ff->next_ktime[port] = ktime_set(0, 0);
+		ff->next_ktime[port] = 0;
 		schedule_work(&ff->rx_midi_work[port]);
 		return;
 	}
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index 7683238..39dfa74 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -99,147 +99,6 @@
 }
 EXPORT_SYMBOL(snd_fw_schedule_registration);
 
-static void async_midi_port_callback(struct fw_card *card, int rcode,
-				     void *data, size_t length,
-				     void *callback_data)
-{
-	struct snd_fw_async_midi_port *port = callback_data;
-	struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
-
-	/* This port is closed. */
-	if (substream == NULL)
-		return;
-
-	if (rcode == RCODE_COMPLETE)
-		snd_rawmidi_transmit_ack(substream, port->consume_bytes);
-	else if (!rcode_is_permanent_error(rcode))
-		/* To start next transaction immediately for recovery. */
-		port->next_ktime = 0;
-	else
-		/* Don't continue processing. */
-		port->error = true;
-
-	port->idling = true;
-
-	if (!snd_rawmidi_transmit_empty(substream))
-		schedule_work(&port->work);
-}
-
-static void midi_port_work(struct work_struct *work)
-{
-	struct snd_fw_async_midi_port *port =
-			container_of(work, struct snd_fw_async_midi_port, work);
-	struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
-	int generation;
-	int type;
-
-	/* Under transacting or error state. */
-	if (!port->idling || port->error)
-		return;
-
-	/* Nothing to do. */
-	if (substream == NULL || snd_rawmidi_transmit_empty(substream))
-		return;
-
-	/* Do it in next chance. */
-	if (ktime_after(port->next_ktime, ktime_get())) {
-		schedule_work(&port->work);
-		return;
-	}
-
-	/*
-	 * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
-	 * Later, snd_rawmidi_transmit_ack() is called.
-	 */
-	memset(port->buf, 0, port->len);
-	port->consume_bytes = port->fill(substream, port->buf);
-	if (port->consume_bytes <= 0) {
-		/* Do it in next chance, immediately. */
-		if (port->consume_bytes == 0) {
-			port->next_ktime = 0;
-			schedule_work(&port->work);
-		} else {
-			/* Fatal error. */
-			port->error = true;
-		}
-		return;
-	}
-
-	/* Calculate type of transaction. */
-	if (port->len == 4)
-		type = TCODE_WRITE_QUADLET_REQUEST;
-	else
-		type = TCODE_WRITE_BLOCK_REQUEST;
-
-	/* Set interval to next transaction. */
-	port->next_ktime = ktime_add_ns(ktime_get(),
-				port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
-
-	/* Start this transaction. */
-	port->idling = false;
-
-	/*
-	 * In Linux FireWire core, when generation is updated with memory
-	 * barrier, node id has already been updated. In this module, After
-	 * this smp_rmb(), load/store instructions to memory are completed.
-	 * Thus, both of generation and node id are available with recent
-	 * values. This is a light-serialization solution to handle bus reset
-	 * events on IEEE 1394 bus.
-	 */
-	generation = port->parent->generation;
-	smp_rmb();
-
-	fw_send_request(port->parent->card, &port->transaction, type,
-			port->parent->node_id, generation,
-			port->parent->max_speed, port->addr,
-			port->buf, port->len, async_midi_port_callback,
-			port);
-}
-
-/**
- * snd_fw_async_midi_port_init - initialize asynchronous MIDI port structure
- * @port: the asynchronous MIDI port to initialize
- * @unit: the target of the asynchronous transaction
- * @addr: the address to which transactions are transferred
- * @len: the length of transaction
- * @fill: the callback function to fill given buffer, and returns the
- *	       number of consumed bytes for MIDI message.
- *
- */
-int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
-		struct fw_unit *unit, u64 addr, unsigned int len,
-		snd_fw_async_midi_port_fill fill)
-{
-	port->len = DIV_ROUND_UP(len, 4) * 4;
-	port->buf = kzalloc(port->len, GFP_KERNEL);
-	if (port->buf == NULL)
-		return -ENOMEM;
-
-	port->parent = fw_parent_device(unit);
-	port->addr = addr;
-	port->fill = fill;
-	port->idling = true;
-	port->next_ktime = 0;
-	port->error = false;
-
-	INIT_WORK(&port->work, midi_port_work);
-
-	return 0;
-}
-EXPORT_SYMBOL(snd_fw_async_midi_port_init);
-
-/**
- * snd_fw_async_midi_port_destroy - free asynchronous MIDI port structure
- * @port: the asynchronous MIDI port structure
- */
-void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port)
-{
-	snd_fw_async_midi_port_finish(port);
-	cancel_work_sync(&port->work);
-	kfree(port->buf);
-}
-EXPORT_SYMBOL(snd_fw_async_midi_port_destroy);
-
 MODULE_DESCRIPTION("FireWire audio helper functions");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
index f676931..eef7092 100644
--- a/sound/firewire/lib.h
+++ b/sound/firewire/lib.h
@@ -25,58 +25,4 @@
 void snd_fw_schedule_registration(struct fw_unit *unit,
 				  struct delayed_work *dwork);
 
-struct snd_fw_async_midi_port;
-typedef int (*snd_fw_async_midi_port_fill)(
-				struct snd_rawmidi_substream *substream,
-				u8 *buf);
-
-struct snd_fw_async_midi_port {
-	struct fw_device *parent;
-	struct work_struct work;
-	bool idling;
-	ktime_t next_ktime;
-	bool error;
-
-	u64 addr;
-	struct fw_transaction transaction;
-
-	u8 *buf;
-	unsigned int len;
-
-	struct snd_rawmidi_substream *substream;
-	snd_fw_async_midi_port_fill fill;
-	unsigned int consume_bytes;
-};
-
-int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
-		struct fw_unit *unit, u64 addr, unsigned int len,
-		snd_fw_async_midi_port_fill fill);
-void snd_fw_async_midi_port_destroy(struct snd_fw_async_midi_port *port);
-
-/**
- * snd_fw_async_midi_port_run - run transactions for the async MIDI port
- * @port: the asynchronous MIDI port
- * @substream: the MIDI substream
- */
-static inline void
-snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
-			   struct snd_rawmidi_substream *substream)
-{
-	if (!port->error) {
-		port->substream = substream;
-		schedule_work(&port->work);
-	}
-}
-
-/**
- * snd_fw_async_midi_port_finish - finish the asynchronous MIDI port
- * @port: the asynchronous MIDI port
- */
-static inline void
-snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
-{
-	port->substream = NULL;
-	port->error = false;
-}
-
 #endif
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index ae84ae6..728f586 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -1,3 +1,5 @@
+CFLAGS_amdtp-motu.o	:= -I$(src)
+
 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
diff --git a/sound/firewire/motu/amdtp-motu-trace.h b/sound/firewire/motu/amdtp-motu-trace.h
new file mode 100644
index 0000000..cd0cbfa9
--- /dev/null
+++ b/sound/firewire/motu/amdtp-motu-trace.h
@@ -0,0 +1,123 @@
+/*
+ * amdtp-motu-trace.h - tracepoint definitions to dump a part of packet data
+ *
+ * Copyright (c) 2017 Takashi Sakamoto
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM		snd_firewire_motu
+
+#if !defined(_SND_FIREWIRE_MOTU_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _SND_FIREWIRE_MOTU_TRACE_H
+
+#include <linux/tracepoint.h>
+
+static void copy_sph(u32 *frame, __be32 *buffer, unsigned int data_blocks,
+		     unsigned int data_block_quadlets);
+static void copy_message(u64 *frames, __be32 *buffer, unsigned int data_blocks,
+			 unsigned int data_block_quadlets);
+
+TRACE_EVENT(in_data_block_sph,
+	TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
+	TP_ARGS(s, data_blocks, buffer),
+	TP_STRUCT__entry(
+		__field(int, src)
+		__field(int, dst)
+		__field(unsigned int, data_blocks)
+		__dynamic_array(u32, tstamps, data_blocks)
+	),
+	TP_fast_assign(
+		__entry->src = fw_parent_device(s->unit)->node_id;
+		__entry->dst = fw_parent_device(s->unit)->card->node_id;
+		__entry->data_blocks = data_blocks;
+		copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
+	),
+	TP_printk(
+		"%04x %04x %u %s",
+		__entry->src,
+		__entry->dst,
+		__entry->data_blocks,
+		__print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4)
+	)
+);
+
+TRACE_EVENT(out_data_block_sph,
+	TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
+	TP_ARGS(s, data_blocks, buffer),
+	TP_STRUCT__entry(
+		__field(int, src)
+		__field(int, dst)
+		__field(unsigned int, data_blocks)
+		__dynamic_array(u32, tstamps, data_blocks)
+	),
+	TP_fast_assign(
+		__entry->src = fw_parent_device(s->unit)->card->node_id;
+		__entry->dst = fw_parent_device(s->unit)->node_id;
+		__entry->data_blocks = data_blocks;
+		copy_sph(__get_dynamic_array(tstamps), buffer, data_blocks, s->data_block_quadlets);
+	),
+	TP_printk(
+		"%04x %04x %u %s",
+		__entry->src,
+		__entry->dst,
+		__entry->data_blocks,
+		__print_array(__get_dynamic_array(tstamps), __entry->data_blocks, 4)
+	)
+);
+
+TRACE_EVENT(in_data_block_message,
+	TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
+	TP_ARGS(s, data_blocks, buffer),
+	TP_STRUCT__entry(
+		__field(int, src)
+		__field(int, dst)
+		__field(unsigned int, data_blocks)
+		__dynamic_array(u64, messages, data_blocks)
+	),
+	TP_fast_assign(
+		__entry->src = fw_parent_device(s->unit)->node_id;
+		__entry->dst = fw_parent_device(s->unit)->card->node_id;
+		__entry->data_blocks = data_blocks;
+		copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
+	),
+	TP_printk(
+		"%04x %04x %u %s",
+		__entry->src,
+		__entry->dst,
+		__entry->data_blocks,
+		__print_array(__get_dynamic_array(messages), __entry->data_blocks, 8)
+	)
+);
+
+TRACE_EVENT(out_data_block_message,
+	TP_PROTO(struct amdtp_stream *s, unsigned int data_blocks, __be32 *buffer),
+	TP_ARGS(s, data_blocks, buffer),
+	TP_STRUCT__entry(
+		__field(int, src)
+		__field(int, dst)
+		__field(unsigned int, data_blocks)
+		__dynamic_array(u64, messages, data_blocks)
+	),
+	TP_fast_assign(
+		__entry->src = fw_parent_device(s->unit)->card->node_id;
+		__entry->dst = fw_parent_device(s->unit)->node_id;
+		__entry->data_blocks = data_blocks;
+		copy_message(__get_dynamic_array(messages), buffer, data_blocks, s->data_block_quadlets);
+	),
+	TP_printk(
+		"%04x %04x %u %s",
+		__entry->src,
+		__entry->dst,
+		__entry->data_blocks,
+		__print_array(__get_dynamic_array(messages), __entry->data_blocks, 8)
+	)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH	.
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE	amdtp-motu-trace
+#include <trace/define_trace.h>
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c
index 08bd176..96f00911 100644
--- a/sound/firewire/motu/amdtp-motu.c
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -10,6 +10,9 @@
 #include <sound/pcm.h>
 #include "motu.h"
 
+#define CREATE_TRACE_POINTS
+#include "amdtp-motu-trace.h"
+
 #define CIP_FMT_MOTU		0x02
 #define CIP_FMT_MOTU_TX_V3	0x22
 #define MOTU_FDF_AM824		0x22
@@ -264,6 +267,36 @@
 	}
 }
 
+/* For tracepoints. */
+static void __maybe_unused copy_sph(u32 *frames, __be32 *buffer,
+				    unsigned int data_blocks,
+				    unsigned int data_block_quadlets)
+{
+	unsigned int i;
+
+	for (i = 0; i < data_blocks; ++i) {
+		*frames = be32_to_cpu(*buffer);
+		buffer += data_block_quadlets;
+		frames++;
+	}
+}
+
+/* For tracepoints. */
+static void __maybe_unused copy_message(u64 *frames, __be32 *buffer,
+					unsigned int data_blocks,
+					unsigned int data_block_quadlets)
+{
+	unsigned int i;
+
+	/* This is just for v2/v3 protocol. */
+	for (i = 0; i < data_blocks; ++i) {
+		*frames = (be32_to_cpu(buffer[1]) << 16) |
+			  (be32_to_cpu(buffer[2]) >> 16);
+		buffer += data_block_quadlets;
+		frames++;
+	}
+}
+
 static unsigned int process_tx_data_blocks(struct amdtp_stream *s,
 				__be32 *buffer, unsigned int data_blocks,
 				unsigned int *syt)
@@ -271,6 +304,9 @@
 	struct amdtp_motu *p = s->protocol;
 	struct snd_pcm_substream *pcm;
 
+	trace_in_data_block_sph(s, data_blocks, buffer);
+	trace_in_data_block_message(s, data_blocks, buffer);
+
 	if (p->midi_ports)
 		read_midi_messages(s, buffer, data_blocks);
 
@@ -346,6 +382,9 @@
 
 	write_sph(s, buffer, data_blocks);
 
+	trace_out_data_block_sph(s, data_blocks, buffer);
+	trace_out_data_block_message(s, data_blocks, buffer);
+
 	return data_blocks;
 }
 
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c
index df4f95d..4a741570 100644
--- a/sound/firewire/tascam/tascam-midi.c
+++ b/sound/firewire/tascam/tascam-midi.c
@@ -18,9 +18,8 @@
 {
 	struct snd_tscm *tscm = substream->rmidi->private_data;
 
-	/* Initialize internal status. */
-	tscm->running_status[substream->number] = 0;
-	tscm->on_sysex[substream->number] = 0;
+	snd_fw_async_midi_port_init(&tscm->out_ports[substream->number]);
+
 	return 0;
 }
 
@@ -32,11 +31,14 @@
 
 static int midi_playback_close(struct snd_rawmidi_substream *substream)
 {
+	return 0;
+}
+
+static void midi_playback_drain(struct snd_rawmidi_substream *substream)
+{
 	struct snd_tscm *tscm = substream->rmidi->private_data;
 
 	snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]);
-
-	return 0;
 }
 
 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
@@ -78,6 +80,7 @@
 	static const struct snd_rawmidi_ops playback_ops = {
 		.open		= midi_playback_open,
 		.close		= midi_playback_close,
+		.drain		= midi_playback_drain,
 		.trigger	= midi_playback_trigger,
 	};
 	struct snd_rawmidi *rmidi;
diff --git a/sound/firewire/tascam/tascam-transaction.c b/sound/firewire/tascam/tascam-transaction.c
index 040a96d..8967c52 100644
--- a/sound/firewire/tascam/tascam-transaction.c
+++ b/sound/firewire/tascam/tascam-transaction.c
@@ -58,39 +58,38 @@
 	return -EINVAL;
 }
 
-static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf)
+static int fill_message(struct snd_fw_async_midi_port *port,
+			struct snd_rawmidi_substream *substream)
 {
-	struct snd_tscm *tscm = substream->rmidi->private_data;
-	unsigned int port = substream->number;
 	int i, len, consume;
 	u8 *label, *msg;
 	u8 status;
 
 	/* The first byte is used for label, the rest for MIDI bytes. */
-	label = buf;
-	msg = buf + 1;
+	label = port->buf;
+	msg = port->buf + 1;
 
 	consume = snd_rawmidi_transmit_peek(substream, msg, 3);
 	if (consume == 0)
 		return 0;
 
 	/* On exclusive message. */
-	if (tscm->on_sysex[port]) {
+	if (port->on_sysex) {
 		/* Seek the end of exclusives. */
 		for (i = 0; i < consume; ++i) {
 			if (msg[i] == 0xf7) {
-				tscm->on_sysex[port] = false;
+				port->on_sysex = false;
 				break;
 			}
 		}
 
 		/* At the end of exclusive message, use label 0x07. */
-		if (!tscm->on_sysex[port]) {
+		if (!port->on_sysex) {
 			consume = i + 1;
-			*label = (port << 4) | 0x07;
+			*label = (substream->number << 4) | 0x07;
 		/* During exclusive message, use label 0x04. */
 		} else if (consume == 3) {
-			*label = (port << 4) | 0x04;
+			*label = (substream->number << 4) | 0x04;
 		/* We need to fill whole 3 bytes. Go to next change. */
 		} else {
 			return 0;
@@ -101,12 +100,12 @@
 		/* The beginning of exclusives. */
 		if (msg[0] == 0xf0) {
 			/* Transfer it in next chance in another condition. */
-			tscm->on_sysex[port] = true;
+			port->on_sysex = true;
 			return 0;
 		} else {
 			/* On running-status. */
 			if ((msg[0] & 0x80) != 0x80)
-				status = tscm->running_status[port];
+				status = port->running_status;
 			else
 				status = msg[0];
 
@@ -124,18 +123,18 @@
 
 				msg[2] = msg[1];
 				msg[1] = msg[0];
-				msg[0] = tscm->running_status[port];
+				msg[0] = port->running_status;
 			} else {
 				/* Enough MIDI bytes were not retrieved. */
 				if (consume < len)
 					return 0;
 				consume = len;
 
-				tscm->running_status[port] = msg[0];
+				port->running_status = msg[0];
 			}
 		}
 
-		*label = (port << 4) | (msg[0] >> 4);
+		*label = (substream->number << 4) | (msg[0] >> 4);
 	}
 
 	if (len > 0 && len < 3)
@@ -144,6 +143,106 @@
 	return consume;
 }
 
+static void async_midi_port_callback(struct fw_card *card, int rcode,
+				     void *data, size_t length,
+				     void *callback_data)
+{
+	struct snd_fw_async_midi_port *port = callback_data;
+	struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+
+	/* This port is closed. */
+	if (substream == NULL)
+		return;
+
+	if (rcode == RCODE_COMPLETE)
+		snd_rawmidi_transmit_ack(substream, port->consume_bytes);
+	else if (!rcode_is_permanent_error(rcode))
+		/* To start next transaction immediately for recovery. */
+		port->next_ktime = 0;
+	else
+		/* Don't continue processing. */
+		port->error = true;
+
+	port->idling = true;
+
+	if (!snd_rawmidi_transmit_empty(substream))
+		schedule_work(&port->work);
+}
+
+static void midi_port_work(struct work_struct *work)
+{
+	struct snd_fw_async_midi_port *port =
+			container_of(work, struct snd_fw_async_midi_port, work);
+	struct snd_rawmidi_substream *substream = ACCESS_ONCE(port->substream);
+	int generation;
+
+	/* Under transacting or error state. */
+	if (!port->idling || port->error)
+		return;
+
+	/* Nothing to do. */
+	if (substream == NULL || snd_rawmidi_transmit_empty(substream))
+		return;
+
+	/* Do it in next chance. */
+	if (ktime_after(port->next_ktime, ktime_get())) {
+		schedule_work(&port->work);
+		return;
+	}
+
+	/*
+	 * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
+	 * Later, snd_rawmidi_transmit_ack() is called.
+	 */
+	memset(port->buf, 0, 4);
+	port->consume_bytes = fill_message(port, substream);
+	if (port->consume_bytes <= 0) {
+		/* Do it in next chance, immediately. */
+		if (port->consume_bytes == 0) {
+			port->next_ktime = 0;
+			schedule_work(&port->work);
+		} else {
+			/* Fatal error. */
+			port->error = true;
+		}
+		return;
+	}
+
+	/* Set interval to next transaction. */
+	port->next_ktime = ktime_add_ns(ktime_get(),
+				port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
+
+	/* Start this transaction. */
+	port->idling = false;
+
+	/*
+	 * In Linux FireWire core, when generation is updated with memory
+	 * barrier, node id has already been updated. In this module, After
+	 * this smp_rmb(), load/store instructions to memory are completed.
+	 * Thus, both of generation and node id are available with recent
+	 * values. This is a light-serialization solution to handle bus reset
+	 * events on IEEE 1394 bus.
+	 */
+	generation = port->parent->generation;
+	smp_rmb();
+
+	fw_send_request(port->parent->card, &port->transaction,
+			TCODE_WRITE_QUADLET_REQUEST,
+			port->parent->node_id, generation,
+			port->parent->max_speed,
+			TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD,
+			port->buf, 4, async_midi_port_callback,
+			port);
+}
+
+void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port)
+{
+	port->idling = true;
+	port->error = false;
+	port->running_status = 0;
+	port->on_sysex = false;
+}
+
 static void handle_midi_tx(struct fw_card *card, struct fw_request *request,
 			   int tcode, int destination, int source,
 			   int generation, unsigned long long offset,
@@ -219,12 +318,9 @@
 		goto error;
 
 	for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) {
-		err = snd_fw_async_midi_port_init(
-				&tscm->out_ports[i], tscm->unit,
-				TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD,
-				4, fill_message);
-		if (err < 0)
-			goto error;
+		tscm->out_ports[i].parent = fw_parent_device(tscm->unit);
+		tscm->out_ports[i].next_ktime = 0;
+		INIT_WORK(&tscm->out_ports[i].work, midi_port_work);
 	}
 
 	return err;
@@ -275,7 +371,6 @@
 void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
 {
 	__be32 reg;
-	unsigned int i;
 
 	if (tscm->async_handler.callback_data == NULL)
 		return;
@@ -302,7 +397,4 @@
 
 	fw_core_remove_address_handler(&tscm->async_handler);
 	tscm->async_handler.callback_data = NULL;
-
-	for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++)
-		snd_fw_async_midi_port_destroy(&tscm->out_ports[i]);
 }
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index d3cd406..08ecfae 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -45,6 +45,23 @@
 #define TSCM_MIDI_IN_PORT_MAX	4
 #define TSCM_MIDI_OUT_PORT_MAX	4
 
+struct snd_fw_async_midi_port {
+	struct fw_device *parent;
+	struct work_struct work;
+	bool idling;
+	ktime_t next_ktime;
+	bool error;
+
+	struct fw_transaction transaction;
+
+	u8 buf[4];
+	u8 running_status;
+	bool on_sysex;
+
+	struct snd_rawmidi_substream *substream;
+	int consume_bytes;
+};
+
 struct snd_tscm {
 	struct snd_card *card;
 	struct fw_unit *unit;
@@ -72,8 +89,6 @@
 
 	/* For MIDI message outgoing transactions. */
 	struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
-	u8 running_status[TSCM_MIDI_OUT_PORT_MAX];
-	bool on_sysex[TSCM_MIDI_OUT_PORT_MAX];
 };
 
 #define TSCM_ADDR_BASE			0xffff00000000ull
@@ -131,6 +146,26 @@
 int snd_tscm_stream_lock_try(struct snd_tscm *tscm);
 void snd_tscm_stream_lock_release(struct snd_tscm *tscm);
 
+void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port);
+
+static inline void
+snd_fw_async_midi_port_run(struct snd_fw_async_midi_port *port,
+			   struct snd_rawmidi_substream *substream)
+{
+	if (!port->error) {
+		port->substream = substream;
+		schedule_work(&port->work);
+	}
+}
+
+static inline void
+snd_fw_async_midi_port_finish(struct snd_fw_async_midi_port *port)
+{
+	port->substream = NULL;
+	cancel_work_sync(&port->work);
+	port->error = false;
+}
+
 int snd_tscm_transaction_register(struct snd_tscm *tscm);
 int snd_tscm_transaction_reregister(struct snd_tscm *tscm);
 void snd_tscm_transaction_unregister(struct snd_tscm *tscm);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 59ab34f..b786fba 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -370,8 +370,10 @@
 #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71)
 #define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0)
 #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198)
 #define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \
-			IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci)
+			IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci)	|| \
+			IS_GLK(pci)
 
 static char *driver_short_names[] = {
 	[AZX_DRIVER_ICH] = "HDA Intel",
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 69266b8..e825373 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -52,6 +52,12 @@
 	bool dc_enable;
 	unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
 	struct nid_path *dc_mode_path;
+
+	int mute_led_polarity;
+	unsigned int gpio_led;
+	unsigned int gpio_mute_led_mask;
+	unsigned int gpio_mic_led_mask;
+
 };
 
 
@@ -264,6 +270,7 @@
 	CXT_FIXUP_HP_DOCK,
 	CXT_FIXUP_HP_SPECTRE,
 	CXT_FIXUP_HP_GATE_MIC,
+	CXT_FIXUP_MUTE_LED_GPIO,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -646,6 +653,74 @@
 		snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
 }
 
+/* update LED status via GPIO */
+static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+				bool enabled)
+{
+	struct conexant_spec *spec = codec->spec;
+	unsigned int oldval = spec->gpio_led;
+
+	if (spec->mute_led_polarity)
+		enabled = !enabled;
+
+	if (enabled)
+		spec->gpio_led &= ~mask;
+	else
+		spec->gpio_led |= mask;
+	if (spec->gpio_led != oldval)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct conexant_spec *spec = codec->spec;
+
+	cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+					 struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct conexant_spec *spec = codec->spec;
+
+	if (ucontrol)
+		cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
+				    ucontrol->value.integer.value[0] ||
+				    ucontrol->value.integer.value[1]);
+}
+
+
+static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	struct conexant_spec *spec = codec->spec;
+	static const struct hda_verb gpio_init[] = {
+		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
+		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
+		{}
+	};
+	codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
+		spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
+		spec->gpio_led = 0;
+		spec->mute_led_polarity = 0;
+		spec->gpio_mute_led_mask = 0x01;
+		spec->gpio_mic_led_mask = 0x02;
+	}
+	snd_hda_add_verbs(codec, gpio_init);
+	if (spec->gpio_led)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -799,6 +874,10 @@
 		.type = HDA_FIXUP_FUNC,
 		.v.func = cxt_fixup_hp_gate_mic_jack,
 	},
+	[CXT_FIXUP_MUTE_LED_GPIO] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cxt_fixup_mute_led_gpio,
+	},
 };
 
 static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -851,6 +930,7 @@
 	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
 	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
 	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
+	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
 	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -882,6 +962,7 @@
 	{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
 	{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
 	{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
+	{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
 	{}
 };
 
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 37f1156..90e4ff8 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -177,6 +177,7 @@
 	bool i915_bound; /* was i915 bound in this driver? */
 
 	struct hdac_chmap chmap;
+	hda_nid_t vendor_nid;
 };
 
 #ifdef CONFIG_SND_HDA_I915
@@ -2372,6 +2373,7 @@
 }
 
 #define INTEL_VENDOR_NID 0x08
+#define INTEL_GLK_VENDOR_NID 0x0B
 #define INTEL_GET_VENDOR_VERB 0xf81
 #define INTEL_SET_VENDOR_VERB 0x781
 #define INTEL_EN_DP12			0x02 /* enable DP 1.2 features */
@@ -2381,14 +2383,15 @@
 					  bool update_tree)
 {
 	unsigned int vendor_param;
+	struct hdmi_spec *spec = codec->spec;
 
-	vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
 		return;
 
 	vendor_param |= INTEL_EN_ALL_PIN_CVTS;
-	vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
 				INTEL_SET_VENDOR_VERB, vendor_param);
 	if (vendor_param == -1)
 		return;
@@ -2400,8 +2403,9 @@
 static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
 {
 	unsigned int vendor_param;
+	struct hdmi_spec *spec = codec->spec;
 
-	vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0,
+	vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
 				INTEL_GET_VENDOR_VERB, 0);
 	if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
 		return;
@@ -2409,7 +2413,7 @@
 	/* enable DP1.2 mode */
 	vendor_param |= INTEL_EN_DP12;
 	snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
-	snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0,
+	snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
 				INTEL_SET_VENDOR_VERB, vendor_param);
 }
 
@@ -2503,7 +2507,7 @@
 }
 
 /* Intel Haswell and onwards; audio component with eld notifier */
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid)
 {
 	struct hdmi_spec *spec;
 	int err;
@@ -2520,6 +2524,7 @@
 	spec = codec->spec;
 	codec->dp_mst = true;
 	spec->dyn_pcm_assign = true;
+	spec->vendor_nid = vendor_nid;
 
 	intel_haswell_enable_all_pins(codec, true);
 	intel_haswell_fixup_enable_dp12(codec);
@@ -2548,6 +2553,16 @@
 	return 0;
 }
 
+static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+{
+	return intel_hsw_common_init(codec, INTEL_VENDOR_NID);
+}
+
+static int patch_i915_glk_hdmi(struct hda_codec *codec)
+{
+	return intel_hsw_common_init(codec, INTEL_GLK_VENDOR_NID);
+}
+
 /* Intel Baytrail and Braswell; with eld notifier */
 static int patch_i915_byt_hdmi(struct hda_codec *codec)
 {
@@ -3800,7 +3815,7 @@
 HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",	patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",	patch_i915_hsw_hdmi),
 HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",	patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI",	patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI",	patch_i915_glk_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",	patch_i915_byt_hdmi),
 HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",	patch_i915_byt_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 57eeefd..93846bf 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6873,6 +6873,7 @@
 	ALC668_FIXUP_DELL_DISABLE_AAMIX,
 	ALC668_FIXUP_DELL_XPS13,
 	ALC662_FIXUP_ASUS_Nx50,
+	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 	ALC668_FIXUP_ASUS_Nx51,
 	ALC891_FIXUP_HEADSET_MODE,
 	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
@@ -7126,14 +7127,21 @@
 		.chained = true,
 		.chain_id = ALC662_FIXUP_BASS_1A
 	},
+	[ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc_fixup_headset_mode_alc668,
+		.chain_id = ALC662_FIXUP_BASS_CHMAP
+	},
 	[ALC668_FIXUP_ASUS_Nx51] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
-			{0x1a, 0x90170151}, /* bass speaker */
+			{ 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ 0x1a, 0x90170151 }, /* bass speaker */
+			{ 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
 			{}
 		},
 		.chained = true,
-		.chain_id = ALC662_FIXUP_BASS_CHMAP,
+		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 	},
 	[ALC891_FIXUP_HEADSET_MODE] = {
 		.type = HDA_FIXUP_FUNC,
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
index fab53f5..b3854f8 100644
--- a/sound/usb/line6/pcm.c
+++ b/sound/usb/line6/pcm.c
@@ -430,7 +430,7 @@
 }
 
 /* control definition */
-static struct snd_kcontrol_new line6_controls[] = {
+static const struct snd_kcontrol_new line6_controls[] = {
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "PCM Playback Volume",
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
index 17aa616..358224c 100644
--- a/sound/usb/line6/pod.c
+++ b/sound/usb/line6/pod.c
@@ -380,7 +380,7 @@
 }
 
 /* control definition */
-static struct snd_kcontrol_new pod_control_monitor = {
+static const struct snd_kcontrol_new pod_control_monitor = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Monitor Playback Volume",
 	.index = 0,
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 8e22f43..ba7975c 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -250,7 +250,7 @@
 }
 
 /* control definition */
-static struct snd_kcontrol_new toneport_control_monitor = {
+static const struct snd_kcontrol_new toneport_control_monitor = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Monitor Playback Volume",
 	.index = 0,
@@ -261,7 +261,7 @@
 };
 
 /* source selector definition */
-static struct snd_kcontrol_new toneport_control_source = {
+static const struct snd_kcontrol_new toneport_control_source = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "PCM Capture Source",
 	.index = 0,
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 6e763bc..a35f4146 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1922,7 +1922,7 @@
 	return changed;
 }
 
-static struct snd_kcontrol_new roland_load_ctl = {
+static const struct snd_kcontrol_new roland_load_ctl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "MIDI Input Mode",
 	.info = roland_load_info,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 4703cae..082736c 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1172,7 +1172,7 @@
 };
 
 /* the read-only variant */
-static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
+static const struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "", /* will be filled later manually */
 	.info = mixer_ctl_feature_info,
@@ -1745,7 +1745,7 @@
 }
 
 /* alsa control interface for processing/extension unit */
-static struct snd_kcontrol_new mixer_procunit_ctl = {
+static const struct snd_kcontrol_new mixer_procunit_ctl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "", /* will be filled later */
 	.info = mixer_ctl_feature_info,
@@ -2033,7 +2033,7 @@
 }
 
 /* alsa control interface for selector unit */
-static struct snd_kcontrol_new mixer_selectunit_ctl = {
+static const struct snd_kcontrol_new mixer_selectunit_ctl = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "", /* will be filled later */
 	.info = mixer_ctl_selector_info,
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index cf45bf1..e118bdc 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -472,7 +472,7 @@
 	hw->ops.mmap = usb_stream_hwdep_mmap;
 	hw->ops.poll = usb_stream_hwdep_poll;
 
-	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm",
+	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm",
 		dev->bus->busnum, dev->devnum);
 	return 0;
 }
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 605e104..f4b3cda 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -258,7 +258,7 @@
 	hw->ops.mmap = snd_us428ctls_mmap;
 	hw->ops.poll = snd_us428ctls_poll;
 	hw->exclusive = 1;
-	sprintf(hw->name, "/proc/bus/usb/%03d/%03d", device->bus->busnum, device->devnum);
+	sprintf(hw->name, "/dev/bus/usb/%03d/%03d", device->bus->busnum, device->devnum);
 	return 0;
 }
 
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index f95164b..d51c7fd 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -723,7 +723,7 @@
 	hw->ops.release = snd_usX2Y_hwdep_pcm_release;
 	hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
 	hw->exclusive = 1;
-	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
+	sprintf(hw->name, "/dev/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
 
 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
 	if (err < 0) {