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