All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] ALSA: fireface: add support for Fireface UCX
@ 2019-01-20  8:25 Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 1/9] ALSA: fireface: rename protocol layer for former models Takashi Sakamoto
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Hi,

In 2012, RME GmbH shipped Fireface UFX. This model is one of latter
models of Fireface series and support both of IEEE 1394 bus and USB.
Furthermore, it supports two types of remote control unit (Basic
Remote and Advanced Remote Control) with by 9pin mini-din connector.

This patchset adds support for this model, as a part of devices
by ALSA firewire stack (therefore it's not a device of USB). At
present, maintain of isochronous communication and synchronization
status are cleared but asynchronous communication for MIDI messages
are not yet, therefore this commit adds support for isochronous
communication for PCM frames.

This work is based on my packet analysis from rent device for a short
term (2 weeks). I'm happy to get your responses till next weekend.
Driver code in a remote branch is available for backport till Linux
kernel v4.17 or later for your test.
https://github.com/takaswie/snd-firewire-improve/tree/topic/ff800-midi

Regards

Takashi Sakamoto (9):
  ALSA: fireface: rename protocol layer for former models
  ALSA: fireface: unify protocol layer for FF400/FF800
  ALSA: fireface: obsolete proc node to leave one node
  ALSA: fireface: add protocol-dependent operation to dump status
  ALSA: fireface: add protocol-dependent operation to switch mode to
    fetch PCM frame
  ALSA: fireface: add protocol-dependent operation to get clock status
  ALSA: fireface: code refactoring for dump of sync status
  ALSA: fireface: code refactoring to parse of clock configuration
  ALSA: fireface: add support for Fireface UCX

 sound/firewire/Kconfig                       |   1 +
 sound/firewire/fireface/Makefile             |   4 +-
 sound/firewire/fireface/ff-pcm.c             |   2 +-
 sound/firewire/fireface/ff-proc.c            | 217 +-------
 sound/firewire/fireface/ff-protocol-ff400.c  | 161 ------
 sound/firewire/fireface/ff-protocol-ff800.c  | 143 -----
 sound/firewire/fireface/ff-protocol-former.c | 549 +++++++++++++++++++
 sound/firewire/fireface/ff-protocol-latter.c | 273 +++++++++
 sound/firewire/fireface/ff-stream.c          |  40 +-
 sound/firewire/fireface/ff-transaction.c     |  63 ---
 sound/firewire/fireface/ff.c                 |  41 +-
 sound/firewire/fireface/ff.h                 |  13 +-
 12 files changed, 886 insertions(+), 621 deletions(-)
 delete mode 100644 sound/firewire/fireface/ff-protocol-ff400.c
 delete mode 100644 sound/firewire/fireface/ff-protocol-ff800.c
 create mode 100644 sound/firewire/fireface/ff-protocol-former.c
 create mode 100644 sound/firewire/fireface/ff-protocol-latter.c

-- 
2.19.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/9] ALSA: fireface: rename protocol layer for former models
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 2/9] ALSA: fireface: unify protocol layer for FF400/FF800 Takashi Sakamoto
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

In a series of Fireface, later model supports different protocol
from former models.

This commit is a preparation to support both of protocols.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/Makefile                    |  2 +-
 .../{ff-protocol-ff800.c => ff-protocol-former.c}   | 13 ++++++-------
 2 files changed, 7 insertions(+), 8 deletions(-)
 rename sound/firewire/fireface/{ff-protocol-ff800.c => ff-protocol-former.c} (94%)

diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 79a7d6d99d72..3fb586d32584 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,4 +1,4 @@
 snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
 		     ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \
-		     ff-protocol-ff800.o
+		     ff-protocol-former.o
 obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-former.c
similarity index 94%
rename from sound/firewire/fireface/ff-protocol-ff800.c
rename to sound/firewire/fireface/ff-protocol-former.c
index 2acbf6039770..a383fd5fc879 100644
--- a/sound/firewire/fireface/ff-protocol-ff800.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -1,10 +1,9 @@
-/*
- * ff-protocol-ff800.c - a part of driver for RME Fireface series
- *
- * Copyright (c) 2018 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
- */
+// SPDX-License-Identifier: GPL-2.0
+// ff-protocol-former.c - a part of driver for RME Fireface series
+//
+// Copyright (c) 2019 Takashi Sakamoto
+//
+// Licensed under the terms of the GNU General Public License, version 2.
 
 #include <linux/delay.h>
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/9] ALSA: fireface: unify protocol layer for FF400/FF800
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 1/9] ALSA: fireface: rename protocol layer for former models Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 3/9] ALSA: fireface: obsolete proc node to leave one node Takashi Sakamoto
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

This commit moves codes for Fireface 400 to a file of former protocol.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/Makefile             |   3 +-
 sound/firewire/fireface/ff-protocol-ff400.c  | 161 -------------------
 sound/firewire/fireface/ff-protocol-former.c | 147 +++++++++++++++++
 3 files changed, 148 insertions(+), 163 deletions(-)
 delete mode 100644 sound/firewire/fireface/ff-protocol-ff400.c

diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 3fb586d32584..62eb78962b93 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,4 +1,3 @@
 snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
-		     ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \
-		     ff-protocol-former.o
+		     ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o
 obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-protocol-ff400.c b/sound/firewire/fireface/ff-protocol-ff400.c
deleted file mode 100644
index 2280fab9b3c7..000000000000
--- a/sound/firewire/fireface/ff-protocol-ff400.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * ff-protocol-ff400.c - a part of driver for RME Fireface series
- *
- * Copyright (c) 2015-2017 Takashi Sakamoto
- *
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/delay.h>
-#include "ff.h"
-
-#define FF400_STF		0x000080100500ull
-#define FF400_RX_PACKET_FORMAT	0x000080100504ull
-#define FF400_ISOC_COMM_START	0x000080100508ull
-#define FF400_TX_PACKET_FORMAT	0x00008010050cull
-#define FF400_ISOC_COMM_STOP	0x000080100510ull
-
-/*
- * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
- * we can allocate between 0 and 7 channel.
- */
-static int keep_resources(struct snd_ff *ff, unsigned int rate)
-{
-	enum snd_ff_stream_mode mode;
-	int i;
-	int err;
-
-	// Check whether the given value is supported or not.
-	for (i = 0; i < CIP_SFC_COUNT; i++) {
-		if (amdtp_rate_table[i] == rate)
-			break;
-	}
-	if (i >= CIP_SFC_COUNT)
-		return -EINVAL;
-
-	err = snd_ff_stream_get_multiplier_mode(i, &mode);
-	if (err < 0)
-		return err;
-
-	/* Keep resources for in-stream. */
-	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
-	err = fw_iso_resources_allocate(&ff->tx_resources,
-			amdtp_stream_get_max_payload(&ff->tx_stream),
-			fw_parent_device(ff->unit)->max_speed);
-	if (err < 0)
-		return err;
-
-	/* Keep resources for out-stream. */
-	err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
-				      ff->spec->pcm_playback_channels[mode]);
-	if (err < 0)
-		return err;
-	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
-	err = fw_iso_resources_allocate(&ff->rx_resources,
-			amdtp_stream_get_max_payload(&ff->rx_stream),
-			fw_parent_device(ff->unit)->max_speed);
-	if (err < 0)
-		fw_iso_resources_free(&ff->tx_resources);
-
-	return err;
-}
-
-static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
-{
-	__le32 reg;
-	int err;
-
-	err = keep_resources(ff, rate);
-	if (err < 0)
-		return err;
-
-	/* Set the number of data blocks transferred in a second. */
-	reg = cpu_to_le32(rate);
-	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-				 FF400_STF, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return err;
-
-	msleep(100);
-
-	/*
-	 * Set isochronous channel and the number of quadlets of received
-	 * packets.
-	 */
-	reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
-			  ff->rx_resources.channel);
-	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-				 FF400_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return err;
-
-	/*
-	 * Set isochronous channel and the number of quadlets of transmitted
-	 * packet.
-	 */
-	/* TODO: investigate the purpose of this 0x80. */
-	reg = cpu_to_le32((0x80 << 24) |
-			  (ff->tx_resources.channel << 5) |
-			  (ff->tx_stream.data_block_quadlets));
-	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-				 FF400_TX_PACKET_FORMAT, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return err;
-
-	/* Allow to transmit packets. */
-	reg = cpu_to_le32(0x00000001);
-	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-				 FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
-}
-
-static void ff400_finish_session(struct snd_ff *ff)
-{
-	__le32 reg;
-
-	reg = cpu_to_le32(0x80000000);
-	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
-			   FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
-}
-
-static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
-{
-	int i;
-
-	for (i = 0; i < length / 4; i++) {
-		u32 quad = le32_to_cpu(buf[i]);
-		u8 byte;
-		unsigned int index;
-		struct snd_rawmidi_substream *substream;
-
-		/* Message in first port. */
-		/*
-		 * This value may represent the index of this unit when the same
-		 * units are on the same IEEE 1394 bus. This driver doesn't use
-		 * it.
-		 */
-		index = (quad >> 8) & 0xff;
-		if (index > 0) {
-			substream = READ_ONCE(ff->tx_midi_substreams[0]);
-			if (substream != NULL) {
-				byte = quad & 0xff;
-				snd_rawmidi_receive(substream, &byte, 1);
-			}
-		}
-
-		/* Message in second port. */
-		index = (quad >> 24) & 0xff;
-		if (index > 0) {
-			substream = READ_ONCE(ff->tx_midi_substreams[1]);
-			if (substream != NULL) {
-				byte = (quad >> 16) & 0xff;
-				snd_rawmidi_receive(substream, &byte, 1);
-			}
-		}
-	}
-}
-
-const struct snd_ff_protocol snd_ff_protocol_ff400 = {
-	.handle_midi_msg	= ff400_handle_midi_msg,
-	.begin_session		= ff400_begin_session,
-	.finish_session		= ff400_finish_session,
-};
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index a383fd5fc879..ed1271a89484 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -140,3 +140,150 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 	.begin_session		= ff800_begin_session,
 	.finish_session		= ff800_finish_session,
 };
+
+#define FF400_STF		0x000080100500ull
+#define FF400_RX_PACKET_FORMAT	0x000080100504ull
+#define FF400_ISOC_COMM_START	0x000080100508ull
+#define FF400_TX_PACKET_FORMAT	0x00008010050cull
+#define FF400_ISOC_COMM_STOP	0x000080100510ull
+
+/*
+ * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
+ * we can allocate between 0 and 7 channel.
+ */
+static int keep_resources(struct snd_ff *ff, unsigned int rate)
+{
+	enum snd_ff_stream_mode mode;
+	int i;
+	int err;
+
+	// Check whether the given value is supported or not.
+	for (i = 0; i < CIP_SFC_COUNT; i++) {
+		if (amdtp_rate_table[i] == rate)
+			break;
+	}
+	if (i >= CIP_SFC_COUNT)
+		return -EINVAL;
+
+	err = snd_ff_stream_get_multiplier_mode(i, &mode);
+	if (err < 0)
+		return err;
+
+	/* Keep resources for in-stream. */
+	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
+	err = fw_iso_resources_allocate(&ff->tx_resources,
+			amdtp_stream_get_max_payload(&ff->tx_stream),
+			fw_parent_device(ff->unit)->max_speed);
+	if (err < 0)
+		return err;
+
+	/* Keep resources for out-stream. */
+	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
+	err = fw_iso_resources_allocate(&ff->rx_resources,
+			amdtp_stream_get_max_payload(&ff->rx_stream),
+			fw_parent_device(ff->unit)->max_speed);
+	if (err < 0)
+		fw_iso_resources_free(&ff->tx_resources);
+
+	return err;
+}
+
+static int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+	__le32 reg;
+	int err;
+
+	err = keep_resources(ff, rate);
+	if (err < 0)
+		return err;
+
+	/* Set the number of data blocks transferred in a second. */
+	reg = cpu_to_le32(rate);
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 FF400_STF, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+
+	msleep(100);
+
+	/*
+	 * Set isochronous channel and the number of quadlets of received
+	 * packets.
+	 */
+	reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
+			  ff->rx_resources.channel);
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 FF400_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+
+	/*
+	 * Set isochronous channel and the number of quadlets of transmitted
+	 * packet.
+	 */
+	/* TODO: investigate the purpose of this 0x80. */
+	reg = cpu_to_le32((0x80 << 24) |
+			  (ff->tx_resources.channel << 5) |
+			  (ff->tx_stream.data_block_quadlets));
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 FF400_TX_PACKET_FORMAT, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+
+	/* Allow to transmit packets. */
+	reg = cpu_to_le32(0x00000001);
+	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
+}
+
+static void ff400_finish_session(struct snd_ff *ff)
+{
+	__le32 reg;
+
+	reg = cpu_to_le32(0x80000000);
+	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+			   FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
+}
+
+static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
+{
+	int i;
+
+	for (i = 0; i < length / 4; i++) {
+		u32 quad = le32_to_cpu(buf[i]);
+		u8 byte;
+		unsigned int index;
+		struct snd_rawmidi_substream *substream;
+
+		/* Message in first port. */
+		/*
+		 * This value may represent the index of this unit when the same
+		 * units are on the same IEEE 1394 bus. This driver doesn't use
+		 * it.
+		 */
+		index = (quad >> 8) & 0xff;
+		if (index > 0) {
+			substream = READ_ONCE(ff->tx_midi_substreams[0]);
+			if (substream != NULL) {
+				byte = quad & 0xff;
+				snd_rawmidi_receive(substream, &byte, 1);
+			}
+		}
+
+		/* Message in second port. */
+		index = (quad >> 24) & 0xff;
+		if (index > 0) {
+			substream = READ_ONCE(ff->tx_midi_substreams[1]);
+			if (substream != NULL) {
+				byte = (quad >> 16) & 0xff;
+				snd_rawmidi_receive(substream, &byte, 1);
+			}
+		}
+	}
+}
+
+const struct snd_ff_protocol snd_ff_protocol_ff400 = {
+	.handle_midi_msg	= ff400_handle_midi_msg,
+	.begin_session		= ff400_begin_session,
+	.finish_session		= ff400_finish_session,
+};
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/9] ALSA: fireface: obsolete proc node to leave one node
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 1/9] ALSA: fireface: rename protocol layer for former models Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 2/9] ALSA: fireface: unify protocol layer for FF400/FF800 Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 4/9] ALSA: fireface: add protocol-dependent operation to dump status Takashi Sakamoto
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

In a series of Fireface, latter protocol has no way for drivers to
retrieve current clock configuration. On the other hand, this driver
has proc node for it.

This commit removes a proc node to dump both clock configuration
and synchronization status in one proc node.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-proc.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c
index a0c550dabe9a..37f84b7fc432 100644
--- a/sound/firewire/fireface/ff-proc.c
+++ b/sound/firewire/fireface/ff-proc.c
@@ -8,10 +8,8 @@
 
 #include "./ff.h"
 
-static void proc_dump_clock_config(struct snd_info_entry *entry,
-				   struct snd_info_buffer *buffer)
+static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
 {
-	struct snd_ff *ff = entry->private_data;
 	__le32 reg;
 	u32 data;
 	unsigned int rate;
@@ -87,10 +85,8 @@ static void proc_dump_clock_config(struct snd_info_entry *entry,
 	snd_iprintf(buffer, "Sync to clock source: %s\n", src);
 }
 
-static void proc_dump_sync_status(struct snd_info_entry *entry,
-				  struct snd_info_buffer *buffer)
+static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
 {
-	struct snd_ff *ff = entry->private_data;
 	__le32 reg;
 	u32 data;
 	int err;
@@ -213,6 +209,15 @@ static void proc_dump_sync_status(struct snd_info_entry *entry,
 	snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
 }
 
+static void proc_dump_status(struct snd_info_entry *entry,
+			     struct snd_info_buffer *buffer)
+{
+	struct snd_ff *ff = entry->private_data;
+
+	dump_clock_config(ff, buffer);
+	dump_sync_status(ff, buffer);
+}
+
 static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
 		     const char *name,
 		     void (*op)(struct snd_info_entry *e,
@@ -247,6 +252,5 @@ void snd_ff_proc_init(struct snd_ff *ff)
 		return;
 	}
 
-	add_node(ff, root, "clock-config", proc_dump_clock_config);
-	add_node(ff, root, "sync-status", proc_dump_sync_status);
+	add_node(ff, root, "status", proc_dump_status);
 }
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/9] ALSA: fireface: add protocol-dependent operation to dump status
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (2 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 3/9] ALSA: fireface: obsolete proc node to leave one node Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 5/9] ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame Takashi Sakamoto
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

This commit adds a member for a callback function to dump status and
move existing code to former protocol.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-proc.c            | 204 +-----------------
 sound/firewire/fireface/ff-protocol-former.c | 212 +++++++++++++++++++
 sound/firewire/fireface/ff.h                 |   2 +-
 3 files changed, 214 insertions(+), 204 deletions(-)

diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c
index 37f84b7fc432..8a7cfb6ccce6 100644
--- a/sound/firewire/fireface/ff-proc.c
+++ b/sound/firewire/fireface/ff-proc.c
@@ -8,214 +8,12 @@
 
 #include "./ff.h"
 
-static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
-{
-	__le32 reg;
-	u32 data;
-	unsigned int rate;
-	const char *src;
-	int err;
-
-	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
-				 SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return;
-
-	data = le32_to_cpu(reg);
-
-	snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
-		    (data & 0x20) ? "Professional" : "Consumer",
-		    (data & 0x40) ? "on" : "off");
-
-	snd_iprintf(buffer, "Optical output interface format: %s\n",
-		    ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
-
-	snd_iprintf(buffer, "Word output single speed: %s\n",
-		    ((data >> 8) & 0x20) ? "on" : "off");
-
-	snd_iprintf(buffer, "S/PDIF input interface: %s\n",
-		    ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
-
-	switch ((data >> 1) & 0x03) {
-	case 0x01:
-		rate = 32000;
-		break;
-	case 0x00:
-		rate = 44100;
-		break;
-	case 0x03:
-		rate = 48000;
-		break;
-	case 0x02:
-	default:
-		return;
-	}
-
-	if (data & 0x08)
-		rate *= 2;
-	else if (data & 0x10)
-		rate *= 4;
-
-	snd_iprintf(buffer, "Sampling rate: %d\n", rate);
-
-	if (data & 0x01) {
-		src = "Internal";
-	} else {
-		switch ((data >> 10) & 0x07) {
-		case 0x00:
-			src = "ADAT1";
-			break;
-		case 0x01:
-			src = "ADAT2";
-			break;
-		case 0x03:
-			src = "S/PDIF";
-			break;
-		case 0x04:
-			src = "Word";
-			break;
-		case 0x05:
-			src = "LTC";
-			break;
-		default:
-			return;
-		}
-	}
-
-	snd_iprintf(buffer, "Sync to clock source: %s\n", src);
-}
-
-static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
-{
-	__le32 reg;
-	u32 data;
-	int err;
-
-	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
-				 SND_FF_REG_SYNC_STATUS, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return;
-
-	data = le32_to_cpu(reg);
-
-	snd_iprintf(buffer, "External source detection:\n");
-
-	snd_iprintf(buffer, "Word Clock:");
-	if ((data >> 24) & 0x20) {
-		if ((data >> 24) & 0x40)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
-
-	snd_iprintf(buffer, "S/PDIF:");
-	if ((data >> 16) & 0x10) {
-		if ((data >> 16) & 0x04)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
-
-	snd_iprintf(buffer, "ADAT1:");
-	if ((data >> 8) & 0x04) {
-		if ((data >> 8) & 0x10)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
-
-	snd_iprintf(buffer, "ADAT2:");
-	if ((data >> 8) & 0x08) {
-		if ((data >> 8) & 0x20)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
-
-	snd_iprintf(buffer, "\nUsed external source:\n");
-
-	if (((data >> 22) & 0x07) == 0x07) {
-		snd_iprintf(buffer, "None\n");
-	} else {
-		switch ((data >> 22) & 0x07) {
-		case 0x00:
-			snd_iprintf(buffer, "ADAT1:");
-			break;
-		case 0x01:
-			snd_iprintf(buffer, "ADAT2:");
-			break;
-		case 0x03:
-			snd_iprintf(buffer, "S/PDIF:");
-			break;
-		case 0x04:
-			snd_iprintf(buffer, "Word:");
-			break;
-		case 0x07:
-			snd_iprintf(buffer, "Nothing:");
-			break;
-		case 0x02:
-		case 0x05:
-		case 0x06:
-		default:
-			snd_iprintf(buffer, "unknown:");
-			break;
-		}
-
-		if ((data >> 25) & 0x07) {
-			switch ((data >> 25) & 0x07) {
-			case 0x01:
-				snd_iprintf(buffer, "32000\n");
-				break;
-			case 0x02:
-				snd_iprintf(buffer, "44100\n");
-				break;
-			case 0x03:
-				snd_iprintf(buffer, "48000\n");
-				break;
-			case 0x04:
-				snd_iprintf(buffer, "64000\n");
-				break;
-			case 0x05:
-				snd_iprintf(buffer, "88200\n");
-				break;
-			case 0x06:
-				snd_iprintf(buffer, "96000\n");
-				break;
-			case 0x07:
-				snd_iprintf(buffer, "128000\n");
-				break;
-			case 0x08:
-				snd_iprintf(buffer, "176400\n");
-				break;
-			case 0x09:
-				snd_iprintf(buffer, "192000\n");
-				break;
-			case 0x00:
-				snd_iprintf(buffer, "unknown\n");
-				break;
-			}
-		}
-	}
-
-	snd_iprintf(buffer, "Multiplied:");
-	snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
-}
-
 static void proc_dump_status(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
 {
 	struct snd_ff *ff = entry->private_data;
 
-	dump_clock_config(ff, buffer);
-	dump_sync_status(ff, buffer);
+	ff->spec->protocol->dump_status(ff, buffer);
 }
 
 static void add_node(struct snd_ff *ff, struct snd_info_entry *root,
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index ed1271a89484..5f97e7fc7281 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -9,6 +9,216 @@
 
 #include "ff.h"
 
+#define FORMER_REG_SYNC_STATUS		0x0000801c0000ull
+
+static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
+{
+	__le32 reg;
+	u32 data;
+	unsigned int rate;
+	const char *src;
+	int err;
+
+	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
+				 SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return;
+
+	data = le32_to_cpu(reg);
+
+	snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
+		    (data & 0x20) ? "Professional" : "Consumer",
+		    (data & 0x40) ? "on" : "off");
+
+	snd_iprintf(buffer, "Optical output interface format: %s\n",
+		    ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
+
+	snd_iprintf(buffer, "Word output single speed: %s\n",
+		    ((data >> 8) & 0x20) ? "on" : "off");
+
+	snd_iprintf(buffer, "S/PDIF input interface: %s\n",
+		    ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
+
+	switch ((data >> 1) & 0x03) {
+	case 0x01:
+		rate = 32000;
+		break;
+	case 0x00:
+		rate = 44100;
+		break;
+	case 0x03:
+		rate = 48000;
+		break;
+	case 0x02:
+	default:
+		return;
+	}
+
+	if (data & 0x08)
+		rate *= 2;
+	else if (data & 0x10)
+		rate *= 4;
+
+	snd_iprintf(buffer, "Sampling rate: %d\n", rate);
+
+	if (data & 0x01) {
+		src = "Internal";
+	} else {
+		switch ((data >> 10) & 0x07) {
+		case 0x00:
+			src = "ADAT1";
+			break;
+		case 0x01:
+			src = "ADAT2";
+			break;
+		case 0x03:
+			src = "S/PDIF";
+			break;
+		case 0x04:
+			src = "Word";
+			break;
+		case 0x05:
+			src = "LTC";
+			break;
+		default:
+			return;
+		}
+	}
+
+	snd_iprintf(buffer, "Sync to clock source: %s\n", src);
+}
+
+static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
+{
+	__le32 reg;
+	u32 data;
+	int err;
+
+	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+				 FORMER_REG_SYNC_STATUS, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return;
+
+	data = le32_to_cpu(reg);
+
+	snd_iprintf(buffer, "External source detection:\n");
+
+	snd_iprintf(buffer, "Word Clock:");
+	if ((data >> 24) & 0x20) {
+		if ((data >> 24) & 0x40)
+			snd_iprintf(buffer, "sync\n");
+		else
+			snd_iprintf(buffer, "lock\n");
+	} else {
+		snd_iprintf(buffer, "none\n");
+	}
+
+	snd_iprintf(buffer, "S/PDIF:");
+	if ((data >> 16) & 0x10) {
+		if ((data >> 16) & 0x04)
+			snd_iprintf(buffer, "sync\n");
+		else
+			snd_iprintf(buffer, "lock\n");
+	} else {
+		snd_iprintf(buffer, "none\n");
+	}
+
+	snd_iprintf(buffer, "ADAT1:");
+	if ((data >> 8) & 0x04) {
+		if ((data >> 8) & 0x10)
+			snd_iprintf(buffer, "sync\n");
+		else
+			snd_iprintf(buffer, "lock\n");
+	} else {
+		snd_iprintf(buffer, "none\n");
+	}
+
+	snd_iprintf(buffer, "ADAT2:");
+	if ((data >> 8) & 0x08) {
+		if ((data >> 8) & 0x20)
+			snd_iprintf(buffer, "sync\n");
+		else
+			snd_iprintf(buffer, "lock\n");
+	} else {
+		snd_iprintf(buffer, "none\n");
+	}
+
+	snd_iprintf(buffer, "\nUsed external source:\n");
+
+	if (((data >> 22) & 0x07) == 0x07) {
+		snd_iprintf(buffer, "None\n");
+	} else {
+		switch ((data >> 22) & 0x07) {
+		case 0x00:
+			snd_iprintf(buffer, "ADAT1:");
+			break;
+		case 0x01:
+			snd_iprintf(buffer, "ADAT2:");
+			break;
+		case 0x03:
+			snd_iprintf(buffer, "S/PDIF:");
+			break;
+		case 0x04:
+			snd_iprintf(buffer, "Word:");
+			break;
+		case 0x07:
+			snd_iprintf(buffer, "Nothing:");
+			break;
+		case 0x02:
+		case 0x05:
+		case 0x06:
+		default:
+			snd_iprintf(buffer, "unknown:");
+			break;
+		}
+
+		if ((data >> 25) & 0x07) {
+			switch ((data >> 25) & 0x07) {
+			case 0x01:
+				snd_iprintf(buffer, "32000\n");
+				break;
+			case 0x02:
+				snd_iprintf(buffer, "44100\n");
+				break;
+			case 0x03:
+				snd_iprintf(buffer, "48000\n");
+				break;
+			case 0x04:
+				snd_iprintf(buffer, "64000\n");
+				break;
+			case 0x05:
+				snd_iprintf(buffer, "88200\n");
+				break;
+			case 0x06:
+				snd_iprintf(buffer, "96000\n");
+				break;
+			case 0x07:
+				snd_iprintf(buffer, "128000\n");
+				break;
+			case 0x08:
+				snd_iprintf(buffer, "176400\n");
+				break;
+			case 0x09:
+				snd_iprintf(buffer, "192000\n");
+				break;
+			case 0x00:
+				snd_iprintf(buffer, "unknown\n");
+				break;
+			}
+		}
+	}
+
+	snd_iprintf(buffer, "Multiplied:");
+	snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
+}
+
+static void former_dump_status(struct snd_ff *ff,
+			       struct snd_info_buffer *buffer)
+{
+	dump_clock_config(ff, buffer);
+	dump_sync_status(ff, buffer);
+}
+
 #define FF800_STF		0x0000fc88f000
 #define FF800_RX_PACKET_FORMAT	0x0000fc88f004
 #define FF800_ALLOC_TX_STREAM	0x0000fc88f008
@@ -139,6 +349,7 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 	.handle_midi_msg	= ff800_handle_midi_msg,
 	.begin_session		= ff800_begin_session,
 	.finish_session		= ff800_finish_session,
+	.dump_status		= former_dump_status,
 };
 
 #define FF400_STF		0x000080100500ull
@@ -286,4 +497,5 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = {
 	.handle_midi_msg	= ff400_handle_midi_msg,
 	.begin_session		= ff400_begin_session,
 	.finish_session		= ff400_finish_session,
+	.dump_status		= former_dump_status,
 };
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 7dfc7745a914..3f22b8d84e36 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -35,7 +35,6 @@
 #define SND_FF_IN_MIDI_PORTS		2
 #define SND_FF_OUT_MIDI_PORTS		2
 
-#define SND_FF_REG_SYNC_STATUS		0x0000801c0000ull
 /* For block write request. */
 #define SND_FF_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
 #define SND_FF_REG_CLOCK_CONFIG		0x0000801c0004ull
@@ -111,6 +110,7 @@ struct snd_ff_protocol {
 	void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
 	int (*begin_session)(struct snd_ff *ff, unsigned int rate);
 	void (*finish_session)(struct snd_ff *ff);
+	void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer);
 };
 
 extern const struct snd_ff_protocol snd_ff_protocol_ff800;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/9] ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (3 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 4/9] ALSA: fireface: add protocol-dependent operation to dump status Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 6/9] ALSA: fireface: add protocol-dependent operation to get clock status Takashi Sakamoto
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

This commit adds a member for a callback function to switch frame
fetching mode to former protocol.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-protocol-former.c | 38 ++++++++++++++++++++
 sound/firewire/fireface/ff-stream.c          | 38 ++------------------
 sound/firewire/fireface/ff.h                 |  3 +-
 3 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index 5f97e7fc7281..279bd032acf0 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -10,6 +10,42 @@
 #include "ff.h"
 
 #define FORMER_REG_SYNC_STATUS		0x0000801c0000ull
+/* For block write request. */
+#define FORMER_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
+
+static int former_switch_fetching_mode(struct snd_ff *ff, bool enable)
+{
+	unsigned int count;
+	__le32 *reg;
+	int i;
+	int err;
+
+	count = 0;
+	for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
+		count = max(count, ff->spec->pcm_playback_channels[i]);
+
+	reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
+	if (!reg)
+		return -ENOMEM;
+
+	if (!enable) {
+		/*
+		 * Each quadlet is corresponding to data channels in a data
+		 * blocks in reverse order. Precisely, quadlets for available
+		 * data channels should be enabled. Here, I take second best
+		 * to fetch PCM frames from all of data channels regardless of
+		 * stf.
+		 */
+		for (i = 0; i < count; ++i)
+			reg[i] = cpu_to_le32(0x00000001);
+	}
+
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
+				 FORMER_REG_FETCH_PCM_FRAMES, reg,
+				 sizeof(__le32) * count, 0);
+	kfree(reg);
+	return err;
+}
 
 static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
 {
@@ -347,6 +383,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
 
 const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 	.handle_midi_msg	= ff800_handle_midi_msg,
+	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff800_begin_session,
 	.finish_session		= ff800_finish_session,
 	.dump_status		= former_dump_status,
@@ -495,6 +532,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
 
 const struct snd_ff_protocol snd_ff_protocol_ff400 = {
 	.handle_midi_msg	= ff400_handle_midi_msg,
+	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff400_begin_session,
 	.finish_session		= ff400_finish_session,
 	.dump_status		= former_dump_status,
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index a490e4553721..43e1e2679798 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -37,44 +37,10 @@ static void release_resources(struct snd_ff *ff)
 	fw_iso_resources_free(&ff->rx_resources);
 }
 
-static int switch_fetching_mode(struct snd_ff *ff, bool enable)
-{
-	unsigned int count;
-	__le32 *reg;
-	int i;
-	int err;
-
-	count = 0;
-	for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
-		count = max(count, ff->spec->pcm_playback_channels[i]);
-
-	reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
-	if (!reg)
-		return -ENOMEM;
-
-	if (!enable) {
-		/*
-		 * Each quadlet is corresponding to data channels in a data
-		 * blocks in reverse order. Precisely, quadlets for available
-		 * data channels should be enabled. Here, I take second best
-		 * to fetch PCM frames from all of data channels regardless of
-		 * stf.
-		 */
-		for (i = 0; i < count; ++i)
-			reg[i] = cpu_to_le32(0x00000001);
-	}
-
-	err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
-				 SND_FF_REG_FETCH_PCM_FRAMES, reg,
-				 sizeof(__le32) * count, 0);
-	kfree(reg);
-	return err;
-}
-
 static inline void finish_session(struct snd_ff *ff)
 {
 	ff->spec->protocol->finish_session(ff);
-	switch_fetching_mode(ff, false);
+	ff->spec->protocol->switch_fetching_mode(ff, false);
 }
 
 static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
@@ -206,7 +172,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
 			goto error;
 		}
 
-		err = switch_fetching_mode(ff, true);
+		err = ff->spec->protocol->switch_fetching_mode(ff, true);
 		if (err < 0)
 			goto error;
 	}
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 3f22b8d84e36..29f55518bf85 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -35,8 +35,6 @@
 #define SND_FF_IN_MIDI_PORTS		2
 #define SND_FF_OUT_MIDI_PORTS		2
 
-/* For block write request. */
-#define SND_FF_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
 #define SND_FF_REG_CLOCK_CONFIG		0x0000801c0004ull
 
 enum snd_ff_stream_mode {
@@ -108,6 +106,7 @@ enum snd_ff_clock_src {
 
 struct snd_ff_protocol {
 	void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
+	int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
 	int (*begin_session)(struct snd_ff *ff, unsigned int rate);
 	void (*finish_session)(struct snd_ff *ff);
 	void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer);
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/9] ALSA: fireface: add protocol-dependent operation to get clock status
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (4 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 5/9] ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 7/9] ALSA: fireface: code refactoring for dump of sync status Takashi Sakamoto
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

This commit adds a member for a callback function to get clock status
to former protocol.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-pcm.c             |  2 +-
 sound/firewire/fireface/ff-protocol-former.c | 68 +++++++++++++++++++-
 sound/firewire/fireface/ff-stream.c          |  2 +-
 sound/firewire/fireface/ff-transaction.c     | 63 ------------------
 sound/firewire/fireface/ff.h                 |  6 +-
 5 files changed, 71 insertions(+), 70 deletions(-)

diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index d0bc96b20a65..5adf04b95c04 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -152,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
 	if (err < 0)
 		goto release_lock;
 
-	err = snd_ff_transaction_get_clock(ff, &rate, &src);
+	err = ff->spec->protocol->get_clock(ff, &rate, &src);
 	if (err < 0)
 		goto release_lock;
 
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index 279bd032acf0..d32104ed0c08 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -12,6 +12,70 @@
 #define FORMER_REG_SYNC_STATUS		0x0000801c0000ull
 /* For block write request. */
 #define FORMER_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
+#define FORMER_REG_CLOCK_CONFIG		0x0000801c0004ull
+
+static int former_get_clock(struct snd_ff *ff, unsigned int *rate,
+			    enum snd_ff_clock_src *src)
+{
+	__le32 reg;
+	u32 data;
+	int err;
+
+	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+				 FORMER_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+	data = le32_to_cpu(reg);
+
+	/* Calculate sampling rate. */
+	switch ((data >> 1) & 0x03) {
+	case 0x01:
+		*rate = 32000;
+		break;
+	case 0x00:
+		*rate = 44100;
+		break;
+	case 0x03:
+		*rate = 48000;
+		break;
+	case 0x02:
+	default:
+		return -EIO;
+	}
+
+	if (data & 0x08)
+		*rate *= 2;
+	else if (data & 0x10)
+		*rate *= 4;
+
+	/* Calculate source of clock. */
+	if (data & 0x01) {
+		*src = SND_FF_CLOCK_SRC_INTERNAL;
+	} else {
+		/* TODO: 0x02, 0x06, 0x07? */
+		switch ((data >> 10) & 0x07) {
+		case 0x00:
+			*src = SND_FF_CLOCK_SRC_ADAT1;
+			break;
+		case 0x01:
+			*src = SND_FF_CLOCK_SRC_ADAT2;
+			break;
+		case 0x03:
+			*src = SND_FF_CLOCK_SRC_SPDIF;
+			break;
+		case 0x04:
+			*src = SND_FF_CLOCK_SRC_WORD;
+			break;
+		case 0x05:
+			*src = SND_FF_CLOCK_SRC_LTC;
+			break;
+		default:
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
 
 static int former_switch_fetching_mode(struct snd_ff *ff, bool enable)
 {
@@ -56,7 +120,7 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
 	int err;
 
 	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
-				 SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
+				 FORMER_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
 	if (err < 0)
 		return;
 
@@ -383,6 +447,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
 
 const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 	.handle_midi_msg	= ff800_handle_midi_msg,
+	.get_clock		= former_get_clock,
 	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff800_begin_session,
 	.finish_session		= ff800_finish_session,
@@ -532,6 +597,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
 
 const struct snd_ff_protocol snd_ff_protocol_ff400 = {
 	.handle_midi_msg	= ff400_handle_midi_msg,
+	.get_clock		= former_get_clock,
 	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff400_begin_session,
 	.finish_session		= ff400_finish_session,
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c
index 43e1e2679798..a8a90f1ae09e 100644
--- a/sound/firewire/fireface/ff-stream.c
+++ b/sound/firewire/fireface/ff-stream.c
@@ -113,7 +113,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
 	if (ff->substreams_counter == 0)
 		return 0;
 
-	err = snd_ff_transaction_get_clock(ff, &curr_rate, &src);
+	err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
 	if (err < 0)
 		return err;
 	if (curr_rate != rate ||
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 5f4ddfd55403..065e045d3fb5 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -11,69 +11,6 @@
 #define SND_FF_REG_MIDI_RX_PORT_0	0x000080180000ull
 #define SND_FF_REG_MIDI_RX_PORT_1	0x000080190000ull
 
-int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
-				 enum snd_ff_clock_src *src)
-{
-	__le32 reg;
-	u32 data;
-	int err;
-
-	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
-				 SND_FF_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
-	if (err < 0)
-		return err;
-	data = le32_to_cpu(reg);
-
-	/* Calculate sampling rate. */
-	switch ((data >> 1) & 0x03) {
-	case 0x01:
-		*rate = 32000;
-		break;
-	case 0x00:
-		*rate = 44100;
-		break;
-	case 0x03:
-		*rate = 48000;
-		break;
-	case 0x02:
-	default:
-		return -EIO;
-	}
-
-	if (data & 0x08)
-		*rate *= 2;
-	else if (data & 0x10)
-		*rate *= 4;
-
-	/* Calculate source of clock. */
-	if (data & 0x01) {
-		*src = SND_FF_CLOCK_SRC_INTERNAL;
-	} else {
-		/* TODO: 0x02, 0x06, 0x07? */
-		switch ((data >> 10) & 0x07) {
-		case 0x00:
-			*src = SND_FF_CLOCK_SRC_ADAT1;
-			break;
-		case 0x01:
-			*src = SND_FF_CLOCK_SRC_ADAT2;
-			break;
-		case 0x03:
-			*src = SND_FF_CLOCK_SRC_SPDIF;
-			break;
-		case 0x04:
-			*src = SND_FF_CLOCK_SRC_WORD;
-			break;
-		case 0x05:
-			*src = SND_FF_CLOCK_SRC_LTC;
-			break;
-		default:
-			return -EIO;
-		}
-	}
-
-	return 0;
-}
-
 static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
 				     int rcode)
 {
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 29f55518bf85..1de2f5ec26fd 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -35,8 +35,6 @@
 #define SND_FF_IN_MIDI_PORTS		2
 #define SND_FF_OUT_MIDI_PORTS		2
 
-#define SND_FF_REG_CLOCK_CONFIG		0x0000801c0004ull
-
 enum snd_ff_stream_mode {
 	SND_FF_STREAM_MODE_LOW = 0,
 	SND_FF_STREAM_MODE_MID,
@@ -106,6 +104,8 @@ enum snd_ff_clock_src {
 
 struct snd_ff_protocol {
 	void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
+	int (*get_clock)(struct snd_ff *ff, unsigned int *rate,
+			 enum snd_ff_clock_src *src);
 	int (*switch_fetching_mode)(struct snd_ff *ff, bool enable);
 	int (*begin_session)(struct snd_ff *ff, unsigned int rate);
 	void (*finish_session)(struct snd_ff *ff);
@@ -115,8 +115,6 @@ struct snd_ff_protocol {
 extern const struct snd_ff_protocol snd_ff_protocol_ff800;
 extern const struct snd_ff_protocol snd_ff_protocol_ff400;
 
-int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate,
-				 enum snd_ff_clock_src *src);
 int snd_ff_transaction_register(struct snd_ff *ff);
 int snd_ff_transaction_reregister(struct snd_ff *ff);
 void snd_ff_transaction_unregister(struct snd_ff *ff);
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/9] ALSA: fireface: code refactoring for dump of sync status
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (5 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 6/9] ALSA: fireface: add protocol-dependent operation to get clock status Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 8/9] ALSA: fireface: code refactoring to parse of clock configuration Takashi Sakamoto
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

This commit adds refactoring for dump of sync status by adding
tables for check bits.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-protocol-former.c | 176 ++++++++-----------
 1 file changed, 75 insertions(+), 101 deletions(-)

diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index d32104ed0c08..fb2af10d2690 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -190,126 +190,100 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
 
 static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
 {
-	__le32 reg;
-	u32 data;
+	static const struct {
+		char *const label;
+		u32 locked_mask;
+		u32 synced_mask;
+	} *clk_entry, clk_entries[] = {
+		{ "WDClk",	0x40000000, 0x20000000, },
+		{ "S/PDIF",	0x00080000, 0x00040000, },
+		{ "ADAT1",	0x00000400, 0x00001000, },
+		{ "ADAT2",	0x00000800, 0x00002000, },
+	};
+	static const struct {
+		char *const label;
+		u32 mask;
+	} *referred_entry, referred_entries[] = {
+		{ "ADAT1",	0x00000000, },
+		{ "ADAT2",	0x00400000, },
+		{ "S/PDIF",	0x00c00000, },
+		{ "WDclk",	0x01000000, },
+		{ "TCO",	0x01400000, },
+	};
+	static const struct {
+		unsigned int rate;
+		u32 mask;
+	} *rate_entry, rate_entries[] = {
+		{ 32000,	0x02000000, },
+		{ 44100,	0x04000000, },
+		{ 48000,	0x06000000, },
+		{ 64000,	0x08000000, },
+		{ 88200,	0x0a000000, },
+		{ 96000,	0x0c000000, },
+		{ 128000,	0x0e000000, },
+		{ 176400,	0x10000000, },
+		{ 192000,	0x12000000, },
+	};
+	__le32 reg[2];
+	u32 data[2];
+	int i;
 	int err;
 
-	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
-				 FORMER_REG_SYNC_STATUS, &reg, sizeof(reg), 0);
+	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
+				 FORMER_REG_SYNC_STATUS, reg, sizeof(reg), 0);
 	if (err < 0)
 		return;
-
-	data = le32_to_cpu(reg);
+	data[0] = le32_to_cpu(reg[0]);
+	data[1] = le32_to_cpu(reg[1]);
 
 	snd_iprintf(buffer, "External source detection:\n");
 
-	snd_iprintf(buffer, "Word Clock:");
-	if ((data >> 24) & 0x20) {
-		if ((data >> 24) & 0x40)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
+	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+		const char *state;
+
+		clk_entry = clk_entries + i;
+		if (data[0] & clk_entry->locked_mask) {
+			if (data[0] & clk_entry->synced_mask)
+				state = "sync";
+			else
+				state = "lock";
+		} else {
+			state = "none";
+		}
 
-	snd_iprintf(buffer, "S/PDIF:");
-	if ((data >> 16) & 0x10) {
-		if ((data >> 16) & 0x04)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
+		snd_iprintf(buffer, "%s: %s\n", clk_entry->label, state);
 	}
 
-	snd_iprintf(buffer, "ADAT1:");
-	if ((data >> 8) & 0x04) {
-		if ((data >> 8) & 0x10)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
-	} else {
-		snd_iprintf(buffer, "none\n");
-	}
+	snd_iprintf(buffer, "Referred clock:\n");
 
-	snd_iprintf(buffer, "ADAT2:");
-	if ((data >> 8) & 0x08) {
-		if ((data >> 8) & 0x20)
-			snd_iprintf(buffer, "sync\n");
-		else
-			snd_iprintf(buffer, "lock\n");
+	if (data[1] & 0x00000001) {
+		snd_iprintf(buffer, "Internal\n");
 	} else {
-		snd_iprintf(buffer, "none\n");
-	}
+		unsigned int rate;
+		const char *label;
 
-	snd_iprintf(buffer, "\nUsed external source:\n");
-
-	if (((data >> 22) & 0x07) == 0x07) {
-		snd_iprintf(buffer, "None\n");
-	} else {
-		switch ((data >> 22) & 0x07) {
-		case 0x00:
-			snd_iprintf(buffer, "ADAT1:");
-			break;
-		case 0x01:
-			snd_iprintf(buffer, "ADAT2:");
-			break;
-		case 0x03:
-			snd_iprintf(buffer, "S/PDIF:");
-			break;
-		case 0x04:
-			snd_iprintf(buffer, "Word:");
-			break;
-		case 0x07:
-			snd_iprintf(buffer, "Nothing:");
-			break;
-		case 0x02:
-		case 0x05:
-		case 0x06:
-		default:
-			snd_iprintf(buffer, "unknown:");
-			break;
+		for (i = 0; i < ARRAY_SIZE(referred_entries); ++i) {
+			referred_entry = referred_entries + i;
+			if ((data[0] & 0x1e0000) == referred_entry->mask) {
+				label = referred_entry->label;
+				break;
+			}
 		}
+		if (i == ARRAY_SIZE(referred_entries))
+			label = "none";
 
-		if ((data >> 25) & 0x07) {
-			switch ((data >> 25) & 0x07) {
-			case 0x01:
-				snd_iprintf(buffer, "32000\n");
-				break;
-			case 0x02:
-				snd_iprintf(buffer, "44100\n");
-				break;
-			case 0x03:
-				snd_iprintf(buffer, "48000\n");
-				break;
-			case 0x04:
-				snd_iprintf(buffer, "64000\n");
-				break;
-			case 0x05:
-				snd_iprintf(buffer, "88200\n");
-				break;
-			case 0x06:
-				snd_iprintf(buffer, "96000\n");
-				break;
-			case 0x07:
-				snd_iprintf(buffer, "128000\n");
-				break;
-			case 0x08:
-				snd_iprintf(buffer, "176400\n");
-				break;
-			case 0x09:
-				snd_iprintf(buffer, "192000\n");
-				break;
-			case 0x00:
-				snd_iprintf(buffer, "unknown\n");
+		for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
+			rate_entry = rate_entries + i;
+			if ((data[0] & 0x1e000000) == rate_entry->mask) {
+				rate = rate_entry->rate;
 				break;
 			}
 		}
-	}
+		if (i == ARRAY_SIZE(rate_entries))
+			rate = 0;
 
-	snd_iprintf(buffer, "Multiplied:");
-	snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250);
+		snd_iprintf(buffer, "%s %d\n", label, rate);
+	}
 }
 
 static void former_dump_status(struct snd_ff *ff,
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 8/9] ALSA: fireface: code refactoring to parse of clock configuration
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (6 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 7/9] ALSA: fireface: code refactoring for dump of sync status Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-20  8:25 ` [PATCH 9/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
  2019-01-21 14:30 ` [PATCH 0/9] " Takashi Iwai
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

A procedure to retrieve clock configuration is used by two callers.
Each of caller has duplicated code to parse bits.

This commit adds refactoring to remove the duplicated code.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-proc.c            |  17 ++
 sound/firewire/fireface/ff-protocol-former.c | 172 ++++++++-----------
 sound/firewire/fireface/ff.h                 |   1 +
 3 files changed, 89 insertions(+), 101 deletions(-)

diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c
index 8a7cfb6ccce6..a55e68ec1832 100644
--- a/sound/firewire/fireface/ff-proc.c
+++ b/sound/firewire/fireface/ff-proc.c
@@ -8,6 +8,23 @@
 
 #include "./ff.h"
 
+const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src)
+{
+	static const char *const labels[] = {
+		"Internal",
+		"S/PDIF",
+		"ADAT1",
+		"ADAT2",
+		"Word",
+		"LTC",
+	};
+
+	if (src >= ARRAY_SIZE(labels))
+		return NULL;
+
+	return labels[src];
+}
+
 static void proc_dump_status(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
 {
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index fb2af10d2690..9c0ae50e88d1 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -14,6 +14,62 @@
 #define FORMER_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
 #define FORMER_REG_CLOCK_CONFIG		0x0000801c0004ull
 
+static int parse_clock_bits(u32 data, unsigned int *rate,
+			    enum snd_ff_clock_src *src)
+{
+	static const struct {
+		unsigned int rate;
+		u32 mask;
+	} *rate_entry, rate_entries[] = {
+		{  32000, 0x00000002, },
+		{  44100, 0x00000000, },
+		{  48000, 0x00000006, },
+		{  64000, 0x0000000a, },
+		{  88200, 0x00000008, },
+		{  96000, 0x0000000e, },
+		{ 128000, 0x00000012, },
+		{ 176400, 0x00000010, },
+		{ 192000, 0x00000016, },
+	};
+	static const struct {
+		enum snd_ff_clock_src src;
+		u32 mask;
+	} *clk_entry, clk_entries[] = {
+		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000000, },
+		{ SND_FF_CLOCK_SRC_ADAT2,	0x00000400, },
+		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000c00, },
+		{ SND_FF_CLOCK_SRC_WORD,	0x00001000, },
+		{ SND_FF_CLOCK_SRC_LTC,		0x00001800, },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
+		rate_entry = rate_entries + i;
+		if ((data & 0x0000001e) == rate_entry->mask) {
+			*rate = rate_entry->rate;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(rate_entries))
+		return -EIO;
+
+	if (data & 0x00000001) {
+		*src = SND_FF_CLOCK_SRC_INTERNAL;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+			clk_entry = clk_entries + i;
+			if ((data & 0x00001c00) == clk_entry->mask) {
+				*src = clk_entry->src;
+				break;
+			}
+		}
+		if (i == ARRAY_SIZE(clk_entries))
+			return -EIO;
+	}
+
+	return 0;
+}
+
 static int former_get_clock(struct snd_ff *ff, unsigned int *rate,
 			    enum snd_ff_clock_src *src)
 {
@@ -27,54 +83,7 @@ static int former_get_clock(struct snd_ff *ff, unsigned int *rate,
 		return err;
 	data = le32_to_cpu(reg);
 
-	/* Calculate sampling rate. */
-	switch ((data >> 1) & 0x03) {
-	case 0x01:
-		*rate = 32000;
-		break;
-	case 0x00:
-		*rate = 44100;
-		break;
-	case 0x03:
-		*rate = 48000;
-		break;
-	case 0x02:
-	default:
-		return -EIO;
-	}
-
-	if (data & 0x08)
-		*rate *= 2;
-	else if (data & 0x10)
-		*rate *= 4;
-
-	/* Calculate source of clock. */
-	if (data & 0x01) {
-		*src = SND_FF_CLOCK_SRC_INTERNAL;
-	} else {
-		/* TODO: 0x02, 0x06, 0x07? */
-		switch ((data >> 10) & 0x07) {
-		case 0x00:
-			*src = SND_FF_CLOCK_SRC_ADAT1;
-			break;
-		case 0x01:
-			*src = SND_FF_CLOCK_SRC_ADAT2;
-			break;
-		case 0x03:
-			*src = SND_FF_CLOCK_SRC_SPDIF;
-			break;
-		case 0x04:
-			*src = SND_FF_CLOCK_SRC_WORD;
-			break;
-		case 0x05:
-			*src = SND_FF_CLOCK_SRC_LTC;
-			break;
-		default:
-			return -EIO;
-		}
-	}
-
-	return 0;
+	return parse_clock_bits(data, rate, src);
 }
 
 static int former_switch_fetching_mode(struct snd_ff *ff, bool enable)
@@ -116,76 +125,37 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
 	__le32 reg;
 	u32 data;
 	unsigned int rate;
-	const char *src;
+	enum snd_ff_clock_src src;
+	const char *label;
 	int err;
 
 	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
 				 FORMER_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
 	if (err < 0)
 		return;
-
 	data = le32_to_cpu(reg);
 
 	snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
-		    (data & 0x20) ? "Professional" : "Consumer",
-		    (data & 0x40) ? "on" : "off");
+		    (data & 0x00000020) ? "Professional" : "Consumer",
+		    (data & 0x00000040) ? "on" : "off");
 
 	snd_iprintf(buffer, "Optical output interface format: %s\n",
-		    ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT");
+		    (data & 0x00000100) ? "S/PDIF" : "ADAT");
 
 	snd_iprintf(buffer, "Word output single speed: %s\n",
-		    ((data >> 8) & 0x20) ? "on" : "off");
+		    (data & 0x00002000) ? "on" : "off");
 
 	snd_iprintf(buffer, "S/PDIF input interface: %s\n",
-		    ((data >> 8) & 0x02) ? "Optical" : "Coaxial");
-
-	switch ((data >> 1) & 0x03) {
-	case 0x01:
-		rate = 32000;
-		break;
-	case 0x00:
-		rate = 44100;
-		break;
-	case 0x03:
-		rate = 48000;
-		break;
-	case 0x02:
-	default:
-		return;
-	}
-
-	if (data & 0x08)
-		rate *= 2;
-	else if (data & 0x10)
-		rate *= 4;
-
-	snd_iprintf(buffer, "Sampling rate: %d\n", rate);
+		    (data & 0x00000200) ? "Optical" : "Coaxial");
 
-	if (data & 0x01) {
-		src = "Internal";
-	} else {
-		switch ((data >> 10) & 0x07) {
-		case 0x00:
-			src = "ADAT1";
-			break;
-		case 0x01:
-			src = "ADAT2";
-			break;
-		case 0x03:
-			src = "S/PDIF";
-			break;
-		case 0x04:
-			src = "Word";
-			break;
-		case 0x05:
-			src = "LTC";
-			break;
-		default:
-			return;
-		}
-	}
+	err = parse_clock_bits(data, &rate, &src);
+	if (err < 0)
+		return;
+	label = snd_ff_proc_get_clk_label(src);
+	if (!label)
+		return;
 
-	snd_iprintf(buffer, "Sync to clock source: %s\n", src);
+	snd_iprintf(buffer, "Clock configuration: %d %s\n", rate, label);
 }
 
 static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 1de2f5ec26fd..cdb16e931c31 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -139,6 +139,7 @@ int snd_ff_stream_lock_try(struct snd_ff *ff);
 void snd_ff_stream_lock_release(struct snd_ff *ff);
 
 void snd_ff_proc_init(struct snd_ff *ff);
+const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src);
 
 int snd_ff_create_midi_devices(struct snd_ff *ff);
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 9/9] ALSA: fireface: add support for Fireface UCX
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (7 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 8/9] ALSA: fireface: code refactoring to parse of clock configuration Takashi Sakamoto
@ 2019-01-20  8:25 ` Takashi Sakamoto
  2019-01-21 14:30 ` [PATCH 0/9] " Takashi Iwai
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Sakamoto @ 2019-01-20  8:25 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Fireface UFX was shipped by RME GmbH in 2012. This model supports later
protocol for management of isochronous communication and synchronization
of sampling transmission frequency.

This commit adds support for the model. At present, it's not clear how
to encode MIDI messages and decide destination address for asynchronous
transaction, thus this commit adds support for isochronous communication
for PCM frames only.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/Kconfig                       |   1 +
 sound/firewire/fireface/Makefile             |   3 +-
 sound/firewire/fireface/ff-protocol-latter.c | 273 +++++++++++++++++++
 sound/firewire/fireface/ff.c                 |  41 ++-
 sound/firewire/fireface/ff.h                 |   1 +
 5 files changed, 310 insertions(+), 9 deletions(-)
 create mode 100644 sound/firewire/fireface/ff-protocol-latter.c

diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 052e00590259..b9e96d0b3a0a 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -163,5 +163,6 @@ config SND_FIREFACE
 	 Say Y here to include support for RME fireface series.
 	  * Fireface 400
 	  * Fireface 800
+	  * Fireface UCX
 
 endif # SND_FIREWIRE
diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 62eb78962b93..d64f4e2a1096 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,3 +1,4 @@
 snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \
-		     ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o
+		     ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o \
+		     ff-protocol-latter.o
 obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c
new file mode 100644
index 000000000000..64767ba439db
--- /dev/null
+++ b/sound/firewire/fireface/ff-protocol-latter.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+// ff-protocol-latter - a part of driver for RME Fireface series
+//
+// Copyright (c) 2019 Takashi Sakamoto
+//
+// Licensed under the terms of the GNU General Public License, version 2.
+
+#include <linux/delay.h>
+
+#include "ff.h"
+
+#define LATTER_STF		0xffff00000004
+#define LATTER_ISOC_CHANNELS	0xffff00000008
+#define LATTER_ISOC_START	0xffff0000000c
+#define LATTER_FETCH_MODE	0xffff00000010
+#define LATTER_SYNC_STATUS	0x0000801c0000
+
+static int parse_clock_bits(u32 data, unsigned int *rate,
+			    enum snd_ff_clock_src *src)
+{
+	static const struct {
+		unsigned int rate;
+		u32 flag;
+	} *rate_entry, rate_entries[] = {
+		{ 32000,	0x00000000, },
+		{ 44100,	0x01000000, },
+		{ 48000,	0x02000000, },
+		{ 64000,	0x04000000, },
+		{ 88200,	0x05000000, },
+		{ 96000,	0x06000000, },
+		{ 128000,	0x08000000, },
+		{ 176400,	0x09000000, },
+		{ 192000,	0x0a000000, },
+	};
+	static const struct {
+		enum snd_ff_clock_src src;
+		u32 flag;
+	} *clk_entry, clk_entries[] = {
+		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000200, },
+		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000400, },
+		{ SND_FF_CLOCK_SRC_WORD,	0x00000600, },
+		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
+		rate_entry = rate_entries + i;
+		if ((data & 0x0f000000) == rate_entry->flag) {
+			*rate = rate_entry->rate;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(rate_entries))
+		return -EIO;
+
+	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+		clk_entry = clk_entries + i;
+		if ((data & 0x000e00) == clk_entry->flag) {
+			*src = clk_entry->src;
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(clk_entries))
+		return -EIO;
+
+	return 0;
+}
+
+static int latter_get_clock(struct snd_ff *ff, unsigned int *rate,
+			   enum snd_ff_clock_src *src)
+{
+	__le32 reg;
+	u32 data;
+	int err;
+
+	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+	data = le32_to_cpu(reg);
+
+	return parse_clock_bits(data, rate, src);
+}
+
+static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
+{
+	u32 data;
+	__le32 reg;
+
+	if (enable)
+		data = 0x00000000;
+	else
+		data = 0xffffffff;
+	reg = cpu_to_le32(data);
+
+	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				  LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
+}
+
+static int keep_resources(struct snd_ff *ff, unsigned int rate)
+{
+	enum snd_ff_stream_mode mode;
+	int i;
+	int err;
+
+	// Check whether the given value is supported or not.
+	for (i = 0; i < CIP_SFC_COUNT; i++) {
+		if (amdtp_rate_table[i] == rate)
+			break;
+	}
+	if (i >= CIP_SFC_COUNT)
+		return -EINVAL;
+
+	err = snd_ff_stream_get_multiplier_mode(i, &mode);
+	if (err < 0)
+		return err;
+
+	/* Keep resources for in-stream. */
+	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
+	err = fw_iso_resources_allocate(&ff->tx_resources,
+			amdtp_stream_get_max_payload(&ff->tx_stream),
+			fw_parent_device(ff->unit)->max_speed);
+	if (err < 0)
+		return err;
+
+	/* Keep resources for out-stream. */
+	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
+	err = fw_iso_resources_allocate(&ff->rx_resources,
+			amdtp_stream_get_max_payload(&ff->rx_stream),
+			fw_parent_device(ff->unit)->max_speed);
+	if (err < 0)
+		fw_iso_resources_free(&ff->tx_resources);
+
+	return err;
+}
+
+static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
+{
+	static const struct {
+		unsigned int stf;
+		unsigned int code;
+		unsigned int flag;
+	} *entry, rate_table[] = {
+		{ 32000,  0x00, 0x92, },
+		{ 44100,  0x02, 0x92, },
+		{ 48000,  0x04, 0x92, },
+		{ 64000,  0x08, 0x8e, },
+		{ 88200,  0x0a, 0x8e, },
+		{ 96000,  0x0c, 0x8e, },
+		{ 128000, 0x10, 0x8c, },
+		{ 176400, 0x12, 0x8c, },
+		{ 192000, 0x14, 0x8c, },
+	};
+	u32 data;
+	__le32 reg;
+	unsigned int count;
+	int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(rate_table); ++i) {
+		entry = rate_table + i;
+		if (entry->stf == rate)
+			break;
+	}
+	if (i == ARRAY_SIZE(rate_table))
+		return -EINVAL;
+
+	reg = cpu_to_le32(entry->code);
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 LATTER_STF, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+
+	// Confirm to shift transmission clock.
+	count = 0;
+	while (count++ < 10) {
+		unsigned int curr_rate;
+		enum snd_ff_clock_src src;
+
+		err = latter_get_clock(ff, &curr_rate, &src);
+		if (err < 0)
+			return err;
+
+		if (curr_rate == rate)
+			break;
+	}
+	if (count == 10)
+		return -ETIMEDOUT;
+
+	err = keep_resources(ff, rate);
+	if (err < 0)
+		return err;
+
+	data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
+	reg = cpu_to_le32(data);
+	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				 LATTER_ISOC_CHANNELS, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return err;
+
+	// Always use the maximum number of data channels in data block of
+	// packet.
+	reg = cpu_to_le32(entry->flag);
+	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+				  LATTER_ISOC_START, &reg, sizeof(reg), 0);
+}
+
+static void latter_finish_session(struct snd_ff *ff)
+{
+	__le32 reg;
+
+	reg = cpu_to_le32(0x00000000);
+	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
+			   LATTER_ISOC_START, &reg, sizeof(reg), 0);
+}
+
+static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
+{
+	static const struct {
+		char *const label;
+		u32 locked_mask;
+		u32 synced_mask;
+	} *clk_entry, clk_entries[] = {
+		{ "S/PDIF",	0x00000001, 0x00000010, },
+		{ "ADAT",	0x00000002, 0x00000020, },
+		{ "WDClk",	0x00000004, 0x00000040, },
+	};
+	__le32 reg;
+	u32 data;
+	unsigned int rate;
+	enum snd_ff_clock_src src;
+	const char *label;
+	int i;
+	int err;
+
+	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
+				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);
+	if (err < 0)
+		return;
+	data = le32_to_cpu(reg);
+
+	snd_iprintf(buffer, "External source detection:\n");
+
+	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
+		clk_entry = clk_entries + i;
+		snd_iprintf(buffer, "%s: ", clk_entry->label);
+		if (data & clk_entry->locked_mask) {
+			if (data & clk_entry->synced_mask)
+				snd_iprintf(buffer, "sync\n");
+			else
+				snd_iprintf(buffer, "lock\n");
+		} else {
+			snd_iprintf(buffer, "none\n");
+		}
+	}
+
+	err = parse_clock_bits(data, &rate, &src);
+	if (err < 0)
+		return;
+	label = snd_ff_proc_get_clk_label(src);
+	if (!label)
+		return;
+
+	snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate);
+}
+
+const struct snd_ff_protocol snd_ff_protocol_latter = {
+	.get_clock		= latter_get_clock,
+	.switch_fetching_mode	= latter_switch_fetching_mode,
+	.begin_session		= latter_begin_session,
+	.finish_session		= latter_finish_session,
+	.dump_status		= latter_dump_status,
+};
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index 36575f4159d1..fd9c980e3cf4 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -32,7 +32,8 @@ static void ff_card_free(struct snd_card *card)
 	struct snd_ff *ff = card->private_data;
 
 	snd_ff_stream_destroy_duplex(ff);
-	snd_ff_transaction_unregister(ff);
+	if (ff->spec->midi_high_addr > 0)
+		snd_ff_transaction_unregister(ff);
 }
 
 static void do_registration(struct work_struct *work)
@@ -50,9 +51,11 @@ static void do_registration(struct work_struct *work)
 	ff->card->private_free = ff_card_free;
 	ff->card->private_data = ff;
 
-	err = snd_ff_transaction_register(ff);
-	if (err < 0)
-		goto error;
+	if (ff->spec->midi_high_addr > 0) {
+		err = snd_ff_transaction_register(ff);
+		if (err < 0)
+			goto error;
+	}
 
 	name_card(ff);
 
@@ -62,9 +65,11 @@ static void do_registration(struct work_struct *work)
 
 	snd_ff_proc_init(ff);
 
-	err = snd_ff_create_midi_devices(ff);
-	if (err < 0)
-		goto error;
+	if (ff->spec->midi_in_ports > 0 || ff->spec->midi_out_ports > 0) {
+		err = snd_ff_create_midi_devices(ff);
+		if (err < 0)
+			goto error;
+	}
 
 	err = snd_ff_create_pcm_devices(ff);
 	if (err < 0)
@@ -119,7 +124,8 @@ static void snd_ff_update(struct fw_unit *unit)
 	if (!ff->registered)
 		snd_fw_schedule_registration(unit, &ff->dwork);
 
-	snd_ff_transaction_reregister(ff);
+	if (ff->spec->midi_high_addr > 0)
+		snd_ff_transaction_reregister(ff);
 
 	if (ff->registered)
 		snd_ff_stream_update_duplex(ff);
@@ -165,6 +171,13 @@ static const struct snd_ff_spec spec_ff400 = {
 	.midi_high_addr = 0x0000801003f4ull,
 };
 
+static const struct snd_ff_spec spec_ucx = {
+	.name = "FirefaceUCX",
+	.pcm_capture_channels = {18, 14, 12},
+	.pcm_playback_channels = {18, 14, 12},
+	.protocol = &snd_ff_protocol_latter,
+};
+
 static const struct ieee1394_device_id snd_ff_id_table[] = {
 	/* Fireface 800 */
 	{
@@ -190,6 +203,18 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
 		.model_id	= 0x101800,
 		.driver_data	= (kernel_ulong_t)&spec_ff400,
 	},
+	// Fireface UCX.
+	{
+		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
+				  IEEE1394_MATCH_SPECIFIER_ID |
+				  IEEE1394_MATCH_VERSION |
+				  IEEE1394_MATCH_MODEL_ID,
+		.vendor_id	= OUI_RME,
+		.specifier_id	= OUI_RME,
+		.version	= 0x000004,
+		.model_id	= 0x101800,
+		.driver_data	= (kernel_ulong_t)&spec_ucx,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(ieee1394, snd_ff_id_table);
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index cdb16e931c31..8aea7920b57f 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -114,6 +114,7 @@ struct snd_ff_protocol {
 
 extern const struct snd_ff_protocol snd_ff_protocol_ff800;
 extern const struct snd_ff_protocol snd_ff_protocol_ff400;
+extern const struct snd_ff_protocol snd_ff_protocol_latter;
 
 int snd_ff_transaction_register(struct snd_ff *ff);
 int snd_ff_transaction_reregister(struct snd_ff *ff);
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/9] ALSA: fireface: add support for Fireface UCX
  2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
                   ` (8 preceding siblings ...)
  2019-01-20  8:25 ` [PATCH 9/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
@ 2019-01-21 14:30 ` Takashi Iwai
  9 siblings, 0 replies; 11+ messages in thread
From: Takashi Iwai @ 2019-01-21 14:30 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: ffado-devel, alsa-devel, clemens

On Sun, 20 Jan 2019 09:25:44 +0100,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> In 2012, RME GmbH shipped Fireface UFX. This model is one of latter
> models of Fireface series and support both of IEEE 1394 bus and USB.
> Furthermore, it supports two types of remote control unit (Basic
> Remote and Advanced Remote Control) with by 9pin mini-din connector.
> 
> This patchset adds support for this model, as a part of devices
> by ALSA firewire stack (therefore it's not a device of USB). At
> present, maintain of isochronous communication and synchronization
> status are cleared but asynchronous communication for MIDI messages
> are not yet, therefore this commit adds support for isochronous
> communication for PCM frames.
> 
> This work is based on my packet analysis from rent device for a short
> term (2 weeks). I'm happy to get your responses till next weekend.
> Driver code in a remote branch is available for backport till Linux
> kernel v4.17 or later for your test.
> https://github.com/takaswie/snd-firewire-improve/tree/topic/ff800-midi
> 
> Regards
> 
> Takashi Sakamoto (9):
>   ALSA: fireface: rename protocol layer for former models
>   ALSA: fireface: unify protocol layer for FF400/FF800
>   ALSA: fireface: obsolete proc node to leave one node
>   ALSA: fireface: add protocol-dependent operation to dump status
>   ALSA: fireface: add protocol-dependent operation to switch mode to
>     fetch PCM frame
>   ALSA: fireface: add protocol-dependent operation to get clock status
>   ALSA: fireface: code refactoring for dump of sync status
>   ALSA: fireface: code refactoring to parse of clock configuration
>   ALSA: fireface: add support for Fireface UCX

Applied all patches now.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-01-21 14:30 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-20  8:25 [PATCH 0/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 1/9] ALSA: fireface: rename protocol layer for former models Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 2/9] ALSA: fireface: unify protocol layer for FF400/FF800 Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 3/9] ALSA: fireface: obsolete proc node to leave one node Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 4/9] ALSA: fireface: add protocol-dependent operation to dump status Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 5/9] ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 6/9] ALSA: fireface: add protocol-dependent operation to get clock status Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 7/9] ALSA: fireface: code refactoring for dump of sync status Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 8/9] ALSA: fireface: code refactoring to parse of clock configuration Takashi Sakamoto
2019-01-20  8:25 ` [PATCH 9/9] ALSA: fireface: add support for Fireface UCX Takashi Sakamoto
2019-01-21 14:30 ` [PATCH 0/9] " Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.