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