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