1 /* $NetBSD: midi.c,v 1.24 2002/06/01 17:54:21 gson Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (augustss@netbsd.org). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.24 2002/06/01 17:54:21 gson Exp $"); 41 42 #include "midi.h" 43 #include "sequencer.h" 44 45 #include <sys/param.h> 46 #include <sys/ioctl.h> 47 #include <sys/fcntl.h> 48 #include <sys/vnode.h> 49 #include <sys/select.h> 50 #include <sys/poll.h> 51 #include <sys/malloc.h> 52 #include <sys/proc.h> 53 #include <sys/systm.h> 54 #include <sys/callout.h> 55 #include <sys/syslog.h> 56 #include <sys/kernel.h> 57 #include <sys/signalvar.h> 58 #include <sys/conf.h> 59 #include <sys/audioio.h> 60 #include <sys/midiio.h> 61 #include <sys/device.h> 62 63 #include <dev/audio_if.h> 64 #include <dev/midi_if.h> 65 #include <dev/midivar.h> 66 67 #if NMIDI > 0 68 69 #ifdef AUDIO_DEBUG 70 #define DPRINTF(x) if (mididebug) printf x 71 #define DPRINTFN(n,x) if (mididebug >= (n)) printf x 72 int mididebug = 0; 73 #else 74 #define DPRINTF(x) 75 #define DPRINTFN(n,x) 76 #endif 77 78 int midi_wait; 79 80 void midi_in(void *, int); 81 void midi_out(void *); 82 int midi_start_output(struct midi_softc *, int); 83 int midi_sleep_timo(int *, char *, int); 84 int midi_sleep(int *, char *); 85 void midi_wakeup(int *); 86 void midi_initbuf(struct midi_buffer *); 87 void midi_timeout(void *); 88 89 int midiprobe(struct device *, struct cfdata *, void *); 90 void midiattach(struct device *, struct device *, void *); 91 int mididetach(struct device *, int); 92 int midiactivate(struct device *, enum devact); 93 94 struct cfattach midi_ca = { 95 sizeof(struct midi_softc), midiprobe, midiattach, 96 mididetach, midiactivate 97 }; 98 99 #ifdef MIDI_SAVE 100 #define MIDI_SAVE_SIZE 100000 101 int midicnt; 102 struct { 103 int cnt; 104 u_char buf[MIDI_SAVE_SIZE]; 105 } midisave; 106 #define MIDI_GETSAVE _IOWR('m', 100, int) 107 108 #endif 109 110 extern struct cfdriver midi_cd; 111 112 int 113 midiprobe(struct device *parent, struct cfdata *match, void *aux) 114 { 115 struct audio_attach_args *sa = aux; 116 117 DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n", 118 sa->type, sa, sa->hwif)); 119 return (sa->type == AUDIODEV_TYPE_MIDI); 120 } 121 122 void 123 midiattach(struct device *parent, struct device *self, void *aux) 124 { 125 struct midi_softc *sc = (void *)self; 126 struct audio_attach_args *sa = aux; 127 struct midi_hw_if *hwp = sa->hwif; 128 void *hdlp = sa->hdl; 129 130 DPRINTFN(6, ("MIDI attach\n")); 131 132 #ifdef DIAGNOSTIC 133 if (hwp == 0 || 134 hwp->open == 0 || 135 hwp->close == 0 || 136 hwp->output == 0 || 137 hwp->getinfo == 0) { 138 printf("midi: missing method\n"); 139 return; 140 } 141 #endif 142 143 callout_init(&sc->sc_callout); 144 145 sc->hw_if = hwp; 146 sc->hw_hdl = hdlp; 147 sc->dying = 0; 148 midi_attach(sc, parent); 149 } 150 151 int 152 midiactivate(struct device *self, enum devact act) 153 { 154 struct midi_softc *sc = (struct midi_softc *)self; 155 156 switch (act) { 157 case DVACT_ACTIVATE: 158 return (EOPNOTSUPP); 159 break; 160 161 case DVACT_DEACTIVATE: 162 sc->dying = 1; 163 break; 164 } 165 return (0); 166 } 167 168 int 169 mididetach(struct device *self, int flags) 170 { 171 struct midi_softc *sc = (struct midi_softc *)self; 172 int maj, mn; 173 174 DPRINTF(("midi_detach: sc=%p flags=%d\n", sc, flags)); 175 176 sc->dying = 1; 177 178 wakeup(&sc->wchan); 179 wakeup(&sc->rchan); 180 181 /* locate the major number */ 182 for (maj = 0; maj < nchrdev; maj++) 183 if (cdevsw[maj].d_open == midiopen) 184 break; 185 186 /* Nuke the vnodes for any open instances (calls close). */ 187 mn = self->dv_unit; 188 vdevgone(maj, mn, mn, VCHR); 189 190 return (0); 191 } 192 193 void 194 midi_attach(struct midi_softc *sc, struct device *parent) 195 { 196 struct midi_info mi; 197 198 sc->isopen = 0; 199 200 midi_wait = MIDI_WAIT * hz / 1000000; 201 if (midi_wait == 0) 202 midi_wait = 1; 203 204 sc->sc_dev = parent; 205 sc->hw_if->getinfo(sc->hw_hdl, &mi); 206 sc->props = mi.props; 207 printf(": %s\n", mi.name); 208 } 209 210 int 211 midi_unit_count(void) 212 { 213 return midi_cd.cd_ndevs; 214 } 215 216 void 217 midi_initbuf(struct midi_buffer *mb) 218 { 219 mb->used = 0; 220 mb->usedhigh = MIDI_BUFSIZE; 221 mb->end = mb->start + mb->usedhigh; 222 mb->inp = mb->outp = mb->start; 223 } 224 225 int 226 midi_sleep_timo(int *chan, char *label, int timo) 227 { 228 int st; 229 230 if (!label) 231 label = "midi"; 232 233 DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo)); 234 *chan = 1; 235 st = tsleep(chan, PWAIT | PCATCH, label, timo); 236 *chan = 0; 237 #ifdef MIDI_DEBUG 238 if (st != 0) 239 printf("midi_sleep: %d\n", st); 240 #endif 241 return st; 242 } 243 244 int 245 midi_sleep(int *chan, char *label) 246 { 247 return midi_sleep_timo(chan, label, 0); 248 } 249 250 void 251 midi_wakeup(int *chan) 252 { 253 if (*chan) { 254 DPRINTFN(5, ("midi_wakeup: %p\n", chan)); 255 wakeup(chan); 256 *chan = 0; 257 } 258 } 259 260 static int midi_lengths[] = { 2,2,2,2,1,1,2,0 }; 261 /* Number of bytes in a MIDI command */ 262 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7]) 263 264 void 265 midi_in(void *addr, int data) 266 { 267 struct midi_softc *sc = addr; 268 struct midi_buffer *mb = &sc->inbuf; 269 int i; 270 271 if (!sc->isopen) 272 return; 273 if (data == MIDI_ACK) 274 return; 275 276 DPRINTFN(3, ("midi_in: sc=%p data=0x%02x state=%d pos=%d\n", 277 sc, data, sc->in_state, sc->in_pos)); 278 279 if (!(sc->flags & FREAD)) 280 return; /* discard data if not reading */ 281 282 switch(sc->in_state) { 283 case MIDI_IN_START: 284 if (MIDI_IS_STATUS(data)) { 285 switch(data) { 286 case 0xf0: /* Sysex */ 287 sc->in_state = MIDI_IN_SYSEX; 288 break; 289 case 0xf1: /* MTC quarter frame */ 290 case 0xf3: /* Song select */ 291 sc->in_state = MIDI_IN_DATA; 292 sc->in_msg[0] = data; 293 sc->in_pos = 1; 294 sc->in_left = 1; 295 break; 296 case 0xf2: /* Song position pointer */ 297 sc->in_state = MIDI_IN_DATA; 298 sc->in_msg[0] = data; 299 sc->in_pos = 1; 300 sc->in_left = 2; 301 break; 302 default: 303 if (MIDI_IS_COMMON(data)) { 304 sc->in_msg[0] = data; 305 sc->in_pos = 1; 306 goto deliver; 307 } else { 308 sc->in_state = MIDI_IN_DATA; 309 sc->in_msg[0] = sc->in_status = data; 310 sc->in_pos = 1; 311 sc->in_left = MIDI_LENGTH(data); 312 } 313 break; 314 } 315 } else { 316 if (MIDI_IS_STATUS(sc->in_status)) { 317 sc->in_state = MIDI_IN_DATA; 318 sc->in_msg[0] = sc->in_status; 319 sc->in_msg[1] = data; 320 sc->in_pos = 2; 321 sc->in_left = MIDI_LENGTH(sc->in_status) - 1; 322 } 323 } 324 return; 325 case MIDI_IN_DATA: 326 sc->in_msg[sc->in_pos++] = data; 327 if (--sc->in_left <= 0) 328 break; /* deliver data */ 329 return; 330 case MIDI_IN_SYSEX: 331 if (data == MIDI_SYSEX_END) 332 sc->in_state = MIDI_IN_START; 333 return; 334 } 335 deliver: 336 sc->in_state = MIDI_IN_START; 337 #if NSEQUENCER > 0 338 if (sc->seqopen) { 339 extern void midiseq_in(struct midi_dev *,u_char *,int); 340 midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos); 341 return; 342 } 343 #endif 344 345 if (mb->used + sc->in_pos > mb->usedhigh) { 346 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n", 347 sc->in_msg[0])); 348 return; 349 } 350 for (i = 0; i < sc->in_pos; i++) { 351 *mb->inp++ = sc->in_msg[i]; 352 if (mb->inp >= mb->end) 353 mb->inp = mb->start; 354 mb->used++; 355 } 356 midi_wakeup(&sc->rchan); 357 selwakeup(&sc->rsel); 358 if (sc->async) 359 psignal(sc->async, SIGIO); 360 } 361 362 void 363 midi_out(void *addr) 364 { 365 struct midi_softc *sc = addr; 366 367 if (!sc->isopen) 368 return; 369 DPRINTFN(3, ("midi_out: %p\n", sc)); 370 midi_start_output(sc, 1); 371 } 372 373 int 374 midiopen(dev_t dev, int flags, int ifmt, struct proc *p) 375 { 376 struct midi_softc *sc; 377 struct midi_hw_if *hw; 378 int error; 379 380 sc = device_lookup(&midi_cd, MIDIUNIT(dev)); 381 if (sc == NULL) 382 return (ENXIO); 383 if (sc->dying) 384 return (EIO); 385 386 DPRINTF(("midiopen %p\n", sc)); 387 388 hw = sc->hw_if; 389 if (!hw) 390 return ENXIO; 391 if (sc->isopen) 392 return EBUSY; 393 sc->in_state = MIDI_IN_START; 394 sc->in_status = 0; 395 error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc); 396 if (error) 397 return error; 398 sc->isopen++; 399 midi_initbuf(&sc->outbuf); 400 midi_initbuf(&sc->inbuf); 401 sc->flags = flags; 402 sc->rchan = 0; 403 sc->wchan = 0; 404 sc->pbus = 0; 405 sc->async = 0; 406 407 #ifdef MIDI_SAVE 408 if (midicnt != 0) { 409 midisave.cnt = midicnt; 410 midicnt = 0; 411 } 412 #endif 413 414 return 0; 415 } 416 417 int 418 midiclose(dev_t dev, int flags, int ifmt, struct proc *p) 419 { 420 int unit = MIDIUNIT(dev); 421 struct midi_softc *sc = midi_cd.cd_devs[unit]; 422 struct midi_hw_if *hw = sc->hw_if; 423 int s, error; 424 425 DPRINTF(("midiclose %p\n", sc)); 426 427 midi_start_output(sc, 0); 428 error = 0; 429 s = splaudio(); 430 while (sc->outbuf.used > 0 && !error) { 431 DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used)); 432 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz); 433 } 434 splx(s); 435 sc->isopen = 0; 436 hw->close(sc->hw_hdl); 437 #if NSEQUENCER > 0 438 sc->seqopen = 0; 439 sc->seq_md = 0; 440 #endif 441 return 0; 442 } 443 444 int 445 midiread(dev_t dev, struct uio *uio, int ioflag) 446 { 447 int unit = MIDIUNIT(dev); 448 struct midi_softc *sc = midi_cd.cd_devs[unit]; 449 struct midi_buffer *mb = &sc->inbuf; 450 int error; 451 u_char *outp; 452 int used, cc, n, resid; 453 int s; 454 455 DPRINTF(("midiread: %p, count=%lu\n", sc, 456 (unsigned long)uio->uio_resid)); 457 458 if (sc->dying) 459 return EIO; 460 461 error = 0; 462 resid = uio->uio_resid; 463 while (uio->uio_resid == resid && !error) { 464 s = splaudio(); 465 while (mb->used <= 0) { 466 if (ioflag & IO_NDELAY) { 467 splx(s); 468 return EWOULDBLOCK; 469 } 470 error = midi_sleep(&sc->rchan, "mid rd"); 471 if (error) { 472 splx(s); 473 return error; 474 } 475 } 476 used = mb->used; 477 outp = mb->outp; 478 splx(s); 479 if (sc->dying) 480 return EIO; 481 cc = used; /* maximum to read */ 482 n = mb->end - outp; 483 if (n < cc) 484 cc = n; /* don't read beyond end of buffer */ 485 if (uio->uio_resid < cc) 486 cc = uio->uio_resid; /* and no more than we want */ 487 DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc)); 488 error = uiomove(outp, cc, uio); 489 if (error) 490 break; 491 used -= cc; 492 outp += cc; 493 if (outp >= mb->end) 494 outp = mb->start; 495 s = splaudio(); 496 mb->outp = outp; 497 mb->used = used; 498 splx(s); 499 } 500 return error; 501 } 502 503 void 504 midi_timeout(void *arg) 505 { 506 struct midi_softc *sc = arg; 507 508 DPRINTFN(3,("midi_timeout: %p\n", sc)); 509 midi_start_output(sc, 1); 510 } 511 512 int 513 midi_start_output(struct midi_softc *sc, int intr) 514 { 515 struct midi_buffer *mb = &sc->outbuf; 516 u_char out; 517 int error; 518 int s; 519 int i; 520 521 error = 0; 522 523 if (sc->dying) 524 return EIO; 525 526 if (sc->pbus && !intr) { 527 DPRINTFN(4, ("midi_start_output: busy\n")); 528 return 0; 529 } 530 sc->pbus = (mb->used > 0)?1:0; 531 for (i = 0; i < MIDI_MAX_WRITE && mb->used > 0 && 532 (!error || error==EINPROGRESS); i++) { 533 s = splaudio(); 534 out = *mb->outp; 535 mb->outp++; 536 if (mb->outp >= mb->end) 537 mb->outp = mb->start; 538 mb->used--; 539 splx(s); 540 #ifdef MIDI_SAVE 541 midisave.buf[midicnt] = out; 542 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE; 543 #endif 544 DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n", 545 sc, i, out)); 546 error = sc->hw_if->output(sc->hw_hdl, out); 547 if ((sc->props & MIDI_PROP_OUT_INTR) && error!=EINPROGRESS) 548 /* If ointr is enabled, midi_start_output() 549 * normally writes only one byte, 550 * except hw_if->output() returns EINPROGRESS. 551 */ 552 break; 553 } 554 midi_wakeup(&sc->wchan); 555 selwakeup(&sc->wsel); 556 if (sc->async) 557 psignal(sc->async, SIGIO); 558 if (!(sc->props & MIDI_PROP_OUT_INTR) || error==EINPROGRESS) { 559 if (mb->used > 0) 560 callout_reset(&sc->sc_callout, midi_wait, 561 midi_timeout, sc); 562 else 563 sc->pbus = 0; 564 } 565 if ((sc->props & MIDI_PROP_OUT_INTR) && error==EINPROGRESS) 566 error = 0; 567 568 return error; 569 } 570 571 int 572 midiwrite(dev_t dev, struct uio *uio, int ioflag) 573 { 574 int unit = MIDIUNIT(dev); 575 struct midi_softc *sc = midi_cd.cd_devs[unit]; 576 struct midi_buffer *mb = &sc->outbuf; 577 int error; 578 u_char *inp; 579 int used, cc, n; 580 int s; 581 582 DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit, 583 (unsigned long)uio->uio_resid)); 584 585 if (sc->dying) 586 return EIO; 587 588 error = 0; 589 while (uio->uio_resid > 0 && !error) { 590 s = splaudio(); 591 if (mb->used >= mb->usedhigh) { 592 DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n", 593 mb->used, mb->usedhigh)); 594 if (ioflag & IO_NDELAY) { 595 splx(s); 596 return EWOULDBLOCK; 597 } 598 error = midi_sleep(&sc->wchan, "mid wr"); 599 if (error) { 600 splx(s); 601 return error; 602 } 603 } 604 used = mb->used; 605 inp = mb->inp; 606 splx(s); 607 if (sc->dying) 608 return EIO; 609 cc = mb->usedhigh - used; /* maximum to write */ 610 n = mb->end - inp; 611 if (n < cc) 612 cc = n; /* don't write beyond end of buffer */ 613 if (uio->uio_resid < cc) 614 cc = uio->uio_resid; /* and no more than we have */ 615 error = uiomove(inp, cc, uio); 616 #ifdef MIDI_DEBUG 617 if (error) 618 printf("midi_write:(1) uiomove failed %d; " 619 "cc=%d inp=%p\n", 620 error, cc, inp); 621 #endif 622 if (error) 623 break; 624 inp = mb->inp + cc; 625 if (inp >= mb->end) 626 inp = mb->start; 627 s = splaudio(); 628 mb->inp = inp; 629 mb->used += cc; 630 splx(s); 631 error = midi_start_output(sc, 0); 632 } 633 return error; 634 } 635 636 /* 637 * This write routine is only called from sequencer code and expects 638 * a write that is smaller than the MIDI buffer. 639 */ 640 int 641 midi_writebytes(int unit, u_char *buf, int cc) 642 { 643 struct midi_softc *sc = midi_cd.cd_devs[unit]; 644 struct midi_buffer *mb = &sc->outbuf; 645 int n, s; 646 647 DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc)); 648 DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2])); 649 650 if (sc->dying) 651 return EIO; 652 653 s = splaudio(); 654 if (mb->used + cc >= mb->usedhigh) { 655 splx(s); 656 return (EWOULDBLOCK); 657 } 658 n = mb->end - mb->inp; 659 if (cc < n) 660 n = cc; 661 mb->used += cc; 662 memcpy(mb->inp, buf, n); 663 mb->inp += n; 664 if (mb->inp >= mb->end) { 665 mb->inp = mb->start; 666 cc -= n; 667 if (cc > 0) { 668 memcpy(mb->inp, buf + n, cc); 669 mb->inp += cc; 670 } 671 } 672 splx(s); 673 return (midi_start_output(sc, 0)); 674 } 675 676 int 677 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 678 { 679 int unit = MIDIUNIT(dev); 680 struct midi_softc *sc = midi_cd.cd_devs[unit]; 681 struct midi_hw_if *hw = sc->hw_if; 682 int error; 683 684 DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd)); 685 686 if (sc->dying) 687 return EIO; 688 689 error = 0; 690 switch (cmd) { 691 case FIONBIO: 692 /* All handled in the upper FS layer. */ 693 break; 694 695 case FIOASYNC: 696 if (*(int *)addr) { 697 if (sc->async) 698 return EBUSY; 699 sc->async = p; 700 DPRINTF(("midi_ioctl: FIOASYNC %p\n", p)); 701 } else 702 sc->async = 0; 703 break; 704 705 #if 0 706 case MIDI_PRETIME: 707 /* XXX OSS 708 * This should set up a read timeout, but that's 709 * why we have poll(), so there's nothing yet. */ 710 error = EINVAL; 711 break; 712 #endif 713 714 #ifdef MIDI_SAVE 715 case MIDI_GETSAVE: 716 error = copyout(&midisave, *(void **)addr, sizeof midisave); 717 break; 718 #endif 719 720 default: 721 if (hw->ioctl) 722 error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p); 723 else 724 error = EINVAL; 725 break; 726 } 727 return error; 728 } 729 730 int 731 midipoll(dev_t dev, int events, struct proc *p) 732 { 733 int unit = MIDIUNIT(dev); 734 struct midi_softc *sc = midi_cd.cd_devs[unit]; 735 int revents = 0; 736 int s; 737 738 DPRINTF(("midipoll: %p events=0x%x\n", sc, events)); 739 740 if (sc->dying) 741 return EIO; 742 743 s = splaudio(); 744 745 if (events & (POLLIN | POLLRDNORM)) 746 if (sc->inbuf.used > 0) 747 revents |= events & (POLLIN | POLLRDNORM); 748 749 if (events & (POLLOUT | POLLWRNORM)) 750 if (sc->outbuf.used < sc->outbuf.usedhigh) 751 revents |= events & (POLLOUT | POLLWRNORM); 752 753 if (revents == 0) { 754 if (events & (POLLIN | POLLRDNORM)) 755 selrecord(p, &sc->rsel); 756 757 if (events & (POLLOUT | POLLWRNORM)) 758 selrecord(p, &sc->wsel); 759 } 760 761 splx(s); 762 return revents; 763 } 764 765 void 766 midi_getinfo(dev_t dev, struct midi_info *mi) 767 { 768 struct midi_softc *sc; 769 770 sc = device_lookup(&midi_cd, MIDIUNIT(dev)); 771 if (sc == NULL) 772 return; 773 if (sc->dying) 774 return; 775 776 sc->hw_if->getinfo(sc->hw_hdl, mi); 777 } 778 779 #endif /* NMIDI > 0 */ 780 781 #if NMIDI > 0 || NMIDIBUS > 0 782 783 int audioprint(void *, const char *); 784 785 struct device * 786 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev) 787 { 788 struct audio_attach_args arg; 789 790 #ifdef DIAGNOSTIC 791 if (mhwp == NULL) { 792 printf("midi_attach_mi: NULL\n"); 793 return (0); 794 } 795 #endif 796 arg.type = AUDIODEV_TYPE_MIDI; 797 arg.hwif = mhwp; 798 arg.hdl = hdlp; 799 return (config_found(dev, &arg, audioprint)); 800 } 801 802 #endif /* NMIDI > 0 || NMIDIBUS > 0 */ 803