Annotation of sys/dev/midi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: midi.c,v 1.16 2006/12/21 02:28:47 krw Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2003, 2004 Alexandre Ratchov
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * TODO
! 21: * - put the sequencer stuff in sequencer.c and sequencervar.h
! 22: * there is no reason to have it here. The sequencer
! 23: * driver need only to open the midi hw_if thus it does not
! 24: * need this driver
! 25: */
! 26:
! 27: #include "midi.h"
! 28: #include "sequencer.h"
! 29: #if NMIDI > 0
! 30:
! 31: #include <sys/param.h>
! 32: #include <sys/fcntl.h>
! 33: #include <sys/systm.h>
! 34: #include <sys/ioctl.h>
! 35: #include <sys/exec.h>
! 36: #include <sys/conf.h>
! 37: #include <sys/lkm.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/poll.h>
! 40: #include <sys/kernel.h>
! 41: #include <sys/timeout.h>
! 42: #include <sys/vnode.h>
! 43: #include <sys/signalvar.h>
! 44: #include <sys/malloc.h>
! 45: #include <sys/device.h>
! 46:
! 47: #include <dev/midi_if.h>
! 48: #include <dev/audio_if.h>
! 49: #include <dev/midivar.h>
! 50:
! 51:
! 52: int midiopen(dev_t, int, int, struct proc *);
! 53: int midiclose(dev_t, int, int, struct proc *);
! 54: int midiread(dev_t, struct uio *, int);
! 55: int midiwrite(dev_t, struct uio *, int);
! 56: int midipoll(dev_t, int, struct proc *);
! 57: int midiioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 58: int midiprobe(struct device *, void *, void *);
! 59: void midiattach(struct device *, struct device *, void *);
! 60: int mididetach(struct device *, int);
! 61: int midiprint(void *, const char *);
! 62:
! 63: void midi_iintr(void *, int);
! 64: void midi_ointr(void *);
! 65: void midi_out_start(struct midi_softc *);
! 66: void midi_out_stop(struct midi_softc *);
! 67: void midi_out_do(struct midi_softc *);
! 68: void midi_attach(struct midi_softc *, struct device *);
! 69:
! 70:
! 71: #if NSEQUENCER > 0
! 72: int midi_unit_count(void);
! 73: struct midi_hw_if *midi_get_hwif(int);
! 74: void midi_toevent(struct midi_softc *, int);
! 75: int midi_writebytes(int, u_char *, int);
! 76: void midiseq_in(struct midi_dev *, u_char *, int);
! 77: #endif
! 78:
! 79: struct cfattach midi_ca = {
! 80: sizeof(struct midi_softc), midiprobe, midiattach, mididetach
! 81: };
! 82:
! 83: struct cfdriver midi_cd = {
! 84: NULL, "midi", DV_DULL
! 85: };
! 86:
! 87:
! 88: void
! 89: midi_iintr(void *addr, int data)
! 90: {
! 91: struct midi_softc *sc = (struct midi_softc *)addr;
! 92: struct midi_buffer *mb = &sc->inbuf;
! 93:
! 94: if (sc->isdying || !sc->isopen || !(sc->flags & FREAD)) return;
! 95:
! 96: #if NSEQUENCER > 0
! 97: if (sc->seqopen) {
! 98: midi_toevent(sc, data);
! 99: return;
! 100: }
! 101: #endif
! 102: if (MIDIBUF_ISFULL(mb))
! 103: return; /* discard data */
! 104: if (MIDIBUF_ISEMPTY(mb)) {
! 105: if (sc->rchan) {
! 106: sc->rchan = 0;
! 107: wakeup(&sc->rchan);
! 108: }
! 109: selwakeup(&sc->rsel);
! 110: if (sc->async)
! 111: psignal(sc->async, SIGIO);
! 112: }
! 113: MIDIBUF_WRITE(mb, data);
! 114: }
! 115:
! 116:
! 117: int
! 118: midiread(dev_t dev, struct uio *uio, int ioflag)
! 119: {
! 120: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 121: struct midi_buffer *mb = &sc->inbuf;
! 122: unsigned count;
! 123: int s, error;
! 124:
! 125: if (!(sc->flags & FREAD))
! 126: return ENXIO;
! 127:
! 128: /* if there is no data then sleep (unless IO_NDELAY flag is set) */
! 129:
! 130: s = splaudio();
! 131: while(MIDIBUF_ISEMPTY(mb)) {
! 132: if (sc->isdying) {
! 133: splx(s);
! 134: return EIO;
! 135: }
! 136: if (ioflag & IO_NDELAY) {
! 137: splx(s);
! 138: return EWOULDBLOCK;
! 139: }
! 140: sc->rchan = 1;
! 141: error = tsleep(&sc->rchan, PWAIT|PCATCH, "mid_rd", 0);
! 142: if (error) {
! 143: splx(s);
! 144: return error;
! 145: }
! 146: }
! 147:
! 148: /* at this stage, there is at least 1 byte */
! 149:
! 150: while (uio->uio_resid > 0 && mb->used > 0) {
! 151: count = MIDIBUF_SIZE - mb->start;
! 152: if (count > mb->used)
! 153: count = mb->used;
! 154: if (count > uio->uio_resid)
! 155: count = uio->uio_resid;
! 156: error = uiomove(mb->data + mb->start, count, uio);
! 157: if (error) {
! 158: splx(s);
! 159: return error;
! 160: }
! 161: MIDIBUF_REMOVE(mb, count);
! 162: }
! 163: splx(s);
! 164: return 0;
! 165: }
! 166:
! 167:
! 168: void
! 169: midi_ointr(void *addr)
! 170: {
! 171: struct midi_softc *sc = (struct midi_softc *)addr;
! 172: struct midi_buffer *mb;
! 173: int s;
! 174:
! 175: if (sc->isopen && !sc->isdying) {
! 176: #ifdef MIDI_DEBUG
! 177: if (!sc->isbusy) {
! 178: printf("midi_ointr: output should be busy\n");
! 179: }
! 180: #endif
! 181: mb = &sc->outbuf;
! 182: s = splaudio();
! 183: if (mb->used == 0)
! 184: midi_out_stop(sc);
! 185: else
! 186: midi_out_do(sc); /* restart output */
! 187: splx(s);
! 188: }
! 189: }
! 190:
! 191:
! 192: void
! 193: midi_out_start(struct midi_softc *sc)
! 194: {
! 195: if (!sc->isbusy) {
! 196: sc->isbusy = 1;
! 197: midi_out_do(sc);
! 198: }
! 199: }
! 200:
! 201: void
! 202: midi_out_stop(struct midi_softc *sc)
! 203: {
! 204: sc->isbusy = 0;
! 205: if (sc->wchan) {
! 206: sc->wchan = 0;
! 207: wakeup(&sc->wchan);
! 208: }
! 209: selwakeup(&sc->wsel);
! 210: if (sc->async)
! 211: psignal(sc->async, SIGIO);
! 212: }
! 213:
! 214:
! 215: /*
! 216: * drain output buffer, must be called with
! 217: * interrupts disabled
! 218: */
! 219: void
! 220: midi_out_do(struct midi_softc *sc)
! 221: {
! 222: struct midi_buffer *mb = &sc->outbuf;
! 223: unsigned i, max;
! 224: int error;
! 225:
! 226: /*
! 227: * If output interrupts are not supported then we write MIDI_MAXWRITE
! 228: * bytes instead of 1, and then we wait sc->wait
! 229: */
! 230:
! 231: max = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAXWRITE;
! 232: for (i = max; i != 0;) {
! 233: if (mb->used == 0)
! 234: break;
! 235: error = sc->hw_if->output(sc->hw_hdl, mb->data[mb->start]);
! 236: /*
! 237: * 0 means that data is being sent, an interrupt will
! 238: * be generated when the interface becomes ready again
! 239: *
! 240: * EINPROGRESS means that data has been queued, but
! 241: * will not be sent immediately and thus will not
! 242: * generate interrupt, in this case we can send
! 243: * another byte. The flush() method can be called
! 244: * to force the transfer.
! 245: *
! 246: * EAGAIN means that data cannot be queued or sent;
! 247: * because the interface isn't ready. An interrupt
! 248: * will be generated once the interface is ready again
! 249: *
! 250: * any other (fatal) error code means that data couldn't
! 251: * be sent and was lost, interrupt will not be generated
! 252: */
! 253: if (error == EINPROGRESS) {
! 254: MIDIBUF_REMOVE(mb, 1);
! 255: if (MIDIBUF_ISEMPTY(mb)) {
! 256: if (sc->hw_if->flush != NULL)
! 257: sc->hw_if->flush(sc->hw_hdl);
! 258: midi_out_stop(sc);
! 259: return;
! 260: }
! 261: } else if (error == 0) {
! 262: MIDIBUF_REMOVE(mb, 1);
! 263: i--;
! 264: } else if (error == EAGAIN) {
! 265: break;
! 266: } else {
! 267: MIDIBUF_INIT(mb);
! 268: midi_out_stop(sc);
! 269: return;
! 270: }
! 271: }
! 272:
! 273: if (!(sc->props & MIDI_PROP_OUT_INTR)) {
! 274: if (MIDIBUF_ISEMPTY(mb))
! 275: midi_out_stop(sc);
! 276: else
! 277: timeout_add(&sc->timeo, sc->wait);
! 278: }
! 279: }
! 280:
! 281:
! 282: int
! 283: midiwrite(dev_t dev, struct uio *uio, int ioflag)
! 284: {
! 285: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 286: struct midi_buffer *mb = &sc->outbuf;
! 287: unsigned count;
! 288: int s, error;
! 289:
! 290: if (!(sc->flags & FWRITE))
! 291: return ENXIO;
! 292: if (sc->isdying)
! 293: return EIO;
! 294:
! 295: /*
! 296: * If IO_NDELAY flag is set then check if there is enough room
! 297: * in the buffer to store at least one byte. If not then dont
! 298: * start the write process.
! 299: */
! 300:
! 301: if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) &&
! 302: (uio->uio_resid > 0))
! 303: return EWOULDBLOCK;
! 304:
! 305: while (uio->uio_resid > 0) {
! 306: s = splaudio();
! 307: while (MIDIBUF_ISFULL(mb)) {
! 308: if (ioflag & IO_NDELAY) {
! 309: /*
! 310: * At this stage at least one byte is already
! 311: * moved so we do not return EWOULDBLOCK
! 312: */
! 313: splx(s);
! 314: return 0;
! 315: }
! 316: sc->wchan = 1;
! 317: error = tsleep(&sc->wchan, PWAIT|PCATCH, "mid_wr", 0);
! 318: if (error) {
! 319: splx(s);
! 320: return error;
! 321: }
! 322: if (sc->isdying) {
! 323: splx(s);
! 324: return EIO;
! 325: }
! 326: }
! 327:
! 328: count = MIDIBUF_SIZE - MIDIBUF_END(mb);
! 329: if (count > MIDIBUF_AVAIL(mb))
! 330: count = MIDIBUF_AVAIL(mb);
! 331: if (count > uio->uio_resid)
! 332: count = uio->uio_resid;
! 333: error = uiomove(mb->data + MIDIBUF_END(mb), count, uio);
! 334: if (error) {
! 335: splx(s);
! 336: return error;
! 337: }
! 338: mb->used += count;
! 339: midi_out_start(sc);
! 340: splx(s);
! 341: }
! 342: return 0;
! 343: }
! 344:
! 345:
! 346: int
! 347: midipoll(dev_t dev, int events, struct proc *p)
! 348: {
! 349: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 350: int s, revents;
! 351:
! 352: if (sc->isdying)
! 353: return POLLERR;
! 354:
! 355: revents = 0;
! 356: s = splaudio();
! 357: if (events & (POLLIN | POLLRDNORM)) {
! 358: if (!MIDIBUF_ISEMPTY(&sc->inbuf))
! 359: revents |= events & (POLLIN | POLLRDNORM);
! 360: }
! 361: if (events & (POLLOUT | POLLWRNORM)) {
! 362: if (!MIDIBUF_ISFULL(&sc->outbuf))
! 363: revents |= events & (POLLOUT | POLLWRNORM);
! 364: }
! 365: if (revents == 0) {
! 366: if (events & (POLLIN | POLLRDNORM))
! 367: selrecord(p, &sc->rsel);
! 368: if (events & (POLLOUT | POLLWRNORM))
! 369: selrecord(p, &sc->wsel);
! 370: }
! 371: splx(s);
! 372: return (revents);
! 373: }
! 374:
! 375:
! 376: int
! 377: midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 378: {
! 379: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 380:
! 381: if (sc->isdying) return EIO;
! 382:
! 383: switch(cmd) {
! 384: case FIONBIO:
! 385: /* All handled in the upper FS layer */
! 386: break;
! 387: case FIOASYNC:
! 388: if (*(int *)addr) {
! 389: if (sc->async) return EBUSY;
! 390: sc->async = p;
! 391: } else
! 392: sc->async = 0;
! 393: break;
! 394: default:
! 395: return ENOTTY;
! 396: break;
! 397: }
! 398: return 0;
! 399: }
! 400:
! 401:
! 402: int
! 403: midiopen(dev_t dev, int flags, int mode, struct proc *p)
! 404: {
! 405: struct midi_softc *sc;
! 406: int err;
! 407:
! 408: if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs)
! 409: return ENXIO;
! 410: sc = MIDI_DEV2SC(dev);
! 411: if (sc == NULL) /* there may be more units than devices */
! 412: return ENXIO;
! 413: if (sc->isdying)
! 414: return EIO;
! 415: if (sc->isopen)
! 416: return EBUSY;
! 417:
! 418: MIDIBUF_INIT(&sc->inbuf);
! 419: MIDIBUF_INIT(&sc->outbuf);
! 420: sc->isbusy = 0;
! 421: sc->rchan = sc->wchan = 0;
! 422: sc->async = 0;
! 423: sc->flags = flags;
! 424:
! 425: err = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc);
! 426: if (err)
! 427: return err;
! 428: sc->isopen = 1;
! 429: #if NSEQUENCER > 0
! 430: sc->seq_md = 0;
! 431: sc->seqopen = 0;
! 432: sc->evstatus = 0xff;
! 433: #endif
! 434: return 0;
! 435: }
! 436:
! 437:
! 438: int
! 439: midiclose(dev_t dev, int fflag, int devtype, struct proc *p)
! 440: {
! 441: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 442: struct midi_buffer *mb;
! 443: int error;
! 444: int s;
! 445:
! 446: mb = &sc->outbuf;
! 447: if (!sc->isdying) {
! 448: /* start draining output buffer */
! 449: s = splaudio();
! 450: if (!MIDIBUF_ISEMPTY(mb))
! 451: midi_out_start(sc);
! 452: while (sc->isbusy) {
! 453: sc->wchan = 1;
! 454: error = tsleep(&sc->wchan, PWAIT|PCATCH, "mid_dr", 0);
! 455: if (error || sc->isdying)
! 456: break;
! 457: }
! 458: splx(s);
! 459: }
! 460:
! 461: /*
! 462: * some hw_if->close() reset immediately the midi uart
! 463: * which flushes the internal buffer of the uart device,
! 464: * so we may lose some (important) data. To avoid this, we sleep 2*wait,
! 465: * which gives the time to the uart to drain its internal buffers.
! 466: *
! 467: * Note: we'd better sleep in the corresponding hw_if->close()
! 468: */
! 469:
! 470: tsleep(&sc->wchan, PWAIT|PCATCH, "mid_cl", 2 * sc->wait);
! 471: sc->hw_if->close(sc->hw_hdl);
! 472: sc->isopen = 0;
! 473: return 0;
! 474: }
! 475:
! 476:
! 477: int
! 478: midiprobe(struct device *parent, void *match, void *aux)
! 479: {
! 480: struct audio_attach_args *sa = aux;
! 481: return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
! 482: }
! 483:
! 484:
! 485: void
! 486: midi_attach(struct midi_softc *sc, struct device *parent)
! 487: {
! 488: struct midi_info mi;
! 489:
! 490: sc->isdying = 0;
! 491: sc->wait = (hz * MIDI_MAXWRITE) / MIDI_RATE;
! 492: if (sc->wait == 0)
! 493: sc->wait = 1;
! 494: sc->hw_if->getinfo(sc->hw_hdl, &mi);
! 495: sc->props = mi.props;
! 496: sc->isopen = 0;
! 497: timeout_set(&sc->timeo, midi_ointr, sc);
! 498: printf(": <%s>\n", mi.name);
! 499: }
! 500:
! 501:
! 502: void
! 503: midiattach(struct device *parent, struct device *self, void *aux)
! 504: {
! 505: struct midi_softc *sc = (struct midi_softc *)self;
! 506: struct audio_attach_args *sa = (struct audio_attach_args *)aux;
! 507: struct midi_hw_if *hwif = sa->hwif;
! 508: void *hdl = sa->hdl;
! 509:
! 510: #ifdef DIAGNOSTIC
! 511: if (hwif == 0 ||
! 512: hwif->open == 0 ||
! 513: hwif->close == 0 ||
! 514: hwif->output == 0 ||
! 515: hwif->getinfo == 0) {
! 516: printf("midi: missing method\n");
! 517: return;
! 518: }
! 519: #endif
! 520: sc->hw_if = hwif;
! 521: sc->hw_hdl = hdl;
! 522: midi_attach(sc, parent);
! 523: }
! 524:
! 525:
! 526: int
! 527: mididetach(struct device *self, int flags)
! 528: {
! 529: struct midi_softc *sc = (struct midi_softc *)self;
! 530: int maj, mn;
! 531:
! 532: sc->isdying = 1;
! 533: if (sc->wchan) {
! 534: sc->wchan = 0;
! 535: wakeup(&sc->wchan);
! 536: }
! 537: if (sc->rchan) {
! 538: sc->rchan = 0;
! 539: wakeup(&sc->rchan);
! 540: }
! 541:
! 542: /* locate the major number */
! 543: for (maj = 0; maj < nchrdev; maj++)
! 544: if (cdevsw[maj].d_open == midiopen)
! 545: break;
! 546:
! 547: /* Nuke the vnodes for any open instances (calls close). */
! 548: mn = self->dv_unit;
! 549: vdevgone(maj, mn, mn, VCHR);
! 550:
! 551: return 0;
! 552: }
! 553:
! 554:
! 555: int
! 556: midiprint(void *aux, const char *pnp)
! 557: {
! 558: if (pnp)
! 559: printf("midi at %s", pnp);
! 560: return (UNCONF);
! 561: }
! 562:
! 563:
! 564: void
! 565: midi_getinfo(dev_t dev, struct midi_info *mi)
! 566: {
! 567: struct midi_softc *sc = MIDI_DEV2SC(dev);
! 568: if (MIDI_UNIT(dev) >= midi_cd.cd_ndevs || sc == NULL || sc->isdying) {
! 569: mi->name = "unconfigured";
! 570: mi->props = 0;
! 571: return;
! 572: }
! 573: sc->hw_if->getinfo(sc->hw_hdl, mi);
! 574: }
! 575:
! 576:
! 577: struct device *
! 578: midi_attach_mi(struct midi_hw_if *hwif, void *hdl, struct device *dev)
! 579: {
! 580: struct audio_attach_args arg;
! 581:
! 582: arg.type = AUDIODEV_TYPE_MIDI;
! 583: arg.hwif = hwif;
! 584: arg.hdl = hdl;
! 585: return config_found(dev, &arg, midiprint);
! 586: }
! 587:
! 588:
! 589: int
! 590: midi_unit_count(void)
! 591: {
! 592: return midi_cd.cd_ndevs;
! 593: }
! 594:
! 595:
! 596: #if NSEQUENCER > 0
! 597: #define MIDI_EVLEN(status) (midi_evlen[((status) >> 4) & 7])
! 598: unsigned midi_evlen[] = { 2, 2, 2, 2, 1, 1, 2 };
! 599:
! 600: void
! 601: midi_toevent(struct midi_softc *sc, int data)
! 602: {
! 603: unsigned char mesg[3];
! 604:
! 605: if (data >= 0xf8) { /* is it a realtime message ? */
! 606: switch(data) {
! 607: case 0xf8: /* midi timer tic */
! 608: case 0xfa: /* midi timer start */
! 609: case 0xfb: /* midi timer continue (after stop) */
! 610: case 0xfc: /* midi timer stop */
! 611: mesg[0] = data;
! 612: midiseq_in(sc->seq_md, mesg, 1);
! 613: break;
! 614: default:
! 615: break;
! 616: }
! 617: } else if (data >= 0x80) { /* is it a common or voice message ? */
! 618: sc->evstatus = data;
! 619: sc->evindex = 0;
! 620: } else { /* else it is a data byte */
! 621: /* strip common messages and bogus data */
! 622: if (sc->evstatus >= 0xf0 || sc->evstatus < 0x80)
! 623: return;
! 624:
! 625: sc->evdata[sc->evindex++] = data;
! 626: if (sc->evindex == MIDI_EVLEN(sc->evstatus)) {
! 627: sc->evindex = 0;
! 628: mesg[0] = sc->evstatus;
! 629: mesg[1] = sc->evdata[0];
! 630: mesg[2] = sc->evdata[1];
! 631: midiseq_in(sc->seq_md, mesg, 1 + MIDI_EVLEN(sc->evstatus));
! 632: }
! 633: }
! 634: }
! 635:
! 636:
! 637: int
! 638: midi_writebytes(int unit, unsigned char *mesg, int mesglen)
! 639: {
! 640: struct midi_softc *sc = midi_cd.cd_devs[unit];
! 641: struct midi_buffer *mb = &sc->outbuf;
! 642: unsigned count;
! 643: int s;
! 644:
! 645: s = splaudio();
! 646: if (mesglen > MIDIBUF_AVAIL(mb)) {
! 647: splx(s);
! 648: return EWOULDBLOCK;
! 649: }
! 650:
! 651: while (mesglen > 0) {
! 652: count = MIDIBUF_SIZE - MIDIBUF_END(mb);
! 653: if (count > MIDIBUF_AVAIL(mb)) count = MIDIBUF_AVAIL(mb);
! 654: if (count > mesglen) count = mesglen;
! 655: bcopy(mesg, mb->data + MIDIBUF_END(mb), count);
! 656: mb->used += count;
! 657: mesg += count;
! 658: mesglen -= count;
! 659: midi_out_start(sc);
! 660: }
! 661: splx(s);
! 662: return 0;
! 663: }
! 664:
! 665: #endif /* NSEQUENCER > 0 */
! 666: #endif /* NMIDI > 0 */
CVSweb