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