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