ALSA: fireface: add support for MIDI functionality
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Fri, 31 Mar 2017 13:06:04 +0000 (22:06 +0900)
committerTakashi Iwai <tiwai@suse.de>
Wed, 5 Apr 2017 19:31:34 +0000 (21:31 +0200)
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>
sound/firewire/fireface/Makefile
sound/firewire/fireface/ff-midi.c [new file with mode: 0644]
sound/firewire/fireface/ff.c
sound/firewire/fireface/ff.h

index 864aacc80256750949b64f5110bbdd48073f9816..8e465e4bd539d3ee456064bc6e35959992d06d07 100644 (file)
@@ -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 (file)
index 0000000..29ee0a7
--- /dev/null
@@ -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;
+}
index 4db630fe241cbcdd06d8cf52c484b2cdf61817bd..11d76b372cd9353a65f04ed7cad41f180964c4db 100644 (file)
@@ -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;
 
index bac2e58b2e354c489cf691357ac78e6c0c2e50fa..2944bde250bf9d3f052f67753779bdbcc6f1e79f 100644 (file)
@@ -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