1 /* 2 * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family 3 * 4 * Copyright (c) 2014-2015 Takashi Sakamoto 5 * 6 * Licensed under the terms of the GNU General Public License, version 2. 7 */ 8 9 #include "digi00x.h" 10 11 static int midi_phys_open(struct snd_rawmidi_substream *substream) 12 { 13 struct snd_dg00x *dg00x = substream->rmidi->private_data; 14 int err; 15 16 err = snd_dg00x_stream_lock_try(dg00x); 17 if (err < 0) 18 return err; 19 20 mutex_lock(&dg00x->mutex); 21 dg00x->substreams_counter++; 22 err = snd_dg00x_stream_start_duplex(dg00x, 0); 23 mutex_unlock(&dg00x->mutex); 24 if (err < 0) 25 snd_dg00x_stream_lock_release(dg00x); 26 27 return err; 28 } 29 30 static int midi_phys_close(struct snd_rawmidi_substream *substream) 31 { 32 struct snd_dg00x *dg00x = substream->rmidi->private_data; 33 34 mutex_lock(&dg00x->mutex); 35 dg00x->substreams_counter--; 36 snd_dg00x_stream_stop_duplex(dg00x); 37 mutex_unlock(&dg00x->mutex); 38 39 snd_dg00x_stream_lock_release(dg00x); 40 return 0; 41 } 42 43 static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream, 44 int up) 45 { 46 struct snd_dg00x *dg00x = substream->rmidi->private_data; 47 unsigned long flags; 48 49 spin_lock_irqsave(&dg00x->lock, flags); 50 51 if (up) 52 amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number, 53 substream); 54 else 55 amdtp_dot_midi_trigger(&dg00x->tx_stream, substream->number, 56 NULL); 57 58 spin_unlock_irqrestore(&dg00x->lock, flags); 59 } 60 61 static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream, 62 int up) 63 { 64 struct snd_dg00x *dg00x = substream->rmidi->private_data; 65 unsigned long flags; 66 67 spin_lock_irqsave(&dg00x->lock, flags); 68 69 if (up) 70 amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number, 71 substream); 72 else 73 amdtp_dot_midi_trigger(&dg00x->rx_stream, substream->number, 74 NULL); 75 76 spin_unlock_irqrestore(&dg00x->lock, flags); 77 } 78 79 static struct snd_rawmidi_ops midi_phys_capture_ops = { 80 .open = midi_phys_open, 81 .close = midi_phys_close, 82 .trigger = midi_phys_capture_trigger, 83 }; 84 85 static struct snd_rawmidi_ops midi_phys_playback_ops = { 86 .open = midi_phys_open, 87 .close = midi_phys_close, 88 .trigger = midi_phys_playback_trigger, 89 }; 90 91 static int midi_ctl_open(struct snd_rawmidi_substream *substream) 92 { 93 /* Do nothing. */ 94 return 0; 95 } 96 97 static int midi_ctl_capture_close(struct snd_rawmidi_substream *substream) 98 { 99 /* Do nothing. */ 100 return 0; 101 } 102 103 static int midi_ctl_playback_close(struct snd_rawmidi_substream *substream) 104 { 105 struct snd_dg00x *dg00x = substream->rmidi->private_data; 106 107 snd_fw_async_midi_port_finish(&dg00x->out_control); 108 109 return 0; 110 } 111 112 static void midi_ctl_capture_trigger(struct snd_rawmidi_substream *substream, 113 int up) 114 { 115 struct snd_dg00x *dg00x = substream->rmidi->private_data; 116 unsigned long flags; 117 118 spin_lock_irqsave(&dg00x->lock, flags); 119 120 if (up) 121 dg00x->in_control = substream; 122 else 123 dg00x->in_control = NULL; 124 125 spin_unlock_irqrestore(&dg00x->lock, flags); 126 } 127 128 static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream, 129 int up) 130 { 131 struct snd_dg00x *dg00x = substream->rmidi->private_data; 132 unsigned long flags; 133 134 spin_lock_irqsave(&dg00x->lock, flags); 135 136 if (up) 137 snd_fw_async_midi_port_run(&dg00x->out_control, substream); 138 139 spin_unlock_irqrestore(&dg00x->lock, flags); 140 } 141 142 static struct snd_rawmidi_ops midi_ctl_capture_ops = { 143 .open = midi_ctl_open, 144 .close = midi_ctl_capture_close, 145 .trigger = midi_ctl_capture_trigger, 146 }; 147 148 static struct snd_rawmidi_ops midi_ctl_playback_ops = { 149 .open = midi_ctl_open, 150 .close = midi_ctl_playback_close, 151 .trigger = midi_ctl_playback_trigger, 152 }; 153 154 static void set_midi_substream_names(struct snd_dg00x *dg00x, 155 struct snd_rawmidi_str *str, 156 bool is_ctl) 157 { 158 struct snd_rawmidi_substream *subs; 159 160 list_for_each_entry(subs, &str->substreams, list) { 161 if (!is_ctl) 162 snprintf(subs->name, sizeof(subs->name), 163 "%s MIDI %d", 164 dg00x->card->shortname, subs->number + 1); 165 else 166 /* This port is for asynchronous transaction. */ 167 snprintf(subs->name, sizeof(subs->name), 168 "%s control", 169 dg00x->card->shortname); 170 } 171 } 172 173 int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) 174 { 175 struct snd_rawmidi *rmidi[2]; 176 struct snd_rawmidi_str *str; 177 unsigned int i; 178 int err; 179 180 /* Add physical midi ports. */ 181 err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0, 182 DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, &rmidi[0]); 183 if (err < 0) 184 return err; 185 186 snprintf(rmidi[0]->name, sizeof(rmidi[0]->name), 187 "%s MIDI", dg00x->card->shortname); 188 189 snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT, 190 &midi_phys_capture_ops); 191 snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT, 192 &midi_phys_playback_ops); 193 194 /* Add a pair of control midi ports. */ 195 err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1, 196 1, 1, &rmidi[1]); 197 if (err < 0) 198 return err; 199 200 snprintf(rmidi[1]->name, sizeof(rmidi[1]->name), 201 "%s control", dg00x->card->shortname); 202 203 snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT, 204 &midi_ctl_capture_ops); 205 snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT, 206 &midi_ctl_playback_ops); 207 208 for (i = 0; i < ARRAY_SIZE(rmidi); i++) { 209 rmidi[i]->private_data = dg00x; 210 211 rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 212 str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_INPUT]; 213 set_midi_substream_names(dg00x, str, i); 214 215 rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 216 str = &rmidi[i]->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 217 set_midi_substream_names(dg00x, str, i); 218 219 rmidi[i]->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; 220 } 221 222 return 0; 223 } 224