1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * motu-midi.h - a part of driver for MOTU FireWire series 4 * 5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6 */ 7 #include "motu.h" 8 9 static int midi_capture_open(struct snd_rawmidi_substream *substream) 10 { 11 struct snd_motu *motu = substream->rmidi->private_data; 12 int err; 13 14 err = snd_motu_stream_lock_try(motu); 15 if (err < 0) 16 return err; 17 18 mutex_lock(&motu->mutex); 19 20 motu->capture_substreams++; 21 err = snd_motu_stream_start_duplex(motu, 0); 22 23 mutex_unlock(&motu->mutex); 24 25 if (err < 0) 26 snd_motu_stream_lock_release(motu); 27 28 return err; 29 } 30 31 static int midi_playback_open(struct snd_rawmidi_substream *substream) 32 { 33 struct snd_motu *motu = substream->rmidi->private_data; 34 int err; 35 36 err = snd_motu_stream_lock_try(motu); 37 if (err < 0) 38 return err; 39 40 mutex_lock(&motu->mutex); 41 42 motu->playback_substreams++; 43 err = snd_motu_stream_start_duplex(motu, 0); 44 45 mutex_unlock(&motu->mutex); 46 47 if (err < 0) 48 snd_motu_stream_lock_release(motu); 49 50 return err; 51 } 52 53 static int midi_capture_close(struct snd_rawmidi_substream *substream) 54 { 55 struct snd_motu *motu = substream->rmidi->private_data; 56 57 mutex_lock(&motu->mutex); 58 59 motu->capture_substreams--; 60 snd_motu_stream_stop_duplex(motu); 61 62 mutex_unlock(&motu->mutex); 63 64 snd_motu_stream_lock_release(motu); 65 return 0; 66 } 67 68 static int midi_playback_close(struct snd_rawmidi_substream *substream) 69 { 70 struct snd_motu *motu = substream->rmidi->private_data; 71 72 mutex_lock(&motu->mutex); 73 74 motu->playback_substreams--; 75 snd_motu_stream_stop_duplex(motu); 76 77 mutex_unlock(&motu->mutex); 78 79 snd_motu_stream_lock_release(motu); 80 return 0; 81 } 82 83 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) 84 { 85 struct snd_motu *motu = substrm->rmidi->private_data; 86 unsigned long flags; 87 88 spin_lock_irqsave(&motu->lock, flags); 89 90 if (up) 91 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, 92 substrm); 93 else 94 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, 95 NULL); 96 97 spin_unlock_irqrestore(&motu->lock, flags); 98 } 99 100 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) 101 { 102 struct snd_motu *motu = substrm->rmidi->private_data; 103 unsigned long flags; 104 105 spin_lock_irqsave(&motu->lock, flags); 106 107 if (up) 108 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, 109 substrm); 110 else 111 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, 112 NULL); 113 114 spin_unlock_irqrestore(&motu->lock, flags); 115 } 116 117 static void set_midi_substream_names(struct snd_motu *motu, 118 struct snd_rawmidi_str *str) 119 { 120 struct snd_rawmidi_substream *subs; 121 122 list_for_each_entry(subs, &str->substreams, list) { 123 snprintf(subs->name, sizeof(subs->name), 124 "%s MIDI %d", motu->card->shortname, subs->number + 1); 125 } 126 } 127 128 int snd_motu_create_midi_devices(struct snd_motu *motu) 129 { 130 static const struct snd_rawmidi_ops capture_ops = { 131 .open = midi_capture_open, 132 .close = midi_capture_close, 133 .trigger = midi_capture_trigger, 134 }; 135 static const struct snd_rawmidi_ops playback_ops = { 136 .open = midi_playback_open, 137 .close = midi_playback_close, 138 .trigger = midi_playback_trigger, 139 }; 140 struct snd_rawmidi *rmidi; 141 struct snd_rawmidi_str *str; 142 int err; 143 144 /* create midi ports */ 145 err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi); 146 if (err < 0) 147 return err; 148 149 snprintf(rmidi->name, sizeof(rmidi->name), 150 "%s MIDI", motu->card->shortname); 151 rmidi->private_data = motu; 152 153 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | 154 SNDRV_RAWMIDI_INFO_OUTPUT | 155 SNDRV_RAWMIDI_INFO_DUPLEX; 156 157 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 158 &capture_ops); 159 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; 160 set_midi_substream_names(motu, str); 161 162 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 163 &playback_ops); 164 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 165 set_midi_substream_names(motu, str); 166 167 return 0; 168 } 169