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