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