xref: /freebsd/sys/dev/sound/midi/midi.c (revision e17f5b1d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
3  *
4  * Copyright (c) 2003 Mathew Kanner
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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33  /*
34   * Parts of this file started out as NetBSD: midi.c 1.31
35   * They are mostly gone.  Still the most obvious will be the state
36   * machine midi_in
37   */
38 
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/queue.h>
45 #include <sys/kernel.h>
46 #include <sys/lock.h>
47 #include <sys/mutex.h>
48 #include <sys/proc.h>
49 #include <sys/signalvar.h>
50 #include <sys/conf.h>
51 #include <sys/selinfo.h>
52 #include <sys/sysctl.h>
53 #include <sys/malloc.h>
54 #include <sys/sx.h>
55 #include <sys/proc.h>
56 #include <sys/fcntl.h>
57 #include <sys/types.h>
58 #include <sys/uio.h>
59 #include <sys/poll.h>
60 #include <sys/sbuf.h>
61 #include <sys/kobj.h>
62 #include <sys/module.h>
63 
64 #ifdef HAVE_KERNEL_OPTION_HEADERS
65 #include "opt_snd.h"
66 #endif
67 
68 #include <dev/sound/midi/midi.h>
69 #include "mpu_if.h"
70 
71 #include <dev/sound/midi/midiq.h>
72 #include "synth_if.h"
73 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
74 
75 #ifndef KOBJMETHOD_END
76 #define KOBJMETHOD_END	{ NULL, NULL }
77 #endif
78 
79 #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
80 #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
81 
82 #define MIDI_DEV_RAW	2
83 #define MIDI_DEV_MIDICTL 12
84 
85 enum midi_states {
86 	MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
87 };
88 
89 /*
90  * The MPU interface current has init() uninit() inqsize() outqsize()
91  * callback() : fiddle with the tx|rx status.
92  */
93 
94 #include "mpu_if.h"
95 
96 /*
97  * /dev/rmidi	Structure definitions
98  */
99 
100 #define MIDI_NAMELEN   16
101 struct snd_midi {
102 	KOBJ_FIELDS;
103 	struct mtx lock;		/* Protects all but queues */
104 	void   *cookie;
105 
106 	int	unit;			/* Should only be used in midistat */
107 	int	channel;		/* Should only be used in midistat */
108 
109 	int	busy;
110 	int	flags;			/* File flags */
111 	char	name[MIDI_NAMELEN];
112 	struct mtx qlock;		/* Protects inq, outq and flags */
113 	MIDIQ_HEAD(, char) inq, outq;
114 	int	rchan, wchan;
115 	struct selinfo rsel, wsel;
116 	int	hiwat;			/* QLEN(outq)>High-water -> disable
117 					 * writes from userland */
118 	enum midi_states inq_state;
119 	int	inq_status, inq_left;	/* Variables for the state machine in
120 					 * Midi_in, this is to provide that
121 					 * signals only get issued only
122 					 * complete command packets. */
123 	struct proc *async;
124 	struct cdev *dev;
125 	struct synth_midi *synth;
126 	int	synth_flags;
127 	TAILQ_ENTRY(snd_midi) link;
128 };
129 
130 struct synth_midi {
131 	KOBJ_FIELDS;
132 	struct snd_midi *m;
133 };
134 
135 static synth_open_t midisynth_open;
136 static synth_close_t midisynth_close;
137 static synth_writeraw_t midisynth_writeraw;
138 static synth_killnote_t midisynth_killnote;
139 static synth_startnote_t midisynth_startnote;
140 static synth_setinstr_t midisynth_setinstr;
141 static synth_alloc_t midisynth_alloc;
142 static synth_controller_t midisynth_controller;
143 static synth_bender_t midisynth_bender;
144 
145 
146 static kobj_method_t midisynth_methods[] = {
147 	KOBJMETHOD(synth_open, midisynth_open),
148 	KOBJMETHOD(synth_close, midisynth_close),
149 	KOBJMETHOD(synth_writeraw, midisynth_writeraw),
150 	KOBJMETHOD(synth_setinstr, midisynth_setinstr),
151 	KOBJMETHOD(synth_startnote, midisynth_startnote),
152 	KOBJMETHOD(synth_killnote, midisynth_killnote),
153 	KOBJMETHOD(synth_alloc, midisynth_alloc),
154 	KOBJMETHOD(synth_controller, midisynth_controller),
155 	KOBJMETHOD(synth_bender, midisynth_bender),
156 	KOBJMETHOD_END
157 };
158 
159 DEFINE_CLASS(midisynth, midisynth_methods, 0);
160 
161 /*
162  * Module Exports & Interface
163  *
164  * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan,
165  *     void *cookie)
166  * int midi_uninit(struct snd_midi *)
167  *
168  * 0 == no error
169  * EBUSY or other error
170  *
171  * int midi_in(struct snd_midi *, char *buf, int count)
172  * int midi_out(struct snd_midi *, char *buf, int count)
173  *
174  * midi_{in,out} return actual size transfered
175  *
176  */
177 
178 
179 /*
180  * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
181  */
182 
183 TAILQ_HEAD(, snd_midi) midi_devs;
184 
185 /*
186  * /dev/midistat variables and declarations, protected by midistat_lock
187  */
188 
189 static struct sx midistat_lock;
190 static int      midistat_isopen = 0;
191 static struct sbuf midistat_sbuf;
192 static struct cdev *midistat_dev;
193 
194 /*
195  * /dev/midistat	dev_t declarations
196  */
197 
198 static d_open_t midistat_open;
199 static d_close_t midistat_close;
200 static d_read_t midistat_read;
201 
202 static struct cdevsw midistat_cdevsw = {
203 	.d_version = D_VERSION,
204 	.d_open = midistat_open,
205 	.d_close = midistat_close,
206 	.d_read = midistat_read,
207 	.d_name = "midistat",
208 };
209 
210 
211 /*
212  * /dev/rmidi dev_t declarations, struct variable access is protected by
213  * locks contained within the structure.
214  */
215 
216 static d_open_t midi_open;
217 static d_close_t midi_close;
218 static d_ioctl_t midi_ioctl;
219 static d_read_t midi_read;
220 static d_write_t midi_write;
221 static d_poll_t midi_poll;
222 
223 static struct cdevsw midi_cdevsw = {
224 	.d_version = D_VERSION,
225 	.d_open = midi_open,
226 	.d_close = midi_close,
227 	.d_read = midi_read,
228 	.d_write = midi_write,
229 	.d_ioctl = midi_ioctl,
230 	.d_poll = midi_poll,
231 	.d_name = "rmidi",
232 };
233 
234 /*
235  * Prototypes of library functions
236  */
237 
238 static int      midi_destroy(struct snd_midi *, int);
239 static int      midistat_prepare(struct sbuf * s);
240 static int      midi_load(void);
241 static int      midi_unload(void);
242 
243 /*
244  * Misc declr.
245  */
246 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
247     "Midi driver");
248 static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
249     "Status device");
250 
251 int             midi_debug;
252 /* XXX: should this be moved into debug.midi? */
253 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
254 
255 int             midi_dumpraw;
256 SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
257 
258 int             midi_instroff;
259 SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
260 
261 int             midistat_verbose;
262 SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
263 	&midistat_verbose, 0, "");
264 
265 #define MIDI_DEBUG(l,a)	if(midi_debug>=l) a
266 /*
267  * CODE START
268  */
269 
270 /*
271  * Register a new rmidi device. cls midi_if interface unit == 0 means
272  * auto-assign new unit number unit != 0 already assigned a unit number, eg.
273  * not the first channel provided by this device. channel,	sub-unit
274  * cookie is passed back on MPU calls Typical device drivers will call with
275  * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
276  * what unit number is used.
277  *
278  * It is an error to call midi_init with an already used unit/channel combo.
279  *
280  * Returns NULL on error
281  *
282  */
283 struct snd_midi *
284 midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
285 {
286 	struct snd_midi *m;
287 	int i;
288 	int inqsize, outqsize;
289 	MIDI_TYPE *buf;
290 
291 	MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
292 	sx_xlock(&midistat_lock);
293 	/*
294 	 * Protect against call with existing unit/channel or auto-allocate a
295 	 * new unit number.
296 	 */
297 	i = -1;
298 	TAILQ_FOREACH(m, &midi_devs, link) {
299 		mtx_lock(&m->lock);
300 		if (unit != 0) {
301 			if (m->unit == unit && m->channel == channel) {
302 				mtx_unlock(&m->lock);
303 				goto err0;
304 			}
305 		} else {
306 			/*
307 			 * Find a better unit number
308 			 */
309 			if (m->unit > i)
310 				i = m->unit;
311 		}
312 		mtx_unlock(&m->lock);
313 	}
314 
315 	if (unit == 0)
316 		unit = i + 1;
317 
318 	MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
319 	m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
320 	m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO);
321 	kobj_init((kobj_t)m->synth, &midisynth_class);
322 	m->synth->m = m;
323 	kobj_init((kobj_t)m, cls);
324 	inqsize = MPU_INQSIZE(m, cookie);
325 	outqsize = MPU_OUTQSIZE(m, cookie);
326 
327 	MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
328 	if (!inqsize && !outqsize)
329 		goto err1;
330 
331 	mtx_init(&m->lock, "raw midi", NULL, 0);
332 	mtx_init(&m->qlock, "q raw midi", NULL, 0);
333 
334 	mtx_lock(&m->lock);
335 	mtx_lock(&m->qlock);
336 
337 	if (inqsize)
338 		buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
339 	else
340 		buf = NULL;
341 
342 	MIDIQ_INIT(m->inq, buf, inqsize);
343 
344 	if (outqsize)
345 		buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
346 	else
347 		buf = NULL;
348 	m->hiwat = outqsize / 2;
349 
350 	MIDIQ_INIT(m->outq, buf, outqsize);
351 
352 	if ((inqsize && !MIDIQ_BUF(m->inq)) ||
353 	    (outqsize && !MIDIQ_BUF(m->outq)))
354 		goto err2;
355 
356 	m->busy = 0;
357 	m->flags = 0;
358 	m->unit = unit;
359 	m->channel = channel;
360 	m->cookie = cookie;
361 
362 	if (MPU_INIT(m, cookie))
363 		goto err2;
364 
365 	mtx_unlock(&m->lock);
366 	mtx_unlock(&m->qlock);
367 
368 	TAILQ_INSERT_TAIL(&midi_devs, m, link);
369 
370 	sx_xunlock(&midistat_lock);
371 
372 	m->dev = make_dev(&midi_cdevsw,
373 	    MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
374 	    UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
375 	m->dev->si_drv1 = m;
376 
377 	return m;
378 
379 err2:
380 	mtx_destroy(&m->qlock);
381 	mtx_destroy(&m->lock);
382 
383 	if (MIDIQ_BUF(m->inq))
384 		free(MIDIQ_BUF(m->inq), M_MIDI);
385 	if (MIDIQ_BUF(m->outq))
386 		free(MIDIQ_BUF(m->outq), M_MIDI);
387 err1:
388 	free(m->synth, M_MIDI);
389 	free(m, M_MIDI);
390 err0:
391 	sx_xunlock(&midistat_lock);
392 	MIDI_DEBUG(1, printf("midi_init ended in error\n"));
393 	return NULL;
394 }
395 
396 /*
397  * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
398  * entry point. midi_uninit if fact, does not send any methods. A call to
399  * midi_uninit is a defacto promise that you won't manipulate ch anymore
400  *
401  */
402 
403 int
404 midi_uninit(struct snd_midi *m)
405 {
406 	int err;
407 
408 	err = EBUSY;
409 	sx_xlock(&midistat_lock);
410 	mtx_lock(&m->lock);
411 	if (m->busy) {
412 		if (!(m->rchan || m->wchan))
413 			goto err;
414 
415 		if (m->rchan) {
416 			wakeup(&m->rchan);
417 			m->rchan = 0;
418 		}
419 		if (m->wchan) {
420 			wakeup(&m->wchan);
421 			m->wchan = 0;
422 		}
423 	}
424 	err = midi_destroy(m, 0);
425 	if (!err)
426 		goto exit;
427 
428 err:
429 	mtx_unlock(&m->lock);
430 exit:
431 	sx_xunlock(&midistat_lock);
432 	return err;
433 }
434 
435 /*
436  * midi_in: process all data until the queue is full, then discards the rest.
437  * Since midi_in is a state machine, data discards can cause it to get out of
438  * whack.  Process as much as possible.  It calls, wakeup, selnotify and
439  * psignal at most once.
440  */
441 
442 #ifdef notdef
443 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
444 
445 #endif					/* notdef */
446 /* Number of bytes in a MIDI command */
447 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
448 #define MIDI_ACK	0xfe
449 #define MIDI_IS_STATUS(d) ((d) >= 0x80)
450 #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
451 
452 #define MIDI_SYSEX_START	0xF0
453 #define MIDI_SYSEX_END	    0xF7
454 
455 
456 int
457 midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
458 {
459 	/* int             i, sig, enq; */
460 	int used;
461 
462 	/* MIDI_TYPE       data; */
463 	MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
464 
465 /*
466  * XXX: locking flub
467  */
468 	if (!(m->flags & M_RX))
469 		return size;
470 
471 	used = 0;
472 
473 	mtx_lock(&m->qlock);
474 #if 0
475 	/*
476 	 * Don't bother queuing if not in read mode.  Discard everything and
477 	 * return size so the caller doesn't freak out.
478 	 */
479 
480 	if (!(m->flags & M_RX))
481 		return size;
482 
483 	for (i = sig = 0; i < size; i++) {
484 
485 		data = buf[i];
486 		enq = 0;
487 		if (data == MIDI_ACK)
488 			continue;
489 
490 		switch (m->inq_state) {
491 		case MIDI_IN_START:
492 			if (MIDI_IS_STATUS(data)) {
493 				switch (data) {
494 				case 0xf0:	/* Sysex */
495 					m->inq_state = MIDI_IN_SYSEX;
496 					break;
497 				case 0xf1:	/* MTC quarter frame */
498 				case 0xf3:	/* Song select */
499 					m->inq_state = MIDI_IN_DATA;
500 					enq = 1;
501 					m->inq_left = 1;
502 					break;
503 				case 0xf2:	/* Song position pointer */
504 					m->inq_state = MIDI_IN_DATA;
505 					enq = 1;
506 					m->inq_left = 2;
507 					break;
508 				default:
509 					if (MIDI_IS_COMMON(data)) {
510 						enq = 1;
511 						sig = 1;
512 					} else {
513 						m->inq_state = MIDI_IN_DATA;
514 						enq = 1;
515 						m->inq_status = data;
516 						m->inq_left = MIDI_LENGTH(data);
517 					}
518 					break;
519 				}
520 			} else if (MIDI_IS_STATUS(m->inq_status)) {
521 				m->inq_state = MIDI_IN_DATA;
522 				if (!MIDIQ_FULL(m->inq)) {
523 					used++;
524 					MIDIQ_ENQ(m->inq, &m->inq_status, 1);
525 				}
526 				enq = 1;
527 				m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
528 			}
529 			break;
530 			/*
531 			 * End of case MIDI_IN_START:
532 			 */
533 
534 		case MIDI_IN_DATA:
535 			enq = 1;
536 			if (--m->inq_left <= 0)
537 				sig = 1;/* deliver data */
538 			break;
539 		case MIDI_IN_SYSEX:
540 			if (data == MIDI_SYSEX_END)
541 				m->inq_state = MIDI_IN_START;
542 			break;
543 		}
544 
545 		if (enq)
546 			if (!MIDIQ_FULL(m->inq)) {
547 				MIDIQ_ENQ(m->inq, &data, 1);
548 				used++;
549 			}
550 		/*
551 	         * End of the state machines main "for loop"
552 	         */
553 	}
554 	if (sig) {
555 #endif
556 		MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
557 		    (intmax_t)MIDIQ_LEN(m->inq),
558 		    (intmax_t)MIDIQ_AVAIL(m->inq)));
559 		if (MIDIQ_AVAIL(m->inq) > size) {
560 			used = size;
561 			MIDIQ_ENQ(m->inq, buf, size);
562 		} else {
563 			MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
564 			mtx_unlock(&m->qlock);
565 			return 0;
566 		}
567 		if (m->rchan) {
568 			wakeup(&m->rchan);
569 			m->rchan = 0;
570 		}
571 		selwakeup(&m->rsel);
572 		if (m->async) {
573 			PROC_LOCK(m->async);
574 			kern_psignal(m->async, SIGIO);
575 			PROC_UNLOCK(m->async);
576 		}
577 #if 0
578 	}
579 #endif
580 	mtx_unlock(&m->qlock);
581 	return used;
582 }
583 
584 /*
585  * midi_out: The only clearer of the M_TXEN flag.
586  */
587 int
588 midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
589 {
590 	int used;
591 
592 /*
593  * XXX: locking flub
594  */
595 	if (!(m->flags & M_TXEN))
596 		return 0;
597 
598 	MIDI_DEBUG(2, printf("midi_out: %p\n", m));
599 	mtx_lock(&m->qlock);
600 	used = MIN(size, MIDIQ_LEN(m->outq));
601 	MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
602 	if (used)
603 		MIDIQ_DEQ(m->outq, buf, used);
604 	if (MIDIQ_EMPTY(m->outq)) {
605 		m->flags &= ~M_TXEN;
606 		MPU_CALLBACKP(m, m->cookie, m->flags);
607 	}
608 	if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
609 		if (m->wchan) {
610 			wakeup(&m->wchan);
611 			m->wchan = 0;
612 		}
613 		selwakeup(&m->wsel);
614 		if (m->async) {
615 			PROC_LOCK(m->async);
616 			kern_psignal(m->async, SIGIO);
617 			PROC_UNLOCK(m->async);
618 		}
619 	}
620 	mtx_unlock(&m->qlock);
621 	return used;
622 }
623 
624 
625 /*
626  * /dev/rmidi#.#	device access functions
627  */
628 int
629 midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
630 {
631 	struct snd_midi *m = i_dev->si_drv1;
632 	int retval;
633 
634 	MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
635 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
636 	if (m == NULL)
637 		return ENXIO;
638 
639 	mtx_lock(&m->lock);
640 	mtx_lock(&m->qlock);
641 
642 	retval = 0;
643 
644 	if (flags & FREAD) {
645 		if (MIDIQ_SIZE(m->inq) == 0)
646 			retval = ENXIO;
647 		else if (m->flags & M_RX)
648 			retval = EBUSY;
649 		if (retval)
650 			goto err;
651 	}
652 	if (flags & FWRITE) {
653 		if (MIDIQ_SIZE(m->outq) == 0)
654 			retval = ENXIO;
655 		else if (m->flags & M_TX)
656 			retval = EBUSY;
657 		if (retval)
658 			goto err;
659 	}
660 	m->busy++;
661 
662 	m->rchan = 0;
663 	m->wchan = 0;
664 	m->async = 0;
665 
666 	if (flags & FREAD) {
667 		m->flags |= M_RX | M_RXEN;
668 		/*
669 	         * Only clear the inq, the outq might still have data to drain
670 	         * from a previous session
671 	         */
672 		MIDIQ_CLEAR(m->inq);
673 	}
674 
675 	if (flags & FWRITE)
676 		m->flags |= M_TX;
677 
678 	MPU_CALLBACK(m, m->cookie, m->flags);
679 
680 	MIDI_DEBUG(2, printf("midi_open: opened.\n"));
681 
682 err:	mtx_unlock(&m->qlock);
683 	mtx_unlock(&m->lock);
684 	return retval;
685 }
686 
687 int
688 midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
689 {
690 	struct snd_midi *m = i_dev->si_drv1;
691 	int retval;
692 	int oldflags;
693 
694 	MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
695 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
696 
697 	if (m == NULL)
698 		return ENXIO;
699 
700 	mtx_lock(&m->lock);
701 	mtx_lock(&m->qlock);
702 
703 	if ((flags & FREAD && !(m->flags & M_RX)) ||
704 	    (flags & FWRITE && !(m->flags & M_TX))) {
705 		retval = ENXIO;
706 		goto err;
707 	}
708 	m->busy--;
709 
710 	oldflags = m->flags;
711 
712 	if (flags & FREAD)
713 		m->flags &= ~(M_RX | M_RXEN);
714 	if (flags & FWRITE)
715 		m->flags &= ~M_TX;
716 
717 	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
718 		MPU_CALLBACK(m, m->cookie, m->flags);
719 
720 	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
721 
722 	mtx_unlock(&m->qlock);
723 	mtx_unlock(&m->lock);
724 	retval = 0;
725 err:	return retval;
726 }
727 
728 /*
729  * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
730  * as data is available.
731  */
732 int
733 midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
734 {
735 #define MIDI_RSIZE 32
736 	struct snd_midi *m = i_dev->si_drv1;
737 	int retval;
738 	int used;
739 	char buf[MIDI_RSIZE];
740 
741 	MIDI_DEBUG(5, printf("midiread: count=%lu\n",
742 	    (unsigned long)uio->uio_resid));
743 
744 	retval = EIO;
745 
746 	if (m == NULL)
747 		goto err0;
748 
749 	mtx_lock(&m->lock);
750 	mtx_lock(&m->qlock);
751 
752 	if (!(m->flags & M_RX))
753 		goto err1;
754 
755 	while (uio->uio_resid > 0) {
756 		while (MIDIQ_EMPTY(m->inq)) {
757 			retval = EWOULDBLOCK;
758 			if (ioflag & O_NONBLOCK)
759 				goto err1;
760 			mtx_unlock(&m->lock);
761 			m->rchan = 1;
762 			retval = msleep(&m->rchan, &m->qlock,
763 			    PCATCH | PDROP, "midi RX", 0);
764 			/*
765 			 * We slept, maybe things have changed since last
766 			 * dying check
767 			 */
768 			if (retval == EINTR)
769 				goto err0;
770 			if (m != i_dev->si_drv1)
771 				retval = ENXIO;
772 			/* if (retval && retval != ERESTART) */
773 			if (retval)
774 				goto err0;
775 			mtx_lock(&m->lock);
776 			mtx_lock(&m->qlock);
777 			m->rchan = 0;
778 			if (!m->busy)
779 				goto err1;
780 		}
781 		MIDI_DEBUG(6, printf("midi_read start\n"));
782 		/*
783 	         * At this point, it is certain that m->inq has data
784 	         */
785 
786 		used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
787 		used = MIN(used, MIDI_RSIZE);
788 
789 		MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
790 		MIDIQ_DEQ(m->inq, buf, used);
791 		retval = uiomove(buf, used, uio);
792 		if (retval)
793 			goto err1;
794 	}
795 
796 	/*
797 	 * If we Made it here then transfer is good
798 	 */
799 	retval = 0;
800 err1:	mtx_unlock(&m->qlock);
801 	mtx_unlock(&m->lock);
802 err0:	MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
803 	return retval;
804 }
805 
806 /*
807  * midi_write: The only setter of M_TXEN
808  */
809 
810 int
811 midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
812 {
813 #define MIDI_WSIZE 32
814 	struct snd_midi *m = i_dev->si_drv1;
815 	int retval;
816 	int used;
817 	char buf[MIDI_WSIZE];
818 
819 
820 	MIDI_DEBUG(4, printf("midi_write\n"));
821 	retval = 0;
822 	if (m == NULL)
823 		goto err0;
824 
825 	mtx_lock(&m->lock);
826 	mtx_lock(&m->qlock);
827 
828 	if (!(m->flags & M_TX))
829 		goto err1;
830 
831 	while (uio->uio_resid > 0) {
832 		while (MIDIQ_AVAIL(m->outq) == 0) {
833 			retval = EWOULDBLOCK;
834 			if (ioflag & O_NONBLOCK)
835 				goto err1;
836 			mtx_unlock(&m->lock);
837 			m->wchan = 1;
838 			MIDI_DEBUG(3, printf("midi_write msleep\n"));
839 			retval = msleep(&m->wchan, &m->qlock,
840 			    PCATCH | PDROP, "midi TX", 0);
841 			/*
842 			 * We slept, maybe things have changed since last
843 			 * dying check
844 			 */
845 			if (retval == EINTR)
846 				goto err0;
847 			if (m != i_dev->si_drv1)
848 				retval = ENXIO;
849 			if (retval)
850 				goto err0;
851 			mtx_lock(&m->lock);
852 			mtx_lock(&m->qlock);
853 			m->wchan = 0;
854 			if (!m->busy)
855 				goto err1;
856 		}
857 
858 		/*
859 	         * We are certain than data can be placed on the queue
860 	         */
861 
862 		used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
863 		used = MIN(used, MIDI_WSIZE);
864 		MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
865 		    uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
866 		    (intmax_t)MIDIQ_AVAIL(m->outq)));
867 
868 
869 		MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
870 		retval = uiomove(buf, used, uio);
871 		if (retval)
872 			goto err1;
873 		MIDIQ_ENQ(m->outq, buf, used);
874 		/*
875 	         * Inform the bottom half that data can be written
876 	         */
877 		if (!(m->flags & M_TXEN)) {
878 			m->flags |= M_TXEN;
879 			MPU_CALLBACK(m, m->cookie, m->flags);
880 		}
881 	}
882 	/*
883 	 * If we Made it here then transfer is good
884 	 */
885 	retval = 0;
886 err1:	mtx_unlock(&m->qlock);
887 	mtx_unlock(&m->lock);
888 err0:	return retval;
889 }
890 
891 int
892 midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
893     struct thread *td)
894 {
895 	return ENXIO;
896 }
897 
898 int
899 midi_poll(struct cdev *i_dev, int events, struct thread *td)
900 {
901 	struct snd_midi *m = i_dev->si_drv1;
902 	int revents;
903 
904 	if (m == NULL)
905 		return 0;
906 
907 	revents = 0;
908 
909 	mtx_lock(&m->lock);
910 	mtx_lock(&m->qlock);
911 
912 	if (events & (POLLIN | POLLRDNORM))
913 		if (!MIDIQ_EMPTY(m->inq))
914 			events |= events & (POLLIN | POLLRDNORM);
915 
916 	if (events & (POLLOUT | POLLWRNORM))
917 		if (MIDIQ_AVAIL(m->outq) < m->hiwat)
918 			events |= events & (POLLOUT | POLLWRNORM);
919 
920 	if (revents == 0) {
921 		if (events & (POLLIN | POLLRDNORM))
922 			selrecord(td, &m->rsel);
923 
924 		if (events & (POLLOUT | POLLWRNORM))
925 			selrecord(td, &m->wsel);
926 	}
927 	mtx_unlock(&m->lock);
928 	mtx_unlock(&m->qlock);
929 
930 	return (revents);
931 }
932 
933 /*
934  * /dev/midistat device functions
935  *
936  */
937 static int
938 midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
939 {
940 	int error;
941 
942 	MIDI_DEBUG(1, printf("midistat_open\n"));
943 
944 	sx_xlock(&midistat_lock);
945 	if (midistat_isopen) {
946 		sx_xunlock(&midistat_lock);
947 		return EBUSY;
948 	}
949 	midistat_isopen = 1;
950 	if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
951 		error = ENXIO;
952 		goto out;
953 	}
954 	error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
955 out:
956 	if (error)
957 		midistat_isopen = 0;
958 	sx_xunlock(&midistat_lock);
959 	return error;
960 }
961 
962 static int
963 midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
964 {
965 	MIDI_DEBUG(1, printf("midistat_close\n"));
966 	sx_xlock(&midistat_lock);
967 	if (!midistat_isopen) {
968 		sx_xunlock(&midistat_lock);
969 		return EBADF;
970 	}
971 	sbuf_delete(&midistat_sbuf);
972 	midistat_isopen = 0;
973 	sx_xunlock(&midistat_lock);
974 	return 0;
975 }
976 
977 static int
978 midistat_read(struct cdev *i_dev, struct uio *uio, int flag)
979 {
980 	long l;
981 	int err;
982 
983 	MIDI_DEBUG(4, printf("midistat_read\n"));
984 	sx_xlock(&midistat_lock);
985 	if (!midistat_isopen) {
986 		sx_xunlock(&midistat_lock);
987 		return EBADF;
988 	}
989 	if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) {
990 		sx_xunlock(&midistat_lock);
991 		return EINVAL;
992 	}
993 	err = 0;
994 	l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset);
995 	if (l > 0) {
996 		err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l,
997 		    uio);
998 	}
999 	sx_xunlock(&midistat_lock);
1000 	return err;
1001 }
1002 
1003 /*
1004  * Module library functions
1005  */
1006 
1007 static int
1008 midistat_prepare(struct sbuf *s)
1009 {
1010 	struct snd_midi *m;
1011 
1012 	sx_assert(&midistat_lock, SA_XLOCKED);
1013 
1014 	sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1015 	if (TAILQ_EMPTY(&midi_devs)) {
1016 		sbuf_printf(s, "No devices installed.\n");
1017 		sbuf_finish(s);
1018 		return sbuf_len(s);
1019 	}
1020 	sbuf_printf(s, "Installed devices:\n");
1021 
1022 	TAILQ_FOREACH(m, &midi_devs, link) {
1023 		mtx_lock(&m->lock);
1024 		sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1025 		    MPU_PROVIDER(m, m->cookie));
1026 		sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1027 		sbuf_printf(s, "\n");
1028 		mtx_unlock(&m->lock);
1029 	}
1030 
1031 	sbuf_finish(s);
1032 	return sbuf_len(s);
1033 }
1034 
1035 #ifdef notdef
1036 /*
1037  * Convert IOCTL command to string for debugging
1038  */
1039 
1040 static char *
1041 midi_cmdname(int cmd)
1042 {
1043 	static struct {
1044 		int	cmd;
1045 		char   *name;
1046 	}     *tab, cmdtab_midiioctl[] = {
1047 #define A(x)	{x, ## x}
1048 		/*
1049 	         * Once we have some real IOCTLs define, the following will
1050 	         * be relavant.
1051 	         *
1052 	         * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1053 	         * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1054 	         * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1055 	         * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1056 	         * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1057 	         * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1058 	         * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1059 	         * A(AIOGCAP),
1060 	         */
1061 #undef A
1062 		{
1063 			-1, "unknown"
1064 		},
1065 	};
1066 
1067 	for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1068 	return tab->name;
1069 }
1070 
1071 #endif					/* notdef */
1072 
1073 /*
1074  * midisynth
1075  */
1076 
1077 
1078 int
1079 midisynth_open(void *n, void *arg, int flags)
1080 {
1081 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1082 	int retval;
1083 
1084 	MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
1085 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1086 
1087 	if (m == NULL)
1088 		return ENXIO;
1089 
1090 	mtx_lock(&m->lock);
1091 	mtx_lock(&m->qlock);
1092 
1093 	retval = 0;
1094 
1095 	if (flags & FREAD) {
1096 		if (MIDIQ_SIZE(m->inq) == 0)
1097 			retval = ENXIO;
1098 		else if (m->flags & M_RX)
1099 			retval = EBUSY;
1100 		if (retval)
1101 			goto err;
1102 	}
1103 	if (flags & FWRITE) {
1104 		if (MIDIQ_SIZE(m->outq) == 0)
1105 			retval = ENXIO;
1106 		else if (m->flags & M_TX)
1107 			retval = EBUSY;
1108 		if (retval)
1109 			goto err;
1110 	}
1111 	m->busy++;
1112 
1113 	/*
1114 	 * TODO: Consider m->async = 0;
1115 	 */
1116 
1117 	if (flags & FREAD) {
1118 		m->flags |= M_RX | M_RXEN;
1119 		/*
1120 	         * Only clear the inq, the outq might still have data to drain
1121 	         * from a previous session
1122 	         */
1123 		MIDIQ_CLEAR(m->inq);
1124 		m->rchan = 0;
1125 	}
1126 
1127 	if (flags & FWRITE) {
1128 		m->flags |= M_TX;
1129 		m->wchan = 0;
1130 	}
1131 	m->synth_flags = flags & (FREAD | FWRITE);
1132 
1133 	MPU_CALLBACK(m, m->cookie, m->flags);
1134 
1135 
1136 err:	mtx_unlock(&m->qlock);
1137 	mtx_unlock(&m->lock);
1138 	MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1139 	return retval;
1140 }
1141 
1142 int
1143 midisynth_close(void *n)
1144 {
1145 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1146 	int retval;
1147 	int oldflags;
1148 
1149 	MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1150 	    m->synth_flags & FREAD ? "M_RX" : "",
1151 	    m->synth_flags & FWRITE ? "M_TX" : ""));
1152 
1153 	if (m == NULL)
1154 		return ENXIO;
1155 
1156 	mtx_lock(&m->lock);
1157 	mtx_lock(&m->qlock);
1158 
1159 	if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1160 	    (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1161 		retval = ENXIO;
1162 		goto err;
1163 	}
1164 	m->busy--;
1165 
1166 	oldflags = m->flags;
1167 
1168 	if (m->synth_flags & FREAD)
1169 		m->flags &= ~(M_RX | M_RXEN);
1170 	if (m->synth_flags & FWRITE)
1171 		m->flags &= ~M_TX;
1172 
1173 	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1174 		MPU_CALLBACK(m, m->cookie, m->flags);
1175 
1176 	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1177 
1178 	mtx_unlock(&m->qlock);
1179 	mtx_unlock(&m->lock);
1180 	retval = 0;
1181 err:	return retval;
1182 }
1183 
1184 /*
1185  * Always blocking.
1186  */
1187 
1188 int
1189 midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1190 {
1191 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1192 	int retval;
1193 	int used;
1194 	int i;
1195 
1196 	MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1197 
1198 	retval = 0;
1199 
1200 	if (m == NULL)
1201 		return ENXIO;
1202 
1203 	mtx_lock(&m->lock);
1204 	mtx_lock(&m->qlock);
1205 
1206 	if (!(m->flags & M_TX))
1207 		goto err1;
1208 
1209 	if (midi_dumpraw)
1210 		printf("midi dump: ");
1211 
1212 	while (len > 0) {
1213 		while (MIDIQ_AVAIL(m->outq) == 0) {
1214 			if (!(m->flags & M_TXEN)) {
1215 				m->flags |= M_TXEN;
1216 				MPU_CALLBACK(m, m->cookie, m->flags);
1217 			}
1218 			mtx_unlock(&m->lock);
1219 			m->wchan = 1;
1220 			MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
1221 			retval = msleep(&m->wchan, &m->qlock,
1222 			    PCATCH | PDROP, "midi TX", 0);
1223 			/*
1224 			 * We slept, maybe things have changed since last
1225 			 * dying check
1226 			 */
1227 			if (retval == EINTR)
1228 				goto err0;
1229 
1230 			if (retval)
1231 				goto err0;
1232 			mtx_lock(&m->lock);
1233 			mtx_lock(&m->qlock);
1234 			m->wchan = 0;
1235 			if (!m->busy)
1236 				goto err1;
1237 		}
1238 
1239 		/*
1240 	         * We are certain than data can be placed on the queue
1241 	         */
1242 
1243 		used = MIN(MIDIQ_AVAIL(m->outq), len);
1244 		used = MIN(used, MIDI_WSIZE);
1245 		MIDI_DEBUG(5,
1246 		    printf("midi_synth: resid %zu len %jd avail %jd\n",
1247 		    len, (intmax_t)MIDIQ_LEN(m->outq),
1248 		    (intmax_t)MIDIQ_AVAIL(m->outq)));
1249 
1250 		if (midi_dumpraw)
1251 			for (i = 0; i < used; i++)
1252 				printf("%x ", buf[i]);
1253 
1254 		MIDIQ_ENQ(m->outq, buf, used);
1255 		len -= used;
1256 
1257 		/*
1258 	         * Inform the bottom half that data can be written
1259 	         */
1260 		if (!(m->flags & M_TXEN)) {
1261 			m->flags |= M_TXEN;
1262 			MPU_CALLBACK(m, m->cookie, m->flags);
1263 		}
1264 	}
1265 	/*
1266 	 * If we Made it here then transfer is good
1267 	 */
1268 	if (midi_dumpraw)
1269 		printf("\n");
1270 
1271 	retval = 0;
1272 err1:	mtx_unlock(&m->qlock);
1273 	mtx_unlock(&m->lock);
1274 err0:	return retval;
1275 }
1276 
1277 static int
1278 midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1279 {
1280 	u_char c[3];
1281 
1282 
1283 	if (note > 127 || chn > 15)
1284 		return (EINVAL);
1285 
1286 	if (vel > 127)
1287 		vel = 127;
1288 
1289 	if (vel == 64) {
1290 		c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1291 		c[1] = (u_char)note;
1292 		c[2] = 0;
1293 	} else {
1294 		c[0] = 0x80 | (chn & 0x0f);	/* Note off. */
1295 		c[1] = (u_char)note;
1296 		c[2] = (u_char)vel;
1297 	}
1298 
1299 	return midisynth_writeraw(n, c, 3);
1300 }
1301 
1302 static int
1303 midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1304 {
1305 	u_char c[2];
1306 
1307 	if (instr > 127 || chn > 15)
1308 		return EINVAL;
1309 
1310 	c[0] = 0xc0 | (chn & 0x0f);	/* Progamme change. */
1311 	c[1] = instr + midi_instroff;
1312 
1313 	return midisynth_writeraw(n, c, 2);
1314 }
1315 
1316 static int
1317 midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1318 {
1319 	u_char c[3];
1320 
1321 	if (note > 127 || chn > 15)
1322 		return EINVAL;
1323 
1324 	if (vel > 127)
1325 		vel = 127;
1326 
1327 	c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1328 	c[1] = (u_char)note;
1329 	c[2] = (u_char)vel;
1330 
1331 	return midisynth_writeraw(n, c, 3);
1332 }
1333 static int
1334 midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1335 {
1336 	return chan;
1337 }
1338 
1339 static int
1340 midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1341 {
1342 	u_char c[3];
1343 
1344 	if (ctrlnum > 127 || chn > 15)
1345 		return EINVAL;
1346 
1347 	c[0] = 0xb0 | (chn & 0x0f);	/* Control Message. */
1348 	c[1] = ctrlnum;
1349 	c[2] = val;
1350 	return midisynth_writeraw(n, c, 3);
1351 }
1352 
1353 static int
1354 midisynth_bender(void *n, uint8_t chn, uint16_t val)
1355 {
1356 	u_char c[3];
1357 
1358 
1359 	if (val > 16383 || chn > 15)
1360 		return EINVAL;
1361 
1362 	c[0] = 0xe0 | (chn & 0x0f);	/* Pitch bend. */
1363 	c[1] = (u_char)val & 0x7f;
1364 	c[2] = (u_char)(val >> 7) & 0x7f;
1365 
1366 	return midisynth_writeraw(n, c, 3);
1367 }
1368 
1369 /*
1370  * Single point of midi destructions.
1371  */
1372 static int
1373 midi_destroy(struct snd_midi *m, int midiuninit)
1374 {
1375 	sx_assert(&midistat_lock, SA_XLOCKED);
1376 	mtx_assert(&m->lock, MA_OWNED);
1377 
1378 	MIDI_DEBUG(3, printf("midi_destroy\n"));
1379 	m->dev->si_drv1 = NULL;
1380 	mtx_unlock(&m->lock);	/* XXX */
1381 	destroy_dev(m->dev);
1382 	TAILQ_REMOVE(&midi_devs, m, link);
1383 	if (midiuninit)
1384 		MPU_UNINIT(m, m->cookie);
1385 	free(MIDIQ_BUF(m->inq), M_MIDI);
1386 	free(MIDIQ_BUF(m->outq), M_MIDI);
1387 	mtx_destroy(&m->qlock);
1388 	mtx_destroy(&m->lock);
1389 	free(m->synth, M_MIDI);
1390 	free(m, M_MIDI);
1391 	return 0;
1392 }
1393 
1394 /*
1395  * Load and unload functions, creates the /dev/midistat device
1396  */
1397 
1398 static int
1399 midi_load(void)
1400 {
1401 	sx_init(&midistat_lock, "midistat lock");
1402 	TAILQ_INIT(&midi_devs);
1403 
1404 	midistat_dev = make_dev(&midistat_cdevsw,
1405 	    MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1406 	    UID_ROOT, GID_WHEEL, 0666, "midistat");
1407 
1408 	return 0;
1409 }
1410 
1411 static int
1412 midi_unload(void)
1413 {
1414 	struct snd_midi *m, *tmp;
1415 	int retval;
1416 
1417 	MIDI_DEBUG(1, printf("midi_unload()\n"));
1418 	retval = EBUSY;
1419 	sx_xlock(&midistat_lock);
1420 	if (midistat_isopen)
1421 		goto exit0;
1422 
1423 	TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
1424 		mtx_lock(&m->lock);
1425 		if (m->busy)
1426 			retval = EBUSY;
1427 		else
1428 			retval = midi_destroy(m, 1);
1429 		if (retval)
1430 			goto exit1;
1431 	}
1432 	sx_xunlock(&midistat_lock);
1433 	destroy_dev(midistat_dev);
1434 
1435 	/*
1436 	 * Made it here then unload is complete
1437 	 */
1438 	sx_destroy(&midistat_lock);
1439 	return 0;
1440 
1441 exit1:
1442 	mtx_unlock(&m->lock);
1443 exit0:
1444 	sx_xunlock(&midistat_lock);
1445 	if (retval)
1446 		MIDI_DEBUG(2, printf("midi_unload: failed\n"));
1447 	return retval;
1448 }
1449 
1450 extern int seq_modevent(module_t mod, int type, void *data);
1451 
1452 static int
1453 midi_modevent(module_t mod, int type, void *data)
1454 {
1455 	int retval;
1456 
1457 	retval = 0;
1458 
1459 	switch (type) {
1460 	case MOD_LOAD:
1461 		retval = midi_load();
1462 		if (retval == 0)
1463 			retval = seq_modevent(mod, type, data);
1464 		break;
1465 
1466 	case MOD_UNLOAD:
1467 		retval = midi_unload();
1468 		if (retval == 0)
1469 			retval = seq_modevent(mod, type, data);
1470 		break;
1471 
1472 	default:
1473 		break;
1474 	}
1475 
1476 	return retval;
1477 }
1478 
1479 kobj_t
1480 midimapper_addseq(void *arg1, int *unit, void **cookie)
1481 {
1482 	unit = NULL;
1483 
1484 	return (kobj_t)arg1;
1485 }
1486 
1487 int
1488 midimapper_open(void *arg1, void **cookie)
1489 {
1490 	int retval = 0;
1491 	struct snd_midi *m;
1492 
1493 	sx_xlock(&midistat_lock);
1494 	TAILQ_FOREACH(m, &midi_devs, link) {
1495 		retval++;
1496 	}
1497 	sx_xunlock(&midistat_lock);
1498 	return retval;
1499 }
1500 
1501 int
1502 midimapper_close(void *arg1, void *cookie)
1503 {
1504 	return 0;
1505 }
1506 
1507 kobj_t
1508 midimapper_fetch_synth(void *arg, void *cookie, int unit)
1509 {
1510 	struct snd_midi *m;
1511 	int retval = 0;
1512 
1513 	sx_xlock(&midistat_lock);
1514 	TAILQ_FOREACH(m, &midi_devs, link) {
1515 		if (unit == retval) {
1516 			sx_xunlock(&midistat_lock);
1517 			return (kobj_t)m->synth;
1518 		}
1519 		retval++;
1520 	}
1521 	sx_xunlock(&midistat_lock);
1522 	return NULL;
1523 }
1524 
1525 DEV_MODULE(midi, midi_modevent, NULL);
1526 MODULE_VERSION(midi, 1);
1527