summaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/motu/Makefile3
-rw-r--r--sound/firewire/motu/amdtp-motu.c3
-rw-r--r--sound/firewire/motu/motu-command-dsp-message-parser.c160
-rw-r--r--sound/firewire/motu/motu-protocol-v3.c10
-rw-r--r--sound/firewire/motu/motu-stream.c4
-rw-r--r--sound/firewire/motu/motu.c4
-rw-r--r--sound/firewire/motu/motu.h7
7 files changed, 186 insertions, 5 deletions
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index edbdf40c7162..3bef2a0b1e2e 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -4,5 +4,6 @@ CFLAGS_amdtp-motu.o := -I$(src)
snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
motu-protocol-v2.o motu-protocol-v3.o \
- motu-protocol-v1.o motu-register-dsp-message-parser.o
+ motu-protocol-v1.o motu-register-dsp-message-parser.o \
+ motu-command-dsp-message-parser.o
obj-$(CONFIG_SND_FIREWIRE_MOTU) += snd-firewire-motu.o
diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c
index 605b831492ac..3ea91e281147 100644
--- a/sound/firewire/motu/amdtp-motu.c
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -361,6 +361,9 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
snd_motu_register_dsp_message_parser_parse(motu, descs, packets,
s->data_block_quadlets);
+ } else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) {
+ snd_motu_command_dsp_message_parser_parse(motu, descs, packets,
+ s->data_block_quadlets);
}
// For tracepoints.
diff --git a/sound/firewire/motu/motu-command-dsp-message-parser.c b/sound/firewire/motu/motu-command-dsp-message-parser.c
new file mode 100644
index 000000000000..6716074f8bc1
--- /dev/null
+++ b/sound/firewire/motu/motu-command-dsp-message-parser.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// motu-command-dsp-message-parser.c - a part of driver for MOTU FireWire series
+//
+// Copyright (c) 2021 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+
+// Below models allow software to configure their DSP function by command transferred in
+// asynchronous transaction:
+// * 828 mk3 (FireWire only and Hybrid)
+// * 896 mk3 (FireWire only and Hybrid)
+// * Ultralite mk3 (FireWire only and Hybrid)
+// * Traveler mk3
+// * Track 16
+//
+// Isochronous packets from the above models includes messages to report state of hardware meter.
+
+#include "motu.h"
+
+enum msg_parser_state {
+ INITIALIZED,
+ FRAGMENT_DETECTED,
+ AVAILABLE,
+};
+
+struct msg_parser {
+ enum msg_parser_state state;
+ unsigned int interval;
+ unsigned int message_count;
+ unsigned int fragment_pos;
+ unsigned int value_index;
+ u64 value;
+ struct snd_firewire_motu_command_dsp_meter meter;
+};
+
+int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu)
+{
+ struct msg_parser *parser;
+
+ parser = devm_kzalloc(&motu->card->card_dev, sizeof(*parser), GFP_KERNEL);
+ if (!parser)
+ return -ENOMEM;
+ motu->message_parser = parser;
+
+ return 0;
+}
+
+int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc)
+{
+ struct msg_parser *parser = motu->message_parser;
+
+ parser->state = INITIALIZED;
+
+ // All of data blocks don't have messages with meaningful information.
+ switch (sfc) {
+ case CIP_SFC_176400:
+ case CIP_SFC_192000:
+ parser->interval = 4;
+ break;
+ case CIP_SFC_88200:
+ case CIP_SFC_96000:
+ parser->interval = 2;
+ break;
+ case CIP_SFC_32000:
+ case CIP_SFC_44100:
+ case CIP_SFC_48000:
+ default:
+ parser->interval = 1;
+ break;
+ }
+
+ return 0;
+}
+
+#define FRAGMENT_POS 6
+#define MIDI_BYTE_POS 7
+#define MIDI_FLAG_POS 8
+// One value of hardware meter consists of 4 messages.
+#define FRAGMENTS_PER_VALUE 4
+#define VALUES_AT_IMAGE_END 0xffffffffffffffff
+
+void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
+ unsigned int desc_count, unsigned int data_block_quadlets)
+{
+ struct msg_parser *parser = motu->message_parser;
+ unsigned int interval = parser->interval;
+ int i;
+
+ for (i = 0; i < desc_count; ++i) {
+ const struct pkt_desc *desc = descs + i;
+ __be32 *buffer = desc->ctx_payload;
+ unsigned int data_blocks = desc->data_blocks;
+ int j;
+
+ for (j = 0; j < data_blocks; ++j) {
+ u8 *b = (u8 *)buffer;
+ buffer += data_block_quadlets;
+
+ switch (parser->state) {
+ case INITIALIZED:
+ {
+ u8 fragment = b[FRAGMENT_POS];
+
+ if (fragment > 0) {
+ parser->value = fragment;
+ parser->message_count = 1;
+ parser->state = FRAGMENT_DETECTED;
+ }
+ break;
+ }
+ case FRAGMENT_DETECTED:
+ {
+ if (parser->message_count % interval == 0) {
+ u8 fragment = b[FRAGMENT_POS];
+
+ parser->value >>= 8;
+ parser->value |= (u64)fragment << 56;
+
+ if (parser->value == VALUES_AT_IMAGE_END) {
+ parser->state = AVAILABLE;
+ parser->fragment_pos = 0;
+ parser->value_index = 0;
+ parser->message_count = 0;
+ }
+ }
+ ++parser->message_count;
+ break;
+ }
+ case AVAILABLE:
+ default:
+ {
+ if (parser->message_count % interval == 0) {
+ u8 fragment = b[FRAGMENT_POS];
+
+ parser->value >>= 8;
+ parser->value |= (u64)fragment << 56;
+ ++parser->fragment_pos;
+
+ if (parser->fragment_pos == 4) {
+ if (parser->value_index <
+ SNDRV_FIREWIRE_MOTU_COMMAND_DSP_METER_COUNT) {
+ u32 val = (u32)(parser->value >> 32);
+ parser->meter.data[parser->value_index] = val;
+ ++parser->value_index;
+ }
+ parser->fragment_pos = 0;
+ }
+
+ if (parser->value == VALUES_AT_IMAGE_END) {
+ parser->value_index = 0;
+ parser->fragment_pos = 0;
+ parser->message_count = 0;
+ }
+ }
+ ++parser->message_count;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c
index d0dd587460de..05608e8ca0bc 100644
--- a/sound/firewire/motu/motu-protocol-v3.c
+++ b/sound/firewire/motu/motu-protocol-v3.c
@@ -261,12 +261,12 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu)
return 0;
}
-
const struct snd_motu_spec snd_motu_spec_828mk3_fw = {
.name = "828mk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
- SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+ SND_MOTU_SPEC_TX_MIDI_3RD_Q |
+ SND_MOTU_SPEC_COMMAND_DSP,
.tx_fixed_pcm_chunks = {18, 18, 14},
.rx_fixed_pcm_chunks = {14, 14, 10},
};
@@ -275,7 +275,8 @@ const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = {
.name = "828mk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
- SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+ SND_MOTU_SPEC_TX_MIDI_3RD_Q |
+ SND_MOTU_SPEC_COMMAND_DSP,
.tx_fixed_pcm_chunks = {18, 18, 14},
.rx_fixed_pcm_chunks = {14, 14, 14}, // Additional 4 dummy chunks at higher rate.
};
@@ -284,7 +285,8 @@ const struct snd_motu_spec snd_motu_spec_ultralite_mk3 = {
.name = "UltraLiteMk3",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_3RD_Q |
- SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+ SND_MOTU_SPEC_TX_MIDI_3RD_Q |
+ SND_MOTU_SPEC_COMMAND_DSP,
.tx_fixed_pcm_chunks = {18, 14, 10},
.rx_fixed_pcm_chunks = {14, 14, 14},
};
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
index 654b313ba98d..64aec9c3eefd 100644
--- a/sound/firewire/motu/motu-stream.c
+++ b/sound/firewire/motu/motu-stream.c
@@ -259,6 +259,10 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
err = snd_motu_register_dsp_message_parser_init(motu);
if (err < 0)
return err;
+ } else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) {
+ err = snd_motu_command_dsp_message_parser_init(motu, motu->tx_stream.sfc);
+ if (err < 0)
+ return err;
}
err = begin_session(motu);
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index 0edf8f594a55..5fc7ae475537 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -116,6 +116,10 @@ static int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
err = snd_motu_register_dsp_message_parser_new(motu);
if (err < 0)
goto error;
+ } else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) {
+ err = snd_motu_command_dsp_message_parser_new(motu);
+ if (err < 0)
+ goto error;
}
err = snd_card_register(card);
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 8d6850bb925e..d818ce4901c9 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -88,6 +88,7 @@ enum snd_motu_spec_flags {
SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0004,
SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0008,
SND_MOTU_SPEC_REGISTER_DSP = 0x0010,
+ SND_MOTU_SPEC_COMMAND_DSP = 0x0020,
};
#define SND_MOTU_CLOCK_RATE_COUNT 6
@@ -278,4 +279,10 @@ int snd_motu_register_dsp_message_parser_init(struct snd_motu *motu);
void snd_motu_register_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
unsigned int desc_count, unsigned int data_block_quadlets);
+
+int snd_motu_command_dsp_message_parser_new(struct snd_motu *motu);
+int snd_motu_command_dsp_message_parser_init(struct snd_motu *motu, enum cip_sfc sfc);
+void snd_motu_command_dsp_message_parser_parse(struct snd_motu *motu, const struct pkt_desc *descs,
+ unsigned int desc_count, unsigned int data_block_quadlets);
+
#endif