Home | History | Annotate | Line # | Download | only in dev
midi.c revision 1.22
      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 (at) 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