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