summaryrefslogtreecommitdiff
path: root/sound/firewire/motu
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/motu')
-rw-r--r--sound/firewire/motu/Makefile2
-rw-r--r--sound/firewire/motu/amdtp-motu.c6
-rw-r--r--sound/firewire/motu/motu-protocol-v2.c14
-rw-r--r--sound/firewire/motu/motu-protocol-v3.c4
-rw-r--r--sound/firewire/motu/motu-register-dsp-message-parser.c145
-rw-r--r--sound/firewire/motu/motu-stream.c6
-rw-r--r--sound/firewire/motu/motu.c6
-rw-r--r--sound/firewire/motu/motu.h8
8 files changed, 184 insertions, 7 deletions
diff --git a/sound/firewire/motu/Makefile b/sound/firewire/motu/Makefile
index acdf66564fb0..edbdf40c7162 100644
--- a/sound/firewire/motu/Makefile
+++ b/sound/firewire/motu/Makefile
@@ -4,5 +4,5 @@ CFLAGS_amdtp-motu.o := -I$(src)
snd-firewire-motu-objs := motu.o amdtp-motu.o motu-transaction.o motu-stream.o \
motu-proc.o motu-pcm.o motu-midi.o motu-hwdep.o \
motu-protocol-v2.o motu-protocol-v3.o \
- motu-protocol-v1.o
+ motu-protocol-v1.o motu-register-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 a18c2c033e83..605b831492ac 100644
--- a/sound/firewire/motu/amdtp-motu.c
+++ b/sound/firewire/motu/amdtp-motu.c
@@ -333,6 +333,7 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
unsigned int packets,
struct snd_pcm_substream *pcm)
{
+ struct snd_motu *motu = container_of(s, struct snd_motu, tx_stream);
struct amdtp_motu *p = s->protocol;
unsigned int pcm_frames = 0;
int i;
@@ -357,6 +358,11 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
read_midi_messages(s, buf, data_blocks);
}
+ if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
+ snd_motu_register_dsp_message_parser_parse(motu, descs, packets,
+ s->data_block_quadlets);
+ }
+
// For tracepoints.
if (trace_data_block_sph_enabled() ||
trace_data_block_message_enabled())
diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c
index 2bd4485e4bc7..a5f70efa2e88 100644
--- a/sound/firewire/motu/motu-protocol-v2.c
+++ b/sound/firewire/motu/motu-protocol-v2.c
@@ -275,7 +275,8 @@ const struct snd_motu_spec snd_motu_spec_828mk2 = {
.name = "828mk2",
.protocol_version = SND_MOTU_PROTOCOL_V2,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
- SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+ SND_MOTU_SPEC_TX_MIDI_2ND_Q |
+ SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {14, 14, 0},
.rx_fixed_pcm_chunks = {14, 14, 0},
};
@@ -283,7 +284,7 @@ const struct snd_motu_spec snd_motu_spec_828mk2 = {
const struct snd_motu_spec snd_motu_spec_896hd = {
.name = "896HD",
.protocol_version = SND_MOTU_PROTOCOL_V2,
- // No support for MIDI.
+ .flags = SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {14, 14, 8},
.rx_fixed_pcm_chunks = {14, 14, 8},
};
@@ -292,7 +293,8 @@ const struct snd_motu_spec snd_motu_spec_traveler = {
.name = "Traveler",
.protocol_version = SND_MOTU_PROTOCOL_V2,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
- SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+ SND_MOTU_SPEC_TX_MIDI_2ND_Q |
+ SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {14, 14, 8},
.rx_fixed_pcm_chunks = {14, 14, 8},
};
@@ -301,7 +303,8 @@ const struct snd_motu_spec snd_motu_spec_ultralite = {
.name = "UltraLite",
.protocol_version = SND_MOTU_PROTOCOL_V2,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
- SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+ SND_MOTU_SPEC_TX_MIDI_2ND_Q |
+ SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {14, 14, 0},
.rx_fixed_pcm_chunks = {14, 14, 0},
};
@@ -310,7 +313,8 @@ const struct snd_motu_spec snd_motu_spec_8pre = {
.name = "8pre",
.protocol_version = SND_MOTU_PROTOCOL_V2,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
- SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+ SND_MOTU_SPEC_TX_MIDI_2ND_Q |
+ SND_MOTU_SPEC_REGISTER_DSP,
// Two dummy chunks always in the end of data block.
.tx_fixed_pcm_chunks = {10, 10, 0},
.rx_fixed_pcm_chunks = {6, 6, 0},
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c
index 56e4504e7ec9..d0dd587460de 100644
--- a/sound/firewire/motu/motu-protocol-v3.c
+++ b/sound/firewire/motu/motu-protocol-v3.c
@@ -293,7 +293,8 @@ const struct snd_motu_spec snd_motu_spec_audio_express = {
.name = "AudioExpress",
.protocol_version = SND_MOTU_PROTOCOL_V3,
.flags = SND_MOTU_SPEC_RX_MIDI_2ND_Q |
- SND_MOTU_SPEC_TX_MIDI_3RD_Q,
+ SND_MOTU_SPEC_TX_MIDI_3RD_Q |
+ SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {10, 10, 0},
.rx_fixed_pcm_chunks = {10, 10, 0},
};
@@ -301,6 +302,7 @@ const struct snd_motu_spec snd_motu_spec_audio_express = {
const struct snd_motu_spec snd_motu_spec_4pre = {
.name = "4pre",
.protocol_version = SND_MOTU_PROTOCOL_V3,
+ .flags = SND_MOTU_SPEC_REGISTER_DSP,
.tx_fixed_pcm_chunks = {10, 10, 0},
.rx_fixed_pcm_chunks = {10, 10, 0},
};
diff --git a/sound/firewire/motu/motu-register-dsp-message-parser.c b/sound/firewire/motu/motu-register-dsp-message-parser.c
new file mode 100644
index 000000000000..efb9708b5b5f
--- /dev/null
+++ b/sound/firewire/motu/motu-register-dsp-message-parser.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// motu-register-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 functions by asynchronous transaction
+// to access their internal registers.
+// * 828 mk2
+// * 896hd
+// * Traveler
+// * 8 pre
+// * Ultralite
+// * 4 pre
+// * Audio Express
+//
+// Additionally, isochronous packets from the above models include messages to notify state of
+// DSP. The messages are two set of 3 byte data in 2nd and 3rd quadlet of data block. When user
+// operates hardware components such as dial and switch, corresponding messages are transferred.
+// The messages include Hardware metering and MIDI messages as well.
+
+#include "motu.h"
+
+#define MSG_FLAG_POS 4
+#define MSG_FLAG_TYPE_MASK 0xf8
+#define MSG_FLAG_MIDI_MASK 0x01
+#define MSG_FLAG_MODEL_SPECIFIC_MASK 0x06
+#define MSG_FLAG_8PRE 0x00
+#define MSG_FLAG_ULTRALITE 0x04
+#define MSG_FLAG_TRAVELER 0x04
+#define MSG_FLAG_828MK2 0x04
+#define MSG_FLAG_896HD 0x04
+#define MSG_FLAG_4PRE 0x05 // MIDI mask is in 8th byte.
+#define MSG_FLAG_AUDIOEXPRESS 0x05 // MIDI mask is in 8th byte.
+#define MSG_FLAG_TYPE_SHIFT 3
+#define MSG_VALUE_POS 5
+#define MSG_MIDI_BYTE_POS 6
+#define MSG_METER_IDX_POS 7
+
+// In 4 pre and Audio express, meter index is in 6th byte. MIDI flag is in 8th byte and MIDI byte
+// is in 7th byte.
+#define MSG_METER_IDX_POS_4PRE_AE 6
+#define MSG_MIDI_BYTE_POS_4PRE_AE 7
+#define MSG_FLAG_MIDI_POS_4PRE_AE 8
+
+enum register_dsp_msg_type {
+ // Used for messages with no information.
+ INVALID = 0x00,
+ MIXER_SELECT = 0x01,
+ MIXER_SRC_GAIN = 0x02,
+ MIXER_SRC_PAN = 0x03,
+ MIXER_SRC_FLAG = 0x04,
+ MIXER_OUTPUT_PAIRED_VOLUME = 0x05,
+ MIXER_OUTPUT_PAIRED_FLAG = 0x06,
+ MAIN_OUTPUT_PAIRED_VOLUME = 0x07,
+ HP_OUTPUT_PAIRED_VOLUME = 0x08,
+ HP_OUTPUT_ASSIGN = 0x09,
+ // Transferred by all models but the purpose is still unknown.
+ UNKNOWN_0 = 0x0a,
+ // Specific to 828mk2, 896hd, Traveler.
+ UNKNOWN_2 = 0x0c,
+ // Specific to 828mk2, Traveler, and 896hd (not functional).
+ LINE_INPUT_BOOST = 0x0d,
+ // Specific to 828mk2, Traveler, and 896hd (not functional).
+ LINE_INPUT_NOMINAL_LEVEL = 0x0e,
+ // Specific to Ultralite, 4 pre, Audio express, and 8 pre (not functional).
+ INPUT_GAIN_AND_INVERT = 0x15,
+ // Specific to 4 pre, and Audio express.
+ INPUT_FLAG = 0x16,
+ // Specific to 4 pre, and Audio express.
+ MIXER_SRC_PAIRED_BALANCE = 0x17,
+ // Specific to 4 pre, and Audio express.
+ MIXER_SRC_PAIRED_WIDTH = 0x18,
+ // Transferred by all models. This type of message interposes the series of the other
+ // messages. The message delivers signal level up to 96.0 kHz. In 828mk2, 896hd, and
+ // Traveler, one of physical outputs is selected for the message. The selection is done
+ // by LSB one byte in asynchronous write quadlet transaction to 0x'ffff'f000'0b2c.
+ METER = 0x1f,
+};
+
+struct msg_parser {
+ struct snd_firewire_motu_register_dsp_meter meter;
+ bool meter_pos_quirk;
+};
+
+int snd_motu_register_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;
+ if (motu->spec == &snd_motu_spec_4pre || motu->spec == &snd_motu_spec_audio_express)
+ parser->meter_pos_quirk = true;
+ motu->message_parser = parser;
+ return 0;
+}
+
+int snd_motu_register_dsp_message_parser_init(struct snd_motu *motu)
+{
+ return 0;
+}
+
+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)
+{
+ struct msg_parser *parser = motu->message_parser;
+ bool meter_pos_quirk = parser->meter_pos_quirk;
+ 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;
+ u8 msg_type = (b[MSG_FLAG_POS] & MSG_FLAG_TYPE_MASK) >> MSG_FLAG_TYPE_SHIFT;
+ u8 val = b[MSG_VALUE_POS];
+
+ buffer += data_block_quadlets;
+
+ switch (msg_type) {
+ case METER:
+ {
+ u8 pos;
+
+ if (!meter_pos_quirk)
+ pos = b[MSG_METER_IDX_POS];
+ else
+ pos = b[MSG_METER_IDX_POS_4PRE_AE];
+
+ if (pos < 0x80)
+ pos &= 0x1f;
+ else
+ pos = (pos & 0x1f) + 20;
+ parser->meter.data[pos] = val;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c
index 9e6ca39ebd7f..654b313ba98d 100644
--- a/sound/firewire/motu/motu-stream.c
+++ b/sound/firewire/motu/motu-stream.c
@@ -255,6 +255,12 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu)
if (err < 0)
return err;
+ if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
+ err = snd_motu_register_dsp_message_parser_init(motu);
+ if (err < 0)
+ return err;
+ }
+
err = begin_session(motu);
if (err < 0) {
dev_err(&motu->unit->device,
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index f65426238d4c..0edf8f594a55 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -112,6 +112,12 @@ static int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
if (err < 0)
goto error;
+ if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) {
+ err = snd_motu_register_dsp_message_parser_new(motu);
+ if (err < 0)
+ goto error;
+ }
+
err = snd_card_register(card);
if (err < 0)
goto error;
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index f1a830b358d4..8d6850bb925e 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -78,6 +78,8 @@ struct snd_motu {
struct amdtp_domain domain;
struct amdtp_motu_cache cache;
+
+ void *message_parser;
};
enum snd_motu_spec_flags {
@@ -85,6 +87,7 @@ enum snd_motu_spec_flags {
SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0002,
SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0004,
SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0008,
+ SND_MOTU_SPEC_REGISTER_DSP = 0x0010,
};
#define SND_MOTU_CLOCK_RATE_COUNT 6
@@ -270,4 +273,9 @@ static inline int snd_motu_protocol_cache_packet_formats(struct snd_motu *motu)
return -ENXIO;
}
+int snd_motu_register_dsp_message_parser_new(struct snd_motu *motu);
+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);
+
#endif