diff options
-rw-r--r-- | sound/firewire/fireface/ff-midi.c | 2 | ||||
-rw-r--r-- | sound/firewire/fireface/ff-protocol-latter.c | 96 | ||||
-rw-r--r-- | sound/firewire/fireface/ff.c | 1 | ||||
-rw-r--r-- | 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]; |