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