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