xref: /dflybsd-src/sys/dev/sound/midi/sequencer.c (revision d147c94391cf5cc415970d2b885fcc931026c34e)
16c94880fSSascha Wildner /*-
26c94880fSSascha Wildner  * Copyright (c) 2003 Mathew Kanner
36c94880fSSascha Wildner  * Copyright (c) 1993 Hannu Savolainen
46c94880fSSascha Wildner  * All rights reserved.
56c94880fSSascha Wildner  *
66c94880fSSascha Wildner  * Redistribution and use in source and binary forms, with or without
76c94880fSSascha Wildner  * modification, are permitted provided that the following conditions
86c94880fSSascha Wildner  * are met:
96c94880fSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
106c94880fSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
116c94880fSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
126c94880fSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
136c94880fSSascha Wildner  *    documentation and/or other materials provided with the distribution.
146c94880fSSascha Wildner  *
156c94880fSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166c94880fSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176c94880fSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186c94880fSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196c94880fSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206c94880fSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216c94880fSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226c94880fSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236c94880fSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246c94880fSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256c94880fSSascha Wildner  * SUCH DAMAGE.
266c94880fSSascha Wildner  */
276c94880fSSascha Wildner 
286c94880fSSascha Wildner /*
296c94880fSSascha Wildner  * The sequencer personality manager.
306c94880fSSascha Wildner  */
316c94880fSSascha Wildner 
326c94880fSSascha Wildner #include <sys/cdefs.h>
336c94880fSSascha Wildner __FBSDID("$FreeBSD: head/sys/dev/sound/midi/sequencer.c 274035 2014-11-03 11:11:45Z bapt $");
346c94880fSSascha Wildner 
356c94880fSSascha Wildner #include <sys/param.h>
366c94880fSSascha Wildner #include <sys/systm.h>
376c94880fSSascha Wildner 
386c94880fSSascha Wildner #include <sys/filio.h>
396c94880fSSascha Wildner #include <sys/lock.h>
406c94880fSSascha Wildner #include <sys/sockio.h>
416c94880fSSascha Wildner #include <sys/fcntl.h>
426c94880fSSascha Wildner #include <sys/proc.h>
436c94880fSSascha Wildner #include <sys/sysctl.h>
446c94880fSSascha Wildner 
456c94880fSSascha Wildner #include <sys/kernel.h>			/* for DATA_SET */
466c94880fSSascha Wildner 
476c94880fSSascha Wildner #include <sys/module.h>
486c94880fSSascha Wildner #include <sys/conf.h>
496c94880fSSascha Wildner #include <sys/file.h>
506c94880fSSascha Wildner #include <sys/uio.h>
516c94880fSSascha Wildner #include <sys/syslog.h>
526c94880fSSascha Wildner #include <sys/errno.h>
536c94880fSSascha Wildner #include <sys/malloc.h>
546c94880fSSascha Wildner #include <sys/bus.h>
556c94880fSSascha Wildner #include <machine/clock.h>		/* for DELAY */
566c94880fSSascha Wildner #include <sys/soundcard.h>
576c94880fSSascha Wildner #include <sys/rman.h>
586c94880fSSascha Wildner #include <sys/mman.h>
596c94880fSSascha Wildner #include <sys/poll.h>
606c94880fSSascha Wildner #include <sys/condvar.h>
616c94880fSSascha Wildner #include <sys/kthread.h>
626c94880fSSascha Wildner #include <sys/unistd.h>
63*af11d9eeSSascha Wildner #include <sys/device.h>
646c94880fSSascha Wildner 
656c94880fSSascha Wildner #ifdef HAVE_KERNEL_OPTION_HEADERS
666c94880fSSascha Wildner #include "opt_snd.h"
676c94880fSSascha Wildner #endif
686c94880fSSascha Wildner 
696c94880fSSascha Wildner #include <dev/sound/midi/midi.h>
706c94880fSSascha Wildner #include <dev/sound/midi/midiq.h>
716c94880fSSascha Wildner #include "synth_if.h"
726c94880fSSascha Wildner 
736c94880fSSascha Wildner #include <dev/sound/midi/sequencer.h>
746c94880fSSascha Wildner 
756c94880fSSascha Wildner #define TMR_TIMERBASE 13
766c94880fSSascha Wildner 
776c94880fSSascha Wildner #define SND_DEV_SEQ	1		/* Sequencer output /dev/sequencer (FM
786c94880fSSascha Wildner 					 * synthesizer and MIDI output) */
796c94880fSSascha Wildner #define SND_DEV_MUSIC	8		/* /dev/music, level 2 interface */
806c94880fSSascha Wildner 
816c94880fSSascha Wildner /* Length of a sequencer event. */
826c94880fSSascha Wildner #define EV_SZ 8
836c94880fSSascha Wildner #define IEV_SZ 8
846c94880fSSascha Wildner 
856c94880fSSascha Wildner /* Lookup modes */
866c94880fSSascha Wildner #define LOOKUP_EXIST	(0)
876c94880fSSascha Wildner #define LOOKUP_OPEN	(1)
886c94880fSSascha Wildner #define LOOKUP_CLOSE	(2)
896c94880fSSascha Wildner 
906c94880fSSascha Wildner #define PCMMKMINOR(u, d, c) \
916c94880fSSascha Wildner 	    ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
926c94880fSSascha Wildner #define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
936c94880fSSascha Wildner #define MIDIUNIT(y) ((dev2unit(y) >> 4) & 0x0f)
946c94880fSSascha Wildner #define MIDIDEV(y) (dev2unit(y) & 0x0f)
956c94880fSSascha Wildner 
966c94880fSSascha Wildner /* These are the entries to the sequencer driver. */
976c94880fSSascha Wildner static d_open_t seq_open;
986c94880fSSascha Wildner static d_close_t seq_close;
996c94880fSSascha Wildner static d_ioctl_t seq_ioctl;
1006c94880fSSascha Wildner static d_read_t seq_read;
1016c94880fSSascha Wildner static d_write_t seq_write;
102*af11d9eeSSascha Wildner static d_kqfilter_t seq_kqfilter;
1036c94880fSSascha Wildner 
104*af11d9eeSSascha Wildner static void	seq_filter_detach(struct knote *);
105*af11d9eeSSascha Wildner static int	seq_filter_read(struct knote *, long);
106*af11d9eeSSascha Wildner static int	seq_filter_write(struct knote *, long);
107*af11d9eeSSascha Wildner 
108*af11d9eeSSascha Wildner static struct dev_ops seq_ops = {
109*af11d9eeSSascha Wildner 	{ "sequencer", 0, D_MPSAFE },
1106c94880fSSascha Wildner 	.d_open = seq_open,
1116c94880fSSascha Wildner 	.d_close = seq_close,
1126c94880fSSascha Wildner 	.d_read = seq_read,
1136c94880fSSascha Wildner 	.d_write = seq_write,
1146c94880fSSascha Wildner 	.d_ioctl = seq_ioctl,
115*af11d9eeSSascha Wildner 	.d_kqfilter = seq_kqfilter,
1166c94880fSSascha Wildner };
1176c94880fSSascha Wildner 
118*af11d9eeSSascha Wildner static struct filterops seq_read_filterops =
119*af11d9eeSSascha Wildner 	{ FILTEROP_ISFD, NULL, seq_filter_detach, seq_filter_read };
120*af11d9eeSSascha Wildner static struct filterops seq_write_filterops =
121*af11d9eeSSascha Wildner 	{ FILTEROP_ISFD, NULL, seq_filter_detach, seq_filter_write };
122*af11d9eeSSascha Wildner 
1236c94880fSSascha Wildner struct seq_softc {
1246c94880fSSascha Wildner 	KOBJ_FIELDS;
1256c94880fSSascha Wildner 
126*af11d9eeSSascha Wildner 	struct lock seq_lock, q_lock;
1276c94880fSSascha Wildner 	struct cv empty_cv, reset_cv, in_cv, out_cv, state_cv, th_cv;
1286c94880fSSascha Wildner 
1296c94880fSSascha Wildner 	MIDIQ_HEAD(, u_char) in_q, out_q;
1306c94880fSSascha Wildner 
1316c94880fSSascha Wildner 	u_long	flags;
1326c94880fSSascha Wildner 	/* Flags (protected by flag_mtx of mididev_info) */
1336c94880fSSascha Wildner 	int	fflags;			/* Access mode */
1346c94880fSSascha Wildner 	int	music;
1356c94880fSSascha Wildner 
1366c94880fSSascha Wildner 	int	out_water;		/* Sequence output threshould */
1376c94880fSSascha Wildner 	snd_sync_parm sync_parm;	/* AIOSYNC parameter set */
1386c94880fSSascha Wildner 	struct thread *sync_thread;	/* AIOSYNCing thread */
139*af11d9eeSSascha Wildner 	struct kqinfo in_kq, out_kq;
1406c94880fSSascha Wildner 	int	midi_number;
1416c94880fSSascha Wildner 	struct cdev *seqdev, *musicdev;
1426c94880fSSascha Wildner 	int	unit;
1436c94880fSSascha Wildner 	int	maxunits;
1446c94880fSSascha Wildner 	kobj_t *midis;
1456c94880fSSascha Wildner 	int    *midi_flags;
1466c94880fSSascha Wildner 	kobj_t	mapper;
1476c94880fSSascha Wildner 	void   *mapper_cookie;
1486c94880fSSascha Wildner 	struct timeval timerstop, timersub;
1496c94880fSSascha Wildner 	int	timerbase, tempo;
1506c94880fSSascha Wildner 	int	timerrun;
1516c94880fSSascha Wildner 	int	done;
1526c94880fSSascha Wildner 	int	playing;
1536c94880fSSascha Wildner 	int	recording;
1546c94880fSSascha Wildner 	int	busy;
1556c94880fSSascha Wildner 	int	pre_event_timeout;
1566c94880fSSascha Wildner 	int	waiting;
1576c94880fSSascha Wildner };
1586c94880fSSascha Wildner 
1596c94880fSSascha Wildner /*
1606c94880fSSascha Wildner  * Module specific stuff, including how many sequecers
1616c94880fSSascha Wildner  * we currently own.
1626c94880fSSascha Wildner  */
1636c94880fSSascha Wildner 
1646c94880fSSascha Wildner SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD, 0, "Midi sequencer");
1656c94880fSSascha Wildner 
1666c94880fSSascha Wildner int					seq_debug;
1676c94880fSSascha Wildner /* XXX: should this be moved into debug.midi? */
1686c94880fSSascha Wildner SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, "");
1696c94880fSSascha Wildner 
1706c94880fSSascha Wildner midi_cmdtab	cmdtab_seqevent[] = {
1716c94880fSSascha Wildner 	{SEQ_NOTEOFF,		"SEQ_NOTEOFF"},
1726c94880fSSascha Wildner 	{SEQ_NOTEON,		"SEQ_NOTEON"},
1736c94880fSSascha Wildner 	{SEQ_WAIT,		"SEQ_WAIT"},
1746c94880fSSascha Wildner 	{SEQ_PGMCHANGE,		"SEQ_PGMCHANGE"},
1756c94880fSSascha Wildner 	{SEQ_SYNCTIMER,		"SEQ_SYNCTIMER"},
1766c94880fSSascha Wildner 	{SEQ_MIDIPUTC,		"SEQ_MIDIPUTC"},
1776c94880fSSascha Wildner 	{SEQ_DRUMON,		"SEQ_DRUMON"},
1786c94880fSSascha Wildner 	{SEQ_DRUMOFF,		"SEQ_DRUMOFF"},
1796c94880fSSascha Wildner 	{SEQ_ECHO,		"SEQ_ECHO"},
1806c94880fSSascha Wildner 	{SEQ_AFTERTOUCH,	"SEQ_AFTERTOUCH"},
1816c94880fSSascha Wildner 	{SEQ_CONTROLLER,	"SEQ_CONTROLLER"},
1826c94880fSSascha Wildner 	{SEQ_BALANCE,		"SEQ_BALANCE"},
1836c94880fSSascha Wildner 	{SEQ_VOLMODE,		"SEQ_VOLMODE"},
1846c94880fSSascha Wildner 	{SEQ_FULLSIZE,		"SEQ_FULLSIZE"},
1856c94880fSSascha Wildner 	{SEQ_PRIVATE,		"SEQ_PRIVATE"},
1866c94880fSSascha Wildner 	{SEQ_EXTENDED,		"SEQ_EXTENDED"},
1876c94880fSSascha Wildner 	{EV_SEQ_LOCAL,		"EV_SEQ_LOCAL"},
1886c94880fSSascha Wildner 	{EV_TIMING,		"EV_TIMING"},
1896c94880fSSascha Wildner 	{EV_CHN_COMMON,		"EV_CHN_COMMON"},
1906c94880fSSascha Wildner 	{EV_CHN_VOICE,		"EV_CHN_VOICE"},
1916c94880fSSascha Wildner 	{EV_SYSEX,		"EV_SYSEX"},
1926c94880fSSascha Wildner 	{-1,			NULL},
1936c94880fSSascha Wildner };
1946c94880fSSascha Wildner 
1956c94880fSSascha Wildner midi_cmdtab	cmdtab_seqioctl[] = {
1966c94880fSSascha Wildner 	{SNDCTL_SEQ_RESET,	"SNDCTL_SEQ_RESET"},
1976c94880fSSascha Wildner 	{SNDCTL_SEQ_SYNC,	"SNDCTL_SEQ_SYNC"},
1986c94880fSSascha Wildner 	{SNDCTL_SYNTH_INFO,	"SNDCTL_SYNTH_INFO"},
1996c94880fSSascha Wildner 	{SNDCTL_SEQ_CTRLRATE,	"SNDCTL_SEQ_CTRLRATE"},
2006c94880fSSascha Wildner 	{SNDCTL_SEQ_GETOUTCOUNT,	"SNDCTL_SEQ_GETOUTCOUNT"},
2016c94880fSSascha Wildner 	{SNDCTL_SEQ_GETINCOUNT,	"SNDCTL_SEQ_GETINCOUNT"},
2026c94880fSSascha Wildner 	{SNDCTL_SEQ_PERCMODE,	"SNDCTL_SEQ_PERCMODE"},
2036c94880fSSascha Wildner 	{SNDCTL_FM_LOAD_INSTR,	"SNDCTL_FM_LOAD_INSTR"},
2046c94880fSSascha Wildner 	{SNDCTL_SEQ_TESTMIDI,	"SNDCTL_SEQ_TESTMIDI"},
2056c94880fSSascha Wildner 	{SNDCTL_SEQ_RESETSAMPLES,	"SNDCTL_SEQ_RESETSAMPLES"},
2066c94880fSSascha Wildner 	{SNDCTL_SEQ_NRSYNTHS,	"SNDCTL_SEQ_NRSYNTHS"},
2076c94880fSSascha Wildner 	{SNDCTL_SEQ_NRMIDIS,	"SNDCTL_SEQ_NRMIDIS"},
2086c94880fSSascha Wildner 	{SNDCTL_SEQ_GETTIME,	"SNDCTL_SEQ_GETTIME"},
2096c94880fSSascha Wildner 	{SNDCTL_MIDI_INFO,	"SNDCTL_MIDI_INFO"},
2106c94880fSSascha Wildner 	{SNDCTL_SEQ_THRESHOLD,	"SNDCTL_SEQ_THRESHOLD"},
2116c94880fSSascha Wildner 	{SNDCTL_SYNTH_MEMAVL,	"SNDCTL_SYNTH_MEMAVL"},
2126c94880fSSascha Wildner 	{SNDCTL_FM_4OP_ENABLE,	"SNDCTL_FM_4OP_ENABLE"},
2136c94880fSSascha Wildner 	{SNDCTL_PMGR_ACCESS,	"SNDCTL_PMGR_ACCESS"},
2146c94880fSSascha Wildner 	{SNDCTL_SEQ_PANIC,	"SNDCTL_SEQ_PANIC"},
2156c94880fSSascha Wildner 	{SNDCTL_SEQ_OUTOFBAND,	"SNDCTL_SEQ_OUTOFBAND"},
2166c94880fSSascha Wildner 	{SNDCTL_TMR_TIMEBASE,	"SNDCTL_TMR_TIMEBASE"},
2176c94880fSSascha Wildner 	{SNDCTL_TMR_START,	"SNDCTL_TMR_START"},
2186c94880fSSascha Wildner 	{SNDCTL_TMR_STOP,	"SNDCTL_TMR_STOP"},
2196c94880fSSascha Wildner 	{SNDCTL_TMR_CONTINUE,	"SNDCTL_TMR_CONTINUE"},
2206c94880fSSascha Wildner 	{SNDCTL_TMR_TEMPO,	"SNDCTL_TMR_TEMPO"},
2216c94880fSSascha Wildner 	{SNDCTL_TMR_SOURCE,	"SNDCTL_TMR_SOURCE"},
2226c94880fSSascha Wildner 	{SNDCTL_TMR_METRONOME,	"SNDCTL_TMR_METRONOME"},
2236c94880fSSascha Wildner 	{SNDCTL_TMR_SELECT,	"SNDCTL_TMR_SELECT"},
2246c94880fSSascha Wildner 	{SNDCTL_MIDI_PRETIME,	"SNDCTL_MIDI_PRETIME"},
2256c94880fSSascha Wildner 	{AIONWRITE,		"AIONWRITE"},
2266c94880fSSascha Wildner 	{AIOGSIZE,		"AIOGSIZE"},
2276c94880fSSascha Wildner 	{AIOSSIZE,		"AIOSSIZE"},
2286c94880fSSascha Wildner 	{AIOGFMT,		"AIOGFMT"},
2296c94880fSSascha Wildner 	{AIOSFMT,		"AIOSFMT"},
2306c94880fSSascha Wildner 	{AIOGMIX,		"AIOGMIX"},
2316c94880fSSascha Wildner 	{AIOSMIX,		"AIOSMIX"},
2326c94880fSSascha Wildner 	{AIOSTOP,		"AIOSTOP"},
2336c94880fSSascha Wildner 	{AIOSYNC,		"AIOSYNC"},
2346c94880fSSascha Wildner 	{AIOGCAP,		"AIOGCAP"},
2356c94880fSSascha Wildner 	{-1,			NULL},
2366c94880fSSascha Wildner };
2376c94880fSSascha Wildner 
2386c94880fSSascha Wildner midi_cmdtab	cmdtab_timer[] = {
2396c94880fSSascha Wildner 	{TMR_WAIT_REL,	"TMR_WAIT_REL"},
2406c94880fSSascha Wildner 	{TMR_WAIT_ABS,	"TMR_WAIT_ABS"},
2416c94880fSSascha Wildner 	{TMR_STOP,	"TMR_STOP"},
2426c94880fSSascha Wildner 	{TMR_START,	"TMR_START"},
2436c94880fSSascha Wildner 	{TMR_CONTINUE,	"TMR_CONTINUE"},
2446c94880fSSascha Wildner 	{TMR_TEMPO,	"TMR_TEMPO"},
2456c94880fSSascha Wildner 	{TMR_ECHO,	"TMR_ECHO"},
2466c94880fSSascha Wildner 	{TMR_CLOCK,	"TMR_CLOCK"},
2476c94880fSSascha Wildner 	{TMR_SPP,	"TMR_SPP"},
2486c94880fSSascha Wildner 	{TMR_TIMESIG,	"TMR_TIMESIG"},
2496c94880fSSascha Wildner 	{-1,		NULL},
2506c94880fSSascha Wildner };
2516c94880fSSascha Wildner 
2526c94880fSSascha Wildner midi_cmdtab	cmdtab_seqcv[] = {
2536c94880fSSascha Wildner 	{MIDI_NOTEOFF,		"MIDI_NOTEOFF"},
2546c94880fSSascha Wildner 	{MIDI_NOTEON,		"MIDI_NOTEON"},
2556c94880fSSascha Wildner 	{MIDI_KEY_PRESSURE,	"MIDI_KEY_PRESSURE"},
2566c94880fSSascha Wildner 	{-1,			NULL},
2576c94880fSSascha Wildner };
2586c94880fSSascha Wildner 
2596c94880fSSascha Wildner midi_cmdtab	cmdtab_seqccmn[] = {
2606c94880fSSascha Wildner 	{MIDI_CTL_CHANGE,	"MIDI_CTL_CHANGE"},
2616c94880fSSascha Wildner 	{MIDI_PGM_CHANGE,	"MIDI_PGM_CHANGE"},
2626c94880fSSascha Wildner 	{MIDI_CHN_PRESSURE,	"MIDI_CHN_PRESSURE"},
2636c94880fSSascha Wildner 	{MIDI_PITCH_BEND,	"MIDI_PITCH_BEND"},
2646c94880fSSascha Wildner 	{MIDI_SYSTEM_PREFIX,	"MIDI_SYSTEM_PREFIX"},
2656c94880fSSascha Wildner 	{-1,			NULL},
2666c94880fSSascha Wildner };
2676c94880fSSascha Wildner 
2686c94880fSSascha Wildner #ifndef KOBJMETHOD_END
2696c94880fSSascha Wildner #define KOBJMETHOD_END	{ NULL, NULL }
2706c94880fSSascha Wildner #endif
2716c94880fSSascha Wildner 
2726c94880fSSascha Wildner /*
2736c94880fSSascha Wildner  * static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
2746c94880fSSascha Wildner  */
2756c94880fSSascha Wildner 
2766c94880fSSascha Wildner static kobj_method_t seq_methods[] = {
2776c94880fSSascha Wildner 	/* KOBJMETHOD(mpu_provider,mpu401_mprovider), */
2786c94880fSSascha Wildner 	KOBJMETHOD_END
2796c94880fSSascha Wildner };
2806c94880fSSascha Wildner 
2816c94880fSSascha Wildner DEFINE_CLASS(sequencer, seq_methods, 0);
2826c94880fSSascha Wildner 
2836c94880fSSascha Wildner /* The followings are the local function. */
2846c94880fSSascha Wildner static int seq_convertold(u_char *event, u_char *out);
2856c94880fSSascha Wildner 
2866c94880fSSascha Wildner /*
2876c94880fSSascha Wildner  * static void seq_midiinput(struct seq_softc * scp, void *md);
2886c94880fSSascha Wildner  */
2896c94880fSSascha Wildner static void seq_reset(struct seq_softc *scp);
2906c94880fSSascha Wildner static int seq_sync(struct seq_softc *scp);
2916c94880fSSascha Wildner 
2926c94880fSSascha Wildner static int seq_processevent(struct seq_softc *scp, u_char *event);
2936c94880fSSascha Wildner 
2946c94880fSSascha Wildner static int seq_timing(struct seq_softc *scp, u_char *event);
2956c94880fSSascha Wildner static int seq_local(struct seq_softc *scp, u_char *event);
2966c94880fSSascha Wildner 
2976c94880fSSascha Wildner static int seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event);
2986c94880fSSascha Wildner static int seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event);
2996c94880fSSascha Wildner static int seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event);
3006c94880fSSascha Wildner 
3016c94880fSSascha Wildner static int seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md);
3026c94880fSSascha Wildner void	seq_copytoinput(struct seq_softc *scp, u_char *event, int len);
3036c94880fSSascha Wildner int	seq_modevent(module_t mod, int type, void *data);
3046c94880fSSascha Wildner struct seq_softc *seqs[10];
305*af11d9eeSSascha Wildner static struct lock seqinfo_lock;
3066c94880fSSascha Wildner static u_long nseq = 0;
3076c94880fSSascha Wildner 
3086c94880fSSascha Wildner static void timer_start(struct seq_softc *t);
3096c94880fSSascha Wildner static void timer_stop(struct seq_softc *t);
3106c94880fSSascha Wildner static void timer_setvals(struct seq_softc *t, int tempo, int timerbase);
3116c94880fSSascha Wildner static void timer_wait(struct seq_softc *t, int ticks, int wait_abs);
3126c94880fSSascha Wildner static int timer_now(struct seq_softc *t);
3136c94880fSSascha Wildner 
3146c94880fSSascha Wildner 
3156c94880fSSascha Wildner static void
timer_start(struct seq_softc * t)3166c94880fSSascha Wildner timer_start(struct seq_softc *t)
3176c94880fSSascha Wildner {
3186c94880fSSascha Wildner 	t->timerrun = 1;
3196c94880fSSascha Wildner 	getmicrotime(&t->timersub);
3206c94880fSSascha Wildner }
3216c94880fSSascha Wildner 
3226c94880fSSascha Wildner static void
timer_continue(struct seq_softc * t)3236c94880fSSascha Wildner timer_continue(struct seq_softc *t)
3246c94880fSSascha Wildner {
3256c94880fSSascha Wildner 	struct timeval now;
3266c94880fSSascha Wildner 
3276c94880fSSascha Wildner 	if (t->timerrun == 1)
3286c94880fSSascha Wildner 		return;
3296c94880fSSascha Wildner 	t->timerrun = 1;
3306c94880fSSascha Wildner 	getmicrotime(&now);
3316c94880fSSascha Wildner 	timevalsub(&now, &t->timerstop);
3326c94880fSSascha Wildner 	timevaladd(&t->timersub, &now);
3336c94880fSSascha Wildner }
3346c94880fSSascha Wildner 
3356c94880fSSascha Wildner static void
timer_stop(struct seq_softc * t)3366c94880fSSascha Wildner timer_stop(struct seq_softc *t)
3376c94880fSSascha Wildner {
3386c94880fSSascha Wildner 	t->timerrun = 0;
3396c94880fSSascha Wildner 	getmicrotime(&t->timerstop);
3406c94880fSSascha Wildner }
3416c94880fSSascha Wildner 
3426c94880fSSascha Wildner static void
timer_setvals(struct seq_softc * t,int tempo,int timerbase)3436c94880fSSascha Wildner timer_setvals(struct seq_softc *t, int tempo, int timerbase)
3446c94880fSSascha Wildner {
3456c94880fSSascha Wildner 	t->tempo = tempo;
3466c94880fSSascha Wildner 	t->timerbase = timerbase;
3476c94880fSSascha Wildner }
3486c94880fSSascha Wildner 
3496c94880fSSascha Wildner static void
timer_wait(struct seq_softc * t,int ticks,int wait_abs)3506c94880fSSascha Wildner timer_wait(struct seq_softc *t, int ticks, int wait_abs)
3516c94880fSSascha Wildner {
3526c94880fSSascha Wildner 	struct timeval now, when;
3536c94880fSSascha Wildner 	int ret;
3546c94880fSSascha Wildner 	unsigned long long i;
3556c94880fSSascha Wildner 
3566c94880fSSascha Wildner 	while (t->timerrun == 0) {
357*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("Timer wait when timer isn't running\n"));
3586c94880fSSascha Wildner 		/*
3596c94880fSSascha Wildner 	         * The old sequencer used timeouts that only increased
3606c94880fSSascha Wildner 	         * the timer when the timer was running.
3616c94880fSSascha Wildner 	         * Hence the sequencer would stick (?) if the
3626c94880fSSascha Wildner 	         * timer was disabled.
3636c94880fSSascha Wildner 	         */
3646c94880fSSascha Wildner 		cv_wait(&t->reset_cv, &t->seq_lock);
3656c94880fSSascha Wildner 		if (t->playing == 0)
3666c94880fSSascha Wildner 			return;
3676c94880fSSascha Wildner 	}
3686c94880fSSascha Wildner 
3696c94880fSSascha Wildner 	i = ticks * 60ull * 1000000ull / (t->tempo * t->timerbase);
3706c94880fSSascha Wildner 
3716c94880fSSascha Wildner 	when.tv_sec = i / 1000000;
3726c94880fSSascha Wildner 	when.tv_usec = i % 1000000;
3736c94880fSSascha Wildner 
3746c94880fSSascha Wildner #if 0
375*af11d9eeSSascha Wildner 	kprintf("timer_wait tempo %d timerbase %d ticks %d abs %d u_sec %llu\n",
3766c94880fSSascha Wildner 	    t->tempo, t->timerbase, ticks, wait_abs, i);
3776c94880fSSascha Wildner #endif
3786c94880fSSascha Wildner 
3796c94880fSSascha Wildner 	if (wait_abs != 0) {
3806c94880fSSascha Wildner 		getmicrotime(&now);
3816c94880fSSascha Wildner 		timevalsub(&now, &t->timersub);
3826c94880fSSascha Wildner 		timevalsub(&when, &now);
3836c94880fSSascha Wildner 	}
3846c94880fSSascha Wildner 	if (when.tv_sec < 0 || when.tv_usec < 0) {
3856c94880fSSascha Wildner 		SEQ_DEBUG(3,
386*af11d9eeSSascha Wildner 		    kprintf("seq_timer error negative time %lds.%06lds\n",
3876c94880fSSascha Wildner 		    (long)when.tv_sec, (long)when.tv_usec));
3886c94880fSSascha Wildner 		return;
3896c94880fSSascha Wildner 	}
3906c94880fSSascha Wildner 	i = when.tv_sec * 1000000ull;
3916c94880fSSascha Wildner 	i += when.tv_usec;
3926c94880fSSascha Wildner 	i *= hz;
3936c94880fSSascha Wildner 	i /= 1000000ull;
3946c94880fSSascha Wildner #if 0
395*af11d9eeSSascha Wildner 	kprintf("seq_timer usec %llu ticks %llu\n",
3966c94880fSSascha Wildner 	    when.tv_sec * 1000000ull + when.tv_usec, i);
3976c94880fSSascha Wildner #endif
3986c94880fSSascha Wildner 	t->waiting = 1;
3996c94880fSSascha Wildner 	ret = cv_timedwait(&t->reset_cv, &t->seq_lock, i + 1);
4006c94880fSSascha Wildner 	t->waiting = 0;
4016c94880fSSascha Wildner 
4026c94880fSSascha Wildner 	if (ret != EWOULDBLOCK)
403*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_timer didn't timeout\n"));
4046c94880fSSascha Wildner 
4056c94880fSSascha Wildner }
4066c94880fSSascha Wildner 
4076c94880fSSascha Wildner static int
timer_now(struct seq_softc * t)4086c94880fSSascha Wildner timer_now(struct seq_softc *t)
4096c94880fSSascha Wildner {
4106c94880fSSascha Wildner 	struct timeval now;
4116c94880fSSascha Wildner 	unsigned long long i;
4126c94880fSSascha Wildner 	int ret;
4136c94880fSSascha Wildner 
4146c94880fSSascha Wildner 	if (t->timerrun == 0)
4156c94880fSSascha Wildner 		now = t->timerstop;
4166c94880fSSascha Wildner 	else
4176c94880fSSascha Wildner 		getmicrotime(&now);
4186c94880fSSascha Wildner 
4196c94880fSSascha Wildner 	timevalsub(&now, &t->timersub);
4206c94880fSSascha Wildner 
4216c94880fSSascha Wildner 	i = now.tv_sec * 1000000ull;
4226c94880fSSascha Wildner 	i += now.tv_usec;
4236c94880fSSascha Wildner 	i *= t->timerbase;
4246c94880fSSascha Wildner /*	i /= t->tempo; */
4256c94880fSSascha Wildner 	i /= 1000000ull;
4266c94880fSSascha Wildner 
4276c94880fSSascha Wildner 	ret = i;
4286c94880fSSascha Wildner 	/*
429*af11d9eeSSascha Wildner 	 * kprintf("timer_now: %llu %d\n", i, ret);
4306c94880fSSascha Wildner 	 */
4316c94880fSSascha Wildner 
4326c94880fSSascha Wildner 	return ret;
4336c94880fSSascha Wildner }
4346c94880fSSascha Wildner 
4356c94880fSSascha Wildner static void
seq_eventthread(void * arg)4366c94880fSSascha Wildner seq_eventthread(void *arg)
4376c94880fSSascha Wildner {
4386c94880fSSascha Wildner 	struct seq_softc *scp = arg;
4396c94880fSSascha Wildner 	char event[EV_SZ];
4406c94880fSSascha Wildner 
441*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
442*af11d9eeSSascha Wildner 	SEQ_DEBUG(2, kprintf("seq_eventthread started\n"));
4436c94880fSSascha Wildner 	while (scp->done == 0) {
4446c94880fSSascha Wildner restart:
4456c94880fSSascha Wildner 		while (scp->playing == 0) {
4466c94880fSSascha Wildner 			cv_wait(&scp->state_cv, &scp->seq_lock);
4476c94880fSSascha Wildner 			if (scp->done)
4486c94880fSSascha Wildner 				goto done;
4496c94880fSSascha Wildner 		}
4506c94880fSSascha Wildner 
4516c94880fSSascha Wildner 		while (MIDIQ_EMPTY(scp->out_q)) {
4526c94880fSSascha Wildner 			cv_broadcast(&scp->empty_cv);
4536c94880fSSascha Wildner 			cv_wait(&scp->out_cv, &scp->seq_lock);
4546c94880fSSascha Wildner 			if (scp->playing == 0)
4556c94880fSSascha Wildner 				goto restart;
4566c94880fSSascha Wildner 			if (scp->done)
4576c94880fSSascha Wildner 				goto done;
4586c94880fSSascha Wildner 		}
4596c94880fSSascha Wildner 
4606c94880fSSascha Wildner 		MIDIQ_DEQ(scp->out_q, event, EV_SZ);
4616c94880fSSascha Wildner 
4626c94880fSSascha Wildner 		if (MIDIQ_AVAIL(scp->out_q) < scp->out_water) {
4636c94880fSSascha Wildner 			cv_broadcast(&scp->out_cv);
464*af11d9eeSSascha Wildner 			KNOTE(&scp->out_kq.ki_note, 0);
4656c94880fSSascha Wildner 		}
4666c94880fSSascha Wildner 		seq_processevent(scp, event);
4676c94880fSSascha Wildner 	}
4686c94880fSSascha Wildner 
4696c94880fSSascha Wildner done:
4706c94880fSSascha Wildner 	cv_broadcast(&scp->th_cv);
471*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
472*af11d9eeSSascha Wildner 	SEQ_DEBUG(2, kprintf("seq_eventthread finished\n"));
473*af11d9eeSSascha Wildner 	kthread_exit();
4746c94880fSSascha Wildner }
4756c94880fSSascha Wildner 
4766c94880fSSascha Wildner /*
4776c94880fSSascha Wildner  * seq_processevent:  This maybe called by the event thread or the IOCTL
4786c94880fSSascha Wildner  * handler for queued and out of band events respectively.
4796c94880fSSascha Wildner  */
4806c94880fSSascha Wildner static int
seq_processevent(struct seq_softc * scp,u_char * event)4816c94880fSSascha Wildner seq_processevent(struct seq_softc *scp, u_char *event)
4826c94880fSSascha Wildner {
4836c94880fSSascha Wildner 	int ret;
4846c94880fSSascha Wildner 	kobj_t m;
4856c94880fSSascha Wildner 
4866c94880fSSascha Wildner 	ret = 0;
4876c94880fSSascha Wildner 
4886c94880fSSascha Wildner 	if (event[0] == EV_SEQ_LOCAL)
4896c94880fSSascha Wildner 		ret = seq_local(scp, event);
4906c94880fSSascha Wildner 	else if (event[0] == EV_TIMING)
4916c94880fSSascha Wildner 		ret = seq_timing(scp, event);
4926c94880fSSascha Wildner 	else if (event[0] != EV_CHN_VOICE &&
4936c94880fSSascha Wildner 		    event[0] != EV_CHN_COMMON &&
4946c94880fSSascha Wildner 		    event[0] != EV_SYSEX &&
4956c94880fSSascha Wildner 	    event[0] != SEQ_MIDIPUTC) {
4966c94880fSSascha Wildner 		ret = 1;
497*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_processevent not known %d\n",
4986c94880fSSascha Wildner 		    event[0]));
4996c94880fSSascha Wildner 	} else if (seq_fetch_mid(scp, event[1], &m) != 0) {
5006c94880fSSascha Wildner 		ret = 1;
501*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_processevent midi unit not found %d\n",
5026c94880fSSascha Wildner 		    event[1]));
5036c94880fSSascha Wildner 	} else
5046c94880fSSascha Wildner 		switch (event[0]) {
5056c94880fSSascha Wildner 		case EV_CHN_VOICE:
5066c94880fSSascha Wildner 			ret = seq_chnvoice(scp, m, event);
5076c94880fSSascha Wildner 			break;
5086c94880fSSascha Wildner 		case EV_CHN_COMMON:
5096c94880fSSascha Wildner 			ret = seq_chncommon(scp, m, event);
5106c94880fSSascha Wildner 			break;
5116c94880fSSascha Wildner 		case EV_SYSEX:
5126c94880fSSascha Wildner 			ret = seq_sysex(scp, m, event);
5136c94880fSSascha Wildner 			break;
5146c94880fSSascha Wildner 		case SEQ_MIDIPUTC:
515*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_RELEASE);
5166c94880fSSascha Wildner 			ret = SYNTH_WRITERAW(m, &event[2], 1);
517*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
5186c94880fSSascha Wildner 			break;
5196c94880fSSascha Wildner 		}
5206c94880fSSascha Wildner 	return ret;
5216c94880fSSascha Wildner }
5226c94880fSSascha Wildner 
5236c94880fSSascha Wildner static int
seq_addunit(void)5246c94880fSSascha Wildner seq_addunit(void)
5256c94880fSSascha Wildner {
5266c94880fSSascha Wildner 	struct seq_softc *scp;
5276c94880fSSascha Wildner 	int ret;
5286c94880fSSascha Wildner 	u_char *buf;
5296c94880fSSascha Wildner 
5306c94880fSSascha Wildner 	/* Allocate the softc. */
5316c94880fSSascha Wildner 	ret = ENOMEM;
532*af11d9eeSSascha Wildner 	scp = kmalloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO);
5336c94880fSSascha Wildner 	kobj_init((kobj_t)scp, &sequencer_class);
5346c94880fSSascha Wildner 
535*af11d9eeSSascha Wildner 	buf = kmalloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_WAITOK | M_ZERO);
5366c94880fSSascha Wildner 	MIDIQ_INIT(scp->in_q, buf, EV_SZ * 1024);
537*af11d9eeSSascha Wildner 	buf = kmalloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_WAITOK | M_ZERO);
5386c94880fSSascha Wildner 	MIDIQ_INIT(scp->out_q, buf, EV_SZ * 1024);
5396c94880fSSascha Wildner 	ret = EINVAL;
5406c94880fSSascha Wildner 
541*af11d9eeSSascha Wildner 	scp->midis = kmalloc(sizeof(kobj_t) * 32, M_TEMP, M_WAITOK | M_ZERO);
542*af11d9eeSSascha Wildner 	scp->midi_flags = kmalloc(sizeof(*scp->midi_flags) * 32, M_TEMP,
543*af11d9eeSSascha Wildner 	    M_WAITOK | M_ZERO);
5446c94880fSSascha Wildner 
5456c94880fSSascha Wildner 	scp->flags = 0;
5466c94880fSSascha Wildner 
547*af11d9eeSSascha Wildner 	lockinit(&scp->seq_lock, "seqflq", 0, LK_CANRECURSE);
5486c94880fSSascha Wildner 	cv_init(&scp->state_cv, "seqstate");
5496c94880fSSascha Wildner 	cv_init(&scp->empty_cv, "seqempty");
5506c94880fSSascha Wildner 	cv_init(&scp->reset_cv, "seqtimer");
5516c94880fSSascha Wildner 	cv_init(&scp->out_cv, "seqqout");
5526c94880fSSascha Wildner 	cv_init(&scp->in_cv, "seqqin");
5536c94880fSSascha Wildner 	cv_init(&scp->th_cv, "seqstart");
5546c94880fSSascha Wildner 
5556c94880fSSascha Wildner 	/*
5566c94880fSSascha Wildner 	 * Init the damn timer
5576c94880fSSascha Wildner 	 */
5586c94880fSSascha Wildner 
5596c94880fSSascha Wildner 	scp->mapper = midimapper_addseq(scp, &scp->unit, &scp->mapper_cookie);
5606c94880fSSascha Wildner 	if (scp->mapper == NULL)
5616c94880fSSascha Wildner 		goto err;
5626c94880fSSascha Wildner 
563*af11d9eeSSascha Wildner 	scp->seqdev = make_dev(&seq_ops,
5646c94880fSSascha Wildner 	    MIDIMKMINOR(scp->unit, SND_DEV_SEQ, 0), UID_ROOT,
5656c94880fSSascha Wildner 	    GID_WHEEL, 0666, "sequencer%d", scp->unit);
5666c94880fSSascha Wildner 
567*af11d9eeSSascha Wildner 	scp->musicdev = make_dev(&seq_ops,
5686c94880fSSascha Wildner 	    MIDIMKMINOR(scp->unit, SND_DEV_MUSIC, 0), UID_ROOT,
5696c94880fSSascha Wildner 	    GID_WHEEL, 0666, "music%d", scp->unit);
5706c94880fSSascha Wildner 
5716c94880fSSascha Wildner 	if (scp->seqdev == NULL || scp->musicdev == NULL)
5726c94880fSSascha Wildner 		goto err;
5736c94880fSSascha Wildner 	/*
5746c94880fSSascha Wildner 	 * TODO: Add to list of sequencers this module provides
5756c94880fSSascha Wildner 	 */
5766c94880fSSascha Wildner 
5776c94880fSSascha Wildner 	ret =
578*af11d9eeSSascha Wildner 	    kthread_create
579*af11d9eeSSascha Wildner 	    (seq_eventthread, scp, NULL,
5806c94880fSSascha Wildner 	    "sequencer %02d", scp->unit);
5816c94880fSSascha Wildner 
5826c94880fSSascha Wildner 	if (ret)
5836c94880fSSascha Wildner 		goto err;
5846c94880fSSascha Wildner 
5856c94880fSSascha Wildner 	scp->seqdev->si_drv1 = scp->musicdev->si_drv1 = scp;
5866c94880fSSascha Wildner 
587*af11d9eeSSascha Wildner 	SEQ_DEBUG(2, kprintf("sequencer %d created scp %p\n", scp->unit, scp));
5886c94880fSSascha Wildner 
5896c94880fSSascha Wildner 	ret = 0;
5906c94880fSSascha Wildner 
591*af11d9eeSSascha Wildner 	lockmgr(&seqinfo_lock, LK_EXCLUSIVE);
5926c94880fSSascha Wildner 	seqs[nseq++] = scp;
593*af11d9eeSSascha Wildner 	lockmgr(&seqinfo_lock, LK_RELEASE);
5946c94880fSSascha Wildner 
5956c94880fSSascha Wildner 	goto ok;
5966c94880fSSascha Wildner 
5976c94880fSSascha Wildner err:
5986c94880fSSascha Wildner 	if (scp != NULL) {
5996c94880fSSascha Wildner 		if (scp->seqdev != NULL)
6006c94880fSSascha Wildner 			destroy_dev(scp->seqdev);
6016c94880fSSascha Wildner 		if (scp->musicdev != NULL)
6026c94880fSSascha Wildner 			destroy_dev(scp->musicdev);
6036c94880fSSascha Wildner 		/*
6046c94880fSSascha Wildner 	         * TODO: Destroy mutex and cv
6056c94880fSSascha Wildner 	         */
6066c94880fSSascha Wildner 		if (scp->midis != NULL)
607*af11d9eeSSascha Wildner 			kfree(scp->midis, M_TEMP);
6086c94880fSSascha Wildner 		if (scp->midi_flags != NULL)
609*af11d9eeSSascha Wildner 			kfree(scp->midi_flags, M_TEMP);
6106c94880fSSascha Wildner 		if (scp->out_q.b)
611*af11d9eeSSascha Wildner 			kfree(scp->out_q.b, M_TEMP);
6126c94880fSSascha Wildner 		if (scp->in_q.b)
613*af11d9eeSSascha Wildner 			kfree(scp->in_q.b, M_TEMP);
614*af11d9eeSSascha Wildner 		kfree(scp, M_DEVBUF);
6156c94880fSSascha Wildner 	}
6166c94880fSSascha Wildner ok:
6176c94880fSSascha Wildner 	return ret;
6186c94880fSSascha Wildner }
6196c94880fSSascha Wildner 
6206c94880fSSascha Wildner static int
seq_delunit(int unit)6216c94880fSSascha Wildner seq_delunit(int unit)
6226c94880fSSascha Wildner {
6236c94880fSSascha Wildner 	struct seq_softc *scp = seqs[unit];
6246c94880fSSascha Wildner 	int i;
6256c94880fSSascha Wildner 
626*af11d9eeSSascha Wildner 	//SEQ_DEBUG(4, kprintf("seq_delunit: %d\n", unit));
627*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 1 \n"));
628*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
6296c94880fSSascha Wildner 
6306c94880fSSascha Wildner 	scp->playing = 0;
6316c94880fSSascha Wildner 	scp->done = 1;
6326c94880fSSascha Wildner 	cv_broadcast(&scp->out_cv);
6336c94880fSSascha Wildner 	cv_broadcast(&scp->state_cv);
6346c94880fSSascha Wildner 	cv_broadcast(&scp->reset_cv);
635*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 2 \n"));
6366c94880fSSascha Wildner 	cv_wait(&scp->th_cv, &scp->seq_lock);
637*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 3.0 \n"));
638*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
639*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 3.1 \n"));
6406c94880fSSascha Wildner 
6416c94880fSSascha Wildner 	cv_destroy(&scp->state_cv);
642*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 4 \n"));
6436c94880fSSascha Wildner 	cv_destroy(&scp->empty_cv);
644*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 5 \n"));
6456c94880fSSascha Wildner 	cv_destroy(&scp->reset_cv);
646*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 6 \n"));
6476c94880fSSascha Wildner 	cv_destroy(&scp->out_cv);
648*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 7 \n"));
6496c94880fSSascha Wildner 	cv_destroy(&scp->in_cv);
650*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 8 \n"));
6516c94880fSSascha Wildner 	cv_destroy(&scp->th_cv);
6526c94880fSSascha Wildner 
653*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 10 \n"));
6546c94880fSSascha Wildner 	if (scp->seqdev)
6556c94880fSSascha Wildner 		destroy_dev(scp->seqdev);
656*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 11 \n"));
6576c94880fSSascha Wildner 	if (scp->musicdev)
6586c94880fSSascha Wildner 		destroy_dev(scp->musicdev);
659*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 12 \n"));
6606c94880fSSascha Wildner 	scp->seqdev = scp->musicdev = NULL;
6616c94880fSSascha Wildner 	if (scp->midis != NULL)
662*af11d9eeSSascha Wildner 		kfree(scp->midis, M_TEMP);
663*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 13 \n"));
6646c94880fSSascha Wildner 	if (scp->midi_flags != NULL)
665*af11d9eeSSascha Wildner 		kfree(scp->midi_flags, M_TEMP);
666*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 14 \n"));
667*af11d9eeSSascha Wildner 	kfree(scp->out_q.b, M_TEMP);
668*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 15 \n"));
669*af11d9eeSSascha Wildner 	kfree(scp->in_q.b, M_TEMP);
6706c94880fSSascha Wildner 
671*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 16 \n"));
6726c94880fSSascha Wildner 
673*af11d9eeSSascha Wildner 	lockuninit(&scp->seq_lock);
674*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_delunit: 17 \n"));
675*af11d9eeSSascha Wildner 	kfree(scp, M_DEVBUF);
6766c94880fSSascha Wildner 
677*af11d9eeSSascha Wildner 	lockmgr(&seqinfo_lock, LK_EXCLUSIVE);
6786c94880fSSascha Wildner 	for (i = unit; i < (nseq - 1); i++)
6796c94880fSSascha Wildner 		seqs[i] = seqs[i + 1];
6806c94880fSSascha Wildner 	nseq--;
681*af11d9eeSSascha Wildner 	lockmgr(&seqinfo_lock, LK_RELEASE);
6826c94880fSSascha Wildner 
6836c94880fSSascha Wildner 	return 0;
6846c94880fSSascha Wildner }
6856c94880fSSascha Wildner 
6866c94880fSSascha Wildner int
seq_modevent(module_t mod,int type,void * data)6876c94880fSSascha Wildner seq_modevent(module_t mod, int type, void *data)
6886c94880fSSascha Wildner {
6896c94880fSSascha Wildner 	int retval, r;
6906c94880fSSascha Wildner 
6916c94880fSSascha Wildner 	retval = 0;
6926c94880fSSascha Wildner 
6936c94880fSSascha Wildner 	switch (type) {
6946c94880fSSascha Wildner 	case MOD_LOAD:
695*af11d9eeSSascha Wildner 		lockinit(&seqinfo_lock, "seqmod", 0, LK_CANRECURSE);
6966c94880fSSascha Wildner 		retval = seq_addunit();
6976c94880fSSascha Wildner 		break;
6986c94880fSSascha Wildner 
6996c94880fSSascha Wildner 	case MOD_UNLOAD:
7006c94880fSSascha Wildner 		while (nseq) {
7016c94880fSSascha Wildner 			r = seq_delunit(nseq - 1);
7026c94880fSSascha Wildner 			if (r) {
7036c94880fSSascha Wildner 				retval = r;
7046c94880fSSascha Wildner 				break;
7056c94880fSSascha Wildner 			}
7066c94880fSSascha Wildner 		}
7076c94880fSSascha Wildner 		if (nseq == 0) {
7086c94880fSSascha Wildner 			retval = 0;
709*af11d9eeSSascha Wildner 			lockuninit(&seqinfo_lock);
7106c94880fSSascha Wildner 		}
7116c94880fSSascha Wildner 		break;
7126c94880fSSascha Wildner 
7136c94880fSSascha Wildner 	default:
7146c94880fSSascha Wildner 		break;
7156c94880fSSascha Wildner 	}
7166c94880fSSascha Wildner 
7176c94880fSSascha Wildner 	return retval;
7186c94880fSSascha Wildner }
7196c94880fSSascha Wildner 
7206c94880fSSascha Wildner static int
seq_fetch_mid(struct seq_softc * scp,int unit,kobj_t * md)7216c94880fSSascha Wildner seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md)
7226c94880fSSascha Wildner {
7236c94880fSSascha Wildner 
7246c94880fSSascha Wildner 	if (unit > scp->midi_number || unit < 0)
7256c94880fSSascha Wildner 		return EINVAL;
7266c94880fSSascha Wildner 
7276c94880fSSascha Wildner 	*md = scp->midis[unit];
7286c94880fSSascha Wildner 
7296c94880fSSascha Wildner 	return 0;
7306c94880fSSascha Wildner }
7316c94880fSSascha Wildner 
7326c94880fSSascha Wildner int
seq_open(struct dev_open_args * ap)733*af11d9eeSSascha Wildner seq_open(struct dev_open_args *ap)
7346c94880fSSascha Wildner {
735*af11d9eeSSascha Wildner 	cdev_t i_dev = ap->a_head.a_dev;
736*af11d9eeSSascha Wildner 	int flags = ap->a_oflags;
7376c94880fSSascha Wildner 	struct seq_softc *scp = i_dev->si_drv1;
7386c94880fSSascha Wildner 	int i;
7396c94880fSSascha Wildner 
7406c94880fSSascha Wildner 	if (scp == NULL)
7416c94880fSSascha Wildner 		return ENXIO;
7426c94880fSSascha Wildner 
743*af11d9eeSSascha Wildner 	SEQ_DEBUG(3, kprintf("seq_open: scp %p unit %d, flags 0x%x.\n",
7446c94880fSSascha Wildner 	    scp, scp->unit, flags));
7456c94880fSSascha Wildner 
7466c94880fSSascha Wildner 	/*
7476c94880fSSascha Wildner 	 * Mark this device busy.
7486c94880fSSascha Wildner 	 */
7496c94880fSSascha Wildner 
750*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
7516c94880fSSascha Wildner 	if (scp->busy) {
752*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
753*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_open: unit %d is busy.\n", scp->unit));
7546c94880fSSascha Wildner 		return EBUSY;
7556c94880fSSascha Wildner 	}
7566c94880fSSascha Wildner 	scp->fflags = flags;
7576c94880fSSascha Wildner 	/*
7586c94880fSSascha Wildner 	if ((scp->fflags & O_NONBLOCK) != 0)
7596c94880fSSascha Wildner 		scp->flags |= SEQ_F_NBIO;
7606c94880fSSascha Wildner 		*/
7616c94880fSSascha Wildner 	scp->music = MIDIDEV(i_dev) == SND_DEV_MUSIC;
7626c94880fSSascha Wildner 
7636c94880fSSascha Wildner 	/*
7646c94880fSSascha Wildner 	 * Enumerate the available midi devices
7656c94880fSSascha Wildner 	 */
7666c94880fSSascha Wildner 	scp->midi_number = 0;
7676c94880fSSascha Wildner 	scp->maxunits = midimapper_open(scp->mapper, &scp->mapper_cookie);
7686c94880fSSascha Wildner 
7696c94880fSSascha Wildner 	if (scp->maxunits == 0)
770*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_open: no midi devices\n"));
7716c94880fSSascha Wildner 
7726c94880fSSascha Wildner 	for (i = 0; i < scp->maxunits; i++) {
7736c94880fSSascha Wildner 		scp->midis[scp->midi_number] =
7746c94880fSSascha Wildner 		    midimapper_fetch_synth(scp->mapper, scp->mapper_cookie, i);
7756c94880fSSascha Wildner 		if (scp->midis[scp->midi_number]) {
7766c94880fSSascha Wildner 			if (SYNTH_OPEN(scp->midis[scp->midi_number], scp,
7776c94880fSSascha Wildner 				scp->fflags) != 0)
7786c94880fSSascha Wildner 				scp->midis[scp->midi_number] = NULL;
7796c94880fSSascha Wildner 			else {
7806c94880fSSascha Wildner 				scp->midi_flags[scp->midi_number] =
7816c94880fSSascha Wildner 				    SYNTH_QUERY(scp->midis[scp->midi_number]);
7826c94880fSSascha Wildner 				scp->midi_number++;
7836c94880fSSascha Wildner 			}
7846c94880fSSascha Wildner 		}
7856c94880fSSascha Wildner 	}
7866c94880fSSascha Wildner 
7876c94880fSSascha Wildner 	timer_setvals(scp, 60, 100);
7886c94880fSSascha Wildner 
7896c94880fSSascha Wildner 	timer_start(scp);
7906c94880fSSascha Wildner 	timer_stop(scp);
7916c94880fSSascha Wildner 	/*
7926c94880fSSascha Wildner 	 * actually, if we're in rdonly mode, we should start the timer
7936c94880fSSascha Wildner 	 */
7946c94880fSSascha Wildner 	/*
7956c94880fSSascha Wildner 	 * TODO: Handle recording now
7966c94880fSSascha Wildner 	 */
7976c94880fSSascha Wildner 
7986c94880fSSascha Wildner 	scp->out_water = MIDIQ_SIZE(scp->out_q) / 2;
7996c94880fSSascha Wildner 
8006c94880fSSascha Wildner 	scp->busy = 1;
801*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
8026c94880fSSascha Wildner 
803*af11d9eeSSascha Wildner 	SEQ_DEBUG(2, kprintf("seq_open: opened, mode %s.\n",
8046c94880fSSascha Wildner 	    scp->music ? "music" : "sequencer"));
8056c94880fSSascha Wildner 	SEQ_DEBUG(2,
806*af11d9eeSSascha Wildner 	    kprintf("Sequencer %d %p opened maxunits %d midi_number %d:\n",
8076c94880fSSascha Wildner 		scp->unit, scp, scp->maxunits, scp->midi_number));
8086c94880fSSascha Wildner 	for (i = 0; i < scp->midi_number; i++)
809*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("  midi %d %p\n", i, scp->midis[i]));
8106c94880fSSascha Wildner 
8116c94880fSSascha Wildner 	return 0;
8126c94880fSSascha Wildner }
8136c94880fSSascha Wildner 
8146c94880fSSascha Wildner /*
8156c94880fSSascha Wildner  * seq_close
8166c94880fSSascha Wildner  */
8176c94880fSSascha Wildner int
seq_close(struct dev_close_args * ap)818*af11d9eeSSascha Wildner seq_close(struct dev_close_args *ap)
8196c94880fSSascha Wildner {
820*af11d9eeSSascha Wildner 	cdev_t i_dev = ap->a_head.a_dev;
8216c94880fSSascha Wildner 	int i;
8226c94880fSSascha Wildner 	struct seq_softc *scp = i_dev->si_drv1;
8236c94880fSSascha Wildner 	int ret;
8246c94880fSSascha Wildner 
8256c94880fSSascha Wildner 	if (scp == NULL)
8266c94880fSSascha Wildner 		return ENXIO;
8276c94880fSSascha Wildner 
828*af11d9eeSSascha Wildner 	SEQ_DEBUG(2, kprintf("seq_close: unit %d.\n", scp->unit));
8296c94880fSSascha Wildner 
830*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
8316c94880fSSascha Wildner 
8326c94880fSSascha Wildner 	ret = ENXIO;
8336c94880fSSascha Wildner 	if (scp->busy == 0)
8346c94880fSSascha Wildner 		goto err;
8356c94880fSSascha Wildner 
8366c94880fSSascha Wildner 	seq_reset(scp);
8376c94880fSSascha Wildner 	seq_sync(scp);
8386c94880fSSascha Wildner 
8396c94880fSSascha Wildner 	for (i = 0; i < scp->midi_number; i++)
8406c94880fSSascha Wildner 		if (scp->midis[i])
8416c94880fSSascha Wildner 			SYNTH_CLOSE(scp->midis[i]);
8426c94880fSSascha Wildner 
8436c94880fSSascha Wildner 	midimapper_close(scp->mapper, scp->mapper_cookie);
8446c94880fSSascha Wildner 
8456c94880fSSascha Wildner 	timer_stop(scp);
8466c94880fSSascha Wildner 
8476c94880fSSascha Wildner 	scp->busy = 0;
8486c94880fSSascha Wildner 	ret = 0;
8496c94880fSSascha Wildner 
8506c94880fSSascha Wildner err:
851*af11d9eeSSascha Wildner 	SEQ_DEBUG(3, kprintf("seq_close: closed ret = %d.\n", ret));
852*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
8536c94880fSSascha Wildner 	return ret;
8546c94880fSSascha Wildner }
8556c94880fSSascha Wildner 
8566c94880fSSascha Wildner int
seq_read(struct dev_read_args * ap)857*af11d9eeSSascha Wildner seq_read(struct dev_read_args *ap)
8586c94880fSSascha Wildner {
859*af11d9eeSSascha Wildner 	cdev_t i_dev = ap->a_head.a_dev;
860*af11d9eeSSascha Wildner 	struct uio *uio = ap->a_uio;
861*af11d9eeSSascha Wildner 	int ioflag = ap->a_ioflag;
8626c94880fSSascha Wildner 	int retval, used;
8636c94880fSSascha Wildner 	struct seq_softc *scp = i_dev->si_drv1;
8646c94880fSSascha Wildner 
8656c94880fSSascha Wildner #define SEQ_RSIZE 32
8666c94880fSSascha Wildner 	u_char buf[SEQ_RSIZE];
8676c94880fSSascha Wildner 
8686c94880fSSascha Wildner 	if (scp == NULL)
8696c94880fSSascha Wildner 		return ENXIO;
8706c94880fSSascha Wildner 
871*af11d9eeSSascha Wildner 	SEQ_DEBUG(7, kprintf("seq_read: unit %d, resid %zd.\n",
8726c94880fSSascha Wildner 	    scp->unit, uio->uio_resid));
8736c94880fSSascha Wildner 
874*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
8756c94880fSSascha Wildner 	if ((scp->fflags & FREAD) == 0) {
876*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_read: unit %d is not for reading.\n",
8776c94880fSSascha Wildner 		    scp->unit));
8786c94880fSSascha Wildner 		retval = EIO;
8796c94880fSSascha Wildner 		goto err1;
8806c94880fSSascha Wildner 	}
8816c94880fSSascha Wildner 	/*
8826c94880fSSascha Wildner 	 * Begin recording.
8836c94880fSSascha Wildner 	 */
8846c94880fSSascha Wildner 	/*
8856c94880fSSascha Wildner 	 * if ((scp->flags & SEQ_F_READING) == 0)
8866c94880fSSascha Wildner 	 */
8876c94880fSSascha Wildner 	/*
8886c94880fSSascha Wildner 	 * TODO, start recording if not alread
8896c94880fSSascha Wildner 	 */
8906c94880fSSascha Wildner 
8916c94880fSSascha Wildner 	/*
8926c94880fSSascha Wildner 	 * I think the semantics are to return as soon
8936c94880fSSascha Wildner 	 * as possible.
8946c94880fSSascha Wildner 	 * Second thought, it doens't seem like midimoutain
8956c94880fSSascha Wildner 	 * expects that at all.
8966c94880fSSascha Wildner 	 * TODO: Look up in some sort of spec
8976c94880fSSascha Wildner 	 */
8986c94880fSSascha Wildner 
8996c94880fSSascha Wildner 	while (uio->uio_resid > 0) {
9006c94880fSSascha Wildner 		while (MIDIQ_EMPTY(scp->in_q)) {
9016c94880fSSascha Wildner 			retval = EWOULDBLOCK;
9026c94880fSSascha Wildner 			/*
9036c94880fSSascha Wildner 			 * I wish I knew which one to care about
9046c94880fSSascha Wildner 			 */
9056c94880fSSascha Wildner 
9066c94880fSSascha Wildner 			if (scp->fflags & O_NONBLOCK)
9076c94880fSSascha Wildner 				goto err1;
9086c94880fSSascha Wildner 			if (ioflag & O_NONBLOCK)
9096c94880fSSascha Wildner 				goto err1;
9106c94880fSSascha Wildner 
9116c94880fSSascha Wildner 			retval = cv_wait_sig(&scp->in_cv, &scp->seq_lock);
9126c94880fSSascha Wildner 			if (retval == EINTR)
9136c94880fSSascha Wildner 				goto err1;
9146c94880fSSascha Wildner 		}
9156c94880fSSascha Wildner 
9166c94880fSSascha Wildner 		used = MIN(MIDIQ_LEN(scp->in_q), uio->uio_resid);
9176c94880fSSascha Wildner 		used = MIN(used, SEQ_RSIZE);
9186c94880fSSascha Wildner 
919*af11d9eeSSascha Wildner 		SEQ_DEBUG(8, kprintf("midiread: uiomove cc=%d\n", used));
9206c94880fSSascha Wildner 		MIDIQ_DEQ(scp->in_q, buf, used);
9216c94880fSSascha Wildner 		retval = uiomove(buf, used, uio);
9226c94880fSSascha Wildner 		if (retval)
9236c94880fSSascha Wildner 			goto err1;
9246c94880fSSascha Wildner 	}
9256c94880fSSascha Wildner 
9266c94880fSSascha Wildner 	retval = 0;
9276c94880fSSascha Wildner err1:
928*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
929*af11d9eeSSascha Wildner 	SEQ_DEBUG(6, kprintf("seq_read: ret %d, resid %zd.\n",
9306c94880fSSascha Wildner 	    retval, uio->uio_resid));
9316c94880fSSascha Wildner 
9326c94880fSSascha Wildner 	return retval;
9336c94880fSSascha Wildner }
9346c94880fSSascha Wildner 
9356c94880fSSascha Wildner int
seq_write(struct dev_write_args * ap)936*af11d9eeSSascha Wildner seq_write(struct dev_write_args *ap)
9376c94880fSSascha Wildner {
938*af11d9eeSSascha Wildner 	cdev_t i_dev = ap->a_head.a_dev;
939*af11d9eeSSascha Wildner 	struct uio *uio = ap->a_uio;
940*af11d9eeSSascha Wildner 	int ioflag = ap->a_ioflag;
9416c94880fSSascha Wildner 	u_char event[EV_SZ], newevent[EV_SZ], ev_code;
9426c94880fSSascha Wildner 	struct seq_softc *scp = i_dev->si_drv1;
9436c94880fSSascha Wildner 	int retval;
9446c94880fSSascha Wildner 	int used;
9456c94880fSSascha Wildner 
946*af11d9eeSSascha Wildner 	SEQ_DEBUG(7, kprintf("seq_write: unit %d, resid %zd.\n",
9476c94880fSSascha Wildner 	    scp->unit, uio->uio_resid));
9486c94880fSSascha Wildner 
9496c94880fSSascha Wildner 	if (scp == NULL)
9506c94880fSSascha Wildner 		return ENXIO;
9516c94880fSSascha Wildner 
952*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
9536c94880fSSascha Wildner 
9546c94880fSSascha Wildner 	if ((scp->fflags & FWRITE) == 0) {
955*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_write: unit %d is not for writing.\n",
9566c94880fSSascha Wildner 		    scp->unit));
9576c94880fSSascha Wildner 		retval = EIO;
9586c94880fSSascha Wildner 		goto err0;
9596c94880fSSascha Wildner 	}
9606c94880fSSascha Wildner 	while (uio->uio_resid > 0) {
9616c94880fSSascha Wildner 		while (MIDIQ_AVAIL(scp->out_q) == 0) {
9626c94880fSSascha Wildner 			retval = EWOULDBLOCK;
9636c94880fSSascha Wildner 			if (scp->fflags & O_NONBLOCK)
9646c94880fSSascha Wildner 				goto err0;
9656c94880fSSascha Wildner 			if (ioflag & O_NONBLOCK)
9666c94880fSSascha Wildner 				goto err0;
967*af11d9eeSSascha Wildner 			SEQ_DEBUG(8, kprintf("seq_write cvwait\n"));
9686c94880fSSascha Wildner 
9696c94880fSSascha Wildner 			scp->playing = 1;
9706c94880fSSascha Wildner 			cv_broadcast(&scp->out_cv);
9716c94880fSSascha Wildner 			cv_broadcast(&scp->state_cv);
9726c94880fSSascha Wildner 
9736c94880fSSascha Wildner 			retval = cv_wait_sig(&scp->out_cv, &scp->seq_lock);
9746c94880fSSascha Wildner 			/*
9756c94880fSSascha Wildner 		         * We slept, maybe things have changed since last
9766c94880fSSascha Wildner 		         * dying check
9776c94880fSSascha Wildner 		         */
9786c94880fSSascha Wildner 			if (retval == EINTR)
9796c94880fSSascha Wildner 				goto err0;
9806c94880fSSascha Wildner #if 0
9816c94880fSSascha Wildner 			/*
9826c94880fSSascha Wildner 		         * Useless test
9836c94880fSSascha Wildner 		         */
9846c94880fSSascha Wildner 			if (scp != i_dev->si_drv1)
9856c94880fSSascha Wildner 				retval = ENXIO;
9866c94880fSSascha Wildner #endif
9876c94880fSSascha Wildner 		}
9886c94880fSSascha Wildner 
9896c94880fSSascha Wildner 		used = MIN(uio->uio_resid, 4);
9906c94880fSSascha Wildner 
991*af11d9eeSSascha Wildner 		SEQ_DEBUG(8, kprintf("seqout: resid %zd len %jd avail %jd\n",
9926c94880fSSascha Wildner 		    uio->uio_resid, (intmax_t)MIDIQ_LEN(scp->out_q),
9936c94880fSSascha Wildner 		    (intmax_t)MIDIQ_AVAIL(scp->out_q)));
9946c94880fSSascha Wildner 
9956c94880fSSascha Wildner 		if (used != 4) {
9966c94880fSSascha Wildner 			retval = ENXIO;
9976c94880fSSascha Wildner 			goto err0;
9986c94880fSSascha Wildner 		}
9996c94880fSSascha Wildner 		retval = uiomove(event, used, uio);
10006c94880fSSascha Wildner 		if (retval)
10016c94880fSSascha Wildner 			goto err0;
10026c94880fSSascha Wildner 
10036c94880fSSascha Wildner 		ev_code = event[0];
1004*af11d9eeSSascha Wildner 		SEQ_DEBUG(8, kprintf("seq_write: unit %d, event %s.\n",
10056c94880fSSascha Wildner 		    scp->unit, midi_cmdname(ev_code, cmdtab_seqevent)));
10066c94880fSSascha Wildner 
10076c94880fSSascha Wildner 		/* Have a look at the event code. */
10086c94880fSSascha Wildner 		if (ev_code == SEQ_FULLSIZE) {
10096c94880fSSascha Wildner 
10106c94880fSSascha Wildner 			/*
10116c94880fSSascha Wildner 			 * TODO: restore code for SEQ_FULLSIZE
10126c94880fSSascha Wildner 			 */
10136c94880fSSascha Wildner #if 0
10146c94880fSSascha Wildner 			/*
10156c94880fSSascha Wildner 			 * A long event, these are the patches/samples for a
10166c94880fSSascha Wildner 			 * synthesizer.
10176c94880fSSascha Wildner 			 */
10186c94880fSSascha Wildner 			midiunit = *(u_short *)&event[2];
1019*af11d9eeSSascha Wildner 			lockmgr(&sd->seq_lock, LK_EXCLUSIVE);
10206c94880fSSascha Wildner 			ret = lookup_mididev(scp, midiunit, LOOKUP_OPEN, &md);
1021*af11d9eeSSascha Wildner 			lockmgr(&sd->seq_lock, LK_RELEASE);
10226c94880fSSascha Wildner 			if (ret != 0)
10236c94880fSSascha Wildner 				return (ret);
10246c94880fSSascha Wildner 
1025*af11d9eeSSascha Wildner 			SEQ_DEBUG(kprintf("seq_write: loading a patch to the unit %d.\n", midiunit));
10266c94880fSSascha Wildner 
10276c94880fSSascha Wildner 			ret = md->synth.loadpatch(md, *(short *)&event[0], buf,
10286c94880fSSascha Wildner 			    p + 4, count, 0);
10296c94880fSSascha Wildner 			return (ret);
10306c94880fSSascha Wildner #else
10316c94880fSSascha Wildner 			/*
10326c94880fSSascha Wildner 			 * For now, just flush the darn buffer
10336c94880fSSascha Wildner 			 */
10346c94880fSSascha Wildner 			SEQ_DEBUG(2,
1035*af11d9eeSSascha Wildner 			   kprintf("seq_write: SEQ_FULLSIZE flusing buffer.\n"));
10366c94880fSSascha Wildner 			while (uio->uio_resid > 0) {
10376c94880fSSascha Wildner 				retval = uiomove(event, EV_SZ, uio);
10386c94880fSSascha Wildner 				if (retval)
10396c94880fSSascha Wildner 					goto err0;
10406c94880fSSascha Wildner 
10416c94880fSSascha Wildner 			}
10426c94880fSSascha Wildner 			retval = 0;
10436c94880fSSascha Wildner 			goto err0;
10446c94880fSSascha Wildner #endif
10456c94880fSSascha Wildner 		}
10466c94880fSSascha Wildner 		retval = EINVAL;
10476c94880fSSascha Wildner 		if (ev_code >= 128) {
10486c94880fSSascha Wildner 
10496c94880fSSascha Wildner 			/*
10506c94880fSSascha Wildner 			 * Some sort of an extended event. The size is eight
10516c94880fSSascha Wildner 			 * bytes. scoop extra info.
10526c94880fSSascha Wildner 			 */
10536c94880fSSascha Wildner 			if (scp->music && ev_code == SEQ_EXTENDED) {
1054*af11d9eeSSascha Wildner 				SEQ_DEBUG(2, kprintf("seq_write: invalid level two event %x.\n", ev_code));
10556c94880fSSascha Wildner 				goto err0;
10566c94880fSSascha Wildner 			}
10576c94880fSSascha Wildner 			if (uiomove((caddr_t)&event[4], 4, uio)) {
10586c94880fSSascha Wildner 				SEQ_DEBUG(2,
1059*af11d9eeSSascha Wildner 				   kprintf("seq_write: user memory mangled?\n"));
10606c94880fSSascha Wildner 				goto err0;
10616c94880fSSascha Wildner 			}
10626c94880fSSascha Wildner 		} else {
10636c94880fSSascha Wildner 			/*
10646c94880fSSascha Wildner 			 * Size four event.
10656c94880fSSascha Wildner 			 */
10666c94880fSSascha Wildner 			if (scp->music) {
1067*af11d9eeSSascha Wildner 				SEQ_DEBUG(2, kprintf("seq_write: four byte event in music mode.\n"));
10686c94880fSSascha Wildner 				goto err0;
10696c94880fSSascha Wildner 			}
10706c94880fSSascha Wildner 		}
10716c94880fSSascha Wildner 		if (ev_code == SEQ_MIDIPUTC) {
10726c94880fSSascha Wildner 			/*
10736c94880fSSascha Wildner 			 * TODO: event[2] is unit number to receive char.
10746c94880fSSascha Wildner 			 * Range check it.
10756c94880fSSascha Wildner 			 */
10766c94880fSSascha Wildner 		}
10776c94880fSSascha Wildner 		if (scp->music) {
10786c94880fSSascha Wildner #ifdef not_ever_ever
10796c94880fSSascha Wildner 			if (event[0] == EV_TIMING &&
10806c94880fSSascha Wildner 			    (event[1] == TMR_START || event[1] == TMR_STOP)) {
10816c94880fSSascha Wildner 				/*
10826c94880fSSascha Wildner 			         * For now, try to make midimoutain work by
10836c94880fSSascha Wildner 			         * forcing these events to be processed
10846c94880fSSascha Wildner 				 * immediatly.
10856c94880fSSascha Wildner 			         */
10866c94880fSSascha Wildner 				seq_processevent(scp, event);
10876c94880fSSascha Wildner 			} else
10886c94880fSSascha Wildner 				MIDIQ_ENQ(scp->out_q, event, EV_SZ);
10896c94880fSSascha Wildner #else
10906c94880fSSascha Wildner 			MIDIQ_ENQ(scp->out_q, event, EV_SZ);
10916c94880fSSascha Wildner #endif
10926c94880fSSascha Wildner 		} else {
10936c94880fSSascha Wildner 			if (seq_convertold(event, newevent) > 0)
10946c94880fSSascha Wildner 				MIDIQ_ENQ(scp->out_q, newevent, EV_SZ);
10956c94880fSSascha Wildner #if 0
10966c94880fSSascha Wildner 			else
10976c94880fSSascha Wildner 				goto err0;
10986c94880fSSascha Wildner #endif
10996c94880fSSascha Wildner 		}
11006c94880fSSascha Wildner 
11016c94880fSSascha Wildner 	}
11026c94880fSSascha Wildner 
11036c94880fSSascha Wildner 	scp->playing = 1;
11046c94880fSSascha Wildner 	cv_broadcast(&scp->state_cv);
11056c94880fSSascha Wildner 	cv_broadcast(&scp->out_cv);
11066c94880fSSascha Wildner 
11076c94880fSSascha Wildner 	retval = 0;
11086c94880fSSascha Wildner 
11096c94880fSSascha Wildner err0:
11106c94880fSSascha Wildner 	SEQ_DEBUG(6,
1111*af11d9eeSSascha Wildner 	    kprintf("seq_write done: leftover buffer length %zd retval %d\n",
11126c94880fSSascha Wildner 	    uio->uio_resid, retval));
1113*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
11146c94880fSSascha Wildner 	return retval;
11156c94880fSSascha Wildner }
11166c94880fSSascha Wildner 
11176c94880fSSascha Wildner int
seq_ioctl(struct dev_ioctl_args * ap)1118*af11d9eeSSascha Wildner seq_ioctl(struct dev_ioctl_args *ap)
11196c94880fSSascha Wildner {
1120*af11d9eeSSascha Wildner 	cdev_t i_dev = ap->a_head.a_dev;
1121*af11d9eeSSascha Wildner 	u_long cmd = ap->a_cmd;
1122*af11d9eeSSascha Wildner 	caddr_t arg = ap->a_data;
1123*af11d9eeSSascha Wildner 	int mode = ap->a_fflag;
11246c94880fSSascha Wildner 	int midiunit, ret, tmp;
11256c94880fSSascha Wildner 	struct seq_softc *scp = i_dev->si_drv1;
11266c94880fSSascha Wildner 	struct synth_info *synthinfo;
11276c94880fSSascha Wildner 	struct midi_info *midiinfo;
11286c94880fSSascha Wildner 	u_char event[EV_SZ];
11296c94880fSSascha Wildner 	u_char newevent[EV_SZ];
11306c94880fSSascha Wildner 
11316c94880fSSascha Wildner 	kobj_t md;
11326c94880fSSascha Wildner 
11336c94880fSSascha Wildner 	/*
11346c94880fSSascha Wildner 	 * struct snd_size *sndsize;
11356c94880fSSascha Wildner 	 */
11366c94880fSSascha Wildner 
11376c94880fSSascha Wildner 	if (scp == NULL)
11386c94880fSSascha Wildner 		return ENXIO;
11396c94880fSSascha Wildner 
1140*af11d9eeSSascha Wildner 	SEQ_DEBUG(6, kprintf("seq_ioctl: unit %d, cmd %s.\n",
11416c94880fSSascha Wildner 	    scp->unit, midi_cmdname(cmd, cmdtab_seqioctl)));
11426c94880fSSascha Wildner 
11436c94880fSSascha Wildner 	ret = 0;
11446c94880fSSascha Wildner 
11456c94880fSSascha Wildner 	switch (cmd) {
11466c94880fSSascha Wildner 	case SNDCTL_SEQ_GETTIME:
11476c94880fSSascha Wildner 		/*
11486c94880fSSascha Wildner 		 * ioctl needed by libtse
11496c94880fSSascha Wildner 		 */
1150*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
11516c94880fSSascha Wildner 		*(int *)arg = timer_now(scp);
1152*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1153*af11d9eeSSascha Wildner 		SEQ_DEBUG(6, kprintf("seq_ioctl: gettime %d.\n", *(int *)arg));
11546c94880fSSascha Wildner 		ret = 0;
11556c94880fSSascha Wildner 		break;
11566c94880fSSascha Wildner 	case SNDCTL_TMR_METRONOME:
11576c94880fSSascha Wildner 		/* fallthrough */
11586c94880fSSascha Wildner 	case SNDCTL_TMR_SOURCE:
11596c94880fSSascha Wildner 		/*
11606c94880fSSascha Wildner 		 * Not implemented
11616c94880fSSascha Wildner 		 */
11626c94880fSSascha Wildner 		ret = 0;
11636c94880fSSascha Wildner 		break;
11646c94880fSSascha Wildner 	case SNDCTL_TMR_TEMPO:
11656c94880fSSascha Wildner 		event[1] = TMR_TEMPO;
11666c94880fSSascha Wildner 		event[4] = *(int *)arg & 0xFF;
11676c94880fSSascha Wildner 		event[5] = (*(int *)arg >> 8) & 0xFF;
11686c94880fSSascha Wildner 		event[6] = (*(int *)arg >> 16) & 0xFF;
11696c94880fSSascha Wildner 		event[7] = (*(int *)arg >> 24) & 0xFF;
11706c94880fSSascha Wildner 		goto timerevent;
11716c94880fSSascha Wildner 	case SNDCTL_TMR_TIMEBASE:
11726c94880fSSascha Wildner 		event[1] = TMR_TIMERBASE;
11736c94880fSSascha Wildner 		event[4] = *(int *)arg & 0xFF;
11746c94880fSSascha Wildner 		event[5] = (*(int *)arg >> 8) & 0xFF;
11756c94880fSSascha Wildner 		event[6] = (*(int *)arg >> 16) & 0xFF;
11766c94880fSSascha Wildner 		event[7] = (*(int *)arg >> 24) & 0xFF;
11776c94880fSSascha Wildner 		goto timerevent;
11786c94880fSSascha Wildner 	case SNDCTL_TMR_START:
11796c94880fSSascha Wildner 		event[1] = TMR_START;
11806c94880fSSascha Wildner 		goto timerevent;
11816c94880fSSascha Wildner 	case SNDCTL_TMR_STOP:
11826c94880fSSascha Wildner 		event[1] = TMR_STOP;
11836c94880fSSascha Wildner 		goto timerevent;
11846c94880fSSascha Wildner 	case SNDCTL_TMR_CONTINUE:
11856c94880fSSascha Wildner 		event[1] = TMR_CONTINUE;
11866c94880fSSascha Wildner timerevent:
11876c94880fSSascha Wildner 		event[0] = EV_TIMING;
1188*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
11896c94880fSSascha Wildner 		if (!scp->music) {
11906c94880fSSascha Wildner 			ret = EINVAL;
1191*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_RELEASE);
11926c94880fSSascha Wildner 			break;
11936c94880fSSascha Wildner 		}
11946c94880fSSascha Wildner 		seq_processevent(scp, event);
1195*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
11966c94880fSSascha Wildner 		break;
11976c94880fSSascha Wildner 	case SNDCTL_TMR_SELECT:
11986c94880fSSascha Wildner 		SEQ_DEBUG(2,
1199*af11d9eeSSascha Wildner 		    kprintf("seq_ioctl: SNDCTL_TMR_SELECT not supported\n"));
12006c94880fSSascha Wildner 		ret = EINVAL;
12016c94880fSSascha Wildner 		break;
12026c94880fSSascha Wildner 	case SNDCTL_SEQ_SYNC:
12036c94880fSSascha Wildner 		if (mode == O_RDONLY) {
12046c94880fSSascha Wildner 			ret = 0;
12056c94880fSSascha Wildner 			break;
12066c94880fSSascha Wildner 		}
1207*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12086c94880fSSascha Wildner 		ret = seq_sync(scp);
1209*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
12106c94880fSSascha Wildner 		break;
12116c94880fSSascha Wildner 	case SNDCTL_SEQ_PANIC:
12126c94880fSSascha Wildner 		/* fallthrough */
12136c94880fSSascha Wildner 	case SNDCTL_SEQ_RESET:
12146c94880fSSascha Wildner 		/*
12156c94880fSSascha Wildner 		 * SNDCTL_SEQ_PANIC == SNDCTL_SEQ_RESET
12166c94880fSSascha Wildner 		 */
1217*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12186c94880fSSascha Wildner 		seq_reset(scp);
1219*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
12206c94880fSSascha Wildner 		ret = 0;
12216c94880fSSascha Wildner 		break;
12226c94880fSSascha Wildner 	case SNDCTL_SEQ_TESTMIDI:
1223*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12246c94880fSSascha Wildner 		/*
12256c94880fSSascha Wildner 		 * TODO: SNDCTL_SEQ_TESTMIDI now means "can I write to the
12266c94880fSSascha Wildner 		 * device?".
12276c94880fSSascha Wildner 		 */
1228*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
12296c94880fSSascha Wildner 		break;
12306c94880fSSascha Wildner #if 0
12316c94880fSSascha Wildner 	case SNDCTL_SEQ_GETINCOUNT:
12326c94880fSSascha Wildner 		if (mode == O_WRONLY)
12336c94880fSSascha Wildner 			*(int *)arg = 0;
12346c94880fSSascha Wildner 		else {
1235*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12366c94880fSSascha Wildner 			*(int *)arg = scp->in_q.rl;
1237*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_RELEASE);
1238*af11d9eeSSascha Wildner 			SEQ_DEBUG(kprintf("seq_ioctl: incount %d.\n",
12396c94880fSSascha Wildner 			    *(int *)arg));
12406c94880fSSascha Wildner 		}
12416c94880fSSascha Wildner 		ret = 0;
12426c94880fSSascha Wildner 		break;
12436c94880fSSascha Wildner 	case SNDCTL_SEQ_GETOUTCOUNT:
12446c94880fSSascha Wildner 		if (mode == O_RDONLY)
12456c94880fSSascha Wildner 			*(int *)arg = 0;
12466c94880fSSascha Wildner 		else {
1247*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12486c94880fSSascha Wildner 			*(int *)arg = scp->out_q.fl;
1249*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_RELEASE);
1250*af11d9eeSSascha Wildner 			SEQ_DEBUG(kprintf("seq_ioctl: outcount %d.\n",
12516c94880fSSascha Wildner 			    *(int *)arg));
12526c94880fSSascha Wildner 		}
12536c94880fSSascha Wildner 		ret = 0;
12546c94880fSSascha Wildner 		break;
12556c94880fSSascha Wildner #endif
12566c94880fSSascha Wildner 	case SNDCTL_SEQ_CTRLRATE:
12576c94880fSSascha Wildner 		if (*(int *)arg != 0) {
12586c94880fSSascha Wildner 			ret = EINVAL;
12596c94880fSSascha Wildner 			break;
12606c94880fSSascha Wildner 		}
1261*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12626c94880fSSascha Wildner 		*(int *)arg = scp->timerbase;
1263*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1264*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_ioctl: ctrlrate %d.\n", *(int *)arg));
12656c94880fSSascha Wildner 		ret = 0;
12666c94880fSSascha Wildner 		break;
12676c94880fSSascha Wildner 		/*
12686c94880fSSascha Wildner 		 * TODO: ioctl SNDCTL_SEQ_RESETSAMPLES
12696c94880fSSascha Wildner 		 */
12706c94880fSSascha Wildner #if 0
12716c94880fSSascha Wildner 	case SNDCTL_SEQ_RESETSAMPLES:
1272*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12736c94880fSSascha Wildner 		ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
1274*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
12756c94880fSSascha Wildner 		if (ret != 0)
12766c94880fSSascha Wildner 			break;
12776c94880fSSascha Wildner 		ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
12786c94880fSSascha Wildner 		    SND_DEV_MIDIN), cmd, arg, mode, td);
12796c94880fSSascha Wildner 		break;
12806c94880fSSascha Wildner #endif
12816c94880fSSascha Wildner 	case SNDCTL_SEQ_NRSYNTHS:
1282*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12836c94880fSSascha Wildner 		*(int *)arg = scp->midi_number;
1284*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1285*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_ioctl: synths %d.\n", *(int *)arg));
12866c94880fSSascha Wildner 		ret = 0;
12876c94880fSSascha Wildner 		break;
12886c94880fSSascha Wildner 	case SNDCTL_SEQ_NRMIDIS:
1289*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
12906c94880fSSascha Wildner 		if (scp->music)
12916c94880fSSascha Wildner 			*(int *)arg = 0;
12926c94880fSSascha Wildner 		else {
12936c94880fSSascha Wildner 			/*
12946c94880fSSascha Wildner 		         * TODO: count the numbder of devices that can WRITERAW
12956c94880fSSascha Wildner 		         */
12966c94880fSSascha Wildner 			*(int *)arg = scp->midi_number;
12976c94880fSSascha Wildner 		}
1298*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1299*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_ioctl: midis %d.\n", *(int *)arg));
13006c94880fSSascha Wildner 		ret = 0;
13016c94880fSSascha Wildner 		break;
13026c94880fSSascha Wildner 		/*
13036c94880fSSascha Wildner 		 * TODO: ioctl SNDCTL_SYNTH_MEMAVL
13046c94880fSSascha Wildner 		 */
13056c94880fSSascha Wildner #if 0
13066c94880fSSascha Wildner 	case SNDCTL_SYNTH_MEMAVL:
1307*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13086c94880fSSascha Wildner 		ret = lookup_mididev(scp, *(int *)arg, LOOKUP_OPEN, &md);
1309*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
13106c94880fSSascha Wildner 		if (ret != 0)
13116c94880fSSascha Wildner 			break;
13126c94880fSSascha Wildner 		ret = midi_ioctl(MIDIMKDEV(major(i_dev), *(int *)arg,
13136c94880fSSascha Wildner 		    SND_DEV_MIDIN), cmd, arg, mode, td);
13146c94880fSSascha Wildner 		break;
13156c94880fSSascha Wildner #endif
13166c94880fSSascha Wildner 	case SNDCTL_SEQ_OUTOFBAND:
13176c94880fSSascha Wildner 		for (ret = 0; ret < EV_SZ; ret++)
13186c94880fSSascha Wildner 			event[ret] = (u_char)arg[0];
13196c94880fSSascha Wildner 
1320*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13216c94880fSSascha Wildner 		if (scp->music)
13226c94880fSSascha Wildner 			ret = seq_processevent(scp, event);
13236c94880fSSascha Wildner 		else {
13246c94880fSSascha Wildner 			if (seq_convertold(event, newevent) > 0)
13256c94880fSSascha Wildner 				ret = seq_processevent(scp, newevent);
13266c94880fSSascha Wildner 			else
13276c94880fSSascha Wildner 				ret = EINVAL;
13286c94880fSSascha Wildner 		}
1329*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
13306c94880fSSascha Wildner 		break;
13316c94880fSSascha Wildner 	case SNDCTL_SYNTH_INFO:
13326c94880fSSascha Wildner 		synthinfo = (struct synth_info *)arg;
13336c94880fSSascha Wildner 		midiunit = synthinfo->device;
1334*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13356c94880fSSascha Wildner 		if (seq_fetch_mid(scp, midiunit, &md) == 0) {
13366c94880fSSascha Wildner 			bzero(synthinfo, sizeof(*synthinfo));
13376c94880fSSascha Wildner 			synthinfo->name[0] = 'f';
13386c94880fSSascha Wildner 			synthinfo->name[1] = 'a';
13396c94880fSSascha Wildner 			synthinfo->name[2] = 'k';
13406c94880fSSascha Wildner 			synthinfo->name[3] = 'e';
13416c94880fSSascha Wildner 			synthinfo->name[4] = 's';
13426c94880fSSascha Wildner 			synthinfo->name[5] = 'y';
13436c94880fSSascha Wildner 			synthinfo->name[6] = 'n';
13446c94880fSSascha Wildner 			synthinfo->name[7] = 't';
13456c94880fSSascha Wildner 			synthinfo->name[8] = 'h';
13466c94880fSSascha Wildner 			synthinfo->device = midiunit;
13476c94880fSSascha Wildner 			synthinfo->synth_type = SYNTH_TYPE_MIDI;
13486c94880fSSascha Wildner 			synthinfo->capabilities = scp->midi_flags[midiunit];
13496c94880fSSascha Wildner 			ret = 0;
13506c94880fSSascha Wildner 		} else
13516c94880fSSascha Wildner 			ret = EINVAL;
1352*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
13536c94880fSSascha Wildner 		break;
13546c94880fSSascha Wildner 	case SNDCTL_MIDI_INFO:
13556c94880fSSascha Wildner 		midiinfo = (struct midi_info *)arg;
13566c94880fSSascha Wildner 		midiunit = midiinfo->device;
1357*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13586c94880fSSascha Wildner 		if (seq_fetch_mid(scp, midiunit, &md) == 0) {
13596c94880fSSascha Wildner 			bzero(midiinfo, sizeof(*midiinfo));
13606c94880fSSascha Wildner 			midiinfo->name[0] = 'f';
13616c94880fSSascha Wildner 			midiinfo->name[1] = 'a';
13626c94880fSSascha Wildner 			midiinfo->name[2] = 'k';
13636c94880fSSascha Wildner 			midiinfo->name[3] = 'e';
13646c94880fSSascha Wildner 			midiinfo->name[4] = 'm';
13656c94880fSSascha Wildner 			midiinfo->name[5] = 'i';
13666c94880fSSascha Wildner 			midiinfo->name[6] = 'd';
13676c94880fSSascha Wildner 			midiinfo->name[7] = 'i';
13686c94880fSSascha Wildner 			midiinfo->device = midiunit;
13696c94880fSSascha Wildner 			midiinfo->capabilities = scp->midi_flags[midiunit];
13706c94880fSSascha Wildner 			/*
13716c94880fSSascha Wildner 		         * TODO: What devtype?
13726c94880fSSascha Wildner 		         */
13736c94880fSSascha Wildner 			midiinfo->dev_type = 0x01;
13746c94880fSSascha Wildner 			ret = 0;
13756c94880fSSascha Wildner 		} else
13766c94880fSSascha Wildner 			ret = EINVAL;
1377*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
13786c94880fSSascha Wildner 		break;
13796c94880fSSascha Wildner 	case SNDCTL_SEQ_THRESHOLD:
1380*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13816c94880fSSascha Wildner 		RANGE(*(int *)arg, 1, MIDIQ_SIZE(scp->out_q) - 1);
13826c94880fSSascha Wildner 		scp->out_water = *(int *)arg;
1383*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1384*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_ioctl: water %d.\n", *(int *)arg));
13856c94880fSSascha Wildner 		ret = 0;
13866c94880fSSascha Wildner 		break;
13876c94880fSSascha Wildner 	case SNDCTL_MIDI_PRETIME:
13886c94880fSSascha Wildner 		tmp = *(int *)arg;
13896c94880fSSascha Wildner 		if (tmp < 0)
13906c94880fSSascha Wildner 			tmp = 0;
1391*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
13926c94880fSSascha Wildner 		scp->pre_event_timeout = (hz * tmp) / 10;
13936c94880fSSascha Wildner 		*(int *)arg = scp->pre_event_timeout;
1394*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
1395*af11d9eeSSascha Wildner 		SEQ_DEBUG(3, kprintf("seq_ioctl: pretime %d.\n", *(int *)arg));
13966c94880fSSascha Wildner 		ret = 0;
13976c94880fSSascha Wildner 		break;
13986c94880fSSascha Wildner 	case SNDCTL_FM_4OP_ENABLE:
13996c94880fSSascha Wildner 	case SNDCTL_PMGR_IFACE:
14006c94880fSSascha Wildner 	case SNDCTL_PMGR_ACCESS:
14016c94880fSSascha Wildner 		/*
14026c94880fSSascha Wildner 		 * Patch manager and fm are ded, ded, ded.
14036c94880fSSascha Wildner 		 */
14046c94880fSSascha Wildner 		/* fallthrough */
14056c94880fSSascha Wildner 	default:
14066c94880fSSascha Wildner 		/*
14076c94880fSSascha Wildner 		 * TODO: Consider ioctl default case.
14086c94880fSSascha Wildner 		 * Old code used to
14096c94880fSSascha Wildner 		 * if ((scp->fflags & O_ACCMODE) == FREAD) {
14106c94880fSSascha Wildner 		 *	ret = EIO;
14116c94880fSSascha Wildner 		 *	break;
14126c94880fSSascha Wildner 		 * }
14136c94880fSSascha Wildner 		 * Then pass on the ioctl to device 0
14146c94880fSSascha Wildner 		 */
14156c94880fSSascha Wildner 		SEQ_DEBUG(2,
1416*af11d9eeSSascha Wildner 		    kprintf("seq_ioctl: unsupported IOCTL %ld.\n", cmd));
14176c94880fSSascha Wildner 		ret = EINVAL;
14186c94880fSSascha Wildner 		break;
14196c94880fSSascha Wildner 	}
14206c94880fSSascha Wildner 
14216c94880fSSascha Wildner 	return ret;
14226c94880fSSascha Wildner }
14236c94880fSSascha Wildner 
14246c94880fSSascha Wildner int
seq_kqfilter(struct dev_kqfilter_args * ap)1425*af11d9eeSSascha Wildner seq_kqfilter(struct dev_kqfilter_args *ap)
14266c94880fSSascha Wildner {
1427*af11d9eeSSascha Wildner 	cdev_t dev = ap->a_head.a_dev;
1428*af11d9eeSSascha Wildner 	struct knote *kn = ap->a_kn;
1429*af11d9eeSSascha Wildner 	struct seq_softc *scp;
1430*af11d9eeSSascha Wildner 	struct klist *klist;
14316c94880fSSascha Wildner 
1432*af11d9eeSSascha Wildner 	ap->a_result = 0;
1433*af11d9eeSSascha Wildner 	scp = dev->si_drv1;
14346c94880fSSascha Wildner 
1435*af11d9eeSSascha Wildner 	switch (kn->kn_filter) {
1436*af11d9eeSSascha Wildner 	case EVFILT_READ:
1437*af11d9eeSSascha Wildner 		kn->kn_fop = &seq_read_filterops;
1438*af11d9eeSSascha Wildner 		kn->kn_hook = (caddr_t)scp;
1439*af11d9eeSSascha Wildner 		klist = &scp->in_kq.ki_note;
1440*af11d9eeSSascha Wildner 		break;
1441*af11d9eeSSascha Wildner 	case EVFILT_WRITE:
1442*af11d9eeSSascha Wildner 		kn->kn_fop = &seq_write_filterops;
1443*af11d9eeSSascha Wildner 		kn->kn_hook = (caddr_t)scp;
1444*af11d9eeSSascha Wildner 		klist = &scp->out_kq.ki_note;
1445*af11d9eeSSascha Wildner 		break;
1446*af11d9eeSSascha Wildner 	default:
1447*af11d9eeSSascha Wildner 		ap->a_result = EOPNOTSUPP;
1448*af11d9eeSSascha Wildner 		return (0);
1449*af11d9eeSSascha Wildner 	}
14506c94880fSSascha Wildner 
1451*af11d9eeSSascha Wildner 	knote_insert(klist, kn);
1452*af11d9eeSSascha Wildner 
1453*af11d9eeSSascha Wildner 	return(0);
1454*af11d9eeSSascha Wildner }
1455*af11d9eeSSascha Wildner 
1456*af11d9eeSSascha Wildner static void
seq_filter_detach(struct knote * kn)1457*af11d9eeSSascha Wildner seq_filter_detach(struct knote *kn)
1458*af11d9eeSSascha Wildner {
1459*af11d9eeSSascha Wildner 	struct seq_softc *scp = (struct seq_softc *)kn->kn_hook;
1460*af11d9eeSSascha Wildner 	struct klist *in_klist = &scp->in_kq.ki_note;
1461*af11d9eeSSascha Wildner 	struct klist *out_klist = &scp->out_kq.ki_note;
1462*af11d9eeSSascha Wildner 
1463*af11d9eeSSascha Wildner 	knote_remove(in_klist, kn);
1464*af11d9eeSSascha Wildner 	knote_remove(out_klist, kn);
1465*af11d9eeSSascha Wildner }
1466*af11d9eeSSascha Wildner 
1467*af11d9eeSSascha Wildner static int
seq_filter_read(struct knote * kn,long hint)1468*af11d9eeSSascha Wildner seq_filter_read(struct knote *kn, long hint)
1469*af11d9eeSSascha Wildner {
1470*af11d9eeSSascha Wildner 	struct seq_softc *scp = (struct seq_softc *)kn->kn_hook;
1471*af11d9eeSSascha Wildner 	int ready = 0;
1472*af11d9eeSSascha Wildner 	int lim;
1473*af11d9eeSSascha Wildner 
1474*af11d9eeSSascha Wildner 	SEQ_DEBUG(3, kprintf("seq_filter_read: unit %d.\n", scp->unit));
1475*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_filter_read: unit %d.\n", scp->unit));
1476*af11d9eeSSascha Wildner 
1477*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
14786c94880fSSascha Wildner 
14796c94880fSSascha Wildner 	/* Look up the apropriate queue and select it. */
1480*af11d9eeSSascha Wildner 
1481*af11d9eeSSascha Wildner 	/* TODO: Start recording. */
1482*af11d9eeSSascha Wildner 
1483*af11d9eeSSascha Wildner 	/* Find out the boundary. */
1484*af11d9eeSSascha Wildner 	lim = 1;
1485*af11d9eeSSascha Wildner 	if (MIDIQ_LEN(scp->in_q) >= lim) {
1486*af11d9eeSSascha Wildner 		/* We can read now. */
1487*af11d9eeSSascha Wildner 		ready = 1;
1488*af11d9eeSSascha Wildner 	}
1489*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
1490*af11d9eeSSascha Wildner 
1491*af11d9eeSSascha Wildner 	return (ready);
1492*af11d9eeSSascha Wildner }
1493*af11d9eeSSascha Wildner 
1494*af11d9eeSSascha Wildner static int
seq_filter_write(struct knote * kn,long hint)1495*af11d9eeSSascha Wildner seq_filter_write(struct knote *kn, long hint)
1496*af11d9eeSSascha Wildner {
1497*af11d9eeSSascha Wildner 	struct seq_softc *scp = (struct seq_softc *)kn->kn_hook;
1498*af11d9eeSSascha Wildner 	int ready = 0;
1499*af11d9eeSSascha Wildner 	int lim;
1500*af11d9eeSSascha Wildner 
1501*af11d9eeSSascha Wildner 	SEQ_DEBUG(3, kprintf("seq_filter_write: unit %d.\n", scp->unit));
1502*af11d9eeSSascha Wildner 	SEQ_DEBUG(1, kprintf("seq_filter_write: unit %d.\n", scp->unit));
1503*af11d9eeSSascha Wildner 
1504*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
1505*af11d9eeSSascha Wildner 
1506*af11d9eeSSascha Wildner 	/* Look up the apropriate queue and select it. */
1507*af11d9eeSSascha Wildner 
15086c94880fSSascha Wildner 	/* Start playing. */
15096c94880fSSascha Wildner 	scp->playing = 1;
15106c94880fSSascha Wildner 	cv_broadcast(&scp->state_cv);
15116c94880fSSascha Wildner 	cv_broadcast(&scp->out_cv);
15126c94880fSSascha Wildner 
15136c94880fSSascha Wildner 	lim = scp->out_water;
15146c94880fSSascha Wildner 
1515*af11d9eeSSascha Wildner 	if (MIDIQ_AVAIL(scp->out_q) >= lim) {
15166c94880fSSascha Wildner 		/* We can write now. */
1517*af11d9eeSSascha Wildner 		ready = 1;
15186c94880fSSascha Wildner 	}
1519*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
15206c94880fSSascha Wildner 
1521*af11d9eeSSascha Wildner 	return (ready);
15226c94880fSSascha Wildner }
15236c94880fSSascha Wildner 
15246c94880fSSascha Wildner #if 0
15256c94880fSSascha Wildner static void
15266c94880fSSascha Wildner sein_qtr(void *p, void /* mididev_info */ *md)
15276c94880fSSascha Wildner {
15286c94880fSSascha Wildner 	struct seq_softc *scp;
15296c94880fSSascha Wildner 
15306c94880fSSascha Wildner 	scp = (struct seq_softc *)p;
15316c94880fSSascha Wildner 
1532*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
15336c94880fSSascha Wildner 
15346c94880fSSascha Wildner 	/* Restart playing if we have the data to output. */
15356c94880fSSascha Wildner 	if (scp->queueout_pending)
15366c94880fSSascha Wildner 		seq_callback(scp, SEQ_CB_START | SEQ_CB_WR);
15376c94880fSSascha Wildner 	/* Check the midi device if we are reading. */
15386c94880fSSascha Wildner 	if ((scp->flags & SEQ_F_READING) != 0)
15396c94880fSSascha Wildner 		seq_midiinput(scp, md);
15406c94880fSSascha Wildner 
1541*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
15426c94880fSSascha Wildner }
15436c94880fSSascha Wildner 
15446c94880fSSascha Wildner #endif
15456c94880fSSascha Wildner /*
15466c94880fSSascha Wildner  * seq_convertold
15476c94880fSSascha Wildner  * Was the old playevent.  Use this to convert and old
15486c94880fSSascha Wildner  * style /dev/sequencer event to a /dev/music event
15496c94880fSSascha Wildner  */
15506c94880fSSascha Wildner static int
seq_convertold(u_char * event,u_char * out)15516c94880fSSascha Wildner seq_convertold(u_char *event, u_char *out)
15526c94880fSSascha Wildner {
15536c94880fSSascha Wildner 	int used;
15546c94880fSSascha Wildner 	u_char dev, chn, note, vel;
15556c94880fSSascha Wildner 
15566c94880fSSascha Wildner 	out[0] = out[1] = out[2] = out[3] = out[4] = out[5] = out[6] =
15576c94880fSSascha Wildner 	    out[7] = 0;
15586c94880fSSascha Wildner 
15596c94880fSSascha Wildner 	dev = 0;
15606c94880fSSascha Wildner 	chn = event[1];
15616c94880fSSascha Wildner 	note = event[2];
15626c94880fSSascha Wildner 	vel = event[3];
15636c94880fSSascha Wildner 
15646c94880fSSascha Wildner 	used = 0;
15656c94880fSSascha Wildner 
15666c94880fSSascha Wildner restart:
15676c94880fSSascha Wildner 	/*
15686c94880fSSascha Wildner 	 * TODO: Debug statement
15696c94880fSSascha Wildner 	 */
15706c94880fSSascha Wildner 	switch (event[0]) {
15716c94880fSSascha Wildner 	case EV_TIMING:
15726c94880fSSascha Wildner 	case EV_CHN_VOICE:
15736c94880fSSascha Wildner 	case EV_CHN_COMMON:
15746c94880fSSascha Wildner 	case EV_SYSEX:
15756c94880fSSascha Wildner 	case EV_SEQ_LOCAL:
15766c94880fSSascha Wildner 		out[0] = event[0];
15776c94880fSSascha Wildner 		out[1] = event[1];
15786c94880fSSascha Wildner 		out[2] = event[2];
15796c94880fSSascha Wildner 		out[3] = event[3];
15806c94880fSSascha Wildner 		out[4] = event[4];
15816c94880fSSascha Wildner 		out[5] = event[5];
15826c94880fSSascha Wildner 		out[6] = event[6];
15836c94880fSSascha Wildner 		out[7] = event[7];
15846c94880fSSascha Wildner 		used += 8;
15856c94880fSSascha Wildner 		break;
15866c94880fSSascha Wildner 	case SEQ_NOTEOFF:
15876c94880fSSascha Wildner 		out[0] = EV_CHN_VOICE;
15886c94880fSSascha Wildner 		out[1] = dev;
15896c94880fSSascha Wildner 		out[2] = MIDI_NOTEOFF;
15906c94880fSSascha Wildner 		out[3] = chn;
15916c94880fSSascha Wildner 		out[4] = note;
15926c94880fSSascha Wildner 		out[5] = 255;
15936c94880fSSascha Wildner 		used += 4;
15946c94880fSSascha Wildner 		break;
15956c94880fSSascha Wildner 
15966c94880fSSascha Wildner 	case SEQ_NOTEON:
15976c94880fSSascha Wildner 		out[0] = EV_CHN_VOICE;
15986c94880fSSascha Wildner 		out[1] = dev;
15996c94880fSSascha Wildner 		out[2] = MIDI_NOTEON;
16006c94880fSSascha Wildner 		out[3] = chn;
16016c94880fSSascha Wildner 		out[4] = note;
16026c94880fSSascha Wildner 		out[5] = vel;
16036c94880fSSascha Wildner 		used += 4;
16046c94880fSSascha Wildner 		break;
16056c94880fSSascha Wildner 
16066c94880fSSascha Wildner 		/*
16076c94880fSSascha Wildner 		 * wait delay = (event[2] << 16) + (event[3] << 8) + event[4]
16086c94880fSSascha Wildner 		 */
16096c94880fSSascha Wildner 
16106c94880fSSascha Wildner 	case SEQ_PGMCHANGE:
16116c94880fSSascha Wildner 		out[0] = EV_CHN_COMMON;
16126c94880fSSascha Wildner 		out[1] = dev;
16136c94880fSSascha Wildner 		out[2] = MIDI_PGM_CHANGE;
16146c94880fSSascha Wildner 		out[3] = chn;
16156c94880fSSascha Wildner 		out[4] = note;
16166c94880fSSascha Wildner 		out[5] = vel;
16176c94880fSSascha Wildner 		used += 4;
16186c94880fSSascha Wildner 		break;
16196c94880fSSascha Wildner /*
16206c94880fSSascha Wildner 		out[0] = EV_TIMING;
16216c94880fSSascha Wildner 		out[1] = dev;
16226c94880fSSascha Wildner 		out[2] = MIDI_PGM_CHANGE;
16236c94880fSSascha Wildner 		out[3] = chn;
16246c94880fSSascha Wildner 		out[4] = note;
16256c94880fSSascha Wildner 		out[5] = vel;
1626*af11d9eeSSascha Wildner 		SEQ_DEBUG(4,kprintf("seq_playevent: synctimer\n"));
16276c94880fSSascha Wildner 		break;
16286c94880fSSascha Wildner */
16296c94880fSSascha Wildner 
16306c94880fSSascha Wildner 	case SEQ_MIDIPUTC:
16316c94880fSSascha Wildner 		SEQ_DEBUG(4,
1632*af11d9eeSSascha Wildner 		    kprintf("seq_playevent: put data 0x%02x, unit %d.\n",
16336c94880fSSascha Wildner 		    event[1], event[2]));
16346c94880fSSascha Wildner 		/*
16356c94880fSSascha Wildner 		 * Pass through to the midi device.
16366c94880fSSascha Wildner 		 * device = event[2]
16376c94880fSSascha Wildner 		 * data = event[1]
16386c94880fSSascha Wildner 		 */
16396c94880fSSascha Wildner 		out[0] = SEQ_MIDIPUTC;
16406c94880fSSascha Wildner 		out[1] = dev;
16416c94880fSSascha Wildner 		out[2] = chn;
16426c94880fSSascha Wildner 		used += 4;
16436c94880fSSascha Wildner 		break;
16446c94880fSSascha Wildner #ifdef notyet
16456c94880fSSascha Wildner 	case SEQ_ECHO:
16466c94880fSSascha Wildner 		/*
16476c94880fSSascha Wildner 		 * This isn't handled here yet because I don't know if I can
16486c94880fSSascha Wildner 		 * just use four bytes events.  There might be consequences
16496c94880fSSascha Wildner 		 * in the _read routing
16506c94880fSSascha Wildner 		 */
16516c94880fSSascha Wildner 		if (seq_copytoinput(scp, event, 4) == EAGAIN) {
16526c94880fSSascha Wildner 			ret = QUEUEFULL;
16536c94880fSSascha Wildner 			break;
16546c94880fSSascha Wildner 		}
16556c94880fSSascha Wildner 		ret = MORE;
16566c94880fSSascha Wildner 		break;
16576c94880fSSascha Wildner #endif
16586c94880fSSascha Wildner 	case SEQ_EXTENDED:
16596c94880fSSascha Wildner 		switch (event[1]) {
16606c94880fSSascha Wildner 		case SEQ_NOTEOFF:
16616c94880fSSascha Wildner 		case SEQ_NOTEON:
16626c94880fSSascha Wildner 		case SEQ_PGMCHANGE:
16636c94880fSSascha Wildner 			event++;
16646c94880fSSascha Wildner 			used = 4;
16656c94880fSSascha Wildner 			goto restart;
16666c94880fSSascha Wildner 			break;
16676c94880fSSascha Wildner 		case SEQ_AFTERTOUCH:
16686c94880fSSascha Wildner 			/*
16696c94880fSSascha Wildner 			 * SYNTH_AFTERTOUCH(md, event[3], event[4])
16706c94880fSSascha Wildner 			 */
16716c94880fSSascha Wildner 		case SEQ_BALANCE:
16726c94880fSSascha Wildner 			/*
16736c94880fSSascha Wildner 			 * SYNTH_PANNING(md, event[3], (char)event[4])
16746c94880fSSascha Wildner 			 */
16756c94880fSSascha Wildner 		case SEQ_CONTROLLER:
16766c94880fSSascha Wildner 			/*
16776c94880fSSascha Wildner 			 * SYNTH_CONTROLLER(md, event[3], event[4], *(short *)&event[5])
16786c94880fSSascha Wildner 			 */
16796c94880fSSascha Wildner 		case SEQ_VOLMODE:
16806c94880fSSascha Wildner 			/*
16816c94880fSSascha Wildner 			 * SYNTH_VOLUMEMETHOD(md, event[3])
16826c94880fSSascha Wildner 			 */
16836c94880fSSascha Wildner 		default:
16846c94880fSSascha Wildner 			SEQ_DEBUG(2,
1685*af11d9eeSSascha Wildner 			    kprintf("seq_convertold: SEQ_EXTENDED type %d"
16866c94880fSSascha Wildner 			    "not handled\n", event[1]));
16876c94880fSSascha Wildner 			break;
16886c94880fSSascha Wildner 		}
16896c94880fSSascha Wildner 		break;
16906c94880fSSascha Wildner 	case SEQ_WAIT:
16916c94880fSSascha Wildner 		out[0] = EV_TIMING;
16926c94880fSSascha Wildner 		out[1] = TMR_WAIT_REL;
16936c94880fSSascha Wildner 		out[4] = event[2];
16946c94880fSSascha Wildner 		out[5] = event[3];
16956c94880fSSascha Wildner 		out[6] = event[4];
16966c94880fSSascha Wildner 
1697*af11d9eeSSascha Wildner 		SEQ_DEBUG(5, kprintf("SEQ_WAIT %d",
16986c94880fSSascha Wildner 		    event[2] + (event[3] << 8) + (event[4] << 24)));
16996c94880fSSascha Wildner 
17006c94880fSSascha Wildner 		used += 4;
17016c94880fSSascha Wildner 		break;
17026c94880fSSascha Wildner 
17036c94880fSSascha Wildner 	case SEQ_ECHO:
17046c94880fSSascha Wildner 	case SEQ_SYNCTIMER:
17056c94880fSSascha Wildner 	case SEQ_PRIVATE:
17066c94880fSSascha Wildner 	default:
17076c94880fSSascha Wildner 		SEQ_DEBUG(2,
1708*af11d9eeSSascha Wildner 		  kprintf("seq_convertold: event type %d not handled %d %d %d\n",
17096c94880fSSascha Wildner 		    event[0], event[1], event[2], event[3]));
17106c94880fSSascha Wildner 		break;
17116c94880fSSascha Wildner 	}
17126c94880fSSascha Wildner 	return used;
17136c94880fSSascha Wildner }
17146c94880fSSascha Wildner 
17156c94880fSSascha Wildner /*
17166c94880fSSascha Wildner  * Writting to the sequencer buffer never blocks and drops
17176c94880fSSascha Wildner  * input which cannot be queued
17186c94880fSSascha Wildner  */
17196c94880fSSascha Wildner void
seq_copytoinput(struct seq_softc * scp,u_char * event,int len)17206c94880fSSascha Wildner seq_copytoinput(struct seq_softc *scp, u_char *event, int len)
17216c94880fSSascha Wildner {
17226c94880fSSascha Wildner 
1723*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
17246c94880fSSascha Wildner 
17256c94880fSSascha Wildner 	if (MIDIQ_AVAIL(scp->in_q) < len) {
17266c94880fSSascha Wildner 		/*
17276c94880fSSascha Wildner 	         * ENOROOM?  EINPUTDROPPED? ETOUGHLUCK?
17286c94880fSSascha Wildner 	         */
1729*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_copytoinput: queue full\n"));
17306c94880fSSascha Wildner 	} else {
17316c94880fSSascha Wildner 		MIDIQ_ENQ(scp->in_q, event, len);
1732*af11d9eeSSascha Wildner 		KNOTE(&scp->in_kq.ki_note, 0);
17336c94880fSSascha Wildner 		cv_broadcast(&scp->in_cv);
17346c94880fSSascha Wildner 	}
17356c94880fSSascha Wildner 
17366c94880fSSascha Wildner }
17376c94880fSSascha Wildner 
17386c94880fSSascha Wildner static int
seq_chnvoice(struct seq_softc * scp,kobj_t md,u_char * event)17396c94880fSSascha Wildner seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event)
17406c94880fSSascha Wildner {
17416c94880fSSascha Wildner 	int ret, voice;
17426c94880fSSascha Wildner 	u_char cmd, chn, note, parm;
17436c94880fSSascha Wildner 
17446c94880fSSascha Wildner 	ret = 0;
17456c94880fSSascha Wildner 	cmd = event[2];
17466c94880fSSascha Wildner 	chn = event[3];
17476c94880fSSascha Wildner 	note = event[4];
17486c94880fSSascha Wildner 	parm = event[5];
17496c94880fSSascha Wildner 
1750*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
17516c94880fSSascha Wildner 
1752*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_chnvoice: unit %d, dev %d, cmd %s,"
17536c94880fSSascha Wildner 	    " chn %d, note %d, parm %d.\n", scp->unit, event[1],
17546c94880fSSascha Wildner 	    midi_cmdname(cmd, cmdtab_seqcv), chn, note, parm));
17556c94880fSSascha Wildner 
17566c94880fSSascha Wildner 	voice = SYNTH_ALLOC(md, chn, note);
17576c94880fSSascha Wildner 
1758*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
17596c94880fSSascha Wildner 
17606c94880fSSascha Wildner 	switch (cmd) {
17616c94880fSSascha Wildner 	case MIDI_NOTEON:
17626c94880fSSascha Wildner 		if (note < 128 || note == 255) {
17636c94880fSSascha Wildner #if 0
17646c94880fSSascha Wildner 			if (scp->music && chn == 9) {
17656c94880fSSascha Wildner 				/*
17666c94880fSSascha Wildner 				 * This channel is a percussion. The note
17676c94880fSSascha Wildner 				 * number is the patch number.
17686c94880fSSascha Wildner 				 */
17696c94880fSSascha Wildner 				/*
1770*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_RELEASE);
17716c94880fSSascha Wildner 				if (SYNTH_SETINSTR(md, voice, 128 + note)
17726c94880fSSascha Wildner 				    == EAGAIN) {
1773*af11d9eeSSascha Wildner 					lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
17746c94880fSSascha Wildner 					return (QUEUEFULL);
17756c94880fSSascha Wildner 				}
1776*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
17776c94880fSSascha Wildner 				*/
17786c94880fSSascha Wildner 				note = 60;	/* Middle C. */
17796c94880fSSascha Wildner 			}
17806c94880fSSascha Wildner #endif
17816c94880fSSascha Wildner 			if (scp->music) {
17826c94880fSSascha Wildner 				/*
1783*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_RELEASE);
17846c94880fSSascha Wildner 				if (SYNTH_SETUPVOICE(md, voice, chn)
17856c94880fSSascha Wildner 				    == EAGAIN) {
1786*af11d9eeSSascha Wildner 					lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
17876c94880fSSascha Wildner 					return (QUEUEFULL);
17886c94880fSSascha Wildner 				}
1789*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
17906c94880fSSascha Wildner 				*/
17916c94880fSSascha Wildner 			}
17926c94880fSSascha Wildner 			SYNTH_STARTNOTE(md, voice, note, parm);
17936c94880fSSascha Wildner 		}
17946c94880fSSascha Wildner 		break;
17956c94880fSSascha Wildner 	case MIDI_NOTEOFF:
17966c94880fSSascha Wildner 		SYNTH_KILLNOTE(md, voice, note, parm);
17976c94880fSSascha Wildner 		break;
17986c94880fSSascha Wildner 	case MIDI_KEY_PRESSURE:
17996c94880fSSascha Wildner 		SYNTH_AFTERTOUCH(md, voice, parm);
18006c94880fSSascha Wildner 		break;
18016c94880fSSascha Wildner 	default:
18026c94880fSSascha Wildner 		ret = 1;
1803*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_chnvoice event type %d not handled\n",
18046c94880fSSascha Wildner 		    event[1]));
18056c94880fSSascha Wildner 		break;
18066c94880fSSascha Wildner 	}
18076c94880fSSascha Wildner 
1808*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18096c94880fSSascha Wildner 	return ret;
18106c94880fSSascha Wildner }
18116c94880fSSascha Wildner 
18126c94880fSSascha Wildner static int
seq_chncommon(struct seq_softc * scp,kobj_t md,u_char * event)18136c94880fSSascha Wildner seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event)
18146c94880fSSascha Wildner {
18156c94880fSSascha Wildner 	int ret;
18166c94880fSSascha Wildner 	u_short w14;
18176c94880fSSascha Wildner 	u_char cmd, chn, p1;
18186c94880fSSascha Wildner 
18196c94880fSSascha Wildner 	ret = 0;
18206c94880fSSascha Wildner 	cmd = event[2];
18216c94880fSSascha Wildner 	chn = event[3];
18226c94880fSSascha Wildner 	p1 = event[4];
18236c94880fSSascha Wildner 	w14 = *(u_short *)&event[6];
18246c94880fSSascha Wildner 
1825*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_chncommon: unit %d, dev %d, cmd %s, chn %d,"
18266c94880fSSascha Wildner 	    " p1 %d, w14 %d.\n", scp->unit, event[1],
18276c94880fSSascha Wildner 	    midi_cmdname(cmd, cmdtab_seqccmn), chn, p1, w14));
1828*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
18296c94880fSSascha Wildner 	switch (cmd) {
18306c94880fSSascha Wildner 	case MIDI_PGM_CHANGE:
1831*af11d9eeSSascha Wildner 		SEQ_DEBUG(4, kprintf("seq_chncommon pgmchn chn %d pg %d\n",
18326c94880fSSascha Wildner 		    chn, p1));
18336c94880fSSascha Wildner 		SYNTH_SETINSTR(md, chn, p1);
18346c94880fSSascha Wildner 		break;
18356c94880fSSascha Wildner 	case MIDI_CTL_CHANGE:
1836*af11d9eeSSascha Wildner 		SEQ_DEBUG(4, kprintf("seq_chncommon ctlch chn %d pg %d %d\n",
18376c94880fSSascha Wildner 		    chn, p1, w14));
18386c94880fSSascha Wildner 		SYNTH_CONTROLLER(md, chn, p1, w14);
18396c94880fSSascha Wildner 		break;
18406c94880fSSascha Wildner 	case MIDI_PITCH_BEND:
18416c94880fSSascha Wildner 		if (scp->music) {
18426c94880fSSascha Wildner 			/*
18436c94880fSSascha Wildner 		         * TODO: MIDI_PITCH_BEND
18446c94880fSSascha Wildner 		         */
18456c94880fSSascha Wildner #if 0
1846*af11d9eeSSascha Wildner 			lockmgr(&md->synth.vc_lock, LK_EXCLUSIVE);
18476c94880fSSascha Wildner 			md->synth.chn_info[chn].bender_value = w14;
18486c94880fSSascha Wildner 			if (md->midiunit >= 0) {
18496c94880fSSascha Wildner 				/*
18506c94880fSSascha Wildner 				 * Handle all of the notes playing on this
18516c94880fSSascha Wildner 				 * channel.
18526c94880fSSascha Wildner 				 */
18536c94880fSSascha Wildner 				key = ((int)chn << 8);
18546c94880fSSascha Wildner 				for (i = 0; i < md->synth.alloc.max_voice; i++)
18556c94880fSSascha Wildner 					if ((md->synth.alloc.map[i] & 0xff00) == key) {
1856*af11d9eeSSascha Wildner 						lockmgr(&md->synth.vc_lock, LK_RELEASE);
1857*af11d9eeSSascha Wildner 						lockmgr(&scp->seq_lock, LK_RELEASE);
18586c94880fSSascha Wildner 						if (md->synth.bender(md, i, w14) == EAGAIN) {
1859*af11d9eeSSascha Wildner 							lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18606c94880fSSascha Wildner 							return (QUEUEFULL);
18616c94880fSSascha Wildner 						}
1862*af11d9eeSSascha Wildner 						lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18636c94880fSSascha Wildner 					}
18646c94880fSSascha Wildner 			} else {
1865*af11d9eeSSascha Wildner 				lockmgr(&md->synth.vc_lock, LK_RELEASE);
1866*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_RELEASE);
18676c94880fSSascha Wildner 				if (md->synth.bender(md, chn, w14) == EAGAIN) {
1868*af11d9eeSSascha Wildner 					lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18696c94880fSSascha Wildner 					return (QUEUEFULL);
18706c94880fSSascha Wildner 				}
1871*af11d9eeSSascha Wildner 				lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18726c94880fSSascha Wildner 			}
18736c94880fSSascha Wildner #endif
18746c94880fSSascha Wildner 		} else
18756c94880fSSascha Wildner 			SYNTH_BENDER(md, chn, w14);
18766c94880fSSascha Wildner 		break;
18776c94880fSSascha Wildner 	default:
18786c94880fSSascha Wildner 		ret = 1;
18796c94880fSSascha Wildner 		SEQ_DEBUG(2,
1880*af11d9eeSSascha Wildner 		    kprintf("seq_chncommon event type %d not handled.\n",
18816c94880fSSascha Wildner 		    event[1]));
18826c94880fSSascha Wildner 		break;
18836c94880fSSascha Wildner 
18846c94880fSSascha Wildner 	}
1885*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
18866c94880fSSascha Wildner 	return ret;
18876c94880fSSascha Wildner }
18886c94880fSSascha Wildner 
18896c94880fSSascha Wildner static int
seq_timing(struct seq_softc * scp,u_char * event)18906c94880fSSascha Wildner seq_timing(struct seq_softc *scp, u_char *event)
18916c94880fSSascha Wildner {
18926c94880fSSascha Wildner 	int param;
18936c94880fSSascha Wildner 	int ret;
18946c94880fSSascha Wildner 
18956c94880fSSascha Wildner 	ret = 0;
18966c94880fSSascha Wildner 	param = event[4] + (event[5] << 8) +
18976c94880fSSascha Wildner 	    (event[6] << 16) + (event[7] << 24);
18986c94880fSSascha Wildner 
1899*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_timing: unit %d, cmd %d, param %d.\n",
19006c94880fSSascha Wildner 	    scp->unit, event[1], param));
19016c94880fSSascha Wildner 	switch (event[1]) {
19026c94880fSSascha Wildner 	case TMR_WAIT_REL:
19036c94880fSSascha Wildner 		timer_wait(scp, param, 0);
19046c94880fSSascha Wildner 		break;
19056c94880fSSascha Wildner 	case TMR_WAIT_ABS:
19066c94880fSSascha Wildner 		timer_wait(scp, param, 1);
19076c94880fSSascha Wildner 		break;
19086c94880fSSascha Wildner 	case TMR_START:
19096c94880fSSascha Wildner 		timer_start(scp);
19106c94880fSSascha Wildner 		cv_broadcast(&scp->reset_cv);
19116c94880fSSascha Wildner 		break;
19126c94880fSSascha Wildner 	case TMR_STOP:
19136c94880fSSascha Wildner 		timer_stop(scp);
19146c94880fSSascha Wildner 		/*
19156c94880fSSascha Wildner 		 * The following cv_broadcast isn't needed since we only
19166c94880fSSascha Wildner 		 * wait for 0->1 transitions.  It probably won't hurt
19176c94880fSSascha Wildner 		 */
19186c94880fSSascha Wildner 		cv_broadcast(&scp->reset_cv);
19196c94880fSSascha Wildner 		break;
19206c94880fSSascha Wildner 	case TMR_CONTINUE:
19216c94880fSSascha Wildner 		timer_continue(scp);
19226c94880fSSascha Wildner 		cv_broadcast(&scp->reset_cv);
19236c94880fSSascha Wildner 		break;
19246c94880fSSascha Wildner 	case TMR_TEMPO:
19256c94880fSSascha Wildner 		if (param < 8)
19266c94880fSSascha Wildner 			param = 8;
19276c94880fSSascha Wildner 		if (param > 360)
19286c94880fSSascha Wildner 			param = 360;
1929*af11d9eeSSascha Wildner 		SEQ_DEBUG(4, kprintf("Timer set tempo %d\n", param));
19306c94880fSSascha Wildner 		timer_setvals(scp, param, scp->timerbase);
19316c94880fSSascha Wildner 		break;
19326c94880fSSascha Wildner 	case TMR_TIMERBASE:
19336c94880fSSascha Wildner 		if (param < 1)
19346c94880fSSascha Wildner 			param = 1;
19356c94880fSSascha Wildner 		if (param > 1000)
19366c94880fSSascha Wildner 			param = 1000;
1937*af11d9eeSSascha Wildner 		SEQ_DEBUG(4, kprintf("Timer set timerbase %d\n", param));
19386c94880fSSascha Wildner 		timer_setvals(scp, scp->tempo, param);
19396c94880fSSascha Wildner 		break;
19406c94880fSSascha Wildner 	case TMR_ECHO:
19416c94880fSSascha Wildner 		/*
19426c94880fSSascha Wildner 		 * TODO: Consider making 4-byte events for /dev/sequencer
19436c94880fSSascha Wildner 		 * PRO: Maybe needed by legacy apps
19446c94880fSSascha Wildner 		 * CON: soundcard.h has been warning for a while many years
19456c94880fSSascha Wildner 		 * to expect 8 byte events.
19466c94880fSSascha Wildner 		 */
19476c94880fSSascha Wildner #if 0
19486c94880fSSascha Wildner 		if (scp->music)
19496c94880fSSascha Wildner 			seq_copytoinput(scp, event, 8);
19506c94880fSSascha Wildner 		else {
19516c94880fSSascha Wildner 			param = (param << 8 | SEQ_ECHO);
19526c94880fSSascha Wildner 			seq_copytoinput(scp, (u_char *)&param, 4);
19536c94880fSSascha Wildner 		}
19546c94880fSSascha Wildner #else
19556c94880fSSascha Wildner 		seq_copytoinput(scp, event, 8);
19566c94880fSSascha Wildner #endif
19576c94880fSSascha Wildner 		break;
19586c94880fSSascha Wildner 	default:
1959*af11d9eeSSascha Wildner 		SEQ_DEBUG(2, kprintf("seq_timing event type %d not handled.\n",
19606c94880fSSascha Wildner 		    event[1]));
19616c94880fSSascha Wildner 		ret = 1;
19626c94880fSSascha Wildner 		break;
19636c94880fSSascha Wildner 	}
19646c94880fSSascha Wildner 	return ret;
19656c94880fSSascha Wildner }
19666c94880fSSascha Wildner 
19676c94880fSSascha Wildner static int
seq_local(struct seq_softc * scp,u_char * event)19686c94880fSSascha Wildner seq_local(struct seq_softc *scp, u_char *event)
19696c94880fSSascha Wildner {
19706c94880fSSascha Wildner 	int ret;
19716c94880fSSascha Wildner 
19726c94880fSSascha Wildner 	ret = 0;
1973*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
19746c94880fSSascha Wildner 
1975*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_local: unit %d, cmd %d\n", scp->unit,
19766c94880fSSascha Wildner 	    event[1]));
19776c94880fSSascha Wildner 	switch (event[1]) {
19786c94880fSSascha Wildner 	default:
1979*af11d9eeSSascha Wildner 		SEQ_DEBUG(1, kprintf("seq_local event type %d not handled\n",
19806c94880fSSascha Wildner 		    event[1]));
19816c94880fSSascha Wildner 		ret = 1;
19826c94880fSSascha Wildner 		break;
19836c94880fSSascha Wildner 	}
19846c94880fSSascha Wildner 	return ret;
19856c94880fSSascha Wildner }
19866c94880fSSascha Wildner 
19876c94880fSSascha Wildner static int
seq_sysex(struct seq_softc * scp,kobj_t md,u_char * event)19886c94880fSSascha Wildner seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event)
19896c94880fSSascha Wildner {
19906c94880fSSascha Wildner 	int i, l;
19916c94880fSSascha Wildner 
1992*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
1993*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_sysex: unit %d device %d\n", scp->unit,
19946c94880fSSascha Wildner 	    event[1]));
19956c94880fSSascha Wildner 	l = 0;
19966c94880fSSascha Wildner 	for (i = 0; i < 6 && event[i + 2] != 0xff; i++)
19976c94880fSSascha Wildner 		l = i + 1;
19986c94880fSSascha Wildner 	if (l > 0) {
1999*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
20006c94880fSSascha Wildner 		if (SYNTH_SENDSYSEX(md, &event[2], l) == EAGAIN) {
2001*af11d9eeSSascha Wildner 			lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
20026c94880fSSascha Wildner 			return 1;
20036c94880fSSascha Wildner 		}
2004*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
20056c94880fSSascha Wildner 	}
20066c94880fSSascha Wildner 	return 0;
20076c94880fSSascha Wildner }
20086c94880fSSascha Wildner 
20096c94880fSSascha Wildner /*
20106c94880fSSascha Wildner  * Reset no longer closes the raw devices nor seq_sync's
20116c94880fSSascha Wildner  * Callers are IOCTL and seq_close
20126c94880fSSascha Wildner  */
20136c94880fSSascha Wildner static void
seq_reset(struct seq_softc * scp)20146c94880fSSascha Wildner seq_reset(struct seq_softc *scp)
20156c94880fSSascha Wildner {
20166c94880fSSascha Wildner 	int chn, i;
20176c94880fSSascha Wildner 	kobj_t m;
20186c94880fSSascha Wildner 
2019*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
20206c94880fSSascha Wildner 
2021*af11d9eeSSascha Wildner 	SEQ_DEBUG(5, kprintf("seq_reset: unit %d.\n", scp->unit));
20226c94880fSSascha Wildner 
20236c94880fSSascha Wildner 	/*
20246c94880fSSascha Wildner 	 * Stop reading and writing.
20256c94880fSSascha Wildner 	 */
20266c94880fSSascha Wildner 
20276c94880fSSascha Wildner 	/* scp->recording = 0; */
20286c94880fSSascha Wildner 	scp->playing = 0;
20296c94880fSSascha Wildner 	cv_broadcast(&scp->state_cv);
20306c94880fSSascha Wildner 	cv_broadcast(&scp->out_cv);
20316c94880fSSascha Wildner 	cv_broadcast(&scp->reset_cv);
20326c94880fSSascha Wildner 
20336c94880fSSascha Wildner 	/*
20346c94880fSSascha Wildner 	 * For now, don't reset the timers.
20356c94880fSSascha Wildner 	 */
20366c94880fSSascha Wildner 	MIDIQ_CLEAR(scp->in_q);
20376c94880fSSascha Wildner 	MIDIQ_CLEAR(scp->out_q);
20386c94880fSSascha Wildner 
20396c94880fSSascha Wildner 	for (i = 0; i < scp->midi_number; i++) {
20406c94880fSSascha Wildner 		m = scp->midis[i];
2041*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_RELEASE);
20426c94880fSSascha Wildner 		SYNTH_RESET(m);
20436c94880fSSascha Wildner 		for (chn = 0; chn < 16; chn++) {
20446c94880fSSascha Wildner 			SYNTH_CONTROLLER(m, chn, 123, 0);
20456c94880fSSascha Wildner 			SYNTH_CONTROLLER(m, chn, 121, 0);
20466c94880fSSascha Wildner 			SYNTH_BENDER(m, chn, 1 << 13);
20476c94880fSSascha Wildner 		}
2048*af11d9eeSSascha Wildner 		lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
20496c94880fSSascha Wildner 	}
20506c94880fSSascha Wildner }
20516c94880fSSascha Wildner 
20526c94880fSSascha Wildner /*
20536c94880fSSascha Wildner  * seq_sync
20546c94880fSSascha Wildner  * *really* flush the output queue
20556c94880fSSascha Wildner  * flush the event queue, then flush the synthsisers.
20566c94880fSSascha Wildner  * Callers are IOCTL and close
20576c94880fSSascha Wildner  */
20586c94880fSSascha Wildner 
20596c94880fSSascha Wildner #define SEQ_SYNC_TIMEOUT 8
20606c94880fSSascha Wildner static int
seq_sync(struct seq_softc * scp)20616c94880fSSascha Wildner seq_sync(struct seq_softc *scp)
20626c94880fSSascha Wildner {
20636c94880fSSascha Wildner 	int i, rl, sync[16], done;
20646c94880fSSascha Wildner 
2065*af11d9eeSSascha Wildner 	KKASSERT(lockowned(&scp->seq_lock));
20666c94880fSSascha Wildner 
2067*af11d9eeSSascha Wildner 	SEQ_DEBUG(4, kprintf("seq_sync: unit %d.\n", scp->unit));
20686c94880fSSascha Wildner 
20696c94880fSSascha Wildner 	/*
20706c94880fSSascha Wildner 	 * Wait until output queue is empty.  Check every so often to see if
20716c94880fSSascha Wildner 	 * the queue is moving along.  If it isn't just abort.
20726c94880fSSascha Wildner 	 */
20736c94880fSSascha Wildner 	while (!MIDIQ_EMPTY(scp->out_q)) {
20746c94880fSSascha Wildner 
20756c94880fSSascha Wildner 		if (!scp->playing) {
20766c94880fSSascha Wildner 			scp->playing = 1;
20776c94880fSSascha Wildner 			cv_broadcast(&scp->state_cv);
20786c94880fSSascha Wildner 			cv_broadcast(&scp->out_cv);
20796c94880fSSascha Wildner 		}
20806c94880fSSascha Wildner 		rl = MIDIQ_LEN(scp->out_q);
20816c94880fSSascha Wildner 
20826c94880fSSascha Wildner 		i = cv_timedwait_sig(&scp->out_cv,
20836c94880fSSascha Wildner 		    &scp->seq_lock, SEQ_SYNC_TIMEOUT * hz);
20846c94880fSSascha Wildner 
20856c94880fSSascha Wildner 		if (i == EINTR || i == ERESTART) {
20866c94880fSSascha Wildner 			if (i == EINTR) {
20876c94880fSSascha Wildner 				/*
20886c94880fSSascha Wildner 			         * XXX: I don't know why we stop playing
20896c94880fSSascha Wildner 			         */
20906c94880fSSascha Wildner 				scp->playing = 0;
20916c94880fSSascha Wildner 				cv_broadcast(&scp->out_cv);
20926c94880fSSascha Wildner 			}
20936c94880fSSascha Wildner 			return i;
20946c94880fSSascha Wildner 		}
20956c94880fSSascha Wildner 		if (i == EWOULDBLOCK && rl == MIDIQ_LEN(scp->out_q) &&
20966c94880fSSascha Wildner 		    scp->waiting == 0) {
20976c94880fSSascha Wildner 			/*
20986c94880fSSascha Wildner 			 * A queue seems to be stuck up. Give up and clear
20996c94880fSSascha Wildner 			 * queues.
21006c94880fSSascha Wildner 			 */
21016c94880fSSascha Wildner 			MIDIQ_CLEAR(scp->out_q);
21026c94880fSSascha Wildner 			scp->playing = 0;
21036c94880fSSascha Wildner 			cv_broadcast(&scp->state_cv);
21046c94880fSSascha Wildner 			cv_broadcast(&scp->out_cv);
21056c94880fSSascha Wildner 			cv_broadcast(&scp->reset_cv);
21066c94880fSSascha Wildner 
21076c94880fSSascha Wildner 			/*
21086c94880fSSascha Wildner 			 * TODO: Consider if the raw devices need to be flushed
21096c94880fSSascha Wildner 			 */
21106c94880fSSascha Wildner 
2111*af11d9eeSSascha Wildner 			SEQ_DEBUG(1, kprintf("seq_sync queue stuck, aborting\n"));
21126c94880fSSascha Wildner 
21136c94880fSSascha Wildner 			return i;
21146c94880fSSascha Wildner 		}
21156c94880fSSascha Wildner 	}
21166c94880fSSascha Wildner 
21176c94880fSSascha Wildner 	scp->playing = 0;
21186c94880fSSascha Wildner 	/*
21196c94880fSSascha Wildner 	 * Since syncing a midi device might block, unlock scp->seq_lock.
21206c94880fSSascha Wildner 	 */
21216c94880fSSascha Wildner 
2122*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_RELEASE);
21236c94880fSSascha Wildner 	for (i = 0; i < scp->midi_number; i++)
21246c94880fSSascha Wildner 		sync[i] = 1;
21256c94880fSSascha Wildner 
21266c94880fSSascha Wildner 	do {
21276c94880fSSascha Wildner 		done = 1;
21286c94880fSSascha Wildner 		for (i = 0; i < scp->midi_number; i++)
21296c94880fSSascha Wildner 			if (sync[i]) {
21306c94880fSSascha Wildner 				if (SYNTH_INSYNC(scp->midis[i]) == 0)
21316c94880fSSascha Wildner 					sync[i] = 0;
21326c94880fSSascha Wildner 				else
21336c94880fSSascha Wildner 					done = 0;
21346c94880fSSascha Wildner 			}
21356c94880fSSascha Wildner 		if (!done)
21366c94880fSSascha Wildner 			DELAY(5000);
21376c94880fSSascha Wildner 
21386c94880fSSascha Wildner 	} while (!done);
21396c94880fSSascha Wildner 
2140*af11d9eeSSascha Wildner 	lockmgr(&scp->seq_lock, LK_EXCLUSIVE);
21416c94880fSSascha Wildner 	return 0;
21426c94880fSSascha Wildner }
21436c94880fSSascha Wildner 
21446c94880fSSascha Wildner char   *
midi_cmdname(int cmd,midi_cmdtab * tab)21456c94880fSSascha Wildner midi_cmdname(int cmd, midi_cmdtab *tab)
21466c94880fSSascha Wildner {
21476c94880fSSascha Wildner 	while (tab->name != NULL) {
21486c94880fSSascha Wildner 		if (cmd == tab->cmd)
21496c94880fSSascha Wildner 			return (tab->name);
21506c94880fSSascha Wildner 		tab++;
21516c94880fSSascha Wildner 	}
21526c94880fSSascha Wildner 
21536c94880fSSascha Wildner 	return ("unknown");
21546c94880fSSascha Wildner }
2155