1206b17d7SAlexander Leidinger /*-
2b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro 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/param.h>
4035fd0fc4SMark Johnston #include <sys/systm.h>
41206b17d7SAlexander Leidinger #include <sys/queue.h>
42206b17d7SAlexander Leidinger #include <sys/kernel.h>
43206b17d7SAlexander Leidinger #include <sys/lock.h>
44206b17d7SAlexander Leidinger #include <sys/mutex.h>
45206b17d7SAlexander Leidinger #include <sys/proc.h>
46206b17d7SAlexander Leidinger #include <sys/signalvar.h>
47206b17d7SAlexander Leidinger #include <sys/conf.h>
48206b17d7SAlexander Leidinger #include <sys/selinfo.h>
49206b17d7SAlexander Leidinger #include <sys/sysctl.h>
50206b17d7SAlexander Leidinger #include <sys/malloc.h>
5135fd0fc4SMark Johnston #include <sys/sx.h>
52206b17d7SAlexander Leidinger #include <sys/proc.h>
53206b17d7SAlexander Leidinger #include <sys/fcntl.h>
54206b17d7SAlexander Leidinger #include <sys/types.h>
55206b17d7SAlexander Leidinger #include <sys/uio.h>
56206b17d7SAlexander Leidinger #include <sys/poll.h>
57206b17d7SAlexander Leidinger #include <sys/sbuf.h>
58206b17d7SAlexander Leidinger #include <sys/kobj.h>
59206b17d7SAlexander Leidinger #include <sys/module.h>
60206b17d7SAlexander Leidinger
6190da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
6290da2b28SAriff Abdullah #include "opt_snd.h"
6390da2b28SAriff Abdullah #endif
6490da2b28SAriff Abdullah
65206b17d7SAlexander Leidinger #include <dev/sound/midi/midi.h>
66206b17d7SAlexander Leidinger #include "mpu_if.h"
67206b17d7SAlexander Leidinger
68206b17d7SAlexander Leidinger #include <dev/sound/midi/midiq.h>
69206b17d7SAlexander Leidinger #include "synth_if.h"
70206b17d7SAlexander Leidinger MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
71206b17d7SAlexander Leidinger
725870e3c9SAriff Abdullah #ifndef KOBJMETHOD_END
735870e3c9SAriff Abdullah #define KOBJMETHOD_END { NULL, NULL }
745870e3c9SAriff Abdullah #endif
75206b17d7SAlexander Leidinger
76206b17d7SAlexander Leidinger #define MIDI_DEV_MIDICTL 12
77206b17d7SAlexander Leidinger
78206b17d7SAlexander Leidinger enum midi_states {
79206b17d7SAlexander Leidinger MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
80206b17d7SAlexander Leidinger };
81206b17d7SAlexander Leidinger
82206b17d7SAlexander Leidinger /*
837cbd5addSTai-hwa Liang * The MPU interface current has init() uninit() inqsize() outqsize()
84206b17d7SAlexander Leidinger * callback() : fiddle with the tx|rx status.
85206b17d7SAlexander Leidinger */
86206b17d7SAlexander Leidinger
87206b17d7SAlexander Leidinger #include "mpu_if.h"
88206b17d7SAlexander Leidinger
89206b17d7SAlexander Leidinger /*
90206b17d7SAlexander Leidinger * /dev/rmidi Structure definitions
91206b17d7SAlexander Leidinger */
92206b17d7SAlexander Leidinger
93206b17d7SAlexander Leidinger #define MIDI_NAMELEN 16
94206b17d7SAlexander Leidinger struct snd_midi {
95206b17d7SAlexander Leidinger KOBJ_FIELDS;
96206b17d7SAlexander Leidinger struct mtx lock; /* Protects all but queues */
97206b17d7SAlexander Leidinger void *cookie;
98206b17d7SAlexander Leidinger
99206b17d7SAlexander Leidinger int unit; /* Should only be used in midistat */
100206b17d7SAlexander Leidinger int channel; /* Should only be used in midistat */
101206b17d7SAlexander Leidinger
102206b17d7SAlexander Leidinger int busy;
103206b17d7SAlexander Leidinger int flags; /* File flags */
104206b17d7SAlexander Leidinger char name[MIDI_NAMELEN];
105206b17d7SAlexander Leidinger struct mtx qlock; /* Protects inq, outq and flags */
106206b17d7SAlexander Leidinger MIDIQ_HEAD(, char) inq, outq;
107206b17d7SAlexander Leidinger int rchan, wchan;
108206b17d7SAlexander Leidinger struct selinfo rsel, wsel;
1098f981688SAlexander Leidinger int hiwat; /* QLEN(outq)>High-water -> disable
1108f981688SAlexander Leidinger * writes from userland */
111206b17d7SAlexander Leidinger enum midi_states inq_state;
1128f981688SAlexander Leidinger int inq_status, inq_left; /* Variables for the state machine in
1138f981688SAlexander Leidinger * Midi_in, this is to provide that
1148f981688SAlexander Leidinger * signals only get issued only
115206b17d7SAlexander Leidinger * complete command packets. */
116206b17d7SAlexander Leidinger struct proc *async;
117206b17d7SAlexander Leidinger struct cdev *dev;
118206b17d7SAlexander Leidinger struct synth_midi *synth;
119206b17d7SAlexander Leidinger int synth_flags;
120206b17d7SAlexander Leidinger TAILQ_ENTRY(snd_midi) link;
121206b17d7SAlexander Leidinger };
122206b17d7SAlexander Leidinger
123206b17d7SAlexander Leidinger struct synth_midi {
124206b17d7SAlexander Leidinger KOBJ_FIELDS;
125206b17d7SAlexander Leidinger struct snd_midi *m;
126206b17d7SAlexander Leidinger };
127206b17d7SAlexander Leidinger
128206b17d7SAlexander Leidinger static synth_open_t midisynth_open;
129206b17d7SAlexander Leidinger static synth_close_t midisynth_close;
130206b17d7SAlexander Leidinger static synth_writeraw_t midisynth_writeraw;
131206b17d7SAlexander Leidinger static synth_killnote_t midisynth_killnote;
132206b17d7SAlexander Leidinger static synth_startnote_t midisynth_startnote;
133206b17d7SAlexander Leidinger static synth_setinstr_t midisynth_setinstr;
134206b17d7SAlexander Leidinger static synth_alloc_t midisynth_alloc;
135206b17d7SAlexander Leidinger static synth_controller_t midisynth_controller;
136206b17d7SAlexander Leidinger static synth_bender_t midisynth_bender;
137206b17d7SAlexander Leidinger
138206b17d7SAlexander Leidinger static kobj_method_t midisynth_methods[] = {
139206b17d7SAlexander Leidinger KOBJMETHOD(synth_open, midisynth_open),
140206b17d7SAlexander Leidinger KOBJMETHOD(synth_close, midisynth_close),
141206b17d7SAlexander Leidinger KOBJMETHOD(synth_writeraw, midisynth_writeraw),
142206b17d7SAlexander Leidinger KOBJMETHOD(synth_setinstr, midisynth_setinstr),
143206b17d7SAlexander Leidinger KOBJMETHOD(synth_startnote, midisynth_startnote),
144206b17d7SAlexander Leidinger KOBJMETHOD(synth_killnote, midisynth_killnote),
145206b17d7SAlexander Leidinger KOBJMETHOD(synth_alloc, midisynth_alloc),
146206b17d7SAlexander Leidinger KOBJMETHOD(synth_controller, midisynth_controller),
147206b17d7SAlexander Leidinger KOBJMETHOD(synth_bender, midisynth_bender),
14890da2b28SAriff Abdullah KOBJMETHOD_END
149206b17d7SAlexander Leidinger };
150206b17d7SAlexander Leidinger
151206b17d7SAlexander Leidinger DEFINE_CLASS(midisynth, midisynth_methods, 0);
152206b17d7SAlexander Leidinger
153206b17d7SAlexander Leidinger /*
154206b17d7SAlexander Leidinger * Module Exports & Interface
155206b17d7SAlexander Leidinger *
1567cbd5addSTai-hwa Liang * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan,
1577cbd5addSTai-hwa Liang * void *cookie)
1587cbd5addSTai-hwa Liang * int midi_uninit(struct snd_midi *)
1597cbd5addSTai-hwa Liang *
1607cbd5addSTai-hwa Liang * 0 == no error
1617cbd5addSTai-hwa Liang * EBUSY or other error
1627cbd5addSTai-hwa Liang *
1637cbd5addSTai-hwa Liang * int midi_in(struct snd_midi *, char *buf, int count)
1647cbd5addSTai-hwa Liang * int midi_out(struct snd_midi *, char *buf, int count)
165206b17d7SAlexander Leidinger *
166206b17d7SAlexander Leidinger * midi_{in,out} return actual size transfered
167206b17d7SAlexander Leidinger *
168206b17d7SAlexander Leidinger */
169206b17d7SAlexander Leidinger
170206b17d7SAlexander Leidinger /*
171206b17d7SAlexander Leidinger * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
172206b17d7SAlexander Leidinger */
173206b17d7SAlexander Leidinger
174206b17d7SAlexander Leidinger TAILQ_HEAD(, snd_midi) midi_devs;
175206b17d7SAlexander Leidinger
176206b17d7SAlexander Leidinger /*
177206b17d7SAlexander Leidinger * /dev/midistat variables and declarations, protected by midistat_lock
178206b17d7SAlexander Leidinger */
179206b17d7SAlexander Leidinger
1802d6fc246SChristos Margiolis struct sx mstat_lock;
181fc76e24eSChristos Margiolis
182206b17d7SAlexander Leidinger static int midistat_isopen = 0;
183206b17d7SAlexander Leidinger static struct sbuf midistat_sbuf;
184206b17d7SAlexander Leidinger static struct cdev *midistat_dev;
185206b17d7SAlexander Leidinger
186206b17d7SAlexander Leidinger /*
187206b17d7SAlexander Leidinger * /dev/midistat dev_t declarations
188206b17d7SAlexander Leidinger */
189206b17d7SAlexander Leidinger
190206b17d7SAlexander Leidinger static d_open_t midistat_open;
191206b17d7SAlexander Leidinger static d_close_t midistat_close;
192206b17d7SAlexander Leidinger static d_read_t midistat_read;
193206b17d7SAlexander Leidinger
194206b17d7SAlexander Leidinger static struct cdevsw midistat_cdevsw = {
195206b17d7SAlexander Leidinger .d_version = D_VERSION,
196206b17d7SAlexander Leidinger .d_open = midistat_open,
197206b17d7SAlexander Leidinger .d_close = midistat_close,
198206b17d7SAlexander Leidinger .d_read = midistat_read,
199206b17d7SAlexander Leidinger .d_name = "midistat",
200206b17d7SAlexander Leidinger };
201206b17d7SAlexander Leidinger
202206b17d7SAlexander Leidinger /*
203206b17d7SAlexander Leidinger * /dev/rmidi dev_t declarations, struct variable access is protected by
204206b17d7SAlexander Leidinger * locks contained within the structure.
205206b17d7SAlexander Leidinger */
206206b17d7SAlexander Leidinger
207206b17d7SAlexander Leidinger static d_open_t midi_open;
208206b17d7SAlexander Leidinger static d_close_t midi_close;
209206b17d7SAlexander Leidinger static d_ioctl_t midi_ioctl;
210206b17d7SAlexander Leidinger static d_read_t midi_read;
211206b17d7SAlexander Leidinger static d_write_t midi_write;
212206b17d7SAlexander Leidinger static d_poll_t midi_poll;
213206b17d7SAlexander Leidinger
214206b17d7SAlexander Leidinger static struct cdevsw midi_cdevsw = {
215206b17d7SAlexander Leidinger .d_version = D_VERSION,
216206b17d7SAlexander Leidinger .d_open = midi_open,
217206b17d7SAlexander Leidinger .d_close = midi_close,
218206b17d7SAlexander Leidinger .d_read = midi_read,
219206b17d7SAlexander Leidinger .d_write = midi_write,
220206b17d7SAlexander Leidinger .d_ioctl = midi_ioctl,
221206b17d7SAlexander Leidinger .d_poll = midi_poll,
222206b17d7SAlexander Leidinger .d_name = "rmidi",
223206b17d7SAlexander Leidinger };
224206b17d7SAlexander Leidinger
225206b17d7SAlexander Leidinger /*
226206b17d7SAlexander Leidinger * Prototypes of library functions
227206b17d7SAlexander Leidinger */
228206b17d7SAlexander Leidinger
229206b17d7SAlexander Leidinger static int midi_destroy(struct snd_midi *, int);
230206b17d7SAlexander Leidinger static int midistat_prepare(struct sbuf * s);
231206b17d7SAlexander Leidinger static int midi_load(void);
232206b17d7SAlexander Leidinger static int midi_unload(void);
233206b17d7SAlexander Leidinger
234206b17d7SAlexander Leidinger /*
235206b17d7SAlexander Leidinger * Misc declr.
236206b17d7SAlexander Leidinger */
2377029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2387029da5cSPawel Biernacki "Midi driver");
2397029da5cSPawel Biernacki static SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2407029da5cSPawel Biernacki "Status device");
241206b17d7SAlexander Leidinger
242206b17d7SAlexander Leidinger int midi_debug;
243851a904aSAlexander Leidinger /* XXX: should this be moved into debug.midi? */
244206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
245206b17d7SAlexander Leidinger
246206b17d7SAlexander Leidinger int midi_dumpraw;
247206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
248206b17d7SAlexander Leidinger
249206b17d7SAlexander Leidinger int midi_instroff;
250206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
251206b17d7SAlexander Leidinger
252206b17d7SAlexander Leidinger int midistat_verbose;
253206b17d7SAlexander Leidinger SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
254206b17d7SAlexander Leidinger &midistat_verbose, 0, "");
255206b17d7SAlexander Leidinger
256206b17d7SAlexander Leidinger #define MIDI_DEBUG(l,a) if(midi_debug>=l) a
257206b17d7SAlexander Leidinger /*
258206b17d7SAlexander Leidinger * CODE START
259206b17d7SAlexander Leidinger */
260206b17d7SAlexander Leidinger
2612d6fc246SChristos Margiolis void
midistat_lock(void)2622d6fc246SChristos Margiolis midistat_lock(void)
2632d6fc246SChristos Margiolis {
2642d6fc246SChristos Margiolis sx_xlock(&mstat_lock);
2652d6fc246SChristos Margiolis }
2662d6fc246SChristos Margiolis
2672d6fc246SChristos Margiolis void
midistat_unlock(void)2682d6fc246SChristos Margiolis midistat_unlock(void)
2692d6fc246SChristos Margiolis {
2702d6fc246SChristos Margiolis sx_xunlock(&mstat_lock);
2712d6fc246SChristos Margiolis }
2722d6fc246SChristos Margiolis
2732d6fc246SChristos Margiolis void
midistat_lockassert(void)2742d6fc246SChristos Margiolis midistat_lockassert(void)
2752d6fc246SChristos Margiolis {
2762d6fc246SChristos Margiolis sx_assert(&mstat_lock, SA_XLOCKED);
2772d6fc246SChristos Margiolis }
2782d6fc246SChristos Margiolis
279206b17d7SAlexander Leidinger /*
280206b17d7SAlexander Leidinger * Register a new rmidi device. cls midi_if interface unit == 0 means
281206b17d7SAlexander Leidinger * auto-assign new unit number unit != 0 already assigned a unit number, eg.
282206b17d7SAlexander Leidinger * not the first channel provided by this device. channel, sub-unit
283206b17d7SAlexander Leidinger * cookie is passed back on MPU calls Typical device drivers will call with
284206b17d7SAlexander Leidinger * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
285206b17d7SAlexander Leidinger * what unit number is used.
286206b17d7SAlexander Leidinger *
287206b17d7SAlexander Leidinger * It is an error to call midi_init with an already used unit/channel combo.
288206b17d7SAlexander Leidinger *
289206b17d7SAlexander Leidinger * Returns NULL on error
290206b17d7SAlexander Leidinger *
291206b17d7SAlexander Leidinger */
292206b17d7SAlexander Leidinger struct snd_midi *
midi_init(kobj_class_t cls,int unit,int channel,void * cookie)293206b17d7SAlexander Leidinger midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
294206b17d7SAlexander Leidinger {
295206b17d7SAlexander Leidinger struct snd_midi *m;
296206b17d7SAlexander Leidinger int i;
297206b17d7SAlexander Leidinger int inqsize, outqsize;
298526bd1d8SChristos Margiolis uint8_t *buf;
299206b17d7SAlexander Leidinger
300206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
3012d6fc246SChristos Margiolis midistat_lock();
302206b17d7SAlexander Leidinger /*
303206b17d7SAlexander Leidinger * Protect against call with existing unit/channel or auto-allocate a
304206b17d7SAlexander Leidinger * new unit number.
305206b17d7SAlexander Leidinger */
306206b17d7SAlexander Leidinger i = -1;
307206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) {
308206b17d7SAlexander Leidinger mtx_lock(&m->lock);
309206b17d7SAlexander Leidinger if (unit != 0) {
310206b17d7SAlexander Leidinger if (m->unit == unit && m->channel == channel) {
311206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
312206b17d7SAlexander Leidinger goto err0;
313206b17d7SAlexander Leidinger }
314206b17d7SAlexander Leidinger } else {
315206b17d7SAlexander Leidinger /*
316206b17d7SAlexander Leidinger * Find a better unit number
317206b17d7SAlexander Leidinger */
318206b17d7SAlexander Leidinger if (m->unit > i)
319206b17d7SAlexander Leidinger i = m->unit;
320206b17d7SAlexander Leidinger }
321206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
322206b17d7SAlexander Leidinger }
323206b17d7SAlexander Leidinger
324206b17d7SAlexander Leidinger if (unit == 0)
325206b17d7SAlexander Leidinger unit = i + 1;
326206b17d7SAlexander Leidinger
327206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
32835fd0fc4SMark Johnston m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
32935fd0fc4SMark Johnston m->synth = malloc(sizeof(*m->synth), M_MIDI, M_WAITOK | M_ZERO);
330206b17d7SAlexander Leidinger kobj_init((kobj_t)m->synth, &midisynth_class);
331206b17d7SAlexander Leidinger m->synth->m = m;
332206b17d7SAlexander Leidinger kobj_init((kobj_t)m, cls);
333206b17d7SAlexander Leidinger inqsize = MPU_INQSIZE(m, cookie);
334206b17d7SAlexander Leidinger outqsize = MPU_OUTQSIZE(m, cookie);
335206b17d7SAlexander Leidinger
336206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
337206b17d7SAlexander Leidinger if (!inqsize && !outqsize)
33835fd0fc4SMark Johnston goto err1;
339206b17d7SAlexander Leidinger
3408c0a77e3SAriff Abdullah mtx_init(&m->lock, "raw midi", NULL, 0);
3418c0a77e3SAriff Abdullah mtx_init(&m->qlock, "q raw midi", NULL, 0);
342206b17d7SAlexander Leidinger
343206b17d7SAlexander Leidinger mtx_lock(&m->lock);
344206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
345206b17d7SAlexander Leidinger
346206b17d7SAlexander Leidinger if (inqsize)
347526bd1d8SChristos Margiolis buf = malloc(sizeof(uint8_t) * inqsize, M_MIDI, M_NOWAIT);
348206b17d7SAlexander Leidinger else
349206b17d7SAlexander Leidinger buf = NULL;
350206b17d7SAlexander Leidinger
351206b17d7SAlexander Leidinger MIDIQ_INIT(m->inq, buf, inqsize);
352206b17d7SAlexander Leidinger
353206b17d7SAlexander Leidinger if (outqsize)
354526bd1d8SChristos Margiolis buf = malloc(sizeof(uint8_t) * outqsize, M_MIDI, M_NOWAIT);
355206b17d7SAlexander Leidinger else
356206b17d7SAlexander Leidinger buf = NULL;
357206b17d7SAlexander Leidinger m->hiwat = outqsize / 2;
358206b17d7SAlexander Leidinger
359206b17d7SAlexander Leidinger MIDIQ_INIT(m->outq, buf, outqsize);
360206b17d7SAlexander Leidinger
361206b17d7SAlexander Leidinger if ((inqsize && !MIDIQ_BUF(m->inq)) ||
362206b17d7SAlexander Leidinger (outqsize && !MIDIQ_BUF(m->outq)))
36335fd0fc4SMark Johnston goto err2;
364206b17d7SAlexander Leidinger
365206b17d7SAlexander Leidinger m->busy = 0;
366206b17d7SAlexander Leidinger m->flags = 0;
367206b17d7SAlexander Leidinger m->unit = unit;
368206b17d7SAlexander Leidinger m->channel = channel;
369206b17d7SAlexander Leidinger m->cookie = cookie;
370206b17d7SAlexander Leidinger
371206b17d7SAlexander Leidinger if (MPU_INIT(m, cookie))
37235fd0fc4SMark Johnston goto err2;
373206b17d7SAlexander Leidinger
374206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
375206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
376206b17d7SAlexander Leidinger
377206b17d7SAlexander Leidinger TAILQ_INSERT_TAIL(&midi_devs, m, link);
378206b17d7SAlexander Leidinger
3792d6fc246SChristos Margiolis midistat_unlock();
380206b17d7SAlexander Leidinger
3818b9e1b62SChristos Margiolis m->dev = make_dev(&midi_cdevsw, unit, UID_ROOT, GID_WHEEL, 0666,
3828b9e1b62SChristos Margiolis "midi%d.%d", unit, channel);
383206b17d7SAlexander Leidinger m->dev->si_drv1 = m;
384206b17d7SAlexander Leidinger
385206b17d7SAlexander Leidinger return m;
386206b17d7SAlexander Leidinger
38735fd0fc4SMark Johnston err2:
38835fd0fc4SMark Johnston mtx_destroy(&m->qlock);
389206b17d7SAlexander Leidinger mtx_destroy(&m->lock);
390206b17d7SAlexander Leidinger
391206b17d7SAlexander Leidinger if (MIDIQ_BUF(m->inq))
392206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->inq), M_MIDI);
393206b17d7SAlexander Leidinger if (MIDIQ_BUF(m->outq))
394206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->outq), M_MIDI);
39535fd0fc4SMark Johnston err1:
39635fd0fc4SMark Johnston free(m->synth, M_MIDI);
39735fd0fc4SMark Johnston free(m, M_MIDI);
39835fd0fc4SMark Johnston err0:
3992d6fc246SChristos Margiolis midistat_unlock();
400206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_init ended in error\n"));
401206b17d7SAlexander Leidinger return NULL;
402206b17d7SAlexander Leidinger }
403206b17d7SAlexander Leidinger
404206b17d7SAlexander Leidinger /*
405206b17d7SAlexander Leidinger * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
4067cbd5addSTai-hwa Liang * entry point. midi_uninit if fact, does not send any methods. A call to
407206b17d7SAlexander Leidinger * midi_uninit is a defacto promise that you won't manipulate ch anymore
408206b17d7SAlexander Leidinger *
409206b17d7SAlexander Leidinger */
410206b17d7SAlexander Leidinger
411206b17d7SAlexander Leidinger int
midi_uninit(struct snd_midi * m)412206b17d7SAlexander Leidinger midi_uninit(struct snd_midi *m)
413206b17d7SAlexander Leidinger {
414206b17d7SAlexander Leidinger int err;
415206b17d7SAlexander Leidinger
416076cf2ddSTai-hwa Liang err = EBUSY;
4172d6fc246SChristos Margiolis midistat_lock();
418206b17d7SAlexander Leidinger mtx_lock(&m->lock);
419206b17d7SAlexander Leidinger if (m->busy) {
420206b17d7SAlexander Leidinger if (!(m->rchan || m->wchan))
421206b17d7SAlexander Leidinger goto err;
422206b17d7SAlexander Leidinger
423206b17d7SAlexander Leidinger if (m->rchan) {
424206b17d7SAlexander Leidinger wakeup(&m->rchan);
425206b17d7SAlexander Leidinger m->rchan = 0;
426206b17d7SAlexander Leidinger }
427206b17d7SAlexander Leidinger if (m->wchan) {
428206b17d7SAlexander Leidinger wakeup(&m->wchan);
429206b17d7SAlexander Leidinger m->wchan = 0;
430206b17d7SAlexander Leidinger }
431206b17d7SAlexander Leidinger }
432206b17d7SAlexander Leidinger err = midi_destroy(m, 0);
433206b17d7SAlexander Leidinger if (!err)
434206b17d7SAlexander Leidinger goto exit;
435206b17d7SAlexander Leidinger
43635fd0fc4SMark Johnston err:
43735fd0fc4SMark Johnston mtx_unlock(&m->lock);
43835fd0fc4SMark Johnston exit:
4392d6fc246SChristos Margiolis midistat_unlock();
440206b17d7SAlexander Leidinger return err;
441206b17d7SAlexander Leidinger }
442206b17d7SAlexander Leidinger
443206b17d7SAlexander Leidinger /*
444206b17d7SAlexander Leidinger * midi_in: process all data until the queue is full, then discards the rest.
445206b17d7SAlexander Leidinger * Since midi_in is a state machine, data discards can cause it to get out of
446206b17d7SAlexander Leidinger * whack. Process as much as possible. It calls, wakeup, selnotify and
447206b17d7SAlexander Leidinger * psignal at most once.
448206b17d7SAlexander Leidinger */
449206b17d7SAlexander Leidinger
4502916c293SRuslan Ermilov #ifdef notdef
451206b17d7SAlexander Leidinger static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
4528f981688SAlexander Leidinger
453206b17d7SAlexander Leidinger #endif /* notdef */
454206b17d7SAlexander Leidinger /* Number of bytes in a MIDI command */
455206b17d7SAlexander Leidinger #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
456206b17d7SAlexander Leidinger #define MIDI_ACK 0xfe
457206b17d7SAlexander Leidinger #define MIDI_IS_STATUS(d) ((d) >= 0x80)
458206b17d7SAlexander Leidinger #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
459206b17d7SAlexander Leidinger
460206b17d7SAlexander Leidinger #define MIDI_SYSEX_START 0xF0
461206b17d7SAlexander Leidinger #define MIDI_SYSEX_END 0xF7
462206b17d7SAlexander Leidinger
463206b17d7SAlexander Leidinger int
midi_in(struct snd_midi * m,uint8_t * buf,int size)464526bd1d8SChristos Margiolis midi_in(struct snd_midi *m, uint8_t *buf, int size)
465206b17d7SAlexander Leidinger {
466206b17d7SAlexander Leidinger /* int i, sig, enq; */
467206b17d7SAlexander Leidinger int used;
4688f981688SAlexander Leidinger
469526bd1d8SChristos Margiolis /* uint8_t data; */
470206b17d7SAlexander Leidinger MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
471206b17d7SAlexander Leidinger
472206b17d7SAlexander Leidinger /*
473206b17d7SAlexander Leidinger * XXX: locking flub
474206b17d7SAlexander Leidinger */
475206b17d7SAlexander Leidinger if (!(m->flags & M_RX))
476206b17d7SAlexander Leidinger return size;
477206b17d7SAlexander Leidinger
478206b17d7SAlexander Leidinger used = 0;
479206b17d7SAlexander Leidinger
480206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
481206b17d7SAlexander Leidinger #if 0
482206b17d7SAlexander Leidinger /*
483206b17d7SAlexander Leidinger * Don't bother queuing if not in read mode. Discard everything and
484206b17d7SAlexander Leidinger * return size so the caller doesn't freak out.
485206b17d7SAlexander Leidinger */
486206b17d7SAlexander Leidinger
487206b17d7SAlexander Leidinger if (!(m->flags & M_RX))
488206b17d7SAlexander Leidinger return size;
489206b17d7SAlexander Leidinger
490206b17d7SAlexander Leidinger for (i = sig = 0; i < size; i++) {
491206b17d7SAlexander Leidinger data = buf[i];
492206b17d7SAlexander Leidinger enq = 0;
493206b17d7SAlexander Leidinger if (data == MIDI_ACK)
494206b17d7SAlexander Leidinger continue;
495206b17d7SAlexander Leidinger
496206b17d7SAlexander Leidinger switch (m->inq_state) {
497206b17d7SAlexander Leidinger case MIDI_IN_START:
498206b17d7SAlexander Leidinger if (MIDI_IS_STATUS(data)) {
499206b17d7SAlexander Leidinger switch (data) {
500206b17d7SAlexander Leidinger case 0xf0: /* Sysex */
501206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_SYSEX;
502206b17d7SAlexander Leidinger break;
503206b17d7SAlexander Leidinger case 0xf1: /* MTC quarter frame */
504206b17d7SAlexander Leidinger case 0xf3: /* Song select */
505206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA;
506206b17d7SAlexander Leidinger enq = 1;
507206b17d7SAlexander Leidinger m->inq_left = 1;
508206b17d7SAlexander Leidinger break;
509206b17d7SAlexander Leidinger case 0xf2: /* Song position pointer */
510206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA;
511206b17d7SAlexander Leidinger enq = 1;
512206b17d7SAlexander Leidinger m->inq_left = 2;
513206b17d7SAlexander Leidinger break;
514206b17d7SAlexander Leidinger default:
515206b17d7SAlexander Leidinger if (MIDI_IS_COMMON(data)) {
516206b17d7SAlexander Leidinger enq = 1;
517206b17d7SAlexander Leidinger sig = 1;
518206b17d7SAlexander Leidinger } else {
519206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA;
520206b17d7SAlexander Leidinger enq = 1;
521206b17d7SAlexander Leidinger m->inq_status = data;
522206b17d7SAlexander Leidinger m->inq_left = MIDI_LENGTH(data);
523206b17d7SAlexander Leidinger }
524206b17d7SAlexander Leidinger break;
525206b17d7SAlexander Leidinger }
526206b17d7SAlexander Leidinger } else if (MIDI_IS_STATUS(m->inq_status)) {
527206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_DATA;
528206b17d7SAlexander Leidinger if (!MIDIQ_FULL(m->inq)) {
529206b17d7SAlexander Leidinger used++;
530206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, &m->inq_status, 1);
531206b17d7SAlexander Leidinger }
532206b17d7SAlexander Leidinger enq = 1;
533206b17d7SAlexander Leidinger m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
534206b17d7SAlexander Leidinger }
535206b17d7SAlexander Leidinger break;
536206b17d7SAlexander Leidinger /*
537206b17d7SAlexander Leidinger * End of case MIDI_IN_START:
538206b17d7SAlexander Leidinger */
539206b17d7SAlexander Leidinger
540206b17d7SAlexander Leidinger case MIDI_IN_DATA:
541206b17d7SAlexander Leidinger enq = 1;
542206b17d7SAlexander Leidinger if (--m->inq_left <= 0)
543206b17d7SAlexander Leidinger sig = 1;/* deliver data */
544206b17d7SAlexander Leidinger break;
545206b17d7SAlexander Leidinger case MIDI_IN_SYSEX:
546206b17d7SAlexander Leidinger if (data == MIDI_SYSEX_END)
547206b17d7SAlexander Leidinger m->inq_state = MIDI_IN_START;
548206b17d7SAlexander Leidinger break;
549206b17d7SAlexander Leidinger }
550206b17d7SAlexander Leidinger
551206b17d7SAlexander Leidinger if (enq)
552206b17d7SAlexander Leidinger if (!MIDIQ_FULL(m->inq)) {
553206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, &data, 1);
554206b17d7SAlexander Leidinger used++;
555206b17d7SAlexander Leidinger }
556206b17d7SAlexander Leidinger /*
557206b17d7SAlexander Leidinger * End of the state machines main "for loop"
558206b17d7SAlexander Leidinger */
559206b17d7SAlexander Leidinger }
560206b17d7SAlexander Leidinger if (sig) {
561206b17d7SAlexander Leidinger #endif
5628f981688SAlexander Leidinger MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
5638f981688SAlexander Leidinger (intmax_t)MIDIQ_LEN(m->inq),
5648f981688SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->inq)));
565206b17d7SAlexander Leidinger if (MIDIQ_AVAIL(m->inq) > size) {
566206b17d7SAlexander Leidinger used = size;
567206b17d7SAlexander Leidinger MIDIQ_ENQ(m->inq, buf, size);
568206b17d7SAlexander Leidinger } else {
569206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
570206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
571206b17d7SAlexander Leidinger return 0;
572206b17d7SAlexander Leidinger }
573206b17d7SAlexander Leidinger if (m->rchan) {
574206b17d7SAlexander Leidinger wakeup(&m->rchan);
575206b17d7SAlexander Leidinger m->rchan = 0;
576206b17d7SAlexander Leidinger }
577206b17d7SAlexander Leidinger selwakeup(&m->rsel);
578206b17d7SAlexander Leidinger if (m->async) {
579206b17d7SAlexander Leidinger PROC_LOCK(m->async);
5808451d0ddSKip Macy kern_psignal(m->async, SIGIO);
581206b17d7SAlexander Leidinger PROC_UNLOCK(m->async);
582206b17d7SAlexander Leidinger }
583206b17d7SAlexander Leidinger #if 0
584206b17d7SAlexander Leidinger }
585206b17d7SAlexander Leidinger #endif
586206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
587206b17d7SAlexander Leidinger return used;
588206b17d7SAlexander Leidinger }
589206b17d7SAlexander Leidinger
590206b17d7SAlexander Leidinger /*
591206b17d7SAlexander Leidinger * midi_out: The only clearer of the M_TXEN flag.
592206b17d7SAlexander Leidinger */
593206b17d7SAlexander Leidinger int
midi_out(struct snd_midi * m,uint8_t * buf,int size)594526bd1d8SChristos Margiolis midi_out(struct snd_midi *m, uint8_t *buf, int size)
595206b17d7SAlexander Leidinger {
596206b17d7SAlexander Leidinger int used;
597206b17d7SAlexander Leidinger
598206b17d7SAlexander Leidinger /*
599206b17d7SAlexander Leidinger * XXX: locking flub
600206b17d7SAlexander Leidinger */
601206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN))
602206b17d7SAlexander Leidinger return 0;
603206b17d7SAlexander Leidinger
604206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midi_out: %p\n", m));
605206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
606206b17d7SAlexander Leidinger used = MIN(size, MIDIQ_LEN(m->outq));
607206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
608206b17d7SAlexander Leidinger if (used)
609206b17d7SAlexander Leidinger MIDIQ_DEQ(m->outq, buf, used);
610206b17d7SAlexander Leidinger if (MIDIQ_EMPTY(m->outq)) {
611206b17d7SAlexander Leidinger m->flags &= ~M_TXEN;
612206b17d7SAlexander Leidinger MPU_CALLBACKP(m, m->cookie, m->flags);
613206b17d7SAlexander Leidinger }
614206b17d7SAlexander Leidinger if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
615206b17d7SAlexander Leidinger if (m->wchan) {
616206b17d7SAlexander Leidinger wakeup(&m->wchan);
617206b17d7SAlexander Leidinger m->wchan = 0;
618206b17d7SAlexander Leidinger }
619206b17d7SAlexander Leidinger selwakeup(&m->wsel);
620206b17d7SAlexander Leidinger if (m->async) {
621206b17d7SAlexander Leidinger PROC_LOCK(m->async);
6228451d0ddSKip Macy kern_psignal(m->async, SIGIO);
623206b17d7SAlexander Leidinger PROC_UNLOCK(m->async);
624206b17d7SAlexander Leidinger }
625206b17d7SAlexander Leidinger }
626206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
627206b17d7SAlexander Leidinger return used;
628206b17d7SAlexander Leidinger }
629206b17d7SAlexander Leidinger
630206b17d7SAlexander Leidinger /*
631206b17d7SAlexander Leidinger * /dev/rmidi#.# device access functions
632206b17d7SAlexander Leidinger */
633206b17d7SAlexander Leidinger int
midi_open(struct cdev * i_dev,int flags,int mode,struct thread * td)634206b17d7SAlexander Leidinger midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
635206b17d7SAlexander Leidinger {
636206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1;
637206b17d7SAlexander Leidinger int retval;
638206b17d7SAlexander Leidinger
639206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
640206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
641206b17d7SAlexander Leidinger if (m == NULL)
642206b17d7SAlexander Leidinger return ENXIO;
643206b17d7SAlexander Leidinger
644206b17d7SAlexander Leidinger mtx_lock(&m->lock);
645206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
646206b17d7SAlexander Leidinger
647206b17d7SAlexander Leidinger retval = 0;
648206b17d7SAlexander Leidinger
649206b17d7SAlexander Leidinger if (flags & FREAD) {
650206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->inq) == 0)
651206b17d7SAlexander Leidinger retval = ENXIO;
652206b17d7SAlexander Leidinger else if (m->flags & M_RX)
653206b17d7SAlexander Leidinger retval = EBUSY;
654206b17d7SAlexander Leidinger if (retval)
655206b17d7SAlexander Leidinger goto err;
656206b17d7SAlexander Leidinger }
657206b17d7SAlexander Leidinger if (flags & FWRITE) {
658206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->outq) == 0)
659206b17d7SAlexander Leidinger retval = ENXIO;
660206b17d7SAlexander Leidinger else if (m->flags & M_TX)
661206b17d7SAlexander Leidinger retval = EBUSY;
662206b17d7SAlexander Leidinger if (retval)
663206b17d7SAlexander Leidinger goto err;
664206b17d7SAlexander Leidinger }
665206b17d7SAlexander Leidinger m->busy++;
666206b17d7SAlexander Leidinger
667206b17d7SAlexander Leidinger m->rchan = 0;
668206b17d7SAlexander Leidinger m->wchan = 0;
669206b17d7SAlexander Leidinger m->async = 0;
670206b17d7SAlexander Leidinger
671206b17d7SAlexander Leidinger if (flags & FREAD) {
672206b17d7SAlexander Leidinger m->flags |= M_RX | M_RXEN;
673206b17d7SAlexander Leidinger /*
6748f981688SAlexander Leidinger * Only clear the inq, the outq might still have data to drain
6758f981688SAlexander Leidinger * from a previous session
676206b17d7SAlexander Leidinger */
677206b17d7SAlexander Leidinger MIDIQ_CLEAR(m->inq);
67874b8d63dSPedro F. Giffuni }
679206b17d7SAlexander Leidinger
680206b17d7SAlexander Leidinger if (flags & FWRITE)
681206b17d7SAlexander Leidinger m->flags |= M_TX;
682206b17d7SAlexander Leidinger
683206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
684206b17d7SAlexander Leidinger
685206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midi_open: opened.\n"));
686206b17d7SAlexander Leidinger
687206b17d7SAlexander Leidinger err: mtx_unlock(&m->qlock);
688206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
689206b17d7SAlexander Leidinger return retval;
690206b17d7SAlexander Leidinger }
691206b17d7SAlexander Leidinger
692206b17d7SAlexander Leidinger int
midi_close(struct cdev * i_dev,int flags,int mode,struct thread * td)693206b17d7SAlexander Leidinger midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
694206b17d7SAlexander Leidinger {
695206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1;
696206b17d7SAlexander Leidinger int retval;
697206b17d7SAlexander Leidinger int oldflags;
698206b17d7SAlexander Leidinger
699206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
700206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
701206b17d7SAlexander Leidinger
702206b17d7SAlexander Leidinger if (m == NULL)
703206b17d7SAlexander Leidinger return ENXIO;
704206b17d7SAlexander Leidinger
705206b17d7SAlexander Leidinger mtx_lock(&m->lock);
706206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
707206b17d7SAlexander Leidinger
708206b17d7SAlexander Leidinger if ((flags & FREAD && !(m->flags & M_RX)) ||
709206b17d7SAlexander Leidinger (flags & FWRITE && !(m->flags & M_TX))) {
710206b17d7SAlexander Leidinger retval = ENXIO;
711206b17d7SAlexander Leidinger goto err;
712206b17d7SAlexander Leidinger }
713206b17d7SAlexander Leidinger m->busy--;
714206b17d7SAlexander Leidinger
715206b17d7SAlexander Leidinger oldflags = m->flags;
716206b17d7SAlexander Leidinger
717206b17d7SAlexander Leidinger if (flags & FREAD)
718206b17d7SAlexander Leidinger m->flags &= ~(M_RX | M_RXEN);
719206b17d7SAlexander Leidinger if (flags & FWRITE)
720206b17d7SAlexander Leidinger m->flags &= ~M_TX;
721206b17d7SAlexander Leidinger
722206b17d7SAlexander Leidinger if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
723206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
724206b17d7SAlexander Leidinger
725206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
726206b17d7SAlexander Leidinger
727206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
728206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
729206b17d7SAlexander Leidinger retval = 0;
730206b17d7SAlexander Leidinger err: return retval;
731206b17d7SAlexander Leidinger }
7328f981688SAlexander Leidinger
733206b17d7SAlexander Leidinger /*
7348f981688SAlexander Leidinger * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
7358f981688SAlexander Leidinger * as data is available.
736206b17d7SAlexander Leidinger */
737206b17d7SAlexander Leidinger int
midi_read(struct cdev * i_dev,struct uio * uio,int ioflag)738206b17d7SAlexander Leidinger midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
739206b17d7SAlexander Leidinger {
740206b17d7SAlexander Leidinger #define MIDI_RSIZE 32
741206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1;
742206b17d7SAlexander Leidinger int retval;
743206b17d7SAlexander Leidinger int used;
744206b17d7SAlexander Leidinger char buf[MIDI_RSIZE];
745206b17d7SAlexander Leidinger
7468f981688SAlexander Leidinger MIDI_DEBUG(5, printf("midiread: count=%lu\n",
7478f981688SAlexander Leidinger (unsigned long)uio->uio_resid));
748206b17d7SAlexander Leidinger
749206b17d7SAlexander Leidinger retval = EIO;
750206b17d7SAlexander Leidinger
751206b17d7SAlexander Leidinger if (m == NULL)
752206b17d7SAlexander Leidinger goto err0;
753206b17d7SAlexander Leidinger
754206b17d7SAlexander Leidinger mtx_lock(&m->lock);
755206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
756206b17d7SAlexander Leidinger
757206b17d7SAlexander Leidinger if (!(m->flags & M_RX))
758206b17d7SAlexander Leidinger goto err1;
759206b17d7SAlexander Leidinger
760206b17d7SAlexander Leidinger while (uio->uio_resid > 0) {
761206b17d7SAlexander Leidinger while (MIDIQ_EMPTY(m->inq)) {
762206b17d7SAlexander Leidinger retval = EWOULDBLOCK;
763206b17d7SAlexander Leidinger if (ioflag & O_NONBLOCK)
764206b17d7SAlexander Leidinger goto err1;
765206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
766206b17d7SAlexander Leidinger m->rchan = 1;
767206b17d7SAlexander Leidinger retval = msleep(&m->rchan, &m->qlock,
768206b17d7SAlexander Leidinger PCATCH | PDROP, "midi RX", 0);
769206b17d7SAlexander Leidinger /*
770206b17d7SAlexander Leidinger * We slept, maybe things have changed since last
771206b17d7SAlexander Leidinger * dying check
772206b17d7SAlexander Leidinger */
773206b17d7SAlexander Leidinger if (retval == EINTR)
774206b17d7SAlexander Leidinger goto err0;
775206b17d7SAlexander Leidinger if (m != i_dev->si_drv1)
776206b17d7SAlexander Leidinger retval = ENXIO;
777206b17d7SAlexander Leidinger /* if (retval && retval != ERESTART) */
778206b17d7SAlexander Leidinger if (retval)
779206b17d7SAlexander Leidinger goto err0;
780206b17d7SAlexander Leidinger mtx_lock(&m->lock);
781206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
782206b17d7SAlexander Leidinger m->rchan = 0;
783206b17d7SAlexander Leidinger if (!m->busy)
784206b17d7SAlexander Leidinger goto err1;
785206b17d7SAlexander Leidinger }
786206b17d7SAlexander Leidinger MIDI_DEBUG(6, printf("midi_read start\n"));
787206b17d7SAlexander Leidinger /*
788206b17d7SAlexander Leidinger * At this point, it is certain that m->inq has data
789206b17d7SAlexander Leidinger */
790206b17d7SAlexander Leidinger
791206b17d7SAlexander Leidinger used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
792206b17d7SAlexander Leidinger used = MIN(used, MIDI_RSIZE);
793206b17d7SAlexander Leidinger
794206b17d7SAlexander Leidinger MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
795206b17d7SAlexander Leidinger MIDIQ_DEQ(m->inq, buf, used);
796206b17d7SAlexander Leidinger retval = uiomove(buf, used, uio);
797206b17d7SAlexander Leidinger if (retval)
798206b17d7SAlexander Leidinger goto err1;
799206b17d7SAlexander Leidinger }
800206b17d7SAlexander Leidinger
801206b17d7SAlexander Leidinger /*
802206b17d7SAlexander Leidinger * If we Made it here then transfer is good
803206b17d7SAlexander Leidinger */
804206b17d7SAlexander Leidinger retval = 0;
805206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock);
806206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
807206b17d7SAlexander Leidinger err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
808206b17d7SAlexander Leidinger return retval;
809206b17d7SAlexander Leidinger }
810206b17d7SAlexander Leidinger
811206b17d7SAlexander Leidinger /*
812206b17d7SAlexander Leidinger * midi_write: The only setter of M_TXEN
813206b17d7SAlexander Leidinger */
814206b17d7SAlexander Leidinger
815206b17d7SAlexander Leidinger int
midi_write(struct cdev * i_dev,struct uio * uio,int ioflag)816206b17d7SAlexander Leidinger midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
817206b17d7SAlexander Leidinger {
818206b17d7SAlexander Leidinger #define MIDI_WSIZE 32
819206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1;
820206b17d7SAlexander Leidinger int retval;
821206b17d7SAlexander Leidinger int used;
822206b17d7SAlexander Leidinger char buf[MIDI_WSIZE];
823206b17d7SAlexander Leidinger
824206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midi_write\n"));
825206b17d7SAlexander Leidinger retval = 0;
826206b17d7SAlexander Leidinger if (m == NULL)
827206b17d7SAlexander Leidinger goto err0;
828206b17d7SAlexander Leidinger
829206b17d7SAlexander Leidinger mtx_lock(&m->lock);
830206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
831206b17d7SAlexander Leidinger
832206b17d7SAlexander Leidinger if (!(m->flags & M_TX))
833206b17d7SAlexander Leidinger goto err1;
834206b17d7SAlexander Leidinger
835206b17d7SAlexander Leidinger while (uio->uio_resid > 0) {
836206b17d7SAlexander Leidinger while (MIDIQ_AVAIL(m->outq) == 0) {
837206b17d7SAlexander Leidinger retval = EWOULDBLOCK;
838206b17d7SAlexander Leidinger if (ioflag & O_NONBLOCK)
839206b17d7SAlexander Leidinger goto err1;
840206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
841206b17d7SAlexander Leidinger m->wchan = 1;
842206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_write msleep\n"));
843206b17d7SAlexander Leidinger retval = msleep(&m->wchan, &m->qlock,
844206b17d7SAlexander Leidinger PCATCH | PDROP, "midi TX", 0);
845206b17d7SAlexander Leidinger /*
846206b17d7SAlexander Leidinger * We slept, maybe things have changed since last
847206b17d7SAlexander Leidinger * dying check
848206b17d7SAlexander Leidinger */
849206b17d7SAlexander Leidinger if (retval == EINTR)
850206b17d7SAlexander Leidinger goto err0;
851206b17d7SAlexander Leidinger if (m != i_dev->si_drv1)
852206b17d7SAlexander Leidinger retval = ENXIO;
853206b17d7SAlexander Leidinger if (retval)
854206b17d7SAlexander Leidinger goto err0;
855206b17d7SAlexander Leidinger mtx_lock(&m->lock);
856206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
857206b17d7SAlexander Leidinger m->wchan = 0;
858206b17d7SAlexander Leidinger if (!m->busy)
859206b17d7SAlexander Leidinger goto err1;
860206b17d7SAlexander Leidinger }
861206b17d7SAlexander Leidinger
862206b17d7SAlexander Leidinger /*
863206b17d7SAlexander Leidinger * We are certain than data can be placed on the queue
864206b17d7SAlexander Leidinger */
865206b17d7SAlexander Leidinger
866206b17d7SAlexander Leidinger used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
867206b17d7SAlexander Leidinger used = MIN(used, MIDI_WSIZE);
8689f80ce04SKonstantin Belousov MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
8698f981688SAlexander Leidinger uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
8708f981688SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->outq)));
871206b17d7SAlexander Leidinger
872206b17d7SAlexander Leidinger MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
873206b17d7SAlexander Leidinger retval = uiomove(buf, used, uio);
874206b17d7SAlexander Leidinger if (retval)
875206b17d7SAlexander Leidinger goto err1;
876206b17d7SAlexander Leidinger MIDIQ_ENQ(m->outq, buf, used);
877206b17d7SAlexander Leidinger /*
878206b17d7SAlexander Leidinger * Inform the bottom half that data can be written
879206b17d7SAlexander Leidinger */
880206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) {
881206b17d7SAlexander Leidinger m->flags |= M_TXEN;
882206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
883206b17d7SAlexander Leidinger }
884206b17d7SAlexander Leidinger }
885206b17d7SAlexander Leidinger /*
886206b17d7SAlexander Leidinger * If we Made it here then transfer is good
887206b17d7SAlexander Leidinger */
888206b17d7SAlexander Leidinger retval = 0;
889206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock);
890206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
891206b17d7SAlexander Leidinger err0: return retval;
892206b17d7SAlexander Leidinger }
893206b17d7SAlexander Leidinger
894206b17d7SAlexander Leidinger int
midi_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)8958f981688SAlexander Leidinger midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
8968f981688SAlexander Leidinger struct thread *td)
897206b17d7SAlexander Leidinger {
898206b17d7SAlexander Leidinger return ENXIO;
899206b17d7SAlexander Leidinger }
900206b17d7SAlexander Leidinger
901206b17d7SAlexander Leidinger int
midi_poll(struct cdev * i_dev,int events,struct thread * td)902206b17d7SAlexander Leidinger midi_poll(struct cdev *i_dev, int events, struct thread *td)
903206b17d7SAlexander Leidinger {
904206b17d7SAlexander Leidinger struct snd_midi *m = i_dev->si_drv1;
905206b17d7SAlexander Leidinger int revents;
906206b17d7SAlexander Leidinger
907206b17d7SAlexander Leidinger if (m == NULL)
908206b17d7SAlexander Leidinger return 0;
909206b17d7SAlexander Leidinger
910206b17d7SAlexander Leidinger revents = 0;
911206b17d7SAlexander Leidinger
912206b17d7SAlexander Leidinger mtx_lock(&m->lock);
913206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
914206b17d7SAlexander Leidinger
915206b17d7SAlexander Leidinger if (events & (POLLIN | POLLRDNORM))
916206b17d7SAlexander Leidinger if (!MIDIQ_EMPTY(m->inq))
917206b17d7SAlexander Leidinger events |= events & (POLLIN | POLLRDNORM);
918206b17d7SAlexander Leidinger
919206b17d7SAlexander Leidinger if (events & (POLLOUT | POLLWRNORM))
920206b17d7SAlexander Leidinger if (MIDIQ_AVAIL(m->outq) < m->hiwat)
921206b17d7SAlexander Leidinger events |= events & (POLLOUT | POLLWRNORM);
922206b17d7SAlexander Leidinger
923206b17d7SAlexander Leidinger if (revents == 0) {
924206b17d7SAlexander Leidinger if (events & (POLLIN | POLLRDNORM))
925206b17d7SAlexander Leidinger selrecord(td, &m->rsel);
926206b17d7SAlexander Leidinger
927206b17d7SAlexander Leidinger if (events & (POLLOUT | POLLWRNORM))
928206b17d7SAlexander Leidinger selrecord(td, &m->wsel);
929206b17d7SAlexander Leidinger }
930206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
931206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
932206b17d7SAlexander Leidinger
933206b17d7SAlexander Leidinger return (revents);
934206b17d7SAlexander Leidinger }
935206b17d7SAlexander Leidinger
936206b17d7SAlexander Leidinger /*
937206b17d7SAlexander Leidinger * /dev/midistat device functions
938206b17d7SAlexander Leidinger *
939206b17d7SAlexander Leidinger */
940206b17d7SAlexander Leidinger static int
midistat_open(struct cdev * i_dev,int flags,int mode,struct thread * td)941206b17d7SAlexander Leidinger midistat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
942206b17d7SAlexander Leidinger {
943206b17d7SAlexander Leidinger int error;
944206b17d7SAlexander Leidinger
945206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midistat_open\n"));
946206b17d7SAlexander Leidinger
9472d6fc246SChristos Margiolis midistat_lock();
948206b17d7SAlexander Leidinger if (midistat_isopen) {
9492d6fc246SChristos Margiolis midistat_unlock();
950206b17d7SAlexander Leidinger return EBUSY;
951206b17d7SAlexander Leidinger }
952206b17d7SAlexander Leidinger midistat_isopen = 1;
953*aaf84d0eSChristos Margiolis sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND);
954206b17d7SAlexander Leidinger error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
95535fd0fc4SMark Johnston if (error)
956206b17d7SAlexander Leidinger midistat_isopen = 0;
9572d6fc246SChristos Margiolis midistat_unlock();
958206b17d7SAlexander Leidinger return error;
959206b17d7SAlexander Leidinger }
960206b17d7SAlexander Leidinger
961206b17d7SAlexander Leidinger static int
midistat_close(struct cdev * i_dev,int flags,int mode,struct thread * td)962206b17d7SAlexander Leidinger midistat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
963206b17d7SAlexander Leidinger {
964206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midistat_close\n"));
9652d6fc246SChristos Margiolis midistat_lock();
966206b17d7SAlexander Leidinger if (!midistat_isopen) {
9672d6fc246SChristos Margiolis midistat_unlock();
968206b17d7SAlexander Leidinger return EBADF;
969206b17d7SAlexander Leidinger }
970206b17d7SAlexander Leidinger sbuf_delete(&midistat_sbuf);
971206b17d7SAlexander Leidinger midistat_isopen = 0;
9722d6fc246SChristos Margiolis midistat_unlock();
973206b17d7SAlexander Leidinger return 0;
974206b17d7SAlexander Leidinger }
975206b17d7SAlexander Leidinger
976206b17d7SAlexander Leidinger static int
midistat_read(struct cdev * i_dev,struct uio * uio,int flag)97735fd0fc4SMark Johnston midistat_read(struct cdev *i_dev, struct uio *uio, int flag)
978206b17d7SAlexander Leidinger {
97935fd0fc4SMark Johnston long l;
98035fd0fc4SMark Johnston int err;
981206b17d7SAlexander Leidinger
982206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midistat_read\n"));
9832d6fc246SChristos Margiolis midistat_lock();
984206b17d7SAlexander Leidinger if (!midistat_isopen) {
9852d6fc246SChristos Margiolis midistat_unlock();
986206b17d7SAlexander Leidinger return EBADF;
987206b17d7SAlexander Leidinger }
98835fd0fc4SMark Johnston if (uio->uio_offset < 0 || uio->uio_offset > sbuf_len(&midistat_sbuf)) {
9892d6fc246SChristos Margiolis midistat_unlock();
99035fd0fc4SMark Johnston return EINVAL;
99135fd0fc4SMark Johnston }
992206b17d7SAlexander Leidinger err = 0;
99335fd0fc4SMark Johnston l = lmin(uio->uio_resid, sbuf_len(&midistat_sbuf) - uio->uio_offset);
994d130d865SAriff Abdullah if (l > 0) {
99535fd0fc4SMark Johnston err = uiomove(sbuf_data(&midistat_sbuf) + uio->uio_offset, l,
99635fd0fc4SMark Johnston uio);
99735fd0fc4SMark Johnston }
9982d6fc246SChristos Margiolis midistat_unlock();
999206b17d7SAlexander Leidinger return err;
1000206b17d7SAlexander Leidinger }
1001206b17d7SAlexander Leidinger
1002206b17d7SAlexander Leidinger /*
1003206b17d7SAlexander Leidinger * Module library functions
1004206b17d7SAlexander Leidinger */
1005206b17d7SAlexander Leidinger
1006206b17d7SAlexander Leidinger static int
midistat_prepare(struct sbuf * s)1007206b17d7SAlexander Leidinger midistat_prepare(struct sbuf *s)
1008206b17d7SAlexander Leidinger {
1009206b17d7SAlexander Leidinger struct snd_midi *m;
1010206b17d7SAlexander Leidinger
10112d6fc246SChristos Margiolis midistat_lockassert();
1012206b17d7SAlexander Leidinger
1013206b17d7SAlexander Leidinger sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1014206b17d7SAlexander Leidinger if (TAILQ_EMPTY(&midi_devs)) {
1015206b17d7SAlexander Leidinger sbuf_printf(s, "No devices installed.\n");
1016206b17d7SAlexander Leidinger sbuf_finish(s);
1017206b17d7SAlexander Leidinger return sbuf_len(s);
1018206b17d7SAlexander Leidinger }
1019206b17d7SAlexander Leidinger sbuf_printf(s, "Installed devices:\n");
1020206b17d7SAlexander Leidinger
1021206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) {
1022206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1023206b17d7SAlexander Leidinger sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1024206b17d7SAlexander Leidinger MPU_PROVIDER(m, m->cookie));
1025206b17d7SAlexander Leidinger sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1026206b17d7SAlexander Leidinger sbuf_printf(s, "\n");
1027206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1028206b17d7SAlexander Leidinger }
1029206b17d7SAlexander Leidinger
1030206b17d7SAlexander Leidinger sbuf_finish(s);
1031206b17d7SAlexander Leidinger return sbuf_len(s);
1032206b17d7SAlexander Leidinger }
1033206b17d7SAlexander Leidinger
10342916c293SRuslan Ermilov #ifdef notdef
1035206b17d7SAlexander Leidinger /*
1036206b17d7SAlexander Leidinger * Convert IOCTL command to string for debugging
1037206b17d7SAlexander Leidinger */
1038206b17d7SAlexander Leidinger
1039206b17d7SAlexander Leidinger static char *
midi_cmdname(int cmd)1040206b17d7SAlexander Leidinger midi_cmdname(int cmd)
1041206b17d7SAlexander Leidinger {
1042206b17d7SAlexander Leidinger static struct {
1043206b17d7SAlexander Leidinger int cmd;
1044206b17d7SAlexander Leidinger char *name;
1045206b17d7SAlexander Leidinger } *tab, cmdtab_midiioctl[] = {
1046206b17d7SAlexander Leidinger #define A(x) {x, ## x}
1047206b17d7SAlexander Leidinger /*
1048206b17d7SAlexander Leidinger * Once we have some real IOCTLs define, the following will
1049206b17d7SAlexander Leidinger * be relavant.
1050206b17d7SAlexander Leidinger *
1051206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1052206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1053206b17d7SAlexander Leidinger * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1054206b17d7SAlexander Leidinger * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1055206b17d7SAlexander Leidinger * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1056206b17d7SAlexander Leidinger * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1057206b17d7SAlexander Leidinger * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1058206b17d7SAlexander Leidinger * A(AIOGCAP),
1059206b17d7SAlexander Leidinger */
1060206b17d7SAlexander Leidinger #undef A
1061206b17d7SAlexander Leidinger {
1062206b17d7SAlexander Leidinger -1, "unknown"
1063206b17d7SAlexander Leidinger },
1064206b17d7SAlexander Leidinger };
1065206b17d7SAlexander Leidinger
10668f981688SAlexander Leidinger for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++);
1067206b17d7SAlexander Leidinger return tab->name;
1068206b17d7SAlexander Leidinger }
10698f981688SAlexander Leidinger
1070206b17d7SAlexander Leidinger #endif /* notdef */
1071206b17d7SAlexander Leidinger
1072206b17d7SAlexander Leidinger /*
1073206b17d7SAlexander Leidinger * midisynth
1074206b17d7SAlexander Leidinger */
1075206b17d7SAlexander Leidinger
1076206b17d7SAlexander Leidinger int
midisynth_open(void * n,void * arg,int flags)1077206b17d7SAlexander Leidinger midisynth_open(void *n, void *arg, int flags)
1078206b17d7SAlexander Leidinger {
1079206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m;
1080206b17d7SAlexander Leidinger int retval;
1081206b17d7SAlexander Leidinger
1082206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midisynth_open %s %s\n",
1083206b17d7SAlexander Leidinger flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
1084206b17d7SAlexander Leidinger
1085206b17d7SAlexander Leidinger if (m == NULL)
1086206b17d7SAlexander Leidinger return ENXIO;
1087206b17d7SAlexander Leidinger
1088206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1089206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
1090206b17d7SAlexander Leidinger
1091206b17d7SAlexander Leidinger retval = 0;
1092206b17d7SAlexander Leidinger
1093206b17d7SAlexander Leidinger if (flags & FREAD) {
1094206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->inq) == 0)
1095206b17d7SAlexander Leidinger retval = ENXIO;
1096206b17d7SAlexander Leidinger else if (m->flags & M_RX)
1097206b17d7SAlexander Leidinger retval = EBUSY;
1098206b17d7SAlexander Leidinger if (retval)
1099206b17d7SAlexander Leidinger goto err;
1100206b17d7SAlexander Leidinger }
1101206b17d7SAlexander Leidinger if (flags & FWRITE) {
1102206b17d7SAlexander Leidinger if (MIDIQ_SIZE(m->outq) == 0)
1103206b17d7SAlexander Leidinger retval = ENXIO;
1104206b17d7SAlexander Leidinger else if (m->flags & M_TX)
1105206b17d7SAlexander Leidinger retval = EBUSY;
1106206b17d7SAlexander Leidinger if (retval)
1107206b17d7SAlexander Leidinger goto err;
1108206b17d7SAlexander Leidinger }
1109206b17d7SAlexander Leidinger m->busy++;
1110206b17d7SAlexander Leidinger
1111206b17d7SAlexander Leidinger /*
1112206b17d7SAlexander Leidinger * TODO: Consider m->async = 0;
1113206b17d7SAlexander Leidinger */
1114206b17d7SAlexander Leidinger
1115206b17d7SAlexander Leidinger if (flags & FREAD) {
1116206b17d7SAlexander Leidinger m->flags |= M_RX | M_RXEN;
1117206b17d7SAlexander Leidinger /*
11188f981688SAlexander Leidinger * Only clear the inq, the outq might still have data to drain
11198f981688SAlexander Leidinger * from a previous session
1120206b17d7SAlexander Leidinger */
1121206b17d7SAlexander Leidinger MIDIQ_CLEAR(m->inq);
1122206b17d7SAlexander Leidinger m->rchan = 0;
112374b8d63dSPedro F. Giffuni }
1124206b17d7SAlexander Leidinger
1125206b17d7SAlexander Leidinger if (flags & FWRITE) {
1126206b17d7SAlexander Leidinger m->flags |= M_TX;
1127206b17d7SAlexander Leidinger m->wchan = 0;
1128206b17d7SAlexander Leidinger }
1129206b17d7SAlexander Leidinger m->synth_flags = flags & (FREAD | FWRITE);
1130206b17d7SAlexander Leidinger
1131206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
1132206b17d7SAlexander Leidinger
1133206b17d7SAlexander Leidinger err: mtx_unlock(&m->qlock);
1134206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1135206b17d7SAlexander Leidinger MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1136206b17d7SAlexander Leidinger return retval;
1137206b17d7SAlexander Leidinger }
1138206b17d7SAlexander Leidinger
1139206b17d7SAlexander Leidinger int
midisynth_close(void * n)1140206b17d7SAlexander Leidinger midisynth_close(void *n)
1141206b17d7SAlexander Leidinger {
1142206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m;
1143206b17d7SAlexander Leidinger int retval;
1144206b17d7SAlexander Leidinger int oldflags;
1145206b17d7SAlexander Leidinger
1146206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1147206b17d7SAlexander Leidinger m->synth_flags & FREAD ? "M_RX" : "",
1148206b17d7SAlexander Leidinger m->synth_flags & FWRITE ? "M_TX" : ""));
1149206b17d7SAlexander Leidinger
1150206b17d7SAlexander Leidinger if (m == NULL)
1151206b17d7SAlexander Leidinger return ENXIO;
1152206b17d7SAlexander Leidinger
1153206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1154206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
1155206b17d7SAlexander Leidinger
1156206b17d7SAlexander Leidinger if ((m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1157206b17d7SAlexander Leidinger (m->synth_flags & FWRITE && !(m->flags & M_TX))) {
1158206b17d7SAlexander Leidinger retval = ENXIO;
1159206b17d7SAlexander Leidinger goto err;
1160206b17d7SAlexander Leidinger }
1161206b17d7SAlexander Leidinger m->busy--;
1162206b17d7SAlexander Leidinger
1163206b17d7SAlexander Leidinger oldflags = m->flags;
1164206b17d7SAlexander Leidinger
1165206b17d7SAlexander Leidinger if (m->synth_flags & FREAD)
1166206b17d7SAlexander Leidinger m->flags &= ~(M_RX | M_RXEN);
1167206b17d7SAlexander Leidinger if (m->synth_flags & FWRITE)
1168206b17d7SAlexander Leidinger m->flags &= ~M_TX;
1169206b17d7SAlexander Leidinger
1170206b17d7SAlexander Leidinger if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
1171206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
1172206b17d7SAlexander Leidinger
1173206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1174206b17d7SAlexander Leidinger
1175206b17d7SAlexander Leidinger mtx_unlock(&m->qlock);
1176206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1177206b17d7SAlexander Leidinger retval = 0;
1178206b17d7SAlexander Leidinger err: return retval;
1179206b17d7SAlexander Leidinger }
1180206b17d7SAlexander Leidinger
1181206b17d7SAlexander Leidinger /*
1182206b17d7SAlexander Leidinger * Always blocking.
1183206b17d7SAlexander Leidinger */
1184206b17d7SAlexander Leidinger
1185206b17d7SAlexander Leidinger int
midisynth_writeraw(void * n,uint8_t * buf,size_t len)1186206b17d7SAlexander Leidinger midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1187206b17d7SAlexander Leidinger {
1188206b17d7SAlexander Leidinger struct snd_midi *m = ((struct synth_midi *)n)->m;
1189206b17d7SAlexander Leidinger int retval;
1190206b17d7SAlexander Leidinger int used;
1191206b17d7SAlexander Leidinger int i;
1192206b17d7SAlexander Leidinger
1193206b17d7SAlexander Leidinger MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1194206b17d7SAlexander Leidinger
1195206b17d7SAlexander Leidinger retval = 0;
1196206b17d7SAlexander Leidinger
1197206b17d7SAlexander Leidinger if (m == NULL)
1198206b17d7SAlexander Leidinger return ENXIO;
1199206b17d7SAlexander Leidinger
1200206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1201206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
1202206b17d7SAlexander Leidinger
1203206b17d7SAlexander Leidinger if (!(m->flags & M_TX))
1204206b17d7SAlexander Leidinger goto err1;
1205206b17d7SAlexander Leidinger
1206206b17d7SAlexander Leidinger if (midi_dumpraw)
1207206b17d7SAlexander Leidinger printf("midi dump: ");
1208206b17d7SAlexander Leidinger
1209206b17d7SAlexander Leidinger while (len > 0) {
1210206b17d7SAlexander Leidinger while (MIDIQ_AVAIL(m->outq) == 0) {
1211206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) {
1212206b17d7SAlexander Leidinger m->flags |= M_TXEN;
1213206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
1214206b17d7SAlexander Leidinger }
1215206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1216206b17d7SAlexander Leidinger m->wchan = 1;
1217206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midisynth_writeraw msleep\n"));
1218206b17d7SAlexander Leidinger retval = msleep(&m->wchan, &m->qlock,
1219206b17d7SAlexander Leidinger PCATCH | PDROP, "midi TX", 0);
1220206b17d7SAlexander Leidinger /*
1221206b17d7SAlexander Leidinger * We slept, maybe things have changed since last
1222206b17d7SAlexander Leidinger * dying check
1223206b17d7SAlexander Leidinger */
1224206b17d7SAlexander Leidinger if (retval == EINTR)
1225206b17d7SAlexander Leidinger goto err0;
1226206b17d7SAlexander Leidinger
1227206b17d7SAlexander Leidinger if (retval)
1228206b17d7SAlexander Leidinger goto err0;
1229206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1230206b17d7SAlexander Leidinger mtx_lock(&m->qlock);
1231206b17d7SAlexander Leidinger m->wchan = 0;
1232206b17d7SAlexander Leidinger if (!m->busy)
1233206b17d7SAlexander Leidinger goto err1;
1234206b17d7SAlexander Leidinger }
1235206b17d7SAlexander Leidinger
1236206b17d7SAlexander Leidinger /*
1237206b17d7SAlexander Leidinger * We are certain than data can be placed on the queue
1238206b17d7SAlexander Leidinger */
1239206b17d7SAlexander Leidinger
1240206b17d7SAlexander Leidinger used = MIN(MIDIQ_AVAIL(m->outq), len);
1241206b17d7SAlexander Leidinger used = MIN(used, MIDI_WSIZE);
12428f981688SAlexander Leidinger MIDI_DEBUG(5,
12438f981688SAlexander Leidinger printf("midi_synth: resid %zu len %jd avail %jd\n",
1244206b17d7SAlexander Leidinger len, (intmax_t)MIDIQ_LEN(m->outq),
1245206b17d7SAlexander Leidinger (intmax_t)MIDIQ_AVAIL(m->outq)));
1246206b17d7SAlexander Leidinger
1247206b17d7SAlexander Leidinger if (midi_dumpraw)
12488f981688SAlexander Leidinger for (i = 0; i < used; i++)
12498f981688SAlexander Leidinger printf("%x ", buf[i]);
1250206b17d7SAlexander Leidinger
1251206b17d7SAlexander Leidinger MIDIQ_ENQ(m->outq, buf, used);
1252206b17d7SAlexander Leidinger len -= used;
1253206b17d7SAlexander Leidinger
1254206b17d7SAlexander Leidinger /*
1255206b17d7SAlexander Leidinger * Inform the bottom half that data can be written
1256206b17d7SAlexander Leidinger */
1257206b17d7SAlexander Leidinger if (!(m->flags & M_TXEN)) {
1258206b17d7SAlexander Leidinger m->flags |= M_TXEN;
1259206b17d7SAlexander Leidinger MPU_CALLBACK(m, m->cookie, m->flags);
1260206b17d7SAlexander Leidinger }
1261206b17d7SAlexander Leidinger }
1262206b17d7SAlexander Leidinger /*
1263206b17d7SAlexander Leidinger * If we Made it here then transfer is good
1264206b17d7SAlexander Leidinger */
1265206b17d7SAlexander Leidinger if (midi_dumpraw)
1266206b17d7SAlexander Leidinger printf("\n");
1267206b17d7SAlexander Leidinger
1268206b17d7SAlexander Leidinger retval = 0;
1269206b17d7SAlexander Leidinger err1: mtx_unlock(&m->qlock);
1270206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1271206b17d7SAlexander Leidinger err0: return retval;
1272206b17d7SAlexander Leidinger }
1273206b17d7SAlexander Leidinger
1274206b17d7SAlexander Leidinger static int
midisynth_killnote(void * n,uint8_t chn,uint8_t note,uint8_t vel)1275206b17d7SAlexander Leidinger midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1276206b17d7SAlexander Leidinger {
1277206b17d7SAlexander Leidinger u_char c[3];
1278206b17d7SAlexander Leidinger
1279206b17d7SAlexander Leidinger if (note > 127 || chn > 15)
1280206b17d7SAlexander Leidinger return (EINVAL);
1281206b17d7SAlexander Leidinger
1282206b17d7SAlexander Leidinger if (vel > 127)
1283206b17d7SAlexander Leidinger vel = 127;
1284206b17d7SAlexander Leidinger
1285206b17d7SAlexander Leidinger if (vel == 64) {
1286206b17d7SAlexander Leidinger c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1287206b17d7SAlexander Leidinger c[1] = (u_char)note;
1288206b17d7SAlexander Leidinger c[2] = 0;
1289206b17d7SAlexander Leidinger } else {
1290206b17d7SAlexander Leidinger c[0] = 0x80 | (chn & 0x0f); /* Note off. */
1291206b17d7SAlexander Leidinger c[1] = (u_char)note;
1292206b17d7SAlexander Leidinger c[2] = (u_char)vel;
1293206b17d7SAlexander Leidinger }
1294206b17d7SAlexander Leidinger
1295206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3);
1296206b17d7SAlexander Leidinger }
1297206b17d7SAlexander Leidinger
1298206b17d7SAlexander Leidinger static int
midisynth_setinstr(void * n,uint8_t chn,uint16_t instr)1299206b17d7SAlexander Leidinger midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1300206b17d7SAlexander Leidinger {
1301206b17d7SAlexander Leidinger u_char c[2];
1302206b17d7SAlexander Leidinger
1303206b17d7SAlexander Leidinger if (instr > 127 || chn > 15)
1304206b17d7SAlexander Leidinger return EINVAL;
1305206b17d7SAlexander Leidinger
1306206b17d7SAlexander Leidinger c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
1307206b17d7SAlexander Leidinger c[1] = instr + midi_instroff;
1308206b17d7SAlexander Leidinger
1309206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 2);
1310206b17d7SAlexander Leidinger }
1311206b17d7SAlexander Leidinger
1312206b17d7SAlexander Leidinger static int
midisynth_startnote(void * n,uint8_t chn,uint8_t note,uint8_t vel)1313206b17d7SAlexander Leidinger midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1314206b17d7SAlexander Leidinger {
1315206b17d7SAlexander Leidinger u_char c[3];
1316206b17d7SAlexander Leidinger
1317206b17d7SAlexander Leidinger if (note > 127 || chn > 15)
1318206b17d7SAlexander Leidinger return EINVAL;
1319206b17d7SAlexander Leidinger
1320206b17d7SAlexander Leidinger if (vel > 127)
1321206b17d7SAlexander Leidinger vel = 127;
1322206b17d7SAlexander Leidinger
1323206b17d7SAlexander Leidinger c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1324206b17d7SAlexander Leidinger c[1] = (u_char)note;
1325206b17d7SAlexander Leidinger c[2] = (u_char)vel;
1326206b17d7SAlexander Leidinger
1327206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3);
1328206b17d7SAlexander Leidinger }
1329206b17d7SAlexander Leidinger static int
midisynth_alloc(void * n,uint8_t chan,uint8_t note)1330206b17d7SAlexander Leidinger midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1331206b17d7SAlexander Leidinger {
1332206b17d7SAlexander Leidinger return chan;
1333206b17d7SAlexander Leidinger }
1334206b17d7SAlexander Leidinger
1335206b17d7SAlexander Leidinger static int
midisynth_controller(void * n,uint8_t chn,uint8_t ctrlnum,uint16_t val)1336206b17d7SAlexander Leidinger midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1337206b17d7SAlexander Leidinger {
1338206b17d7SAlexander Leidinger u_char c[3];
1339206b17d7SAlexander Leidinger
1340206b17d7SAlexander Leidinger if (ctrlnum > 127 || chn > 15)
1341206b17d7SAlexander Leidinger return EINVAL;
1342206b17d7SAlexander Leidinger
1343206b17d7SAlexander Leidinger c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
1344206b17d7SAlexander Leidinger c[1] = ctrlnum;
1345206b17d7SAlexander Leidinger c[2] = val;
1346206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3);
1347206b17d7SAlexander Leidinger }
1348206b17d7SAlexander Leidinger
1349206b17d7SAlexander Leidinger static int
midisynth_bender(void * n,uint8_t chn,uint16_t val)1350206b17d7SAlexander Leidinger midisynth_bender(void *n, uint8_t chn, uint16_t val)
1351206b17d7SAlexander Leidinger {
1352206b17d7SAlexander Leidinger u_char c[3];
1353206b17d7SAlexander Leidinger
1354206b17d7SAlexander Leidinger if (val > 16383 || chn > 15)
1355206b17d7SAlexander Leidinger return EINVAL;
1356206b17d7SAlexander Leidinger
1357206b17d7SAlexander Leidinger c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
1358206b17d7SAlexander Leidinger c[1] = (u_char)val & 0x7f;
1359206b17d7SAlexander Leidinger c[2] = (u_char)(val >> 7) & 0x7f;
1360206b17d7SAlexander Leidinger
1361206b17d7SAlexander Leidinger return midisynth_writeraw(n, c, 3);
1362206b17d7SAlexander Leidinger }
1363206b17d7SAlexander Leidinger
1364206b17d7SAlexander Leidinger /*
1365206b17d7SAlexander Leidinger * Single point of midi destructions.
1366206b17d7SAlexander Leidinger */
1367206b17d7SAlexander Leidinger static int
midi_destroy(struct snd_midi * m,int midiuninit)1368206b17d7SAlexander Leidinger midi_destroy(struct snd_midi *m, int midiuninit)
1369206b17d7SAlexander Leidinger {
13702d6fc246SChristos Margiolis midistat_lockassert();
1371206b17d7SAlexander Leidinger mtx_assert(&m->lock, MA_OWNED);
1372206b17d7SAlexander Leidinger
1373206b17d7SAlexander Leidinger MIDI_DEBUG(3, printf("midi_destroy\n"));
1374206b17d7SAlexander Leidinger m->dev->si_drv1 = NULL;
137590da2b28SAriff Abdullah mtx_unlock(&m->lock); /* XXX */
1376206b17d7SAlexander Leidinger destroy_dev(m->dev);
1377206b17d7SAlexander Leidinger TAILQ_REMOVE(&midi_devs, m, link);
1378206b17d7SAlexander Leidinger if (midiuninit)
1379206b17d7SAlexander Leidinger MPU_UNINIT(m, m->cookie);
1380206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->inq), M_MIDI);
1381206b17d7SAlexander Leidinger free(MIDIQ_BUF(m->outq), M_MIDI);
1382206b17d7SAlexander Leidinger mtx_destroy(&m->qlock);
1383206b17d7SAlexander Leidinger mtx_destroy(&m->lock);
1384671b5759STai-hwa Liang free(m->synth, M_MIDI);
1385206b17d7SAlexander Leidinger free(m, M_MIDI);
1386206b17d7SAlexander Leidinger return 0;
1387206b17d7SAlexander Leidinger }
1388206b17d7SAlexander Leidinger
1389206b17d7SAlexander Leidinger /*
1390206b17d7SAlexander Leidinger * Load and unload functions, creates the /dev/midistat device
1391206b17d7SAlexander Leidinger */
1392206b17d7SAlexander Leidinger
1393206b17d7SAlexander Leidinger static int
midi_load(void)1394115b4b94SConrad Meyer midi_load(void)
1395206b17d7SAlexander Leidinger {
13962d6fc246SChristos Margiolis sx_init(&mstat_lock, "midistat lock");
139735fd0fc4SMark Johnston TAILQ_INIT(&midi_devs);
1398206b17d7SAlexander Leidinger
13998b9e1b62SChristos Margiolis midistat_dev = make_dev(&midistat_cdevsw, MIDI_DEV_MIDICTL, UID_ROOT,
14008b9e1b62SChristos Margiolis GID_WHEEL, 0666, "midistat");
1401206b17d7SAlexander Leidinger
1402206b17d7SAlexander Leidinger return 0;
1403206b17d7SAlexander Leidinger }
1404206b17d7SAlexander Leidinger
1405206b17d7SAlexander Leidinger static int
midi_unload(void)1406115b4b94SConrad Meyer midi_unload(void)
1407206b17d7SAlexander Leidinger {
1408115b4b94SConrad Meyer struct snd_midi *m, *tmp;
1409206b17d7SAlexander Leidinger int retval;
1410206b17d7SAlexander Leidinger
1411206b17d7SAlexander Leidinger MIDI_DEBUG(1, printf("midi_unload()\n"));
1412206b17d7SAlexander Leidinger retval = EBUSY;
14132d6fc246SChristos Margiolis midistat_lock();
1414206b17d7SAlexander Leidinger if (midistat_isopen)
1415206b17d7SAlexander Leidinger goto exit0;
1416206b17d7SAlexander Leidinger
1417115b4b94SConrad Meyer TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
1418206b17d7SAlexander Leidinger mtx_lock(&m->lock);
1419206b17d7SAlexander Leidinger if (m->busy)
1420206b17d7SAlexander Leidinger retval = EBUSY;
1421206b17d7SAlexander Leidinger else
1422206b17d7SAlexander Leidinger retval = midi_destroy(m, 1);
1423206b17d7SAlexander Leidinger if (retval)
1424206b17d7SAlexander Leidinger goto exit1;
1425206b17d7SAlexander Leidinger }
14262d6fc246SChristos Margiolis midistat_unlock();
1427206b17d7SAlexander Leidinger destroy_dev(midistat_dev);
142835fd0fc4SMark Johnston
1429206b17d7SAlexander Leidinger /*
1430206b17d7SAlexander Leidinger * Made it here then unload is complete
1431206b17d7SAlexander Leidinger */
14322d6fc246SChristos Margiolis sx_destroy(&mstat_lock);
1433206b17d7SAlexander Leidinger return 0;
1434206b17d7SAlexander Leidinger
1435206b17d7SAlexander Leidinger exit1:
1436206b17d7SAlexander Leidinger mtx_unlock(&m->lock);
1437206b17d7SAlexander Leidinger exit0:
14382d6fc246SChristos Margiolis midistat_unlock();
14398f981688SAlexander Leidinger if (retval)
14408f981688SAlexander Leidinger MIDI_DEBUG(2, printf("midi_unload: failed\n"));
1441206b17d7SAlexander Leidinger return retval;
1442206b17d7SAlexander Leidinger }
1443206b17d7SAlexander Leidinger
1444206b17d7SAlexander Leidinger extern int seq_modevent(module_t mod, int type, void *data);
1445206b17d7SAlexander Leidinger
1446206b17d7SAlexander Leidinger static int
midi_modevent(module_t mod,int type,void * data)1447206b17d7SAlexander Leidinger midi_modevent(module_t mod, int type, void *data)
1448206b17d7SAlexander Leidinger {
1449206b17d7SAlexander Leidinger int retval;
1450206b17d7SAlexander Leidinger
1451206b17d7SAlexander Leidinger retval = 0;
1452206b17d7SAlexander Leidinger
1453206b17d7SAlexander Leidinger switch (type) {
1454206b17d7SAlexander Leidinger case MOD_LOAD:
1455206b17d7SAlexander Leidinger retval = midi_load();
1456206b17d7SAlexander Leidinger if (retval == 0)
1457206b17d7SAlexander Leidinger retval = seq_modevent(mod, type, data);
1458206b17d7SAlexander Leidinger break;
1459206b17d7SAlexander Leidinger
1460206b17d7SAlexander Leidinger case MOD_UNLOAD:
1461206b17d7SAlexander Leidinger retval = midi_unload();
1462206b17d7SAlexander Leidinger if (retval == 0)
1463206b17d7SAlexander Leidinger retval = seq_modevent(mod, type, data);
1464206b17d7SAlexander Leidinger break;
1465206b17d7SAlexander Leidinger
1466206b17d7SAlexander Leidinger default:
1467206b17d7SAlexander Leidinger break;
1468206b17d7SAlexander Leidinger }
1469206b17d7SAlexander Leidinger
1470206b17d7SAlexander Leidinger return retval;
1471206b17d7SAlexander Leidinger }
1472206b17d7SAlexander Leidinger
1473206b17d7SAlexander Leidinger kobj_t
midimapper_addseq(void * arg1,int * unit,void ** cookie)1474206b17d7SAlexander Leidinger midimapper_addseq(void *arg1, int *unit, void **cookie)
1475206b17d7SAlexander Leidinger {
147687d8fcc8SPedro F. Giffuni unit = NULL;
1477206b17d7SAlexander Leidinger
1478206b17d7SAlexander Leidinger return (kobj_t)arg1;
1479206b17d7SAlexander Leidinger }
1480206b17d7SAlexander Leidinger
1481206b17d7SAlexander Leidinger int
midimapper_open_locked(void * arg1,void ** cookie)1482fc76e24eSChristos Margiolis midimapper_open_locked(void *arg1, void **cookie)
1483206b17d7SAlexander Leidinger {
1484206b17d7SAlexander Leidinger int retval = 0;
1485206b17d7SAlexander Leidinger struct snd_midi *m;
1486206b17d7SAlexander Leidinger
14872d6fc246SChristos Margiolis midistat_lockassert();
1488206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) {
1489206b17d7SAlexander Leidinger retval++;
1490206b17d7SAlexander Leidinger }
1491fc76e24eSChristos Margiolis
1492fc76e24eSChristos Margiolis return retval;
1493fc76e24eSChristos Margiolis }
1494fc76e24eSChristos Margiolis
1495fc76e24eSChristos Margiolis int
midimapper_open(void * arg1,void ** cookie)1496fc76e24eSChristos Margiolis midimapper_open(void *arg1, void **cookie)
1497fc76e24eSChristos Margiolis {
1498fc76e24eSChristos Margiolis int retval;
1499fc76e24eSChristos Margiolis
15002d6fc246SChristos Margiolis midistat_lock();
1501fc76e24eSChristos Margiolis retval = midimapper_open_locked(arg1, cookie);
15022d6fc246SChristos Margiolis midistat_unlock();
1503fc76e24eSChristos Margiolis
1504206b17d7SAlexander Leidinger return retval;
1505206b17d7SAlexander Leidinger }
1506206b17d7SAlexander Leidinger
1507206b17d7SAlexander Leidinger int
midimapper_close(void * arg1,void * cookie)1508206b17d7SAlexander Leidinger midimapper_close(void *arg1, void *cookie)
1509206b17d7SAlexander Leidinger {
1510206b17d7SAlexander Leidinger return 0;
1511206b17d7SAlexander Leidinger }
1512206b17d7SAlexander Leidinger
1513206b17d7SAlexander Leidinger kobj_t
midimapper_fetch_synth_locked(void * arg,void * cookie,int unit)1514fc76e24eSChristos Margiolis midimapper_fetch_synth_locked(void *arg, void *cookie, int unit)
1515206b17d7SAlexander Leidinger {
1516206b17d7SAlexander Leidinger struct snd_midi *m;
1517206b17d7SAlexander Leidinger int retval = 0;
1518206b17d7SAlexander Leidinger
15192d6fc246SChristos Margiolis midistat_lockassert();
1520206b17d7SAlexander Leidinger TAILQ_FOREACH(m, &midi_devs, link) {
1521fc76e24eSChristos Margiolis if (unit == retval)
1522206b17d7SAlexander Leidinger return (kobj_t)m->synth;
1523206b17d7SAlexander Leidinger retval++;
1524206b17d7SAlexander Leidinger }
1525fc76e24eSChristos Margiolis
1526206b17d7SAlexander Leidinger return NULL;
1527206b17d7SAlexander Leidinger }
1528206b17d7SAlexander Leidinger
1529fc76e24eSChristos Margiolis kobj_t
midimapper_fetch_synth(void * arg,void * cookie,int unit)1530fc76e24eSChristos Margiolis midimapper_fetch_synth(void *arg, void *cookie, int unit)
1531fc76e24eSChristos Margiolis {
1532fc76e24eSChristos Margiolis kobj_t synth;
1533fc76e24eSChristos Margiolis
15342d6fc246SChristos Margiolis midistat_lock();
1535fc76e24eSChristos Margiolis synth = midimapper_fetch_synth_locked(arg, cookie, unit);
15362d6fc246SChristos Margiolis midistat_unlock();
1537fc76e24eSChristos Margiolis
1538fc76e24eSChristos Margiolis return synth;
1539fc76e24eSChristos Margiolis }
1540fc76e24eSChristos Margiolis
1541206b17d7SAlexander Leidinger DEV_MODULE(midi, midi_modevent, NULL);
1542206b17d7SAlexander Leidinger MODULE_VERSION(midi, 1);
1543