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 v3.19 711 lines 17 kB view raw
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 <sound/asoundef.h> 24#include "seq_oss_midi.h" 25#include "seq_oss_readq.h" 26#include "seq_oss_timer.h" 27#include "seq_oss_event.h" 28#include <sound/seq_midi_event.h> 29#include "../seq_lock.h" 30#include <linux/init.h> 31#include <linux/slab.h> 32 33 34/* 35 * constants 36 */ 37#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30 38 39/* 40 * definition of midi device record 41 */ 42struct seq_oss_midi { 43 int seq_device; /* device number */ 44 int client; /* sequencer client number */ 45 int port; /* sequencer port number */ 46 unsigned int flags; /* port capability */ 47 int opened; /* flag for opening */ 48 unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME]; 49 struct snd_midi_event *coder; /* MIDI event coder */ 50 struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */ 51 snd_use_lock_t use_lock; 52}; 53 54 55/* 56 * midi device table 57 */ 58static int max_midi_devs; 59static struct seq_oss_midi *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS]; 60 61static DEFINE_SPINLOCK(register_lock); 62 63/* 64 * prototypes 65 */ 66static struct seq_oss_midi *get_mdev(int dev); 67static struct seq_oss_midi *get_mididev(struct seq_oss_devinfo *dp, int dev); 68static int send_synth_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int dev); 69static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev); 70 71/* 72 * look up the existing ports 73 * this looks a very exhausting job. 74 */ 75int 76snd_seq_oss_midi_lookup_ports(int client) 77{ 78 struct snd_seq_client_info *clinfo; 79 struct snd_seq_port_info *pinfo; 80 81 clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); 82 pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); 83 if (! clinfo || ! pinfo) { 84 kfree(clinfo); 85 kfree(pinfo); 86 return -ENOMEM; 87 } 88 clinfo->client = -1; 89 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) { 90 if (clinfo->client == client) 91 continue; /* ignore myself */ 92 pinfo->addr.client = clinfo->client; 93 pinfo->addr.port = -1; 94 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0) 95 snd_seq_oss_midi_check_new_port(pinfo); 96 } 97 kfree(clinfo); 98 kfree(pinfo); 99 return 0; 100} 101 102 103/* 104 */ 105static struct seq_oss_midi * 106get_mdev(int dev) 107{ 108 struct seq_oss_midi *mdev; 109 unsigned long flags; 110 111 spin_lock_irqsave(&register_lock, flags); 112 mdev = midi_devs[dev]; 113 if (mdev) 114 snd_use_lock_use(&mdev->use_lock); 115 spin_unlock_irqrestore(&register_lock, flags); 116 return mdev; 117} 118 119/* 120 * look for the identical slot 121 */ 122static struct seq_oss_midi * 123find_slot(int client, int port) 124{ 125 int i; 126 struct seq_oss_midi *mdev; 127 unsigned long flags; 128 129 spin_lock_irqsave(&register_lock, flags); 130 for (i = 0; i < max_midi_devs; i++) { 131 mdev = midi_devs[i]; 132 if (mdev && mdev->client == client && mdev->port == port) { 133 /* found! */ 134 snd_use_lock_use(&mdev->use_lock); 135 spin_unlock_irqrestore(&register_lock, flags); 136 return mdev; 137 } 138 } 139 spin_unlock_irqrestore(&register_lock, flags); 140 return NULL; 141} 142 143 144#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE) 145#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ) 146/* 147 * register a new port if it doesn't exist yet 148 */ 149int 150snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo) 151{ 152 int i; 153 struct seq_oss_midi *mdev; 154 unsigned long flags; 155 156 /* the port must include generic midi */ 157 if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC)) 158 return 0; 159 /* either read or write subscribable */ 160 if ((pinfo->capability & PERM_WRITE) != PERM_WRITE && 161 (pinfo->capability & PERM_READ) != PERM_READ) 162 return 0; 163 164 /* 165 * look for the identical slot 166 */ 167 if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) { 168 /* already exists */ 169 snd_use_lock_free(&mdev->use_lock); 170 return 0; 171 } 172 173 /* 174 * allocate midi info record 175 */ 176 if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { 177 pr_err("ALSA: seq_oss: can't malloc midi info\n"); 178 return -ENOMEM; 179 } 180 181 /* copy the port information */ 182 mdev->client = pinfo->addr.client; 183 mdev->port = pinfo->addr.port; 184 mdev->flags = pinfo->capability; 185 mdev->opened = 0; 186 snd_use_lock_init(&mdev->use_lock); 187 188 /* copy and truncate the name of synth device */ 189 strlcpy(mdev->name, pinfo->name, sizeof(mdev->name)); 190 191 /* create MIDI coder */ 192 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) { 193 pr_err("ALSA: seq_oss: can't malloc midi coder\n"); 194 kfree(mdev); 195 return -ENOMEM; 196 } 197 /* OSS sequencer adds running status to all sequences */ 198 snd_midi_event_no_status(mdev->coder, 1); 199 200 /* 201 * look for en empty slot 202 */ 203 spin_lock_irqsave(&register_lock, flags); 204 for (i = 0; i < max_midi_devs; i++) { 205 if (midi_devs[i] == NULL) 206 break; 207 } 208 if (i >= max_midi_devs) { 209 if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) { 210 spin_unlock_irqrestore(&register_lock, flags); 211 snd_midi_event_free(mdev->coder); 212 kfree(mdev); 213 return -ENOMEM; 214 } 215 max_midi_devs++; 216 } 217 mdev->seq_device = i; 218 midi_devs[mdev->seq_device] = mdev; 219 spin_unlock_irqrestore(&register_lock, flags); 220 221 return 0; 222} 223 224/* 225 * release the midi device if it was registered 226 */ 227int 228snd_seq_oss_midi_check_exit_port(int client, int port) 229{ 230 struct seq_oss_midi *mdev; 231 unsigned long flags; 232 int index; 233 234 if ((mdev = find_slot(client, port)) != NULL) { 235 spin_lock_irqsave(&register_lock, flags); 236 midi_devs[mdev->seq_device] = NULL; 237 spin_unlock_irqrestore(&register_lock, flags); 238 snd_use_lock_free(&mdev->use_lock); 239 snd_use_lock_sync(&mdev->use_lock); 240 if (mdev->coder) 241 snd_midi_event_free(mdev->coder); 242 kfree(mdev); 243 } 244 spin_lock_irqsave(&register_lock, flags); 245 for (index = max_midi_devs - 1; index >= 0; index--) { 246 if (midi_devs[index]) 247 break; 248 } 249 max_midi_devs = index + 1; 250 spin_unlock_irqrestore(&register_lock, flags); 251 return 0; 252} 253 254 255/* 256 * release the midi device if it was registered 257 */ 258void 259snd_seq_oss_midi_clear_all(void) 260{ 261 int i; 262 struct seq_oss_midi *mdev; 263 unsigned long flags; 264 265 spin_lock_irqsave(&register_lock, flags); 266 for (i = 0; i < max_midi_devs; i++) { 267 if ((mdev = midi_devs[i]) != NULL) { 268 if (mdev->coder) 269 snd_midi_event_free(mdev->coder); 270 kfree(mdev); 271 midi_devs[i] = NULL; 272 } 273 } 274 max_midi_devs = 0; 275 spin_unlock_irqrestore(&register_lock, flags); 276} 277 278 279/* 280 * set up midi tables 281 */ 282void 283snd_seq_oss_midi_setup(struct seq_oss_devinfo *dp) 284{ 285 dp->max_mididev = max_midi_devs; 286} 287 288/* 289 * clean up midi tables 290 */ 291void 292snd_seq_oss_midi_cleanup(struct seq_oss_devinfo *dp) 293{ 294 int i; 295 for (i = 0; i < dp->max_mididev; i++) 296 snd_seq_oss_midi_close(dp, i); 297 dp->max_mididev = 0; 298} 299 300 301/* 302 * open all midi devices. ignore errors. 303 */ 304void 305snd_seq_oss_midi_open_all(struct seq_oss_devinfo *dp, int file_mode) 306{ 307 int i; 308 for (i = 0; i < dp->max_mididev; i++) 309 snd_seq_oss_midi_open(dp, i, file_mode); 310} 311 312 313/* 314 * get the midi device information 315 */ 316static struct seq_oss_midi * 317get_mididev(struct seq_oss_devinfo *dp, int dev) 318{ 319 if (dev < 0 || dev >= dp->max_mididev) 320 return NULL; 321 return get_mdev(dev); 322} 323 324 325/* 326 * open the midi device if not opened yet 327 */ 328int 329snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode) 330{ 331 int perm; 332 struct seq_oss_midi *mdev; 333 struct snd_seq_port_subscribe subs; 334 335 if ((mdev = get_mididev(dp, dev)) == NULL) 336 return -ENODEV; 337 338 /* already used? */ 339 if (mdev->opened && mdev->devinfo != dp) { 340 snd_use_lock_free(&mdev->use_lock); 341 return -EBUSY; 342 } 343 344 perm = 0; 345 if (is_write_mode(fmode)) 346 perm |= PERM_WRITE; 347 if (is_read_mode(fmode)) 348 perm |= PERM_READ; 349 perm &= mdev->flags; 350 if (perm == 0) { 351 snd_use_lock_free(&mdev->use_lock); 352 return -ENXIO; 353 } 354 355 /* already opened? */ 356 if ((mdev->opened & perm) == perm) { 357 snd_use_lock_free(&mdev->use_lock); 358 return 0; 359 } 360 361 perm &= ~mdev->opened; 362 363 memset(&subs, 0, sizeof(subs)); 364 365 if (perm & PERM_WRITE) { 366 subs.sender = dp->addr; 367 subs.dest.client = mdev->client; 368 subs.dest.port = mdev->port; 369 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) 370 mdev->opened |= PERM_WRITE; 371 } 372 if (perm & PERM_READ) { 373 subs.sender.client = mdev->client; 374 subs.sender.port = mdev->port; 375 subs.dest = dp->addr; 376 subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP; 377 subs.queue = dp->queue; /* queue for timestamps */ 378 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0) 379 mdev->opened |= PERM_READ; 380 } 381 382 if (! mdev->opened) { 383 snd_use_lock_free(&mdev->use_lock); 384 return -ENXIO; 385 } 386 387 mdev->devinfo = dp; 388 snd_use_lock_free(&mdev->use_lock); 389 return 0; 390} 391 392/* 393 * close the midi device if already opened 394 */ 395int 396snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev) 397{ 398 struct seq_oss_midi *mdev; 399 struct snd_seq_port_subscribe subs; 400 401 if ((mdev = get_mididev(dp, dev)) == NULL) 402 return -ENODEV; 403 if (! mdev->opened || mdev->devinfo != dp) { 404 snd_use_lock_free(&mdev->use_lock); 405 return 0; 406 } 407 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 memset(&ev, 0, sizeof(ev)); 472 ev.dest.client = mdev->client; 473 ev.dest.port = mdev->port; 474 ev.queue = dp->queue; 475 ev.source.port = dp->port; 476 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) { 477 ev.type = SNDRV_SEQ_EVENT_SENSING; 478 snd_seq_oss_dispatch(dp, &ev, 0, 0); 479 } 480 for (c = 0; c < 16; c++) { 481 ev.type = SNDRV_SEQ_EVENT_CONTROLLER; 482 ev.data.control.channel = c; 483 ev.data.control.param = MIDI_CTL_ALL_NOTES_OFF; 484 snd_seq_oss_dispatch(dp, &ev, 0, 0); 485 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { 486 ev.data.control.param = 487 MIDI_CTL_RESET_CONTROLLERS; 488 snd_seq_oss_dispatch(dp, &ev, 0, 0); 489 ev.type = SNDRV_SEQ_EVENT_PITCHBEND; 490 ev.data.control.value = 0; 491 snd_seq_oss_dispatch(dp, &ev, 0, 0); 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; /* FIXME: ?? */ 664 inf->capabilities = 0; /* FIXME: ?? */ 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 */