git: 79b968063998 - main - sound: Retire the MIDI sequencer

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Sun, 06 Jul 2025 13:09:00 UTC
The branch main has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=79b968063998e67a3c65b580908da640c4544a56

commit 79b968063998e67a3c65b580908da640c4544a56
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2025-07-06 13:08:10 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2025-07-06 13:08:10 +0000

    sound: Retire the MIDI sequencer
    
    The in-kernel MIDI sequencer is not used anymore, since this is done by
    userland applications nowadays. It also contains bugs, and we are not
    exactly sure how it works, or if it worked properly in the first place.
    
    Sponsored by:   The FreeBSD Foundation
    Reviewed by:    vishwin, markj
    Differential Revision:  https://reviews.freebsd.org/D50605
---
 sys/conf/files                   |    1 -
 sys/dev/sound/midi/midi.c        |   14 -
 sys/dev/sound/midi/midi.h        |    1 -
 sys/dev/sound/midi/sequencer.c   | 2107 --------------------------------------
 sys/dev/sound/midi/sequencer.h   |   89 --
 sys/dev/sound/pcm/sndstat.c      |    3 -
 sys/dev/sound/pcm/sound.h        |    1 -
 sys/modules/sound/sound/Makefile |    2 +-
 8 files changed, 1 insertion(+), 2217 deletions(-)

diff --git a/sys/conf/files b/sys/conf/files
index dd6f9a3021d4..7c023af39b2a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3173,7 +3173,6 @@ dev/sound/midi/midi.c		optional sound
 dev/sound/midi/mpu401.c		optional sound
 dev/sound/midi/mpu_if.m		optional sound
 dev/sound/midi/mpufoi_if.m	optional sound
-dev/sound/midi/sequencer.c	optional sound
 dev/sound/midi/synth_if.m	optional sound
 dev/spibus/acpi_spibus.c	optional acpi spibus
 dev/spibus/ofw_spibus.c		optional fdt spibus
diff --git a/sys/dev/sound/midi/midi.c b/sys/dev/sound/midi/midi.c
index fbfb69de2913..93a535b940a2 100644
--- a/sys/dev/sound/midi/midi.c
+++ b/sys/dev/sound/midi/midi.c
@@ -1441,8 +1441,6 @@ exit0:
 	return retval;
 }
 
-extern int seq_modevent(module_t mod, int type, void *data);
-
 static int
 midi_modevent(module_t mod, int type, void *data)
 {
@@ -1453,14 +1451,10 @@ midi_modevent(module_t mod, int type, void *data)
 	switch (type) {
 	case MOD_LOAD:
 		retval = midi_load();
-		if (retval == 0)
-			retval = seq_modevent(mod, type, data);
 		break;
 
 	case MOD_UNLOAD:
 		retval = midi_unload();
-		if (retval == 0)
-			retval = seq_modevent(mod, type, data);
 		break;
 
 	default:
@@ -1470,14 +1464,6 @@ midi_modevent(module_t mod, int type, void *data)
 	return retval;
 }
 
-kobj_t
-midimapper_addseq(void *arg1, int *unit, void **cookie)
-{
-	unit = NULL;
-
-	return (kobj_t)arg1;
-}
-
 int
 midimapper_open_locked(void *arg1, void **cookie)
 {
diff --git a/sys/dev/sound/midi/midi.h b/sys/dev/sound/midi/midi.h
index 2254fab690e9..8becc20d35e6 100644
--- a/sys/dev/sound/midi/midi.h
+++ b/sys/dev/sound/midi/midi.h
@@ -51,7 +51,6 @@ int	midi_uninit(struct snd_midi *_m);
 int	midi_out(struct snd_midi *_m, uint8_t *_buf, int _size);
 int	midi_in(struct snd_midi *_m, uint8_t *_buf, int _size);
 
-kobj_t	midimapper_addseq(void *arg1, int *unit, void **cookie);
 int	midimapper_open_locked(void *arg1, void **cookie);
 int	midimapper_open(void *arg1, void **cookie);
 int	midimapper_close(void *arg1, void *cookie);
diff --git a/sys/dev/sound/midi/sequencer.c b/sys/dev/sound/midi/sequencer.c
deleted file mode 100644
index 03b71688175c..000000000000
--- a/sys/dev/sound/midi/sequencer.c
+++ /dev/null
@@ -1,2107 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2003 Mathew Kanner
- * Copyright (c) 1993 Hannu Savolainen
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * The sequencer personality manager.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/ioccom.h>
-
-#include <sys/filio.h>
-#include <sys/lock.h>
-#include <sys/sockio.h>
-#include <sys/fcntl.h>
-#include <sys/proc.h>
-#include <sys/sysctl.h>
-
-#include <sys/kernel.h>			/* for DATA_SET */
-
-#include <sys/module.h>
-#include <sys/conf.h>
-#include <sys/file.h>
-#include <sys/uio.h>
-#include <sys/syslog.h>
-#include <sys/errno.h>
-#include <sys/malloc.h>
-#include <sys/bus.h>
-#include <machine/resource.h>
-#include <machine/bus.h>
-#include <machine/clock.h>		/* for DELAY */
-#include <sys/soundcard.h>
-#include <sys/rman.h>
-#include <sys/mman.h>
-#include <sys/poll.h>
-#include <sys/mutex.h>
-#include <sys/condvar.h>
-#include <sys/kthread.h>
-#include <sys/unistd.h>
-#include <sys/selinfo.h>
-#include <sys/sx.h>
-
-#ifdef HAVE_KERNEL_OPTION_HEADERS
-#include "opt_snd.h"
-#endif
-
-#include <dev/sound/midi/midi.h>
-#include <dev/sound/midi/midiq.h>
-#include "synth_if.h"
-
-#include <dev/sound/midi/sequencer.h>
-
-#define TMR_TIMERBASE 13
-
-#define SND_DEV_SEQ	1		/* Sequencer output /dev/sequencer (FM
-					 * synthesizer and MIDI output) */
-#define SND_DEV_MUSIC	8		/* /dev/music, level 2 interface */
-
-/* Length of a sequencer event. */
-#define EV_SZ 8
-#define IEV_SZ 8
-
-/* Lookup modes */
-#define LOOKUP_EXIST	(0)
-#define LOOKUP_OPEN	(1)
-#define LOOKUP_CLOSE	(2)
-
-#define MIDIDEV(y) (dev2unit(y) & 0x0f)
-
-/* These are the entries to the sequencer driver. */
-static d_open_t mseq_open;
-static d_close_t mseq_close;
-static d_ioctl_t mseq_ioctl;
-static d_read_t mseq_read;
-static d_write_t mseq_write;
-static d_poll_t mseq_poll;
-
-static struct cdevsw seq_cdevsw = {
-	.d_version = D_VERSION,
-	.d_open = mseq_open,
-	.d_close = mseq_close,
-	.d_read = mseq_read,
-	.d_write = mseq_write,
-	.d_ioctl = mseq_ioctl,
-	.d_poll = mseq_poll,
-	.d_name = "sequencer",
-};
-
-struct seq_softc {
-	KOBJ_FIELDS;
-
-	struct mtx seq_lock, q_lock;
-	struct cv empty_cv, reset_cv, in_cv, out_cv, state_cv, th_cv;
-
-	MIDIQ_HEAD(, u_char) in_q, out_q;
-
-	u_long	flags;
-	/* Flags (protected by flag_mtx of mididev_info) */
-	int	fflags;			/* Access mode */
-	int	music;
-
-	int	out_water;		/* Sequence output threshould */
-	snd_sync_parm sync_parm;	/* AIOSYNC parameter set */
-	struct thread *sync_thread;	/* AIOSYNCing thread */
-	struct selinfo in_sel, out_sel;
-	int	midi_number;
-	struct cdev *seqdev, *musicdev;
-	int	unit;
-	int	maxunits;
-	kobj_t *midis;
-	int    *midi_flags;
-	kobj_t	mapper;
-	void   *mapper_cookie;
-	struct timeval timerstop, timersub;
-	int	timerbase, tempo;
-	int	timerrun;
-	int	done;
-	int	playing;
-	int	recording;
-	int	busy;
-	int	pre_event_timeout;
-	int	waiting;
-};
-
-/*
- * Module specific stuff, including how many sequecers
- * we currently own.
- */
-
-SYSCTL_NODE(_hw_midi, OID_AUTO, seq, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
-    "Midi sequencer");
-
-int					seq_debug;
-/* XXX: should this be moved into debug.midi? */
-SYSCTL_INT(_hw_midi_seq, OID_AUTO, debug, CTLFLAG_RW, &seq_debug, 0, "");
-
-midi_cmdtab	cmdtab_seqevent[] = {
-	{SEQ_NOTEOFF,		"SEQ_NOTEOFF"},
-	{SEQ_NOTEON,		"SEQ_NOTEON"},
-	{SEQ_WAIT,		"SEQ_WAIT"},
-	{SEQ_PGMCHANGE,		"SEQ_PGMCHANGE"},
-	{SEQ_SYNCTIMER,		"SEQ_SYNCTIMER"},
-	{SEQ_MIDIPUTC,		"SEQ_MIDIPUTC"},
-	{SEQ_DRUMON,		"SEQ_DRUMON"},
-	{SEQ_DRUMOFF,		"SEQ_DRUMOFF"},
-	{SEQ_ECHO,		"SEQ_ECHO"},
-	{SEQ_AFTERTOUCH,	"SEQ_AFTERTOUCH"},
-	{SEQ_CONTROLLER,	"SEQ_CONTROLLER"},
-	{SEQ_BALANCE,		"SEQ_BALANCE"},
-	{SEQ_VOLMODE,		"SEQ_VOLMODE"},
-	{SEQ_FULLSIZE,		"SEQ_FULLSIZE"},
-	{SEQ_PRIVATE,		"SEQ_PRIVATE"},
-	{SEQ_EXTENDED,		"SEQ_EXTENDED"},
-	{EV_SEQ_LOCAL,		"EV_SEQ_LOCAL"},
-	{EV_TIMING,		"EV_TIMING"},
-	{EV_CHN_COMMON,		"EV_CHN_COMMON"},
-	{EV_CHN_VOICE,		"EV_CHN_VOICE"},
-	{EV_SYSEX,		"EV_SYSEX"},
-	{-1,			NULL},
-};
-
-midi_cmdtab	cmdtab_seqioctl[] = {
-	{SNDCTL_SEQ_RESET,	"SNDCTL_SEQ_RESET"},
-	{SNDCTL_SEQ_SYNC,	"SNDCTL_SEQ_SYNC"},
-	{SNDCTL_SYNTH_INFO,	"SNDCTL_SYNTH_INFO"},
-	{SNDCTL_SEQ_CTRLRATE,	"SNDCTL_SEQ_CTRLRATE"},
-	{SNDCTL_SEQ_GETOUTCOUNT,	"SNDCTL_SEQ_GETOUTCOUNT"},
-	{SNDCTL_SEQ_GETINCOUNT,	"SNDCTL_SEQ_GETINCOUNT"},
-	{SNDCTL_SEQ_PERCMODE,	"SNDCTL_SEQ_PERCMODE"},
-	{SNDCTL_FM_LOAD_INSTR,	"SNDCTL_FM_LOAD_INSTR"},
-	{SNDCTL_SEQ_TESTMIDI,	"SNDCTL_SEQ_TESTMIDI"},
-	{SNDCTL_SEQ_RESETSAMPLES,	"SNDCTL_SEQ_RESETSAMPLES"},
-	{SNDCTL_SEQ_NRSYNTHS,	"SNDCTL_SEQ_NRSYNTHS"},
-	{SNDCTL_SEQ_NRMIDIS,	"SNDCTL_SEQ_NRMIDIS"},
-	{SNDCTL_SEQ_GETTIME,	"SNDCTL_SEQ_GETTIME"},
-	{SNDCTL_MIDI_INFO,	"SNDCTL_MIDI_INFO"},
-	{SNDCTL_SEQ_THRESHOLD,	"SNDCTL_SEQ_THRESHOLD"},
-	{SNDCTL_SYNTH_MEMAVL,	"SNDCTL_SYNTH_MEMAVL"},
-	{SNDCTL_FM_4OP_ENABLE,	"SNDCTL_FM_4OP_ENABLE"},
-	{SNDCTL_PMGR_ACCESS,	"SNDCTL_PMGR_ACCESS"},
-	{SNDCTL_SEQ_PANIC,	"SNDCTL_SEQ_PANIC"},
-	{SNDCTL_SEQ_OUTOFBAND,	"SNDCTL_SEQ_OUTOFBAND"},
-	{SNDCTL_TMR_TIMEBASE,	"SNDCTL_TMR_TIMEBASE"},
-	{SNDCTL_TMR_START,	"SNDCTL_TMR_START"},
-	{SNDCTL_TMR_STOP,	"SNDCTL_TMR_STOP"},
-	{SNDCTL_TMR_CONTINUE,	"SNDCTL_TMR_CONTINUE"},
-	{SNDCTL_TMR_TEMPO,	"SNDCTL_TMR_TEMPO"},
-	{SNDCTL_TMR_SOURCE,	"SNDCTL_TMR_SOURCE"},
-	{SNDCTL_TMR_METRONOME,	"SNDCTL_TMR_METRONOME"},
-	{SNDCTL_TMR_SELECT,	"SNDCTL_TMR_SELECT"},
-	{SNDCTL_MIDI_PRETIME,	"SNDCTL_MIDI_PRETIME"},
-	{AIONWRITE,		"AIONWRITE"},
-	{AIOGSIZE,		"AIOGSIZE"},
-	{AIOSSIZE,		"AIOSSIZE"},
-	{AIOGFMT,		"AIOGFMT"},
-	{AIOSFMT,		"AIOSFMT"},
-	{AIOGMIX,		"AIOGMIX"},
-	{AIOSMIX,		"AIOSMIX"},
-	{AIOSTOP,		"AIOSTOP"},
-	{AIOSYNC,		"AIOSYNC"},
-	{AIOGCAP,		"AIOGCAP"},
-	{-1,			NULL},
-};
-
-midi_cmdtab	cmdtab_timer[] = {
-	{TMR_WAIT_REL,	"TMR_WAIT_REL"},
-	{TMR_WAIT_ABS,	"TMR_WAIT_ABS"},
-	{TMR_STOP,	"TMR_STOP"},
-	{TMR_START,	"TMR_START"},
-	{TMR_CONTINUE,	"TMR_CONTINUE"},
-	{TMR_TEMPO,	"TMR_TEMPO"},
-	{TMR_ECHO,	"TMR_ECHO"},
-	{TMR_CLOCK,	"TMR_CLOCK"},
-	{TMR_SPP,	"TMR_SPP"},
-	{TMR_TIMESIG,	"TMR_TIMESIG"},
-	{-1,		NULL},
-};
-
-midi_cmdtab	cmdtab_seqcv[] = {
-	{MIDI_NOTEOFF,		"MIDI_NOTEOFF"},
-	{MIDI_NOTEON,		"MIDI_NOTEON"},
-	{MIDI_KEY_PRESSURE,	"MIDI_KEY_PRESSURE"},
-	{-1,			NULL},
-};
-
-midi_cmdtab	cmdtab_seqccmn[] = {
-	{MIDI_CTL_CHANGE,	"MIDI_CTL_CHANGE"},
-	{MIDI_PGM_CHANGE,	"MIDI_PGM_CHANGE"},
-	{MIDI_CHN_PRESSURE,	"MIDI_CHN_PRESSURE"},
-	{MIDI_PITCH_BEND,	"MIDI_PITCH_BEND"},
-	{MIDI_SYSTEM_PREFIX,	"MIDI_SYSTEM_PREFIX"},
-	{-1,			NULL},
-};
-
-#ifndef KOBJMETHOD_END
-#define KOBJMETHOD_END	{ NULL, NULL }
-#endif
-
-/*
- * static const char *mpu401_mprovider(kobj_t obj, struct mpu401 *m);
- */
-
-static kobj_method_t seq_methods[] = {
-	/* KOBJMETHOD(mpu_provider,mpu401_mprovider), */
-	KOBJMETHOD_END
-};
-
-DEFINE_CLASS(sequencer, seq_methods, 0);
-
-/* The followings are the local function. */
-static int seq_convertold(u_char *event, u_char *out);
-
-/*
- * static void seq_midiinput(struct seq_softc * scp, void *md);
- */
-static void seq_reset(struct seq_softc *scp);
-static int seq_sync(struct seq_softc *scp);
-
-static int seq_processevent(struct seq_softc *scp, u_char *event);
-
-static int seq_timing(struct seq_softc *scp, u_char *event);
-static int seq_local(struct seq_softc *scp, u_char *event);
-
-static int seq_chnvoice(struct seq_softc *scp, kobj_t md, u_char *event);
-static int seq_chncommon(struct seq_softc *scp, kobj_t md, u_char *event);
-static int seq_sysex(struct seq_softc *scp, kobj_t md, u_char *event);
-
-static int seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md);
-void	seq_copytoinput(struct seq_softc *scp, u_char *event, int len);
-int	seq_modevent(module_t mod, int type, void *data);
-struct seq_softc *seqs[10];
-static struct mtx seqinfo_mtx;
-static u_long nseq = 0;
-
-static void timer_start(struct seq_softc *t);
-static void timer_stop(struct seq_softc *t);
-static void timer_setvals(struct seq_softc *t, int tempo, int timerbase);
-static void timer_wait(struct seq_softc *t, int ticks, int wait_abs);
-static int timer_now(struct seq_softc *t);
-
-static void
-timer_start(struct seq_softc *t)
-{
-	t->timerrun = 1;
-	getmicrotime(&t->timersub);
-}
-
-static void
-timer_continue(struct seq_softc *t)
-{
-	struct timeval now;
-
-	if (t->timerrun == 1)
-		return;
-	t->timerrun = 1;
-	getmicrotime(&now);
-	timevalsub(&now, &t->timerstop);
-	timevaladd(&t->timersub, &now);
-}
-
-static void
-timer_stop(struct seq_softc *t)
-{
-	t->timerrun = 0;
-	getmicrotime(&t->timerstop);
-}
-
-static void
-timer_setvals(struct seq_softc *t, int tempo, int timerbase)
-{
-	t->tempo = tempo;
-	t->timerbase = timerbase;
-}
-
-static void
-timer_wait(struct seq_softc *t, int ticks, int wait_abs)
-{
-	struct timeval now, when;
-	int ret;
-	unsigned long long i;
-
-	while (t->timerrun == 0) {
-		SEQ_DEBUG(2, printf("Timer wait when timer isn't running\n"));
-		/*
-	         * The old sequencer used timeouts that only increased
-	         * the timer when the timer was running.
-	         * Hence the sequencer would stick (?) if the
-	         * timer was disabled.
-	         */
-		cv_wait(&t->reset_cv, &t->seq_lock);
-		if (t->playing == 0)
-			return;
-	}
-
-	i = ticks * 60ull * 1000000ull / (t->tempo * t->timerbase);
-
-	when.tv_sec = i / 1000000;
-	when.tv_usec = i % 1000000;
-
-#if 0
-	printf("timer_wait tempo %d timerbase %d ticks %d abs %d u_sec %llu\n",
-	    t->tempo, t->timerbase, ticks, wait_abs, i);
-#endif
-
-	if (wait_abs != 0) {
-		getmicrotime(&now);
-		timevalsub(&now, &t->timersub);
-		timevalsub(&when, &now);
-	}
-	if (when.tv_sec < 0 || when.tv_usec < 0) {
-		SEQ_DEBUG(3,
-		    printf("seq_timer error negative time %lds.%06lds\n",
-		    (long)when.tv_sec, (long)when.tv_usec));
-		return;
-	}
-	i = when.tv_sec * 1000000ull;
-	i += when.tv_usec;
-	i *= hz;
-	i /= 1000000ull;
-#if 0
-	printf("seq_timer usec %llu ticks %llu\n",
-	    when.tv_sec * 1000000ull + when.tv_usec, i);
-#endif
-	t->waiting = 1;
-	ret = cv_timedwait(&t->reset_cv, &t->seq_lock, i + 1);
-	t->waiting = 0;
-
-	if (ret != EWOULDBLOCK)
-		SEQ_DEBUG(3, printf("seq_timer didn't timeout\n"));
-
-}
-
-static int
-timer_now(struct seq_softc *t)
-{
-	struct timeval now;
-	unsigned long long i;
-	int ret;
-
-	if (t->timerrun == 0)
-		now = t->timerstop;
-	else
-		getmicrotime(&now);
-
-	timevalsub(&now, &t->timersub);
-
-	i = now.tv_sec * 1000000ull;
-	i += now.tv_usec;
-	i *= t->timerbase;
-/*	i /= t->tempo; */
-	i /= 1000000ull;
-
-	ret = i;
-	/*
-	 * printf("timer_now: %llu %d\n", i, ret);
-	 */
-
-	return ret;
-}
-
-static void
-seq_eventthread(void *arg)
-{
-	struct seq_softc *scp = arg;
-	u_char event[EV_SZ];
-
-	mtx_lock(&scp->seq_lock);
-	SEQ_DEBUG(2, printf("seq_eventthread started\n"));
-	while (scp->done == 0) {
-restart:
-		while (scp->playing == 0) {
-			cv_wait(&scp->state_cv, &scp->seq_lock);
-			if (scp->done)
-				goto done;
-		}
-
-		while (MIDIQ_EMPTY(scp->out_q)) {
-			cv_broadcast(&scp->empty_cv);
-			cv_wait(&scp->out_cv, &scp->seq_lock);
-			if (scp->playing == 0)
-				goto restart;
-			if (scp->done)
-				goto done;
-		}
-
-		MIDIQ_DEQ(scp->out_q, event, EV_SZ);
-
-		if (MIDIQ_AVAIL(scp->out_q) < scp->out_water) {
-			cv_broadcast(&scp->out_cv);
-			selwakeup(&scp->out_sel);
-		}
-		seq_processevent(scp, event);
-	}
-
-done:
-	cv_broadcast(&scp->th_cv);
-	mtx_unlock(&scp->seq_lock);
-	SEQ_DEBUG(2, printf("seq_eventthread finished\n"));
-	kproc_exit(0);
-}
-
-/*
- * seq_processevent:  This maybe called by the event thread or the IOCTL
- * handler for queued and out of band events respectively.
- */
-static int
-seq_processevent(struct seq_softc *scp, u_char *event)
-{
-	int ret;
-	kobj_t m;
-
-	ret = 0;
-
-	if (event[0] == EV_SEQ_LOCAL)
-		ret = seq_local(scp, event);
-	else if (event[0] == EV_TIMING)
-		ret = seq_timing(scp, event);
-	else if (event[0] != EV_CHN_VOICE &&
-		    event[0] != EV_CHN_COMMON &&
-		    event[0] != EV_SYSEX &&
-	    event[0] != SEQ_MIDIPUTC) {
-		ret = 1;
-		SEQ_DEBUG(2, printf("seq_processevent not known %d\n",
-		    event[0]));
-	} else if (seq_fetch_mid(scp, event[1], &m) != 0) {
-		ret = 1;
-		SEQ_DEBUG(2, printf("seq_processevent midi unit not found %d\n",
-		    event[1]));
-	} else
-		switch (event[0]) {
-		case EV_CHN_VOICE:
-			ret = seq_chnvoice(scp, m, event);
-			break;
-		case EV_CHN_COMMON:
-			ret = seq_chncommon(scp, m, event);
-			break;
-		case EV_SYSEX:
-			ret = seq_sysex(scp, m, event);
-			break;
-		case SEQ_MIDIPUTC:
-			mtx_unlock(&scp->seq_lock);
-			ret = SYNTH_WRITERAW(m, &event[2], 1);
-			mtx_lock(&scp->seq_lock);
-			break;
-		}
-	return ret;
-}
-
-static int
-seq_addunit(void)
-{
-	struct seq_softc *scp;
-	int ret;
-	u_char *buf;
-
-	gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer "
-	    "needed or used\n");
-
-	/* Allocate the softc. */
-	ret = ENOMEM;
-	scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
-	if (scp == NULL) {
-		SEQ_DEBUG(1, printf("seq_addunit: softc allocation failed.\n"));
-		goto err;
-	}
-	kobj_init((kobj_t)scp, &sequencer_class);
-
-	buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
-	if (buf == NULL)
-		goto err;
-	MIDIQ_INIT(scp->in_q, buf, EV_SZ * 1024);
-	buf = malloc(sizeof(*buf) * EV_SZ * 1024, M_TEMP, M_NOWAIT | M_ZERO);
-	if (buf == NULL)
-		goto err;
-	MIDIQ_INIT(scp->out_q, buf, EV_SZ * 1024);
-	ret = EINVAL;
-
-	scp->midis = malloc(sizeof(kobj_t) * 32, M_TEMP, M_NOWAIT | M_ZERO);
-	scp->midi_flags = malloc(sizeof(*scp->midi_flags) * 32, M_TEMP,
-	    M_NOWAIT | M_ZERO);
-
-	if (scp->midis == NULL || scp->midi_flags == NULL)
-		goto err;
-
-	scp->flags = 0;
-
-	mtx_init(&scp->seq_lock, "seqflq", NULL, 0);
-	cv_init(&scp->state_cv, "seqstate");
-	cv_init(&scp->empty_cv, "seqempty");
-	cv_init(&scp->reset_cv, "seqtimer");
-	cv_init(&scp->out_cv, "seqqout");
-	cv_init(&scp->in_cv, "seqqin");
-	cv_init(&scp->th_cv, "seqstart");
-
-	/*
-	 * Init the damn timer
-	 */
-
-	scp->mapper = midimapper_addseq(scp, &scp->unit, &scp->mapper_cookie);
-	if (scp->mapper == NULL)
-		goto err;
-
-	scp->seqdev = make_dev(&seq_cdevsw, SND_DEV_SEQ, UID_ROOT, GID_WHEEL,
-	    0666, "sequencer%d", scp->unit);
-
-	scp->musicdev = make_dev(&seq_cdevsw, SND_DEV_MUSIC, UID_ROOT,
-	    GID_WHEEL, 0666, "music%d", scp->unit);
-
-	if (scp->seqdev == NULL || scp->musicdev == NULL)
-		goto err;
-	/*
-	 * TODO: Add to list of sequencers this module provides
-	 */
-
-	ret =
-	    kproc_create
-	    (seq_eventthread, scp, NULL, RFHIGHPID, 0,
-	    "sequencer %02d", scp->unit);
-
-	if (ret)
-		goto err;
-
-	scp->seqdev->si_drv1 = scp->musicdev->si_drv1 = scp;
-
-	SEQ_DEBUG(2, printf("sequencer %d created scp %p\n", scp->unit, scp));
-
-	ret = 0;
-
-	mtx_lock(&seqinfo_mtx);
-	seqs[nseq++] = scp;
-	mtx_unlock(&seqinfo_mtx);
-
-	goto ok;
-
-err:
-	if (scp != NULL) {
-		if (scp->seqdev != NULL)
-			destroy_dev(scp->seqdev);
-		if (scp->musicdev != NULL)
-			destroy_dev(scp->musicdev);
-		/*
-	         * TODO: Destroy mutex and cv
-	         */
-		if (scp->midis != NULL)
-			free(scp->midis, M_TEMP);
-		if (scp->midi_flags != NULL)
-			free(scp->midi_flags, M_TEMP);
-		if (scp->out_q.b)
-			free(scp->out_q.b, M_TEMP);
-		if (scp->in_q.b)
-			free(scp->in_q.b, M_TEMP);
-		free(scp, M_DEVBUF);
-	}
-ok:
-	return ret;
-}
-
-static int
-seq_delunit(int unit)
-{
-	struct seq_softc *scp = seqs[unit];
-	int i;
-
-	//SEQ_DEBUG(4, printf("seq_delunit: %d\n", unit));
-	SEQ_DEBUG(1, printf("seq_delunit: 1 \n"));
-	mtx_lock(&scp->seq_lock);
-
-	scp->playing = 0;
-	scp->done = 1;
-	cv_broadcast(&scp->out_cv);
-	cv_broadcast(&scp->state_cv);
-	cv_broadcast(&scp->reset_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 2 \n"));
-	cv_wait(&scp->th_cv, &scp->seq_lock);
-	SEQ_DEBUG(1, printf("seq_delunit: 3.0 \n"));
-	mtx_unlock(&scp->seq_lock);
-	SEQ_DEBUG(1, printf("seq_delunit: 3.1 \n"));
-
-	cv_destroy(&scp->state_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 4 \n"));
-	cv_destroy(&scp->empty_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 5 \n"));
-	cv_destroy(&scp->reset_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 6 \n"));
-	cv_destroy(&scp->out_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 7 \n"));
-	cv_destroy(&scp->in_cv);
-	SEQ_DEBUG(1, printf("seq_delunit: 8 \n"));
-	cv_destroy(&scp->th_cv);
-
-	SEQ_DEBUG(1, printf("seq_delunit: 10 \n"));
-	if (scp->seqdev)
-		destroy_dev(scp->seqdev);
-	SEQ_DEBUG(1, printf("seq_delunit: 11 \n"));
-	if (scp->musicdev)
-		destroy_dev(scp->musicdev);
-	SEQ_DEBUG(1, printf("seq_delunit: 12 \n"));
-	scp->seqdev = scp->musicdev = NULL;
-	if (scp->midis != NULL)
-		free(scp->midis, M_TEMP);
-	SEQ_DEBUG(1, printf("seq_delunit: 13 \n"));
-	if (scp->midi_flags != NULL)
-		free(scp->midi_flags, M_TEMP);
-	SEQ_DEBUG(1, printf("seq_delunit: 14 \n"));
-	free(scp->out_q.b, M_TEMP);
-	SEQ_DEBUG(1, printf("seq_delunit: 15 \n"));
-	free(scp->in_q.b, M_TEMP);
-
-	SEQ_DEBUG(1, printf("seq_delunit: 16 \n"));
-
-	mtx_destroy(&scp->seq_lock);
-	SEQ_DEBUG(1, printf("seq_delunit: 17 \n"));
-	free(scp, M_DEVBUF);
-
-	mtx_lock(&seqinfo_mtx);
-	for (i = unit; i < (nseq - 1); i++)
-		seqs[i] = seqs[i + 1];
-	nseq--;
-	mtx_unlock(&seqinfo_mtx);
-
-	return 0;
-}
-
-int
-seq_modevent(module_t mod, int type, void *data)
-{
-	int retval, r;
-
-	retval = 0;
-
-	switch (type) {
-	case MOD_LOAD:
-		mtx_init(&seqinfo_mtx, "seqmod", NULL, 0);
-		retval = seq_addunit();
-		break;
-
-	case MOD_UNLOAD:
-		while (nseq) {
-			r = seq_delunit(nseq - 1);
-			if (r) {
-				retval = r;
-				break;
-			}
-		}
-		if (nseq == 0) {
-			retval = 0;
-			mtx_destroy(&seqinfo_mtx);
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return retval;
-}
-
-static int
-seq_fetch_mid(struct seq_softc *scp, int unit, kobj_t *md)
-{
-
-	if (unit >= scp->midi_number || unit < 0)
-		return EINVAL;
-
-	*md = scp->midis[unit];
-
-	return 0;
-}
-
-int
-mseq_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
-	struct seq_softc *scp = i_dev->si_drv1;
-	int i;
-
-	gone_in(15, "Warning! MIDI sequencer to be removed soon: no longer "
-	    "needed or used\n");
-
-	if (scp == NULL)
-		return ENXIO;
-
-	SEQ_DEBUG(3, printf("seq_open: scp %p unit %d, flags 0x%x.\n",
-	    scp, scp->unit, flags));
-
-	/*
-	 * Mark this device busy.
-	 */
-
-	midistat_lock();
-	mtx_lock(&scp->seq_lock);
-	if (scp->busy) {
-		mtx_unlock(&scp->seq_lock);
-		midistat_unlock();
-		SEQ_DEBUG(2, printf("seq_open: unit %d is busy.\n", scp->unit));
-		return EBUSY;
-	}
-	scp->fflags = flags;
-	/*
-	if ((scp->fflags & O_NONBLOCK) != 0)
-		scp->flags |= SEQ_F_NBIO;
-		*/
-	scp->music = MIDIDEV(i_dev) == SND_DEV_MUSIC;
-
-	/*
-	 * Enumerate the available midi devices
-	 */
-	scp->midi_number = 0;
-	scp->maxunits = midimapper_open_locked(scp->mapper, &scp->mapper_cookie);
-
-	if (scp->maxunits == 0)
-		SEQ_DEBUG(2, printf("seq_open: no midi devices\n"));
-
-	for (i = 0; i < scp->maxunits; i++) {
-		scp->midis[scp->midi_number] =
-		    midimapper_fetch_synth_locked(scp->mapper,
-		    scp->mapper_cookie, i);
-		if (scp->midis[scp->midi_number]) {
-			if (SYNTH_OPEN(scp->midis[scp->midi_number], scp,
-				scp->fflags) != 0)
-				scp->midis[scp->midi_number] = NULL;
-			else {
-				scp->midi_flags[scp->midi_number] =
-				    SYNTH_QUERY(scp->midis[scp->midi_number]);
-				scp->midi_number++;
-			}
-		}
-	}
-	midistat_unlock();
-
-	timer_setvals(scp, 60, 100);
-
-	timer_start(scp);
-	timer_stop(scp);
-	/*
-	 * actually, if we're in rdonly mode, we should start the timer
-	 */
-	/*
-	 * TODO: Handle recording now
-	 */
-
-	scp->out_water = MIDIQ_SIZE(scp->out_q) / 2;
-
-	scp->busy = 1;
-	mtx_unlock(&scp->seq_lock);
-
-	SEQ_DEBUG(2, printf("seq_open: opened, mode %s.\n",
-	    scp->music ? "music" : "sequencer"));
-	SEQ_DEBUG(2,
-	    printf("Sequencer %d %p opened maxunits %d midi_number %d:\n",
-		scp->unit, scp, scp->maxunits, scp->midi_number));
-	for (i = 0; i < scp->midi_number; i++)
-		SEQ_DEBUG(3, printf("  midi %d %p\n", i, scp->midis[i]));
-
-	return 0;
-}
-
-/*
- * mseq_close
- */
-int
-mseq_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
-	int i;
-	struct seq_softc *scp = i_dev->si_drv1;
-	int ret;
-
-	if (scp == NULL)
-		return ENXIO;
-
-	SEQ_DEBUG(2, printf("seq_close: unit %d.\n", scp->unit));
-
-	mtx_lock(&scp->seq_lock);
-
-	ret = ENXIO;
-	if (scp->busy == 0)
-		goto err;
-
-	seq_reset(scp);
-	seq_sync(scp);
-
-	for (i = 0; i < scp->midi_number; i++)
-		if (scp->midis[i])
-			SYNTH_CLOSE(scp->midis[i]);
-
-	midimapper_close(scp->mapper, scp->mapper_cookie);
-
-	timer_stop(scp);
-
-	scp->busy = 0;
-	ret = 0;
-
-err:
-	SEQ_DEBUG(3, printf("seq_close: closed ret = %d.\n", ret));
-	mtx_unlock(&scp->seq_lock);
-	return ret;
-}
-
-int
-mseq_read(struct cdev *i_dev, struct uio *uio, int ioflag)
-{
-	int retval, used;
-	struct seq_softc *scp = i_dev->si_drv1;
-
-#define SEQ_RSIZE 32
-	u_char buf[SEQ_RSIZE];
-
-	if (scp == NULL)
-		return ENXIO;
-
-	SEQ_DEBUG(7, printf("mseq_read: unit %d, resid %zd.\n",
-	    scp->unit, uio->uio_resid));
-
-	mtx_lock(&scp->seq_lock);
-	if ((scp->fflags & FREAD) == 0) {
-		SEQ_DEBUG(2, printf("mseq_read: unit %d is not for reading.\n",
-		    scp->unit));
-		retval = EIO;
-		goto err1;
*** 1364 LINES SKIPPED ***