All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX
@ 2019-01-22 13:16 Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 1/6] ALSA: fireface: change prototype of handler for async transaction with MIDI messages Takashi Sakamoto
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:16 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Hi,

This patchset is a supplement of my previous one and to complete support
for Fireface UCX:
[alsa-devel] [PATCH 0/9] ALSA: fireface: add support for Fireface UCX
http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144465.html

The mechanism to use MIDi functionality of Fireface UCX is different
from the other supported devices; Fireface 800 and Fireface 400. This
patchset extends abstraction layer of hardware specification and
communication protocol.

Unfortunately, a bitflag to decide lower part of address to transfer
asynchronous transaction for MIDI message is in option register which
has the other options. This driver expects userspace applications to
configure the option as expected. In detail please refer to third patch.

For testers, a remote branch is available to backport a series of
patches to Linux kernel v4.17 or later:
https://github.com/takaswie/snd-firewire-improve/tree/topic/ff-ucx-midi

A userspace tool to configure addressed register is available in another
remote branch for hinawa-utils:
https://github.com/takaswie/hinawa-utils/tree/topic/ff-ucx

As I noted in previous patchset, this work is based on my packet analysis
from rent device for a short term (2 weeks). I'm happy to get your
response till next weekend.

Regards

Takashi Sakamoto (6):
  ALSA: fireface: change prototype of handler for async transaction with
    MIDI messages
  ALSA: fireface: add model-dependent parameter for address range to
    receive async transaction
  ALSA: fireface: support tx MIDI functionality of Fireface UCX
  ALSA: fireface: add model-dependent parameter for address to receive
    async transaction for MIDI messages
  ALSA: fireface: add protocol-specific operation to fill transaction
    buffer with MIDI messages
  ALSA: fireface: support rx MIDI functionality for Fireface UCX

 sound/firewire/fireface/ff-midi.c            |   2 +-
 sound/firewire/fireface/ff-protocol-former.c |  29 +++-
 sound/firewire/fireface/ff-protocol-latter.c | 139 +++++++++++++++++++
 sound/firewire/fireface/ff-transaction.c     |  44 +++---
 sound/firewire/fireface/ff.c                 |  31 +++--
 sound/firewire/fireface/ff.h                 |  10 +-
 6 files changed, 210 insertions(+), 45 deletions(-)

-- 
2.19.1

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

* [PATCH 1/6] ALSA: fireface: change prototype of handler for async transaction with MIDI messages
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 2/6] ALSA: fireface: add model-dependent parameter for address range to receive async transaction Takashi Sakamoto
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

In a series of Fireface, devices transfer asynchronous transaction with
MIDI messages. In the transaction, content is different depending on
models. ALSA fireface driver has protocol-dependent handler to pick up
MIDI messages from the content.

In latter models of the series, the transaction is transferred to range
of address sequentially. This seems to check continuity of transferred
messages.

This commit changes prototype of the handler to receive offset of
address for received transactions.

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

diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index 9c0ae50e88d1..266e4892a818 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -375,7 +375,8 @@ static void ff800_finish_session(struct snd_ff *ff)
 			   FF800_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
 }
 
-static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
+static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
+				  __le32 *buf, size_t length)
 {
 	int i;
 
@@ -502,7 +503,8 @@ static void ff400_finish_session(struct snd_ff *ff)
 			   FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
 }
 
-static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length)
+static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
+				  __le32 *buf, size_t length)
 {
 	int i;
 
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 065e045d3fb5..d3fde813ce17 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -146,7 +146,9 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request,
 
 	fw_send_response(card, request, RCODE_COMPLETE);
 
-	ff->spec->protocol->handle_midi_msg(ff, buf, length);
+	offset -= ff->async_handler.offset;
+	ff->spec->protocol->handle_midi_msg(ff, (unsigned int)offset, buf,
+					    length);
 }
 
 static int allocate_own_address(struct snd_ff *ff, int i)
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index 8aea7920b57f..ddcffb8d85c6 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -103,7 +103,8 @@ enum snd_ff_clock_src {
 };
 
 struct snd_ff_protocol {
-	void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length);
+	void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset,
+				__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);
-- 
2.19.1

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

* [PATCH 2/6] ALSA: fireface: add model-dependent parameter for address range to receive async transaction
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 1/6] ALSA: fireface: change prototype of handler for async transaction with MIDI messages Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 3/6] ALSA: fireface: support tx MIDI functionality of Fireface UCX Takashi Sakamoto
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

In Fireface series, drivers can register destination address for
asynchronous transaction which transfers MIDI messages from device.

In former models, all of the transactions arrive at the registered
address without any offset. In latter models, each of the transaction
arrives at the registered address with sequential offset within 0x00
to 0x7f. This seems to be for discontinuity detection.

This commit adds model-dependent member for the address range.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-transaction.c | 2 +-
 sound/firewire/fireface/ff.c             | 2 ++
 sound/firewire/fireface/ff.h             | 1 +
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index d3fde813ce17..0506755891ce 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -156,7 +156,7 @@ static int allocate_own_address(struct snd_ff *ff, int i)
 	struct fw_address_region midi_msg_region;
 	int err;
 
-	ff->async_handler.length = SND_FF_MAXIMIM_MIDI_QUADS * 4;
+	ff->async_handler.length = ff->spec->midi_addr_range;
 	ff->async_handler.address_callback = handle_midi_msg;
 	ff->async_handler.callback_data = ff;
 
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index fd9c980e3cf4..c09a4875aa86 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -159,6 +159,7 @@ static const struct snd_ff_spec spec_ff800 = {
 	.midi_out_ports = 1,
 	.protocol = &snd_ff_protocol_ff800,
 	.midi_high_addr = 0x000200000320ull,
+	.midi_addr_range = 12,
 };
 
 static const struct snd_ff_spec spec_ff400 = {
@@ -169,6 +170,7 @@ static const struct snd_ff_spec spec_ff400 = {
 	.midi_out_ports = 2,
 	.protocol = &snd_ff_protocol_ff400,
 	.midi_high_addr = 0x0000801003f4ull,
+	.midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4,
 };
 
 static const struct snd_ff_spec spec_ucx = {
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index ddcffb8d85c6..b86ca4fb7d9b 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -54,6 +54,7 @@ struct snd_ff_spec {
 
 	const struct snd_ff_protocol *protocol;
 	u64 midi_high_addr;
+	u8 midi_addr_range;
 };
 
 struct snd_ff {
-- 
2.19.1

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

* [PATCH 3/6] ALSA: fireface: support tx MIDI functionality of Fireface UCX
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 1/6] ALSA: fireface: change prototype of handler for async transaction with MIDI messages Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 2/6] ALSA: fireface: add model-dependent parameter for address range to receive async transaction Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 4/6] ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages Takashi Sakamoto
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Fireface UCX transfers asynchronous transactions for MIDI messages.
One transaction includes quadlet data therefore it can transfer 3
message bytes as maximum. Base address of the destination is
configured by two settings; a register for higher 8 byte of the
address, and a bitflag to option register indicates lower 8byte.

The register for higher address is 0x'ffff'0000'0034. Unfortunately,
firmware v24 includes a bug to ignore registered value for the
destination address and transfers to 0x0001xxxxxxxx always. This
driver doesn't work well if the bug exists, therefore users should
install the latest firmware (v27).

The bitflag is a part of value to be written to option register
(0x'ffff'0000'0014).

lower addr:  bitflag (little endian)
 '0000'0000: 0x00002000
 '0000'0080: 0x00004000
 '0000'0100: 0x00008000
 '0000'0180: 0x00010000

This register includes more options but they are not relevant to
packet streaming or MIDI functionality. This driver don't touch it.

Furthermore, the transaction is sent to address offset incremented
by 4 byte to the offset in previous time. When it reaches base address
plus 0x7c, next offset is the base address.

Content of the transaction includes a prefix byte. Upper 4 bits of
the byte indicates port number, and the rest 4 bits indicate the way
to decode rest of bytes for MIDI message.

Except for system exclusive messages, the rest bits are the same as
status bits of the message without channel bits. For system exclusive
messages, the rest bits are encoded according to included message bytes.
For example:

message: f0 7e 7f 09 01 f7
offset: content (little endian, port 0)
 '0000: 0x04f07e7f
 '0004: 0x070901f7

message: f0 00 00 66 14 20 00 00 00 f7
offset: content (little endian, port 1)
 '0014: 0x14f00000
 '0018: 0x14661420
 '001c: 0x14000000
 '0020: 0x15f70000

message: f0 00 00 66 14 20 00 00 f7
offset: content (little endian, port 0)
 '0078: 0x04f00000
 '007c: 0x04661420
 '0000: 0x070000f7

This commit supports decoding scheme for the above and allows
applications to receive MIDI messages via ALSA rawmidi interface.
The lower 8 bytes of destination address is fixed to 0x'0000'0000,
thus this driver expects userspace applications to configure option
register with bitflag 0x00002000 in advance.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-protocol-latter.c | 43 ++++++++++++++++++++
 sound/firewire/fireface/ff.c                 | 25 +++++-------
 2 files changed, 54 insertions(+), 14 deletions(-)

diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c
index 64767ba439db..a812ab6feb58 100644
--- a/sound/firewire/fireface/ff-protocol-latter.c
+++ b/sound/firewire/fireface/ff-protocol-latter.c
@@ -264,7 +264,50 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer
 	snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate);
 }
 
+// NOTE: transactions are transferred within 0x00-0x7f in allocated range of
+// address. This seems to be for check of discontinuity in receiver side.
+static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
+				   __le32 *buf, size_t length)
+{
+	u32 data = le32_to_cpu(*buf);
+	unsigned int index = (data & 0x000000f0) >> 4;
+	u8 byte[3];
+	struct snd_rawmidi_substream *substream;
+	unsigned int len;
+
+	if (index > ff->spec->midi_in_ports)
+		return;
+
+	switch (data & 0x0000000f) {
+	case 0x00000008:
+	case 0x00000009:
+	case 0x0000000a:
+	case 0x0000000b:
+	case 0x0000000e:
+		len = 3;
+		break;
+	case 0x0000000c:
+	case 0x0000000d:
+		len = 2;
+		break;
+	default:
+		len = data & 0x00000003;
+		if (len == 0)
+			len = 3;
+		break;
+	}
+
+	byte[0] = (data & 0x0000ff00) >> 8;
+	byte[1] = (data & 0x00ff0000) >> 16;
+	byte[2] = (data & 0xff000000) >> 24;
+
+	substream = READ_ONCE(ff->tx_midi_substreams[index]);
+	if (substream)
+		snd_rawmidi_receive(substream, byte, len);
+}
+
 const struct snd_ff_protocol snd_ff_protocol_latter = {
+	.handle_midi_msg	= latter_handle_midi_msg,
 	.get_clock		= latter_get_clock,
 	.switch_fetching_mode	= latter_switch_fetching_mode,
 	.begin_session		= latter_begin_session,
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index c09a4875aa86..a2a9fd82f27d 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -32,8 +32,7 @@ static void ff_card_free(struct snd_card *card)
 	struct snd_ff *ff = card->private_data;
 
 	snd_ff_stream_destroy_duplex(ff);
-	if (ff->spec->midi_high_addr > 0)
-		snd_ff_transaction_unregister(ff);
+	snd_ff_transaction_unregister(ff);
 }
 
 static void do_registration(struct work_struct *work)
@@ -51,11 +50,9 @@ static void do_registration(struct work_struct *work)
 	ff->card->private_free = ff_card_free;
 	ff->card->private_data = ff;
 
-	if (ff->spec->midi_high_addr > 0) {
-		err = snd_ff_transaction_register(ff);
-		if (err < 0)
-			goto error;
-	}
+	err = snd_ff_transaction_register(ff);
+	if (err < 0)
+		goto error;
 
 	name_card(ff);
 
@@ -65,11 +62,9 @@ static void do_registration(struct work_struct *work)
 
 	snd_ff_proc_init(ff);
 
-	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_midi_devices(ff);
+	if (err < 0)
+		goto error;
 
 	err = snd_ff_create_pcm_devices(ff);
 	if (err < 0)
@@ -124,8 +119,7 @@ static void snd_ff_update(struct fw_unit *unit)
 	if (!ff->registered)
 		snd_fw_schedule_registration(unit, &ff->dwork);
 
-	if (ff->spec->midi_high_addr > 0)
-		snd_ff_transaction_reregister(ff);
+	snd_ff_transaction_reregister(ff);
 
 	if (ff->registered)
 		snd_ff_stream_update_duplex(ff);
@@ -177,7 +171,10 @@ static const struct snd_ff_spec spec_ucx = {
 	.name = "FirefaceUCX",
 	.pcm_capture_channels = {18, 14, 12},
 	.pcm_playback_channels = {18, 14, 12},
+	.midi_in_ports = 2,
 	.protocol = &snd_ff_protocol_latter,
+	.midi_high_addr = 0xffff00000034ull,
+	.midi_addr_range = 0x80,
 };
 
 static const struct ieee1394_device_id snd_ff_id_table[] = {
-- 
2.19.1

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

* [PATCH 4/6] ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
                   ` (2 preceding siblings ...)
  2019-01-22 13:17 ` [PATCH 3/6] ALSA: fireface: support tx MIDI functionality of Fireface UCX Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 5/6] ALSA: fireface: add protocol-specific operation to fill transaction buffer with " Takashi Sakamoto
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Between former and latter models, destination address to receive
asynchronous transactions for MIDI messages is different.

This commit adds model-dependent parameter for the addresses.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-transaction.c | 7 ++-----
 sound/firewire/fireface/ff.c             | 3 +++
 sound/firewire/fireface/ff.h             | 1 +
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 0506755891ce..92ca76ab7537 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -8,9 +8,6 @@
 
 #include "ff.h"
 
-#define SND_FF_REG_MIDI_RX_PORT_0	0x000080180000ull
-#define SND_FF_REG_MIDI_RX_PORT_1	0x000080190000ull
-
 static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port,
 				     int rcode)
 {
@@ -93,10 +90,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 		fill_midi_buf(ff, port, i, buf[i]);
 
 	if (port == 0) {
-		addr = SND_FF_REG_MIDI_RX_PORT_0;
+		addr = ff->spec->midi_rx_addrs[0];
 		callback = finish_transmit_midi0_msg;
 	} else {
-		addr = SND_FF_REG_MIDI_RX_PORT_1;
+		addr = ff->spec->midi_rx_addrs[1];
 		callback = finish_transmit_midi1_msg;
 	}
 
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index a2a9fd82f27d..675c6ab556eb 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -154,6 +154,7 @@ static const struct snd_ff_spec spec_ff800 = {
 	.protocol = &snd_ff_protocol_ff800,
 	.midi_high_addr = 0x000200000320ull,
 	.midi_addr_range = 12,
+	.midi_rx_addrs = {0x000080180000ull, 0},
 };
 
 static const struct snd_ff_spec spec_ff400 = {
@@ -165,6 +166,7 @@ static const struct snd_ff_spec spec_ff400 = {
 	.protocol = &snd_ff_protocol_ff400,
 	.midi_high_addr = 0x0000801003f4ull,
 	.midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4,
+	.midi_rx_addrs = {0x000080180000ull, 0x000080190000ull},
 };
 
 static const struct snd_ff_spec spec_ucx = {
@@ -175,6 +177,7 @@ static const struct snd_ff_spec spec_ucx = {
 	.protocol = &snd_ff_protocol_latter,
 	.midi_high_addr = 0xffff00000034ull,
 	.midi_addr_range = 0x80,
+	.midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull},
 };
 
 static const struct ieee1394_device_id snd_ff_id_table[] = {
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index b86ca4fb7d9b..edad75a4b260 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -55,6 +55,7 @@ struct snd_ff_spec {
 	const struct snd_ff_protocol *protocol;
 	u64 midi_high_addr;
 	u8 midi_addr_range;
+	u64 midi_rx_addrs[SND_FF_OUT_MIDI_PORTS];
 };
 
 struct snd_ff {
-- 
2.19.1

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

* [PATCH 5/6] ALSA: fireface: add protocol-specific operation to fill transaction buffer with MIDI messages
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
                   ` (3 preceding siblings ...)
  2019-01-22 13:17 ` [PATCH 4/6] ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 13:17 ` [PATCH 6/6] ALSA: fireface: support rx MIDI functionality for Fireface UCX Takashi Sakamoto
  2019-01-22 16:21 ` [PATCH 0/6] ALSA: fireface: support MIDI functionality of " Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

Between former and latter models, content of asynchronous transaction
for MIDI messages from driver to device is different.

This commit is a preparation to support latter models. A protocol-specific
operation is added to encode MIDI messages to the transaction.

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

diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index 266e4892a818..e0acf40a02ee 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -263,6 +263,27 @@ static void former_dump_status(struct snd_ff *ff,
 	dump_sync_status(ff, buffer);
 }
 
+static int former_fill_midi_msg(struct snd_ff *ff,
+				struct snd_rawmidi_substream *substream,
+				unsigned int port)
+{
+	u8 *buf = (u8 *)ff->msg_buf[port];
+	int len;
+	int i;
+
+	len = snd_rawmidi_transmit_peek(substream, buf,
+					SND_FF_MAXIMIM_MIDI_QUADS);
+	if (len <= 0)
+		return len;
+
+	// One quadlet includes one byte.
+	for (i = len - 1; i >= 0; --i)
+		ff->msg_buf[port][i] = cpu_to_le32(buf[i]);
+	ff->rx_bytes[port] = len;
+
+	return len;
+}
+
 #define FF800_STF		0x0000fc88f000
 #define FF800_RX_PACKET_FORMAT	0x0000fc88f004
 #define FF800_ALLOC_TX_STREAM	0x0000fc88f008
@@ -392,6 +413,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
 
 const struct snd_ff_protocol snd_ff_protocol_ff800 = {
 	.handle_midi_msg	= ff800_handle_midi_msg,
+	.fill_midi_msg		= former_fill_midi_msg,
 	.get_clock		= former_get_clock,
 	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff800_begin_session,
@@ -543,6 +565,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
 
 const struct snd_ff_protocol snd_ff_protocol_ff400 = {
 	.handle_midi_msg	= ff400_handle_midi_msg,
+	.fill_midi_msg		= former_fill_midi_msg,
 	.get_clock		= former_get_clock,
 	.switch_fetching_mode	= former_switch_fetching_mode,
 	.begin_session		= ff400_begin_session,
diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c
index 92ca76ab7537..d8a8b01b39a1 100644
--- a/sound/firewire/fireface/ff-transaction.c
+++ b/sound/firewire/fireface/ff-transaction.c
@@ -51,23 +51,17 @@ static void finish_transmit_midi1_msg(struct fw_card *card, int rcode,
 	finish_transmit_midi_msg(ff, 1, rcode);
 }
 
-static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port,
-				 unsigned int index, u8 byte)
-{
-	ff->msg_buf[port][index] = cpu_to_le32(byte);
-}
-
 static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 {
 	struct snd_rawmidi_substream *substream =
 			READ_ONCE(ff->rx_midi_substreams[port]);
-	u8 *buf = (u8 *)ff->msg_buf[port];
-	int i, len;
+	int quad_count;
 
 	struct fw_device *fw_dev = fw_parent_device(ff->unit);
 	unsigned long long addr;
 	int generation;
 	fw_transaction_callback_t callback;
+	int tcode;
 
 	if (substream == NULL || snd_rawmidi_transmit_empty(substream))
 		return;
@@ -81,14 +75,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 		return;
 	}
 
-	len = snd_rawmidi_transmit_peek(substream, buf,
-					SND_FF_MAXIMIM_MIDI_QUADS);
-	if (len <= 0)
+	quad_count = ff->spec->protocol->fill_midi_msg(ff, substream, port);
+	if (quad_count <= 0)
 		return;
 
-	for (i = len - 1; i >= 0; i--)
-		fill_midi_buf(ff, port, i, buf[i]);
-
 	if (port == 0) {
 		addr = ff->spec->midi_rx_addrs[0];
 		callback = finish_transmit_midi0_msg;
@@ -99,8 +89,12 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 
 	/* Set interval to next transaction. */
 	ff->next_ktime[port] = ktime_add_ns(ktime_get(),
-					    len * 8 * NSEC_PER_SEC / 31250);
-	ff->rx_bytes[port] = len;
+				ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250);
+
+	if (quad_count == 1)
+		tcode = TCODE_WRITE_QUADLET_REQUEST;
+	else
+		tcode = TCODE_WRITE_BLOCK_REQUEST;
 
 	/*
 	 * In Linux FireWire core, when generation is updated with memory
@@ -112,10 +106,9 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
 	 */
 	generation = fw_dev->generation;
 	smp_rmb();
-	fw_send_request(fw_dev->card, &ff->transactions[port],
-			TCODE_WRITE_BLOCK_REQUEST,
+	fw_send_request(fw_dev->card, &ff->transactions[port], tcode,
 			fw_dev->node_id, generation, fw_dev->max_speed,
-			addr, &ff->msg_buf[port], len * 4,
+			addr, &ff->msg_buf[port], quad_count * 4,
 			callback, &ff->transactions[port]);
 }
 
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index edad75a4b260..e52ad11803e0 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -107,6 +107,9 @@ enum snd_ff_clock_src {
 struct snd_ff_protocol {
 	void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset,
 				__le32 *buf, size_t length);
+	int (*fill_midi_msg)(struct snd_ff *ff,
+			     struct snd_rawmidi_substream *substream,
+			     unsigned int port);
 	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);
-- 
2.19.1

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

* [PATCH 6/6] ALSA: fireface: support rx MIDI functionality for Fireface UCX
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
                   ` (4 preceding siblings ...)
  2019-01-22 13:17 ` [PATCH 5/6] ALSA: fireface: add protocol-specific operation to fill transaction buffer with " Takashi Sakamoto
@ 2019-01-22 13:17 ` Takashi Sakamoto
  2019-01-22 16:21 ` [PATCH 0/6] ALSA: fireface: support MIDI functionality of " Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Sakamoto @ 2019-01-22 13:17 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, ffado-devel

In latter model of Fireface series, asynchronous transaction includes
a prefix byte to indicate the way to decode included MIDI bytes.

Upper 4 bits of the prefix byte indicates port number, and the rest 4
bits indicate the way to decode rest of bytes for MIDI messages.

Basically the rest bits indicates the number of bytes for MIDI message.
However, if the last byte of each MIDi message is included, the rest
bits are 0xf. For example:

message: f0 00 00 66 14 20 00 00 f7
offset: content (big endian, port 0)
 '0030: 0x02f00000
 '0030: 0x03006614
 '0030: 0x03200000
 '0030: 0x0ff70000

This commit supports encoding scheme for the above and allows
applications to transfer MIDI messages via ALSA rawmidi interface.
An unused member (running_status) is reused to keep state of
transmission of system exclusive messages.

For your information, this is a dump of config rom.

$ sudo ./hinawa-config-rom-printer /dev/fw1
{ 'bus-info': { 'bmc': False,
                'chip_ID': 13225063715,
                'cmc': False,
                'cyc_clk_acc': 0,
                'imc': False,
                'isc': True,
                'max_rec': 512,
                'name': '1394',
                'node_vendor_ID': 2613},
  'root-directory': [ [ 'NODE_CAPABILITIES',
                        { 'addressing': {'64': True, 'fix': True, 'prv': False},
                          'misc': {'int': False, 'ms': False, 'spt': True},
                          'state': { 'atn': False,
                                     'ded': False,
                                     'drq': True,
                                     'elo': False,
                                     'init': False,
                                     'lst': True,
                                     'off': False},
                          'testing': {'bas': False, 'ext': False}}],
                      ['VENDOR', 2613],
                      ['DESCRIPTOR', 'RME!'],
                      ['EUI_64', 2873037108442403],
                      [ 'UNIT',
                        [ ['SPECIFIER_ID', 2613],
                          ['VERSION', 4],
                          ['MODEL', 1054720],
                          ['DESCRIPTOR', 'Fireface UCX']]]]}

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/fireface/ff-midi.c            |  2 +-
 sound/firewire/fireface/ff-protocol-latter.c | 96 ++++++++++++++++++++
 sound/firewire/fireface/ff.c                 |  1 +
 sound/firewire/fireface/ff.h                 |  2 +-
 4 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c
index 6a49611ee462..5b44e1c4569a 100644
--- a/sound/firewire/fireface/ff-midi.c
+++ b/sound/firewire/fireface/ff-midi.c
@@ -19,7 +19,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
 	struct snd_ff *ff = substream->rmidi->private_data;
 
 	/* Initialize internal status. */
-	ff->running_status[substream->number] = 0;
+	ff->on_sysex[substream->number] = 0;
 	ff->rx_midi_error[substream->number] = false;
 
 	WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c
index a812ab6feb58..817af4447349 100644
--- a/sound/firewire/fireface/ff-protocol-latter.c
+++ b/sound/firewire/fireface/ff-protocol-latter.c
@@ -306,8 +306,104 @@ static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
 		snd_rawmidi_receive(substream, byte, len);
 }
 
+/*
+ * When return minus value, given argument is not MIDI status.
+ * When return 0, given argument is a beginning of system exclusive.
+ * When return the others, given argument is MIDI data.
+ */
+static inline int calculate_message_bytes(u8 status)
+{
+	switch (status) {
+	case 0xf6:	/* Tune request. */
+	case 0xf8:	/* Timing clock. */
+	case 0xfa:	/* Start. */
+	case 0xfb:	/* Continue. */
+	case 0xfc:	/* Stop. */
+	case 0xfe:	/* Active sensing. */
+	case 0xff:	/* System reset. */
+		return 1;
+	case 0xf1:	/* MIDI time code quarter frame. */
+	case 0xf3:	/* Song select. */
+		return 2;
+	case 0xf2:	/* Song position pointer. */
+		return 3;
+	case 0xf0:	/* Exclusive. */
+		return 0;
+	case 0xf7:	/* End of exclusive. */
+		break;
+	case 0xf4:	/* Undefined. */
+	case 0xf5:	/* Undefined. */
+	case 0xf9:	/* Undefined. */
+	case 0xfd:	/* Undefined. */
+		break;
+	default:
+		switch (status & 0xf0) {
+		case 0x80:	/* Note on. */
+		case 0x90:	/* Note off. */
+		case 0xa0:	/* Polyphonic key pressure. */
+		case 0xb0:	/* Control change and Mode change. */
+		case 0xe0:	/* Pitch bend change. */
+			return 3;
+		case 0xc0:	/* Program change. */
+		case 0xd0:	/* Channel pressure. */
+			return 2;
+		default:
+		break;
+		}
+	break;
+	}
+
+	return -EINVAL;
+}
+
+static int latter_fill_midi_msg(struct snd_ff *ff,
+				struct snd_rawmidi_substream *substream,
+				unsigned int port)
+{
+	u32 data = {0};
+	u8 *buf = (u8 *)&data;
+	int consumed;
+
+	buf[0] = port << 4;
+	consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3);
+	if (consumed <= 0)
+		return consumed;
+
+	if (!ff->on_sysex[port]) {
+		if (buf[1] != 0xf0) {
+			if (consumed < calculate_message_bytes(buf[1]))
+				return 0;
+		} else {
+			// The beginning of exclusives.
+			ff->on_sysex[port] = true;
+		}
+
+		buf[0] |= consumed;
+	} else {
+		if (buf[1] != 0xf7) {
+			if (buf[2] == 0xf7 || buf[3] == 0xf7) {
+				// Transfer end code at next time.
+				consumed -= 1;
+			}
+
+			buf[0] |= consumed;
+		} else {
+			// The end of exclusives.
+			ff->on_sysex[port] = false;
+			consumed = 1;
+			buf[0] |= 0x0f;
+		}
+	}
+
+	ff->msg_buf[port][0] = cpu_to_le32(data);
+	ff->rx_bytes[port] = consumed;
+
+	return 1;
+}
+
 const struct snd_ff_protocol snd_ff_protocol_latter = {
 	.handle_midi_msg	= latter_handle_midi_msg,
+	.fill_midi_msg		= latter_fill_midi_msg,
 	.get_clock		= latter_get_clock,
 	.switch_fetching_mode	= latter_switch_fetching_mode,
 	.begin_session		= latter_begin_session,
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index 675c6ab556eb..a9611157f4c8 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -174,6 +174,7 @@ static const struct snd_ff_spec spec_ucx = {
 	.pcm_capture_channels = {18, 14, 12},
 	.pcm_playback_channels = {18, 14, 12},
 	.midi_in_ports = 2,
+	.midi_out_ports = 2,
 	.protocol = &snd_ff_protocol_latter,
 	.midi_high_addr = 0xffff00000034ull,
 	.midi_addr_range = 0x80,
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index e52ad11803e0..ed8fea0ff5e1 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -75,7 +75,7 @@ struct snd_ff {
 
 	/* TO handle MIDI rx. */
 	struct snd_rawmidi_substream *rx_midi_substreams[SND_FF_OUT_MIDI_PORTS];
-	u8 running_status[SND_FF_OUT_MIDI_PORTS];
+	bool on_sysex[SND_FF_OUT_MIDI_PORTS];
 	__le32 msg_buf[SND_FF_OUT_MIDI_PORTS][SND_FF_MAXIMIM_MIDI_QUADS];
 	struct work_struct rx_midi_work[SND_FF_OUT_MIDI_PORTS];
 	struct fw_transaction transactions[SND_FF_OUT_MIDI_PORTS];
-- 
2.19.1

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

* Re: [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX
  2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
                   ` (5 preceding siblings ...)
  2019-01-22 13:17 ` [PATCH 6/6] ALSA: fireface: support rx MIDI functionality for Fireface UCX Takashi Sakamoto
@ 2019-01-22 16:21 ` Takashi Iwai
  6 siblings, 0 replies; 8+ messages in thread
From: Takashi Iwai @ 2019-01-22 16:21 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: ffado-devel, alsa-devel, clemens

On Tue, 22 Jan 2019 14:16:59 +0100,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> This patchset is a supplement of my previous one and to complete support
> for Fireface UCX:
> [alsa-devel] [PATCH 0/9] ALSA: fireface: add support for Fireface UCX
> http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144465.html
> 
> The mechanism to use MIDi functionality of Fireface UCX is different
> from the other supported devices; Fireface 800 and Fireface 400. This
> patchset extends abstraction layer of hardware specification and
> communication protocol.
> 
> Unfortunately, a bitflag to decide lower part of address to transfer
> asynchronous transaction for MIDI message is in option register which
> has the other options. This driver expects userspace applications to
> configure the option as expected. In detail please refer to third patch.
> 
> For testers, a remote branch is available to backport a series of
> patches to Linux kernel v4.17 or later:
> https://github.com/takaswie/snd-firewire-improve/tree/topic/ff-ucx-midi
> 
> A userspace tool to configure addressed register is available in another
> remote branch for hinawa-utils:
> https://github.com/takaswie/hinawa-utils/tree/topic/ff-ucx
> 
> As I noted in previous patchset, this work is based on my packet analysis
> from rent device for a short term (2 weeks). I'm happy to get your
> response till next weekend.
> 
> Regards
> 
> Takashi Sakamoto (6):
>   ALSA: fireface: change prototype of handler for async transaction with
>     MIDI messages
>   ALSA: fireface: add model-dependent parameter for address range to
>     receive async transaction
>   ALSA: fireface: support tx MIDI functionality of Fireface UCX
>   ALSA: fireface: add model-dependent parameter for address to receive
>     async transaction for MIDI messages
>   ALSA: fireface: add protocol-specific operation to fill transaction
>     buffer with MIDI messages
>   ALSA: fireface: support rx MIDI functionality for Fireface UCX

Applied all patches now.  Thanks.


Takashi

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

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

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-22 13:16 [PATCH 0/6] ALSA: fireface: support MIDI functionality of Fireface UCX Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 1/6] ALSA: fireface: change prototype of handler for async transaction with MIDI messages Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 2/6] ALSA: fireface: add model-dependent parameter for address range to receive async transaction Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 3/6] ALSA: fireface: support tx MIDI functionality of Fireface UCX Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 4/6] ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 5/6] ALSA: fireface: add protocol-specific operation to fill transaction buffer with " Takashi Sakamoto
2019-01-22 13:17 ` [PATCH 6/6] ALSA: fireface: support rx MIDI functionality for Fireface UCX Takashi Sakamoto
2019-01-22 16:21 ` [PATCH 0/6] ALSA: fireface: support MIDI functionality of " 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.