xref: /openbsd-src/sys/dev/midi.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: midi.c,v 1.2 1999/01/02 00:59:08 niklas Exp $	*/
2 /*	$NetBSD: midi.c,v 1.10 1998/12/20 14:26:44 drochner Exp $	*/
3 
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@netbsd.org).
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include "midi.h"
41 #include "sequencer.h"
42 
43 #include <sys/param.h>
44 #include <sys/ioctl.h>
45 #include <sys/fcntl.h>
46 #include <sys/vnode.h>
47 #include <sys/select.h>
48 #include <sys/poll.h>
49 #include <sys/malloc.h>
50 #include <sys/proc.h>
51 #include <sys/systm.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 #define __BROKEN_INDIRECT_CONFIG /* XXX */
87 #ifdef __BROKEN_INDIRECT_CONFIG
88 int	midiprobe __P((struct device *, void *, void *));
89 #else
90 int	midiprobe __P((struct device *, struct cfdata *, void *));
91 #endif
92 void	midiattach __P((struct device *, struct device *, void *));
93 
94 struct cfattach midi_ca = {
95 	sizeof(struct midi_softc), midiprobe, midiattach
96 };
97 
98 struct cfdriver midi_cd = {
99 	NULL, "midi", DV_DULL
100 };
101 
102 #ifdef MIDI_SAVE
103 #define MIDI_SAVE_SIZE 100000
104 int midicnt;
105 struct {
106 	int cnt;
107 	u_char buf[MIDI_SAVE_SIZE];
108 } midisave;
109 #define MIDI_GETSAVE		_IOWR('m', 100, int)
110 
111 #endif
112 
113 int
114 midiprobe(parent, match, aux)
115 	struct device *parent;
116 #ifdef __BROKEN_INDIRECT_CONFIG
117 	void *match;
118 #else
119 	struct cfdata *match;
120 #endif
121 	void *aux;
122 {
123 	struct audio_attach_args *sa = aux;
124 
125 	DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
126 		 sa->type, sa, sa->hwif));
127 	return ((sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
128 }
129 
130 void
131 midiattach(parent, self, aux)
132 	struct device *parent, *self;
133 	void *aux;
134 {
135 	struct midi_softc *sc = (void *)self;
136 	struct audio_attach_args *sa = aux;
137 	struct midi_hw_if *hwp = sa->hwif;
138 	void *hdlp = sa->hdl;
139 
140 	DPRINTFN(6, ("MIDI attach\n"));
141 
142 #ifdef DIAGNOSTIC
143 	if (hwp == 0 ||
144 	    hwp->open == 0 ||
145 	    hwp->close == 0 ||
146 	    hwp->output == 0 ||
147 	    hwp->getinfo == 0) {
148 		printf("midi: missing method\n");
149 		return;
150 	}
151 #endif
152 	sc->hw_if = hwp;
153 	sc->hw_hdl = hdlp;
154 	midi_attach(sc, parent);
155 }
156 
157 void
158 midi_attach(sc, parent)
159 	struct midi_softc *sc;
160 	struct device *parent;
161 {
162 	struct midi_info mi;
163 
164 	sc->isopen = 0;
165 
166 	midi_wait = MIDI_WAIT * hz / 1000000;
167 	if (midi_wait == 0)
168 		midi_wait = 1;
169 
170 	sc->sc_dev = parent;
171 	sc->hw_if->getinfo(sc->hw_hdl, &mi);
172 	sc->props = mi.props;
173 	printf(": <%s>\n", mi.name);
174 }
175 
176 int
177 midi_unit_count()
178 {
179 	return (midi_cd.cd_ndevs);
180 }
181 
182 void
183 midi_initbuf(mb)
184 	struct midi_buffer *mb;
185 {
186 	mb->used = 0;
187 	mb->usedhigh = MIDI_BUFSIZE;
188 	mb->end = mb->start + mb->usedhigh;
189 	mb->inp = mb->outp = mb->start;
190 }
191 
192 int
193 midi_sleep_timo(chan, label, timo)
194 	int *chan;
195 	char *label;
196 	int timo;
197 {
198 	int st;
199 
200 	if (!label)
201 		label = "midi";
202 
203 	DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
204 	*chan = 1;
205 	st = tsleep(chan, PWAIT | PCATCH, label, timo);
206 	*chan = 0;
207 #ifdef MIDI_DEBUG
208 	if (st != 0)
209 		printf("midi_sleep: %d\n", st);
210 #endif
211 	return (st);
212 }
213 
214 int
215 midi_sleep(chan, label)
216 	int *chan;
217 	char *label;
218 {
219 	return (midi_sleep_timo(chan, label, 0));
220 }
221 
222 void
223 midi_wakeup(chan)
224 	int *chan;
225 {
226 	if (*chan) {
227 		DPRINTFN(5, ("midi_wakeup: %p\n", chan));
228 		wakeup(chan);
229 		*chan = 0;
230 	}
231 }
232 
233 static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
234 /* Number of bytes in a MIDI command */
235 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
236 
237 void
238 midi_in(addr, data)
239 	void *addr;
240 	int data;
241 {
242 	struct midi_softc *sc = addr;
243 	struct midi_buffer *mb = &sc->inbuf;
244 	int i;
245 
246 	if (!sc->isopen)
247 		return;
248 	if (data == MIDI_ACK)
249 		return;
250 	DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
251 	if (!(sc->flags & FREAD))
252 		return;		/* discard data if not reading */
253 
254 	switch(sc->in_state) {
255 	case MIDI_IN_START:
256 		if (MIDI_IS_STATUS(data)) {
257 			switch(data) {
258 			case 0xf0: /* Sysex */
259 				sc->in_state = MIDI_IN_SYSEX;
260 				break;
261 			case 0xf1: /* MTC quarter frame */
262 			case 0xf3: /* Song select */
263 				sc->in_state = MIDI_IN_DATA;
264 				sc->in_msg[0] = data;
265 				sc->in_pos = 1;
266 				sc->in_left = 1;
267 				break;
268 			case 0xf2: /* Song position pointer */
269 				sc->in_state = MIDI_IN_DATA;
270 				sc->in_msg[0] = data;
271 				sc->in_pos = 1;
272 				sc->in_left = 2;
273 				break;
274 			default:
275 				if (MIDI_IS_COMMON(data)) {
276 					sc->in_msg[0] = data;
277 					sc->in_pos = 1;
278 					goto deliver;
279 				} else {
280 					sc->in_state = MIDI_IN_DATA;
281 					sc->in_msg[0] = sc->in_status = data;
282 					sc->in_pos = 1;
283 					sc->in_left =
284 						MIDI_LENGTH(sc->in_status);
285 				}
286 				break;
287 			}
288 		} else {
289 			if (MIDI_IS_STATUS(sc->in_status)) {
290 				sc->in_state = MIDI_IN_DATA;
291 				sc->in_msg[0] = sc->in_status;
292 				sc->in_msg[1] = data;
293 				sc->in_pos = 2;
294 				sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
295 			}
296 		}
297 		return;
298 	case MIDI_IN_DATA:
299 		sc->in_msg[sc->in_pos++] = data;
300 		if (--sc->in_left <= 0)
301 			break;	/* deliver data */
302 		return;
303 	case MIDI_IN_SYSEX:
304 		if (data == MIDI_SYSEX_END)
305 			sc->in_state = MIDI_IN_START;
306 		return;
307 	}
308 deliver:
309 	sc->in_state = MIDI_IN_START;
310 #if NSEQUENCER > 0
311 	if (sc->seqopen) {
312 		extern void midiseq_in __P((struct midi_dev *,u_char *,int));
313 		midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos);
314 		return;
315 	}
316 #endif
317 
318 	if (mb->used + sc->in_pos > mb->usedhigh) {
319 		DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
320 			 sc->in_msg[0]));
321 		return;
322 	}
323 	for (i = 0; i < sc->in_pos; i++) {
324 		*mb->inp++ = sc->in_msg[i];
325 		if (mb->inp >= mb->end)
326 			mb->inp = mb->start;
327 		mb->used++;
328 	}
329 	midi_wakeup(&sc->rchan);
330 	selwakeup(&sc->rsel);
331 	if (sc->async)
332 		psignal(sc->async, SIGIO);
333 }
334 
335 void
336 midi_out(addr)
337 	void *addr;
338 {
339 	struct midi_softc *sc = addr;
340 
341 	if (!sc->isopen)
342 		return;
343 	DPRINTFN(3, ("midi_out: %p\n", sc));
344 	midi_start_output(sc, 1);
345 }
346 
347 int
348 midiopen(dev, flags, ifmt, p)
349 	dev_t dev;
350 	int flags, ifmt;
351 	struct proc *p;
352 {
353 	int unit = MIDIUNIT(dev);
354 	struct midi_softc *sc;
355 	struct midi_hw_if *hw;
356 	int error;
357 
358 	if (unit >= midi_cd.cd_ndevs ||
359 	    (sc = midi_cd.cd_devs[unit]) == NULL)
360 		return (ENXIO);
361 	DPRINTF(("midiopen %p\n", sc));
362 
363 	hw = sc->hw_if;
364 	if (!hw)
365 		return (ENXIO);
366 	if (sc->isopen)
367 		return (EBUSY);
368 	sc->in_state = MIDI_IN_START;
369 	sc->in_status = 0;
370 	error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
371 	if (error)
372 		return (error);
373 	sc->isopen++;
374 	midi_initbuf(&sc->outbuf);
375 	midi_initbuf(&sc->inbuf);
376 	sc->flags = flags;
377 	sc->rchan = 0;
378 	sc->wchan = 0;
379 	sc->pbus = 0;
380 	sc->async = 0;
381 
382 #ifdef MIDI_SAVE
383 	if (midicnt != 0) {
384 		midisave.cnt = midicnt;
385 		midicnt = 0;
386 	}
387 #endif
388 
389 	return (0);
390 }
391 
392 int
393 midiclose(dev, flags, ifmt, p)
394 	dev_t dev;
395 	int flags, ifmt;
396 	struct proc *p;
397 {
398 	int unit = MIDIUNIT(dev);
399 	struct midi_softc *sc = midi_cd.cd_devs[unit];
400 	struct midi_hw_if *hw = sc->hw_if;
401 	int s, error;
402 
403 	DPRINTF(("midiclose %p\n", sc));
404 
405 	midi_start_output(sc, 0);
406 	error = 0;
407 	s = splaudio();
408 	while (sc->outbuf.used > 0 && !error) {
409 		DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
410 		error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
411 	}
412 	splx(s);
413 	sc->isopen = 0;
414 	hw->close(sc->hw_hdl);
415 #if NSEQUENCER > 0
416 	sc->seqopen = 0;
417 	sc->seq_md = 0;
418 #endif
419 	return (0);
420 }
421 
422 int
423 midiread(dev, uio, ioflag)
424 	dev_t dev;
425 	struct uio *uio;
426 	int ioflag;
427 {
428 	int unit = MIDIUNIT(dev);
429 	struct midi_softc *sc = midi_cd.cd_devs[unit];
430 	struct midi_buffer *mb = &sc->inbuf;
431 	int error;
432 	u_char *outp;
433 	int used, cc, n, resid;
434 	int s;
435 
436 	DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
437 
438 	error = 0;
439 	resid = uio->uio_resid;
440 	while (uio->uio_resid == resid && !error) {
441 		s = splaudio();
442 		while (mb->used <= 0) {
443 			if (ioflag & IO_NDELAY) {
444 				splx(s);
445 				return (EWOULDBLOCK);
446 			}
447 			error = midi_sleep(&sc->rchan, "mid rd");
448 			if (error) {
449 				splx(s);
450 				return (error);
451 			}
452 		}
453 		used = mb->used;
454 		outp = mb->outp;
455 		splx(s);
456 		cc = used;	/* maximum to read */
457 		n = mb->end - outp;
458 		if (n < cc)
459 			cc = n;	/* don't read beyond end of buffer */
460 		if (uio->uio_resid < cc)
461 			cc = uio->uio_resid; /* and no more than we want */
462 		DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
463 		error = uiomove(outp, cc, uio);
464 		if (error)
465 			break;
466 		used -= cc;
467 		outp += cc;
468 		if (outp >= mb->end)
469 			outp = mb->start;
470 		s = splaudio();
471 		mb->outp = outp;
472 		mb->used = used;
473 		splx(s);
474 	}
475 	return (error);
476 }
477 
478 void
479 midi_timeout(arg)
480 	void *arg;
481 {
482 	struct midi_softc *sc = arg;
483 
484 	DPRINTFN(3,("midi_timeout: %p\n", sc));
485 	midi_start_output(sc, 1);
486 }
487 
488 int
489 midi_start_output(sc, intr)
490 	struct midi_softc *sc;
491 	int intr;
492 {
493 	struct midi_buffer *mb = &sc->outbuf;
494 	u_char *outp;
495 	int error;
496 	int s;
497 	int i, mmax;
498 
499 	error = 0;
500 	mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
501 	s = splaudio();
502 	if (sc->pbus && !intr) {
503 		DPRINTFN(4, ("midi_start_output: busy\n"));
504 		splx(s);
505 		return (0);
506 	}
507 	sc->pbus = 1;
508 	for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
509 		outp = mb->outp;
510 		splx(s);
511 		DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
512 			     sc, i, *outp));
513 #ifdef MIDI_SAVE
514 		midisave.buf[midicnt] = *outp;
515 		midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
516 #endif
517 		error = sc->hw_if->output(sc->hw_hdl, *outp++);
518 		if (outp >= mb->end)
519 			outp = mb->start;
520 		s = splaudio();
521 		mb->outp = outp;
522 		mb->used--;
523 	}
524 	midi_wakeup(&sc->wchan);
525 	selwakeup(&sc->wsel);
526 	if (sc->async)
527 		psignal(sc->async, SIGIO);
528 	if (mb->used > 0) {
529 		if (!(sc->props & MIDI_PROP_OUT_INTR))
530 			timeout(midi_timeout, sc, midi_wait);
531 	} else
532 		sc->pbus = 0;
533 	splx(s);
534 	return (error);
535 }
536 
537 int
538 midiwrite(dev, uio, ioflag)
539 	dev_t dev;
540 	struct uio *uio;
541 	int ioflag;
542 {
543 	int unit = MIDIUNIT(dev);
544 	struct midi_softc *sc = midi_cd.cd_devs[unit];
545 	struct midi_buffer *mb = &sc->outbuf;
546 	int error;
547 	u_char *inp;
548 	int used, cc, n;
549 	int s;
550 
551 	DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
552 		     uio->uio_resid));
553 
554 	error = 0;
555 	while (uio->uio_resid > 0 && !error) {
556 		s = splaudio();
557 		if (mb->used >= mb->usedhigh) {
558 			DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
559 				 mb->used, mb->usedhigh));
560 			if (ioflag & IO_NDELAY) {
561 				splx(s);
562 				return (EWOULDBLOCK);
563 			}
564 			error = midi_sleep(&sc->wchan, "mid wr");
565 			if (error) {
566 				splx(s);
567 				return (error);
568 			}
569 		}
570 		used = mb->used;
571 		inp = mb->inp;
572 		splx(s);
573 		cc = mb->usedhigh - used; 	/* maximum to write */
574 		n = mb->end - inp;
575 		if (n < cc)
576 			cc = n;		/* don't write beyond end of buffer */
577 		if (uio->uio_resid < cc)
578 			cc = uio->uio_resid; 	/* and no more than we have */
579 		error = uiomove(inp, cc, uio);
580 #ifdef MIDI_DEBUG
581 		if (error)
582 		        printf("midi_write:(1) uiomove failed %d; "
583 			       "cc=%d inp=%p\n",
584 			       error, cc, inp);
585 #endif
586 		if (error)
587 			break;
588 		inp = mb->inp + cc;
589 		if (inp >= mb->end)
590 			inp = mb->start;
591 		s = splaudio();
592 		mb->inp = inp;
593 		mb->used += cc;
594 		splx(s);
595 		error = midi_start_output(sc, 0);
596 	}
597 	return (error);
598 }
599 
600 /*
601  * This write routine is only called from sequencer code and expects
602  * a write that is smaller than the MIDI buffer.
603  */
604 int
605 midi_writebytes(unit, buf, cc)
606 	int unit;
607 	u_char *buf;
608 	int cc;
609 {
610 	struct midi_softc *sc = midi_cd.cd_devs[unit];
611 	struct midi_buffer *mb = &sc->outbuf;
612 	int n, s;
613 
614 	DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
615 	DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2]));
616 
617 	s = splaudio();
618 	if (mb->used + cc >= mb->usedhigh) {
619 		splx(s);
620 		return (EWOULDBLOCK);
621 	}
622 	n = mb->end - mb->inp;
623 	if (cc < n)
624 		n = cc;
625 	mb->used += cc;
626 	bcopy(buf, mb->inp, n);
627 	mb->inp += n;
628 	if (mb->inp >= mb->end) {
629 		mb->inp = mb->start;
630 		cc -= n;
631 		if (cc > 0) {
632 			bcopy(buf + n, mb->inp, cc);
633 			mb->inp += cc;
634 		}
635 	}
636 	splx(s);
637 	return (midi_start_output(sc, 0));
638 }
639 
640 int
641 midiioctl(dev, cmd, addr, flag, p)
642 	dev_t dev;
643 	u_long cmd;
644 	caddr_t addr;
645 	int flag;
646 	struct proc *p;
647 {
648 	int unit = MIDIUNIT(dev);
649 	struct midi_softc *sc = midi_cd.cd_devs[unit];
650 	struct midi_hw_if *hw = sc->hw_if;
651 	int error;
652 
653 	DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
654 	error = 0;
655 	switch (cmd) {
656 	case FIONBIO:
657 		/* All handled in the upper FS layer. */
658 		break;
659 
660 	case FIOASYNC:
661 		if (*(int *)addr) {
662 			if (sc->async)
663 				return (EBUSY);
664 			sc->async = p;
665 			DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
666 		} else
667 			sc->async = 0;
668 		break;
669 
670 #if 0
671 	case MIDI_PRETIME:
672 		/* XXX OSS
673 		 * This should set up a read timeout, but that's
674 		 * why we have poll(), so there's nothing yet. */
675 		error = EINVAL;
676 		break;
677 #endif
678 
679 #ifdef MIDI_SAVE
680 	case MIDI_GETSAVE:
681 		error = copyout(&midisave, *(void **)addr, sizeof midisave);
682   		break;
683 #endif
684 
685 	default:
686 		if (hw->ioctl)
687 			error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
688 		else
689 			error = EINVAL;
690 		break;
691 	}
692 	return (error);
693 }
694 
695 int
696 midiselect(dev, rw, p)
697 	dev_t dev;
698 	int rw;
699 	struct proc *p;
700 {
701 	int unit = MIDIUNIT(dev);
702 	struct midi_softc *sc = midi_cd.cd_devs[unit];
703 	int s = splaudio();
704 
705 	DPRINTF(("midiselect: %p rw=0x%x\n", sc, rw));
706 
707 	switch (rw) {
708 	case FREAD:
709 		if (sc->inbuf.used > 0) {
710 			splx(s);
711 			return (1);
712 		}
713 		selrecord(p, &sc->rsel);
714 		break;
715 
716 	case FWRITE:
717 		if (sc->outbuf.used < sc->outbuf.usedhigh) {
718 			splx(s);
719 			return (1);
720 		}
721 		selrecord(p, &sc->wsel);
722 		break;
723 	}
724 
725 	splx(s);
726 	return (0);
727 }
728 
729 void
730 midi_getinfo(dev, mi)
731 	dev_t dev;
732 	struct midi_info *mi;
733 {
734 	int unit = MIDIUNIT(dev);
735 	struct midi_softc *sc;
736 
737 	if (unit >= midi_cd.cd_ndevs ||
738 	    (sc = midi_cd.cd_devs[unit]) == NULL)
739 		return;
740 	sc->hw_if->getinfo(sc->hw_hdl, mi);
741 }
742 
743 #endif /* NMIDI > 0 */
744 
745 #if NMIDI > 0 || NMIDIBUS > 0
746 
747 int	audioprint __P((void *, const char *));
748 
749 void
750 midi_attach_mi(mhwp, hdlp, dev)
751 	struct midi_hw_if *mhwp;
752 	void *hdlp;
753 	struct device *dev;
754 {
755 	struct audio_attach_args arg;
756 
757 #ifdef DIAGNOSTIC
758 	if (mhwp == NULL) {
759 		printf("midi_attach_mi: NULL\n");
760 		return;
761 	}
762 #endif
763 	arg.type = AUDIODEV_TYPE_MIDI;
764 	arg.hwif = mhwp;
765 	arg.hdl = hdlp;
766 	(void)config_found(dev, &arg, audioprint);
767 }
768 
769 #endif /* NMIDI > 0 || NMIDIBUS > 0 */
770