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