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