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