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 *)¶m, 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