blob: 1a72a382b384beb5b8ab92c3f65c72920c4d510b [file] [log] [blame]
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +09001/*
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
Takashi Sakamoto5918f962015-10-31 02:43:14 +090011static int midi_phys_open(struct snd_rawmidi_substream *substream)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090012{
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
Takashi Sakamoto5918f962015-10-31 02:43:14 +090030static int midi_phys_close(struct snd_rawmidi_substream *substream)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090031{
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
Takashi Sakamoto5918f962015-10-31 02:43:14 +090043static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream,
44 int up)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090045{
Takashi Sakamoto5918f962015-10-31 02:43:14 +090046 struct snd_dg00x *dg00x = substream->rmidi->private_data;
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090047 unsigned long flags;
48
49 spin_lock_irqsave(&dg00x->lock, flags);
50
Takashi Sakamotod1482fb2015-10-31 02:43:16 +090051 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);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090057
58 spin_unlock_irqrestore(&dg00x->lock, flags);
59}
60
Takashi Sakamoto5918f962015-10-31 02:43:14 +090061static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
62 int up)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090063{
Takashi Sakamoto5918f962015-10-31 02:43:14 +090064 struct snd_dg00x *dg00x = substream->rmidi->private_data;
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090065 unsigned long flags;
66
67 spin_lock_irqsave(&dg00x->lock, flags);
68
Takashi Sakamotod1482fb2015-10-31 02:43:16 +090069 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);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090075
76 spin_unlock_irqrestore(&dg00x->lock, flags);
77}
78
Takashi Sakamoto5918f962015-10-31 02:43:14 +090079static struct snd_rawmidi_ops midi_phys_capture_ops = {
80 .open = midi_phys_open,
81 .close = midi_phys_close,
82 .trigger = midi_phys_capture_trigger,
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090083};
84
Takashi Sakamoto5918f962015-10-31 02:43:14 +090085static struct snd_rawmidi_ops midi_phys_playback_ops = {
86 .open = midi_phys_open,
87 .close = midi_phys_close,
88 .trigger = midi_phys_playback_trigger,
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090089};
90
Takashi Sakamotoc5fcee02015-10-31 02:43:15 +090091static int midi_ctl_open(struct snd_rawmidi_substream *substream)
92{
93 /* Do nothing. */
94 return 0;
95}
96
97static int midi_ctl_capture_close(struct snd_rawmidi_substream *substream)
98{
99 /* Do nothing. */
100 return 0;
101}
102
103static 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
112static 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
128static 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
142static 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
148static 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
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900154static void set_midi_substream_names(struct snd_dg00x *dg00x,
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900155 struct snd_rawmidi_str *str,
156 bool is_ctl)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900157{
158 struct snd_rawmidi_substream *subs;
159
160 list_for_each_entry(subs, &str->substreams, list) {
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900161 if (!is_ctl)
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +0900162 snprintf(subs->name, sizeof(subs->name),
163 "%s MIDI %d",
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900164 dg00x->card->shortname, subs->number + 1);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +0900165 else
166 /* This port is for asynchronous transaction. */
167 snprintf(subs->name, sizeof(subs->name),
168 "%s control",
169 dg00x->card->shortname);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900170 }
171}
172
173int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
174{
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900175 struct snd_rawmidi *rmidi[2];
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900176 struct snd_rawmidi_str *str;
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900177 unsigned int i;
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900178 int err;
179
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900180 /* Add physical midi ports. */
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900181 err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900182 DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS, &rmidi[0]);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900183 if (err < 0)
184 return err;
185
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900186 snprintf(rmidi[0]->name, sizeof(rmidi[0]->name),
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900187 "%s MIDI", dg00x->card->shortname);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900188
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900189 snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900190 &midi_phys_capture_ops);
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900191 snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900192 &midi_phys_playback_ops);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900193
Takashi Sakamotod1482fb2015-10-31 02:43:16 +0900194 /* 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 }
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900221
222 return 0;
223}