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