]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/firewire/digi00x/digi00x-midi.c
Merge tag 'asoc-v4.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[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_open(struct snd_rawmidi_substream *substream)
12 {
13         struct snd_dg00x *dg00x = substream->rmidi->private_data;
14         int err;
15
16         /* This port is for asynchronous transaction. */
17         if (substream->number == 0)
18                 return 0;
19
20         err = snd_dg00x_stream_lock_try(dg00x);
21         if (err < 0)
22                 return err;
23
24         mutex_lock(&dg00x->mutex);
25         dg00x->substreams_counter++;
26         err = snd_dg00x_stream_start_duplex(dg00x, 0);
27         mutex_unlock(&dg00x->mutex);
28         if (err < 0)
29                 snd_dg00x_stream_lock_release(dg00x);
30
31         return err;
32 }
33
34 static int midi_close(struct snd_rawmidi_substream *substream)
35 {
36         struct snd_dg00x *dg00x = substream->rmidi->private_data;
37
38         /* This port is for asynchronous transaction. */
39         if (substream->number == 0)
40                 return 0;
41
42         mutex_lock(&dg00x->mutex);
43         dg00x->substreams_counter--;
44         snd_dg00x_stream_stop_duplex(dg00x);
45         mutex_unlock(&dg00x->mutex);
46
47         snd_dg00x_stream_lock_release(dg00x);
48         return 0;
49 }
50
51 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
52 {
53         struct snd_dg00x *dg00x = substrm->rmidi->private_data;
54         unsigned long flags;
55
56         spin_lock_irqsave(&dg00x->lock, flags);
57
58         /* This port is for asynchronous transaction. */
59         if (substrm->number == 0) {
60                 if (up)
61                         dg00x->in_control = substrm;
62                 else
63                         dg00x->in_control = NULL;
64         } else {
65                 if (up)
66                         amdtp_dot_midi_trigger(&dg00x->tx_stream,
67                                                substrm->number - 1, substrm);
68                 else
69                         amdtp_dot_midi_trigger(&dg00x->tx_stream,
70                                                substrm->number - 1, NULL);
71         }
72
73         spin_unlock_irqrestore(&dg00x->lock, flags);
74 }
75
76 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
77 {
78         struct snd_dg00x *dg00x = substrm->rmidi->private_data;
79         unsigned long flags;
80
81         spin_lock_irqsave(&dg00x->lock, flags);
82
83         /* This port is for asynchronous transaction. */
84         if (substrm->number == 0) {
85                 if (up)
86                         snd_fw_async_midi_port_run(&dg00x->out_control,
87                                                    substrm);
88         } else {
89                 if (up)
90                         amdtp_dot_midi_trigger(&dg00x->rx_stream,
91                                                substrm->number - 1, substrm);
92                 else
93                         amdtp_dot_midi_trigger(&dg00x->rx_stream,
94                                                substrm->number - 1, NULL);
95         }
96
97         spin_unlock_irqrestore(&dg00x->lock, flags);
98 }
99
100 static struct snd_rawmidi_ops midi_capture_ops = {
101         .open           = midi_open,
102         .close          = midi_close,
103         .trigger        = midi_capture_trigger,
104 };
105
106 static struct snd_rawmidi_ops midi_playback_ops = {
107         .open           = midi_open,
108         .close          = midi_close,
109         .trigger        = midi_playback_trigger,
110 };
111
112 static void set_midi_substream_names(struct snd_dg00x *dg00x,
113                                      struct snd_rawmidi_str *str)
114 {
115         struct snd_rawmidi_substream *subs;
116
117         list_for_each_entry(subs, &str->substreams, list) {
118                 if (subs->number > 0)
119                         snprintf(subs->name, sizeof(subs->name),
120                                  "%s MIDI %d",
121                                  dg00x->card->shortname, subs->number);
122                 else
123                         /* This port is for asynchronous transaction. */
124                         snprintf(subs->name, sizeof(subs->name),
125                                  "%s control",
126                                  dg00x->card->shortname);
127         }
128 }
129
130 int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
131 {
132         struct snd_rawmidi *rmidi;
133         struct snd_rawmidi_str *str;
134         int err;
135
136         err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
137                         DOT_MIDI_OUT_PORTS + 1, DOT_MIDI_IN_PORTS + 1, &rmidi);
138         if (err < 0)
139                 return err;
140
141         snprintf(rmidi->name, sizeof(rmidi->name),
142                  "%s MIDI", dg00x->card->shortname);
143         rmidi->private_data = dg00x;
144
145         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
146         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
147                             &midi_capture_ops);
148         str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
149         set_midi_substream_names(dg00x, str);
150
151         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
152         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
153                             &midi_playback_ops);
154         str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
155         set_midi_substream_names(dg00x, str);
156
157         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
158
159         return 0;
160 }