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 err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0); 22 if (err >= 0) { 23 ++oxfw->substreams_count; 24 err = snd_oxfw_stream_start_duplex(oxfw); 25 if (err < 0) 26 --oxfw->substreams_count; 27 } 28 29 mutex_unlock(&oxfw->mutex); 30 31 if (err < 0) 32 snd_oxfw_stream_lock_release(oxfw); 33 34 return err; 35 } 36 37 static int midi_playback_open(struct snd_rawmidi_substream *substream) 38 { 39 struct snd_oxfw *oxfw = substream->rmidi->private_data; 40 int err; 41 42 err = snd_oxfw_stream_lock_try(oxfw); 43 if (err < 0) 44 return err; 45 46 mutex_lock(&oxfw->mutex); 47 48 err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0); 49 if (err >= 0) { 50 ++oxfw->substreams_count; 51 err = snd_oxfw_stream_start_duplex(oxfw); 52 } 53 54 mutex_unlock(&oxfw->mutex); 55 56 if (err < 0) 57 snd_oxfw_stream_lock_release(oxfw); 58 59 return err; 60 } 61 62 static int midi_capture_close(struct snd_rawmidi_substream *substream) 63 { 64 struct snd_oxfw *oxfw = substream->rmidi->private_data; 65 66 mutex_lock(&oxfw->mutex); 67 68 --oxfw->substreams_count; 69 snd_oxfw_stream_stop_duplex(oxfw); 70 71 mutex_unlock(&oxfw->mutex); 72 73 snd_oxfw_stream_lock_release(oxfw); 74 return 0; 75 } 76 77 static int midi_playback_close(struct snd_rawmidi_substream *substream) 78 { 79 struct snd_oxfw *oxfw = substream->rmidi->private_data; 80 81 mutex_lock(&oxfw->mutex); 82 83 --oxfw->substreams_count; 84 snd_oxfw_stream_stop_duplex(oxfw); 85 86 mutex_unlock(&oxfw->mutex); 87 88 snd_oxfw_stream_lock_release(oxfw); 89 return 0; 90 } 91 92 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) 93 { 94 struct snd_oxfw *oxfw = substrm->rmidi->private_data; 95 unsigned long flags; 96 97 spin_lock_irqsave(&oxfw->lock, flags); 98 99 if (up) 100 amdtp_am824_midi_trigger(&oxfw->tx_stream, 101 substrm->number, substrm); 102 else 103 amdtp_am824_midi_trigger(&oxfw->tx_stream, 104 substrm->number, NULL); 105 106 spin_unlock_irqrestore(&oxfw->lock, flags); 107 } 108 109 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) 110 { 111 struct snd_oxfw *oxfw = substrm->rmidi->private_data; 112 unsigned long flags; 113 114 spin_lock_irqsave(&oxfw->lock, flags); 115 116 if (up) 117 amdtp_am824_midi_trigger(&oxfw->rx_stream, 118 substrm->number, substrm); 119 else 120 amdtp_am824_midi_trigger(&oxfw->rx_stream, 121 substrm->number, NULL); 122 123 spin_unlock_irqrestore(&oxfw->lock, flags); 124 } 125 126 static void set_midi_substream_names(struct snd_oxfw *oxfw, 127 struct snd_rawmidi_str *str) 128 { 129 struct snd_rawmidi_substream *subs; 130 131 list_for_each_entry(subs, &str->substreams, list) { 132 scnprintf(subs->name, sizeof(subs->name), 133 "%s MIDI %d", 134 oxfw->card->shortname, subs->number + 1); 135 } 136 } 137 138 int snd_oxfw_create_midi(struct snd_oxfw *oxfw) 139 { 140 static const struct snd_rawmidi_ops capture_ops = { 141 .open = midi_capture_open, 142 .close = midi_capture_close, 143 .trigger = midi_capture_trigger, 144 }; 145 static const struct snd_rawmidi_ops playback_ops = { 146 .open = midi_playback_open, 147 .close = midi_playback_close, 148 .trigger = midi_playback_trigger, 149 }; 150 struct snd_rawmidi *rmidi; 151 struct snd_rawmidi_str *str; 152 int err; 153 154 if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0) 155 return 0; 156 157 /* create midi ports */ 158 err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0, 159 oxfw->midi_output_ports, oxfw->midi_input_ports, 160 &rmidi); 161 if (err < 0) 162 return err; 163 164 snprintf(rmidi->name, sizeof(rmidi->name), 165 "%s MIDI", oxfw->card->shortname); 166 rmidi->private_data = oxfw; 167 168 if (oxfw->midi_input_ports > 0) { 169 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 170 171 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 172 &capture_ops); 173 174 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; 175 176 set_midi_substream_names(oxfw, str); 177 } 178 179 if (oxfw->midi_output_ports > 0) { 180 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 181 182 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 183 &playback_ops); 184 185 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 186 187 set_midi_substream_names(oxfw, str); 188 } 189 190 if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0)) 191 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; 192 193 return 0; 194 } 195