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