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