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