1158979Snetchild/*-
2166322Sjoel * Copyright (c) 2003 Mathew Kanner
3158979Snetchild * Copyright (c) 1998 The NetBSD Foundation, Inc.
4158979Snetchild * All rights reserved.
5158979Snetchild *
6158979Snetchild * This code is derived from software contributed to The NetBSD Foundation
7158979Snetchild * by Lennart Augustsson (augustss@netbsd.org).
8158979Snetchild *
9158979Snetchild * Redistribution and use in source and binary forms, with or without
10158979Snetchild * modification, are permitted provided that the following conditions
11158979Snetchild * are met:
12158979Snetchild * 1. Redistributions of source code must retain the above copyright
13158979Snetchild *    notice, this list of conditions and the following disclaimer.
14158979Snetchild * 2. Redistributions in binary form must reproduce the above copyright
15158979Snetchild *    notice, this list of conditions and the following disclaimer in the
16158979Snetchild *    documentation and/or other materials provided with the distribution.
17158979Snetchild *
18158979Snetchild * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19158979Snetchild * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20158979Snetchild * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21158979Snetchild * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22158979Snetchild * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23158979Snetchild * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24158979Snetchild * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25158979Snetchild * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26158979Snetchild * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27158979Snetchild * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28158979Snetchild * POSSIBILITY OF SUCH DAMAGE.
29158979Snetchild */
30158979Snetchild
31158979Snetchild /*
32158979Snetchild  * Parts of this file started out as NetBSD: midi.c 1.31
33158979Snetchild  * They are mostly gone.  Still the most obvious will be the state
34158979Snetchild  * machine midi_in
35158979Snetchild  */
36158979Snetchild
37158979Snetchild#include <sys/cdefs.h>
38158979Snetchild__FBSDID("$FreeBSD$");
39158979Snetchild
40158979Snetchild#include <sys/param.h>
41158979Snetchild#include <sys/queue.h>
42158979Snetchild#include <sys/kernel.h>
43158979Snetchild#include <sys/lock.h>
44158979Snetchild#include <sys/mutex.h>
45158979Snetchild#include <sys/proc.h>
46158979Snetchild#include <sys/signalvar.h>
47158979Snetchild#include <sys/conf.h>
48158979Snetchild#include <sys/selinfo.h>
49158979Snetchild#include <sys/sysctl.h>
50158979Snetchild#include <sys/types.h>
51158979Snetchild#include <sys/malloc.h>
52158979Snetchild#include <sys/param.h>
53158979Snetchild#include <sys/systm.h>
54158979Snetchild#include <sys/proc.h>
55158979Snetchild#include <sys/fcntl.h>
56158979Snetchild#include <sys/types.h>
57158979Snetchild#include <sys/uio.h>
58158979Snetchild#include <sys/poll.h>
59158979Snetchild#include <sys/sbuf.h>
60158979Snetchild#include <sys/kobj.h>
61158979Snetchild#include <sys/module.h>
62158979Snetchild
63193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
64193640Sariff#include "opt_snd.h"
65193640Sariff#endif
66193640Sariff
67158979Snetchild#include <dev/sound/midi/midi.h>
68158979Snetchild#include "mpu_if.h"
69158979Snetchild
70158979Snetchild#include <dev/sound/midi/midiq.h>
71158979Snetchild#include "synth_if.h"
72158979SnetchildMALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
73158979Snetchild
74193979Sariff#ifndef KOBJMETHOD_END
75193979Sariff#define KOBJMETHOD_END	{ NULL, NULL }
76193979Sariff#endif
77158979Snetchild
78158979Snetchild#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
79158979Snetchild#define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
80158979Snetchild
81158979Snetchild#define MIDI_DEV_RAW	2
82158979Snetchild#define MIDI_DEV_MIDICTL 12
83158979Snetchild
84158979Snetchildenum midi_states {
85158979Snetchild	MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
86158979Snetchild};
87158979Snetchild
88158979Snetchild/*
89158979Snetchild * The MPU interface current has init() uninit() inqsize(( outqsize()
90158979Snetchild * callback() : fiddle with the tx|rx status.
91158979Snetchild */
92158979Snetchild
93158979Snetchild#include "mpu_if.h"
94158979Snetchild
95158979Snetchild/*
96158979Snetchild * /dev/rmidi	Structure definitions
97158979Snetchild */
98158979Snetchild
99158979Snetchild#define MIDI_NAMELEN   16
100158979Snetchildstruct snd_midi {
101158979Snetchild	KOBJ_FIELDS;
102166971Snetchild	struct mtx lock;		/* Protects all but queues */
103166971Snetchild	void   *cookie;
104158979Snetchild
105166971Snetchild	int	unit;			/* Should only be used in midistat */
106166971Snetchild	int	channel;		/* Should only be used in midistat */
107158979Snetchild
108166971Snetchild	int	busy;
109166971Snetchild	int	flags;			/* File flags */
110166971Snetchild	char	name[MIDI_NAMELEN];
111166971Snetchild	struct mtx qlock;		/* Protects inq, outq and flags */
112166971Snetchild	MIDIQ_HEAD(, char) inq, outq;
113166971Snetchild	int	rchan, wchan;
114166971Snetchild	struct selinfo rsel, wsel;
115166971Snetchild	int	hiwat;			/* QLEN(outq)>High-water -> disable
116166971Snetchild					 * writes from userland */
117158979Snetchild	enum midi_states inq_state;
118166971Snetchild	int	inq_status, inq_left;	/* Variables for the state machine in
119166971Snetchild					 * Midi_in, this is to provide that
120166971Snetchild					 * signals only get issued only
121166971Snetchild					 * complete command packets. */
122166971Snetchild	struct proc *async;
123166971Snetchild	struct cdev *dev;
124158979Snetchild	struct synth_midi *synth;
125166971Snetchild	int	synth_flags;
126158979Snetchild	TAILQ_ENTRY(snd_midi) link;
127158979Snetchild};
128158979Snetchild
129158979Snetchildstruct synth_midi {
130166971Snetchild	KOBJ_FIELDS;
131166971Snetchild	struct snd_midi *m;
132158979Snetchild};
133158979Snetchild
134158979Snetchildstatic synth_open_t midisynth_open;
135158979Snetchildstatic synth_close_t midisynth_close;
136158979Snetchildstatic synth_writeraw_t midisynth_writeraw;
137158979Snetchildstatic synth_killnote_t midisynth_killnote;
138158979Snetchildstatic synth_startnote_t midisynth_startnote;
139158979Snetchildstatic synth_setinstr_t midisynth_setinstr;
140158979Snetchildstatic synth_alloc_t midisynth_alloc;
141158979Snetchildstatic synth_controller_t midisynth_controller;
142158979Snetchildstatic synth_bender_t midisynth_bender;
143158979Snetchild
144158979Snetchild
145158979Snetchildstatic kobj_method_t midisynth_methods[] = {
146166971Snetchild	KOBJMETHOD(synth_open, midisynth_open),
147166971Snetchild	KOBJMETHOD(synth_close, midisynth_close),
148166971Snetchild	KOBJMETHOD(synth_writeraw, midisynth_writeraw),
149166971Snetchild	KOBJMETHOD(synth_setinstr, midisynth_setinstr),
150166971Snetchild	KOBJMETHOD(synth_startnote, midisynth_startnote),
151166971Snetchild	KOBJMETHOD(synth_killnote, midisynth_killnote),
152166971Snetchild	KOBJMETHOD(synth_alloc, midisynth_alloc),
153166971Snetchild	KOBJMETHOD(synth_controller, midisynth_controller),
154166971Snetchild	KOBJMETHOD(synth_bender, midisynth_bender),
155193640Sariff	KOBJMETHOD_END
156158979Snetchild};
157158979Snetchild
158158979SnetchildDEFINE_CLASS(midisynth, midisynth_methods, 0);
159158979Snetchild
160158979Snetchild/*
161158979Snetchild * Module Exports & Interface
162166971Snetchild *
163158979Snetchild * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan) int
164158979Snetchild * midi_uninit(struct snd_midi *) 0 == no error EBUSY or other error int
165158979Snetchild * Midi_in(struct midi_chan *, char *buf, int count) int Midi_out(struct
166158979Snetchild * midi_chan *, char *buf, int count)
167166971Snetchild *
168158979Snetchild * midi_{in,out} return actual size transfered
169166971Snetchild *
170158979Snetchild */
171158979Snetchild
172158979Snetchild
173158979Snetchild/*
174158979Snetchild * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
175158979Snetchild */
176158979Snetchild
177158979SnetchildTAILQ_HEAD(, snd_midi) midi_devs;
178158979Snetchild
179158979Snetchild/*
180158979Snetchild * /dev/midistat variables and declarations, protected by midistat_lock
181158979Snetchild */
182158979Snetchild
183158979Snetchildstatic struct mtx midistat_lock;
184158979Snetchildstatic int      midistat_isopen = 0;
185158979Snetchildstatic struct sbuf midistat_sbuf;
186158979Snetchildstatic int      midistat_bufptr;
187158979Snetchildstatic struct cdev *midistat_dev;
188158979Snetchild
189158979Snetchild/*
190158979Snetchild * /dev/midistat	dev_t declarations
191158979Snetchild */
192158979Snetchild
193158979Snetchildstatic d_open_t midistat_open;
194158979Snetchildstatic d_close_t midistat_close;
195158979Snetchildstatic d_read_t midistat_read;
196158979Snetchild
197158979Snetchildstatic struct cdevsw midistat_cdevsw = {
198158979Snetchild	.d_version = D_VERSION,
199158979Snetchild	.d_open = midistat_open,
200158979Snetchild	.d_close = midistat_close,
201158979Snetchild	.d_read = midistat_read,
202158979Snetchild	.d_name = "midistat",
203158979Snetchild};
204158979Snetchild
205158979Snetchild
206158979Snetchild/*
207158979Snetchild * /dev/rmidi dev_t declarations, struct variable access is protected by
208158979Snetchild * locks contained within the structure.
209158979Snetchild */
210158979Snetchild
211158979Snetchildstatic d_open_t midi_open;
212158979Snetchildstatic d_close_t midi_close;
213158979Snetchildstatic d_ioctl_t midi_ioctl;
214158979Snetchildstatic d_read_t midi_read;
215158979Snetchildstatic d_write_t midi_write;
216158979Snetchildstatic d_poll_t midi_poll;
217158979Snetchild
218158979Snetchildstatic struct cdevsw midi_cdevsw = {
219158979Snetchild	.d_version = D_VERSION,
220158979Snetchild	.d_open = midi_open,
221158979Snetchild	.d_close = midi_close,
222158979Snetchild	.d_read = midi_read,
223158979Snetchild	.d_write = midi_write,
224158979Snetchild	.d_ioctl = midi_ioctl,
225158979Snetchild	.d_poll = midi_poll,
226158979Snetchild	.d_name = "rmidi",
227158979Snetchild};
228158979Snetchild
229158979Snetchild/*
230158979Snetchild * Prototypes of library functions
231158979Snetchild */
232158979Snetchild
233158979Snetchildstatic int      midi_destroy(struct snd_midi *, int);
234158979Snetchildstatic int      midistat_prepare(struct sbuf * s);
235158979Snetchildstatic int      midi_load(void);
236158979Snetchildstatic int      midi_unload(void);
237158979Snetchild
238158979Snetchild/*
239158979Snetchild * Misc declr.
240158979Snetchild */
241158979SnetchildSYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
242248085Smariusstatic SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device");
243158979Snetchild
244158979Snetchildint             midi_debug;
245159732Snetchild/* XXX: should this be moved into debug.midi? */
246158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
247158979Snetchild
248158979Snetchildint             midi_dumpraw;
249158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
250158979Snetchild
251158979Snetchildint             midi_instroff;
252158979SnetchildSYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
253158979Snetchild
254158979Snetchildint             midistat_verbose;
255158979SnetchildSYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
256158979Snetchild	&midistat_verbose, 0, "");
257158979Snetchild
258158979Snetchild#define MIDI_DEBUG(l,a)	if(midi_debug>=l) a
259158979Snetchild/*
260158979Snetchild * CODE START
261158979Snetchild */
262158979Snetchild
263158979Snetchild/*
264158979Snetchild * Register a new rmidi device. cls midi_if interface unit == 0 means
265158979Snetchild * auto-assign new unit number unit != 0 already assigned a unit number, eg.
266158979Snetchild * not the first channel provided by this device. channel,	sub-unit
267158979Snetchild * cookie is passed back on MPU calls Typical device drivers will call with
268158979Snetchild * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
269158979Snetchild * what unit number is used.
270166971Snetchild *
271158979Snetchild * It is an error to call midi_init with an already used unit/channel combo.
272166971Snetchild *
273158979Snetchild * Returns NULL on error
274166971Snetchild *
275158979Snetchild */
276158979Snetchildstruct snd_midi *
277158979Snetchildmidi_init(kobj_class_t cls, int unit, int channel, void *cookie)
278158979Snetchild{
279158979Snetchild	struct snd_midi *m;
280166971Snetchild	int i;
281166971Snetchild	int inqsize, outqsize;
282166971Snetchild	MIDI_TYPE *buf;
283158979Snetchild
284166971Snetchild	MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
285158979Snetchild	mtx_lock(&midistat_lock);
286158979Snetchild	/*
287158979Snetchild	 * Protect against call with existing unit/channel or auto-allocate a
288158979Snetchild	 * new unit number.
289158979Snetchild	 */
290158979Snetchild	i = -1;
291158979Snetchild	TAILQ_FOREACH(m, &midi_devs, link) {
292166971Snetchild		mtx_lock(&m->lock);
293166971Snetchild		if (unit != 0) {
294166971Snetchild			if (m->unit == unit && m->channel == channel) {
295166971Snetchild				mtx_unlock(&m->lock);
296166971Snetchild				goto err0;
297166971Snetchild			}
298166971Snetchild		} else {
299166971Snetchild			/*
300166971Snetchild			 * Find a better unit number
301166971Snetchild			 */
302166971Snetchild			if (m->unit > i)
303166971Snetchild				i = m->unit;
304158979Snetchild		}
305166971Snetchild		mtx_unlock(&m->lock);
306158979Snetchild	}
307158979Snetchild
308158979Snetchild	if (unit == 0)
309166971Snetchild		unit = i + 1;
310158979Snetchild
311158979Snetchild	MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
312158979Snetchild	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
313158979Snetchild	if (m == NULL)
314166971Snetchild		goto err0;
315158979Snetchild
316158979Snetchild	m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO);
317158979Snetchild	kobj_init((kobj_t)m->synth, &midisynth_class);
318158979Snetchild	m->synth->m = m;
319158979Snetchild	kobj_init((kobj_t)m, cls);
320158979Snetchild	inqsize = MPU_INQSIZE(m, cookie);
321158979Snetchild	outqsize = MPU_OUTQSIZE(m, cookie);
322158979Snetchild
323158979Snetchild	MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
324158979Snetchild	if (!inqsize && !outqsize)
325166971Snetchild		goto err1;
326158979Snetchild
327167604Sariff	mtx_init(&m->lock, "raw midi", NULL, 0);
328167604Sariff	mtx_init(&m->qlock, "q raw midi", NULL, 0);
329158979Snetchild
330158979Snetchild	mtx_lock(&m->lock);
331158979Snetchild	mtx_lock(&m->qlock);
332158979Snetchild
333158979Snetchild	if (inqsize)
334166971Snetchild		buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
335158979Snetchild	else
336166971Snetchild		buf = NULL;
337158979Snetchild
338158979Snetchild	MIDIQ_INIT(m->inq, buf, inqsize);
339158979Snetchild
340158979Snetchild	if (outqsize)
341166971Snetchild		buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
342158979Snetchild	else
343166971Snetchild		buf = NULL;
344158979Snetchild	m->hiwat = outqsize / 2;
345158979Snetchild
346158979Snetchild	MIDIQ_INIT(m->outq, buf, outqsize);
347158979Snetchild
348158979Snetchild	if ((inqsize && !MIDIQ_BUF(m->inq)) ||
349158979Snetchild	    (outqsize && !MIDIQ_BUF(m->outq)))
350166971Snetchild		goto err2;
351158979Snetchild
352158979Snetchild
353158979Snetchild	m->busy = 0;
354158979Snetchild	m->flags = 0;
355158979Snetchild	m->unit = unit;
356158979Snetchild	m->channel = channel;
357158979Snetchild	m->cookie = cookie;
358158979Snetchild
359158979Snetchild	if (MPU_INIT(m, cookie))
360166971Snetchild		goto err2;
361158979Snetchild
362158979Snetchild	mtx_unlock(&m->lock);
363158979Snetchild	mtx_unlock(&m->qlock);
364158979Snetchild
365158979Snetchild	TAILQ_INSERT_TAIL(&midi_devs, m, link);
366158979Snetchild
367158979Snetchild	mtx_unlock(&midistat_lock);
368158979Snetchild
369158979Snetchild	m->dev = make_dev(&midi_cdevsw,
370166971Snetchild	    MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
371166971Snetchild	    UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
372158979Snetchild	m->dev->si_drv1 = m;
373158979Snetchild
374158979Snetchild	return m;
375158979Snetchild
376158979Snetchilderr2:	mtx_destroy(&m->qlock);
377158979Snetchild	mtx_destroy(&m->lock);
378158979Snetchild
379158979Snetchild	if (MIDIQ_BUF(m->inq))
380166971Snetchild		free(MIDIQ_BUF(m->inq), M_MIDI);
381158979Snetchild	if (MIDIQ_BUF(m->outq))
382166971Snetchild		free(MIDIQ_BUF(m->outq), M_MIDI);
383158979Snetchilderr1:	free(m, M_MIDI);
384158979Snetchilderr0:	mtx_unlock(&midistat_lock);
385158979Snetchild	MIDI_DEBUG(1, printf("midi_init ended in error\n"));
386158979Snetchild	return NULL;
387158979Snetchild}
388158979Snetchild
389158979Snetchild/*
390158979Snetchild * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
391158979Snetchild * entry point. midi_unint if fact, does not send any methods. A call to
392158979Snetchild * midi_uninit is a defacto promise that you won't manipulate ch anymore
393166971Snetchild *
394158979Snetchild */
395158979Snetchild
396158979Snetchildint
397166971Snetchildmidi_uninit(struct snd_midi *m)
398158979Snetchild{
399166971Snetchild	int err;
400158979Snetchild
401158979Snetchild	err = ENXIO;
402158979Snetchild	mtx_lock(&midistat_lock);
403158979Snetchild	mtx_lock(&m->lock);
404158979Snetchild	if (m->busy) {
405166971Snetchild		if (!(m->rchan || m->wchan))
406166971Snetchild			goto err;
407158979Snetchild
408166971Snetchild		if (m->rchan) {
409166971Snetchild			wakeup(&m->rchan);
410166971Snetchild			m->rchan = 0;
411166971Snetchild		}
412166971Snetchild		if (m->wchan) {
413166971Snetchild			wakeup(&m->wchan);
414166971Snetchild			m->wchan = 0;
415166971Snetchild		}
416158979Snetchild	}
417158979Snetchild	err = midi_destroy(m, 0);
418166971Snetchild	if (!err)
419158979Snetchild		goto exit;
420158979Snetchild
421158979Snetchilderr:	mtx_unlock(&m->lock);
422158979Snetchildexit:	mtx_unlock(&midistat_lock);
423158979Snetchild	return err;
424158979Snetchild}
425158979Snetchild
426158979Snetchild/*
427158979Snetchild * midi_in: process all data until the queue is full, then discards the rest.
428158979Snetchild * Since midi_in is a state machine, data discards can cause it to get out of
429158979Snetchild * whack.  Process as much as possible.  It calls, wakeup, selnotify and
430158979Snetchild * psignal at most once.
431158979Snetchild */
432158979Snetchild
433159042Sru#ifdef notdef
434166971Snetchildstatic int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
435166971Snetchild
436166971Snetchild#endif					/* notdef */
437158979Snetchild/* Number of bytes in a MIDI command */
438158979Snetchild#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
439158979Snetchild#define MIDI_ACK	0xfe
440158979Snetchild#define MIDI_IS_STATUS(d) ((d) >= 0x80)
441158979Snetchild#define MIDI_IS_COMMON(d) ((d) >= 0xf0)
442158979Snetchild
443158979Snetchild#define MIDI_SYSEX_START	0xF0
444158979Snetchild#define MIDI_SYSEX_END	    0xF7
445158979Snetchild
446158979Snetchild
447158979Snetchildint
448166971Snetchildmidi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
449158979Snetchild{
450158979Snetchild	/* int             i, sig, enq; */
451166971Snetchild	int used;
452166971Snetchild
453158979Snetchild	/* MIDI_TYPE       data; */
454158979Snetchild	MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
455158979Snetchild
456158979Snetchild/*
457158979Snetchild * XXX: locking flub
458158979Snetchild */
459158979Snetchild	if (!(m->flags & M_RX))
460166971Snetchild		return size;
461158979Snetchild
462158979Snetchild	used = 0;
463158979Snetchild
464158979Snetchild	mtx_lock(&m->qlock);
465158979Snetchild#if 0
466158979Snetchild	/*
467158979Snetchild	 * Don't bother queuing if not in read mode.  Discard everything and
468158979Snetchild	 * return size so the caller doesn't freak out.
469158979Snetchild	 */
470158979Snetchild
471158979Snetchild	if (!(m->flags & M_RX))
472166971Snetchild		return size;
473158979Snetchild
474158979Snetchild	for (i = sig = 0; i < size; i++) {
475158979Snetchild
476166971Snetchild		data = buf[i];
477166971Snetchild		enq = 0;
478166971Snetchild		if (data == MIDI_ACK)
479166971Snetchild			continue;
480158979Snetchild
481166971Snetchild		switch (m->inq_state) {
482166971Snetchild		case MIDI_IN_START:
483166971Snetchild			if (MIDI_IS_STATUS(data)) {
484166971Snetchild				switch (data) {
485166971Snetchild				case 0xf0:	/* Sysex */
486166971Snetchild					m->inq_state = MIDI_IN_SYSEX;
487166971Snetchild					break;
488166971Snetchild				case 0xf1:	/* MTC quarter frame */
489166971Snetchild				case 0xf3:	/* Song select */
490166971Snetchild					m->inq_state = MIDI_IN_DATA;
491166971Snetchild					enq = 1;
492166971Snetchild					m->inq_left = 1;
493166971Snetchild					break;
494166971Snetchild				case 0xf2:	/* Song position pointer */
495166971Snetchild					m->inq_state = MIDI_IN_DATA;
496166971Snetchild					enq = 1;
497166971Snetchild					m->inq_left = 2;
498166971Snetchild					break;
499166971Snetchild				default:
500166971Snetchild					if (MIDI_IS_COMMON(data)) {
501166971Snetchild						enq = 1;
502166971Snetchild						sig = 1;
503166971Snetchild					} else {
504166971Snetchild						m->inq_state = MIDI_IN_DATA;
505166971Snetchild						enq = 1;
506166971Snetchild						m->inq_status = data;
507166971Snetchild						m->inq_left = MIDI_LENGTH(data);
508166971Snetchild					}
509166971Snetchild					break;
510166971Snetchild				}
511166971Snetchild			} else if (MIDI_IS_STATUS(m->inq_status)) {
512166971Snetchild				m->inq_state = MIDI_IN_DATA;
513166971Snetchild				if (!MIDIQ_FULL(m->inq)) {
514166971Snetchild					used++;
515166971Snetchild					MIDIQ_ENQ(m->inq, &m->inq_status, 1);
516166971Snetchild				}
517166971Snetchild				enq = 1;
518166971Snetchild				m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
519166971Snetchild			}
520158979Snetchild			break;
521166971Snetchild			/*
522166971Snetchild			 * End of case MIDI_IN_START:
523166971Snetchild			 */
524166971Snetchild
525166971Snetchild		case MIDI_IN_DATA:
526158979Snetchild			enq = 1;
527166971Snetchild			if (--m->inq_left <= 0)
528166971Snetchild				sig = 1;/* deliver data */
529158979Snetchild			break;
530166971Snetchild		case MIDI_IN_SYSEX:
531166971Snetchild			if (data == MIDI_SYSEX_END)
532166971Snetchild				m->inq_state = MIDI_IN_START;
533158979Snetchild			break;
534166971Snetchild		}
535166971Snetchild
536166971Snetchild		if (enq)
537166971Snetchild			if (!MIDIQ_FULL(m->inq)) {
538166971Snetchild				MIDIQ_ENQ(m->inq, &data, 1);
539166971Snetchild				used++;
540158979Snetchild			}
541158979Snetchild		/*
542166971Snetchild	         * End of the state machines main "for loop"
543166971Snetchild	         */
544158979Snetchild	}
545158979Snetchild	if (sig) {
546158979Snetchild#endif
547166971Snetchild		MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
548166971Snetchild		    (intmax_t)MIDIQ_LEN(m->inq),
549166971Snetchild		    (intmax_t)MIDIQ_AVAIL(m->inq)));
550166971Snetchild		if (MIDIQ_AVAIL(m->inq) > size) {
551166971Snetchild			used = size;
552166971Snetchild			MIDIQ_ENQ(m->inq, buf, size);
553166971Snetchild		} else {
554166971Snetchild			MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
555166971Snetchild			mtx_unlock(&m->qlock);
556166971Snetchild			return 0;
557166971Snetchild		}
558166971Snetchild		if (m->rchan) {
559166971Snetchild			wakeup(&m->rchan);
560166971Snetchild			m->rchan = 0;
561166971Snetchild		}
562166971Snetchild		selwakeup(&m->rsel);
563166971Snetchild		if (m->async) {
564166971Snetchild			PROC_LOCK(m->async);
565225617Skmacy			kern_psignal(m->async, SIGIO);
566166971Snetchild			PROC_UNLOCK(m->async);
567166971Snetchild		}
568158979Snetchild#if 0
569158979Snetchild	}
570158979Snetchild#endif
571158979Snetchild	mtx_unlock(&m->qlock);
572158979Snetchild	return used;
573158979Snetchild}
574158979Snetchild
575158979Snetchild/*
576158979Snetchild * midi_out: The only clearer of the M_TXEN flag.
577158979Snetchild */
578158979Snetchildint
579166971Snetchildmidi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
580158979Snetchild{
581166971Snetchild	int used;
582158979Snetchild
583158979Snetchild/*
584158979Snetchild * XXX: locking flub
585158979Snetchild */
586158979Snetchild	if (!(m->flags & M_TXEN))
587158979Snetchild		return 0;
588158979Snetchild
589166971Snetchild	MIDI_DEBUG(2, printf("midi_out: %p\n", m));
590158979Snetchild	mtx_lock(&m->qlock);
591158979Snetchild	used = MIN(size, MIDIQ_LEN(m->outq));
592158979Snetchild	MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
593158979Snetchild	if (used)
594166971Snetchild		MIDIQ_DEQ(m->outq, buf, used);
595158979Snetchild	if (MIDIQ_EMPTY(m->outq)) {
596166971Snetchild		m->flags &= ~M_TXEN;
597166971Snetchild		MPU_CALLBACKP(m, m->cookie, m->flags);
598158979Snetchild	}
599166971Snetchild	if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
600158979Snetchild		if (m->wchan) {
601158979Snetchild			wakeup(&m->wchan);
602158979Snetchild			m->wchan = 0;
603158979Snetchild		}
604158979Snetchild		selwakeup(&m->wsel);
605166971Snetchild		if (m->async) {
606158979Snetchild			PROC_LOCK(m->async);
607225617Skmacy			kern_psignal(m->async, SIGIO);
608158979Snetchild			PROC_UNLOCK(m->async);
609158979Snetchild		}
610158979Snetchild	}
611158979Snetchild	mtx_unlock(&m->qlock);
612158979Snetchild	return used;
613158979Snetchild}
614158979Snetchild
615158979Snetchild
616158979Snetchild/*
617158979Snetchild * /dev/rmidi#.#	device access functions
618158979Snetchild */
619158979Snetchildint
620166971Snetchildmidi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
621158979Snetchild{
622158979Snetchild	struct snd_midi *m = i_dev->si_drv1;
623166971Snetchild	int retval;
624158979Snetchild
625166971Snetchild	MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
626166971Snetchild	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
627158979Snetchild	if (m == NULL)
628166971Snetchild		return ENXIO;
629158979Snetchild
630158979Snetchild	mtx_lock(&m->lock);
631158979Snetchild	mtx_lock(&m->qlock);
632158979Snetchild
633158979Snetchild	retval = 0;
634158979Snetchild
635158979Snetchild	if (flags & FREAD) {
636166971Snetchild		if (MIDIQ_SIZE(m->inq) == 0)
637166971Snetchild			retval = ENXIO;
638166971Snetchild		else if (m->flags & M_RX)
639166971Snetchild			retval = EBUSY;
640166971Snetchild		if (retval)
641166971Snetchild			goto err;
642158979Snetchild	}
643158979Snetchild	if (flags & FWRITE) {
644166971Snetchild		if (MIDIQ_SIZE(m->outq) == 0)
645166971Snetchild			retval = ENXIO;
646166971Snetchild		else if (m->flags & M_TX)
647166971Snetchild			retval = EBUSY;
648166971Snetchild		if (retval)
649166971Snetchild			goto err;
650158979Snetchild	}
651158979Snetchild	m->busy++;
652158979Snetchild
653158979Snetchild	m->rchan = 0;
654158979Snetchild	m->wchan = 0;
655158979Snetchild	m->async = 0;
656158979Snetchild
657158979Snetchild	if (flags & FREAD) {
658166971Snetchild		m->flags |= M_RX | M_RXEN;
659166971Snetchild		/*
660166971Snetchild	         * Only clear the inq, the outq might still have data to drain
661166971Snetchild	         * from a previous session
662166971Snetchild	         */
663166971Snetchild		MIDIQ_CLEAR(m->inq);
664158979Snetchild	};
665158979Snetchild
666158979Snetchild	if (flags & FWRITE)
667166971Snetchild		m->flags |= M_TX;
668158979Snetchild
669158979Snetchild	MPU_CALLBACK(m, m->cookie, m->flags);
670158979Snetchild
671158979Snetchild	MIDI_DEBUG(2, printf("midi_open: opened.\n"));
672158979Snetchild
673158979Snetchilderr:	mtx_unlock(&m->qlock);
674158979Snetchild	mtx_unlock(&m->lock);
675158979Snetchild	return retval;
676158979Snetchild}
677158979Snetchild
678158979Snetchildint
679166971Snetchildmidi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
680158979Snetchild{
681158979Snetchild	struct snd_midi *m = i_dev->si_drv1;
682166971Snetchild	int retval;
683166971Snetchild	int oldflags;
684158979Snetchild
685158979Snetchild	MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
686166971Snetchild	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
687158979Snetchild
688158979Snetchild	if (m == NULL)
689166971Snetchild		return ENXIO;
690158979Snetchild
691158979Snetchild	mtx_lock(&m->lock);
692158979Snetchild	mtx_lock(&m->qlock);
693158979Snetchild
694166971Snetchild	if ((flags & FREAD && !(m->flags & M_RX)) ||
695166971Snetchild	    (flags & FWRITE && !(m->flags & M_TX))) {
696166971Snetchild		retval = ENXIO;
697166971Snetchild		goto err;
698158979Snetchild	}
699158979Snetchild	m->busy--;
700158979Snetchild
701158979Snetchild	oldflags = m->flags;
702158979Snetchild
703158979Snetchild	if (flags & FREAD)
704166971Snetchild		m->flags &= ~(M_RX | M_RXEN);
705158979Snetchild	if (flags & FWRITE)
706166971Snetchild		m->flags &= ~M_TX;
707158979Snetchild
708166971Snetchild	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
709158979Snetchild		MPU_CALLBACK(m, m->cookie, m->flags);
710158979Snetchild
711158979Snetchild	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
712158979Snetchild
713158979Snetchild	mtx_unlock(&m->qlock);
714158979Snetchild	mtx_unlock(&m->lock);
715158979Snetchild	retval = 0;
716158979Snetchilderr:	return retval;
717158979Snetchild}
718166971Snetchild
719158979Snetchild/*
720166971Snetchild * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
721166971Snetchild * as data is available.
722158979Snetchild */
723158979Snetchildint
724166971Snetchildmidi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
725158979Snetchild{
726158979Snetchild#define MIDI_RSIZE 32
727158979Snetchild	struct snd_midi *m = i_dev->si_drv1;
728166971Snetchild	int retval;
729166971Snetchild	int used;
730166971Snetchild	char buf[MIDI_RSIZE];
731158979Snetchild
732166971Snetchild	MIDI_DEBUG(5, printf("midiread: count=%lu\n",
733166971Snetchild	    (unsigned long)uio->uio_resid));
734158979Snetchild
735158979Snetchild	retval = EIO;
736158979Snetchild
737158979Snetchild	if (m == NULL)
738166971Snetchild		goto err0;
739158979Snetchild
740158979Snetchild	mtx_lock(&m->lock);
741158979Snetchild	mtx_lock(&m->qlock);
742158979Snetchild
743158979Snetchild	if (!(m->flags & M_RX))
744166971Snetchild		goto err1;
745158979Snetchild
746158979Snetchild	while (uio->uio_resid > 0) {
747166971Snetchild		while (MIDIQ_EMPTY(m->inq)) {
748166971Snetchild			retval = EWOULDBLOCK;
749166971Snetchild			if (ioflag & O_NONBLOCK)
750166971Snetchild				goto err1;
751166971Snetchild			mtx_unlock(&m->lock);
752166971Snetchild			m->rchan = 1;
753166971Snetchild			retval = msleep(&m->rchan, &m->qlock,
754166971Snetchild			    PCATCH | PDROP, "midi RX", 0);
755166971Snetchild			/*
756166971Snetchild			 * We slept, maybe things have changed since last
757166971Snetchild			 * dying check
758166971Snetchild			 */
759166971Snetchild			if (retval == EINTR)
760166971Snetchild				goto err0;
761166971Snetchild			if (m != i_dev->si_drv1)
762166971Snetchild				retval = ENXIO;
763166971Snetchild			/* if (retval && retval != ERESTART) */
764166971Snetchild			if (retval)
765166971Snetchild				goto err0;
766166971Snetchild			mtx_lock(&m->lock);
767166971Snetchild			mtx_lock(&m->qlock);
768166971Snetchild			m->rchan = 0;
769166971Snetchild			if (!m->busy)
770166971Snetchild				goto err1;
771166971Snetchild		}
772166971Snetchild		MIDI_DEBUG(6, printf("midi_read start\n"));
773158979Snetchild		/*
774166971Snetchild	         * At this point, it is certain that m->inq has data
775166971Snetchild	         */
776158979Snetchild
777166971Snetchild		used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
778166971Snetchild		used = MIN(used, MIDI_RSIZE);
779158979Snetchild
780166971Snetchild		MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
781166971Snetchild		MIDIQ_DEQ(m->inq, buf, used);
782166971Snetchild		retval = uiomove(buf, used, uio);
783166971Snetchild		if (retval)
784166971Snetchild			goto err1;
785158979Snetchild	}
786158979Snetchild
787158979Snetchild	/*
788158979Snetchild	 * If we Made it here then transfer is good
789158979Snetchild	 */
790158979Snetchild	retval = 0;
791158979Snetchilderr1:	mtx_unlock(&m->qlock);
792158979Snetchild	mtx_unlock(&m->lock);
793166971Snetchilderr0:	MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
794158979Snetchild	return retval;
795158979Snetchild}
796158979Snetchild
797158979Snetchild/*
798158979Snetchild * midi_write: The only setter of M_TXEN
799158979Snetchild */
800158979Snetchild
801158979Snetchildint
802166971Snetchildmidi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
803158979Snetchild{
804158979Snetchild#define MIDI_WSIZE 32
805158979Snetchild	struct snd_midi *m = i_dev->si_drv1;
806166971Snetchild	int retval;
807166971Snetchild	int used;
808166971Snetchild	char buf[MIDI_WSIZE];
809158979Snetchild
810158979Snetchild
811166971Snetchild	MIDI_DEBUG(4, printf("midi_write\n"));
812158979Snetchild	retval = 0;
813158979Snetchild	if (m == NULL)
814166971Snetchild		goto err0;
815158979Snetchild
816158979Snetchild	mtx_lock(&m->lock);
817158979Snetchild	mtx_lock(&m->qlock);
818158979Snetchild
819158979Snetchild	if (!(m->flags & M_TX))
820166971Snetchild		goto err1;
821158979Snetchild
822158979Snetchild	while (uio->uio_resid > 0) {
823166971Snetchild		while (MIDIQ_AVAIL(m->outq) == 0) {
824166971Snetchild			retval = EWOULDBLOCK;
825166971Snetchild			if (ioflag & O_NONBLOCK)
826166971Snetchild				goto err1;
827166971Snetchild			mtx_unlock(&m->lock);
828166971Snetchild			m->wchan = 1;
829166971Snetchild			MIDI_DEBUG(3, printf("midi_write msleep\n"));
830166971Snetchild			retval = msleep(&m->wchan, &m->qlock,
831166971Snetchild			    PCATCH | PDROP, "midi TX", 0);
832166971Snetchild			/*
833166971Snetchild			 * We slept, maybe things have changed since last
834166971Snetchild			 * dying check
835166971Snetchild			 */
836166971Snetchild			if (retval == EINTR)
837166971Snetchild				goto err0;
838166971Snetchild			if (m != i_dev->si_drv1)
839166971Snetchild				retval = ENXIO;
840166971Snetchild			if (retval)
841166971Snetchild				goto err0;
842166971Snetchild			mtx_lock(&m->lock);
843166971Snetchild			mtx_lock(&m->qlock);
844166971Snetchild			m->wchan = 0;
845166971Snetchild			if (!m->busy)
846166971Snetchild				goto err1;
847166971Snetchild		}
848166971Snetchild
849158979Snetchild		/*
850166971Snetchild	         * We are certain than data can be placed on the queue
851166971Snetchild	         */
852158979Snetchild
853166971Snetchild		used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
854166971Snetchild		used = MIN(used, MIDI_WSIZE);
855194990Skib		MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
856166971Snetchild		    uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
857166971Snetchild		    (intmax_t)MIDIQ_AVAIL(m->outq)));
858158979Snetchild
859158979Snetchild
860166971Snetchild		MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
861166971Snetchild		retval = uiomove(buf, used, uio);
862166971Snetchild		if (retval)
863166971Snetchild			goto err1;
864166971Snetchild		MIDIQ_ENQ(m->outq, buf, used);
865166971Snetchild		/*
866166971Snetchild	         * Inform the bottom half that data can be written
867166971Snetchild	         */
868166971Snetchild		if (!(m->flags & M_TXEN)) {
869166971Snetchild			m->flags |= M_TXEN;
870166971Snetchild			MPU_CALLBACK(m, m->cookie, m->flags);
871166971Snetchild		}
872158979Snetchild	}
873158979Snetchild	/*
874158979Snetchild	 * If we Made it here then transfer is good
875158979Snetchild	 */
876158979Snetchild	retval = 0;
877158979Snetchilderr1:	mtx_unlock(&m->qlock);
878158979Snetchild	mtx_unlock(&m->lock);
879158979Snetchilderr0:	return retval;
880158979Snetchild}
881158979Snetchild
882158979Snetchildint
883166971Snetchildmidi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
884166971Snetchild    struct thread *td)
885158979Snetchild{
886158979Snetchild	return ENXIO;
887158979Snetchild}
888158979Snetchild
889158979Snetchildint
890166971Snetchildmidi_poll(struct cdev *i_dev, int events, struct thread *td)
891158979Snetchild{
892158979Snetchild	struct snd_midi *m = i_dev->si_drv1;
893166971Snetchild	int revents;
894158979Snetchild
895158979Snetchild	if (m == NULL)
896166971Snetchild		return 0;
897158979Snetchild
898158979Snetchild	revents = 0;
899158979Snetchild
900158979Snetchild	mtx_lock(&m->lock);
901158979Snetchild	mtx_lock(&m->qlock);
902158979Snetchild
903158979Snetchild	if (events & (POLLIN | POLLRDNORM))
904166971Snetchild		if (!MIDIQ_EMPTY(m->inq))
905166971Snetchild			events |= events & (POLLIN | POLLRDNORM);
906158979Snetchild
907158979Snetchild	if (events & (POLLOUT | POLLWRNORM))
908166971Snetchild		if (MIDIQ_AVAIL(m->outq) < m->hiwat)
909166971Snetchild			events |= events & (POLLOUT | POLLWRNORM);
910158979Snetchild
911158979Snetchild	if (revents == 0) {
912166971Snetchild		if (events & (POLLIN | POLLRDNORM))
913166971Snetchild			selrecord(td, &m->rsel);
914158979Snetchild
915166971Snetchild		if (events & (POLLOUT | POLLWRNORM))
916166971Snetchild			selrecord(td, &m->wsel);
917158979Snetchild	}
918158979Snetchild	mtx_unlock(&m->lock);
919158979Snetchild	mtx_unlock(&m->qlock);
920158979Snetchild
921158979Snetchild	return (revents);
922158979Snetchild}
923158979Snetchild
924158979Snetchild/*
925158979Snetchild * /dev/midistat device functions
926166971Snetchild *
927158979Snetchild */
928158979Snetchildstatic int
929166971Snetchildmidistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
930158979Snetchild{
931166971Snetchild	int error;
932158979Snetchild
933166971Snetchild	MIDI_DEBUG(1, printf("midistat_open\n"));
934158979Snetchild	mtx_lock(&midistat_lock);
935158979Snetchild
936158979Snetchild	if (midistat_isopen) {
937166971Snetchild		mtx_unlock(&midistat_lock);
938166971Snetchild		return EBUSY;
939158979Snetchild	}
940158979Snetchild	midistat_isopen = 1;
941166280Sariff	mtx_unlock(&midistat_lock);
942158979Snetchild
943166280Sariff	if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
944166971Snetchild		error = ENXIO;
945166971Snetchild		mtx_lock(&midistat_lock);
946166971Snetchild		goto out;
947158979Snetchild	}
948166280Sariff	mtx_lock(&midistat_lock);
949158979Snetchild	midistat_bufptr = 0;
950158979Snetchild	error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
951158979Snetchild
952158979Snetchildout:	if (error)
953166971Snetchild		midistat_isopen = 0;
954158979Snetchild	mtx_unlock(&midistat_lock);
955158979Snetchild	return error;
956158979Snetchild}
957158979Snetchild
958158979Snetchildstatic int
959166971Snetchildmidistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
960158979Snetchild{
961166971Snetchild	MIDI_DEBUG(1, printf("midistat_close\n"));
962158979Snetchild	mtx_lock(&midistat_lock);
963158979Snetchild	if (!midistat_isopen) {
964166971Snetchild		mtx_unlock(&midistat_lock);
965166971Snetchild		return EBADF;
966158979Snetchild	}
967158979Snetchild	sbuf_delete(&midistat_sbuf);
968158979Snetchild	midistat_isopen = 0;
969158979Snetchild
970158979Snetchild	mtx_unlock(&midistat_lock);
971158979Snetchild	return 0;
972158979Snetchild}
973158979Snetchild
974158979Snetchildstatic int
975166971Snetchildmidistat_read(struct cdev *i_dev, struct uio *buf, int flag)
976158979Snetchild{
977166971Snetchild	int l, err;
978158979Snetchild
979166971Snetchild	MIDI_DEBUG(4, printf("midistat_read\n"));
980158979Snetchild	mtx_lock(&midistat_lock);
981158979Snetchild	if (!midistat_isopen) {
982166971Snetchild		mtx_unlock(&midistat_lock);
983166971Snetchild		return EBADF;
984158979Snetchild	}
985158979Snetchild	l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr);
986158979Snetchild	err = 0;
987166280Sariff	if (l > 0) {
988166971Snetchild		mtx_unlock(&midistat_lock);
989166971Snetchild		err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l,
990166971Snetchild		    buf);
991166971Snetchild		mtx_lock(&midistat_lock);
992166280Sariff	} else
993166971Snetchild		l = 0;
994158979Snetchild	midistat_bufptr += l;
995158979Snetchild	mtx_unlock(&midistat_lock);
996158979Snetchild	return err;
997158979Snetchild}
998158979Snetchild
999158979Snetchild/*
1000158979Snetchild * Module library functions
1001158979Snetchild */
1002158979Snetchild
1003158979Snetchildstatic int
1004166971Snetchildmidistat_prepare(struct sbuf *s)
1005158979Snetchild{
1006158979Snetchild	struct snd_midi *m;
1007158979Snetchild
1008158979Snetchild	mtx_assert(&midistat_lock, MA_OWNED);
1009158979Snetchild
1010158979Snetchild	sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1011158979Snetchild	if (TAILQ_EMPTY(&midi_devs)) {
1012166971Snetchild		sbuf_printf(s, "No devices installed.\n");
1013166971Snetchild		sbuf_finish(s);
1014166971Snetchild		return sbuf_len(s);
1015158979Snetchild	}
1016158979Snetchild	sbuf_printf(s, "Installed devices:\n");
1017158979Snetchild
1018158979Snetchild	TAILQ_FOREACH(m, &midi_devs, link) {
1019166971Snetchild		mtx_lock(&m->lock);
1020166971Snetchild		sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1021158979Snetchild		    MPU_PROVIDER(m, m->cookie));
1022166971Snetchild		sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1023166971Snetchild		sbuf_printf(s, "\n");
1024166971Snetchild		mtx_unlock(&m->lock);
1025158979Snetchild	}
1026158979Snetchild
1027158979Snetchild	sbuf_finish(s);
1028158979Snetchild	return sbuf_len(s);
1029158979Snetchild}
1030158979Snetchild
1031159042Sru#ifdef notdef
1032158979Snetchild/*
1033158979Snetchild * Convert IOCTL command to string for debugging
1034158979Snetchild */
1035158979Snetchild
1036166971Snetchildstatic char *
1037158979Snetchildmidi_cmdname(int cmd)
1038158979Snetchild{
1039158979Snetchild	static struct {
1040166971Snetchild		int	cmd;
1041166971Snetchild		char   *name;
1042166971Snetchild	}     *tab, cmdtab_midiioctl[] = {
1043158979Snetchild#define A(x)	{x, ## x}
1044166971Snetchild		/*
1045166971Snetchild	         * Once we have some real IOCTLs define, the following will
1046166971Snetchild	         * be relavant.
1047166971Snetchild	         *
1048166971Snetchild	         * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1049166971Snetchild	         * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1050166971Snetchild	         * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1051166971Snetchild	         * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1052166971Snetchild	         * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1053166971Snetchild	         * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1054166971Snetchild	         * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1055166971Snetchild	         * A(AIOGCAP),
1056166971Snetchild	         */
1057158979Snetchild#undef A
1058166971Snetchild		{
1059166971Snetchild			-1, "unknown"
1060166971Snetchild		},
1061158979Snetchild	};
1062158979Snetchild
1063166971Snetchild	for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1064158979Snetchild	return tab->name;
1065158979Snetchild}
1066158979Snetchild
1067166971Snetchild#endif					/* notdef */
1068166971Snetchild
1069158979Snetchild/*
1070158979Snetchild * midisynth
1071158979Snetchild */
1072158979Snetchild
1073158979Snetchild
1074158979Snetchildint
1075158979Snetchildmidisynth_open(void *n, void *arg, int flags)
1076158979Snetchild{
1077166971Snetchild	struct snd_midi *m = ((struct synth_midi *)n)->m;
1078166971Snetchild	int retval;
1079158979Snetchild
1080166971Snetchild	MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
1081166971Snetchild	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1082158979Snetchild
1083158979Snetchild	if (m == NULL)
1084166971Snetchild		return ENXIO;
1085158979Snetchild
1086158979Snetchild	mtx_lock(&m->lock);
1087158979Snetchild	mtx_lock(&m->qlock);
1088158979Snetchild
1089158979Snetchild	retval = 0;
1090158979Snetchild
1091158979Snetchild	if (flags & FREAD) {
1092166971Snetchild		if (MIDIQ_SIZE(m->inq) == 0)
1093166971Snetchild			retval = ENXIO;
1094166971Snetchild		else if (m->flags & M_RX)
1095166971Snetchild			retval = EBUSY;
1096166971Snetchild		if (retval)
1097166971Snetchild			goto err;
1098158979Snetchild	}
1099158979Snetchild	if (flags & FWRITE) {
1100166971Snetchild		if (MIDIQ_SIZE(m->outq) == 0)
1101166971Snetchild			retval = ENXIO;
1102166971Snetchild		else if (m->flags & M_TX)
1103166971Snetchild			retval = EBUSY;
1104166971Snetchild		if (retval)
1105166971Snetchild			goto err;
1106158979Snetchild	}
1107158979Snetchild	m->busy++;
1108158979Snetchild
1109158979Snetchild	/*
1110158979Snetchild	 * TODO: Consider m->async = 0;
1111158979Snetchild	 */
1112158979Snetchild
1113158979Snetchild	if (flags & FREAD) {
1114166971Snetchild		m->flags |= M_RX | M_RXEN;
1115166971Snetchild		/*
1116166971Snetchild	         * Only clear the inq, the outq might still have data to drain
1117166971Snetchild	         * from a previous session
1118166971Snetchild	         */
1119166971Snetchild		MIDIQ_CLEAR(m->inq);
1120166971Snetchild		m->rchan = 0;
1121158979Snetchild	};
1122158979Snetchild
1123158979Snetchild	if (flags & FWRITE) {
1124166971Snetchild		m->flags |= M_TX;
1125166971Snetchild		m->wchan = 0;
1126158979Snetchild	}
1127166971Snetchild	m->synth_flags = flags & (FREAD | FWRITE);
1128158979Snetchild
1129158979Snetchild	MPU_CALLBACK(m, m->cookie, m->flags);
1130158979Snetchild
1131158979Snetchild
1132158979Snetchilderr:	mtx_unlock(&m->qlock);
1133158979Snetchild	mtx_unlock(&m->lock);
1134158979Snetchild	MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1135158979Snetchild	return retval;
1136158979Snetchild}
1137158979Snetchild
1138158979Snetchildint
1139158979Snetchildmidisynth_close(void *n)
1140158979Snetchild{
1141158979Snetchild	struct snd_midi *m = ((struct synth_midi *)n)->m;
1142166971Snetchild	int retval;
1143166971Snetchild	int oldflags;
1144158979Snetchild
1145158979Snetchild	MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1146166971Snetchild	    m->synth_flags & FREAD ? "M_RX" : "",
1147166971Snetchild	    m->synth_flags & FWRITE ? "M_TX" : ""));
1148158979Snetchild
1149158979Snetchild	if (m == NULL)
1150166971Snetchild		return ENXIO;
1151158979Snetchild
1152158979Snetchild	mtx_lock(&m->lock);
1153158979Snetchild	mtx_lock(&m->qlock);
1154158979Snetchild
1155166971Snetchild	if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1156166971Snetchild	    (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1157166971Snetchild		retval = ENXIO;
1158166971Snetchild		goto err;
1159158979Snetchild	}
1160158979Snetchild	m->busy--;
1161158979Snetchild
1162158979Snetchild	oldflags = m->flags;
1163158979Snetchild
1164158979Snetchild	if (m->synth_flags & FREAD)
1165166971Snetchild		m->flags &= ~(M_RX | M_RXEN);
1166158979Snetchild	if (m->synth_flags & FWRITE)
1167166971Snetchild		m->flags &= ~M_TX;
1168158979Snetchild
1169166971Snetchild	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1170158979Snetchild		MPU_CALLBACK(m, m->cookie, m->flags);
1171158979Snetchild
1172158979Snetchild	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1173158979Snetchild
1174158979Snetchild	mtx_unlock(&m->qlock);
1175158979Snetchild	mtx_unlock(&m->lock);
1176158979Snetchild	retval = 0;
1177158979Snetchilderr:	return retval;
1178158979Snetchild}
1179158979Snetchild
1180158979Snetchild/*
1181158979Snetchild * Always blocking.
1182158979Snetchild */
1183158979Snetchild
1184158979Snetchildint
1185158979Snetchildmidisynth_writeraw(void *n, uint8_t *buf, size_t len)
1186158979Snetchild{
1187166971Snetchild	struct snd_midi *m = ((struct synth_midi *)n)->m;
1188166971Snetchild	int retval;
1189166971Snetchild	int used;
1190158979Snetchild	int i;
1191158979Snetchild
1192166971Snetchild	MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1193158979Snetchild
1194158979Snetchild	retval = 0;
1195158979Snetchild
1196158979Snetchild	if (m == NULL)
1197166971Snetchild		return ENXIO;
1198158979Snetchild
1199158979Snetchild	mtx_lock(&m->lock);
1200158979Snetchild	mtx_lock(&m->qlock);
1201158979Snetchild
1202158979Snetchild	if (!(m->flags & M_TX))
1203166971Snetchild		goto err1;
1204158979Snetchild
1205158979Snetchild	if (midi_dumpraw)
1206166971Snetchild		printf("midi dump: ");
1207158979Snetchild
1208158979Snetchild	while (len > 0) {
1209166971Snetchild		while (MIDIQ_AVAIL(m->outq) == 0) {
1210166971Snetchild			if (!(m->flags & M_TXEN)) {
1211166971Snetchild				m->flags |= M_TXEN;
1212166971Snetchild				MPU_CALLBACK(m, m->cookie, m->flags);
1213166971Snetchild			}
1214166971Snetchild			mtx_unlock(&m->lock);
1215166971Snetchild			m->wchan = 1;
1216166971Snetchild			MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
1217166971Snetchild			retval = msleep(&m->wchan, &m->qlock,
1218166971Snetchild			    PCATCH | PDROP, "midi TX", 0);
1219166971Snetchild			/*
1220166971Snetchild			 * We slept, maybe things have changed since last
1221166971Snetchild			 * dying check
1222166971Snetchild			 */
1223166971Snetchild			if (retval == EINTR)
1224166971Snetchild				goto err0;
1225158979Snetchild
1226166971Snetchild			if (retval)
1227166971Snetchild				goto err0;
1228166971Snetchild			mtx_lock(&m->lock);
1229166971Snetchild			mtx_lock(&m->qlock);
1230166971Snetchild			m->wchan = 0;
1231166971Snetchild			if (!m->busy)
1232166971Snetchild				goto err1;
1233166971Snetchild		}
1234158979Snetchild
1235166971Snetchild		/*
1236166971Snetchild	         * We are certain than data can be placed on the queue
1237166971Snetchild	         */
1238158979Snetchild
1239166971Snetchild		used = MIN(MIDIQ_AVAIL(m->outq), len);
1240166971Snetchild		used = MIN(used, MIDI_WSIZE);
1241166971Snetchild		MIDI_DEBUG(5,
1242166971Snetchild		    printf("midi_synth: resid %zu len %jd avail %jd\n",
1243166971Snetchild		    len, (intmax_t)MIDIQ_LEN(m->outq),
1244166971Snetchild		    (intmax_t)MIDIQ_AVAIL(m->outq)));
1245158979Snetchild
1246166971Snetchild		if (midi_dumpraw)
1247166971Snetchild			for (i = 0; i < used; i++)
1248166971Snetchild				printf("%x ", buf[i]);
1249158979Snetchild
1250166971Snetchild		MIDIQ_ENQ(m->outq, buf, used);
1251166971Snetchild		len -= used;
1252158979Snetchild
1253166971Snetchild		/*
1254166971Snetchild	         * Inform the bottom half that data can be written
1255166971Snetchild	         */
1256166971Snetchild		if (!(m->flags & M_TXEN)) {
1257166971Snetchild			m->flags |= M_TXEN;
1258166971Snetchild			MPU_CALLBACK(m, m->cookie, m->flags);
1259166971Snetchild		}
1260158979Snetchild	}
1261158979Snetchild	/*
1262158979Snetchild	 * If we Made it here then transfer is good
1263158979Snetchild	 */
1264158979Snetchild	if (midi_dumpraw)
1265166971Snetchild		printf("\n");
1266158979Snetchild
1267158979Snetchild	retval = 0;
1268158979Snetchilderr1:	mtx_unlock(&m->qlock);
1269158979Snetchild	mtx_unlock(&m->lock);
1270158979Snetchilderr0:	return retval;
1271158979Snetchild}
1272158979Snetchild
1273158979Snetchildstatic int
1274158979Snetchildmidisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1275158979Snetchild{
1276158979Snetchild	u_char c[3];
1277158979Snetchild
1278158979Snetchild
1279158979Snetchild	if (note > 127 || chn > 15)
1280158979Snetchild		return (EINVAL);
1281158979Snetchild
1282158979Snetchild	if (vel > 127)
1283166971Snetchild		vel = 127;
1284158979Snetchild
1285158979Snetchild	if (vel == 64) {
1286166971Snetchild		c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1287158979Snetchild		c[1] = (u_char)note;
1288158979Snetchild		c[2] = 0;
1289158979Snetchild	} else {
1290166971Snetchild		c[0] = 0x80 | (chn & 0x0f);	/* Note off. */
1291158979Snetchild		c[1] = (u_char)note;
1292158979Snetchild		c[2] = (u_char)vel;
1293158979Snetchild	}
1294158979Snetchild
1295158979Snetchild	return midisynth_writeraw(n, c, 3);
1296158979Snetchild}
1297158979Snetchild
1298158979Snetchildstatic int
1299158979Snetchildmidisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1300158979Snetchild{
1301158979Snetchild	u_char c[2];
1302158979Snetchild
1303158979Snetchild	if (instr > 127 || chn > 15)
1304158979Snetchild		return EINVAL;
1305158979Snetchild
1306166971Snetchild	c[0] = 0xc0 | (chn & 0x0f);	/* Progamme change. */
1307158979Snetchild	c[1] = instr + midi_instroff;
1308158979Snetchild
1309158979Snetchild	return midisynth_writeraw(n, c, 2);
1310158979Snetchild}
1311158979Snetchild
1312158979Snetchildstatic int
1313158979Snetchildmidisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1314158979Snetchild{
1315158979Snetchild	u_char c[3];
1316158979Snetchild
1317158979Snetchild	if (note > 127 || chn > 15)
1318158979Snetchild		return EINVAL;
1319158979Snetchild
1320158979Snetchild	if (vel > 127)
1321166971Snetchild		vel = 127;
1322158979Snetchild
1323166971Snetchild	c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1324158979Snetchild	c[1] = (u_char)note;
1325158979Snetchild	c[2] = (u_char)vel;
1326158979Snetchild
1327158979Snetchild	return midisynth_writeraw(n, c, 3);
1328158979Snetchild}
1329158979Snetchildstatic int
1330158979Snetchildmidisynth_alloc(void *n, uint8_t chan, uint8_t note)
1331158979Snetchild{
1332158979Snetchild	return chan;
1333158979Snetchild}
1334158979Snetchild
1335158979Snetchildstatic int
1336158979Snetchildmidisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1337158979Snetchild{
1338158979Snetchild	u_char c[3];
1339158979Snetchild
1340158979Snetchild	if (ctrlnum > 127 || chn > 15)
1341166971Snetchild		return EINVAL;
1342158979Snetchild
1343166971Snetchild	c[0] = 0xb0 | (chn & 0x0f);	/* Control Message. */
1344158979Snetchild	c[1] = ctrlnum;
1345158979Snetchild	c[2] = val;
1346158979Snetchild	return midisynth_writeraw(n, c, 3);
1347158979Snetchild}
1348158979Snetchild
1349158979Snetchildstatic int
1350158979Snetchildmidisynth_bender(void *n, uint8_t chn, uint16_t val)
1351158979Snetchild{
1352158979Snetchild	u_char c[3];
1353158979Snetchild
1354158979Snetchild
1355158979Snetchild	if (val > 16383 || chn > 15)
1356166971Snetchild		return EINVAL;
1357158979Snetchild
1358166971Snetchild	c[0] = 0xe0 | (chn & 0x0f);	/* Pitch bend. */
1359158979Snetchild	c[1] = (u_char)val & 0x7f;
1360158979Snetchild	c[2] = (u_char)(val >> 7) & 0x7f;
1361158979Snetchild
1362158979Snetchild	return midisynth_writeraw(n, c, 3);
1363158979Snetchild}
1364158979Snetchild
1365158979Snetchild/*
1366158979Snetchild * Single point of midi destructions.
1367158979Snetchild */
1368158979Snetchildstatic int
1369166971Snetchildmidi_destroy(struct snd_midi *m, int midiuninit)
1370158979Snetchild{
1371158979Snetchild
1372158979Snetchild	mtx_assert(&midistat_lock, MA_OWNED);
1373158979Snetchild	mtx_assert(&m->lock, MA_OWNED);
1374158979Snetchild
1375166971Snetchild	MIDI_DEBUG(3, printf("midi_destroy\n"));
1376158979Snetchild	m->dev->si_drv1 = NULL;
1377193640Sariff	mtx_unlock(&m->lock);	/* XXX */
1378158979Snetchild	destroy_dev(m->dev);
1379158979Snetchild	TAILQ_REMOVE(&midi_devs, m, link);
1380158979Snetchild	if (midiuninit)
1381166971Snetchild		MPU_UNINIT(m, m->cookie);
1382158979Snetchild	free(MIDIQ_BUF(m->inq), M_MIDI);
1383158979Snetchild	free(MIDIQ_BUF(m->outq), M_MIDI);
1384158979Snetchild	mtx_destroy(&m->qlock);
1385158979Snetchild	mtx_destroy(&m->lock);
1386158979Snetchild	free(m, M_MIDI);
1387158979Snetchild	return 0;
1388158979Snetchild}
1389158979Snetchild
1390158979Snetchild/*
1391158979Snetchild * Load and unload functions, creates the /dev/midistat device
1392158979Snetchild */
1393158979Snetchild
1394158979Snetchildstatic int
1395158979Snetchildmidi_load()
1396158979Snetchild{
1397167604Sariff	mtx_init(&midistat_lock, "midistat lock", NULL, 0);
1398166971Snetchild	TAILQ_INIT(&midi_devs);		/* Initialize the queue. */
1399158979Snetchild
1400158979Snetchild	midistat_dev = make_dev(&midistat_cdevsw,
1401166971Snetchild	    MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1402166971Snetchild	    UID_ROOT, GID_WHEEL, 0666, "midistat");
1403158979Snetchild
1404158979Snetchild	return 0;
1405158979Snetchild}
1406158979Snetchild
1407158979Snetchildstatic int
1408158979Snetchildmidi_unload()
1409158979Snetchild{
1410158979Snetchild	struct snd_midi *m;
1411166971Snetchild	int retval;
1412158979Snetchild
1413166971Snetchild	MIDI_DEBUG(1, printf("midi_unload()\n"));
1414158979Snetchild	retval = EBUSY;
1415158979Snetchild	mtx_lock(&midistat_lock);
1416158979Snetchild	if (midistat_isopen)
1417166971Snetchild		goto exit0;
1418158979Snetchild
1419158979Snetchild	TAILQ_FOREACH(m, &midi_devs, link) {
1420166971Snetchild		mtx_lock(&m->lock);
1421166971Snetchild		if (m->busy)
1422166971Snetchild			retval = EBUSY;
1423166971Snetchild		else
1424166971Snetchild			retval = midi_destroy(m, 1);
1425166971Snetchild		if (retval)
1426166971Snetchild			goto exit1;
1427158979Snetchild	}
1428158979Snetchild
1429193640Sariff	mtx_unlock(&midistat_lock);	/* XXX */
1430193640Sariff
1431158979Snetchild	destroy_dev(midistat_dev);
1432158979Snetchild	/*
1433158979Snetchild	 * Made it here then unload is complete
1434158979Snetchild	 */
1435158979Snetchild	mtx_destroy(&midistat_lock);
1436158979Snetchild	return 0;
1437158979Snetchild
1438158979Snetchildexit1:
1439158979Snetchild	mtx_unlock(&m->lock);
1440158979Snetchildexit0:
1441158979Snetchild	mtx_unlock(&midistat_lock);
1442166971Snetchild	if (retval)
1443166971Snetchild		MIDI_DEBUG(2, printf("midi_unload: failed\n"));
1444158979Snetchild	return retval;
1445158979Snetchild}
1446158979Snetchild
1447158979Snetchildextern int seq_modevent(module_t mod, int type, void *data);
1448158979Snetchild
1449158979Snetchildstatic int
1450158979Snetchildmidi_modevent(module_t mod, int type, void *data)
1451158979Snetchild{
1452166971Snetchild	int retval;
1453158979Snetchild
1454158979Snetchild	retval = 0;
1455158979Snetchild
1456158979Snetchild	switch (type) {
1457158979Snetchild	case MOD_LOAD:
1458166971Snetchild		retval = midi_load();
1459168253Sariff#if 0
1460166971Snetchild		if (retval == 0)
1461166971Snetchild			retval = seq_modevent(mod, type, data);
1462168253Sariff#endif
1463166971Snetchild		break;
1464158979Snetchild
1465158979Snetchild	case MOD_UNLOAD:
1466166971Snetchild		retval = midi_unload();
1467168253Sariff#if 0
1468166971Snetchild		if (retval == 0)
1469166971Snetchild			retval = seq_modevent(mod, type, data);
1470168253Sariff#endif
1471166971Snetchild		break;
1472158979Snetchild
1473158979Snetchild	default:
1474166971Snetchild		break;
1475158979Snetchild	}
1476158979Snetchild
1477158979Snetchild	return retval;
1478158979Snetchild}
1479158979Snetchild
1480158979Snetchildkobj_t
1481158979Snetchildmidimapper_addseq(void *arg1, int *unit, void **cookie)
1482158979Snetchild{
1483158979Snetchild	unit = 0;
1484158979Snetchild
1485166971Snetchild	return (kobj_t)arg1;
1486158979Snetchild}
1487158979Snetchild
1488158979Snetchildint
1489158979Snetchildmidimapper_open(void *arg1, void **cookie)
1490158979Snetchild{
1491158979Snetchild	int retval = 0;
1492158979Snetchild	struct snd_midi *m;
1493158979Snetchild
1494166971Snetchild	mtx_lock(&midistat_lock);
1495158979Snetchild
1496166971Snetchild	TAILQ_FOREACH(m, &midi_devs, link) {
1497166971Snetchild		retval++;
1498166971Snetchild	}
1499158979Snetchild
1500166971Snetchild	mtx_unlock(&midistat_lock);
1501166971Snetchild	return retval;
1502158979Snetchild}
1503158979Snetchild
1504158979Snetchildint
1505158979Snetchildmidimapper_close(void *arg1, void *cookie)
1506158979Snetchild{
1507158979Snetchild	return 0;
1508158979Snetchild}
1509158979Snetchild
1510158979Snetchildkobj_t
1511158979Snetchildmidimapper_fetch_synth(void *arg, void *cookie, int unit)
1512158979Snetchild{
1513158979Snetchild	struct snd_midi *m;
1514158979Snetchild	int retval = 0;
1515158979Snetchild
1516158979Snetchild	mtx_lock(&midistat_lock);
1517158979Snetchild
1518158979Snetchild	TAILQ_FOREACH(m, &midi_devs, link) {
1519166971Snetchild		if (unit == retval) {
1520166971Snetchild			mtx_unlock(&midistat_lock);
1521166971Snetchild			return (kobj_t)m->synth;
1522166971Snetchild		}
1523166971Snetchild		retval++;
1524158979Snetchild	}
1525158979Snetchild
1526158979Snetchild	mtx_unlock(&midistat_lock);
1527158979Snetchild	return NULL;
1528158979Snetchild}
1529158979Snetchild
1530158979SnetchildDEV_MODULE(midi, midi_modevent, NULL);
1531158979SnetchildMODULE_VERSION(midi, 1);
1532