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