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