summaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2017-03-31 22:06:04 +0900
committerTakashi Iwai <tiwai@suse.de>2017-04-05 21:31:34 +0200
commitff2c293efaf43feb120f6b166891e5eca0cf3ccc (patch)
treea2a9b5ce0b457147d751dab2839198d6432ae598 /sound/firewire
parent19174295788de77dd58dc6060b0d1bcfda21625e (diff)
downloadlinux-ff2c293efaf43feb120f6b166891e5eca0cf3ccc.tar.bz2
ALSA: fireface: add support for MIDI functionality
In previous commit, fireface driver supports unique transaction mechanism for MIDI feature. This commit adds MIDI functionality for userspace applications. As I wrote in a followed commit, user space applications get some requirement from this driver. It should not touch a register to which units transmit MIDI messages. It should configure a register in which MIDI transmission is controlled. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/fireface/Makefile2
-rw-r--r--sound/firewire/fireface/ff-midi.c131
-rw-r--r--sound/firewire/fireface/ff.c5
-rw-r--r--sound/firewire/fireface/ff.h3
4 files changed, 140 insertions, 1 deletions
diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile
index 864aacc80256..8e465e4bd539 100644
--- a/sound/firewire/fireface/Makefile
+++ b/sound/firewire/fireface/Makefile
@@ -1,2 +1,2 @@
-snd-fireface-objs := ff.o ff-transaction.o
+snd-fireface-objs := ff.o ff-transaction.o ff-midi.o
obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o
diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c
new file mode 100644
index 000000000000..29ee0a7365c3
--- /dev/null
+++ b/sound/firewire/fireface/ff-midi.c
@@ -0,0 +1,131 @@
+/*
+ * ff-midi.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 "ff.h"
+
+static int midi_capture_open(struct snd_rawmidi_substream *substream)
+{
+ /* Do nothing. */
+ return 0;
+}
+
+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->rx_midi_error[substream->number] = false;
+
+ ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = substream;
+
+ return 0;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *substream)
+{
+ /* Do nothing. */
+ return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_ff *ff = substream->rmidi->private_data;
+
+ cancel_work_sync(&ff->rx_midi_work[substream->number]);
+ ACCESS_ONCE(ff->rx_midi_substreams[substream->number]) = NULL;
+
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct snd_ff *ff = substream->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ff->lock, flags);
+
+ if (up)
+ ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) =
+ substream;
+ else
+ ACCESS_ONCE(ff->tx_midi_substreams[substream->number]) = NULL;
+
+ spin_unlock_irqrestore(&ff->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct snd_ff *ff = substream->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ff->lock, flags);
+
+ if (up || !ff->rx_midi_error[substream->number])
+ schedule_work(&ff->rx_midi_work[substream->number]);
+
+ spin_unlock_irqrestore(&ff->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_rawmidi_str *stream,
+ const char *const name)
+{
+ struct snd_rawmidi_substream *substream;
+
+ list_for_each_entry(substream, &stream->substreams, list) {
+ snprintf(substream->name, sizeof(substream->name),
+ "%s MIDI %d", name, substream->number + 1);
+ }
+}
+
+int snd_ff_create_midi_devices(struct snd_ff *ff)
+{
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *stream;
+ int err;
+
+ err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
+ ff->spec->midi_out_ports, ff->spec->midi_in_ports,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", ff->card->shortname);
+ rmidi->private_data = ff;
+
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &midi_capture_ops);
+ stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+ set_midi_substream_names(stream, ff->card->shortname);
+
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &midi_playback_ops);
+ stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+ set_midi_substream_names(stream, ff->card->shortname);
+
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c
index 4db630fe241c..11d76b372cd9 100644
--- a/sound/firewire/fireface/ff.c
+++ b/sound/firewire/fireface/ff.c
@@ -61,6 +61,10 @@ static void do_registration(struct work_struct *work)
name_card(ff);
+ err = snd_ff_create_midi_devices(ff);
+ if (err < 0)
+ goto error;
+
err = snd_card_register(ff->card);
if (err < 0)
goto error;
@@ -91,6 +95,7 @@ static int snd_ff_probe(struct fw_unit *unit,
dev_set_drvdata(&unit->device, ff);
mutex_init(&ff->mutex);
+ spin_lock_init(&ff->lock);
ff->spec = (const struct snd_ff_spec *)entry->driver_data;
diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h
index bac2e58b2e35..2944bde250bf 100644
--- a/sound/firewire/fireface/ff.h
+++ b/sound/firewire/fireface/ff.h
@@ -47,6 +47,7 @@ struct snd_ff {
struct snd_card *card;
struct fw_unit *unit;
struct mutex mutex;
+ spinlock_t lock;
bool registered;
struct delayed_work dwork;
@@ -98,4 +99,6 @@ 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);
+int snd_ff_create_midi_devices(struct snd_ff *ff);
+
#endif