Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
[cascardo/linux.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 struct snd_rawmidi_ops midi_capture_ops = {
110         .open           = midi_capture_open,
111         .close          = midi_capture_close,
112         .trigger        = midi_capture_trigger,
113 };
114
115 static struct snd_rawmidi_ops midi_playback_ops = {
116         .open           = midi_playback_open,
117         .close          = midi_playback_close,
118         .trigger        = midi_playback_trigger,
119 };
120
121 static void set_midi_substream_names(struct snd_bebob *bebob,
122                                      struct snd_rawmidi_str *str)
123 {
124         struct snd_rawmidi_substream *subs;
125
126         list_for_each_entry(subs, &str->substreams, list) {
127                 snprintf(subs->name, sizeof(subs->name),
128                          "%s MIDI %d",
129                          bebob->card->shortname, subs->number + 1);
130         }
131 }
132
133 int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
134 {
135         struct snd_rawmidi *rmidi;
136         struct snd_rawmidi_str *str;
137         int err;
138
139         /* create midi ports */
140         err = snd_rawmidi_new(bebob->card, bebob->card->driver, 0,
141                               bebob->midi_output_ports, bebob->midi_input_ports,
142                               &rmidi);
143         if (err < 0)
144                 return err;
145
146         snprintf(rmidi->name, sizeof(rmidi->name),
147                  "%s MIDI", bebob->card->shortname);
148         rmidi->private_data = bebob;
149
150         if (bebob->midi_input_ports > 0) {
151                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
152
153                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
154                                     &midi_capture_ops);
155
156                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
157
158                 set_midi_substream_names(bebob, str);
159         }
160
161         if (bebob->midi_output_ports > 0) {
162                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
163
164                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
165                                     &midi_playback_ops);
166
167                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
168
169                 set_midi_substream_names(bebob, str);
170         }
171
172         if ((bebob->midi_output_ports > 0) && (bebob->midi_input_ports > 0))
173                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
174
175         return 0;
176 }