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_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 err = snd_motu_stream_reserve_duplex(motu, 0); 22 if (err >= 0) { 23 ++motu->substreams_counter; 24 err = snd_motu_stream_start_duplex(motu); 25 } 26 27 mutex_unlock(&motu->mutex); 28 29 if (err < 0) 30 snd_motu_stream_lock_release(motu); 31 32 return err; 33 } 34 35 static int midi_close(struct snd_rawmidi_substream *substream) 36 { 37 struct snd_motu *motu = substream->rmidi->private_data; 38 39 mutex_lock(&motu->mutex); 40 41 --motu->substreams_counter; 42 snd_motu_stream_stop_duplex(motu); 43 44 mutex_unlock(&motu->mutex); 45 46 snd_motu_stream_lock_release(motu); 47 return 0; 48 } 49 50 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) 51 { 52 struct snd_motu *motu = substrm->rmidi->private_data; 53 unsigned long flags; 54 55 spin_lock_irqsave(&motu->lock, flags); 56 57 if (up) 58 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, 59 substrm); 60 else 61 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, 62 NULL); 63 64 spin_unlock_irqrestore(&motu->lock, flags); 65 } 66 67 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) 68 { 69 struct snd_motu *motu = substrm->rmidi->private_data; 70 unsigned long flags; 71 72 spin_lock_irqsave(&motu->lock, flags); 73 74 if (up) 75 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, 76 substrm); 77 else 78 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, 79 NULL); 80 81 spin_unlock_irqrestore(&motu->lock, flags); 82 } 83 84 static void set_midi_substream_names(struct snd_motu *motu, 85 struct snd_rawmidi_str *str) 86 { 87 struct snd_rawmidi_substream *subs; 88 89 list_for_each_entry(subs, &str->substreams, list) { 90 snprintf(subs->name, sizeof(subs->name), 91 "%s MIDI %d", motu->card->shortname, subs->number + 1); 92 } 93 } 94 95 int snd_motu_create_midi_devices(struct snd_motu *motu) 96 { 97 static const struct snd_rawmidi_ops capture_ops = { 98 .open = midi_open, 99 .close = midi_close, 100 .trigger = midi_capture_trigger, 101 }; 102 static const struct snd_rawmidi_ops playback_ops = { 103 .open = midi_open, 104 .close = midi_close, 105 .trigger = midi_playback_trigger, 106 }; 107 struct snd_rawmidi *rmidi; 108 struct snd_rawmidi_str *str; 109 int err; 110 111 /* create midi ports */ 112 err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi); 113 if (err < 0) 114 return err; 115 116 snprintf(rmidi->name, sizeof(rmidi->name), 117 "%s MIDI", motu->card->shortname); 118 rmidi->private_data = motu; 119 120 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | 121 SNDRV_RAWMIDI_INFO_OUTPUT | 122 SNDRV_RAWMIDI_INFO_DUPLEX; 123 124 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 125 &capture_ops); 126 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; 127 set_midi_substream_names(motu, str); 128 129 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 130 &playback_ops); 131 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 132 set_midi_substream_names(motu, str); 133 134 return 0; 135 } 136