[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/sound/firewire/motu/Makefile b/src/kernel/linux/v4.14/sound/firewire/motu/Makefile
new file mode 100644
index 0000000..7c502d3
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+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
+obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o
diff --git a/src/kernel/linux/v4.14/sound/firewire/motu/amdtp-motu-trace.h b/src/kernel/linux/v4.14/sound/firewire/motu/amdtp-motu-trace.h
new file mode 100644
index 0000000..cd0cbfa
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/sound/firewire/motu/amdtp-motu.c b/src/kernel/linux/v4.14/sound/firewire/motu/amdtp-motu.c
new file mode 100644
index 0000000..2cf18be
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/amdtp-motu.c
@@ -0,0 +1,429 @@
+/*
+ * 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 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
+
+/*
+ * 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] << 8);
+			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;
+	}
+}
+
+/* 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)
+{
+	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);
+
+	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);
+
+	trace_out_data_block_sph(s, data_blocks, buffer);
+	trace_out_data_block_message(s, data_blocks, buffer);
+
+	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/src/kernel/linux/v4.14/sound/firewire/motu/motu-hwdep.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-hwdep.c
new file mode 100644
index 0000000..b87ccb6
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/sound/firewire/motu/motu-midi.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-midi.c
new file mode 100644
index 0000000..e55cab6
--- /dev/null
+++ b/src/kernel/linux/v4.14/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 const struct snd_rawmidi_ops capture_ops = {
+		.open		= midi_capture_open,
+		.close		= midi_capture_close,
+		.trigger	= midi_capture_trigger,
+	};
+	static const struct snd_rawmidi_ops playback_ops = {
+		.open		= midi_playback_open,
+		.close		= midi_playback_close,
+		.trigger	= midi_playback_trigger,
+	};
+	struct snd_rawmidi *rmidi;
+	struct snd_rawmidi_str *str;
+	int err;
+
+	/* 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/src/kernel/linux/v4.14/sound/firewire/motu/motu-pcm.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-pcm.c
new file mode 100644
index 0000000..4330220
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu-pcm.c
@@ -0,0 +1,394 @@
+/*
+ * 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 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;
+
+	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);
+
+	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 = snd_motu_stream_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);
+}
+
+static int capture_ack(struct snd_pcm_substream *substream)
+{
+	struct snd_motu *motu = substream->private_data;
+
+	return amdtp_stream_pcm_ack(&motu->tx_stream);
+}
+
+static int playback_ack(struct snd_pcm_substream *substream)
+{
+	struct snd_motu *motu = substream->private_data;
+
+	return amdtp_stream_pcm_ack(&motu->rx_stream);
+}
+
+int snd_motu_create_pcm_devices(struct snd_motu *motu)
+{
+	static const 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,
+		.ack       = capture_ack,
+		.page      = snd_pcm_lib_get_vmalloc_page,
+		.mmap      = snd_pcm_lib_mmap_vmalloc,
+	};
+	static const 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,
+		.ack       = playback_ack,
+		.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/src/kernel/linux/v4.14/sound/firewire/motu/motu-proc.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-proc.c
new file mode 100644
index 0000000..706f1e9
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/PDIF 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/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v2.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v2.c
new file mode 100644
index 0000000..525b746
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v2.c
@@ -0,0 +1,232 @@
+/*
+ * 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.pcm_byte_offset = 10;
+	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/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v3.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v3.c
new file mode 100644
index 0000000..c7cd986
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu-protocol-v3.c
@@ -0,0 +1,306 @@
+/*
+ * 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_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;
+	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.pcm_byte_offset = 10;
+	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/src/kernel/linux/v4.14/sound/firewire/motu/motu-stream.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-stream.c
new file mode 100644
index 0000000..483a877
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu-stream.c
@@ -0,0 +1,415 @@
+/*
+ * 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_RX_MIDI_2ND_Q) ||
+	    (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
+		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;
+
+	if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
+	    (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
+		midi_ports = 1;
+	else
+		midi_ports = 0;
+
+	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);
+}
+
+int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
+{
+	int err;
+
+	err = motu->spec->protocol->cache_packet_formats(motu);
+	if (err < 0)
+		return err;
+
+	if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
+		motu->tx_packet_formats.midi_flag_offset = 4;
+		motu->tx_packet_formats.midi_byte_offset = 6;
+	} else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
+		motu->tx_packet_formats.midi_flag_offset = 8;
+		motu->tx_packet_formats.midi_byte_offset = 7;
+	}
+
+	if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
+		motu->rx_packet_formats.midi_flag_offset = 4;
+		motu->rx_packet_formats.midi_byte_offset = 6;
+	} else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
+		motu->rx_packet_formats.midi_flag_offset = 8;
+		motu->rx_packet_formats.midi_byte_offset = 7;
+	}
+
+	return 0;
+}
+
+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 = snd_motu_stream_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);
+			goto stop_streams;
+		}
+
+		err = start_isoc_ctx(motu, &motu->rx_stream);
+		if (err < 0) {
+			dev_err(&motu->unit->device,
+				"fail to start IT context: %d\n", err);
+			goto stop_streams;
+		}
+
+		err = protocol->switch_fetching_mode(motu, true);
+		if (err < 0) {
+			dev_err(&motu->unit->device,
+				"fail to enable frame fetching: %d\n", err);
+			goto stop_streams;
+		}
+	}
+
+	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);
+			goto stop_streams;
+		}
+	}
+
+	return 0;
+
+stop_streams:
+	stop_both_streams(motu);
+	return err;
+}
+
+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_destroy(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/src/kernel/linux/v4.14/sound/firewire/motu/motu-transaction.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu-transaction.c
new file mode 100644
index 0000000..7fc3009
--- /dev/null
+++ b/src/kernel/linux/v4.14/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/src/kernel/linux/v4.14/sound/firewire/motu/motu.c b/src/kernel/linux/v4.14/sound/firewire/motu/motu.c
new file mode 100644
index 0000000..0d6b526
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu.c
@@ -0,0 +1,283 @@
+/*
+ * 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_RX_MIDI_2ND_Q) ||
+	    (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) ||
+	    (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
+	    (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q)) {
+		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_motu_stream_destroy_duplex(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 const 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_RX_MIDI_2ND_Q |
+		 SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+
+	.analog_in_ports = 8,
+	.analog_out_ports = 8,
+};
+
+static const 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_RX_MIDI_3RD_Q |
+		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+
+	.analog_in_ports = 8,
+	.analog_out_ports = 8,
+};
+
+static const struct snd_motu_spec motu_audio_express = {
+	.name = "AudioExpress",
+	.protocol = &snd_motu_protocol_v3,
+	.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
+		 SND_MOTU_SPEC_TX_MICINST_CHUNK |
+		 SND_MOTU_SPEC_TX_RETURN_CHUNK |
+		 SND_MOTU_SPEC_RX_MIDI_2ND_Q |
+		 SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+	.analog_in_ports = 2,
+	.analog_out_ports = 4,
+};
+
+#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. */
+	SND_MOTU_DEV_ENTRY(0x104800, &motu_audio_express),
+	{ }
+};
+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/src/kernel/linux/v4.14/sound/firewire/motu/motu.h b/src/kernel/linux/v4.14/sound/firewire/motu/motu.h
new file mode 100644
index 0000000..4b23cf3
--- /dev/null
+++ b/src/kernel/linux/v4.14/sound/firewire/motu/motu.h
@@ -0,0 +1,165 @@
+/*
+ * 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_RX_MIDI_2ND_Q	= 0x0100,
+	SND_MOTU_SPEC_RX_MIDI_3RD_Q	= 0x0200,
+	SND_MOTU_SPEC_TX_MIDI_2ND_Q	= 0x0400,
+	SND_MOTU_SPEC_TX_MIDI_3RD_Q	= 0x0800,
+};
+
+#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_cache_packet_formats(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