1/* 2 * Virtual Raw MIDI client on Sequencer 3 * 4 * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de>, 5 * Jaroslav Kysela <perex@perex.cz> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 */ 22 23/* 24 * Virtual Raw MIDI client 25 * 26 * The virtual rawmidi client is a sequencer client which associate 27 * a rawmidi device file. The created rawmidi device file can be 28 * accessed as a normal raw midi, but its MIDI source and destination 29 * are arbitrary. For example, a user-client software synth connected 30 * to this port can be used as a normal midi device as well. 31 * 32 * The virtual rawmidi device accepts also multiple opens. Each file 33 * has its own input buffer, so that no conflict would occur. The drain 34 * of input/output buffer acts only to the local buffer. 35 * 36 */ 37 38#include <linux/init.h> 39#include <linux/wait.h> 40#include <linux/slab.h> 41#include <sound/core.h> 42#include <sound/rawmidi.h> 43#include <sound/info.h> 44#include <sound/control.h> 45#include <sound/minors.h> 46#include <sound/seq_kernel.h> 47#include <sound/seq_midi_event.h> 48#include <sound/seq_virmidi.h> 49 50MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 51MODULE_DESCRIPTION("Virtual Raw MIDI client on Sequencer"); 52MODULE_LICENSE("GPL"); 53 54/* 55 * initialize an event record 56 */ 57static void snd_virmidi_init_event(struct snd_virmidi *vmidi, 58 struct snd_seq_event *ev) 59{ 60 memset(ev, 0, sizeof(*ev)); 61 ev->source.port = vmidi->port; 62 switch (vmidi->seq_mode) { 63 case SNDRV_VIRMIDI_SEQ_DISPATCH: 64 ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; 65 break; 66 case SNDRV_VIRMIDI_SEQ_ATTACH: 67 ev->dest.client = vmidi->client; 68 ev->dest.port = vmidi->port; 69 break; 70 } 71 ev->type = SNDRV_SEQ_EVENT_NONE; 72} 73 74/* 75 * decode input event and put to read buffer of each opened file 76 */ 77static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, 78 struct snd_seq_event *ev) 79{ 80 struct snd_virmidi *vmidi; 81 unsigned char msg[4]; 82 int len; 83 84 read_lock(&rdev->filelist_lock); 85 list_for_each_entry(vmidi, &rdev->filelist, list) { 86 if (!vmidi->trigger) 87 continue; 88 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { 89 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) 90 continue; 91 snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); 92 } else { 93 len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); 94 if (len > 0) 95 snd_rawmidi_receive(vmidi->substream, msg, len); 96 } 97 } 98 read_unlock(&rdev->filelist_lock); 99 100 return 0; 101} 102 103/* 104 * receive an event from the remote virmidi port 105 * 106 * for rawmidi inputs, you can call this function from the event 107 * handler of a remote port which is attached to the virmidi via 108 * SNDRV_VIRMIDI_SEQ_ATTACH. 109 */ 110 111/* 112 * event handler of virmidi port 113 */ 114static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct, 115 void *private_data, int atomic, int hop) 116{ 117 struct snd_virmidi_dev *rdev; 118 119 rdev = private_data; 120 if (!(rdev->flags & SNDRV_VIRMIDI_USE)) 121 return 0; /* ignored */ 122 return snd_virmidi_dev_receive_event(rdev, ev); 123} 124 125/* 126 * trigger rawmidi stream for input 127 */ 128static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) 129{ 130 struct snd_virmidi *vmidi = substream->runtime->private_data; 131 132 if (up) { 133 vmidi->trigger = 1; 134 } else { 135 vmidi->trigger = 0; 136 } 137} 138 139/* 140 * trigger rawmidi stream for output 141 */ 142static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) 143{ 144 struct snd_virmidi *vmidi = substream->runtime->private_data; 145 int count, res; 146 unsigned char buf[32], *pbuf; 147 148 if (up) { 149 vmidi->trigger = 1; 150 if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && 151 !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { 152 snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); 153 return; /* ignored */ 154 } 155 if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { 156 if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) 157 return; 158 vmidi->event.type = SNDRV_SEQ_EVENT_NONE; 159 } 160 while (1) { 161 count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); 162 if (count <= 0) 163 break; 164 pbuf = buf; 165 while (count > 0) { 166 res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event); 167 if (res < 0) { 168 snd_midi_event_reset_encode(vmidi->parser); 169 continue; 170 } 171 snd_rawmidi_transmit_ack(substream, res); 172 pbuf += res; 173 count -= res; 174 if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { 175 if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) 176 return; 177 vmidi->event.type = SNDRV_SEQ_EVENT_NONE; 178 } 179 } 180 } 181 } else { 182 vmidi->trigger = 0; 183 } 184} 185 186/* 187 * open rawmidi handle for input 188 */ 189static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) 190{ 191 struct snd_virmidi_dev *rdev = substream->rmidi->private_data; 192 struct snd_rawmidi_runtime *runtime = substream->runtime; 193 struct snd_virmidi *vmidi; 194 unsigned long flags; 195 196 vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); 197 if (vmidi == NULL) 198 return -ENOMEM; 199 vmidi->substream = substream; 200 if (snd_midi_event_new(0, &vmidi->parser) < 0) { 201 kfree(vmidi); 202 return -ENOMEM; 203 } 204 vmidi->seq_mode = rdev->seq_mode; 205 vmidi->client = rdev->client; 206 vmidi->port = rdev->port; 207 runtime->private_data = vmidi; 208 write_lock_irqsave(&rdev->filelist_lock, flags); 209 list_add_tail(&vmidi->list, &rdev->filelist); 210 write_unlock_irqrestore(&rdev->filelist_lock, flags); 211 vmidi->rdev = rdev; 212 return 0; 213} 214 215/* 216 * open rawmidi handle for output 217 */ 218static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) 219{ 220 struct snd_virmidi_dev *rdev = substream->rmidi->private_data; 221 struct snd_rawmidi_runtime *runtime = substream->runtime; 222 struct snd_virmidi *vmidi; 223 224 vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); 225 if (vmidi == NULL) 226 return -ENOMEM; 227 vmidi->substream = substream; 228 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &vmidi->parser) < 0) { 229 kfree(vmidi); 230 return -ENOMEM; 231 } 232 vmidi->seq_mode = rdev->seq_mode; 233 vmidi->client = rdev->client; 234 vmidi->port = rdev->port; 235 snd_virmidi_init_event(vmidi, &vmidi->event); 236 vmidi->rdev = rdev; 237 runtime->private_data = vmidi; 238 return 0; 239} 240 241/* 242 * close rawmidi handle for input 243 */ 244static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) 245{ 246 struct snd_virmidi *vmidi = substream->runtime->private_data; 247 snd_midi_event_free(vmidi->parser); 248 list_del(&vmidi->list); 249 substream->runtime->private_data = NULL; 250 kfree(vmidi); 251 return 0; 252} 253 254/* 255 * close rawmidi handle for output 256 */ 257static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) 258{ 259 struct snd_virmidi *vmidi = substream->runtime->private_data; 260 snd_midi_event_free(vmidi->parser); 261 substream->runtime->private_data = NULL; 262 kfree(vmidi); 263 return 0; 264} 265 266/* 267 * subscribe callback - allow output to rawmidi device 268 */ 269static int snd_virmidi_subscribe(void *private_data, 270 struct snd_seq_port_subscribe *info) 271{ 272 struct snd_virmidi_dev *rdev; 273 274 rdev = private_data; 275 if (!try_module_get(rdev->card->module)) 276 return -EFAULT; 277 rdev->flags |= SNDRV_VIRMIDI_SUBSCRIBE; 278 return 0; 279} 280 281/* 282 * unsubscribe callback - disallow output to rawmidi device 283 */ 284static int snd_virmidi_unsubscribe(void *private_data, 285 struct snd_seq_port_subscribe *info) 286{ 287 struct snd_virmidi_dev *rdev; 288 289 rdev = private_data; 290 rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE; 291 module_put(rdev->card->module); 292 return 0; 293} 294 295 296/* 297 * use callback - allow input to rawmidi device 298 */ 299static int snd_virmidi_use(void *private_data, 300 struct snd_seq_port_subscribe *info) 301{ 302 struct snd_virmidi_dev *rdev; 303 304 rdev = private_data; 305 if (!try_module_get(rdev->card->module)) 306 return -EFAULT; 307 rdev->flags |= SNDRV_VIRMIDI_USE; 308 return 0; 309} 310 311/* 312 * unuse callback - disallow input to rawmidi device 313 */ 314static int snd_virmidi_unuse(void *private_data, 315 struct snd_seq_port_subscribe *info) 316{ 317 struct snd_virmidi_dev *rdev; 318 319 rdev = private_data; 320 rdev->flags &= ~SNDRV_VIRMIDI_USE; 321 module_put(rdev->card->module); 322 return 0; 323} 324 325 326/* 327 * Register functions 328 */ 329 330static struct snd_rawmidi_ops snd_virmidi_input_ops = { 331 .open = snd_virmidi_input_open, 332 .close = snd_virmidi_input_close, 333 .trigger = snd_virmidi_input_trigger, 334}; 335 336static struct snd_rawmidi_ops snd_virmidi_output_ops = { 337 .open = snd_virmidi_output_open, 338 .close = snd_virmidi_output_close, 339 .trigger = snd_virmidi_output_trigger, 340}; 341 342/* 343 * create a sequencer client and a port 344 */ 345static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) 346{ 347 int client; 348 struct snd_seq_port_callback pcallbacks; 349 struct snd_seq_port_info *pinfo; 350 int err; 351 352 if (rdev->client >= 0) 353 return 0; 354 355 pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); 356 if (!pinfo) { 357 err = -ENOMEM; 358 goto __error; 359 } 360 361 client = snd_seq_create_kernel_client(rdev->card, rdev->device, 362 "%s %d-%d", rdev->rmidi->name, 363 rdev->card->number, 364 rdev->device); 365 if (client < 0) { 366 err = client; 367 goto __error; 368 } 369 rdev->client = client; 370 371 /* create a port */ 372 pinfo->addr.client = client; 373 sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device); 374 /* set all capabilities */ 375 pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; 376 pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; 377 pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; 378 pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC 379 | SNDRV_SEQ_PORT_TYPE_SOFTWARE 380 | SNDRV_SEQ_PORT_TYPE_PORT; 381 pinfo->midi_channels = 16; 382 memset(&pcallbacks, 0, sizeof(pcallbacks)); 383 pcallbacks.owner = THIS_MODULE; 384 pcallbacks.private_data = rdev; 385 pcallbacks.subscribe = snd_virmidi_subscribe; 386 pcallbacks.unsubscribe = snd_virmidi_unsubscribe; 387 pcallbacks.use = snd_virmidi_use; 388 pcallbacks.unuse = snd_virmidi_unuse; 389 pcallbacks.event_input = snd_virmidi_event_input; 390 pinfo->kernel = &pcallbacks; 391 err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo); 392 if (err < 0) { 393 snd_seq_delete_kernel_client(client); 394 rdev->client = -1; 395 goto __error; 396 } 397 398 rdev->port = pinfo->addr.port; 399 err = 0; /* success */ 400 401 __error: 402 kfree(pinfo); 403 return err; 404} 405 406 407/* 408 * release the sequencer client 409 */ 410static void snd_virmidi_dev_detach_seq(struct snd_virmidi_dev *rdev) 411{ 412 if (rdev->client >= 0) { 413 snd_seq_delete_kernel_client(rdev->client); 414 rdev->client = -1; 415 } 416} 417 418/* 419 * register the device 420 */ 421static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi) 422{ 423 struct snd_virmidi_dev *rdev = rmidi->private_data; 424 int err; 425 426 switch (rdev->seq_mode) { 427 case SNDRV_VIRMIDI_SEQ_DISPATCH: 428 err = snd_virmidi_dev_attach_seq(rdev); 429 if (err < 0) 430 return err; 431 break; 432 case SNDRV_VIRMIDI_SEQ_ATTACH: 433 if (rdev->client == 0) 434 return -EINVAL; 435 /* should check presence of port more strictly.. */ 436 break; 437 default: 438 snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode); 439 return -EINVAL; 440 } 441 return 0; 442} 443 444 445/* 446 * unregister the device 447 */ 448static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi) 449{ 450 struct snd_virmidi_dev *rdev = rmidi->private_data; 451 452 if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH) 453 snd_virmidi_dev_detach_seq(rdev); 454 return 0; 455} 456 457/* 458 * 459 */ 460static struct snd_rawmidi_global_ops snd_virmidi_global_ops = { 461 .dev_register = snd_virmidi_dev_register, 462 .dev_unregister = snd_virmidi_dev_unregister, 463}; 464 465/* 466 * free device 467 */ 468static void snd_virmidi_free(struct snd_rawmidi *rmidi) 469{ 470 struct snd_virmidi_dev *rdev = rmidi->private_data; 471 kfree(rdev); 472} 473 474/* 475 * create a new device 476 * 477 */ 478/* exported */ 479int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmidi) 480{ 481 struct snd_rawmidi *rmidi; 482 struct snd_virmidi_dev *rdev; 483 int err; 484 485 *rrmidi = NULL; 486 if ((err = snd_rawmidi_new(card, "VirMidi", device, 487 16, /* may be configurable */ 488 16, /* may be configurable */ 489 &rmidi)) < 0) 490 return err; 491 strcpy(rmidi->name, rmidi->id); 492 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); 493 if (rdev == NULL) { 494 snd_device_free(card, rmidi); 495 return -ENOMEM; 496 } 497 rdev->card = card; 498 rdev->rmidi = rmidi; 499 rdev->device = device; 500 rdev->client = -1; 501 rwlock_init(&rdev->filelist_lock); 502 INIT_LIST_HEAD(&rdev->filelist); 503 rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; 504 rmidi->private_data = rdev; 505 rmidi->private_free = snd_virmidi_free; 506 rmidi->ops = &snd_virmidi_global_ops; 507 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_virmidi_input_ops); 508 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_virmidi_output_ops); 509 rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | 510 SNDRV_RAWMIDI_INFO_OUTPUT | 511 SNDRV_RAWMIDI_INFO_DUPLEX; 512 *rrmidi = rmidi; 513 return 0; 514} 515 516/* 517 * ENTRY functions 518 */ 519 520static int __init alsa_virmidi_init(void) 521{ 522 return 0; 523} 524 525static void __exit alsa_virmidi_exit(void) 526{ 527} 528 529module_init(alsa_virmidi_init) 530module_exit(alsa_virmidi_exit) 531 532EXPORT_SYMBOL(snd_virmidi_new); 533