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