GNU Linux-libre 4.9.314-gnu1
[releases.git] / sound / firewire / fireworks / fireworks_midi.c
1 /*
2  * fireworks_midi.c - a part of driver for Fireworks based devices
3  *
4  * Copyright (c) 2009-2010 Clemens Ladisch
5  * Copyright (c) 2013-2014 Takashi Sakamoto
6  *
7  * Licensed under the terms of the GNU General Public License, version 2.
8  */
9 #include "fireworks.h"
10
11 static int midi_capture_open(struct snd_rawmidi_substream *substream)
12 {
13         struct snd_efw *efw = substream->rmidi->private_data;
14         int err;
15
16         err = snd_efw_stream_lock_try(efw);
17         if (err < 0)
18                 goto end;
19
20         mutex_lock(&efw->mutex);
21         efw->capture_substreams++;
22         err = snd_efw_stream_start_duplex(efw, 0);
23         mutex_unlock(&efw->mutex);
24         if (err < 0)
25                 snd_efw_stream_lock_release(efw);
26
27 end:
28         return err;
29 }
30
31 static int midi_playback_open(struct snd_rawmidi_substream *substream)
32 {
33         struct snd_efw *efw = substream->rmidi->private_data;
34         int err;
35
36         err = snd_efw_stream_lock_try(efw);
37         if (err < 0)
38                 goto end;
39
40         mutex_lock(&efw->mutex);
41         efw->playback_substreams++;
42         err = snd_efw_stream_start_duplex(efw, 0);
43         mutex_unlock(&efw->mutex);
44         if (err < 0)
45                 snd_efw_stream_lock_release(efw);
46 end:
47         return err;
48 }
49
50 static int midi_capture_close(struct snd_rawmidi_substream *substream)
51 {
52         struct snd_efw *efw = substream->rmidi->private_data;
53
54         mutex_lock(&efw->mutex);
55         efw->capture_substreams--;
56         snd_efw_stream_stop_duplex(efw);
57         mutex_unlock(&efw->mutex);
58
59         snd_efw_stream_lock_release(efw);
60         return 0;
61 }
62
63 static int midi_playback_close(struct snd_rawmidi_substream *substream)
64 {
65         struct snd_efw *efw = substream->rmidi->private_data;
66
67         mutex_lock(&efw->mutex);
68         efw->playback_substreams--;
69         snd_efw_stream_stop_duplex(efw);
70         mutex_unlock(&efw->mutex);
71
72         snd_efw_stream_lock_release(efw);
73         return 0;
74 }
75
76 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
77 {
78         struct snd_efw *efw = substrm->rmidi->private_data;
79         unsigned long flags;
80
81         spin_lock_irqsave(&efw->lock, flags);
82
83         if (up)
84                 amdtp_am824_midi_trigger(&efw->tx_stream,
85                                           substrm->number, substrm);
86         else
87                 amdtp_am824_midi_trigger(&efw->tx_stream,
88                                           substrm->number, NULL);
89
90         spin_unlock_irqrestore(&efw->lock, flags);
91 }
92
93 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
94 {
95         struct snd_efw *efw = substrm->rmidi->private_data;
96         unsigned long flags;
97
98         spin_lock_irqsave(&efw->lock, flags);
99
100         if (up)
101                 amdtp_am824_midi_trigger(&efw->rx_stream,
102                                          substrm->number, substrm);
103         else
104                 amdtp_am824_midi_trigger(&efw->rx_stream,
105                                          substrm->number, NULL);
106
107         spin_unlock_irqrestore(&efw->lock, flags);
108 }
109
110 static struct snd_rawmidi_ops midi_capture_ops = {
111         .open           = midi_capture_open,
112         .close          = midi_capture_close,
113         .trigger        = midi_capture_trigger,
114 };
115
116 static struct snd_rawmidi_ops midi_playback_ops = {
117         .open           = midi_playback_open,
118         .close          = midi_playback_close,
119         .trigger        = midi_playback_trigger,
120 };
121
122 static void set_midi_substream_names(struct snd_efw *efw,
123                                      struct snd_rawmidi_str *str)
124 {
125         struct snd_rawmidi_substream *subs;
126
127         list_for_each_entry(subs, &str->substreams, list) {
128                 snprintf(subs->name, sizeof(subs->name),
129                          "%s MIDI %d", efw->card->shortname, subs->number + 1);
130         }
131 }
132
133 int snd_efw_create_midi_devices(struct snd_efw *efw)
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(efw->card, efw->card->driver, 0,
141                               efw->midi_out_ports, efw->midi_in_ports,
142                               &rmidi);
143         if (err < 0)
144                 return err;
145
146         snprintf(rmidi->name, sizeof(rmidi->name),
147                  "%s MIDI", efw->card->shortname);
148         rmidi->private_data = efw;
149
150         if (efw->midi_in_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(efw, str);
159         }
160
161         if (efw->midi_out_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(efw, str);
170         }
171
172         if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0))
173                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
174
175         return 0;
176 }