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