GNU Linux-libre 4.14.266-gnu1
[releases.git] / sound / firewire / bebob / bebob_midi.c
1 /*
2  * bebob_midi.c - a part of driver for BeBoB based devices
3  *
4  * Copyright (c) 2013-2014 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8
9 #include "bebob.h"
10
11 static int midi_capture_open(struct snd_rawmidi_substream *substream)
12 {
13         struct snd_bebob *bebob = substream->rmidi->private_data;
14         int err;
15
16         err = snd_bebob_stream_lock_try(bebob);
17         if (err < 0)
18                 goto end;
19
20         mutex_lock(&bebob->mutex);
21         bebob->substreams_counter++;
22         err = snd_bebob_stream_start_duplex(bebob, 0);
23         mutex_unlock(&bebob->mutex);
24         if (err < 0)
25                 snd_bebob_stream_lock_release(bebob);
26 end:
27         return err;
28 }
29
30 static int midi_playback_open(struct snd_rawmidi_substream *substream)
31 {
32         struct snd_bebob *bebob = substream->rmidi->private_data;
33         int err;
34
35         err = snd_bebob_stream_lock_try(bebob);
36         if (err < 0)
37                 goto end;
38
39         mutex_lock(&bebob->mutex);
40         bebob->substreams_counter++;
41         err = snd_bebob_stream_start_duplex(bebob, 0);
42         mutex_unlock(&bebob->mutex);
43         if (err < 0)
44                 snd_bebob_stream_lock_release(bebob);
45 end:
46         return err;
47 }
48
49 static int midi_capture_close(struct snd_rawmidi_substream *substream)
50 {
51         struct snd_bebob *bebob = substream->rmidi->private_data;
52
53         mutex_lock(&bebob->mutex);
54         bebob->substreams_counter--;
55         snd_bebob_stream_stop_duplex(bebob);
56         mutex_unlock(&bebob->mutex);
57
58         snd_bebob_stream_lock_release(bebob);
59         return 0;
60 }
61
62 static int midi_playback_close(struct snd_rawmidi_substream *substream)
63 {
64         struct snd_bebob *bebob = substream->rmidi->private_data;
65
66         mutex_lock(&bebob->mutex);
67         bebob->substreams_counter--;
68         snd_bebob_stream_stop_duplex(bebob);
69         mutex_unlock(&bebob->mutex);
70
71         snd_bebob_stream_lock_release(bebob);
72         return 0;
73 }
74
75 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
76 {
77         struct snd_bebob *bebob = substrm->rmidi->private_data;
78         unsigned long flags;
79
80         spin_lock_irqsave(&bebob->lock, flags);
81
82         if (up)
83                 amdtp_am824_midi_trigger(&bebob->tx_stream,
84                                          substrm->number, substrm);
85         else
86                 amdtp_am824_midi_trigger(&bebob->tx_stream,
87                                          substrm->number, NULL);
88
89         spin_unlock_irqrestore(&bebob->lock, flags);
90 }
91
92 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
93 {
94         struct snd_bebob *bebob = substrm->rmidi->private_data;
95         unsigned long flags;
96
97         spin_lock_irqsave(&bebob->lock, flags);
98
99         if (up)
100                 amdtp_am824_midi_trigger(&bebob->rx_stream,
101                                          substrm->number, substrm);
102         else
103                 amdtp_am824_midi_trigger(&bebob->rx_stream,
104                                          substrm->number, NULL);
105
106         spin_unlock_irqrestore(&bebob->lock, flags);
107 }
108
109 static void set_midi_substream_names(struct snd_bebob *bebob,
110                                      struct snd_rawmidi_str *str)
111 {
112         struct snd_rawmidi_substream *subs;
113
114         list_for_each_entry(subs, &str->substreams, list) {
115                 snprintf(subs->name, sizeof(subs->name),
116                          "%s MIDI %d",
117                          bebob->card->shortname, subs->number + 1);
118         }
119 }
120
121 int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
122 {
123         static const struct snd_rawmidi_ops capture_ops = {
124                 .open           = midi_capture_open,
125                 .close          = midi_capture_close,
126                 .trigger        = midi_capture_trigger,
127         };
128         static const struct snd_rawmidi_ops playback_ops = {
129                 .open           = midi_playback_open,
130                 .close          = midi_playback_close,
131                 .trigger        = midi_playback_trigger,
132         };
133         struct snd_rawmidi *rmidi;
134         struct snd_rawmidi_str *str;
135         int err;
136
137         /* create midi ports */
138         err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0,
139                               bebob->midi_output_ports, bebob->midi_input_ports,
140                               &rmidi);
141         if (err < 0)
142                 return err;
143
144         snprintf(rmidi->name, sizeof(rmidi->name),
145                  "%s MIDI", bebob->card->shortname);
146         rmidi->private_data = bebob;
147
148         if (bebob->midi_input_ports > 0) {
149                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
150
151                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
152                                     &capture_ops);
153
154                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
155
156                 set_midi_substream_names(bebob, str);
157         }
158
159         if (bebob->midi_output_ports > 0) {
160                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
161
162                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
163                                     &playback_ops);
164
165                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
166
167                 set_midi_substream_names(bebob, str);
168         }
169
170         if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0))
171                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
172
173         return 0;
174 }