GNU Linux-libre 4.19.264-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 void set_midi_substream_names(struct snd_efw *efw,
111                                      struct snd_rawmidi_str *str)
112 {
113         struct snd_rawmidi_substream *subs;
114
115         list_for_each_entry(subs, &str->substreams, list) {
116                 snprintf(subs->name, sizeof(subs->name),
117                          "%s MIDI %d", efw->card->shortname, subs->number + 1);
118         }
119 }
120
121 int snd_efw_create_midi_devices(struct snd_efw *efw)
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(efw->card, efw->card->driver, 0,
139                               efw->midi_out_ports, efw->midi_in_ports,
140                               &rmidi);
141         if (err < 0)
142                 return err;
143
144         snprintf(rmidi->name, sizeof(rmidi->name),
145                  "%s MIDI", efw->card->shortname);
146         rmidi->private_data = efw;
147
148         if (efw->midi_in_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(efw, str);
157         }
158
159         if (efw->midi_out_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(efw, str);
168         }
169
170         if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0))
171                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
172
173         return 0;
174 }