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