136 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tascam-midi.c - a part of driver for TASCAM FireWire series4 *5 * Copyright (c) 2015 Takashi Sakamoto6 */7 8#include "tascam.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_tscm *tscm = substream->rmidi->private_data;19 20 snd_fw_async_midi_port_init(&tscm->out_ports[substream->number]);21 22 return 0;23}24 25static int midi_capture_close(struct snd_rawmidi_substream *substream)26{27 /* Do nothing. */28 return 0;29}30 31static int midi_playback_close(struct snd_rawmidi_substream *substream)32{33 return 0;34}35 36static void midi_playback_drain(struct snd_rawmidi_substream *substream)37{38 struct snd_tscm *tscm = substream->rmidi->private_data;39 40 snd_fw_async_midi_port_finish(&tscm->out_ports[substream->number]);41}42 43static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)44{45 struct snd_tscm *tscm = substrm->rmidi->private_data;46 unsigned long flags;47 48 spin_lock_irqsave(&tscm->lock, flags);49 50 if (up)51 tscm->tx_midi_substreams[substrm->number] = substrm;52 else53 tscm->tx_midi_substreams[substrm->number] = NULL;54 55 spin_unlock_irqrestore(&tscm->lock, flags);56}57 58static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)59{60 struct snd_tscm *tscm = substrm->rmidi->private_data;61 unsigned long flags;62 63 spin_lock_irqsave(&tscm->lock, flags);64 65 if (up)66 snd_fw_async_midi_port_run(&tscm->out_ports[substrm->number],67 substrm);68 69 spin_unlock_irqrestore(&tscm->lock, flags);70}71 72int snd_tscm_create_midi_devices(struct snd_tscm *tscm)73{74 static const struct snd_rawmidi_ops capture_ops = {75 .open = midi_capture_open,76 .close = midi_capture_close,77 .trigger = midi_capture_trigger,78 };79 static const struct snd_rawmidi_ops playback_ops = {80 .open = midi_playback_open,81 .close = midi_playback_close,82 .drain = midi_playback_drain,83 .trigger = midi_playback_trigger,84 };85 struct snd_rawmidi *rmidi;86 struct snd_rawmidi_str *stream;87 struct snd_rawmidi_substream *subs;88 int err;89 90 err = snd_rawmidi_new(tscm->card, tscm->card->driver, 0,91 tscm->spec->midi_playback_ports,92 tscm->spec->midi_capture_ports,93 &rmidi);94 if (err < 0)95 return err;96 97 snprintf(rmidi->name, sizeof(rmidi->name),98 "%s MIDI", tscm->card->shortname);99 rmidi->private_data = tscm;100 101 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;102 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,103 &capture_ops);104 stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];105 106 /* Set port names for MIDI input. */107 list_for_each_entry(subs, &stream->substreams, list) {108 /* TODO: support virtual MIDI ports. */109 if (subs->number < tscm->spec->midi_capture_ports) {110 /* Hardware MIDI ports. */111 scnprintf(subs->name, sizeof(subs->name),112 "%s MIDI %d",113 tscm->card->shortname, subs->number + 1);114 }115 }116 117 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;118 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,119 &playback_ops);120 stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];121 122 /* Set port names for MIDI ourput. */123 list_for_each_entry(subs, &stream->substreams, list) {124 if (subs->number < tscm->spec->midi_playback_ports) {125 /* Hardware MIDI ports only. */126 scnprintf(subs->name, sizeof(subs->name),127 "%s MIDI %d",128 tscm->card->shortname, subs->number + 1);129 }130 }131 132 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;133 134 return 0;135}136