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_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_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_capture_trigger(struct snd_rawmidi_substream *substream, 44 int up) 45 { 46 struct snd_dg00x *dg00x = substream->rmidi->private_data; 47 unsigned int port; 48 unsigned long flags; 49 50 if (substream->rmidi->device == 0) 51 port = substream->number; 52 else 53 port = 2; 54 55 spin_lock_irqsave(&dg00x->lock, flags); 56 57 if (up) 58 amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream); 59 else 60 amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL); 61 62 spin_unlock_irqrestore(&dg00x->lock, flags); 63 } 64 65 static void midi_playback_trigger(struct snd_rawmidi_substream *substream, 66 int up) 67 { 68 struct snd_dg00x *dg00x = substream->rmidi->private_data; 69 unsigned int port; 70 unsigned long flags; 71 72 if (substream->rmidi->device == 0) 73 port = substream->number; 74 else 75 port = 2; 76 77 spin_lock_irqsave(&dg00x->lock, flags); 78 79 if (up) 80 amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream); 81 else 82 amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL); 83 84 spin_unlock_irqrestore(&dg00x->lock, flags); 85 } 86 87 static void set_substream_names(struct snd_dg00x *dg00x, 88 struct snd_rawmidi *rmidi, bool is_console) 89 { 90 struct snd_rawmidi_substream *subs; 91 struct snd_rawmidi_str *str; 92 int i; 93 94 for (i = 0; i < 2; ++i) { 95 str = &rmidi->streams[i]; 96 97 list_for_each_entry(subs, &str->substreams, list) { 98 if (!is_console) { 99 snprintf(subs->name, sizeof(subs->name), 100 "%s MIDI %d", 101 dg00x->card->shortname, 102 subs->number + 1); 103 } else { 104 snprintf(subs->name, sizeof(subs->name), 105 "%s control", 106 dg00x->card->shortname); 107 } 108 } 109 } 110 } 111 112 static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports, 113 unsigned int in_ports, bool is_console) 114 { 115 static const struct snd_rawmidi_ops capture_ops = { 116 .open = midi_open, 117 .close = midi_close, 118 .trigger = midi_capture_trigger, 119 }; 120 static const struct snd_rawmidi_ops playback_ops = { 121 .open = midi_open, 122 .close = midi_close, 123 .trigger = midi_playback_trigger, 124 }; 125 const char *label; 126 struct snd_rawmidi *rmidi; 127 int err; 128 129 /* Add physical midi ports. */ 130 err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console, 131 out_ports, in_ports, &rmidi); 132 if (err < 0) 133 return err; 134 rmidi->private_data = dg00x; 135 136 if (!is_console) 137 label = "%s control"; 138 else 139 label = "%s MIDI"; 140 snprintf(rmidi->name, sizeof(rmidi->name), label, 141 dg00x->card->shortname); 142 143 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops); 144 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops); 145 146 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | 147 SNDRV_RAWMIDI_INFO_OUTPUT | 148 SNDRV_RAWMIDI_INFO_DUPLEX; 149 150 set_substream_names(dg00x, rmidi, is_console); 151 152 return 0; 153 } 154 155 int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) 156 { 157 int err; 158 159 /* Add physical midi ports. */ 160 err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, 161 false); 162 if (err < 0) 163 return err; 164 165 if (dg00x->is_console) 166 err = add_substream_pair(dg00x, 1, 1, true); 167 168 return err; 169 } 170