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