Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Midi Sequencer interface routines. | |
4 | * | |
5 | * Copyright (C) 1999 Steve Ratcliffe | |
6 | * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de> | |
1da177e4 LT |
7 | */ |
8 | ||
9 | #include "emux_voice.h" | |
10 | #include <linux/slab.h> | |
da155d5b | 11 | #include <linux/module.h> |
1da177e4 LT |
12 | |
13 | /* Prototypes for static functions */ | |
14 | static void free_port(void *private); | |
03da312a TI |
15 | static void snd_emux_init_port(struct snd_emux_port *p); |
16 | static int snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info); | |
17 | static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info); | |
1da177e4 LT |
18 | |
19 | /* | |
20 | * MIDI emulation operators | |
21 | */ | |
aad7ebb5 | 22 | static const struct snd_midi_op emux_ops = { |
f93a1c9e KC |
23 | .note_on = snd_emux_note_on, |
24 | .note_off = snd_emux_note_off, | |
25 | .key_press = snd_emux_key_press, | |
26 | .note_terminate = snd_emux_terminate_note, | |
27 | .control = snd_emux_control, | |
28 | .nrpn = snd_emux_nrpn, | |
29 | .sysex = snd_emux_sysex, | |
1da177e4 LT |
30 | }; |
31 | ||
32 | ||
33 | /* | |
34 | * number of MIDI channels | |
35 | */ | |
36 | #define MIDI_CHANNELS 16 | |
37 | ||
38 | /* | |
39 | * type flags for MIDI sequencer port | |
40 | */ | |
41 | #define DEFAULT_MIDI_TYPE (SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |\ | |
42 | SNDRV_SEQ_PORT_TYPE_MIDI_GM |\ | |
43 | SNDRV_SEQ_PORT_TYPE_MIDI_GS |\ | |
450047a7 CL |
44 | SNDRV_SEQ_PORT_TYPE_MIDI_XG |\ |
45 | SNDRV_SEQ_PORT_TYPE_HARDWARE |\ | |
46 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) | |
1da177e4 LT |
47 | |
48 | /* | |
49 | * Initialise the EMUX Synth by creating a client and registering | |
50 | * a series of ports. | |
51 | * Each of the ports will contain the 16 midi channels. Applications | |
52 | * can connect to these ports to play midi data. | |
53 | */ | |
54 | int | |
03da312a | 55 | snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index) |
1da177e4 LT |
56 | { |
57 | int i; | |
03da312a | 58 | struct snd_seq_port_callback pinfo; |
1da177e4 LT |
59 | char tmpname[64]; |
60 | ||
7b6d9245 CL |
61 | emu->client = snd_seq_create_kernel_client(card, index, |
62 | "%s WaveTable", emu->name); | |
1da177e4 | 63 | if (emu->client < 0) { |
42b0158b | 64 | snd_printk(KERN_ERR "can't create client\n"); |
1da177e4 LT |
65 | return -ENODEV; |
66 | } | |
67 | ||
68 | if (emu->num_ports < 0) { | |
42b0158b | 69 | snd_printk(KERN_WARNING "seqports must be greater than zero\n"); |
1da177e4 LT |
70 | emu->num_ports = 1; |
71 | } else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) { | |
42b0158b | 72 | snd_printk(KERN_WARNING "too many ports." |
1da177e4 LT |
73 | "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS); |
74 | emu->num_ports = SNDRV_EMUX_MAX_PORTS; | |
75 | } | |
76 | ||
77 | memset(&pinfo, 0, sizeof(pinfo)); | |
78 | pinfo.owner = THIS_MODULE; | |
79 | pinfo.use = snd_emux_use; | |
80 | pinfo.unuse = snd_emux_unuse; | |
81 | pinfo.event_input = snd_emux_event_input; | |
82 | ||
83 | for (i = 0; i < emu->num_ports; i++) { | |
03da312a | 84 | struct snd_emux_port *p; |
1da177e4 LT |
85 | |
86 | sprintf(tmpname, "%s Port %d", emu->name, i); | |
87 | p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS, | |
88 | 0, &pinfo); | |
fbc020b4 | 89 | if (!p) { |
42b0158b | 90 | snd_printk(KERN_ERR "can't create port\n"); |
1da177e4 LT |
91 | return -ENOMEM; |
92 | } | |
93 | ||
94 | p->port_mode = SNDRV_EMUX_PORT_MODE_MIDI; | |
95 | snd_emux_init_port(p); | |
96 | emu->ports[i] = p->chset.port; | |
97 | emu->portptrs[i] = p; | |
98 | } | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | ||
104 | /* | |
105 | * Detach from the ports that were set up for this synthesizer and | |
106 | * destroy the kernel client. | |
107 | */ | |
108 | void | |
03da312a | 109 | snd_emux_detach_seq(struct snd_emux *emu) |
1da177e4 LT |
110 | { |
111 | if (emu->voices) | |
112 | snd_emux_terminate_all(emu); | |
113 | ||
1da177e4 LT |
114 | if (emu->client >= 0) { |
115 | snd_seq_delete_kernel_client(emu->client); | |
116 | emu->client = -1; | |
117 | } | |
1da177e4 LT |
118 | } |
119 | ||
120 | ||
121 | /* | |
122 | * create a sequencer port and channel_set | |
123 | */ | |
124 | ||
03da312a TI |
125 | struct snd_emux_port * |
126 | snd_emux_create_port(struct snd_emux *emu, char *name, | |
127 | int max_channels, int oss_port, | |
128 | struct snd_seq_port_callback *callback) | |
1da177e4 | 129 | { |
03da312a | 130 | struct snd_emux_port *p; |
1da177e4 LT |
131 | int i, type, cap; |
132 | ||
133 | /* Allocate structures for this channel */ | |
c997aabb | 134 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
64a591e6 | 135 | if (!p) |
1da177e4 | 136 | return NULL; |
64a591e6 | 137 | |
949a0c23 ME |
138 | p->chset.channels = kcalloc(max_channels, sizeof(*p->chset.channels), |
139 | GFP_KERNEL); | |
fbc020b4 | 140 | if (!p->chset.channels) { |
1da177e4 LT |
141 | kfree(p); |
142 | return NULL; | |
143 | } | |
144 | for (i = 0; i < max_channels; i++) | |
145 | p->chset.channels[i].number = i; | |
146 | p->chset.private_data = p; | |
147 | p->chset.max_channels = max_channels; | |
148 | p->emu = emu; | |
149 | p->chset.client = emu->client; | |
150 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
151 | snd_emux_create_effect(p); | |
152 | #endif | |
153 | callback->private_free = free_port; | |
154 | callback->private_data = p; | |
155 | ||
156 | cap = SNDRV_SEQ_PORT_CAP_WRITE; | |
157 | if (oss_port) { | |
158 | type = SNDRV_SEQ_PORT_TYPE_SPECIFIC; | |
159 | } else { | |
160 | type = DEFAULT_MIDI_TYPE; | |
161 | cap |= SNDRV_SEQ_PORT_CAP_SUBS_WRITE; | |
162 | } | |
163 | ||
164 | p->chset.port = snd_seq_event_port_attach(emu->client, callback, | |
165 | cap, type, max_channels, | |
166 | emu->max_voices, name); | |
167 | ||
168 | return p; | |
169 | } | |
170 | ||
171 | ||
172 | /* | |
173 | * release memory block for port | |
174 | */ | |
175 | static void | |
176 | free_port(void *private_data) | |
177 | { | |
03da312a | 178 | struct snd_emux_port *p; |
1da177e4 LT |
179 | |
180 | p = private_data; | |
181 | if (p) { | |
182 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
183 | snd_emux_delete_effect(p); | |
184 | #endif | |
185 | kfree(p->chset.channels); | |
186 | kfree(p); | |
187 | } | |
188 | } | |
189 | ||
190 | ||
191 | #define DEFAULT_DRUM_FLAGS (1<<9) | |
192 | ||
193 | /* | |
194 | * initialize the port specific parameters | |
195 | */ | |
196 | static void | |
03da312a | 197 | snd_emux_init_port(struct snd_emux_port *p) |
1da177e4 LT |
198 | { |
199 | p->drum_flags = DEFAULT_DRUM_FLAGS; | |
200 | p->volume_atten = 0; | |
201 | ||
202 | snd_emux_reset_port(p); | |
203 | } | |
204 | ||
205 | ||
206 | /* | |
207 | * reset port | |
208 | */ | |
209 | void | |
03da312a | 210 | snd_emux_reset_port(struct snd_emux_port *port) |
1da177e4 LT |
211 | { |
212 | int i; | |
213 | ||
214 | /* stop all sounds */ | |
215 | snd_emux_sounds_off_all(port); | |
216 | ||
217 | snd_midi_channel_set_clear(&port->chset); | |
218 | ||
219 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
220 | snd_emux_clear_effect(port); | |
221 | #endif | |
222 | ||
223 | /* set port specific control parameters */ | |
224 | port->ctrls[EMUX_MD_DEF_BANK] = 0; | |
225 | port->ctrls[EMUX_MD_DEF_DRUM] = 0; | |
226 | port->ctrls[EMUX_MD_REALTIME_PAN] = 1; | |
227 | ||
228 | for (i = 0; i < port->chset.max_channels; i++) { | |
03da312a | 229 | struct snd_midi_channel *chan = port->chset.channels + i; |
1da177e4 LT |
230 | chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; |
231 | } | |
232 | } | |
233 | ||
234 | ||
235 | /* | |
236 | * input sequencer event | |
237 | */ | |
238 | int | |
03da312a | 239 | snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data, |
1da177e4 LT |
240 | int atomic, int hop) |
241 | { | |
03da312a | 242 | struct snd_emux_port *port; |
1da177e4 LT |
243 | |
244 | port = private_data; | |
5e246b85 TI |
245 | if (snd_BUG_ON(!port || !ev)) |
246 | return -EINVAL; | |
1da177e4 LT |
247 | |
248 | snd_midi_process_event(&emux_ops, ev, &port->chset); | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | ||
254 | /* | |
255 | * increment usage count | |
256 | */ | |
1c94e65c TI |
257 | static int |
258 | __snd_emux_inc_count(struct snd_emux *emu) | |
1da177e4 LT |
259 | { |
260 | emu->used++; | |
261 | if (!try_module_get(emu->ops.owner)) | |
262 | goto __error; | |
263 | if (!try_module_get(emu->card->module)) { | |
264 | module_put(emu->ops.owner); | |
265 | __error: | |
266 | emu->used--; | |
267 | return 0; | |
268 | } | |
269 | return 1; | |
270 | } | |
271 | ||
1c94e65c TI |
272 | int snd_emux_inc_count(struct snd_emux *emu) |
273 | { | |
274 | int ret; | |
275 | ||
276 | mutex_lock(&emu->register_mutex); | |
277 | ret = __snd_emux_inc_count(emu); | |
278 | mutex_unlock(&emu->register_mutex); | |
279 | return ret; | |
280 | } | |
1da177e4 LT |
281 | |
282 | /* | |
283 | * decrease usage count | |
284 | */ | |
1c94e65c TI |
285 | static void |
286 | __snd_emux_dec_count(struct snd_emux *emu) | |
1da177e4 LT |
287 | { |
288 | module_put(emu->card->module); | |
289 | emu->used--; | |
290 | if (emu->used <= 0) | |
291 | snd_emux_terminate_all(emu); | |
292 | module_put(emu->ops.owner); | |
293 | } | |
294 | ||
1c94e65c TI |
295 | void snd_emux_dec_count(struct snd_emux *emu) |
296 | { | |
297 | mutex_lock(&emu->register_mutex); | |
298 | __snd_emux_dec_count(emu); | |
299 | mutex_unlock(&emu->register_mutex); | |
300 | } | |
1da177e4 LT |
301 | |
302 | /* | |
303 | * Routine that is called upon a first use of a particular port | |
304 | */ | |
305 | static int | |
03da312a | 306 | snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) |
1da177e4 | 307 | { |
03da312a TI |
308 | struct snd_emux_port *p; |
309 | struct snd_emux *emu; | |
1da177e4 LT |
310 | |
311 | p = private_data; | |
5e246b85 TI |
312 | if (snd_BUG_ON(!p)) |
313 | return -EINVAL; | |
1da177e4 | 314 | emu = p->emu; |
5e246b85 TI |
315 | if (snd_BUG_ON(!emu)) |
316 | return -EINVAL; | |
1da177e4 | 317 | |
ef9f0a42 | 318 | mutex_lock(&emu->register_mutex); |
1da177e4 | 319 | snd_emux_init_port(p); |
1c94e65c | 320 | __snd_emux_inc_count(emu); |
ef9f0a42 | 321 | mutex_unlock(&emu->register_mutex); |
1da177e4 LT |
322 | return 0; |
323 | } | |
324 | ||
325 | /* | |
326 | * Routine that is called upon the last unuse() of a particular port. | |
327 | */ | |
328 | static int | |
03da312a | 329 | snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) |
1da177e4 | 330 | { |
03da312a TI |
331 | struct snd_emux_port *p; |
332 | struct snd_emux *emu; | |
1da177e4 LT |
333 | |
334 | p = private_data; | |
5e246b85 TI |
335 | if (snd_BUG_ON(!p)) |
336 | return -EINVAL; | |
1da177e4 | 337 | emu = p->emu; |
5e246b85 TI |
338 | if (snd_BUG_ON(!emu)) |
339 | return -EINVAL; | |
1da177e4 | 340 | |
ef9f0a42 | 341 | mutex_lock(&emu->register_mutex); |
1da177e4 | 342 | snd_emux_sounds_off_all(p); |
1c94e65c | 343 | __snd_emux_dec_count(emu); |
ef9f0a42 | 344 | mutex_unlock(&emu->register_mutex); |
1da177e4 LT |
345 | return 0; |
346 | } | |
347 | ||
348 | ||
1da177e4 LT |
349 | /* |
350 | * attach virtual rawmidi devices | |
351 | */ | |
03da312a | 352 | int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card) |
1da177e4 LT |
353 | { |
354 | int i; | |
355 | ||
356 | emu->vmidi = NULL; | |
357 | if (emu->midi_ports <= 0) | |
358 | return 0; | |
359 | ||
949a0c23 | 360 | emu->vmidi = kcalloc(emu->midi_ports, sizeof(*emu->vmidi), GFP_KERNEL); |
fbc020b4 | 361 | if (!emu->vmidi) |
1da177e4 LT |
362 | return -ENOMEM; |
363 | ||
364 | for (i = 0; i < emu->midi_ports; i++) { | |
03da312a TI |
365 | struct snd_rawmidi *rmidi; |
366 | struct snd_virmidi_dev *rdev; | |
1da177e4 LT |
367 | if (snd_virmidi_new(card, emu->midi_devidx + i, &rmidi) < 0) |
368 | goto __error; | |
369 | rdev = rmidi->private_data; | |
370 | sprintf(rmidi->name, "%s Synth MIDI", emu->name); | |
371 | rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH; | |
372 | rdev->client = emu->client; | |
373 | rdev->port = emu->ports[i]; | |
374 | if (snd_device_register(card, rmidi) < 0) { | |
375 | snd_device_free(card, rmidi); | |
376 | goto __error; | |
377 | } | |
378 | emu->vmidi[i] = rmidi; | |
42b0158b | 379 | /* snd_printk(KERN_DEBUG "virmidi %d ok\n", i); */ |
1da177e4 LT |
380 | } |
381 | return 0; | |
382 | ||
383 | __error: | |
42b0158b | 384 | /* snd_printk(KERN_DEBUG "error init..\n"); */ |
1da177e4 LT |
385 | snd_emux_delete_virmidi(emu); |
386 | return -ENOMEM; | |
387 | } | |
388 | ||
03da312a | 389 | int snd_emux_delete_virmidi(struct snd_emux *emu) |
1da177e4 LT |
390 | { |
391 | int i; | |
392 | ||
fbc020b4 | 393 | if (!emu->vmidi) |
1da177e4 LT |
394 | return 0; |
395 | ||
396 | for (i = 0; i < emu->midi_ports; i++) { | |
397 | if (emu->vmidi[i]) | |
398 | snd_device_free(emu->card, emu->vmidi[i]); | |
399 | } | |
400 | kfree(emu->vmidi); | |
401 | emu->vmidi = NULL; | |
402 | return 0; | |
403 | } |