Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.7 696 lines 16 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * OSS compatible sequencer driver 4 * 5 * MIDI device handlers 6 * 7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de> 8 */ 9 10#include <sound/asoundef.h> 11#include "seq_oss_midi.h" 12#include "seq_oss_readq.h" 13#include "seq_oss_timer.h" 14#include "seq_oss_event.h" 15#include <sound/seq_midi_event.h> 16#include "../seq_lock.h" 17#include <linux/init.h> 18#include <linux/slab.h> 19#include <linux/nospec.h> 20 21 22/* 23 * constants 24 */ 25#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30 26 27/* 28 * definition of midi device record 29 */ 30struct seq_oss_midi { 31 int seq_device; /* device number */ 32 int client; /* sequencer client number */ 33 int port; /* sequencer port number */ 34 unsigned int flags; /* port capability */ 35 int opened; /* flag for opening */ 36 unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME]; 37 struct snd_midi_event *coder; /* MIDI event coder */ 38 struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */ 39 snd_use_lock_t use_lock; 40}; 41 42 43/* 44 * midi device table 45 */ 46static int max_midi_devs; 47static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS]; 48 49static DEFINE_SPINLOCK(register_lock); 50 51/* 52 * prototypes 53 */ 54static struct seq_oss_midi *get_mdev(int dev); 55static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev); 56static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev); 57static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev); 58 59/* 60 * look up the existing ports 61 * this looks a very exhausting job. 62 */ 63int 64snd_seq_oss_midi_lookup_ports(int client) 65{ 66 struct snd_seq_client_info *clinfo; 67 struct snd_seq_port_info *pinfo; 68 69 clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); 70 pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); 71 if (! clinfo || ! pinfo) { 72 kfree(clinfo); 73 kfree(pinfo); 74 return -ENOMEM; 75 } 76 clinfo->client = -1; 77 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) { 78 if (clinfo->client == client) 79 continue; /* ignore myself */ 80 pinfo->addr.client = clinfo->client; 81 pinfo->addr.port = -1; 82 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0) 83 snd_seq_oss_midi_check_new_port(pinfo); 84 } 85 kfree(clinfo); 86 kfree(pinfo); 87 return 0; 88} 89 90 91/* 92 */ 93static struct seq_oss_midi * 94get_mdev(int dev) 95{ 96 struct seq_oss_midi *mdev; 97 unsigned long flags; 98 99 spin_lock_irqsave(&register_lock, flags); 100 mdev = midi_devs[dev]; 101 if (mdev) 102 snd_use_lock_use(&mdev->use_lock); 103 spin_unlock_irqrestore(&register_lock, flags); 104 return mdev; 105} 106 107/* 108 * look for the identical slot 109 */ 110static struct seq_oss_midi * 111find_slot(int client, int port) 112{ 113 int i; 114 struct seq_oss_midi *mdev; 115 unsigned long flags; 116 117 spin_lock_irqsave(&register_lock, flags); 118 for (i = 0; i < max_midi_devs; i++) { 119 mdev = midi_devs[i]; 120 if (mdev && mdev->client == client && mdev->port == port) { 121 /* found! */ 122 snd_use_lock_use(&mdev->use_lock); 123 spin_unlock_irqrestore(&register_lock, flags); 124 return mdev; 125 } 126 } 127 spin_unlock_irqrestore(&register_lock, flags); 128 return NULL; 129} 130 131 132#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE) 133#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ) 134/* 135 * register a new port if it doesn't exist yet 136 */ 137int 138snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) 139{ 140 int i; 141 struct seq_oss_midi *mdev; 142 unsigned long flags; 143 144 /* the port must include generic midi */ 145 if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC)) 146 return 0; 147 /* either read or write subscribable */ 148 if ((pinfo->capability & PERM_WRITE) != PERM_WRITE && 149 (pinfo->capability & PERM_READ) != PERM_READ) 150 return 0; 151 152 /* 153 * look for the identical slot 154 */ 155 if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { 156 /* already exists */ 157 snd_use_lock_free(&mdev->use_lock); 158 return 0; 159 } 160 161 /* 162 * allocate midi info record 163 */ 164 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 165 if (!mdev) 166 return -ENOMEM; 167 168 /* copy the port information */ 169 mdev->client = pinfo->addr.client; 170 mdev->port = pinfo->addr.port; 171 mdev->flags = pinfo->capability; 172 mdev->opened = 0; 173 snd_use_lock_init(&mdev->use_lock); 174 175 /* copy and truncate the name of synth device */ 176 strlcpy(mdev->name, pinfo->name, sizeof(mdev->name)); 177 178 /* create MIDI coder */ 179 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) { 180 pr_err("ALSA: seq_oss: can't malloc midi coder\n"); 181 kfree(mdev); 182 return -ENOMEM; 183 } 184 /* OSS sequencer adds running status to all sequences */ 185 snd_midi_event_no_status(mdev->coder, 1); 186 187 /* 188 * look for en empty slot 189 */ 190 spin_lock_irqsave(&register_lock, flags); 191 for (i = 0; i < max_midi_devs; i++) { 192 if (midi_devs[i] == NULL) 193 break; 194 } 195 if (i >= max_midi_devs) { 196 if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) { 197 spin_unlock_irqrestore(&register_lock, flags); 198 snd_midi_event_free(mdev->coder); 199 kfree(mdev); 200 return -ENOMEM; 201 } 202 max_midi_devs++; 203 } 204 mdev->seq_device = i; 205 midi_devs[mdev->seq_device] = mdev; 206 spin_unlock_irqrestore(&register_lock, flags); 207 208 return 0; 209} 210 211/* 212 * release the midi device if it was registered 213 */ 214int 215snd_seq_oss_midi_check_exit_port(int client, int port) 216{ 217 struct seq_oss_midi *mdev; 218 unsigned long flags; 219 int index; 220 221 if ((mdev = find_slot(client, port)) != NULL) { 222 spin_lock_irqsave(&register_lock, flags); 223 midi_devs[mdev->seq_device] = NULL; 224 spin_unlock_irqrestore(&register_lock, flags); 225 snd_use_lock_free(&mdev->use_lock); 226 snd_use_lock_sync(&mdev->use_lock); 227 snd_midi_event_free(mdev->coder); 228 kfree(mdev); 229 } 230 spin_lock_irqsave(&register_lock, flags); 231 for (index = max_midi_devs - 1; index >= 0; index--) { 232 if (midi_devs[index]) 233 break; 234 } 235 max_midi_devs = index + 1; 236 spin_unlock_irqrestore(&register_lock, flags); 237 return 0; 238} 239 240 241/* 242 * release the midi device if it was registered 243 */ 244void 245snd_seq_oss_midi_clear_all(void) 246{ 247 int i; 248 struct seq_oss_midi *mdev; 249 unsigned long flags; 250 251 spin_lock_irqsave(&register_lock, flags); 252 for (i = 0; i < max_midi_devs; i++) { 253 if ((mdev = midi_devs[i]) != NULL) { 254 snd_midi_event_free(mdev->coder); 255 kfree(mdev); 256 midi_devs[i] = NULL; 257 } 258 } 259 max_midi_devs = 0; 260 spin_unlock_irqrestore(&register_lock, flags); 261} 262 263 264/* 265 * set up midi tables 266 */ 267void 268snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) 269{ 270 dp->max_mididev = max_midi_devs; 271} 272 273/* 274 * clean up midi tables 275 */ 276void 277snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp) 278{ 279 int i; 280 for (i = 0; i < dp->max_mididev; i++) 281 snd_seq_oss_midi_close(dp, i); 282 dp->max_mididev = 0; 283} 284 285 286/* 287 * open all midi devices. ignore errors. 288 */ 289void 290snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode) 291{ 292 int i; 293 for (i = 0; i < dp->max_mididev; i++) 294 snd_seq_oss_midi_open(dp, i, file_mode); 295} 296 297 298/* 299 * get the midi device information 300 */ 301static struct seq_oss_midi * 302get_mididev(struct seq_oss_devinfo *dp, int dev) 303{ 304 if (dev < 0 || dev >= dp->max_mididev) 305 return NULL; 306 dev = array_index_nospec(dev, dp->max_mididev); 307 return get_mdev(dev); 308} 309 310 311/* 312 * open the midi device if not opened yet 313 */ 314int 315snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) 316{ 317 int perm; 318 struct seq_oss_midi *mdev; 319 struct snd_seq_port_subscribe subs; 320 321 if ((mdev = get_mididev(dp, dev)) == NULL) 322 return -ENODEV; 323 324 /* already used? */ 325 if (mdev->opened && mdev->devinfo != dp) { 326 snd_use_lock_free(&mdev->use_lock); 327 return -EBUSY; 328 } 329 330 perm = 0; 331 if (is_write_mode(fmode)) 332 perm |= PERM_WRITE; 333 if (is_read_mode(fmode)) 334 perm |= PERM_READ; 335 perm &= mdev->flags; 336 if (perm == 0) { 337 snd_use_lock_free(&mdev->use_lock); 338 return -ENXIO; 339 } 340 341 /* already opened? */ 342 if ((mdev->opened & perm) == perm) { 343 snd_use_lock_free(&mdev->use_lock); 344 return 0; 345 } 346 347 perm &= ~mdev->opened; 348 349 memset(&subs, 0, sizeof(subs)); 350 351 if (perm & PERM_WRITE) { 352 subs.sender = dp->addr; 353 subs.dest.client = mdev->client; 354 subs.dest.port = mdev->port; 355 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) 356 mdev->opened |= PERM_WRITE; 357 } 358 if (perm & PERM_READ) { 359 subs.sender.client = mdev->client; 360 subs.sender.port = mdev->port; 361 subs.dest = dp->addr; 362 subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP; 363 subs.queue = dp->queue; /* queue for timestamps */ 364 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) 365 mdev->opened |= PERM_READ; 366 } 367 368 if (! mdev->opened) { 369 snd_use_lock_free(&mdev->use_lock); 370 return -ENXIO; 371 } 372 373 mdev->devinfo = dp; 374 snd_use_lock_free(&mdev->use_lock); 375 return 0; 376} 377 378/* 379 * close the midi device if already opened 380 */ 381int 382snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) 383{ 384 struct seq_oss_midi *mdev; 385 struct snd_seq_port_subscribe subs; 386 387 if ((mdev = get_mididev(dp, dev)) == NULL) 388 return -ENODEV; 389 if (! mdev->opened || mdev->devinfo != dp) { 390 snd_use_lock_free(&mdev->use_lock); 391 return 0; 392 } 393 394 memset(&subs, 0, sizeof(subs)); 395 if (mdev->opened & PERM_WRITE) { 396 subs.sender = dp->addr; 397 subs.dest.client = mdev->client; 398 subs.dest.port = mdev->port; 399 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs); 400 } 401 if (mdev->opened & PERM_READ) { 402 subs.sender.client = mdev->client; 403 subs.sender.port = mdev->port; 404 subs.dest = dp->addr; 405 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs); 406 } 407 408 mdev->opened = 0; 409 mdev->devinfo = NULL; 410 411 snd_use_lock_free(&mdev->use_lock); 412 return 0; 413} 414 415/* 416 * change seq capability flags to file mode flags 417 */ 418int 419snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev) 420{ 421 struct seq_oss_midi *mdev; 422 int mode; 423 424 if ((mdev = get_mididev(dp, dev)) == NULL) 425 return 0; 426 427 mode = 0; 428 if (mdev->opened & PERM_WRITE) 429 mode |= SNDRV_SEQ_OSS_FILE_WRITE; 430 if (mdev->opened & PERM_READ) 431 mode |= SNDRV_SEQ_OSS_FILE_READ; 432 433 snd_use_lock_free(&mdev->use_lock); 434 return mode; 435} 436 437/* 438 * reset the midi device and close it: 439 * so far, only close the device. 440 */ 441void 442snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev) 443{ 444 struct seq_oss_midi *mdev; 445 446 if ((mdev = get_mididev(dp, dev)) == NULL) 447 return; 448 if (! mdev->opened) { 449 snd_use_lock_free(&mdev->use_lock); 450 return; 451 } 452 453 if (mdev->opened & PERM_WRITE) { 454 struct snd_seq_event ev; 455 int c; 456 457 memset(&ev, 0, sizeof(ev)); 458 ev.dest.client = mdev->client; 459 ev.dest.port = mdev->port; 460 ev.queue = dp->queue; 461 ev.source.port = dp->port; 462 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) { 463 ev.type = SNDRV_SEQ_EVENT_SENSING; 464 snd_seq_oss_dispatch(dp, &ev, 0, 0); 465 } 466 for (c = 0; c < 16; c++) { 467 ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 468 ev.data.control.channel = c; 469 ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF; 470 snd_seq_oss_dispatch(dp, &ev, 0, 0); 471 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { 472 ev.data.control.param = 473 MIDI_CTL_RESET_CONTROLLERS; 474 snd_seq_oss_dispatch(dp, &ev, 0, 0); 475 ev.type = SNDRV_SEQ_EVENT_PITCHBEND; 476 ev.data.control.value = 0; 477 snd_seq_oss_dispatch(dp, &ev, 0, 0); 478 } 479 } 480 } 481 // snd_seq_oss_midi_close(dp, dev); 482 snd_use_lock_free(&mdev->use_lock); 483} 484 485 486/* 487 * get client/port of the specified MIDI device 488 */ 489void 490snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_addr *addr) 491{ 492 struct seq_oss_midi *mdev; 493 494 if ((mdev = get_mididev(dp, dev)) == NULL) 495 return; 496 addr->client = mdev->client; 497 addr->port = mdev->port; 498 snd_use_lock_free(&mdev->use_lock); 499} 500 501 502/* 503 * input callback - this can be atomic 504 */ 505int 506snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data) 507{ 508 struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data; 509 struct seq_oss_midi *mdev; 510 int rc; 511 512 if (dp->readq == NULL) 513 return 0; 514 if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL) 515 return 0; 516 if (! (mdev->opened & PERM_READ)) { 517 snd_use_lock_free(&mdev->use_lock); 518 return 0; 519 } 520 521 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) 522 rc = send_synth_event(dp, ev, mdev->seq_device); 523 else 524 rc = send_midi_event(dp, ev, mdev); 525 526 snd_use_lock_free(&mdev->use_lock); 527 return rc; 528} 529 530/* 531 * convert ALSA sequencer event to OSS synth event 532 */ 533static int 534send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev) 535{ 536 union evrec ossev; 537 538 memset(&ossev, 0, sizeof(ossev)); 539 540 switch (ev->type) { 541 case SNDRV_SEQ_EVENT_NOTEON: 542 ossev.v.cmd = MIDI_NOTEON; break; 543 case SNDRV_SEQ_EVENT_NOTEOFF: 544 ossev.v.cmd = MIDI_NOTEOFF; break; 545 case SNDRV_SEQ_EVENT_KEYPRESS: 546 ossev.v.cmd = MIDI_KEY_PRESSURE; break; 547 case SNDRV_SEQ_EVENT_CONTROLLER: 548 ossev.l.cmd = MIDI_CTL_CHANGE; break; 549 case SNDRV_SEQ_EVENT_PGMCHANGE: 550 ossev.l.cmd = MIDI_PGM_CHANGE; break; 551 case SNDRV_SEQ_EVENT_CHANPRESS: 552 ossev.l.cmd = MIDI_CHN_PRESSURE; break; 553 case SNDRV_SEQ_EVENT_PITCHBEND: 554 ossev.l.cmd = MIDI_PITCH_BEND; break; 555 default: 556 return 0; /* not supported */ 557 } 558 559 ossev.v.dev = dev; 560 561 switch (ev->type) { 562 case SNDRV_SEQ_EVENT_NOTEON: 563 case SNDRV_SEQ_EVENT_NOTEOFF: 564 case SNDRV_SEQ_EVENT_KEYPRESS: 565 ossev.v.code = EV_CHN_VOICE; 566 ossev.v.note = ev->data.note.note; 567 ossev.v.parm = ev->data.note.velocity; 568 ossev.v.chn = ev->data.note.channel; 569 break; 570 case SNDRV_SEQ_EVENT_CONTROLLER: 571 case SNDRV_SEQ_EVENT_PGMCHANGE: 572 case SNDRV_SEQ_EVENT_CHANPRESS: 573 ossev.l.code = EV_CHN_COMMON; 574 ossev.l.p1 = ev->data.control.param; 575 ossev.l.val = ev->data.control.value; 576 ossev.l.chn = ev->data.control.channel; 577 break; 578 case SNDRV_SEQ_EVENT_PITCHBEND: 579 ossev.l.code = EV_CHN_COMMON; 580 ossev.l.val = ev->data.control.value + 8192; 581 ossev.l.chn = ev->data.control.channel; 582 break; 583 } 584 585 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode); 586 snd_seq_oss_readq_put_event(dp->readq, &ossev); 587 588 return 0; 589} 590 591/* 592 * decode event and send MIDI bytes to read queue 593 */ 594static int 595send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev) 596{ 597 char msg[32]; 598 int len; 599 600 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode); 601 if (!dp->timer->running) 602 len = snd_seq_oss_timer_start(dp->timer); 603 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { 604 snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev); 605 snd_midi_event_reset_decode(mdev->coder); 606 } else { 607 len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); 608 if (len > 0) 609 snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len); 610 } 611 612 return 0; 613} 614 615 616/* 617 * dump midi data 618 * return 0 : enqueued 619 * non-zero : invalid - ignored 620 */ 621int 622snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev) 623{ 624 struct seq_oss_midi *mdev; 625 626 if ((mdev = get_mididev(dp, dev)) == NULL) 627 return -ENODEV; 628 if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { 629 snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); 630 snd_use_lock_free(&mdev->use_lock); 631 return 0; 632 } 633 snd_use_lock_free(&mdev->use_lock); 634 return -EINVAL; 635} 636 637/* 638 * create OSS compatible midi_info record 639 */ 640int 641snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info *inf) 642{ 643 struct seq_oss_midi *mdev; 644 645 if ((mdev = get_mididev(dp, dev)) == NULL) 646 return -ENXIO; 647 inf->device = dev; 648 inf->dev_type = 0; /* FIXME: ?? */ 649 inf->capabilities = 0; /* FIXME: ?? */ 650 strlcpy(inf->name, mdev->name, sizeof(inf->name)); 651 snd_use_lock_free(&mdev->use_lock); 652 return 0; 653} 654 655 656#ifdef CONFIG_SND_PROC_FS 657/* 658 * proc interface 659 */ 660static char * 661capmode_str(int val) 662{ 663 val &= PERM_READ|PERM_WRITE; 664 if (val == (PERM_READ|PERM_WRITE)) 665 return "read/write"; 666 else if (val == PERM_READ) 667 return "read"; 668 else if (val == PERM_WRITE) 669 return "write"; 670 else 671 return "none"; 672} 673 674void 675snd_seq_oss_midi_info_read(struct snd_info_buffer *buf) 676{ 677 int i; 678 struct seq_oss_midi *mdev; 679 680 snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs); 681 for (i = 0; i < max_midi_devs; i++) { 682 snd_iprintf(buf, "\nmidi %d: ", i); 683 mdev = get_mdev(i); 684 if (mdev == NULL) { 685 snd_iprintf(buf, "*empty*\n"); 686 continue; 687 } 688 snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name, 689 mdev->client, mdev->port); 690 snd_iprintf(buf, " capability %s / opened %s\n", 691 capmode_str(mdev->flags), 692 capmode_str(mdev->opened)); 693 snd_use_lock_free(&mdev->use_lock); 694 } 695} 696#endif /* CONFIG_SND_PROC_FS */