xref: /linux/sound/core/seq/seq_midi.c (revision ef7607ab1c8adc6258fb1b27d08e26aecdc18a58)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Generic MIDI synth driver for ALSA sequencer
4  *   Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
5  *                         Jaroslav Kysela <perex@perex.cz>
6  */
7 
8 /*
9 Possible options for midisynth module:
10 	- automatic opening of midi ports on first received event or subscription
11 	  (close will be performed when client leaves)
12 */
13 
14 
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/module.h>
20 #include <linux/mutex.h>
21 #include <sound/core.h>
22 #include <sound/rawmidi.h>
23 #include <sound/seq_kernel.h>
24 #include <sound/seq_device.h>
25 #include <sound/seq_midi_event.h>
26 #include <sound/initval.h>
27 #include "seq_lock.h"
28 
29 MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>");
30 MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
31 MODULE_LICENSE("GPL");
32 static int output_buffer_size = PAGE_SIZE;
33 module_param(output_buffer_size, int, 0644);
34 MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes.");
35 static int input_buffer_size = PAGE_SIZE;
36 module_param(input_buffer_size, int, 0644);
37 MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
38 
39 /* data for this midi synth driver */
40 struct seq_midisynth {
41 	struct snd_card *card;
42 	struct snd_rawmidi *rmidi;
43 	int device;
44 	int subdevice;
45 	struct snd_rawmidi_file input_rfile;
46 	spinlock_t output_lock;		/* protects output_rfile publication */
47 	snd_use_lock_t output_use_lock;	/* in-flight event_input users */
48 	struct snd_rawmidi_file output_rfile;
49 	int seq_client;
50 	int seq_port;
51 	struct snd_midi_event *parser;
52 };
53 
54 struct seq_midisynth_client {
55 	int seq_client;
56 	int num_ports;
57 	int ports_per_device[SNDRV_RAWMIDI_DEVICES];
58  	struct seq_midisynth *ports[SNDRV_RAWMIDI_DEVICES];
59 };
60 
61 static struct seq_midisynth_client *synths[SNDRV_CARDS];
62 static DEFINE_MUTEX(register_mutex);
63 
64 /* handle rawmidi input event (MIDI v1.0 stream) */
65 static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
66 {
67 	struct snd_rawmidi_runtime *runtime;
68 	struct seq_midisynth *msynth;
69 	struct snd_seq_event ev;
70 	char buf[16], *pbuf;
71 	long res;
72 
73 	if (substream == NULL)
74 		return;
75 	runtime = substream->runtime;
76 	msynth = runtime->private_data;
77 	if (msynth == NULL)
78 		return;
79 	memset(&ev, 0, sizeof(ev));
80 	while (runtime->avail > 0) {
81 		res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf));
82 		if (res <= 0)
83 			continue;
84 		if (msynth->parser == NULL)
85 			continue;
86 		pbuf = buf;
87 		while (res-- > 0) {
88 			if (!snd_midi_event_encode_byte(msynth->parser,
89 							*pbuf++, &ev))
90 				continue;
91 			ev.source.port = msynth->seq_port;
92 			ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
93 			snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
94 			/* clear event and reset header */
95 			memset(&ev, 0, sizeof(ev));
96 		}
97 	}
98 }
99 
100 static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count)
101 {
102 	struct snd_rawmidi_runtime *runtime;
103 	int tmp;
104 
105 	if (snd_BUG_ON(!substream || !buf))
106 		return -EINVAL;
107 	runtime = substream->runtime;
108 	tmp = runtime->avail;
109 	if (tmp < count) {
110 		if (printk_ratelimit())
111 			pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
112 		return -ENOMEM;
113 	}
114 	if (snd_rawmidi_kernel_write(substream, buf, count) < count)
115 		return -EINVAL;
116 	return 0;
117 }
118 
119 /* callback for snd_seq_dump_var_event(), bridging to dump_midi() */
120 static int __dump_midi(void *ptr, void *buf, int count)
121 {
122 	return dump_midi(ptr, buf, count);
123 }
124 
125 static int event_process_midi(struct snd_seq_event *ev, int direct,
126 			      void *private_data, int atomic, int hop)
127 {
128 	struct seq_midisynth *msynth = private_data;
129 	unsigned char msg[10];	/* buffer for constructing midi messages */
130 	struct snd_rawmidi_substream *substream;
131 	int err = 0;
132 	int len;
133 
134 	if (snd_BUG_ON(!msynth))
135 		return -EINVAL;
136 
137 	scoped_guard(spinlock_irqsave, &msynth->output_lock) {
138 		substream = msynth->output_rfile.output;
139 		if (!substream)
140 			return -ENODEV;
141 		snd_use_lock_use(&msynth->output_use_lock);
142 	}
143 
144 	if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {	/* special case, to save space */
145 		if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
146 			/* invalid event */
147 			pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
148 			goto out;
149 		}
150 		snd_seq_dump_var_event(ev, __dump_midi, substream);
151 		snd_midi_event_reset_decode(msynth->parser);
152 	} else {
153 		if (!msynth->parser) {
154 			err = -EIO;
155 			goto out;
156 		}
157 		len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
158 		if (len < 0)
159 			goto out;
160 		if (dump_midi(substream, msg, len) < 0)
161 			snd_midi_event_reset_decode(msynth->parser);
162 	}
163 
164 out:
165 	snd_use_lock_free(&msynth->output_use_lock);
166 	return err;
167 }
168 
169 
170 static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
171 				 struct snd_card *card,
172 				 int device,
173 				 int subdevice)
174 {
175 	if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &msynth->parser) < 0)
176 		return -ENOMEM;
177 	msynth->card = card;
178 	msynth->device = device;
179 	msynth->subdevice = subdevice;
180 	spin_lock_init(&msynth->output_lock);
181 	snd_use_lock_init(&msynth->output_use_lock);
182 	return 0;
183 }
184 
185 /* open associated midi device for input */
186 static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe *info)
187 {
188 	int err;
189 	struct seq_midisynth *msynth = private_data;
190 	struct snd_rawmidi_runtime *runtime;
191 	struct snd_rawmidi_params params;
192 
193 	/* open midi port */
194 	err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
195 				      SNDRV_RAWMIDI_LFLG_INPUT,
196 				      &msynth->input_rfile);
197 	if (err < 0) {
198 		pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
199 		return err;
200 	}
201 	runtime = msynth->input_rfile.input->runtime;
202 	memset(&params, 0, sizeof(params));
203 	params.avail_min = 1;
204 	params.buffer_size = input_buffer_size;
205 	err = snd_rawmidi_input_params(msynth->input_rfile.input, &params);
206 	if (err < 0) {
207 		snd_rawmidi_kernel_release(&msynth->input_rfile);
208 		return err;
209 	}
210 	snd_midi_event_reset_encode(msynth->parser);
211 	runtime->event = snd_midi_input_event;
212 	runtime->private_data = msynth;
213 	snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0);
214 	return 0;
215 }
216 
217 /* close associated midi device for input */
218 static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscribe *info)
219 {
220 	int err;
221 	struct seq_midisynth *msynth = private_data;
222 
223 	if (snd_BUG_ON(!msynth->input_rfile.input))
224 		return -EINVAL;
225 	err = snd_rawmidi_kernel_release(&msynth->input_rfile);
226 	return err;
227 }
228 
229 /* open associated midi device for output */
230 static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info)
231 {
232 	int err;
233 	struct seq_midisynth *msynth = private_data;
234 	struct snd_rawmidi_file rfile = {};
235 	struct snd_rawmidi_params params;
236 
237 	/* open midi port */
238 	err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
239 				      SNDRV_RAWMIDI_LFLG_OUTPUT,
240 				      &rfile);
241 	if (err < 0) {
242 		pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
243 		return err;
244 	}
245 	memset(&params, 0, sizeof(params));
246 	params.avail_min = 1;
247 	params.buffer_size = output_buffer_size;
248 	params.no_active_sensing = 1;
249 	err = snd_rawmidi_output_params(rfile.output, &params);
250 	if (err < 0) {
251 		snd_rawmidi_kernel_release(&rfile);
252 		return err;
253 	}
254 	snd_midi_event_reset_decode(msynth->parser);
255 	scoped_guard(spinlock_irqsave, &msynth->output_lock)
256 		msynth->output_rfile = rfile;
257 	return 0;
258 }
259 
260 /* close associated midi device for output */
261 static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
262 {
263 	struct seq_midisynth *msynth = private_data;
264 	struct snd_rawmidi_file rfile = {};
265 
266 	scoped_guard(spinlock_irqsave, &msynth->output_lock) {
267 		rfile = msynth->output_rfile;
268 		msynth->output_rfile = (struct snd_rawmidi_file){};
269 	}
270 
271 	if (snd_BUG_ON(!rfile.output))
272 		return -EINVAL;
273 
274 	snd_use_lock_sync(&msynth->output_use_lock);
275 	snd_rawmidi_drain_output(rfile.output);
276 	return snd_rawmidi_kernel_release(&rfile);
277 }
278 
279 /* delete given midi synth port */
280 static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
281 {
282 	if (msynth == NULL)
283 		return;
284 
285 	if (msynth->seq_client > 0) {
286 		/* delete port */
287 		snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
288 	}
289 
290 	snd_midi_event_free(msynth->parser);
291 }
292 
293 /* register new midi synth port */
294 static int
295 snd_seq_midisynth_probe(struct snd_seq_device *dev)
296 {
297 	struct seq_midisynth_client *client;
298 	struct seq_midisynth *msynth, *ms;
299 	struct snd_rawmidi *rmidi = dev->private_data;
300 	int newclient = 0;
301 	unsigned int p, ports;
302 	struct snd_seq_port_callback pcallbacks;
303 	struct snd_card *card = dev->card;
304 	int device = dev->device;
305 	unsigned int input_count = 0, output_count = 0;
306 
307 	if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
308 		return -EINVAL;
309 
310 	struct snd_rawmidi_info *info __free(kfree) =
311 		kmalloc_obj(*info);
312 	if (! info)
313 		return -ENOMEM;
314 	info->device = device;
315 	info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
316 	info->subdevice = 0;
317 	if (snd_rawmidi_info_select(card, info) >= 0)
318 		output_count = info->subdevices_count;
319 	info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
320 	if (snd_rawmidi_info_select(card, info) >= 0) {
321 		input_count = info->subdevices_count;
322 	}
323 	ports = output_count;
324 	if (ports < input_count)
325 		ports = input_count;
326 	if (ports == 0)
327 		return -ENODEV;
328 	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
329 		ports = 256 / SNDRV_RAWMIDI_DEVICES;
330 
331 	guard(mutex)(&register_mutex);
332 	client = synths[card->number];
333 	if (client == NULL) {
334 		newclient = 1;
335 		client = kzalloc_obj(*client);
336 		if (client == NULL)
337 			return -ENOMEM;
338 		client->seq_client =
339 			snd_seq_create_kernel_client(
340 				card, 0, "%s", card->shortname[0] ?
341 				(const char *)card->shortname : "External MIDI");
342 		if (client->seq_client < 0) {
343 			kfree(client);
344 			return -ENOMEM;
345 		}
346 	}
347 
348 	msynth = kzalloc_objs(struct seq_midisynth, ports);
349 
350 	struct snd_seq_port_info *port __free(kfree) =
351 		kmalloc_obj(*port);
352 	if (msynth == NULL || port == NULL)
353 		goto __nomem;
354 
355 	for (p = 0; p < ports; p++) {
356 		ms = &msynth[p];
357 		ms->rmidi = rmidi;
358 
359 		if (snd_seq_midisynth_new(ms, card, device, p) < 0)
360 			goto __nomem;
361 
362 		/* declare port */
363 		memset(port, 0, sizeof(*port));
364 		port->addr.client = client->seq_client;
365 		port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
366 		port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
367 		memset(info, 0, sizeof(*info));
368 		info->device = device;
369 		if (p < output_count)
370 			info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
371 		else
372 			info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
373 		info->subdevice = p;
374 		if (snd_rawmidi_info_select(card, info) >= 0)
375 			strscpy(port->name, info->subname);
376 		if (! port->name[0]) {
377 			if (info->name[0]) {
378 				if (ports > 1)
379 					scnprintf(port->name, sizeof(port->name), "%s-%u", info->name, p);
380 				else
381 					scnprintf(port->name, sizeof(port->name), "%s", info->name);
382 			} else {
383 				/* last resort */
384 				if (ports > 1)
385 					sprintf(port->name, "MIDI %d-%d-%u", card->number, device, p);
386 				else
387 					sprintf(port->name, "MIDI %d-%d", card->number, device);
388 			}
389 		}
390 		if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
391 			port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
392 		if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
393 			port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
394 		if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
395 		    info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
396 			port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
397 		if (port->capability & SNDRV_SEQ_PORT_CAP_READ)
398 			port->direction |= SNDRV_SEQ_PORT_DIR_INPUT;
399 		if (port->capability & SNDRV_SEQ_PORT_CAP_WRITE)
400 			port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
401 		port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
402 			| SNDRV_SEQ_PORT_TYPE_HARDWARE
403 			| SNDRV_SEQ_PORT_TYPE_PORT;
404 		port->midi_channels = 16;
405 		memset(&pcallbacks, 0, sizeof(pcallbacks));
406 		pcallbacks.owner = THIS_MODULE;
407 		pcallbacks.private_data = ms;
408 		pcallbacks.subscribe = midisynth_subscribe;
409 		pcallbacks.unsubscribe = midisynth_unsubscribe;
410 		pcallbacks.use = midisynth_use;
411 		pcallbacks.unuse = midisynth_unuse;
412 		pcallbacks.event_input = event_process_midi;
413 		port->kernel = &pcallbacks;
414 		if (rmidi->ops && rmidi->ops->get_port_info)
415 			rmidi->ops->get_port_info(rmidi, p, port);
416 		if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
417 			goto __nomem;
418 		ms->seq_client = client->seq_client;
419 		ms->seq_port = port->addr.port;
420 	}
421 	client->ports_per_device[device] = ports;
422 	client->ports[device] = msynth;
423 	client->num_ports++;
424 	if (newclient)
425 		synths[card->number] = client;
426 	return 0;	/* success */
427 
428       __nomem:
429 	if (msynth != NULL) {
430 	      	for (p = 0; p < ports; p++)
431 	      		snd_seq_midisynth_delete(&msynth[p]);
432 		kfree(msynth);
433 	}
434 	if (newclient) {
435 		snd_seq_delete_kernel_client(client->seq_client);
436 		kfree(client);
437 	}
438 	return -ENOMEM;
439 }
440 
441 /* release midi synth port */
442 static void
443 snd_seq_midisynth_remove(struct snd_seq_device *dev)
444 {
445 	struct seq_midisynth_client *client;
446 	struct seq_midisynth *msynth;
447 	struct snd_card *card = dev->card;
448 	int device = dev->device, p, ports;
449 
450 	guard(mutex)(&register_mutex);
451 	client = synths[card->number];
452 	if (client == NULL || client->ports[device] == NULL)
453 		return;
454 	ports = client->ports_per_device[device];
455 	client->ports_per_device[device] = 0;
456 	msynth = client->ports[device];
457 	client->ports[device] = NULL;
458 	for (p = 0; p < ports; p++)
459 		snd_seq_midisynth_delete(&msynth[p]);
460 	kfree(msynth);
461 	client->num_ports--;
462 	if (client->num_ports <= 0) {
463 		snd_seq_delete_kernel_client(client->seq_client);
464 		synths[card->number] = NULL;
465 		kfree(client);
466 	}
467 }
468 
469 static struct snd_seq_driver seq_midisynth_driver = {
470 	.probe = snd_seq_midisynth_probe,
471 	.remove = snd_seq_midisynth_remove,
472 	.driver = {
473 		.name = KBUILD_MODNAME,
474 	},
475 	.id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
476 	.argsize = 0,
477 };
478 
479 module_snd_seq_driver(seq_midisynth_driver);
480