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