]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/firewire/digi00x/digi00x-midi.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / sound / firewire / digi00x / digi00x-midi.c
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 }