Merge tag 'imx-fixes-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo...
[linux-2.6-block.git] / sound / firewire / fireworks / fireworks_midi.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * fireworks_midi.c - a part of driver for Fireworks based devices
4  *
5  * Copyright (c) 2009-2010 Clemens Ladisch
6  * Copyright (c) 2013-2014 Takashi Sakamoto
7  */
8 #include "fireworks.h"
9
10 static int midi_capture_open(struct snd_rawmidi_substream *substream)
11 {
12         struct snd_efw *efw = substream->rmidi->private_data;
13         int err;
14
15         err = snd_efw_stream_lock_try(efw);
16         if (err < 0)
17                 goto end;
18
19         mutex_lock(&efw->mutex);
20         efw->capture_substreams++;
21         err = snd_efw_stream_start_duplex(efw, 0);
22         mutex_unlock(&efw->mutex);
23         if (err < 0)
24                 snd_efw_stream_lock_release(efw);
25
26 end:
27         return err;
28 }
29
30 static int midi_playback_open(struct snd_rawmidi_substream *substream)
31 {
32         struct snd_efw *efw = substream->rmidi->private_data;
33         int err;
34
35         err = snd_efw_stream_lock_try(efw);
36         if (err < 0)
37                 goto end;
38
39         mutex_lock(&efw->mutex);
40         efw->playback_substreams++;
41         err = snd_efw_stream_start_duplex(efw, 0);
42         mutex_unlock(&efw->mutex);
43         if (err < 0)
44                 snd_efw_stream_lock_release(efw);
45 end:
46         return err;
47 }
48
49 static int midi_capture_close(struct snd_rawmidi_substream *substream)
50 {
51         struct snd_efw *efw = substream->rmidi->private_data;
52
53         mutex_lock(&efw->mutex);
54         efw->capture_substreams--;
55         snd_efw_stream_stop_duplex(efw);
56         mutex_unlock(&efw->mutex);
57
58         snd_efw_stream_lock_release(efw);
59         return 0;
60 }
61
62 static int midi_playback_close(struct snd_rawmidi_substream *substream)
63 {
64         struct snd_efw *efw = substream->rmidi->private_data;
65
66         mutex_lock(&efw->mutex);
67         efw->playback_substreams--;
68         snd_efw_stream_stop_duplex(efw);
69         mutex_unlock(&efw->mutex);
70
71         snd_efw_stream_lock_release(efw);
72         return 0;
73 }
74
75 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
76 {
77         struct snd_efw *efw = substrm->rmidi->private_data;
78         unsigned long flags;
79
80         spin_lock_irqsave(&efw->lock, flags);
81
82         if (up)
83                 amdtp_am824_midi_trigger(&efw->tx_stream,
84                                           substrm->number, substrm);
85         else
86                 amdtp_am824_midi_trigger(&efw->tx_stream,
87                                           substrm->number, NULL);
88
89         spin_unlock_irqrestore(&efw->lock, flags);
90 }
91
92 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
93 {
94         struct snd_efw *efw = substrm->rmidi->private_data;
95         unsigned long flags;
96
97         spin_lock_irqsave(&efw->lock, flags);
98
99         if (up)
100                 amdtp_am824_midi_trigger(&efw->rx_stream,
101                                          substrm->number, substrm);
102         else
103                 amdtp_am824_midi_trigger(&efw->rx_stream,
104                                          substrm->number, NULL);
105
106         spin_unlock_irqrestore(&efw->lock, flags);
107 }
108
109 static void set_midi_substream_names(struct snd_efw *efw,
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", efw->card->shortname, subs->number + 1);
117         }
118 }
119
120 int snd_efw_create_midi_devices(struct snd_efw *efw)
121 {
122         static const struct snd_rawmidi_ops capture_ops = {
123                 .open           = midi_capture_open,
124                 .close          = midi_capture_close,
125                 .trigger        = midi_capture_trigger,
126         };
127         static const struct snd_rawmidi_ops playback_ops = {
128                 .open           = midi_playback_open,
129                 .close          = midi_playback_close,
130                 .trigger        = midi_playback_trigger,
131         };
132         struct snd_rawmidi *rmidi;
133         struct snd_rawmidi_str *str;
134         int err;
135
136         /* create midi ports */
137         err = snd_rawmidi_new(efw->card, efw->card->driver, 0,
138                               efw->midi_out_ports, efw->midi_in_ports,
139                               &rmidi);
140         if (err < 0)
141                 return err;
142
143         snprintf(rmidi->name, sizeof(rmidi->name),
144                  "%s MIDI", efw->card->shortname);
145         rmidi->private_data = efw;
146
147         if (efw->midi_in_ports > 0) {
148                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
149
150                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
151                                     &capture_ops);
152
153                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
154
155                 set_midi_substream_names(efw, str);
156         }
157
158         if (efw->midi_out_ports > 0) {
159                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
160
161                 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
162                                     &playback_ops);
163
164                 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
165
166                 set_midi_substream_names(efw, str);
167         }
168
169         if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0))
170                 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
171
172         return 0;
173 }