129 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ff-midi.c - a part of driver for RME Fireface series4 *5 * Copyright (c) 2015-2017 Takashi Sakamoto6 */7 8#include "ff.h"9 10static int midi_capture_open(struct snd_rawmidi_substream *substream)11{12 /* Do nothing. */13 return 0;14}15 16static int midi_playback_open(struct snd_rawmidi_substream *substream)17{18 struct snd_ff *ff = substream->rmidi->private_data;19 20 /* Initialize internal status. */21 ff->on_sysex[substream->number] = 0;22 ff->rx_midi_error[substream->number] = false;23 24 WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);25 26 return 0;27}28 29static int midi_capture_close(struct snd_rawmidi_substream *substream)30{31 /* Do nothing. */32 return 0;33}34 35static int midi_playback_close(struct snd_rawmidi_substream *substream)36{37 struct snd_ff *ff = substream->rmidi->private_data;38 39 cancel_work_sync(&ff->rx_midi_work[substream->number]);40 WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);41 42 return 0;43}44 45static void midi_capture_trigger(struct snd_rawmidi_substream *substream,46 int up)47{48 struct snd_ff *ff = substream->rmidi->private_data;49 unsigned long flags;50 51 spin_lock_irqsave(&ff->lock, flags);52 53 if (up)54 WRITE_ONCE(ff->tx_midi_substreams[substream->number],55 substream);56 else57 WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);58 59 spin_unlock_irqrestore(&ff->lock, flags);60}61 62static void midi_playback_trigger(struct snd_rawmidi_substream *substream,63 int up)64{65 struct snd_ff *ff = substream->rmidi->private_data;66 unsigned long flags;67 68 spin_lock_irqsave(&ff->lock, flags);69 70 if (up || !ff->rx_midi_error[substream->number])71 schedule_work(&ff->rx_midi_work[substream->number]);72 73 spin_unlock_irqrestore(&ff->lock, flags);74}75 76static void set_midi_substream_names(struct snd_rawmidi_str *stream,77 const char *const name)78{79 struct snd_rawmidi_substream *substream;80 81 list_for_each_entry(substream, &stream->substreams, list) {82 scnprintf(substream->name, sizeof(substream->name),83 "%s MIDI %d", name, substream->number + 1);84 }85}86 87int snd_ff_create_midi_devices(struct snd_ff *ff)88{89 static const struct snd_rawmidi_ops midi_capture_ops = {90 .open = midi_capture_open,91 .close = midi_capture_close,92 .trigger = midi_capture_trigger,93 };94 static const struct snd_rawmidi_ops midi_playback_ops = {95 .open = midi_playback_open,96 .close = midi_playback_close,97 .trigger = midi_playback_trigger,98 };99 struct snd_rawmidi *rmidi;100 struct snd_rawmidi_str *stream;101 int err;102 103 err = snd_rawmidi_new(ff->card, ff->card->driver, 0,104 ff->spec->midi_out_ports, ff->spec->midi_in_ports,105 &rmidi);106 if (err < 0)107 return err;108 109 snprintf(rmidi->name, sizeof(rmidi->name),110 "%s MIDI", ff->card->shortname);111 rmidi->private_data = ff;112 113 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;114 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,115 &midi_capture_ops);116 stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];117 set_midi_substream_names(stream, ff->card->shortname);118 119 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;120 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,121 &midi_playback_ops);122 stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];123 set_midi_substream_names(stream, ff->card->shortname);124 125 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;126 127 return 0;128}129