xref: /freebsd/sys/dev/sound/midi/midi.c (revision 718cf2ccb9956613756ab15d7a0e28f2c8e91cab)
1206b17d7SAlexander Leidinger /*-
2*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
3*718cf2ccSPedro F. Giffuni  *
448351eafSJoel Dahl  * Copyright (c) 2003 Mathew Kanner
5206b17d7SAlexander Leidinger  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6206b17d7SAlexander Leidinger  * All rights reserved.
7206b17d7SAlexander Leidinger  *
8206b17d7SAlexander Leidinger  * This code is derived from software contributed to The NetBSD Foundation
9206b17d7SAlexander Leidinger  * by Lennart Augustsson (augustss@netbsd.org).
10206b17d7SAlexander Leidinger  *
11206b17d7SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
12206b17d7SAlexander Leidinger  * modification, are permitted provided that the following conditions
13206b17d7SAlexander Leidinger  * are met:
14206b17d7SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
15206b17d7SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer.
16206b17d7SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
17206b17d7SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
18206b17d7SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
19206b17d7SAlexander Leidinger  *
20206b17d7SAlexander Leidinger  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21206b17d7SAlexander Leidinger  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22206b17d7SAlexander Leidinger  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23206b17d7SAlexander Leidinger  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24206b17d7SAlexander Leidinger  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25206b17d7SAlexander Leidinger  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26206b17d7SAlexander Leidinger  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27206b17d7SAlexander Leidinger  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28206b17d7SAlexander Leidinger  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29206b17d7SAlexander Leidinger  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30206b17d7SAlexander Leidinger  * POSSIBILITY OF SUCH DAMAGE.
31206b17d7SAlexander Leidinger  */
32206b17d7SAlexander Leidinger 
33206b17d7SAlexander Leidinger  /*
34206b17d7SAlexander Leidinger   * Parts of this file started out as NetBSD: midi.c 1.31
35206b17d7SAlexander Leidinger   * They are mostly gone.  Still the most obvious will be the state
36206b17d7SAlexander Leidinger   * machine midi_in
37206b17d7SAlexander Leidinger   */
38206b17d7SAlexander Leidinger 
39206b17d7SAlexander Leidinger #include <sys/cdefs.h>
40206b17d7SAlexander Leidinger __FBSDID("$FreeBSD$");
41206b17d7SAlexander Leidinger 
42206b17d7SAlexander Leidinger #include <sys/param.h>
43206b17d7SAlexander Leidinger #include <sys/queue.h>
44206b17d7SAlexander Leidinger #include <sys/kernel.h>
45206b17d7SAlexander Leidinger #include <sys/lock.h>
46206b17d7SAlexander Leidinger #include <sys/mutex.h>
47206b17d7SAlexander Leidinger #include <sys/proc.h>
48206b17d7SAlexander Leidinger #include <sys/signalvar.h>
49206b17d7SAlexander Leidinger #include <sys/conf.h>
50206b17d7SAlexander Leidinger #include <sys/selinfo.h>
51206b17d7SAlexander Leidinger #include <sys/sysctl.h>
52206b17d7SAlexander Leidinger #include <sys/types.h>
53206b17d7SAlexander Leidinger #include <sys/malloc.h>
54206b17d7SAlexander Leidinger #include <sys/param.h>
55206b17d7SAlexander Leidinger #include <sys/systm.h>
56206b17d7SAlexander Leidinger #include <sys/proc.h>
57206b17d7SAlexander Leidinger #include <sys/fcntl.h>
58206b17d7SAlexander Leidinger #include <sys/types.h>
59206b17d7SAlexander Leidinger #include <sys/uio.h>
60206b17d7SAlexander Leidinger #include <sys/poll.h>
61206b17d7SAlexander Leidinger #include <sys/sbuf.h>
62206b17d7SAlexander Leidinger #include <sys/kobj.h>
63206b17d7SAlexander Leidinger #include <sys/module.h>
64206b17d7SAlexander Leidinger 
6590da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
6690da2b28SAriff Abdullah #include "opt_snd.h"
6790da2b28SAriff Abdullah #endif
6890da2b28SAriff Abdullah 
69206b17d7SAlexander Leidinger #include <dev/sound/midi/midi.h>
70206b17d7SAlexander Leidinger #include "mpu_if.h"
71206b17d7SAlexander Leidinger 
72206b17d7SAlexander Leidinger #include <dev/sound/midi/midiq.h>
73206b17d7SAlexander Leidinger #include "synth_if.h"
74206b17d7SAlexander Leidinger MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
75206b17d7SAlexander Leidinger 
765870e3c9SAriff Abdullah #ifndef KOBJMETHOD_END
775870e3c9SAriff Abdullah #define KOBJMETHOD_END	{ NULL, NULL }
785870e3c9SAriff Abdullah #endif
79206b17d7SAlexander Leidinger 
80206b17d7SAlexander Leidinger #define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
81206b17d7SAlexander Leidinger #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
82206b17d7SAlexander Leidinger 
83206b17d7SAlexander Leidinger #define MIDI_DEV_RAW	2
84206b17d7SAlexander Leidinger #define MIDI_DEV_MIDICTL 12
85206b17d7SAlexander Leidinger 
86206b17d7SAlexander Leidinger enum midi_states {
87206b17d7SAlexander Leidinger 	MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
88206b17d7SAlexander Leidinger };
89206b17d7SAlexander Leidinger 
90206b17d7SAlexander Leidinger /*
917cbd5addSTai-hwa Liang  * The MPU interface current has init() uninit() inqsize() outqsize()
92206b17d7SAlexander Leidinger  * callback() : fiddle with the tx|rx status.
93206b17d7SAlexander Leidinger  */
94206b17d7SAlexander Leidinger 
95206b17d7SAlexander Leidinger #include "mpu_if.h"
96206b17d7SAlexander Leidinger 
97206b17d7SAlexander Leidinger /*
98206b17d7SAlexander Leidinger  * /dev/rmidi	Structure definitions
99206b17d7SAlexander Leidinger  */
100206b17d7SAlexander Leidinger 
101206b17d7SAlexander Leidinger #define MIDI_NAMELEN   16
102206b17d7SAlexander Leidinger struct snd_midi {
103206b17d7SAlexander Leidinger 	KOBJ_FIELDS;
104206b17d7SAlexander Leidinger 	struct mtx lock;		/* Protects all but queues */
105206b17d7SAlexander Leidinger 	void   *cookie;
106206b17d7SAlexander Leidinger 
107206b17d7SAlexander Leidinger 	int	unit;			/* Should only be used in midistat */
108206b17d7SAlexander Leidinger 	int	channel;		/* Should only be used in midistat */
109206b17d7SAlexander Leidinger 
110206b17d7SAlexander Leidinger 	int	busy;
111206b17d7SAlexander Leidinger 	int	flags;			/* File flags */
112206b17d7SAlexander Leidinger 	char	name[MIDI_NAMELEN];
113206b17d7SAlexander Leidinger 	struct mtx qlock;		/* Protects inq, outq and flags */
114206b17d7SAlexander Leidinger 	MIDIQ_HEAD(, char) inq, outq;
115206b17d7SAlexander Leidinger 	int	rchan, wchan;
116206b17d7SAlexander Leidinger 	struct selinfo rsel, wsel;
1178f981688SAlexander Leidinger 	int	hiwat;			/* QLEN(outq)>High-water -> disable
1188f981688SAlexander Leidinger 					 * writes from userland */
119206b17d7SAlexander Leidinger 	enum midi_states inq_state;
1208f981688SAlexander Leidinger 	int	inq_status, inq_left;	/* Variables for the state machine in
1218f981688SAlexander Leidinger 					 * Midi_in, this is to provide that
1228f981688SAlexander Leidinger 					 * signals only get issued only
123206b17d7SAlexander Leidinger 					 * complete command packets. */
124206b17d7SAlexander Leidinger 	struct proc *async;
125206b17d7SAlexander Leidinger 	struct cdev *dev;
126206b17d7SAlexander Leidinger 	struct synth_midi *synth;
127206b17d7SAlexander Leidinger 	int	synth_flags;
128206b17d7SAlexander Leidinger 	TAILQ_ENTRY(snd_midi) link;
129206b17d7SAlexander Leidinger };
130206b17d7SAlexander Leidinger 
131206b17d7SAlexander Leidinger struct synth_midi {
132206b17d7SAlexander Leidinger 	KOBJ_FIELDS;
133206b17d7SAlexander Leidinger 	struct snd_midi *m;
134206b17d7SAlexander Leidinger };
135206b17d7SAlexander Leidinger 
136206b17d7SAlexander Leidinger static synth_open_t midisynth_open;
137206b17d7SAlexander Leidinger static synth_close_t midisynth_close;
138206b17d7SAlexander Leidinger static synth_writeraw_t midisynth_writeraw;
139206b17d7SAlexander Leidinger static synth_killnote_t midisynth_killnote;
140206b17d7SAlexander Leidinger static synth_startnote_t midisynth_startnote;
141206b17d7SAlexander Leidinger static synth_setinstr_t midisynth_setinstr;
142206b17d7SAlexander Leidinger static synth_alloc_t midisynth_alloc;
143206b17d7SAlexander Leidinger static synth_controller_t midisynth_controller;
144206b17d7SAlexander Leidinger static synth_bender_t midisynth_bender;
145206b17d7SAlexander Leidinger 
146206b17d7SAlexander Leidinger 
147206b17d7SAlexander Leidinger static kobj_method_t midisynth_methods[] = {
148206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_open, midisynth_open),
149206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_close, midisynth_close),
150206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_writeraw, midisynth_writeraw),
151206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_setinstr, midisynth_setinstr),
152206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_startnote, midisynth_startnote),
153206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_killnote, midisynth_killnote),
154206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_alloc, midisynth_alloc),
155206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_controller, midisynth_controller),
156206b17d7SAlexander Leidinger 	KOBJMETHOD(synth_bender, midisynth_bender),
15790da2b28SAriff Abdullah 	KOBJMETHOD_END
158206b17d7SAlexander Leidinger };
159206b17d7SAlexander Leidinger 
160206b17d7SAlexander Leidinger DEFINE_CLASS(midisynth, midisynth_methods, 0);
161206b17d7SAlexander Leidinger 
162206b17d7SAlexander Leidinger /*
163206b17d7SAlexander Leidinger  * Module Exports & Interface
164206b17d7SAlexander Leidinger  *
1657cbd5addSTai-hwa Liang  * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan,
1667cbd5addSTai-hwa Liang  *     void *cookie)
1677cbd5addSTai-hwa Liang  * int midi_uninit(struct snd_midi *)
1687cbd5addSTai-hwa Liang  *
1697cbd5addSTai-hwa Liang  * 0 == no error
1707cbd5addSTai-hwa Liang  * EBUSY or other error
1717cbd5addSTai-hwa Liang  *
1727cbd5addSTai-hwa Liang  * int midi_in(struct snd_midi *, char *buf, int count)
1737cbd5addSTai-hwa Liang  * int midi_out(struct snd_midi *, char *buf, int count)
174206b17d7SAlexander Leidinger  *
175206b17d7SAlexander Leidinger  * midi_{in,out} return actual size transfered
176206b17d7SAlexander Leidinger  *
177206b17d7SAlexander Leidinger  */
178206b17d7SAlexander Leidinger 
179206b17d7SAlexander Leidinger 
180206b17d7SAlexander Leidinger /*
181206b17d7SAlexander Leidinger  * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
182206b17d7SAlexander Leidinger  */
183206b17d7SAlexander Leidinger 
184206b17d7SAlexander Leidinger TAILQ_HEAD(, snd_midi) midi_devs;
185206b17d7SAlexander Leidinger 
186206b17d7SAlexander Leidinger /*
187206b17d7SAlexander Leidinger  * /dev/midistat variables and declarations, protected by midistat_lock
188206b17d7SAlexander Leidinger  */
189206b17d7SAlexander Leidinger 
190206b17d7SAlexander Leidinger static struct mtx midistat_lock;
191206b17d7SAlexander Leidinger static int      midistat_isopen = 0;
192206b17d7SAlexander Leidinger static struct sbuf midistat_sbuf;
193206b17d7SAlexander Leidinger static int      midistat_bufptr;
194206b17d7SAlexander Leidinger static struct cdev *midistat_dev;
195206b17d7SAlexander Leidinger 
196206b17d7SAlexander Leidinger /*
197206b17d7SAlexander Leidinger  * /dev/midistat	dev_t declarations
198206b17d7SAlexander Leidinger  */
199206b17d7SAlexander Leidinger 
200206b17d7SAlexander Leidinger static d_open_t midistat_open;
201206b17d7SAlexander Leidinger static d_close_t midistat_close;
202206b17d7SAlexander Leidinger static d_read_t midistat_read;
203206b17d7SAlexander Leidinger 
204206b17d7SAlexander Leidinger static struct cdevsw midistat_cdevsw = {
205206b17d7SAlexander Leidinger 	.d_version = D_VERSION,
206206b17d7SAlexander Leidinger 	.d_open = midistat_open,
207206b17d7SAlexander Leidinger 	.d_close = midistat_close,
208206b17d7SAlexander Leidinger 	.d_read = midistat_read,
209206b17d7SAlexander Leidinger 	.d_name = "midistat",
210206b17d7SAlexander Leidinger };
211206b17d7SAlexander Leidinger 
212206b17d7SAlexander Leidinger 
213206b17d7SAlexander Leidinger /*
214206b17d7SAlexander Leidinger  * /dev/rmidi dev_t declarations, struct variable access is protected by
215206b17d7SAlexander Leidinger  * locks contained within the structure.
216206b17d7SAlexander Leidinger  */
217206b17d7SAlexander Leidinger 
218206b17d7SAlexander Leidinger static d_open_t midi_open;
219206b17d7SAlexander Leidinger static d_close_t midi_close;
220206b17d7SAlexander Leidinger static d_ioctl_t midi_ioctl;
221206b17d7SAlexander Leidinger static d_read_t midi_read;
222206b17d7SAlexander Leidinger static d_write_t midi_write;
223206b17d7SAlexander Leidinger static d_poll_t midi_poll;
224206b17d7SAlexander Leidinger 
225206b17d7SAlexander Leidinger static struct cdevsw midi_cdevsw = {
226206b17d7SAlexander Leidinger 	.d_version = D_VERSION,
227206b17d7SAlexander Leidinger 	.d_open = midi_open,
228206b17d7SAlexander Leidinger 	.d_close = midi_close,
229206b17d7SAlexander Leidinger 	.d_read = midi_read,
230206b17d7SAlexander Leidinger 	.d_write = midi_write,
231206b17d7SAlexander Leidinger 	.d_ioctl = midi_ioctl,
232206b17d7SAlexander Leidinger 	.d_poll = midi_poll,
233206b17d7SAlexander Leidinger 	.d_name = "rmidi",
234206b17d7SAlexander Leidinger };
235206b17d7SAlexander Leidinger 
236206b17d7SAlexander Leidinger /*
237206b17d7SAlexander Leidinger  * Prototypes of library functions
238206b17d7SAlexander Leidinger  */
239206b17d7SAlexander Leidinger 
240206b17d7SAlexander Leidinger static int      midi_destroy(struct snd_midi *, int);
241206b17d7SAlexander Leidinger static int      midistat_prepare(struct sbuf * s);
242206b17d7SAlexander Leidinger static int      midi_load(void);
243206b17d7SAlexander Leidinger static int      midi_unload(void);
244206b17d7SAlexander Leidinger 
245206b17d7SAlexander Leidinger /*
246206b17d7SAlexander Leidinger  * Misc declr.
247206b17d7SAlexander Leidinger  */
248206b17d7SAlexander Leidinger SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
2496472ac3dSEd Schouten static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device");
250206b17d7SAlexander Leidinger 
251206b17d7SAlexander Leidinger int             midi_debug;
252851a904aSAlexander Leidinger /* XXX: should this be moved into debug.midi? */
253206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
254206b17d7SAlexander Leidinger 
255206b17d7SAlexander Leidinger int             midi_dumpraw;
256206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
257206b17d7SAlexander Leidinger 
258206b17d7SAlexander Leidinger int             midi_instroff;
259206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
260206b17d7SAlexander Leidinger 
261206b17d7SAlexander Leidinger int             midistat_verbose;
262206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
263206b17d7SAlexander Leidinger 	&midistat_verbose, 0, "");
264206b17d7SAlexander Leidinger 
265206b17d7SAlexander Leidinger #define MIDI_DEBUG(l,a)	if(midi_debug>=l) a
266206b17d7SAlexander Leidinger /*
267206b17d7SAlexander Leidinger  * CODE START
268206b17d7SAlexander Leidinger  */
269206b17d7SAlexander Leidinger 
270206b17d7SAlexander Leidinger /*
271206b17d7SAlexander Leidinger  * Register a new rmidi device. cls midi_if interface unit == 0 means
272206b17d7SAlexander Leidinger  * auto-assign new unit number unit != 0 already assigned a unit number, eg.
273206b17d7SAlexander Leidinger  * not the first channel provided by this device. channel,	sub-unit
274206b17d7SAlexander Leidinger  * cookie is passed back on MPU calls Typical device drivers will call with
275206b17d7SAlexander Leidinger  * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
276206b17d7SAlexander Leidinger  * what unit number is used.
277206b17d7SAlexander Leidinger  *
278206b17d7SAlexander Leidinger  * It is an error to call midi_init with an already used unit/channel combo.
279206b17d7SAlexander Leidinger  *
280206b17d7SAlexander Leidinger  * Returns NULL on error
281206b17d7SAlexander Leidinger  *
282206b17d7SAlexander Leidinger  */
283206b17d7SAlexander Leidinger struct snd_midi *
284206b17d7SAlexander Leidinger midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
285206b17d7SAlexander Leidinger {
286206b17d7SAlexander Leidinger 	struct snd_midi *m;
287206b17d7SAlexander Leidinger 	int i;
288206b17d7SAlexander Leidinger 	int inqsize, outqsize;
289206b17d7SAlexander Leidinger 	MIDI_TYPE *buf;
290206b17d7SAlexander Leidinger 
291206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
292206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
293206b17d7SAlexander Leidinger 	/*
294206b17d7SAlexander Leidinger 	 * Protect against call with existing unit/channel or auto-allocate a
295206b17d7SAlexander Leidinger 	 * new unit number.
296206b17d7SAlexander Leidinger 	 */
297206b17d7SAlexander Leidinger 	i = -1;
298206b17d7SAlexander Leidinger 	TAILQ_FOREACH(m, &midi_devs, link) {
299206b17d7SAlexander Leidinger 		mtx_lock(&m->lock);
300206b17d7SAlexander Leidinger 		if (unit != 0) {
301206b17d7SAlexander Leidinger 			if (m->unit == unit && m->channel == channel) {
302206b17d7SAlexander Leidinger 				mtx_unlock(&m->lock);
303206b17d7SAlexander Leidinger 				goto err0;
304206b17d7SAlexander Leidinger 			}
305206b17d7SAlexander Leidinger 		} else {
306206b17d7SAlexander Leidinger 			/*
307206b17d7SAlexander Leidinger 			 * Find a better unit number
308206b17d7SAlexander Leidinger 			 */
309206b17d7SAlexander Leidinger 			if (m->unit > i)
310206b17d7SAlexander Leidinger 				i = m->unit;
311206b17d7SAlexander Leidinger 		}
312206b17d7SAlexander Leidinger 		mtx_unlock(&m->lock);
313206b17d7SAlexander Leidinger 	}
314206b17d7SAlexander Leidinger 
315206b17d7SAlexander Leidinger 	if (unit == 0)
316206b17d7SAlexander Leidinger 		unit = i + 1;
317206b17d7SAlexander Leidinger 
318206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
319206b17d7SAlexander Leidinger 	m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
320206b17d7SAlexander Leidinger 	if (m == NULL)
321206b17d7SAlexander Leidinger 		goto err0;
322206b17d7SAlexander Leidinger 
323206b17d7SAlexander Leidinger 	m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO);
324671b5759STai-hwa Liang 	if (m->synth == NULL)
325671b5759STai-hwa Liang 		goto err1;
326206b17d7SAlexander Leidinger 	kobj_init((kobj_t)m->synth, &midisynth_class);
327206b17d7SAlexander Leidinger 	m->synth->m = m;
328206b17d7SAlexander Leidinger 	kobj_init((kobj_t)m, cls);
329206b17d7SAlexander Leidinger 	inqsize = MPU_INQSIZE(m, cookie);
330206b17d7SAlexander Leidinger 	outqsize = MPU_OUTQSIZE(m, cookie);
331206b17d7SAlexander Leidinger 
332206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
333206b17d7SAlexander Leidinger 	if (!inqsize && !outqsize)
334671b5759STai-hwa Liang 		goto err2;
335206b17d7SAlexander Leidinger 
3368c0a77e3SAriff Abdullah 	mtx_init(&m->lock, "raw midi", NULL, 0);
3378c0a77e3SAriff Abdullah 	mtx_init(&m->qlock, "q raw midi", NULL, 0);
338206b17d7SAlexander Leidinger 
339206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
340206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
341206b17d7SAlexander Leidinger 
342206b17d7SAlexander Leidinger 	if (inqsize)
343206b17d7SAlexander Leidinger 		buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
344206b17d7SAlexander Leidinger 	else
345206b17d7SAlexander Leidinger 		buf = NULL;
346206b17d7SAlexander Leidinger 
347206b17d7SAlexander Leidinger 	MIDIQ_INIT(m->inq, buf, inqsize);
348206b17d7SAlexander Leidinger 
349206b17d7SAlexander Leidinger 	if (outqsize)
350206b17d7SAlexander Leidinger 		buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
351206b17d7SAlexander Leidinger 	else
352206b17d7SAlexander Leidinger 		buf = NULL;
353206b17d7SAlexander Leidinger 	m->hiwat = outqsize / 2;
354206b17d7SAlexander Leidinger 
355206b17d7SAlexander Leidinger 	MIDIQ_INIT(m->outq, buf, outqsize);
356206b17d7SAlexander Leidinger 
357206b17d7SAlexander Leidinger 	if ((inqsize && !MIDIQ_BUF(m->inq)) ||
358206b17d7SAlexander Leidinger 	    (outqsize && !MIDIQ_BUF(m->outq)))
359671b5759STai-hwa Liang 		goto err3;
360206b17d7SAlexander Leidinger 
361206b17d7SAlexander Leidinger 
362206b17d7SAlexander Leidinger 	m->busy = 0;
363206b17d7SAlexander Leidinger 	m->flags = 0;
364206b17d7SAlexander Leidinger 	m->unit = unit;
365206b17d7SAlexander Leidinger 	m->channel = channel;
366206b17d7SAlexander Leidinger 	m->cookie = cookie;
367206b17d7SAlexander Leidinger 
368206b17d7SAlexander Leidinger 	if (MPU_INIT(m, cookie))
369671b5759STai-hwa Liang 		goto err3;
370206b17d7SAlexander Leidinger 
371206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
372206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
373206b17d7SAlexander Leidinger 
374206b17d7SAlexander Leidinger 	TAILQ_INSERT_TAIL(&midi_devs, m, link);
375206b17d7SAlexander Leidinger 
376206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
377206b17d7SAlexander Leidinger 
378206b17d7SAlexander Leidinger 	m->dev = make_dev(&midi_cdevsw,
379206b17d7SAlexander Leidinger 	    MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
380206b17d7SAlexander Leidinger 	    UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
381206b17d7SAlexander Leidinger 	m->dev->si_drv1 = m;
382206b17d7SAlexander Leidinger 
383206b17d7SAlexander Leidinger 	return m;
384206b17d7SAlexander Leidinger 
385671b5759STai-hwa Liang err3:	mtx_destroy(&m->qlock);
386206b17d7SAlexander Leidinger 	mtx_destroy(&m->lock);
387206b17d7SAlexander Leidinger 
388206b17d7SAlexander Leidinger 	if (MIDIQ_BUF(m->inq))
389206b17d7SAlexander Leidinger 		free(MIDIQ_BUF(m->inq), M_MIDI);
390206b17d7SAlexander Leidinger 	if (MIDIQ_BUF(m->outq))
391206b17d7SAlexander Leidinger 		free(MIDIQ_BUF(m->outq), M_MIDI);
392671b5759STai-hwa Liang err2:	free(m->synth, M_MIDI);
393206b17d7SAlexander Leidinger err1:	free(m, M_MIDI);
394206b17d7SAlexander Leidinger err0:	mtx_unlock(&midistat_lock);
395206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midi_init ended in error\n"));
396206b17d7SAlexander Leidinger 	return NULL;
397206b17d7SAlexander Leidinger }
398206b17d7SAlexander Leidinger 
399206b17d7SAlexander Leidinger /*
400206b17d7SAlexander Leidinger  * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
4017cbd5addSTai-hwa Liang  * entry point. midi_uninit if fact, does not send any methods. A call to
402206b17d7SAlexander Leidinger  * midi_uninit is a defacto promise that you won't manipulate ch anymore
403206b17d7SAlexander Leidinger  *
404206b17d7SAlexander Leidinger  */
405206b17d7SAlexander Leidinger 
406206b17d7SAlexander Leidinger int
407206b17d7SAlexander Leidinger midi_uninit(struct snd_midi *m)
408206b17d7SAlexander Leidinger {
409206b17d7SAlexander Leidinger 	int err;
410206b17d7SAlexander Leidinger 
411076cf2ddSTai-hwa Liang 	err = EBUSY;
412206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
413206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
414206b17d7SAlexander Leidinger 	if (m->busy) {
415206b17d7SAlexander Leidinger 		if (!(m->rchan || m->wchan))
416206b17d7SAlexander Leidinger 			goto err;
417206b17d7SAlexander Leidinger 
418206b17d7SAlexander Leidinger 		if (m->rchan) {
419206b17d7SAlexander Leidinger 			wakeup(&m->rchan);
420206b17d7SAlexander Leidinger 			m->rchan = 0;
421206b17d7SAlexander Leidinger 		}
422206b17d7SAlexander Leidinger 		if (m->wchan) {
423206b17d7SAlexander Leidinger 			wakeup(&m->wchan);
424206b17d7SAlexander Leidinger 			m->wchan = 0;
425206b17d7SAlexander Leidinger 		}
426206b17d7SAlexander Leidinger 	}
427206b17d7SAlexander Leidinger 	err = midi_destroy(m, 0);
428206b17d7SAlexander Leidinger 	if (!err)
429206b17d7SAlexander Leidinger 		goto exit;
430206b17d7SAlexander Leidinger 
431206b17d7SAlexander Leidinger err:	mtx_unlock(&m->lock);
432206b17d7SAlexander Leidinger exit:	mtx_unlock(&midistat_lock);
433206b17d7SAlexander Leidinger 	return err;
434206b17d7SAlexander Leidinger }
435206b17d7SAlexander Leidinger 
436206b17d7SAlexander Leidinger /*
437206b17d7SAlexander Leidinger  * midi_in: process all data until the queue is full, then discards the rest.
438206b17d7SAlexander Leidinger  * Since midi_in is a state machine, data discards can cause it to get out of
439206b17d7SAlexander Leidinger  * whack.  Process as much as possible.  It calls, wakeup, selnotify and
440206b17d7SAlexander Leidinger  * psignal at most once.
441206b17d7SAlexander Leidinger  */
442206b17d7SAlexander Leidinger 
4432916c293SRuslan Ermilov #ifdef notdef
444206b17d7SAlexander Leidinger static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
4458f981688SAlexander Leidinger 
446206b17d7SAlexander Leidinger #endif					/* notdef */
447206b17d7SAlexander Leidinger /* Number of bytes in a MIDI command */
448206b17d7SAlexander Leidinger #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
449206b17d7SAlexander Leidinger #define MIDI_ACK	0xfe
450206b17d7SAlexander Leidinger #define MIDI_IS_STATUS(d) ((d) >= 0x80)
451206b17d7SAlexander Leidinger #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
452206b17d7SAlexander Leidinger 
453206b17d7SAlexander Leidinger #define MIDI_SYSEX_START	0xF0
454206b17d7SAlexander Leidinger #define MIDI_SYSEX_END	    0xF7
455206b17d7SAlexander Leidinger 
456206b17d7SAlexander Leidinger 
457206b17d7SAlexander Leidinger int
458206b17d7SAlexander Leidinger midi_in(struct snd_midi *m, MIDI_TYPE *buf, int size)
459206b17d7SAlexander Leidinger {
460206b17d7SAlexander Leidinger 	/* int             i, sig, enq; */
461206b17d7SAlexander Leidinger 	int used;
4628f981688SAlexander Leidinger 
463206b17d7SAlexander Leidinger 	/* MIDI_TYPE       data; */
464206b17d7SAlexander Leidinger 	MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
465206b17d7SAlexander Leidinger 
466206b17d7SAlexander Leidinger /*
467206b17d7SAlexander Leidinger  * XXX: locking flub
468206b17d7SAlexander Leidinger  */
469206b17d7SAlexander Leidinger 	if (!(m->flags & M_RX))
470206b17d7SAlexander Leidinger 		return size;
471206b17d7SAlexander Leidinger 
472206b17d7SAlexander Leidinger 	used = 0;
473206b17d7SAlexander Leidinger 
474206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
475206b17d7SAlexander Leidinger #if 0
476206b17d7SAlexander Leidinger 	/*
477206b17d7SAlexander Leidinger 	 * Don't bother queuing if not in read mode.  Discard everything and
478206b17d7SAlexander Leidinger 	 * return size so the caller doesn't freak out.
479206b17d7SAlexander Leidinger 	 */
480206b17d7SAlexander Leidinger 
481206b17d7SAlexander Leidinger 	if (!(m->flags & M_RX))
482206b17d7SAlexander Leidinger 		return size;
483206b17d7SAlexander Leidinger 
484206b17d7SAlexander Leidinger 	for (i = sig = 0; i < size; i++) {
485206b17d7SAlexander Leidinger 
486206b17d7SAlexander Leidinger 		data = buf[i];
487206b17d7SAlexander Leidinger 		enq = 0;
488206b17d7SAlexander Leidinger 		if (data == MIDI_ACK)
489206b17d7SAlexander Leidinger 			continue;
490206b17d7SAlexander Leidinger 
491206b17d7SAlexander Leidinger 		switch (m->inq_state) {
492206b17d7SAlexander Leidinger 		case MIDI_IN_START:
493206b17d7SAlexander Leidinger 			if (MIDI_IS_STATUS(data)) {
494206b17d7SAlexander Leidinger 				switch (data) {
495206b17d7SAlexander Leidinger 				case 0xf0:	/* Sysex */
496206b17d7SAlexander Leidinger 					m->inq_state = MIDI_IN_SYSEX;
497206b17d7SAlexander Leidinger 					break;
498206b17d7SAlexander Leidinger 				case 0xf1:	/* MTC quarter frame */
499206b17d7SAlexander Leidinger 				case 0xf3:	/* Song select */
500206b17d7SAlexander Leidinger 					m->inq_state = MIDI_IN_DATA;
501206b17d7SAlexander Leidinger 					enq = 1;
502206b17d7SAlexander Leidinger 					m->inq_left = 1;
503206b17d7SAlexander Leidinger 					break;
504206b17d7SAlexander Leidinger 				case 0xf2:	/* Song position pointer */
505206b17d7SAlexander Leidinger 					m->inq_state = MIDI_IN_DATA;
506206b17d7SAlexander Leidinger 					enq = 1;
507206b17d7SAlexander Leidinger 					m->inq_left = 2;
508206b17d7SAlexander Leidinger 					break;
509206b17d7SAlexander Leidinger 				default:
510206b17d7SAlexander Leidinger 					if (MIDI_IS_COMMON(data)) {
511206b17d7SAlexander Leidinger 						enq = 1;
512206b17d7SAlexander Leidinger 						sig = 1;
513206b17d7SAlexander Leidinger 					} else {
514206b17d7SAlexander Leidinger 						m->inq_state = MIDI_IN_DATA;
515206b17d7SAlexander Leidinger 						enq = 1;
516206b17d7SAlexander Leidinger 						m->inq_status = data;
517206b17d7SAlexander Leidinger 						m->inq_left = MIDI_LENGTH(data);
518206b17d7SAlexander Leidinger 					}
519206b17d7SAlexander Leidinger 					break;
520206b17d7SAlexander Leidinger 				}
521206b17d7SAlexander Leidinger 			} else if (MIDI_IS_STATUS(m->inq_status)) {
522206b17d7SAlexander Leidinger 				m->inq_state = MIDI_IN_DATA;
523206b17d7SAlexander Leidinger 				if (!MIDIQ_FULL(m->inq)) {
524206b17d7SAlexander Leidinger 					used++;
525206b17d7SAlexander Leidinger 					MIDIQ_ENQ(m->inq, &m->inq_status, 1);
526206b17d7SAlexander Leidinger 				}
527206b17d7SAlexander Leidinger 				enq = 1;
528206b17d7SAlexander Leidinger 				m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
529206b17d7SAlexander Leidinger 			}
530206b17d7SAlexander Leidinger 			break;
531206b17d7SAlexander Leidinger 			/*
532206b17d7SAlexander Leidinger 			 * End of case MIDI_IN_START:
533206b17d7SAlexander Leidinger 			 */
534206b17d7SAlexander Leidinger 
535206b17d7SAlexander Leidinger 		case MIDI_IN_DATA:
536206b17d7SAlexander Leidinger 			enq = 1;
537206b17d7SAlexander Leidinger 			if (--m->inq_left <= 0)
538206b17d7SAlexander Leidinger 				sig = 1;/* deliver data */
539206b17d7SAlexander Leidinger 			break;
540206b17d7SAlexander Leidinger 		case MIDI_IN_SYSEX:
541206b17d7SAlexander Leidinger 			if (data == MIDI_SYSEX_END)
542206b17d7SAlexander Leidinger 				m->inq_state = MIDI_IN_START;
543206b17d7SAlexander Leidinger 			break;
544206b17d7SAlexander Leidinger 		}
545206b17d7SAlexander Leidinger 
546206b17d7SAlexander Leidinger 		if (enq)
547206b17d7SAlexander Leidinger 			if (!MIDIQ_FULL(m->inq)) {
548206b17d7SAlexander Leidinger 				MIDIQ_ENQ(m->inq, &data, 1);
549206b17d7SAlexander Leidinger 				used++;
550206b17d7SAlexander Leidinger 			}
551206b17d7SAlexander Leidinger 		/*
552206b17d7SAlexander Leidinger 	         * End of the state machines main "for loop"
553206b17d7SAlexander Leidinger 	         */
554206b17d7SAlexander Leidinger 	}
555206b17d7SAlexander Leidinger 	if (sig) {
556206b17d7SAlexander Leidinger #endif
5578f981688SAlexander Leidinger 		MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
5588f981688SAlexander Leidinger 		    (intmax_t)MIDIQ_LEN(m->inq),
5598f981688SAlexander Leidinger 		    (intmax_t)MIDIQ_AVAIL(m->inq)));
560206b17d7SAlexander Leidinger 		if (MIDIQ_AVAIL(m->inq) > size) {
561206b17d7SAlexander Leidinger 			used = size;
562206b17d7SAlexander Leidinger 			MIDIQ_ENQ(m->inq, buf, size);
563206b17d7SAlexander Leidinger 		} else {
564206b17d7SAlexander Leidinger 			MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
565206b17d7SAlexander Leidinger 			mtx_unlock(&m->qlock);
566206b17d7SAlexander Leidinger 			return 0;
567206b17d7SAlexander Leidinger 		}
568206b17d7SAlexander Leidinger 		if (m->rchan) {
569206b17d7SAlexander Leidinger 			wakeup(&m->rchan);
570206b17d7SAlexander Leidinger 			m->rchan = 0;
571206b17d7SAlexander Leidinger 		}
572206b17d7SAlexander Leidinger 		selwakeup(&m->rsel);
573206b17d7SAlexander Leidinger 		if (m->async) {
574206b17d7SAlexander Leidinger 			PROC_LOCK(m->async);
5758451d0ddSKip Macy 			kern_psignal(m->async, SIGIO);
576206b17d7SAlexander Leidinger 			PROC_UNLOCK(m->async);
577206b17d7SAlexander Leidinger 		}
578206b17d7SAlexander Leidinger #if 0
579206b17d7SAlexander Leidinger 	}
580206b17d7SAlexander Leidinger #endif
581206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
582206b17d7SAlexander Leidinger 	return used;
583206b17d7SAlexander Leidinger }
584206b17d7SAlexander Leidinger 
585206b17d7SAlexander Leidinger /*
586206b17d7SAlexander Leidinger  * midi_out: The only clearer of the M_TXEN flag.
587206b17d7SAlexander Leidinger  */
588206b17d7SAlexander Leidinger int
589206b17d7SAlexander Leidinger midi_out(struct snd_midi *m, MIDI_TYPE *buf, int size)
590206b17d7SAlexander Leidinger {
591206b17d7SAlexander Leidinger 	int used;
592206b17d7SAlexander Leidinger 
593206b17d7SAlexander Leidinger /*
594206b17d7SAlexander Leidinger  * XXX: locking flub
595206b17d7SAlexander Leidinger  */
596206b17d7SAlexander Leidinger 	if (!(m->flags & M_TXEN))
597206b17d7SAlexander Leidinger 		return 0;
598206b17d7SAlexander Leidinger 
599206b17d7SAlexander Leidinger 	MIDI_DEBUG(2, printf("midi_out: %p\n", m));
600206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
601206b17d7SAlexander Leidinger 	used = MIN(size, MIDIQ_LEN(m->outq));
602206b17d7SAlexander Leidinger 	MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
603206b17d7SAlexander Leidinger 	if (used)
604206b17d7SAlexander Leidinger 		MIDIQ_DEQ(m->outq, buf, used);
605206b17d7SAlexander Leidinger 	if (MIDIQ_EMPTY(m->outq)) {
606206b17d7SAlexander Leidinger 		m->flags &= ~M_TXEN;
607206b17d7SAlexander Leidinger 		MPU_CALLBACKP(m, m->cookie, m->flags);
608206b17d7SAlexander Leidinger 	}
609206b17d7SAlexander Leidinger 	if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
610206b17d7SAlexander Leidinger 		if (m->wchan) {
611206b17d7SAlexander Leidinger 			wakeup(&m->wchan);
612206b17d7SAlexander Leidinger 			m->wchan = 0;
613206b17d7SAlexander Leidinger 		}
614206b17d7SAlexander Leidinger 		selwakeup(&m->wsel);
615206b17d7SAlexander Leidinger 		if (m->async) {
616206b17d7SAlexander Leidinger 			PROC_LOCK(m->async);
6178451d0ddSKip Macy 			kern_psignal(m->async, SIGIO);
618206b17d7SAlexander Leidinger 			PROC_UNLOCK(m->async);
619206b17d7SAlexander Leidinger 		}
620206b17d7SAlexander Leidinger 	}
621206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
622206b17d7SAlexander Leidinger 	return used;
623206b17d7SAlexander Leidinger }
624206b17d7SAlexander Leidinger 
625206b17d7SAlexander Leidinger 
626206b17d7SAlexander Leidinger /*
627206b17d7SAlexander Leidinger  * /dev/rmidi#.#	device access functions
628206b17d7SAlexander Leidinger  */
629206b17d7SAlexander Leidinger int
630206b17d7SAlexander Leidinger midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
631206b17d7SAlexander Leidinger {
632206b17d7SAlexander Leidinger 	struct snd_midi *m = i_dev->si_drv1;
633206b17d7SAlexander Leidinger 	int retval;
634206b17d7SAlexander Leidinger 
635206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
636206b17d7SAlexander Leidinger 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
637206b17d7SAlexander Leidinger 	if (m == NULL)
638206b17d7SAlexander Leidinger 		return ENXIO;
639206b17d7SAlexander Leidinger 
640206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
641206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
642206b17d7SAlexander Leidinger 
643206b17d7SAlexander Leidinger 	retval = 0;
644206b17d7SAlexander Leidinger 
645206b17d7SAlexander Leidinger 	if (flags & FREAD) {
646206b17d7SAlexander Leidinger 		if (MIDIQ_SIZE(m->inq) == 0)
647206b17d7SAlexander Leidinger 			retval = ENXIO;
648206b17d7SAlexander Leidinger 		else if (m->flags & M_RX)
649206b17d7SAlexander Leidinger 			retval = EBUSY;
650206b17d7SAlexander Leidinger 		if (retval)
651206b17d7SAlexander Leidinger 			goto err;
652206b17d7SAlexander Leidinger 	}
653206b17d7SAlexander Leidinger 	if (flags & FWRITE) {
654206b17d7SAlexander Leidinger 		if (MIDIQ_SIZE(m->outq) == 0)
655206b17d7SAlexander Leidinger 			retval = ENXIO;
656206b17d7SAlexander Leidinger 		else if (m->flags & M_TX)
657206b17d7SAlexander Leidinger 			retval = EBUSY;
658206b17d7SAlexander Leidinger 		if (retval)
659206b17d7SAlexander Leidinger 			goto err;
660206b17d7SAlexander Leidinger 	}
661206b17d7SAlexander Leidinger 	m->busy++;
662206b17d7SAlexander Leidinger 
663206b17d7SAlexander Leidinger 	m->rchan = 0;
664206b17d7SAlexander Leidinger 	m->wchan = 0;
665206b17d7SAlexander Leidinger 	m->async = 0;
666206b17d7SAlexander Leidinger 
667206b17d7SAlexander Leidinger 	if (flags & FREAD) {
668206b17d7SAlexander Leidinger 		m->flags |= M_RX | M_RXEN;
669206b17d7SAlexander Leidinger 		/*
6708f981688SAlexander Leidinger 	         * Only clear the inq, the outq might still have data to drain
6718f981688SAlexander Leidinger 	         * from a previous session
672206b17d7SAlexander Leidinger 	         */
673206b17d7SAlexander Leidinger 		MIDIQ_CLEAR(m->inq);
67474b8d63dSPedro F. Giffuni 	}
675206b17d7SAlexander Leidinger 
676206b17d7SAlexander Leidinger 	if (flags & FWRITE)
677206b17d7SAlexander Leidinger 		m->flags |= M_TX;
678206b17d7SAlexander Leidinger 
679206b17d7SAlexander Leidinger 	MPU_CALLBACK(m, m->cookie, m->flags);
680206b17d7SAlexander Leidinger 
681206b17d7SAlexander Leidinger 	MIDI_DEBUG(2, printf("midi_open: opened.\n"));
682206b17d7SAlexander Leidinger 
683206b17d7SAlexander Leidinger err:	mtx_unlock(&m->qlock);
684206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
685206b17d7SAlexander Leidinger 	return retval;
686206b17d7SAlexander Leidinger }
687206b17d7SAlexander Leidinger 
688206b17d7SAlexander Leidinger int
689206b17d7SAlexander Leidinger midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
690206b17d7SAlexander Leidinger {
691206b17d7SAlexander Leidinger 	struct snd_midi *m = i_dev->si_drv1;
692206b17d7SAlexander Leidinger 	int retval;
693206b17d7SAlexander Leidinger 	int oldflags;
694206b17d7SAlexander Leidinger 
695206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
696206b17d7SAlexander Leidinger 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
697206b17d7SAlexander Leidinger 
698206b17d7SAlexander Leidinger 	if (m == NULL)
699206b17d7SAlexander Leidinger 		return ENXIO;
700206b17d7SAlexander Leidinger 
701206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
702206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
703206b17d7SAlexander Leidinger 
704206b17d7SAlexander Leidinger 	if ((flags & FREAD && !(m->flags & M_RX)) ||
705206b17d7SAlexander Leidinger 	    (flags & FWRITE && !(m->flags & M_TX))) {
706206b17d7SAlexander Leidinger 		retval = ENXIO;
707206b17d7SAlexander Leidinger 		goto err;
708206b17d7SAlexander Leidinger 	}
709206b17d7SAlexander Leidinger 	m->busy--;
710206b17d7SAlexander Leidinger 
711206b17d7SAlexander Leidinger 	oldflags = m->flags;
712206b17d7SAlexander Leidinger 
713206b17d7SAlexander Leidinger 	if (flags & FREAD)
714206b17d7SAlexander Leidinger 		m->flags &= ~(M_RX | M_RXEN);
715206b17d7SAlexander Leidinger 	if (flags & FWRITE)
716206b17d7SAlexander Leidinger 		m->flags &= ~M_TX;
717206b17d7SAlexander Leidinger 
718206b17d7SAlexander Leidinger 	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
719206b17d7SAlexander Leidinger 		MPU_CALLBACK(m, m->cookie, m->flags);
720206b17d7SAlexander Leidinger 
721206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
722206b17d7SAlexander Leidinger 
723206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
724206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
725206b17d7SAlexander Leidinger 	retval = 0;
726206b17d7SAlexander Leidinger err:	return retval;
727206b17d7SAlexander Leidinger }
7288f981688SAlexander Leidinger 
729206b17d7SAlexander Leidinger /*
7308f981688SAlexander Leidinger  * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
7318f981688SAlexander Leidinger  * as data is available.
732206b17d7SAlexander Leidinger  */
733206b17d7SAlexander Leidinger int
734206b17d7SAlexander Leidinger midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
735206b17d7SAlexander Leidinger {
736206b17d7SAlexander Leidinger #define MIDI_RSIZE 32
737206b17d7SAlexander Leidinger 	struct snd_midi *m = i_dev->si_drv1;
738206b17d7SAlexander Leidinger 	int retval;
739206b17d7SAlexander Leidinger 	int used;
740206b17d7SAlexander Leidinger 	char buf[MIDI_RSIZE];
741206b17d7SAlexander Leidinger 
7428f981688SAlexander Leidinger 	MIDI_DEBUG(5, printf("midiread: count=%lu\n",
7438f981688SAlexander Leidinger 	    (unsigned long)uio->uio_resid));
744206b17d7SAlexander Leidinger 
745206b17d7SAlexander Leidinger 	retval = EIO;
746206b17d7SAlexander Leidinger 
747206b17d7SAlexander Leidinger 	if (m == NULL)
748206b17d7SAlexander Leidinger 		goto err0;
749206b17d7SAlexander Leidinger 
750206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
751206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
752206b17d7SAlexander Leidinger 
753206b17d7SAlexander Leidinger 	if (!(m->flags & M_RX))
754206b17d7SAlexander Leidinger 		goto err1;
755206b17d7SAlexander Leidinger 
756206b17d7SAlexander Leidinger 	while (uio->uio_resid > 0) {
757206b17d7SAlexander Leidinger 		while (MIDIQ_EMPTY(m->inq)) {
758206b17d7SAlexander Leidinger 			retval = EWOULDBLOCK;
759206b17d7SAlexander Leidinger 			if (ioflag & O_NONBLOCK)
760206b17d7SAlexander Leidinger 				goto err1;
761206b17d7SAlexander Leidinger 			mtx_unlock(&m->lock);
762206b17d7SAlexander Leidinger 			m->rchan = 1;
763206b17d7SAlexander Leidinger 			retval = msleep(&m->rchan, &m->qlock,
764206b17d7SAlexander Leidinger 			    PCATCH | PDROP, "midi RX", 0);
765206b17d7SAlexander Leidinger 			/*
766206b17d7SAlexander Leidinger 			 * We slept, maybe things have changed since last
767206b17d7SAlexander Leidinger 			 * dying check
768206b17d7SAlexander Leidinger 			 */
769206b17d7SAlexander Leidinger 			if (retval == EINTR)
770206b17d7SAlexander Leidinger 				goto err0;
771206b17d7SAlexander Leidinger 			if (m != i_dev->si_drv1)
772206b17d7SAlexander Leidinger 				retval = ENXIO;
773206b17d7SAlexander Leidinger 			/* if (retval && retval != ERESTART) */
774206b17d7SAlexander Leidinger 			if (retval)
775206b17d7SAlexander Leidinger 				goto err0;
776206b17d7SAlexander Leidinger 			mtx_lock(&m->lock);
777206b17d7SAlexander Leidinger 			mtx_lock(&m->qlock);
778206b17d7SAlexander Leidinger 			m->rchan = 0;
779206b17d7SAlexander Leidinger 			if (!m->busy)
780206b17d7SAlexander Leidinger 				goto err1;
781206b17d7SAlexander Leidinger 		}
782206b17d7SAlexander Leidinger 		MIDI_DEBUG(6, printf("midi_read start\n"));
783206b17d7SAlexander Leidinger 		/*
784206b17d7SAlexander Leidinger 	         * At this point, it is certain that m->inq has data
785206b17d7SAlexander Leidinger 	         */
786206b17d7SAlexander Leidinger 
787206b17d7SAlexander Leidinger 		used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
788206b17d7SAlexander Leidinger 		used = MIN(used, MIDI_RSIZE);
789206b17d7SAlexander Leidinger 
790206b17d7SAlexander Leidinger 		MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
791206b17d7SAlexander Leidinger 		MIDIQ_DEQ(m->inq, buf, used);
792206b17d7SAlexander Leidinger 		retval = uiomove(buf, used, uio);
793206b17d7SAlexander Leidinger 		if (retval)
794206b17d7SAlexander Leidinger 			goto err1;
795206b17d7SAlexander Leidinger 	}
796206b17d7SAlexander Leidinger 
797206b17d7SAlexander Leidinger 	/*
798206b17d7SAlexander Leidinger 	 * If we Made it here then transfer is good
799206b17d7SAlexander Leidinger 	 */
800206b17d7SAlexander Leidinger 	retval = 0;
801206b17d7SAlexander Leidinger err1:	mtx_unlock(&m->qlock);
802206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
803206b17d7SAlexander Leidinger err0:	MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
804206b17d7SAlexander Leidinger 	return retval;
805206b17d7SAlexander Leidinger }
806206b17d7SAlexander Leidinger 
807206b17d7SAlexander Leidinger /*
808206b17d7SAlexander Leidinger  * midi_write: The only setter of M_TXEN
809206b17d7SAlexander Leidinger  */
810206b17d7SAlexander Leidinger 
811206b17d7SAlexander Leidinger int
812206b17d7SAlexander Leidinger midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
813206b17d7SAlexander Leidinger {
814206b17d7SAlexander Leidinger #define MIDI_WSIZE 32
815206b17d7SAlexander Leidinger 	struct snd_midi *m = i_dev->si_drv1;
816206b17d7SAlexander Leidinger 	int retval;
817206b17d7SAlexander Leidinger 	int used;
818206b17d7SAlexander Leidinger 	char buf[MIDI_WSIZE];
819206b17d7SAlexander Leidinger 
820206b17d7SAlexander Leidinger 
821206b17d7SAlexander Leidinger 	MIDI_DEBUG(4, printf("midi_write\n"));
822206b17d7SAlexander Leidinger 	retval = 0;
823206b17d7SAlexander Leidinger 	if (m == NULL)
824206b17d7SAlexander Leidinger 		goto err0;
825206b17d7SAlexander Leidinger 
826206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
827206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
828206b17d7SAlexander Leidinger 
829206b17d7SAlexander Leidinger 	if (!(m->flags & M_TX))
830206b17d7SAlexander Leidinger 		goto err1;
831206b17d7SAlexander Leidinger 
832206b17d7SAlexander Leidinger 	while (uio->uio_resid > 0) {
833206b17d7SAlexander Leidinger 		while (MIDIQ_AVAIL(m->outq) == 0) {
834206b17d7SAlexander Leidinger 			retval = EWOULDBLOCK;
835206b17d7SAlexander Leidinger 			if (ioflag & O_NONBLOCK)
836206b17d7SAlexander Leidinger 				goto err1;
837206b17d7SAlexander Leidinger 			mtx_unlock(&m->lock);
838206b17d7SAlexander Leidinger 			m->wchan = 1;
839206b17d7SAlexander Leidinger 			MIDI_DEBUG(3, printf("midi_write msleep\n"));
840206b17d7SAlexander Leidinger 			retval = msleep(&m->wchan, &m->qlock,
841206b17d7SAlexander Leidinger 			    PCATCH | PDROP, "midi TX", 0);
842206b17d7SAlexander Leidinger 			/*
843206b17d7SAlexander Leidinger 			 * We slept, maybe things have changed since last
844206b17d7SAlexander Leidinger 			 * dying check
845206b17d7SAlexander Leidinger 			 */
846206b17d7SAlexander Leidinger 			if (retval == EINTR)
847206b17d7SAlexander Leidinger 				goto err0;
848206b17d7SAlexander Leidinger 			if (m != i_dev->si_drv1)
849206b17d7SAlexander Leidinger 				retval = ENXIO;
850206b17d7SAlexander Leidinger 			if (retval)
851206b17d7SAlexander Leidinger 				goto err0;
852206b17d7SAlexander Leidinger 			mtx_lock(&m->lock);
853206b17d7SAlexander Leidinger 			mtx_lock(&m->qlock);
854206b17d7SAlexander Leidinger 			m->wchan = 0;
855206b17d7SAlexander Leidinger 			if (!m->busy)
856206b17d7SAlexander Leidinger 				goto err1;
857206b17d7SAlexander Leidinger 		}
858206b17d7SAlexander Leidinger 
859206b17d7SAlexander Leidinger 		/*
860206b17d7SAlexander Leidinger 	         * We are certain than data can be placed on the queue
861206b17d7SAlexander Leidinger 	         */
862206b17d7SAlexander Leidinger 
863206b17d7SAlexander Leidinger 		used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
864206b17d7SAlexander Leidinger 		used = MIN(used, MIDI_WSIZE);
8659f80ce04SKonstantin Belousov 		MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
8668f981688SAlexander Leidinger 		    uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
8678f981688SAlexander Leidinger 		    (intmax_t)MIDIQ_AVAIL(m->outq)));
868206b17d7SAlexander Leidinger 
869206b17d7SAlexander Leidinger 
870206b17d7SAlexander Leidinger 		MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
871206b17d7SAlexander Leidinger 		retval = uiomove(buf, used, uio);
872206b17d7SAlexander Leidinger 		if (retval)
873206b17d7SAlexander Leidinger 			goto err1;
874206b17d7SAlexander Leidinger 		MIDIQ_ENQ(m->outq, buf, used);
875206b17d7SAlexander Leidinger 		/*
876206b17d7SAlexander Leidinger 	         * Inform the bottom half that data can be written
877206b17d7SAlexander Leidinger 	         */
878206b17d7SAlexander Leidinger 		if (!(m->flags & M_TXEN)) {
879206b17d7SAlexander Leidinger 			m->flags |= M_TXEN;
880206b17d7SAlexander Leidinger 			MPU_CALLBACK(m, m->cookie, m->flags);
881206b17d7SAlexander Leidinger 		}
882206b17d7SAlexander Leidinger 	}
883206b17d7SAlexander Leidinger 	/*
884206b17d7SAlexander Leidinger 	 * If we Made it here then transfer is good
885206b17d7SAlexander Leidinger 	 */
886206b17d7SAlexander Leidinger 	retval = 0;
887206b17d7SAlexander Leidinger err1:	mtx_unlock(&m->qlock);
888206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
889206b17d7SAlexander Leidinger err0:	return retval;
890206b17d7SAlexander Leidinger }
891206b17d7SAlexander Leidinger 
892206b17d7SAlexander Leidinger int
8938f981688SAlexander Leidinger midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
8948f981688SAlexander Leidinger     struct thread *td)
895206b17d7SAlexander Leidinger {
896206b17d7SAlexander Leidinger 	return ENXIO;
897206b17d7SAlexander Leidinger }
898206b17d7SAlexander Leidinger 
899206b17d7SAlexander Leidinger int
900206b17d7SAlexander Leidinger midi_poll(struct cdev *i_dev, int events, struct thread *td)
901206b17d7SAlexander Leidinger {
902206b17d7SAlexander Leidinger 	struct snd_midi *m = i_dev->si_drv1;
903206b17d7SAlexander Leidinger 	int revents;
904206b17d7SAlexander Leidinger 
905206b17d7SAlexander Leidinger 	if (m == NULL)
906206b17d7SAlexander Leidinger 		return 0;
907206b17d7SAlexander Leidinger 
908206b17d7SAlexander Leidinger 	revents = 0;
909206b17d7SAlexander Leidinger 
910206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
911206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
912206b17d7SAlexander Leidinger 
913206b17d7SAlexander Leidinger 	if (events & (POLLIN | POLLRDNORM))
914206b17d7SAlexander Leidinger 		if (!MIDIQ_EMPTY(m->inq))
915206b17d7SAlexander Leidinger 			events |= events & (POLLIN | POLLRDNORM);
916206b17d7SAlexander Leidinger 
917206b17d7SAlexander Leidinger 	if (events & (POLLOUT | POLLWRNORM))
918206b17d7SAlexander Leidinger 		if (MIDIQ_AVAIL(m->outq) < m->hiwat)
919206b17d7SAlexander Leidinger 			events |= events & (POLLOUT | POLLWRNORM);
920206b17d7SAlexander Leidinger 
921206b17d7SAlexander Leidinger 	if (revents == 0) {
922206b17d7SAlexander Leidinger 		if (events & (POLLIN | POLLRDNORM))
923206b17d7SAlexander Leidinger 			selrecord(td, &m->rsel);
924206b17d7SAlexander Leidinger 
925206b17d7SAlexander Leidinger 		if (events & (POLLOUT | POLLWRNORM))
926206b17d7SAlexander Leidinger 			selrecord(td, &m->wsel);
927206b17d7SAlexander Leidinger 	}
928206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
929206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
930206b17d7SAlexander Leidinger 
931206b17d7SAlexander Leidinger 	return (revents);
932206b17d7SAlexander Leidinger }
933206b17d7SAlexander Leidinger 
934206b17d7SAlexander Leidinger /*
935206b17d7SAlexander Leidinger  * /dev/midistat device functions
936206b17d7SAlexander Leidinger  *
937206b17d7SAlexander Leidinger  */
938206b17d7SAlexander Leidinger static int
939206b17d7SAlexander Leidinger midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
940206b17d7SAlexander Leidinger {
941206b17d7SAlexander Leidinger 	int error;
942206b17d7SAlexander Leidinger 
943206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midistat_open\n"));
944206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
945206b17d7SAlexander Leidinger 
946206b17d7SAlexander Leidinger 	if (midistat_isopen) {
947206b17d7SAlexander Leidinger 		mtx_unlock(&midistat_lock);
948206b17d7SAlexander Leidinger 		return EBUSY;
949206b17d7SAlexander Leidinger 	}
950206b17d7SAlexander Leidinger 	midistat_isopen = 1;
951d130d865SAriff Abdullah 	mtx_unlock(&midistat_lock);
952206b17d7SAlexander Leidinger 
953d130d865SAriff Abdullah 	if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
954206b17d7SAlexander Leidinger 		error = ENXIO;
955d130d865SAriff Abdullah 		mtx_lock(&midistat_lock);
956206b17d7SAlexander Leidinger 		goto out;
957206b17d7SAlexander Leidinger 	}
958d130d865SAriff Abdullah 	mtx_lock(&midistat_lock);
959206b17d7SAlexander Leidinger 	midistat_bufptr = 0;
960206b17d7SAlexander Leidinger 	error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
961206b17d7SAlexander Leidinger 
962206b17d7SAlexander Leidinger out:	if (error)
963206b17d7SAlexander Leidinger 		midistat_isopen = 0;
964206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
965206b17d7SAlexander Leidinger 	return error;
966206b17d7SAlexander Leidinger }
967206b17d7SAlexander Leidinger 
968206b17d7SAlexander Leidinger static int
969206b17d7SAlexander Leidinger midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
970206b17d7SAlexander Leidinger {
971206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midistat_close\n"));
972206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
973206b17d7SAlexander Leidinger 	if (!midistat_isopen) {
974206b17d7SAlexander Leidinger 		mtx_unlock(&midistat_lock);
975206b17d7SAlexander Leidinger 		return EBADF;
976206b17d7SAlexander Leidinger 	}
977206b17d7SAlexander Leidinger 	sbuf_delete(&midistat_sbuf);
978206b17d7SAlexander Leidinger 	midistat_isopen = 0;
979206b17d7SAlexander Leidinger 
980206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
981206b17d7SAlexander Leidinger 	return 0;
982206b17d7SAlexander Leidinger }
983206b17d7SAlexander Leidinger 
984206b17d7SAlexander Leidinger static int
985206b17d7SAlexander Leidinger midistat_read(struct cdev *i_dev, struct uio *buf, int flag)
986206b17d7SAlexander Leidinger {
987206b17d7SAlexander Leidinger 	int l, err;
988206b17d7SAlexander Leidinger 
989206b17d7SAlexander Leidinger 	MIDI_DEBUG(4, printf("midistat_read\n"));
990206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
991206b17d7SAlexander Leidinger 	if (!midistat_isopen) {
992206b17d7SAlexander Leidinger 		mtx_unlock(&midistat_lock);
993206b17d7SAlexander Leidinger 		return EBADF;
994206b17d7SAlexander Leidinger 	}
995206b17d7SAlexander Leidinger 	l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr);
996206b17d7SAlexander Leidinger 	err = 0;
997d130d865SAriff Abdullah 	if (l > 0) {
998d130d865SAriff Abdullah 		mtx_unlock(&midistat_lock);
9998f981688SAlexander Leidinger 		err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l,
10008f981688SAlexander Leidinger 		    buf);
1001d130d865SAriff Abdullah 		mtx_lock(&midistat_lock);
1002d130d865SAriff Abdullah 	} else
1003206b17d7SAlexander Leidinger 		l = 0;
1004206b17d7SAlexander Leidinger 	midistat_bufptr += l;
1005206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
1006206b17d7SAlexander Leidinger 	return err;
1007206b17d7SAlexander Leidinger }
1008206b17d7SAlexander Leidinger 
1009206b17d7SAlexander Leidinger /*
1010206b17d7SAlexander Leidinger  * Module library functions
1011206b17d7SAlexander Leidinger  */
1012206b17d7SAlexander Leidinger 
1013206b17d7SAlexander Leidinger static int
1014206b17d7SAlexander Leidinger midistat_prepare(struct sbuf *s)
1015206b17d7SAlexander Leidinger {
1016206b17d7SAlexander Leidinger 	struct snd_midi *m;
1017206b17d7SAlexander Leidinger 
1018206b17d7SAlexander Leidinger 	mtx_assert(&midistat_lock, MA_OWNED);
1019206b17d7SAlexander Leidinger 
1020206b17d7SAlexander Leidinger 	sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1021206b17d7SAlexander Leidinger 	if (TAILQ_EMPTY(&midi_devs)) {
1022206b17d7SAlexander Leidinger 		sbuf_printf(s, "No devices installed.\n");
1023206b17d7SAlexander Leidinger 		sbuf_finish(s);
1024206b17d7SAlexander Leidinger 		return sbuf_len(s);
1025206b17d7SAlexander Leidinger 	}
1026206b17d7SAlexander Leidinger 	sbuf_printf(s, "Installed devices:\n");
1027206b17d7SAlexander Leidinger 
1028206b17d7SAlexander Leidinger 	TAILQ_FOREACH(m, &midi_devs, link) {
1029206b17d7SAlexander Leidinger 		mtx_lock(&m->lock);
1030206b17d7SAlexander Leidinger 		sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1031206b17d7SAlexander Leidinger 		    MPU_PROVIDER(m, m->cookie));
1032206b17d7SAlexander Leidinger 		sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1033206b17d7SAlexander Leidinger 		sbuf_printf(s, "\n");
1034206b17d7SAlexander Leidinger 		mtx_unlock(&m->lock);
1035206b17d7SAlexander Leidinger 	}
1036206b17d7SAlexander Leidinger 
1037206b17d7SAlexander Leidinger 	sbuf_finish(s);
1038206b17d7SAlexander Leidinger 	return sbuf_len(s);
1039206b17d7SAlexander Leidinger }
1040206b17d7SAlexander Leidinger 
10412916c293SRuslan Ermilov #ifdef notdef
1042206b17d7SAlexander Leidinger /*
1043206b17d7SAlexander Leidinger  * Convert IOCTL command to string for debugging
1044206b17d7SAlexander Leidinger  */
1045206b17d7SAlexander Leidinger 
1046206b17d7SAlexander Leidinger static char *
1047206b17d7SAlexander Leidinger midi_cmdname(int cmd)
1048206b17d7SAlexander Leidinger {
1049206b17d7SAlexander Leidinger 	static struct {
1050206b17d7SAlexander Leidinger 		int	cmd;
1051206b17d7SAlexander Leidinger 		char   *name;
1052206b17d7SAlexander Leidinger 	}     *tab, cmdtab_midiioctl[] = {
1053206b17d7SAlexander Leidinger #define A(x)	{x, ## x}
1054206b17d7SAlexander Leidinger 		/*
1055206b17d7SAlexander Leidinger 	         * Once we have some real IOCTLs define, the following will
1056206b17d7SAlexander Leidinger 	         * be relavant.
1057206b17d7SAlexander Leidinger 	         *
1058206b17d7SAlexander Leidinger 	         * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1059206b17d7SAlexander Leidinger 	         * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1060206b17d7SAlexander Leidinger 	         * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1061206b17d7SAlexander Leidinger 	         * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1062206b17d7SAlexander Leidinger 	         * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1063206b17d7SAlexander Leidinger 	         * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1064206b17d7SAlexander Leidinger 	         * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1065206b17d7SAlexander Leidinger 	         * A(AIOGCAP),
1066206b17d7SAlexander Leidinger 	         */
1067206b17d7SAlexander Leidinger #undef A
1068206b17d7SAlexander Leidinger 		{
1069206b17d7SAlexander Leidinger 			-1, "unknown"
1070206b17d7SAlexander Leidinger 		},
1071206b17d7SAlexander Leidinger 	};
1072206b17d7SAlexander Leidinger 
10738f981688SAlexander Leidinger 	for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1074206b17d7SAlexander Leidinger 	return tab->name;
1075206b17d7SAlexander Leidinger }
10768f981688SAlexander Leidinger 
1077206b17d7SAlexander Leidinger #endif					/* notdef */
1078206b17d7SAlexander Leidinger 
1079206b17d7SAlexander Leidinger /*
1080206b17d7SAlexander Leidinger  * midisynth
1081206b17d7SAlexander Leidinger  */
1082206b17d7SAlexander Leidinger 
1083206b17d7SAlexander Leidinger 
1084206b17d7SAlexander Leidinger int
1085206b17d7SAlexander Leidinger midisynth_open(void *n, void *arg, int flags)
1086206b17d7SAlexander Leidinger {
1087206b17d7SAlexander Leidinger 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1088206b17d7SAlexander Leidinger 	int retval;
1089206b17d7SAlexander Leidinger 
1090206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
1091206b17d7SAlexander Leidinger 	    flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1092206b17d7SAlexander Leidinger 
1093206b17d7SAlexander Leidinger 	if (m == NULL)
1094206b17d7SAlexander Leidinger 		return ENXIO;
1095206b17d7SAlexander Leidinger 
1096206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
1097206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
1098206b17d7SAlexander Leidinger 
1099206b17d7SAlexander Leidinger 	retval = 0;
1100206b17d7SAlexander Leidinger 
1101206b17d7SAlexander Leidinger 	if (flags & FREAD) {
1102206b17d7SAlexander Leidinger 		if (MIDIQ_SIZE(m->inq) == 0)
1103206b17d7SAlexander Leidinger 			retval = ENXIO;
1104206b17d7SAlexander Leidinger 		else if (m->flags & M_RX)
1105206b17d7SAlexander Leidinger 			retval = EBUSY;
1106206b17d7SAlexander Leidinger 		if (retval)
1107206b17d7SAlexander Leidinger 			goto err;
1108206b17d7SAlexander Leidinger 	}
1109206b17d7SAlexander Leidinger 	if (flags & FWRITE) {
1110206b17d7SAlexander Leidinger 		if (MIDIQ_SIZE(m->outq) == 0)
1111206b17d7SAlexander Leidinger 			retval = ENXIO;
1112206b17d7SAlexander Leidinger 		else if (m->flags & M_TX)
1113206b17d7SAlexander Leidinger 			retval = EBUSY;
1114206b17d7SAlexander Leidinger 		if (retval)
1115206b17d7SAlexander Leidinger 			goto err;
1116206b17d7SAlexander Leidinger 	}
1117206b17d7SAlexander Leidinger 	m->busy++;
1118206b17d7SAlexander Leidinger 
1119206b17d7SAlexander Leidinger 	/*
1120206b17d7SAlexander Leidinger 	 * TODO: Consider m->async = 0;
1121206b17d7SAlexander Leidinger 	 */
1122206b17d7SAlexander Leidinger 
1123206b17d7SAlexander Leidinger 	if (flags & FREAD) {
1124206b17d7SAlexander Leidinger 		m->flags |= M_RX | M_RXEN;
1125206b17d7SAlexander Leidinger 		/*
11268f981688SAlexander Leidinger 	         * Only clear the inq, the outq might still have data to drain
11278f981688SAlexander Leidinger 	         * from a previous session
1128206b17d7SAlexander Leidinger 	         */
1129206b17d7SAlexander Leidinger 		MIDIQ_CLEAR(m->inq);
1130206b17d7SAlexander Leidinger 		m->rchan = 0;
113174b8d63dSPedro F. Giffuni 	}
1132206b17d7SAlexander Leidinger 
1133206b17d7SAlexander Leidinger 	if (flags & FWRITE) {
1134206b17d7SAlexander Leidinger 		m->flags |= M_TX;
1135206b17d7SAlexander Leidinger 		m->wchan = 0;
1136206b17d7SAlexander Leidinger 	}
1137206b17d7SAlexander Leidinger 	m->synth_flags = flags & (FREAD | FWRITE);
1138206b17d7SAlexander Leidinger 
1139206b17d7SAlexander Leidinger 	MPU_CALLBACK(m, m->cookie, m->flags);
1140206b17d7SAlexander Leidinger 
1141206b17d7SAlexander Leidinger 
1142206b17d7SAlexander Leidinger err:	mtx_unlock(&m->qlock);
1143206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
1144206b17d7SAlexander Leidinger 	MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1145206b17d7SAlexander Leidinger 	return retval;
1146206b17d7SAlexander Leidinger }
1147206b17d7SAlexander Leidinger 
1148206b17d7SAlexander Leidinger int
1149206b17d7SAlexander Leidinger midisynth_close(void *n)
1150206b17d7SAlexander Leidinger {
1151206b17d7SAlexander Leidinger 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1152206b17d7SAlexander Leidinger 	int retval;
1153206b17d7SAlexander Leidinger 	int oldflags;
1154206b17d7SAlexander Leidinger 
1155206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1156206b17d7SAlexander Leidinger 	    m->synth_flags & FREAD ? "M_RX" : "",
1157206b17d7SAlexander Leidinger 	    m->synth_flags & FWRITE ? "M_TX" : ""));
1158206b17d7SAlexander Leidinger 
1159206b17d7SAlexander Leidinger 	if (m == NULL)
1160206b17d7SAlexander Leidinger 		return ENXIO;
1161206b17d7SAlexander Leidinger 
1162206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
1163206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
1164206b17d7SAlexander Leidinger 
1165206b17d7SAlexander Leidinger 	if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1166206b17d7SAlexander Leidinger 	    (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1167206b17d7SAlexander Leidinger 		retval = ENXIO;
1168206b17d7SAlexander Leidinger 		goto err;
1169206b17d7SAlexander Leidinger 	}
1170206b17d7SAlexander Leidinger 	m->busy--;
1171206b17d7SAlexander Leidinger 
1172206b17d7SAlexander Leidinger 	oldflags = m->flags;
1173206b17d7SAlexander Leidinger 
1174206b17d7SAlexander Leidinger 	if (m->synth_flags & FREAD)
1175206b17d7SAlexander Leidinger 		m->flags &= ~(M_RX | M_RXEN);
1176206b17d7SAlexander Leidinger 	if (m->synth_flags & FWRITE)
1177206b17d7SAlexander Leidinger 		m->flags &= ~M_TX;
1178206b17d7SAlexander Leidinger 
1179206b17d7SAlexander Leidinger 	if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1180206b17d7SAlexander Leidinger 		MPU_CALLBACK(m, m->cookie, m->flags);
1181206b17d7SAlexander Leidinger 
1182206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1183206b17d7SAlexander Leidinger 
1184206b17d7SAlexander Leidinger 	mtx_unlock(&m->qlock);
1185206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
1186206b17d7SAlexander Leidinger 	retval = 0;
1187206b17d7SAlexander Leidinger err:	return retval;
1188206b17d7SAlexander Leidinger }
1189206b17d7SAlexander Leidinger 
1190206b17d7SAlexander Leidinger /*
1191206b17d7SAlexander Leidinger  * Always blocking.
1192206b17d7SAlexander Leidinger  */
1193206b17d7SAlexander Leidinger 
1194206b17d7SAlexander Leidinger int
1195206b17d7SAlexander Leidinger midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1196206b17d7SAlexander Leidinger {
1197206b17d7SAlexander Leidinger 	struct snd_midi *m = ((struct synth_midi *)n)->m;
1198206b17d7SAlexander Leidinger 	int retval;
1199206b17d7SAlexander Leidinger 	int used;
1200206b17d7SAlexander Leidinger 	int i;
1201206b17d7SAlexander Leidinger 
1202206b17d7SAlexander Leidinger 	MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1203206b17d7SAlexander Leidinger 
1204206b17d7SAlexander Leidinger 	retval = 0;
1205206b17d7SAlexander Leidinger 
1206206b17d7SAlexander Leidinger 	if (m == NULL)
1207206b17d7SAlexander Leidinger 		return ENXIO;
1208206b17d7SAlexander Leidinger 
1209206b17d7SAlexander Leidinger 	mtx_lock(&m->lock);
1210206b17d7SAlexander Leidinger 	mtx_lock(&m->qlock);
1211206b17d7SAlexander Leidinger 
1212206b17d7SAlexander Leidinger 	if (!(m->flags & M_TX))
1213206b17d7SAlexander Leidinger 		goto err1;
1214206b17d7SAlexander Leidinger 
1215206b17d7SAlexander Leidinger 	if (midi_dumpraw)
1216206b17d7SAlexander Leidinger 		printf("midi dump: ");
1217206b17d7SAlexander Leidinger 
1218206b17d7SAlexander Leidinger 	while (len > 0) {
1219206b17d7SAlexander Leidinger 		while (MIDIQ_AVAIL(m->outq) == 0) {
1220206b17d7SAlexander Leidinger 			if (!(m->flags & M_TXEN)) {
1221206b17d7SAlexander Leidinger 				m->flags |= M_TXEN;
1222206b17d7SAlexander Leidinger 				MPU_CALLBACK(m, m->cookie, m->flags);
1223206b17d7SAlexander Leidinger 			}
1224206b17d7SAlexander Leidinger 			mtx_unlock(&m->lock);
1225206b17d7SAlexander Leidinger 			m->wchan = 1;
1226206b17d7SAlexander Leidinger 			MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
1227206b17d7SAlexander Leidinger 			retval = msleep(&m->wchan, &m->qlock,
1228206b17d7SAlexander Leidinger 			    PCATCH | PDROP, "midi TX", 0);
1229206b17d7SAlexander Leidinger 			/*
1230206b17d7SAlexander Leidinger 			 * We slept, maybe things have changed since last
1231206b17d7SAlexander Leidinger 			 * dying check
1232206b17d7SAlexander Leidinger 			 */
1233206b17d7SAlexander Leidinger 			if (retval == EINTR)
1234206b17d7SAlexander Leidinger 				goto err0;
1235206b17d7SAlexander Leidinger 
1236206b17d7SAlexander Leidinger 			if (retval)
1237206b17d7SAlexander Leidinger 				goto err0;
1238206b17d7SAlexander Leidinger 			mtx_lock(&m->lock);
1239206b17d7SAlexander Leidinger 			mtx_lock(&m->qlock);
1240206b17d7SAlexander Leidinger 			m->wchan = 0;
1241206b17d7SAlexander Leidinger 			if (!m->busy)
1242206b17d7SAlexander Leidinger 				goto err1;
1243206b17d7SAlexander Leidinger 		}
1244206b17d7SAlexander Leidinger 
1245206b17d7SAlexander Leidinger 		/*
1246206b17d7SAlexander Leidinger 	         * We are certain than data can be placed on the queue
1247206b17d7SAlexander Leidinger 	         */
1248206b17d7SAlexander Leidinger 
1249206b17d7SAlexander Leidinger 		used = MIN(MIDIQ_AVAIL(m->outq), len);
1250206b17d7SAlexander Leidinger 		used = MIN(used, MIDI_WSIZE);
12518f981688SAlexander Leidinger 		MIDI_DEBUG(5,
12528f981688SAlexander Leidinger 		    printf("midi_synth: resid %zu len %jd avail %jd\n",
1253206b17d7SAlexander Leidinger 		    len, (intmax_t)MIDIQ_LEN(m->outq),
1254206b17d7SAlexander Leidinger 		    (intmax_t)MIDIQ_AVAIL(m->outq)));
1255206b17d7SAlexander Leidinger 
1256206b17d7SAlexander Leidinger 		if (midi_dumpraw)
12578f981688SAlexander Leidinger 			for (i = 0; i < used; i++)
12588f981688SAlexander Leidinger 				printf("%x ", buf[i]);
1259206b17d7SAlexander Leidinger 
1260206b17d7SAlexander Leidinger 		MIDIQ_ENQ(m->outq, buf, used);
1261206b17d7SAlexander Leidinger 		len -= used;
1262206b17d7SAlexander Leidinger 
1263206b17d7SAlexander Leidinger 		/*
1264206b17d7SAlexander Leidinger 	         * Inform the bottom half that data can be written
1265206b17d7SAlexander Leidinger 	         */
1266206b17d7SAlexander Leidinger 		if (!(m->flags & M_TXEN)) {
1267206b17d7SAlexander Leidinger 			m->flags |= M_TXEN;
1268206b17d7SAlexander Leidinger 			MPU_CALLBACK(m, m->cookie, m->flags);
1269206b17d7SAlexander Leidinger 		}
1270206b17d7SAlexander Leidinger 	}
1271206b17d7SAlexander Leidinger 	/*
1272206b17d7SAlexander Leidinger 	 * If we Made it here then transfer is good
1273206b17d7SAlexander Leidinger 	 */
1274206b17d7SAlexander Leidinger 	if (midi_dumpraw)
1275206b17d7SAlexander Leidinger 		printf("\n");
1276206b17d7SAlexander Leidinger 
1277206b17d7SAlexander Leidinger 	retval = 0;
1278206b17d7SAlexander Leidinger err1:	mtx_unlock(&m->qlock);
1279206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
1280206b17d7SAlexander Leidinger err0:	return retval;
1281206b17d7SAlexander Leidinger }
1282206b17d7SAlexander Leidinger 
1283206b17d7SAlexander Leidinger static int
1284206b17d7SAlexander Leidinger midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1285206b17d7SAlexander Leidinger {
1286206b17d7SAlexander Leidinger 	u_char c[3];
1287206b17d7SAlexander Leidinger 
1288206b17d7SAlexander Leidinger 
1289206b17d7SAlexander Leidinger 	if (note > 127 || chn > 15)
1290206b17d7SAlexander Leidinger 		return (EINVAL);
1291206b17d7SAlexander Leidinger 
1292206b17d7SAlexander Leidinger 	if (vel > 127)
1293206b17d7SAlexander Leidinger 		vel = 127;
1294206b17d7SAlexander Leidinger 
1295206b17d7SAlexander Leidinger 	if (vel == 64) {
1296206b17d7SAlexander Leidinger 		c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1297206b17d7SAlexander Leidinger 		c[1] = (u_char)note;
1298206b17d7SAlexander Leidinger 		c[2] = 0;
1299206b17d7SAlexander Leidinger 	} else {
1300206b17d7SAlexander Leidinger 		c[0] = 0x80 | (chn & 0x0f);	/* Note off. */
1301206b17d7SAlexander Leidinger 		c[1] = (u_char)note;
1302206b17d7SAlexander Leidinger 		c[2] = (u_char)vel;
1303206b17d7SAlexander Leidinger 	}
1304206b17d7SAlexander Leidinger 
1305206b17d7SAlexander Leidinger 	return midisynth_writeraw(n, c, 3);
1306206b17d7SAlexander Leidinger }
1307206b17d7SAlexander Leidinger 
1308206b17d7SAlexander Leidinger static int
1309206b17d7SAlexander Leidinger midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1310206b17d7SAlexander Leidinger {
1311206b17d7SAlexander Leidinger 	u_char c[2];
1312206b17d7SAlexander Leidinger 
1313206b17d7SAlexander Leidinger 	if (instr > 127 || chn > 15)
1314206b17d7SAlexander Leidinger 		return EINVAL;
1315206b17d7SAlexander Leidinger 
1316206b17d7SAlexander Leidinger 	c[0] = 0xc0 | (chn & 0x0f);	/* Progamme change. */
1317206b17d7SAlexander Leidinger 	c[1] = instr + midi_instroff;
1318206b17d7SAlexander Leidinger 
1319206b17d7SAlexander Leidinger 	return midisynth_writeraw(n, c, 2);
1320206b17d7SAlexander Leidinger }
1321206b17d7SAlexander Leidinger 
1322206b17d7SAlexander Leidinger static int
1323206b17d7SAlexander Leidinger midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1324206b17d7SAlexander Leidinger {
1325206b17d7SAlexander Leidinger 	u_char c[3];
1326206b17d7SAlexander Leidinger 
1327206b17d7SAlexander Leidinger 	if (note > 127 || chn > 15)
1328206b17d7SAlexander Leidinger 		return EINVAL;
1329206b17d7SAlexander Leidinger 
1330206b17d7SAlexander Leidinger 	if (vel > 127)
1331206b17d7SAlexander Leidinger 		vel = 127;
1332206b17d7SAlexander Leidinger 
1333206b17d7SAlexander Leidinger 	c[0] = 0x90 | (chn & 0x0f);	/* Note on. */
1334206b17d7SAlexander Leidinger 	c[1] = (u_char)note;
1335206b17d7SAlexander Leidinger 	c[2] = (u_char)vel;
1336206b17d7SAlexander Leidinger 
1337206b17d7SAlexander Leidinger 	return midisynth_writeraw(n, c, 3);
1338206b17d7SAlexander Leidinger }
1339206b17d7SAlexander Leidinger static int
1340206b17d7SAlexander Leidinger midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1341206b17d7SAlexander Leidinger {
1342206b17d7SAlexander Leidinger 	return chan;
1343206b17d7SAlexander Leidinger }
1344206b17d7SAlexander Leidinger 
1345206b17d7SAlexander Leidinger static int
1346206b17d7SAlexander Leidinger midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1347206b17d7SAlexander Leidinger {
1348206b17d7SAlexander Leidinger 	u_char c[3];
1349206b17d7SAlexander Leidinger 
1350206b17d7SAlexander Leidinger 	if (ctrlnum > 127 || chn > 15)
1351206b17d7SAlexander Leidinger 		return EINVAL;
1352206b17d7SAlexander Leidinger 
1353206b17d7SAlexander Leidinger 	c[0] = 0xb0 | (chn & 0x0f);	/* Control Message. */
1354206b17d7SAlexander Leidinger 	c[1] = ctrlnum;
1355206b17d7SAlexander Leidinger 	c[2] = val;
1356206b17d7SAlexander Leidinger 	return midisynth_writeraw(n, c, 3);
1357206b17d7SAlexander Leidinger }
1358206b17d7SAlexander Leidinger 
1359206b17d7SAlexander Leidinger static int
1360206b17d7SAlexander Leidinger midisynth_bender(void *n, uint8_t chn, uint16_t val)
1361206b17d7SAlexander Leidinger {
1362206b17d7SAlexander Leidinger 	u_char c[3];
1363206b17d7SAlexander Leidinger 
1364206b17d7SAlexander Leidinger 
1365206b17d7SAlexander Leidinger 	if (val > 16383 || chn > 15)
1366206b17d7SAlexander Leidinger 		return EINVAL;
1367206b17d7SAlexander Leidinger 
1368206b17d7SAlexander Leidinger 	c[0] = 0xe0 | (chn & 0x0f);	/* Pitch bend. */
1369206b17d7SAlexander Leidinger 	c[1] = (u_char)val & 0x7f;
1370206b17d7SAlexander Leidinger 	c[2] = (u_char)(val >> 7) & 0x7f;
1371206b17d7SAlexander Leidinger 
1372206b17d7SAlexander Leidinger 	return midisynth_writeraw(n, c, 3);
1373206b17d7SAlexander Leidinger }
1374206b17d7SAlexander Leidinger 
1375206b17d7SAlexander Leidinger /*
1376206b17d7SAlexander Leidinger  * Single point of midi destructions.
1377206b17d7SAlexander Leidinger  */
1378206b17d7SAlexander Leidinger static int
1379206b17d7SAlexander Leidinger midi_destroy(struct snd_midi *m, int midiuninit)
1380206b17d7SAlexander Leidinger {
1381206b17d7SAlexander Leidinger 
1382206b17d7SAlexander Leidinger 	mtx_assert(&midistat_lock, MA_OWNED);
1383206b17d7SAlexander Leidinger 	mtx_assert(&m->lock, MA_OWNED);
1384206b17d7SAlexander Leidinger 
1385206b17d7SAlexander Leidinger 	MIDI_DEBUG(3, printf("midi_destroy\n"));
1386206b17d7SAlexander Leidinger 	m->dev->si_drv1 = NULL;
138790da2b28SAriff Abdullah 	mtx_unlock(&m->lock);	/* XXX */
1388206b17d7SAlexander Leidinger 	destroy_dev(m->dev);
1389206b17d7SAlexander Leidinger 	TAILQ_REMOVE(&midi_devs, m, link);
1390206b17d7SAlexander Leidinger 	if (midiuninit)
1391206b17d7SAlexander Leidinger 		MPU_UNINIT(m, m->cookie);
1392206b17d7SAlexander Leidinger 	free(MIDIQ_BUF(m->inq), M_MIDI);
1393206b17d7SAlexander Leidinger 	free(MIDIQ_BUF(m->outq), M_MIDI);
1394206b17d7SAlexander Leidinger 	mtx_destroy(&m->qlock);
1395206b17d7SAlexander Leidinger 	mtx_destroy(&m->lock);
1396671b5759STai-hwa Liang 	free(m->synth, M_MIDI);
1397206b17d7SAlexander Leidinger 	free(m, M_MIDI);
1398206b17d7SAlexander Leidinger 	return 0;
1399206b17d7SAlexander Leidinger }
1400206b17d7SAlexander Leidinger 
1401206b17d7SAlexander Leidinger /*
1402206b17d7SAlexander Leidinger  * Load and unload functions, creates the /dev/midistat device
1403206b17d7SAlexander Leidinger  */
1404206b17d7SAlexander Leidinger 
1405206b17d7SAlexander Leidinger static int
1406115b4b94SConrad Meyer midi_load(void)
1407206b17d7SAlexander Leidinger {
14088c0a77e3SAriff Abdullah 	mtx_init(&midistat_lock, "midistat lock", NULL, 0);
1409206b17d7SAlexander Leidinger 	TAILQ_INIT(&midi_devs);		/* Initialize the queue. */
1410206b17d7SAlexander Leidinger 
1411206b17d7SAlexander Leidinger 	midistat_dev = make_dev(&midistat_cdevsw,
1412206b17d7SAlexander Leidinger 	    MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1413206b17d7SAlexander Leidinger 	    UID_ROOT, GID_WHEEL, 0666, "midistat");
1414206b17d7SAlexander Leidinger 
1415206b17d7SAlexander Leidinger 	return 0;
1416206b17d7SAlexander Leidinger }
1417206b17d7SAlexander Leidinger 
1418206b17d7SAlexander Leidinger static int
1419115b4b94SConrad Meyer midi_unload(void)
1420206b17d7SAlexander Leidinger {
1421115b4b94SConrad Meyer 	struct snd_midi *m, *tmp;
1422206b17d7SAlexander Leidinger 	int retval;
1423206b17d7SAlexander Leidinger 
1424206b17d7SAlexander Leidinger 	MIDI_DEBUG(1, printf("midi_unload()\n"));
1425206b17d7SAlexander Leidinger 	retval = EBUSY;
1426206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
1427206b17d7SAlexander Leidinger 	if (midistat_isopen)
1428206b17d7SAlexander Leidinger 		goto exit0;
1429206b17d7SAlexander Leidinger 
1430115b4b94SConrad Meyer 	TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
1431206b17d7SAlexander Leidinger 		mtx_lock(&m->lock);
1432206b17d7SAlexander Leidinger 		if (m->busy)
1433206b17d7SAlexander Leidinger 			retval = EBUSY;
1434206b17d7SAlexander Leidinger 		else
1435206b17d7SAlexander Leidinger 			retval = midi_destroy(m, 1);
1436206b17d7SAlexander Leidinger 		if (retval)
1437206b17d7SAlexander Leidinger 			goto exit1;
1438206b17d7SAlexander Leidinger 	}
1439206b17d7SAlexander Leidinger 
144090da2b28SAriff Abdullah 	mtx_unlock(&midistat_lock);	/* XXX */
144190da2b28SAriff Abdullah 
1442206b17d7SAlexander Leidinger 	destroy_dev(midistat_dev);
1443206b17d7SAlexander Leidinger 	/*
1444206b17d7SAlexander Leidinger 	 * Made it here then unload is complete
1445206b17d7SAlexander Leidinger 	 */
1446206b17d7SAlexander Leidinger 	mtx_destroy(&midistat_lock);
1447206b17d7SAlexander Leidinger 	return 0;
1448206b17d7SAlexander Leidinger 
1449206b17d7SAlexander Leidinger exit1:
1450206b17d7SAlexander Leidinger 	mtx_unlock(&m->lock);
1451206b17d7SAlexander Leidinger exit0:
1452206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
14538f981688SAlexander Leidinger 	if (retval)
14548f981688SAlexander Leidinger 		MIDI_DEBUG(2, printf("midi_unload: failed\n"));
1455206b17d7SAlexander Leidinger 	return retval;
1456206b17d7SAlexander Leidinger }
1457206b17d7SAlexander Leidinger 
1458206b17d7SAlexander Leidinger extern int seq_modevent(module_t mod, int type, void *data);
1459206b17d7SAlexander Leidinger 
1460206b17d7SAlexander Leidinger static int
1461206b17d7SAlexander Leidinger midi_modevent(module_t mod, int type, void *data)
1462206b17d7SAlexander Leidinger {
1463206b17d7SAlexander Leidinger 	int retval;
1464206b17d7SAlexander Leidinger 
1465206b17d7SAlexander Leidinger 	retval = 0;
1466206b17d7SAlexander Leidinger 
1467206b17d7SAlexander Leidinger 	switch (type) {
1468206b17d7SAlexander Leidinger 	case MOD_LOAD:
1469206b17d7SAlexander Leidinger 		retval = midi_load();
1470ff749957SAriff Abdullah #if 0
1471206b17d7SAlexander Leidinger 		if (retval == 0)
1472206b17d7SAlexander Leidinger 			retval = seq_modevent(mod, type, data);
1473ff749957SAriff Abdullah #endif
1474206b17d7SAlexander Leidinger 		break;
1475206b17d7SAlexander Leidinger 
1476206b17d7SAlexander Leidinger 	case MOD_UNLOAD:
1477206b17d7SAlexander Leidinger 		retval = midi_unload();
1478ff749957SAriff Abdullah #if 0
1479206b17d7SAlexander Leidinger 		if (retval == 0)
1480206b17d7SAlexander Leidinger 			retval = seq_modevent(mod, type, data);
1481ff749957SAriff Abdullah #endif
1482206b17d7SAlexander Leidinger 		break;
1483206b17d7SAlexander Leidinger 
1484206b17d7SAlexander Leidinger 	default:
1485206b17d7SAlexander Leidinger 		break;
1486206b17d7SAlexander Leidinger 	}
1487206b17d7SAlexander Leidinger 
1488206b17d7SAlexander Leidinger 	return retval;
1489206b17d7SAlexander Leidinger }
1490206b17d7SAlexander Leidinger 
1491206b17d7SAlexander Leidinger kobj_t
1492206b17d7SAlexander Leidinger midimapper_addseq(void *arg1, int *unit, void **cookie)
1493206b17d7SAlexander Leidinger {
149487d8fcc8SPedro F. Giffuni 	unit = NULL;
1495206b17d7SAlexander Leidinger 
1496206b17d7SAlexander Leidinger 	return (kobj_t)arg1;
1497206b17d7SAlexander Leidinger }
1498206b17d7SAlexander Leidinger 
1499206b17d7SAlexander Leidinger int
1500206b17d7SAlexander Leidinger midimapper_open(void *arg1, void **cookie)
1501206b17d7SAlexander Leidinger {
1502206b17d7SAlexander Leidinger 	int retval = 0;
1503206b17d7SAlexander Leidinger 	struct snd_midi *m;
1504206b17d7SAlexander Leidinger 
1505206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
1506206b17d7SAlexander Leidinger 
1507206b17d7SAlexander Leidinger 	TAILQ_FOREACH(m, &midi_devs, link) {
1508206b17d7SAlexander Leidinger 		retval++;
1509206b17d7SAlexander Leidinger 	}
1510206b17d7SAlexander Leidinger 
1511206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
1512206b17d7SAlexander Leidinger 	return retval;
1513206b17d7SAlexander Leidinger }
1514206b17d7SAlexander Leidinger 
1515206b17d7SAlexander Leidinger int
1516206b17d7SAlexander Leidinger midimapper_close(void *arg1, void *cookie)
1517206b17d7SAlexander Leidinger {
1518206b17d7SAlexander Leidinger 	return 0;
1519206b17d7SAlexander Leidinger }
1520206b17d7SAlexander Leidinger 
1521206b17d7SAlexander Leidinger kobj_t
1522206b17d7SAlexander Leidinger midimapper_fetch_synth(void *arg, void *cookie, int unit)
1523206b17d7SAlexander Leidinger {
1524206b17d7SAlexander Leidinger 	struct snd_midi *m;
1525206b17d7SAlexander Leidinger 	int retval = 0;
1526206b17d7SAlexander Leidinger 
1527206b17d7SAlexander Leidinger 	mtx_lock(&midistat_lock);
1528206b17d7SAlexander Leidinger 
1529206b17d7SAlexander Leidinger 	TAILQ_FOREACH(m, &midi_devs, link) {
1530206b17d7SAlexander Leidinger 		if (unit == retval) {
1531206b17d7SAlexander Leidinger 			mtx_unlock(&midistat_lock);
1532206b17d7SAlexander Leidinger 			return (kobj_t)m->synth;
1533206b17d7SAlexander Leidinger 		}
1534206b17d7SAlexander Leidinger 		retval++;
1535206b17d7SAlexander Leidinger 	}
1536206b17d7SAlexander Leidinger 
1537206b17d7SAlexander Leidinger 	mtx_unlock(&midistat_lock);
1538206b17d7SAlexander Leidinger 	return NULL;
1539206b17d7SAlexander Leidinger }
1540206b17d7SAlexander Leidinger 
1541206b17d7SAlexander Leidinger DEV_MODULE(midi, midi_modevent, NULL);
1542206b17d7SAlexander Leidinger MODULE_VERSION(midi, 1);
1543