1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 3 * 4 * Copyright (c) 2003 Mathew Kanner 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (augustss@netbsd.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Parts of this file started out as NetBSD: midi.c 1.31 35 * They are mostly gone. Still the most obvious will be the state 36 * machine midi_in 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/queue.h> 45 #include <sys/kernel.h> 46 #include <sys/lock.h> 47 #include <sys/mutex.h> 48 #include <sys/proc.h> 49 #include <sys/signalvar.h> 50 #include <sys/conf.h> 51 #include <sys/selinfo.h> 52 #include <sys/sysctl.h> 53 #include <sys/malloc.h> 54 #include <sys/sx.h> 55 #include <sys/proc.h> 56 #include <sys/fcntl.h> 57 #include <sys/types.h> 58 #include <sys/uio.h> 59 #include <sys/poll.h> 60 #include <sys/sbuf.h> 61 #include <sys/kobj.h> 62 #include <sys/module.h> 63 64 #ifdef HAVE_KERNEL_OPTION_HEADERS 65 #include "opt_snd.h" 66 #endif 67 68 #include <dev/sound/midi/midi.h> 69 #include "mpu_if.h" 70 71 #include <dev/sound/midi/midiq.h> 72 #include "synth_if.h" 73 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area"); 74 75 #ifndef KOBJMETHOD_END 76 #define KOBJMETHOD_END { NULL, NULL } 77 #endif 78 79 #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f)) 80 #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c) 81 82 #define MIDI_DEV_RAW 2 83 #define MIDI_DEV_MIDICTL 12 84 85 enum midi_states { 86 MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA 87 }; 88 89 /* 90 * The MPU interface current has init() uninit() inqsize() outqsize() 91 * callback() : fiddle with the tx|rx status. 92 */ 93 94 #include "mpu_if.h" 95 96 /* 97 * /dev/rmidi Structure definitions 98 */ 99 100 #define MIDI_NAMELEN 16 101 struct snd_midi { 102 KOBJ_FIELDS; 103 struct mtx lock; /* Protects all but queues */ 104 void *cookie; 105 106 int unit; /* Should only be used in midistat */ 107 int channel; /* Should only be used in midistat */ 108 109 int busy; 110 int flags; /* File flags */ 111 char name[MIDI_NAMELEN]; 112 struct mtx qlock; /* Protects inq, outq and flags */ 113 MIDIQ_HEAD(, char) inq, outq; 114 int rchan, wchan; 115 struct selinfo rsel, wsel; 116 int hiwat; /* QLEN(outq)>High-water -> disable 117 * writes from userland */ 118 enum midi_states inq_state; 119 int inq_status, inq_left; /* Variables for the state machine in 120 * Midi_in, this is to provide that 121 * signals only get issued only 122 * complete command packets. */ 123 struct proc *async; 124 struct cdev *dev; 125 struct synth_midi *synth; 126 int synth_flags; 127 TAILQ_ENTRY(snd_midi) link; 128 }; 129 130 struct synth_midi { 131 KOBJ_FIELDS; 132 struct snd_midi *m; 133 }; 134 135 static synth_open_t midisynth_open; 136 static synth_close_t midisynth_close; 137 static synth_writeraw_t midisynth_writeraw; 138 static synth_killnote_t midisynth_killnote; 139 static synth_startnote_t midisynth_startnote; 140 static synth_setinstr_t midisynth_setinstr; 141 static synth_alloc_t midisynth_alloc; 142 static synth_controller_t midisynth_controller; 143 static synth_bender_t midisynth_bender; 144 145 146 static kobj_method_t midisynth_methods[] = { 147 KOBJMETHOD(synth_open, midisynth_open), 148 KOBJMETHOD(synth_close, midisynth_close), 149 KOBJMETHOD(synth_writeraw, midisynth_writeraw), 150 KOBJMETHOD(synth_setinstr, midisynth_setinstr), 151 KOBJMETHOD(synth_startnote, midisynth_startnote), 152 KOBJMETHOD(synth_killnote, midisynth_killnote), 153 KOBJMETHOD(synth_alloc, midisynth_alloc), 154 KOBJMETHOD(synth_controller, midisynth_controller), 155 KOBJMETHOD(synth_bender, midisynth_bender), 156 KOBJMETHOD_END 157 }; 158 159 DEFINE_CLASS(midisynth, midisynth_methods, 0); 160 161 /* 162 * Module Exports & Interface 163 * 164 * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan, 165 * void *cookie) 166 * int midi_uninit(struct snd_midi *) 167 * 168 * 0 == no error 169 * EBUSY or other error 170 * 171 * int midi_in(struct snd_midi *, char *buf, int count) 172 * int midi_out(struct snd_midi *, char *buf, int count) 173 * 174 * midi_{in,out} return actual size transfered 175 * 176 */ 177 178 179 /* 180 * midi_devs tailq, holder of all rmidi instances protected by midistat_lock 181 */ 182 183 TAILQ_HEAD(, snd_midi) midi_devs; 184 185 /* 186 * /dev/midistat variables and declarations, protected by midistat_lock 187 */ 188 189 static struct sx midistat_lock; 190 static int midistat_isopen = 0; 191 static struct sbuf midistat_sbuf; 192 static struct cdev *midistat_dev; 193 194 /* 195 * /dev/midistat dev_t declarations 196 */ 197 198 static d_open_t midistat_open; 199 static d_close_t midistat_close; 200 static d_read_t midistat_read; 201 202 static struct cdevsw midistat_cdevsw = { 203 .d_version = D_VERSION, 204 .d_open = midistat_open, 205 .d_close = midistat_close, 206 .d_read = midistat_read, 207 .d_name = "midistat", 208 }; 209 210 211 /* 212 * /dev/rmidi dev_t declarations, struct variable access is protected by 213 * locks contained within the structure. 214 */ 215 216 static d_open_t midi_open; 217 static d_close_t midi_close; 218 static d_ioctl_t midi_ioctl; 219 static d_read_t midi_read; 220 static d_write_t midi_write; 221 static d_poll_t midi_poll; 222 223 static struct cdevsw midi_cdevsw = { 224 .d_version = D_VERSION, 225 .d_open = midi_open, 226 .d_close = midi_close, 227 .d_read = midi_read, 228 .d_write = midi_write, 229 .d_ioctl = midi_ioctl, 230 .d_poll = midi_poll, 231 .d_name = "rmidi", 232 }; 233 234 /* 235 * Prototypes of library functions 236 */ 237 238 static int midi_destroy(struct snd_midi *, int); 239 static int midistat_prepare(struct sbuf * s); 240 static int midi_load(void); 241 static int midi_unload(void); 242 243 /* 244 * Misc declr. 245 */ 246 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver"); 247 static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device"); 248 249 int midi_debug; 250 /* XXX: should this be moved into debug.midi? */ 251 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, ""); 252 253 int midi_dumpraw; 254 SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, ""); 255 256 int midi_instroff; 257 SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, ""); 258 259 int midistat_verbose; 260 SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW, 261 &midistat_verbose, 0, ""); 262 263 #define MIDI_DEBUG(l,a) if(midi_debug>=l) a 264 /* 265 * CODE START 266 */ 267 268 /* 269 * Register a new rmidi device. cls midi_if interface unit == 0 means 270 * auto-assign new unit number unit != 0 already assigned a unit number, eg. 271 * not the first channel provided by this device. channel, sub-unit 272 * cookie is passed back on MPU calls Typical device drivers will call with 273 * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care 274 * what unit number is used. 275 * 276 * It is an error to call midi_init with an already used unit/channel combo. 277 * 278 * Returns NULL on error 279 * 280 */ 281 struct snd_midi * 282 midi_init(kobj_class_t cls, int unit, int channel, void *cookie) 283 { 284 struct snd_midi *m; 285 int i; 286 int inqsize, outqsize; 287 MIDI_TYPE *buf; 288 289 MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel)); 290 sx_xlock(&midistat_lock); 291 /* 292 * Protect against call with existing unit/channel or auto-allocate a 293 * new unit number. 294 */ 295 i = -1; 296 TAILQ_FOREACH(m, &midi_devs, link) { 297 mtx_lock(&m->lock); 298 if (unit != 0) { 299 if (m->unit == unit && m->channel == channel) { 300 mtx_unlock(&m->lock); 301 goto err0; 302 } 303 } else { 304 /* 305 * Find a better unit number 306 */ 307 if (m->unit > i) 308 i = m->unit; 309 } 310 mtx_unlock(&m->lock); 311 } 312 313 if (unit == 0) 314 unit = i + 1; 315 316 MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel)); 317 m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO); 318 m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO); 319 kobj_init((kobj_t)m->synth, &midisynth_class); 320 m->synth->m = m; 321 kobj_init((kobj_t)m, cls); 322 inqsize = MPU_INQSIZE(m, cookie); 323 outqsize = MPU_OUTQSIZE(m, cookie); 324 325 MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize)); 326 if (!inqsize && !outqsize) 327 goto err1; 328 329 mtx_init(&m->lock, "raw midi", NULL, 0); 330 mtx_init(&m->qlock, "q raw midi", NULL, 0); 331 332 mtx_lock(&m->lock); 333 mtx_lock(&m->qlock); 334 335 if (inqsize) 336 buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT); 337 else 338 buf = NULL; 339 340 MIDIQ_INIT(m->inq, buf, inqsize); 341 342 if (outqsize) 343 buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT); 344 else 345 buf = NULL; 346 m->hiwat = outqsize / 2; 347 348 MIDIQ_INIT(m->outq, buf, outqsize); 349 350 if ((inqsize && !MIDIQ_BUF(m->inq)) || 351 (outqsize && !MIDIQ_BUF(m->outq))) 352 goto err2; 353 354 m->busy = 0; 355 m->flags = 0; 356 m->unit = unit; 357 m->channel = channel; 358 m->cookie = cookie; 359 360 if (MPU_INIT(m, cookie)) 361 goto err2; 362 363 mtx_unlock(&m->lock); 364 mtx_unlock(&m->qlock); 365 366 TAILQ_INSERT_TAIL(&midi_devs, m, link); 367 368 sx_xunlock(&midistat_lock); 369 370 m->dev = make_dev(&midi_cdevsw, 371 MIDIMKMINOR(unit, MIDI_DEV_RAW, channel), 372 UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel); 373 m->dev->si_drv1 = m; 374 375 return m; 376 377 err2: 378 mtx_destroy(&m->qlock); 379 mtx_destroy(&m->lock); 380 381 if (MIDIQ_BUF(m->inq)) 382 free(MIDIQ_BUF(m->inq), M_MIDI); 383 if (MIDIQ_BUF(m->outq)) 384 free(MIDIQ_BUF(m->outq), M_MIDI); 385 err1: 386 free(m->synth, M_MIDI); 387 free(m, M_MIDI); 388 err0: 389 sx_xunlock(&midistat_lock); 390 MIDI_DEBUG(1, printf("midi_init ended in error\n")); 391 return NULL; 392 } 393 394 /* 395 * midi_uninit does not call MIDI_UNINIT, as since this is the implementors 396 * entry point. midi_uninit if fact, does not send any methods. A call to 397 * midi_uninit is a defacto promise that you won't manipulate ch anymore 398 * 399 */ 400 401 int 402 midi_uninit(struct snd_midi *m) 403 { 404 int err; 405 406 err = EBUSY; 407 sx_xlock(&midistat_lock); 408 mtx_lock(&m->lock); 409 if (m->busy) { 410 if (!(m->rchan || m->wchan)) 411 goto err; 412 413 if (m->rchan) { 414 wakeup(&m->rchan); 415 m->rchan = 0; 416 } 417 if (m->wchan) { 418 wakeup(&m->wchan); 419 m->wchan = 0; 420 } 421 } 422 err = midi_destroy(m, 0); 423 if (!err) 424 goto exit; 425 426 err: 427 mtx_unlock(&m->lock); 428 exit: 429 sx_xunlock(&midistat_lock); 430 return err; 431 } 432 433 /* 434 * midi_in: process all data until the queue is full, then discards the rest. 435 * Since midi_in is a state machine, data discards can cause it to get out of 436 * whack. Process as much as possible. It calls, wakeup, selnotify and 437 * psignal at most once. 438 */ 439 440 #ifdef notdef 441 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0}; 442 443 #endif /* notdef */ 444 /* Number of bytes in a MIDI command */ 445 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 446 #define MIDI_ACK 0xfe 447 #define MIDI_IS_STATUS(d) ((d) >= 0x80) 448 #define MIDI_IS_COMMON(d) ((d) >= 0xf0) 449 450 #define MIDI_SYSEX_START 0xF0 451 #define MIDI_SYSEX_END 0xF7 452 453 454 int 455 midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size) 456 { 457 /* int i, sig, enq; */ 458 int used; 459 460 /* MIDI_TYPE data; */ 461 MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size)); 462 463 /* 464 * XXX: locking flub 465 */ 466 if (!(m->flags & M_RX)) 467 return size; 468 469 used = 0; 470 471 mtx_lock(&m->qlock); 472 #if 0 473 /* 474 * Don't bother queuing if not in read mode. Discard everything and 475 * return size so the caller doesn't freak out. 476 */ 477 478 if (!(m->flags & M_RX)) 479 return size; 480 481 for (i = sig = 0; i < size; i++) { 482 483 data = buf[i]; 484 enq = 0; 485 if (data == MIDI_ACK) 486 continue; 487 488 switch (m->inq_state) { 489 case MIDI_IN_START: 490 if (MIDI_IS_STATUS(data)) { 491 switch (data) { 492 case 0xf0: /* Sysex */ 493 m->inq_state = MIDI_IN_SYSEX; 494 break; 495 case 0xf1: /* MTC quarter frame */ 496 case 0xf3: /* Song select */ 497 m->inq_state = MIDI_IN_DATA; 498 enq = 1; 499 m->inq_left = 1; 500 break; 501 case 0xf2: /* Song position pointer */ 502 m->inq_state = MIDI_IN_DATA; 503 enq = 1; 504 m->inq_left = 2; 505 break; 506 default: 507 if (MIDI_IS_COMMON(data)) { 508 enq = 1; 509 sig = 1; 510 } else { 511 m->inq_state = MIDI_IN_DATA; 512 enq = 1; 513 m->inq_status = data; 514 m->inq_left = MIDI_LENGTH(data); 515 } 516 break; 517 } 518 } else if (MIDI_IS_STATUS(m->inq_status)) { 519 m->inq_state = MIDI_IN_DATA; 520 if (!MIDIQ_FULL(m->inq)) { 521 used++; 522 MIDIQ_ENQ(m->inq, &m->inq_status, 1); 523 } 524 enq = 1; 525 m->inq_left = MIDI_LENGTH(m->inq_status) - 1; 526 } 527 break; 528 /* 529 * End of case MIDI_IN_START: 530 */ 531 532 case MIDI_IN_DATA: 533 enq = 1; 534 if (--m->inq_left <= 0) 535 sig = 1;/* deliver data */ 536 break; 537 case MIDI_IN_SYSEX: 538 if (data == MIDI_SYSEX_END) 539 m->inq_state = MIDI_IN_START; 540 break; 541 } 542 543 if (enq) 544 if (!MIDIQ_FULL(m->inq)) { 545 MIDIQ_ENQ(m->inq, &data, 1); 546 used++; 547 } 548 /* 549 * End of the state machines main "for loop" 550 */ 551 } 552 if (sig) { 553 #endif 554 MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n", 555 (intmax_t)MIDIQ_LEN(m->inq), 556 (intmax_t)MIDIQ_AVAIL(m->inq))); 557 if (MIDIQ_AVAIL(m->inq) > size) { 558 used = size; 559 MIDIQ_ENQ(m->inq, buf, size); 560 } else { 561 MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n")); 562 mtx_unlock(&m->qlock); 563 return 0; 564 } 565 if (m->rchan) { 566 wakeup(&m->rchan); 567 m->rchan = 0; 568 } 569 selwakeup(&m->rsel); 570 if (m->async) { 571 PROC_LOCK(m->async); 572 kern_psignal(m->async, SIGIO); 573 PROC_UNLOCK(m->async); 574 } 575 #if 0 576 } 577 #endif 578 mtx_unlock(&m->qlock); 579 return used; 580 } 581 582 /* 583 * midi_out: The only clearer of the M_TXEN flag. 584 */ 585 int 586 midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size) 587 { 588 int used; 589 590 /* 591 * XXX: locking flub 592 */ 593 if (!(m->flags & M_TXEN)) 594 return 0; 595 596 MIDI_DEBUG(2, printf("midi_out: %p\n", m)); 597 mtx_lock(&m->qlock); 598 used = MIN(size, MIDIQ_LEN(m->outq)); 599 MIDI_DEBUG(3, printf("midi_out: used %d\n", used)); 600 if (used) 601 MIDIQ_DEQ(m->outq, buf, used); 602 if (MIDIQ_EMPTY(m->outq)) { 603 m->flags &= ~M_TXEN; 604 MPU_CALLBACKP(m, m->cookie, m->flags); 605 } 606 if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) { 607 if (m->wchan) { 608 wakeup(&m->wchan); 609 m->wchan = 0; 610 } 611 selwakeup(&m->wsel); 612 if (m->async) { 613 PROC_LOCK(m->async); 614 kern_psignal(m->async, SIGIO); 615 PROC_UNLOCK(m->async); 616 } 617 } 618 mtx_unlock(&m->qlock); 619 return used; 620 } 621 622 623 /* 624 * /dev/rmidi#.# device access functions 625 */ 626 int 627 midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 628 { 629 struct snd_midi *m = i_dev->si_drv1; 630 int retval; 631 632 MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td, 633 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 634 if (m == NULL) 635 return ENXIO; 636 637 mtx_lock(&m->lock); 638 mtx_lock(&m->qlock); 639 640 retval = 0; 641 642 if (flags & FREAD) { 643 if (MIDIQ_SIZE(m->inq) == 0) 644 retval = ENXIO; 645 else if (m->flags & M_RX) 646 retval = EBUSY; 647 if (retval) 648 goto err; 649 } 650 if (flags & FWRITE) { 651 if (MIDIQ_SIZE(m->outq) == 0) 652 retval = ENXIO; 653 else if (m->flags & M_TX) 654 retval = EBUSY; 655 if (retval) 656 goto err; 657 } 658 m->busy++; 659 660 m->rchan = 0; 661 m->wchan = 0; 662 m->async = 0; 663 664 if (flags & FREAD) { 665 m->flags |= M_RX | M_RXEN; 666 /* 667 * Only clear the inq, the outq might still have data to drain 668 * from a previous session 669 */ 670 MIDIQ_CLEAR(m->inq); 671 } 672 673 if (flags & FWRITE) 674 m->flags |= M_TX; 675 676 MPU_CALLBACK(m, m->cookie, m->flags); 677 678 MIDI_DEBUG(2, printf("midi_open: opened.\n")); 679 680 err: mtx_unlock(&m->qlock); 681 mtx_unlock(&m->lock); 682 return retval; 683 } 684 685 int 686 midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 687 { 688 struct snd_midi *m = i_dev->si_drv1; 689 int retval; 690 int oldflags; 691 692 MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td, 693 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 694 695 if (m == NULL) 696 return ENXIO; 697 698 mtx_lock(&m->lock); 699 mtx_lock(&m->qlock); 700 701 if ((flags & FREAD && !(m->flags & M_RX)) || 702 (flags & FWRITE && !(m->flags & M_TX))) { 703 retval = ENXIO; 704 goto err; 705 } 706 m->busy--; 707 708 oldflags = m->flags; 709 710 if (flags & FREAD) 711 m->flags &= ~(M_RX | M_RXEN); 712 if (flags & FWRITE) 713 m->flags &= ~M_TX; 714 715 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 716 MPU_CALLBACK(m, m->cookie, m->flags); 717 718 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 719 720 mtx_unlock(&m->qlock); 721 mtx_unlock(&m->lock); 722 retval = 0; 723 err: return retval; 724 } 725 726 /* 727 * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon 728 * as data is available. 729 */ 730 int 731 midi_read(struct cdev *i_dev, struct uio *uio, int ioflag) 732 { 733 #define MIDI_RSIZE 32 734 struct snd_midi *m = i_dev->si_drv1; 735 int retval; 736 int used; 737 char buf[MIDI_RSIZE]; 738 739 MIDI_DEBUG(5, printf("midiread: count=%lu\n", 740 (unsigned long)uio->uio_resid)); 741 742 retval = EIO; 743 744 if (m == NULL) 745 goto err0; 746 747 mtx_lock(&m->lock); 748 mtx_lock(&m->qlock); 749 750 if (!(m->flags & M_RX)) 751 goto err1; 752 753 while (uio->uio_resid > 0) { 754 while (MIDIQ_EMPTY(m->inq)) { 755 retval = EWOULDBLOCK; 756 if (ioflag & O_NONBLOCK) 757 goto err1; 758 mtx_unlock(&m->lock); 759 m->rchan = 1; 760 retval = msleep(&m->rchan, &m->qlock, 761 PCATCH | PDROP, "midi RX", 0); 762 /* 763 * We slept, maybe things have changed since last 764 * dying check 765 */ 766 if (retval == EINTR) 767 goto err0; 768 if (m != i_dev->si_drv1) 769 retval = ENXIO; 770 /* if (retval && retval != ERESTART) */ 771 if (retval) 772 goto err0; 773 mtx_lock(&m->lock); 774 mtx_lock(&m->qlock); 775 m->rchan = 0; 776 if (!m->busy) 777 goto err1; 778 } 779 MIDI_DEBUG(6, printf("midi_read start\n")); 780 /* 781 * At this point, it is certain that m->inq has data 782 */ 783 784 used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid); 785 used = MIN(used, MIDI_RSIZE); 786 787 MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used)); 788 MIDIQ_DEQ(m->inq, buf, used); 789 retval = uiomove(buf, used, uio); 790 if (retval) 791 goto err1; 792 } 793 794 /* 795 * If we Made it here then transfer is good 796 */ 797 retval = 0; 798 err1: mtx_unlock(&m->qlock); 799 mtx_unlock(&m->lock); 800 err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval)); 801 return retval; 802 } 803 804 /* 805 * midi_write: The only setter of M_TXEN 806 */ 807 808 int 809 midi_write(struct cdev *i_dev, struct uio *uio, int ioflag) 810 { 811 #define MIDI_WSIZE 32 812 struct snd_midi *m = i_dev->si_drv1; 813 int retval; 814 int used; 815 char buf[MIDI_WSIZE]; 816 817 818 MIDI_DEBUG(4, printf("midi_write\n")); 819 retval = 0; 820 if (m == NULL) 821 goto err0; 822 823 mtx_lock(&m->lock); 824 mtx_lock(&m->qlock); 825 826 if (!(m->flags & M_TX)) 827 goto err1; 828 829 while (uio->uio_resid > 0) { 830 while (MIDIQ_AVAIL(m->outq) == 0) { 831 retval = EWOULDBLOCK; 832 if (ioflag & O_NONBLOCK) 833 goto err1; 834 mtx_unlock(&m->lock); 835 m->wchan = 1; 836 MIDI_DEBUG(3, printf("midi_write msleep\n")); 837 retval = msleep(&m->wchan, &m->qlock, 838 PCATCH | PDROP, "midi TX", 0); 839 /* 840 * We slept, maybe things have changed since last 841 * dying check 842 */ 843 if (retval == EINTR) 844 goto err0; 845 if (m != i_dev->si_drv1) 846 retval = ENXIO; 847 if (retval) 848 goto err0; 849 mtx_lock(&m->lock); 850 mtx_lock(&m->qlock); 851 m->wchan = 0; 852 if (!m->busy) 853 goto err1; 854 } 855 856 /* 857 * We are certain than data can be placed on the queue 858 */ 859 860 used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid); 861 used = MIN(used, MIDI_WSIZE); 862 MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n", 863 uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq), 864 (intmax_t)MIDIQ_AVAIL(m->outq))); 865 866 867 MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used)); 868 retval = uiomove(buf, used, uio); 869 if (retval) 870 goto err1; 871 MIDIQ_ENQ(m->outq, buf, used); 872 /* 873 * Inform the bottom half that data can be written 874 */ 875 if (!(m->flags & M_TXEN)) { 876 m->flags |= M_TXEN; 877 MPU_CALLBACK(m, m->cookie, m->flags); 878 } 879 } 880 /* 881 * If we Made it here then transfer is good 882 */ 883 retval = 0; 884 err1: mtx_unlock(&m->qlock); 885 mtx_unlock(&m->lock); 886 err0: return retval; 887 } 888 889 int 890 midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, 891 struct thread *td) 892 { 893 return ENXIO; 894 } 895 896 int 897 midi_poll(struct cdev *i_dev, int events, struct thread *td) 898 { 899 struct snd_midi *m = i_dev->si_drv1; 900 int revents; 901 902 if (m == NULL) 903 return 0; 904 905 revents = 0; 906 907 mtx_lock(&m->lock); 908 mtx_lock(&m->qlock); 909 910 if (events & (POLLIN | POLLRDNORM)) 911 if (!MIDIQ_EMPTY(m->inq)) 912 events |= events & (POLLIN | POLLRDNORM); 913 914 if (events & (POLLOUT | POLLWRNORM)) 915 if (MIDIQ_AVAIL(m->outq) < m->hiwat) 916 events |= events & (POLLOUT | POLLWRNORM); 917 918 if (revents == 0) { 919 if (events & (POLLIN | POLLRDNORM)) 920 selrecord(td, &m->rsel); 921 922 if (events & (POLLOUT | POLLWRNORM)) 923 selrecord(td, &m->wsel); 924 } 925 mtx_unlock(&m->lock); 926 mtx_unlock(&m->qlock); 927 928 return (revents); 929 } 930 931 /* 932 * /dev/midistat device functions 933 * 934 */ 935 static int 936 midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td) 937 { 938 int error; 939 940 MIDI_DEBUG(1, printf("midistat_open\n")); 941 942 sx_xlock(&midistat_lock); 943 if (midistat_isopen) { 944 sx_xunlock(&midistat_lock); 945 return EBUSY; 946 } 947 midistat_isopen = 1; 948 if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) { 949 error = ENXIO; 950 goto out; 951 } 952 error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM; 953 out: 954 if (error) 955 midistat_isopen = 0; 956 sx_xunlock(&midistat_lock); 957 return error; 958 } 959 960 static int 961 midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td) 962 { 963 MIDI_DEBUG(1, printf("midistat_close\n")); 964 sx_xlock(&midistat_lock); 965 if (!midistat_isopen) { 966 sx_xunlock(&midistat_lock); 967 return EBADF; 968 } 969 sbuf_delete(&midistat_sbuf); 970 midistat_isopen = 0; 971 sx_xunlock(&midistat_lock); 972 return 0; 973 } 974 975 static int 976 midistat_read(struct cdev *i_dev, struct uio *uio, int flag) 977 { 978 long l; 979 int err; 980 981 MIDI_DEBUG(4, printf("midistat_read\n")); 982 sx_xlock(&midistat_lock); 983 if (!midistat_isopen) { 984 sx_xunlock(&midistat_lock); 985 return EBADF; 986 } 987 if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) { 988 sx_xunlock(&midistat_lock); 989 return EINVAL; 990 } 991 err = 0; 992 l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset); 993 if (l > 0) { 994 err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l, 995 uio); 996 } 997 sx_xunlock(&midistat_lock); 998 return err; 999 } 1000 1001 /* 1002 * Module library functions 1003 */ 1004 1005 static int 1006 midistat_prepare(struct sbuf *s) 1007 { 1008 struct snd_midi *m; 1009 1010 sx_assert(&midistat_lock, SA_XLOCKED); 1011 1012 sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n"); 1013 if (TAILQ_EMPTY(&midi_devs)) { 1014 sbuf_printf(s, "No devices installed.\n"); 1015 sbuf_finish(s); 1016 return sbuf_len(s); 1017 } 1018 sbuf_printf(s, "Installed devices:\n"); 1019 1020 TAILQ_FOREACH(m, &midi_devs, link) { 1021 mtx_lock(&m->lock); 1022 sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel, 1023 MPU_PROVIDER(m, m->cookie)); 1024 sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose)); 1025 sbuf_printf(s, "\n"); 1026 mtx_unlock(&m->lock); 1027 } 1028 1029 sbuf_finish(s); 1030 return sbuf_len(s); 1031 } 1032 1033 #ifdef notdef 1034 /* 1035 * Convert IOCTL command to string for debugging 1036 */ 1037 1038 static char * 1039 midi_cmdname(int cmd) 1040 { 1041 static struct { 1042 int cmd; 1043 char *name; 1044 } *tab, cmdtab_midiioctl[] = { 1045 #define A(x) {x, ## x} 1046 /* 1047 * Once we have some real IOCTLs define, the following will 1048 * be relavant. 1049 * 1050 * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE), 1051 * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO), 1052 * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL), 1053 * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE), 1054 * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE), 1055 * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT), 1056 * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC), 1057 * A(AIOGCAP), 1058 */ 1059 #undef A 1060 { 1061 -1, "unknown" 1062 }, 1063 }; 1064 1065 for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++); 1066 return tab->name; 1067 } 1068 1069 #endif /* notdef */ 1070 1071 /* 1072 * midisynth 1073 */ 1074 1075 1076 int 1077 midisynth_open(void *n, void *arg, int flags) 1078 { 1079 struct snd_midi *m = ((struct synth_midi *)n)->m; 1080 int retval; 1081 1082 MIDI_DEBUG(1, printf("midisynth_open %s %s\n", 1083 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : "")); 1084 1085 if (m == NULL) 1086 return ENXIO; 1087 1088 mtx_lock(&m->lock); 1089 mtx_lock(&m->qlock); 1090 1091 retval = 0; 1092 1093 if (flags & FREAD) { 1094 if (MIDIQ_SIZE(m->inq) == 0) 1095 retval = ENXIO; 1096 else if (m->flags & M_RX) 1097 retval = EBUSY; 1098 if (retval) 1099 goto err; 1100 } 1101 if (flags & FWRITE) { 1102 if (MIDIQ_SIZE(m->outq) == 0) 1103 retval = ENXIO; 1104 else if (m->flags & M_TX) 1105 retval = EBUSY; 1106 if (retval) 1107 goto err; 1108 } 1109 m->busy++; 1110 1111 /* 1112 * TODO: Consider m->async = 0; 1113 */ 1114 1115 if (flags & FREAD) { 1116 m->flags |= M_RX | M_RXEN; 1117 /* 1118 * Only clear the inq, the outq might still have data to drain 1119 * from a previous session 1120 */ 1121 MIDIQ_CLEAR(m->inq); 1122 m->rchan = 0; 1123 } 1124 1125 if (flags & FWRITE) { 1126 m->flags |= M_TX; 1127 m->wchan = 0; 1128 } 1129 m->synth_flags = flags & (FREAD | FWRITE); 1130 1131 MPU_CALLBACK(m, m->cookie, m->flags); 1132 1133 1134 err: mtx_unlock(&m->qlock); 1135 mtx_unlock(&m->lock); 1136 MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval)); 1137 return retval; 1138 } 1139 1140 int 1141 midisynth_close(void *n) 1142 { 1143 struct snd_midi *m = ((struct synth_midi *)n)->m; 1144 int retval; 1145 int oldflags; 1146 1147 MIDI_DEBUG(1, printf("midisynth_close %s %s\n", 1148 m->synth_flags & FREAD ? "M_RX" : "", 1149 m->synth_flags & FWRITE ? "M_TX" : "")); 1150 1151 if (m == NULL) 1152 return ENXIO; 1153 1154 mtx_lock(&m->lock); 1155 mtx_lock(&m->qlock); 1156 1157 if ((m->synth_flags & FREAD && !(m->flags & M_RX)) || 1158 (m->synth_flags & FWRITE && !(m->flags & M_TX))) { 1159 retval = ENXIO; 1160 goto err; 1161 } 1162 m->busy--; 1163 1164 oldflags = m->flags; 1165 1166 if (m->synth_flags & FREAD) 1167 m->flags &= ~(M_RX | M_RXEN); 1168 if (m->synth_flags & FWRITE) 1169 m->flags &= ~M_TX; 1170 1171 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN))) 1172 MPU_CALLBACK(m, m->cookie, m->flags); 1173 1174 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy)); 1175 1176 mtx_unlock(&m->qlock); 1177 mtx_unlock(&m->lock); 1178 retval = 0; 1179 err: return retval; 1180 } 1181 1182 /* 1183 * Always blocking. 1184 */ 1185 1186 int 1187 midisynth_writeraw(void *n, uint8_t *buf, size_t len) 1188 { 1189 struct snd_midi *m = ((struct synth_midi *)n)->m; 1190 int retval; 1191 int used; 1192 int i; 1193 1194 MIDI_DEBUG(4, printf("midisynth_writeraw\n")); 1195 1196 retval = 0; 1197 1198 if (m == NULL) 1199 return ENXIO; 1200 1201 mtx_lock(&m->lock); 1202 mtx_lock(&m->qlock); 1203 1204 if (!(m->flags & M_TX)) 1205 goto err1; 1206 1207 if (midi_dumpraw) 1208 printf("midi dump: "); 1209 1210 while (len > 0) { 1211 while (MIDIQ_AVAIL(m->outq) == 0) { 1212 if (!(m->flags & M_TXEN)) { 1213 m->flags |= M_TXEN; 1214 MPU_CALLBACK(m, m->cookie, m->flags); 1215 } 1216 mtx_unlock(&m->lock); 1217 m->wchan = 1; 1218 MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n")); 1219 retval = msleep(&m->wchan, &m->qlock, 1220 PCATCH | PDROP, "midi TX", 0); 1221 /* 1222 * We slept, maybe things have changed since last 1223 * dying check 1224 */ 1225 if (retval == EINTR) 1226 goto err0; 1227 1228 if (retval) 1229 goto err0; 1230 mtx_lock(&m->lock); 1231 mtx_lock(&m->qlock); 1232 m->wchan = 0; 1233 if (!m->busy) 1234 goto err1; 1235 } 1236 1237 /* 1238 * We are certain than data can be placed on the queue 1239 */ 1240 1241 used = MIN(MIDIQ_AVAIL(m->outq), len); 1242 used = MIN(used, MIDI_WSIZE); 1243 MIDI_DEBUG(5, 1244 printf("midi_synth: resid %zu len %jd avail %jd\n", 1245 len, (intmax_t)MIDIQ_LEN(m->outq), 1246 (intmax_t)MIDIQ_AVAIL(m->outq))); 1247 1248 if (midi_dumpraw) 1249 for (i = 0; i < used; i++) 1250 printf("%x ", buf[i]); 1251 1252 MIDIQ_ENQ(m->outq, buf, used); 1253 len -= used; 1254 1255 /* 1256 * Inform the bottom half that data can be written 1257 */ 1258 if (!(m->flags & M_TXEN)) { 1259 m->flags |= M_TXEN; 1260 MPU_CALLBACK(m, m->cookie, m->flags); 1261 } 1262 } 1263 /* 1264 * If we Made it here then transfer is good 1265 */ 1266 if (midi_dumpraw) 1267 printf("\n"); 1268 1269 retval = 0; 1270 err1: mtx_unlock(&m->qlock); 1271 mtx_unlock(&m->lock); 1272 err0: return retval; 1273 } 1274 1275 static int 1276 midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1277 { 1278 u_char c[3]; 1279 1280 1281 if (note > 127 || chn > 15) 1282 return (EINVAL); 1283 1284 if (vel > 127) 1285 vel = 127; 1286 1287 if (vel == 64) { 1288 c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1289 c[1] = (u_char)note; 1290 c[2] = 0; 1291 } else { 1292 c[0] = 0x80 | (chn & 0x0f); /* Note off. */ 1293 c[1] = (u_char)note; 1294 c[2] = (u_char)vel; 1295 } 1296 1297 return midisynth_writeraw(n, c, 3); 1298 } 1299 1300 static int 1301 midisynth_setinstr(void *n, uint8_t chn, uint16_t instr) 1302 { 1303 u_char c[2]; 1304 1305 if (instr > 127 || chn > 15) 1306 return EINVAL; 1307 1308 c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */ 1309 c[1] = instr + midi_instroff; 1310 1311 return midisynth_writeraw(n, c, 2); 1312 } 1313 1314 static int 1315 midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel) 1316 { 1317 u_char c[3]; 1318 1319 if (note > 127 || chn > 15) 1320 return EINVAL; 1321 1322 if (vel > 127) 1323 vel = 127; 1324 1325 c[0] = 0x90 | (chn & 0x0f); /* Note on. */ 1326 c[1] = (u_char)note; 1327 c[2] = (u_char)vel; 1328 1329 return midisynth_writeraw(n, c, 3); 1330 } 1331 static int 1332 midisynth_alloc(void *n, uint8_t chan, uint8_t note) 1333 { 1334 return chan; 1335 } 1336 1337 static int 1338 midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val) 1339 { 1340 u_char c[3]; 1341 1342 if (ctrlnum > 127 || chn > 15) 1343 return EINVAL; 1344 1345 c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */ 1346 c[1] = ctrlnum; 1347 c[2] = val; 1348 return midisynth_writeraw(n, c, 3); 1349 } 1350 1351 static int 1352 midisynth_bender(void *n, uint8_t chn, uint16_t val) 1353 { 1354 u_char c[3]; 1355 1356 1357 if (val > 16383 || chn > 15) 1358 return EINVAL; 1359 1360 c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */ 1361 c[1] = (u_char)val & 0x7f; 1362 c[2] = (u_char)(val >> 7) & 0x7f; 1363 1364 return midisynth_writeraw(n, c, 3); 1365 } 1366 1367 /* 1368 * Single point of midi destructions. 1369 */ 1370 static int 1371 midi_destroy(struct snd_midi *m, int midiuninit) 1372 { 1373 sx_assert(&midistat_lock, SA_XLOCKED); 1374 mtx_assert(&m->lock, MA_OWNED); 1375 1376 MIDI_DEBUG(3, printf("midi_destroy\n")); 1377 m->dev->si_drv1 = NULL; 1378 mtx_unlock(&m->lock); /* XXX */ 1379 destroy_dev(m->dev); 1380 TAILQ_REMOVE(&midi_devs, m, link); 1381 if (midiuninit) 1382 MPU_UNINIT(m, m->cookie); 1383 free(MIDIQ_BUF(m->inq), M_MIDI); 1384 free(MIDIQ_BUF(m->outq), M_MIDI); 1385 mtx_destroy(&m->qlock); 1386 mtx_destroy(&m->lock); 1387 free(m->synth, M_MIDI); 1388 free(m, M_MIDI); 1389 return 0; 1390 } 1391 1392 /* 1393 * Load and unload functions, creates the /dev/midistat device 1394 */ 1395 1396 static int 1397 midi_load(void) 1398 { 1399 sx_init(&midistat_lock, "midistat lock"); 1400 TAILQ_INIT(&midi_devs); 1401 1402 midistat_dev = make_dev(&midistat_cdevsw, 1403 MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0), 1404 UID_ROOT, GID_WHEEL, 0666, "midistat"); 1405 1406 return 0; 1407 } 1408 1409 static int 1410 midi_unload(void) 1411 { 1412 struct snd_midi *m, *tmp; 1413 int retval; 1414 1415 MIDI_DEBUG(1, printf("midi_unload()\n")); 1416 retval = EBUSY; 1417 sx_xlock(&midistat_lock); 1418 if (midistat_isopen) 1419 goto exit0; 1420 1421 TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) { 1422 mtx_lock(&m->lock); 1423 if (m->busy) 1424 retval = EBUSY; 1425 else 1426 retval = midi_destroy(m, 1); 1427 if (retval) 1428 goto exit1; 1429 } 1430 sx_xunlock(&midistat_lock); 1431 destroy_dev(midistat_dev); 1432 1433 /* 1434 * Made it here then unload is complete 1435 */ 1436 sx_destroy(&midistat_lock); 1437 return 0; 1438 1439 exit1: 1440 mtx_unlock(&m->lock); 1441 exit0: 1442 sx_xunlock(&midistat_lock); 1443 if (retval) 1444 MIDI_DEBUG(2, printf("midi_unload: failed\n")); 1445 return retval; 1446 } 1447 1448 extern int seq_modevent(module_t mod, int type, void *data); 1449 1450 static int 1451 midi_modevent(module_t mod, int type, void *data) 1452 { 1453 int retval; 1454 1455 retval = 0; 1456 1457 switch (type) { 1458 case MOD_LOAD: 1459 retval = midi_load(); 1460 if (retval == 0) 1461 retval = seq_modevent(mod, type, data); 1462 break; 1463 1464 case MOD_UNLOAD: 1465 retval = midi_unload(); 1466 if (retval == 0) 1467 retval = seq_modevent(mod, type, data); 1468 break; 1469 1470 default: 1471 break; 1472 } 1473 1474 return retval; 1475 } 1476 1477 kobj_t 1478 midimapper_addseq(void *arg1, int *unit, void **cookie) 1479 { 1480 unit = NULL; 1481 1482 return (kobj_t)arg1; 1483 } 1484 1485 int 1486 midimapper_open(void *arg1, void **cookie) 1487 { 1488 int retval = 0; 1489 struct snd_midi *m; 1490 1491 sx_xlock(&midistat_lock); 1492 TAILQ_FOREACH(m, &midi_devs, link) { 1493 retval++; 1494 } 1495 sx_xunlock(&midistat_lock); 1496 return retval; 1497 } 1498 1499 int 1500 midimapper_close(void *arg1, void *cookie) 1501 { 1502 return 0; 1503 } 1504 1505 kobj_t 1506 midimapper_fetch_synth(void *arg, void *cookie, int unit) 1507 { 1508 struct snd_midi *m; 1509 int retval = 0; 1510 1511 sx_xlock(&midistat_lock); 1512 TAILQ_FOREACH(m, &midi_devs, link) { 1513 if (unit == retval) { 1514 sx_xunlock(&midistat_lock); 1515 return (kobj_t)m->synth; 1516 } 1517 retval++; 1518 } 1519 sx_xunlock(&midistat_lock); 1520 return NULL; 1521 } 1522 1523 DEV_MODULE(midi, midi_modevent, NULL); 1524 MODULE_VERSION(midi, 1); 1525