xref: /netbsd-src/sys/dev/midi.c (revision bcc8ec9959e7b01e313d813067bfb43a3ad70551)
1 /*	$NetBSD: midi.c,v 1.19 2001/01/13 16:16:12 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 *outp;
547 	int error;
548 	int s;
549 	int i, mmax;
550 
551 	error = 0;
552 	mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
553 
554 	if (sc->dying)
555 		return EIO;
556 
557 	s = splaudio();
558 	if (sc->pbus && !intr) {
559 		DPRINTFN(4, ("midi_start_output: busy\n"));
560 		splx(s);
561 		return 0;
562 	}
563 	sc->pbus = 1;
564 	for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
565 		outp = mb->outp;
566 		splx(s);
567 		DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
568 			     sc, i, *outp));
569 #ifdef MIDI_SAVE
570 		midisave.buf[midicnt] = *outp;
571 		midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
572 #endif
573 		error = sc->hw_if->output(sc->hw_hdl, *outp++);
574 		if (outp >= mb->end)
575 			outp = mb->start;
576 		s = splaudio();
577 		mb->outp = outp;
578 		mb->used--;
579 	}
580 	midi_wakeup(&sc->wchan);
581 	selwakeup(&sc->wsel);
582 	if (sc->async)
583 		psignal(sc->async, SIGIO);
584 	if (mb->used > 0) {
585 		if (!(sc->props & MIDI_PROP_OUT_INTR))
586 			callout_reset(&sc->sc_callout, midi_wait,
587 			    midi_timeout, sc);
588 	} else
589 		sc->pbus = 0;
590 	splx(s);
591 	return error;
592 }
593 
594 int
595 midiwrite(dev, uio, ioflag)
596 	dev_t dev;
597 	struct uio *uio;
598 	int ioflag;
599 {
600 	int unit = MIDIUNIT(dev);
601 	struct midi_softc *sc = midi_cd.cd_devs[unit];
602 	struct midi_buffer *mb = &sc->outbuf;
603 	int error;
604 	u_char *inp;
605 	int used, cc, n;
606 	int s;
607 
608 	DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit,
609 		     (unsigned long)uio->uio_resid));
610 
611 	if (sc->dying)
612 		return EIO;
613 
614 	error = 0;
615 	while (uio->uio_resid > 0 && !error) {
616 		s = splaudio();
617 		if (mb->used >= mb->usedhigh) {
618 			DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
619 				 mb->used, mb->usedhigh));
620 			if (ioflag & IO_NDELAY) {
621 				splx(s);
622 				return EWOULDBLOCK;
623 			}
624 			error = midi_sleep(&sc->wchan, "mid wr");
625 			if (error) {
626 				splx(s);
627 				return error;
628 			}
629 		}
630 		used = mb->used;
631 		inp = mb->inp;
632 		splx(s);
633 		if (sc->dying)
634 			return EIO;
635 		cc = mb->usedhigh - used; 	/* maximum to write */
636 		n = mb->end - inp;
637 		if (n < cc)
638 			cc = n;		/* don't write beyond end of buffer */
639 		if (uio->uio_resid < cc)
640 			cc = uio->uio_resid; 	/* and no more than we have */
641 		error = uiomove(inp, cc, uio);
642 #ifdef MIDI_DEBUG
643 		if (error)
644 		        printf("midi_write:(1) uiomove failed %d; "
645 			       "cc=%d inp=%p\n",
646 			       error, cc, inp);
647 #endif
648 		if (error)
649 			break;
650 		inp = mb->inp + cc;
651 		if (inp >= mb->end)
652 			inp = mb->start;
653 		s = splaudio();
654 		mb->inp = inp;
655 		mb->used += cc;
656 		splx(s);
657 		error = midi_start_output(sc, 0);
658 	}
659 	return error;
660 }
661 
662 /*
663  * This write routine is only called from sequencer code and expects
664  * a write that is smaller than the MIDI buffer.
665  */
666 int
667 midi_writebytes(unit, buf, cc)
668 	int unit;
669 	u_char *buf;
670 	int cc;
671 {
672 	struct midi_softc *sc = midi_cd.cd_devs[unit];
673 	struct midi_buffer *mb = &sc->outbuf;
674 	int n, s;
675 
676 	DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
677 	DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2]));
678 
679 	if (sc->dying)
680 		return EIO;
681 
682 	s = splaudio();
683 	if (mb->used + cc >= mb->usedhigh) {
684 		splx(s);
685 		return (EWOULDBLOCK);
686 	}
687 	n = mb->end - mb->inp;
688 	if (cc < n)
689 		n = cc;
690 	mb->used += cc;
691 	memcpy(mb->inp, buf, n);
692 	mb->inp += n;
693 	if (mb->inp >= mb->end) {
694 		mb->inp = mb->start;
695 		cc -= n;
696 		if (cc > 0) {
697 			memcpy(mb->inp, buf + n, cc);
698 			mb->inp += cc;
699 		}
700 	}
701 	splx(s);
702 	return (midi_start_output(sc, 0));
703 }
704 
705 int
706 midiioctl(dev, cmd, addr, flag, p)
707 	dev_t dev;
708 	u_long cmd;
709 	caddr_t addr;
710 	int flag;
711 	struct proc *p;
712 {
713 	int unit = MIDIUNIT(dev);
714 	struct midi_softc *sc = midi_cd.cd_devs[unit];
715 	struct midi_hw_if *hw = sc->hw_if;
716 	int error;
717 
718 	DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
719 
720 	if (sc->dying)
721 		return EIO;
722 
723 	error = 0;
724 	switch (cmd) {
725 	case FIONBIO:
726 		/* All handled in the upper FS layer. */
727 		break;
728 
729 	case FIOASYNC:
730 		if (*(int *)addr) {
731 			if (sc->async)
732 				return EBUSY;
733 			sc->async = p;
734 			DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
735 		} else
736 			sc->async = 0;
737 		break;
738 
739 #if 0
740 	case MIDI_PRETIME:
741 		/* XXX OSS
742 		 * This should set up a read timeout, but that's
743 		 * why we have poll(), so there's nothing yet. */
744 		error = EINVAL;
745 		break;
746 #endif
747 
748 #ifdef MIDI_SAVE
749 	case MIDI_GETSAVE:
750 		error = copyout(&midisave, *(void **)addr, sizeof midisave);
751   		break;
752 #endif
753 
754 	default:
755 		if (hw->ioctl)
756 			error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
757 		else
758 			error = EINVAL;
759 		break;
760 	}
761 	return error;
762 }
763 
764 int
765 midipoll(dev, events, p)
766 	dev_t dev;
767 	int events;
768 	struct proc *p;
769 {
770 	int unit = MIDIUNIT(dev);
771 	struct midi_softc *sc = midi_cd.cd_devs[unit];
772 	int revents = 0;
773 	int s = splaudio();
774 
775 	DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
776 
777 	if (sc->dying)
778 		return EIO;
779 
780 	if (events & (POLLIN | POLLRDNORM))
781 		if (sc->inbuf.used > 0)
782 			revents |= events & (POLLIN | POLLRDNORM);
783 
784 	if (events & (POLLOUT | POLLWRNORM))
785 		if (sc->outbuf.used < sc->outbuf.usedhigh)
786 			revents |= events & (POLLOUT | POLLWRNORM);
787 
788 	if (revents == 0) {
789 		if (events & (POLLIN | POLLRDNORM))
790 			selrecord(p, &sc->rsel);
791 
792 		if (events & (POLLOUT | POLLWRNORM))
793 			selrecord(p, &sc->wsel);
794 	}
795 
796 	splx(s);
797 	return revents;
798 }
799 
800 void
801 midi_getinfo(dev, mi)
802 	dev_t dev;
803 	struct midi_info *mi;
804 {
805 	struct midi_softc *sc;
806 
807 	sc = device_lookup(&midi_cd, MIDIUNIT(dev));
808 	if (sc == NULL)
809 		return;
810 	if (sc->dying)
811 		return;
812 
813 	sc->hw_if->getinfo(sc->hw_hdl, mi);
814 }
815 
816 #endif /* NMIDI > 0 */
817 
818 #if NMIDI > 0 || NMIDIBUS > 0
819 
820 int	audioprint __P((void *, const char *));
821 
822 struct device *
823 midi_attach_mi(mhwp, hdlp, dev)
824 	struct midi_hw_if *mhwp;
825 	void *hdlp;
826 	struct device *dev;
827 {
828 	struct audio_attach_args arg;
829 
830 #ifdef DIAGNOSTIC
831 	if (mhwp == NULL) {
832 		printf("midi_attach_mi: NULL\n");
833 		return (0);
834 	}
835 #endif
836 	arg.type = AUDIODEV_TYPE_MIDI;
837 	arg.hwif = mhwp;
838 	arg.hdl = hdlp;
839 	return (config_found(dev, &arg, audioprint));
840 }
841 
842 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
843