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