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(¶ms, 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, ¶ms); 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(¶ms, 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, ¶ms); 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)(®ister_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)(®ister_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