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