summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-01-02 00:02:57 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-01-02 00:02:57 +0000
commit16eef665101a8c1334032296ea7d1584ff9c7e57 (patch)
tree5cc9b881cb0bdd13a85c95e2cbd124b47ddc4645 /sys
parent890d46b55a21bec77e2f60dbf22d16199ccdbaa7 (diff)
Midi & sequencer support from NetBSD, mostly by Lennart Augustsson
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amiga/dev/aucc.c4
-rw-r--r--sys/arch/i386/conf/GENERIC15
-rw-r--r--sys/arch/i386/conf/files.i38610
-rw-r--r--sys/arch/i386/i386/conf.c8
-rw-r--r--sys/arch/i386/isa/clock.c82
-rw-r--r--sys/arch/i386/isa/spkrreg.h11
-rw-r--r--sys/arch/sparc/dev/amd7930.c4
-rw-r--r--sys/conf/files20
-rw-r--r--sys/dev/audio.c30
-rw-r--r--sys/dev/audio_if.h24
-rw-r--r--sys/dev/ic/i8253reg.h101
-rw-r--r--sys/dev/ic/opl.c594
-rw-r--r--sys/dev/ic/oplinstrs.c501
-rw-r--r--sys/dev/ic/oplreg.h146
-rw-r--r--sys/dev/ic/oplvar.h92
-rw-r--r--sys/dev/isa/files.isa30
-rw-r--r--sys/dev/isa/gus.c5
-rw-r--r--sys/dev/isa/midi_pcppi.c165
-rw-r--r--sys/dev/isa/mpu401.c226
-rw-r--r--sys/dev/isa/mpu401var.h57
-rw-r--r--sys/dev/isa/opl_isa.c105
-rw-r--r--sys/dev/isa/opl_sb.c113
-rw-r--r--sys/dev/isa/pas.c23
-rw-r--r--sys/dev/isa/pcppi.c235
-rw-r--r--sys/dev/isa/pcppireg.h11
-rw-r--r--sys/dev/isa/pcppivar.h37
-rw-r--r--sys/dev/isa/pss.c4
-rw-r--r--sys/dev/isa/sb.c136
-rw-r--r--sys/dev/isa/sb_isapnp.c23
-rw-r--r--sys/dev/isa/sbdsp.c641
-rw-r--r--sys/dev/isa/sbdspvar.h54
-rw-r--r--sys/dev/isa/spkr.c (renamed from sys/arch/i386/isa/spkr.c)189
-rw-r--r--sys/dev/isa/spkrio.h19
-rw-r--r--sys/dev/isa/wss.c4
-rw-r--r--sys/dev/isa/ym.c4
-rw-r--r--sys/dev/midi.c771
-rw-r--r--sys/dev/midi_if.h70
-rw-r--r--sys/dev/midisyn.c428
-rw-r--r--sys/dev/midisynvar.h98
-rw-r--r--sys/dev/midivar.h94
-rw-r--r--sys/dev/pci/eap.c4
-rw-r--r--sys/dev/pci/sv.c4
-rw-r--r--sys/dev/sequencer.c1382
-rw-r--r--sys/dev/sequencervar.h111
-rw-r--r--sys/sys/conf.h16
-rw-r--r--sys/sys/midiio.h253
46 files changed, 6312 insertions, 642 deletions
diff --git a/sys/arch/amiga/dev/aucc.c b/sys/arch/amiga/dev/aucc.c
index 34ba7ad2b2d..e9124768ced 100644
--- a/sys/arch/amiga/dev/aucc.c
+++ b/sys/arch/amiga/dev/aucc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aucc.c,v 1.4 1998/11/03 21:22:34 downsj Exp $ */
+/* $OpenBSD: aucc.c,v 1.5 1999/01/02 00:02:49 niklas Exp $ */
/* $NetBSD: aucc.c,v 1.22 1998/01/12 10:39:10 thorpej Exp $ */
/*
@@ -253,7 +253,7 @@ auccattach(parent, self, args)
return;
}
- audio_attach_mi(&sa_hw_if, 0, sc, &sc->sc_dev);
+ audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev);
}
int
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 8be2835406a..e03d6a9e24a 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.95 1998/12/28 03:50:38 jason Exp $
+# $OpenBSD: GENERIC,v 1.96 1999/01/02 00:02:54 niklas Exp $
# $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $
#
# GENERIC -- everything that's currently supported
@@ -213,7 +213,18 @@ wss0 at isa? port 0x530 irq 10 drq 0 # Windows Sound System
pas0 at isa? port 0x220 irq 7 drq 1 # ProAudio Spectrum
gus0 at isa? port 0x220 irq 7 drq 1 drq2 6 # Gravis UltraSound (drq2 is record drq)
ym* at isapnp?
-#spkr0 at pckbd? port 0x61
+
+# OPL[23] FM syntheziers
+#opl0 at isa? port 0x388 # use only if not attached to sound card
+opl* at sb?
+
+# MIDI support
+midi* at pcppi? # MIDI interface to the PC speaker
+midi* at sb? # SB MPU401 port
+midi* at opl? # OPL FM synth
+
+# The spkr driver provides a simple tone interface to the built in speaker.
+#spkr0 at pcppi? # PC speaker
#Audio Support
audio* at sb?
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 9f45e42b5d4..6ff9d50f3c0 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.48 1998/10/04 23:34:37 niklas Exp $
+# $OpenBSD: files.i386,v 1.49 1999/01/02 00:02:53 niklas Exp $
# $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $
#
# new style config file for i386 architecture
@@ -162,6 +162,9 @@ device pms
attach pms at pckbd
file arch/i386/isa/pms.c pms needs-flag
+device sysbeep
+attach sysbeep at pcppi
+
# Floppy disk controller
# XXX temporarily conflicts with arc, will soon move to files.isa
device fdc {drive = -1}
@@ -173,11 +176,6 @@ attach fd at fdc
file dev/isa/fd.c fd needs-flag
major {fd = 2}
-# PC speaker
-device spkr: tty
-attach spkr at pckbd
-file arch/i386/isa/spkr.c spkr needs-flag
-
# Adaptec AHA-284x VL SCSI controllers
# device declaration in sys/conf/files
attach ahc at isa with ahc_isa
diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c
index dc4990b7aaa..f71edc9603c 100644
--- a/sys/arch/i386/i386/conf.c
+++ b/sys/arch/i386/i386/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.49 1998/09/11 09:45:14 fgsch Exp $ */
+/* $OpenBSD: conf.c,v 1.50 1999/01/02 00:02:56 niklas Exp $ */
/* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */
/*
@@ -170,6 +170,10 @@ cdev_decl(mcd);
#include "tun.h"
#include "audio.h"
cdev_decl(audio);
+#include "midi.h"
+cdev_decl(midi);
+#include "sequencer.h"
+cdev_decl(music);
cdev_decl(svr4_net);
#include "joy.h"
#include "apm.h"
@@ -269,6 +273,8 @@ struct cdevsw cdevsw[] =
#else
cdev_notdef(), /* 51 */
#endif
+ cdev_midi_init(NMIDI,midi), /* 52: MIDI I/O */
+ cdev_midi_init(NSEQUENCER,sequencer), /* 53: sequencer I/O */
};
int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c
index e76195b349f..4d9c8802993 100644
--- a/sys/arch/i386/isa/clock.c
+++ b/sys/arch/i386/isa/clock.c
@@ -104,13 +104,35 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <dev/ic/mc146818reg.h>
#include <i386/isa/nvram.h>
#include <i386/isa/timerreg.h>
-#include <i386/isa/spkrreg.h>
+
+#include "pcppi.h"
+#if (NPCPPI > 0)
+#include <dev/isa/pcppivar.h>
+
+#define __BROKEN_INDIRECT_CONFIG /* XXX */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int sysbeepmatch __P((struct device *, void *, void *));
+#else
+int sysbeepmatch __P((struct device *, struct cfdata *, void *));
+#endif
+void sysbeepattach __P((struct device *, struct device *, void *));
+
+struct cfattach sysbeep_ca = {
+ sizeof(struct device), sysbeepmatch, sysbeepattach
+};
+
+struct cfdriver sysbeep_cd = {
+ NULL, "sysbeep", DV_DULL
+};
+
+static int ppi_attached;
+static pcppi_tag_t ppicookie;
+#endif /* PCPPI */
void spinwait __P((int));
void findcpuspeed __P((void));
int clockintr __P((void *));
int gettick __P((void));
-void sysbeepstop __P((void *));
void sysbeep __P((int, int));
int rtcget __P((mc_todregs *));
void rtcput __P((mc_todregs *));
@@ -275,48 +297,40 @@ delay(n)
}
}
-static int beeping;
+#if (NPCPPI > 0)
+int
+sysbeepmatch(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ return (!ppi_attached);
+}
void
-sysbeepstop(arg)
- void *arg;
+sysbeepattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
{
+ printf("\n");
- /* disable counter 2 */
- disable_intr();
- outb(PITAUX_PORT, inb(PITAUX_PORT) & ~PIT_SPKR);
- enable_intr();
- beeping = 0;
+ ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
+ ppi_attached = 1;
}
+#endif
void
sysbeep(pitch, period)
int pitch, period;
{
- static int last_pitch;
- extern int cold;
-
- if (cold)
- return; /* Can't beep yet. */
-
- if (beeping)
- untimeout(sysbeepstop, 0);
- if (pitch == 0 || period == 0) {
- sysbeepstop(0);
- last_pitch = 0;
- return;
- }
- if (!beeping || last_pitch != pitch) {
- disable_intr();
- outb(TIMER_MODE, TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
- outb(TIMER_CNTR2, TIMER_DIV(pitch) % 256);
- outb(TIMER_CNTR2, TIMER_DIV(pitch) / 256);
- outb(PITAUX_PORT, inb(PITAUX_PORT) | PIT_SPKR); /* enable counter 2 */
- enable_intr();
- }
- last_pitch = pitch;
- beeping = 1;
- timeout(sysbeepstop, 0, period);
+#if (NPCPPI > 0)
+ if (ppi_attached)
+ pcppi_bell(ppicookie, pitch, period, 0);
+#endif
}
unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
diff --git a/sys/arch/i386/isa/spkrreg.h b/sys/arch/i386/isa/spkrreg.h
deleted file mode 100644
index af1df50e2ad..00000000000
--- a/sys/arch/i386/isa/spkrreg.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* $NetBSD: spkrreg.h,v 1.2 1994/10/27 04:18:16 cgd Exp $ */
-
-/*
- * PIT port addresses and speaker control values
- */
-
-#define PITAUX_PORT 0x61 /* port of Programmable Peripheral Interface */
-#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */
-#define PIT_SPKRDATA 0x02 /* Direct to speaker */
-
-#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA)
diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c
index 607ebc3d309..ec1f11bf659 100644
--- a/sys/arch/sparc/dev/amd7930.c
+++ b/sys/arch/sparc/dev/amd7930.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: amd7930.c,v 1.14 1998/11/03 21:22:36 downsj Exp $ */
+/* $OpenBSD: amd7930.c,v 1.15 1999/01/02 00:02:49 niklas Exp $ */
/* $NetBSD: amd7930.c,v 1.37 1998/03/30 14:23:40 pk Exp $ */
/*
@@ -316,7 +316,7 @@ amd7930attach(parent, self, args)
evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
- audio_attach_mi(&sa_hw_if, 0, sc, &sc->sc_dev);
+ audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev);
}
static void
diff --git a/sys/conf/files b/sys/conf/files
index 49e1f392c13..fab01dce827 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.101 1998/12/26 12:35:10 provos Exp $
+# $OpenBSD: files,v 1.102 1999/01/02 00:02:48 niklas Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -13,14 +13,18 @@ define audio {}
define scsi {}
define ifmedia
define mii {[phy = -1]}
+define midibus { }
+define midisyn
# audio device attributes
define mulaw
define auconv
-# audio device, attaches to audio hardware driver
+# audio and midi devices, attaches to audio hardware driver
device audio
attach audio at audio
+device midi
+attach midi at midibus
# net device attributes - we have generic code for arc(net), ether(net),
# and fddi.
@@ -97,6 +101,11 @@ file dev/ic/ne2000.c ne
device com: tty
file dev/ic/com.c com & (com_isa | com_commulti | com_pcmcia | com_pica | com_algor | com_gsc) needs-flag
+# OPL2/OPL3 FM synth driver
+device opl: midibus, midisyn
+file dev/ic/opl.c opl
+file dev/ic/oplinstrs.c opl
+
# Cyclades Cyclom multiport serial cards
device cy: tty
file dev/ic/cy.c cy & (cy_isa | cy_pci) needs-flag
@@ -140,6 +149,8 @@ pseudo-device strip: ifnet
pseudo-device random
pseudo-device enc: ifnet
+pseudo-device sequencer
+
pseudo-device ksyms
file dev/ksyms.c ksyms needs-flag
@@ -169,7 +180,7 @@ file ddb/db_write_cmd.c ddb
file ddb/db_usrreq.c ddb
file ddb/db_hangman.c ddb
file dev/auconv.c auconv
-file dev/audio.c audio needs-flag
+file dev/audio.c audio | midi |midibus needs-flag
file dev/ccd.c ccd needs-flag
file dev/ic/ncr5380sbc.c ncr5380sbc
file dev/ic/ncr53c7xx.c ncr53c7xx
@@ -178,7 +189,10 @@ file dev/ic/pdq.c pdq
file dev/ic/pdq_ifsubr.c pdq
file dev/ic/dp8390.c dp8390nic
file dev/ic/rtl80x9.c rtl80x9
+file dev/midi.c midi | midibus needs-flag
+file dev/midisyn.c midisyn
file dev/mulaw.c mulaw
+file dev/sequencer.c sequencer needs-flag
file dev/vnd.c vnd needs-flag
file dev/rnd.c
file isofs/cd9660/cd9660_bmap.c cd9660
diff --git a/sys/dev/audio.c b/sys/dev/audio.c
index ae0a57a24ef..f9103165218 100644
--- a/sys/dev/audio.c
+++ b/sys/dev/audio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: audio.c,v 1.15 1998/11/20 15:57:19 deraadt Exp $ */
+/* $OpenBSD: audio.c,v 1.16 1999/01/02 00:02:39 niklas Exp $ */
/* $NetBSD: audio.c,v 1.105 1998/09/27 16:43:56 christos Exp $ */
/*
@@ -390,9 +390,8 @@ au_check_ports(sc, ports, mi, cls, name, mname, tbl)
* probed/attached to the hardware driver.
*/
void
-audio_attach_mi(ahwp, mhwp, hdlp, dev)
+audio_attach_mi(ahwp, hdlp, dev)
struct audio_hw_if *ahwp;
- struct midi_hw_if *mhwp;
void *hdlp;
struct device *dev;
{
@@ -404,14 +403,19 @@ audio_attach_mi(ahwp, mhwp, hdlp, dev)
arg.hdl = hdlp;
(void)config_found(dev, &arg, audioprint);
}
- if (mhwp != NULL) {
- arg.type = AUDIODEV_TYPE_MIDI;
- arg.hwif = mhwp;
- arg.hdl = hdlp;
- (void)config_found(dev, &arg, audioprint);
- }
}
+#include "midi.h"
+
+#if NAUDIO == 0 && (NMIDI > 0 || NMIDIBUS > 0)
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#endif
+
+#if NAUDIO > 0 || (NMIDI > 0 || NMIDIBUS > 0)
int
audioprint(aux, pnp)
void *aux;
@@ -428,6 +432,12 @@ audioprint(aux, pnp)
case AUDIODEV_TYPE_MIDI:
type = "midi";
break;
+ case AUDIODEV_TYPE_OPL:
+ type = "opl";
+ break;
+ case AUDIODEV_TYPE_MPU:
+ type = "mpu";
+ break;
default:
panic("audioprint: unknown type %d", arg->type);
}
@@ -436,6 +446,8 @@ audioprint(aux, pnp)
return (UNCONF);
}
+#endif /* NAUDIO > 0 || (NMIDI > 0 || NMIDIBUS > 0) */
+
#ifdef AUDIO_DEBUG
void audio_printsc __P((struct audio_softc *));
void audio_print_params __P((char *, struct audio_params *));
diff --git a/sys/dev/audio_if.h b/sys/dev/audio_if.h
index f449117c947..534c63f7bb5 100644
--- a/sys/dev/audio_if.h
+++ b/sys/dev/audio_if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: audio_if.h,v 1.7 1998/11/03 21:00:10 downsj Exp $ */
+/* $OpenBSD: audio_if.h,v 1.8 1999/01/02 00:02:39 niklas Exp $ */
/* $NetBSD: audio_if.h,v 1.24 1998/01/10 14:07:25 tv Exp $ */
/*
@@ -125,23 +125,6 @@ struct audio_hw_if {
void (*)(void *), void *, struct audio_params *));
};
-struct midi_info {
- char *name; /* Name of MIDI hardware */
- int props;
-};
-#define MIDI_PROP_OUT_INTR 1
-
-struct midi_hw_if {
- int (*open)__P((void *, int, /* open hardware */
- void (*)__P((void *, int)),
- void (*)__P((void *)),
- void *));
- void (*close)__P((void *)); /* close hardware */
- int (*output)__P((void *, int)); /* output a byte */
- void (*getinfo)__P((void *, struct midi_info *));
- int (*ioctl)__P((u_long, caddr_t, int, struct proc *));
-};
-
struct audio_attach_args {
int type;
void *hwif; /* either audio_hw_if * or midi_hw_if * */
@@ -149,9 +132,12 @@ struct audio_attach_args {
};
#define AUDIODEV_TYPE_AUDIO 0
#define AUDIODEV_TYPE_MIDI 1
+#define AUDIODEV_TYPE_OPL 2
+#define AUDIODEV_TYPE_MPU 3
/* Attach the MI driver(s) to the MD driver. */
-extern void audio_attach_mi __P((struct audio_hw_if *, struct midi_hw_if *, void *, struct device *));
+void audio_attach_mi __P((struct audio_hw_if *, void *, struct device *));
+int audioprint __P((void *, const char *));
/* Device identity flags */
#define SOUND_DEVICE 0
diff --git a/sys/dev/ic/i8253reg.h b/sys/dev/ic/i8253reg.h
new file mode 100644
index 00000000000..f1be2c08fab
--- /dev/null
+++ b/sys/dev/ic/i8253reg.h
@@ -0,0 +1,101 @@
+/* $OpenBSD: i8253reg.h,v 1.1 1999/01/02 00:02:42 niklas Exp $ */
+/* $NetBSD: i8253reg.h,v 1.5 1998/01/19 11:38:00 drochner Exp $ */
+
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Frequency of all three count-down timers; (TIMER_FREQ/freq) is the
+ * appropriate count to generate a frequency of freq hz.
+ */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 0 /* timer 0 counter port */
+#define TIMER_CNTR1 1 /* timer 1 counter port */
+#define TIMER_CNTR2 2 /* timer 2 counter port */
+#define TIMER_MODE 3 /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/dev/ic/opl.c b/sys/dev/ic/opl.c
new file mode 100644
index 00000000000..53049c04f4c
--- /dev/null
+++ b/sys/dev/ic/opl.c
@@ -0,0 +1,594 @@
+/* $OpenBSD: opl.c,v 1.1 1999/01/02 00:02:40 niklas Exp $ */
+/* $NetBSD: opl.c,v 1.7 1998/12/08 14:26:56 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The OPL3 (YMF262) manual can be found at
+ * ftp://ftp.yamahayst.com/pub/Fax_Back_Doc/Sound/YMF262.PDF
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/select.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+#include <dev/audio_if.h>
+
+#include <dev/midi_if.h>
+#include <dev/midivar.h>
+#include <dev/midisynvar.h>
+
+#include <dev/ic/oplreg.h>
+#include <dev/ic/oplvar.h>
+
+#ifdef AUDIO_DEBUG
+#define DPRINTF(x) if (opldebug) printf x
+#define DPRINTFN(n,x) if (opldebug >= (n)) printf x
+int opldebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+struct real_voice {
+ u_int8_t voice_num;
+ u_int8_t voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
+ u_int8_t iooffs; /* I/O port (left or right side) */
+ u_int8_t op[4]; /* Operator offsets */
+};
+
+struct opl_voice voicetab[] = {
+/* No I/O offs OP1 OP2 OP3 OP4 */
+/* --------------------------------------------------- */
+ { 0, OPL_L, {0x00, 0x03, 0x08, 0x0b}},
+ { 1, OPL_L, {0x01, 0x04, 0x09, 0x0c}},
+ { 2, OPL_L, {0x02, 0x05, 0x0a, 0x0d}},
+
+ { 3, OPL_L, {0x08, 0x0b, 0x00, 0x00}},
+ { 4, OPL_L, {0x09, 0x0c, 0x00, 0x00}},
+ { 5, OPL_L, {0x0a, 0x0d, 0x00, 0x00}},
+
+ { 6, OPL_L, {0x10, 0x13, 0x00, 0x00}},
+ { 7, OPL_L, {0x11, 0x14, 0x00, 0x00}},
+ { 8, OPL_L, {0x12, 0x15, 0x00, 0x00}},
+
+ { 0, OPL_R, {0x00, 0x03, 0x08, 0x0b}},
+ { 1, OPL_R, {0x01, 0x04, 0x09, 0x0c}},
+ { 2, OPL_R, {0x02, 0x05, 0x0a, 0x0d}},
+ { 3, OPL_R, {0x08, 0x0b, 0x00, 0x00}},
+ { 4, OPL_R, {0x09, 0x0c, 0x00, 0x00}},
+ { 5, OPL_R, {0x0a, 0x0d, 0x00, 0x00}},
+
+ { 6, OPL_R, {0x10, 0x13, 0x00, 0x00}},
+ { 7, OPL_R, {0x11, 0x14, 0x00, 0x00}},
+ { 8, OPL_R, {0x12, 0x15, 0x00, 0x00}}
+};
+
+static void opl_command(struct opl_softc *, int, int, int);
+void opl_reset(struct opl_softc *);
+void opl_freq_to_fnum (int freq, int *block, int *fnum);
+
+int oplsyn_open __P((midisyn *ms, int));
+void oplsyn_close __P((midisyn *));
+void oplsyn_reset __P((void *));
+void oplsyn_noteon __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void oplsyn_noteoff __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void oplsyn_keypressure __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void oplsyn_ctlchange __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void oplsyn_pitchbend __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void oplsyn_loadpatch __P((midisyn *, struct sysex_info *, struct uio *));
+
+
+void opl_set_op_reg __P((struct opl_softc *, int, int, int, u_char));
+void opl_set_ch_reg __P((struct opl_softc *, int, int, u_char));
+void opl_load_patch __P((struct opl_softc *, int));
+u_int32_t opl_get_block_fnum __P((int freq));
+int opl_calc_vol __P((int regbyte, int volume, int main_vol));
+
+struct cfdriver opl_cd = {
+ NULL, "opl", DV_DULL
+};
+
+struct midisyn_methods opl3_midi = {
+ oplsyn_open,
+ oplsyn_close,
+ 0,
+ 0,
+ oplsyn_noteon,
+ oplsyn_noteoff,
+ oplsyn_keypressure,
+ oplsyn_ctlchange,
+ 0,
+ 0,
+ oplsyn_pitchbend,
+ 0
+};
+
+void
+opl_attach(sc)
+ struct opl_softc *sc;
+{
+ int i;
+
+ if (!opl_find(sc)) {
+ printf("\nopl: find failed\n");
+ return;
+ }
+
+ sc->syn.mets = &opl3_midi;
+ sprintf(sc->syn.name, "%sYamaha OPL%d", sc->syn.name, sc->model);
+ sc->syn.data = sc;
+ sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
+ sc->syn.flags = MS_DOALLOC | MS_FREQXLATE;
+ midisyn_attach(&sc->mididev, &sc->syn);
+
+ /* Set up voice table */
+ for (i = 0; i < OPL3_NVOICE; i++)
+ sc->voices[i] = voicetab[i];
+
+ opl_reset(sc);
+
+ printf(": model OPL%d\n", sc->model);
+
+ midi_attach_mi(&midisyn_hw_if, &sc->syn, &sc->mididev.dev);
+}
+
+static void
+opl_command(sc, offs, addr, data)
+ struct opl_softc *sc;
+ int offs;
+ int addr, data;
+{
+ DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
+ sc, offs, addr, data));
+ offs += sc->offs;
+ bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
+ if (sc->model == OPL_2)
+ delay(10);
+ else
+ delay(6);
+ bus_space_write_1(sc->iot, sc->ioh, OPL_DATA+offs, data);
+ if (sc->model == OPL_2)
+ delay(30);
+ else
+ delay(6);
+}
+
+int
+opl_find(sc)
+ struct opl_softc *sc;
+{
+ u_int8_t status1, status2;
+
+ DPRINTFN(2,("opl_find: ioh=0x%x\n", (int)sc->ioh));
+ sc->model = OPL_2; /* worst case assumtion */
+
+ /* Reset timers 1 and 2 */
+ opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
+ OPL_TIMER1_MASK | OPL_TIMER2_MASK);
+ /* Reset the IRQ of the FM chip */
+ opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
+
+ /* get status bits */
+ status1 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
+
+ opl_command(sc, OPL_L, OPL_TIMER1, -2); /* wait 2 ticks */
+ opl_command(sc, OPL_L, OPL_TIMER_CONTROL, /* start timer1 */
+ OPL_TIMER1_START | OPL_TIMER2_MASK);
+ delay(1000); /* wait for timer to expire */
+
+ /* get status bits again */
+ status2 = bus_space_read_1(sc->iot,sc->ioh,OPL_STATUS+OPL_L+sc->offs);
+
+ opl_command(sc, OPL_L, OPL_TIMER_CONTROL,
+ OPL_TIMER1_MASK | OPL_TIMER2_MASK);
+ opl_command(sc, OPL_L, OPL_TIMER_CONTROL, OPL_IRQ_RESET);
+
+ DPRINTFN(2,("opl_find: %02x %02x\n", status1, status2));
+
+ if ((status1 & OPL_STATUS_MASK) != 0 ||
+ (status2 & OPL_STATUS_MASK) != (OPL_STATUS_IRQ | OPL_STATUS_FT1))
+ return (0);
+
+ switch(status1) {
+ case 0x00:
+ case 0x0f:
+ sc->model = OPL_3;
+ break;
+ case 0x06:
+ sc->model = OPL_2;
+ break;
+ default:
+ return 0;
+ }
+
+ DPRINTFN(2,("opl_find: OPL%d at 0x%x detected\n",
+ sc->model, (int)sc->ioh));
+ return (1);
+}
+
+void
+opl_set_op_reg(sc, base, voice, op, value)
+ struct opl_softc *sc;
+ int base;
+ int voice;
+ int op;
+ u_char value;
+{
+ struct opl_voice *v = &sc->voices[voice];
+ opl_command(sc, v->iooffs, base + v->op[op], value);
+}
+
+void
+opl_set_ch_reg(sc, base, voice, value)
+ struct opl_softc *sc;
+ int base;
+ int voice;
+ u_char value;
+{
+ struct opl_voice *v = &sc->voices[voice];
+ opl_command(sc, v->iooffs, base + v->voiceno, value);
+}
+
+
+void
+opl_load_patch(sc, v)
+ struct opl_softc *sc;
+ int v;
+{
+ struct opl_operators *p = sc->voices[v].patch;
+
+ opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]);
+ opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]);
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]);
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 1, p->ops[OO_KSL_LEV+1]);
+ opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 0, p->ops[OO_ATT_DEC+0]);
+ opl_set_op_reg(sc, OPL_ATTACK_DECAY, v, 1, p->ops[OO_ATT_DEC+1]);
+ opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 0, p->ops[OO_SUS_REL+0]);
+ opl_set_op_reg(sc, OPL_SUSTAIN_RELEASE, v, 1, p->ops[OO_SUS_REL+1]);
+ opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 0, p->ops[OO_WAV_SEL+0]);
+ opl_set_op_reg(sc, OPL_WAVE_SELECT, v, 1, p->ops[OO_WAV_SEL+1]);
+ opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, v, p->ops[OO_FB_CONN]);
+}
+
+#define OPL_FNUM_FAIL 0xffff
+u_int32_t
+opl_get_block_fnum(freq)
+ int freq;
+{
+ u_int32_t f_num = freq / 3125;
+ u_int32_t block = 0;
+
+ while (f_num > 0x3FF && block < 8) {
+ block++;
+ f_num >>= 1;
+ }
+
+ if (block > 7)
+ return (OPL_FNUM_FAIL);
+ else
+ return ((block << 10) | f_num);
+ }
+
+
+void
+opl_reset(sc)
+ struct opl_softc *sc;
+{
+ int i;
+
+ for (i = 1; i <= OPL_MAXREG; i++)
+ opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
+
+ opl_command(sc, OPL_L, OPL_TEST, OPL_ENABLE_WAVE_SELECT);
+ opl_command(sc, OPL_L, OPL_PERCUSSION, 0);
+ if (sc->model == OPL_3) {
+ opl_command(sc, OPL_R, OPL_MODE, OPL3_ENABLE);
+ opl_command(sc, OPL_R,OPL_CONNECTION_SELECT,OPL_NOCONNECTION);
+ }
+
+ sc->volume = 64;
+}
+
+int
+oplsyn_open(ms, flags)
+ midisyn *ms;
+ int flags;
+{
+ struct opl_softc *sc = ms->data;
+
+ DPRINTFN(2, ("oplsyn_open: %d\n", flags));
+
+ opl_reset(ms->data);
+ if (sc->spkrctl)
+ sc->spkrctl(sc->spkrarg, 1);
+ return (0);
+}
+
+void
+oplsyn_close(ms)
+ midisyn *ms;
+{
+ struct opl_softc *sc = ms->data;
+
+ DPRINTFN(2, ("oplsyn_close:\n"));
+
+ /*opl_reset(ms->data);*/
+ if (sc->spkrctl)
+ sc->spkrctl(sc->spkrarg, 0);
+}
+
+#if 0
+void
+oplsyn_getinfo(addr, sd)
+ void *addr;
+ struct synth_dev *sd;
+{
+ struct opl_softc *sc = addr;
+
+ sd->name = sc->model == OPL_2 ? "Yamaha OPL2" : "Yamaha OPL3";
+ sd->type = SYNTH_TYPE_FM;
+ sd->subtype = sc->model == OPL_2 ? SYNTH_SUB_FM_TYPE_ADLIB
+ : SYNTH_SUB_FM_TYPE_OPL3;
+ sd->capabilities = 0;
+}
+#endif
+
+void
+oplsyn_reset(addr)
+ void *addr;
+{
+ struct opl_softc *sc = addr;
+ DPRINTFN(3, ("oplsyn_reset:\n"));
+ opl_reset(sc);
+}
+
+int8_t opl_volume_table[128] =
+ {-64, -48, -40, -35, -32, -29, -27, -26,
+ -24, -23, -21, -20, -19, -18, -18, -17,
+ -16, -15, -15, -14, -13, -13, -12, -12,
+ -11, -11, -10, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -6, -6, -6,
+ -5, -5, -5, -5, -4, -4, -4, -4,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8};
+
+int
+opl_calc_vol(regbyte, volume, mainvol)
+ int regbyte;
+ int volume;
+ int mainvol;
+{
+ int level = ~regbyte & OPL_TOTAL_LEVEL_MASK;
+
+ if (mainvol > 127)
+ mainvol = 127;
+
+ volume = (volume * mainvol) / 127;
+
+ if (level)
+ level += opl_volume_table[volume];
+
+ if (level > OPL_TOTAL_LEVEL_MASK)
+ level = OPL_TOTAL_LEVEL_MASK;
+ if (level < 0)
+ level = 0;
+
+ return (~level & OPL_TOTAL_LEVEL_MASK);
+}
+
+void
+oplsyn_noteon(ms, voice, freq, vel)
+ midisyn *ms;
+ u_int32_t voice, freq, vel;
+{
+ struct opl_softc *sc = ms->data;
+ struct opl_voice *v;
+ struct opl_operators *p;
+ u_int32_t block_fnum;
+ int mult;
+ int c_mult, m_mult;
+ u_int8_t chars0, chars1, ksl0, ksl1, fbc;
+ u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
+ u_int8_t vol0, vol1;
+
+ DPRINTFN(3, ("oplsyn_noteon: %p %d %d\n", sc, voice,
+ MIDISYN_FREQ_TO_HZ(freq)));
+
+#ifdef DIAGNOSTIC
+ if (voice < 0 || voice >= sc->syn.nvoice) {
+ printf("oplsyn_noteon: bad voice %d\n", voice);
+ return;
+ }
+#endif
+ /* Turn off old note */
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, 0xff);
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, 0xff);
+ opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, 0);
+
+ v = &sc->voices[voice];
+
+ p = &opl2_instrs[MS_GETPGM(ms, voice)];
+ v->patch = p;
+ opl_load_patch(sc, voice);
+
+ mult = 1;
+ for (;;) {
+ block_fnum = opl_get_block_fnum(freq / mult);
+ if (block_fnum != OPL_FNUM_FAIL)
+ break;
+ mult *= 2;
+ if (mult == 16)
+ mult = 15;
+ }
+
+ chars0 = p->ops[OO_CHARS+0];
+ chars1 = p->ops[OO_CHARS+1];
+ m_mult = (chars0 & OPL_MULTIPLE_MASK) * mult;
+ c_mult = (chars1 & OPL_MULTIPLE_MASK) * mult;
+ if ((block_fnum == OPL_FNUM_FAIL) || (m_mult > 15) || (c_mult > 15)) {
+ printf("oplsyn_noteon: frequence out of range %d\n",
+ MIDISYN_FREQ_TO_HZ(freq));
+ return;
+ }
+ r20m = (chars0 &~ OPL_MULTIPLE_MASK) | m_mult;
+ r20c = (chars1 &~ OPL_MULTIPLE_MASK) | c_mult;
+
+ /* 2 voice */
+ ksl0 = p->ops[OO_KSL_LEV+0];
+ ksl1 = p->ops[OO_KSL_LEV+1];
+ if (p->ops[OO_FB_CONN] & 0x01) {
+ vol0 = opl_calc_vol(ksl0, vel, sc->volume);
+ vol1 = opl_calc_vol(ksl1, vel, sc->volume);
+ } else {
+ vol0 = ksl0;
+ vol1 = opl_calc_vol(ksl1, vel, sc->volume);
+ }
+ r40m = (ksl0 & OPL_KSL_MASK) | vol0;
+ r40c = (ksl1 & OPL_KSL_MASK) | vol1;
+
+ rA0 = block_fnum & 0xFF;
+ rB0 = (block_fnum >> 8) | OPL_KEYON_BIT;
+
+ v->rB0 = rB0;
+
+ fbc = p->ops[OO_FB_CONN];
+ if (sc->model == OPL_3) {
+ fbc &= ~OPL_STEREO_BITS;
+ /* XXX use pan */
+ fbc |= OPL_VOICE_TO_LEFT | OPL_VOICE_TO_RIGHT;
+ }
+ opl_set_ch_reg(sc, OPL_FEEDBACK_CONNECTION, voice, fbc);
+
+ opl_set_op_reg(sc, OPL_AM_VIB, voice, 0, r20m);
+ opl_set_op_reg(sc, OPL_AM_VIB, voice, 1, r20c);
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 0, r40m);
+ opl_set_op_reg(sc, OPL_KSL_LEVEL, voice, 1, r40c);
+ opl_set_ch_reg(sc, OPL_FNUM_LOW, voice, rA0);
+ opl_set_ch_reg(sc, OPL_KEYON_BLOCK, voice, rB0);
+}
+
+void
+oplsyn_noteoff(ms, voice, note, vel)
+ midisyn *ms;
+ u_int32_t voice, note, vel;
+{
+ struct opl_softc *sc = ms->data;
+ struct opl_voice *v;
+
+ DPRINTFN(3, ("oplsyn_noteoff: %p %d %d\n", sc, voice,
+ MIDISYN_FREQ_TO_HZ(note)));
+
+#ifdef DIAGNOSTIC
+ if (voice < 0 || voice >= sc->syn.nvoice) {
+ printf("oplsyn_noteoff: bad voice %d\n", voice);
+ return;
+ }
+#endif
+ v = &sc->voices[voice];
+ opl_set_ch_reg(sc, 0xB0, voice, v->rB0 & ~OPL_KEYON_BIT);
+}
+
+void
+oplsyn_keypressure(ms, voice, note, vel)
+ midisyn *ms;
+ u_int32_t voice, note, vel;
+{
+#ifdef AUDIO_DEBUG
+ struct opl_softc *sc = ms->data;
+ DPRINTFN(1, ("oplsyn_keypressure: %p %d\n", sc, note));
+#endif
+}
+
+void
+oplsyn_ctlchange(ms, voice, parm, w14)
+ midisyn *ms;
+ u_int32_t voice, parm, w14;
+{
+#ifdef AUDIO_DEBUG
+ struct opl_softc *sc = ms->data;
+ DPRINTFN(1, ("oplsyn_ctlchange: %p %d\n", sc, voice));
+#endif
+}
+
+void
+oplsyn_pitchbend(ms, voice, parm, x)
+ midisyn *ms;
+ u_int32_t voice, parm, x;
+{
+#ifdef AUDIO_DEBUG
+ struct opl_softc *sc = ms->data;
+ DPRINTFN(1, ("oplsyn_pitchbend: %p %d\n", sc, voice));
+#endif
+}
+
+void
+oplsyn_loadpatch(ms, sysex, uio)
+ midisyn *ms;
+ struct sysex_info *sysex;
+ struct uio *uio;
+{
+#if 0
+ struct opl_softc *sc = ms->data;
+ struct sbi_instrument ins;
+
+ DPRINTFN(1, ("oplsyn_loadpatch: %p\n", sc));
+
+ memcpy(&ins, sysex, sizeof *sysex);
+ if (uio->uio_resid >= sizeof ins - sizeof *sysex)
+ return EINVAL;
+ uiomove((char *)&ins + sizeof *sysex, sizeof ins - sizeof *sysex, uio);
+ /* XXX */
+#endif
+}
diff --git a/sys/dev/ic/oplinstrs.c b/sys/dev/ic/oplinstrs.c
new file mode 100644
index 00000000000..61f4f7d8461
--- /dev/null
+++ b/sys/dev/ic/oplinstrs.c
@@ -0,0 +1,501 @@
+/* $OpenBSD: oplinstrs.c,v 1.1 1999/01/02 00:02:41 niklas Exp $ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/select.h>
+
+#include <machine/bus.h>
+
+#include <dev/midivar.h>
+#include <dev/midisynvar.h>
+
+#include <dev/ic/oplreg.h>
+#include <dev/ic/oplvar.h>
+
+/*
+ * Operator settings for the OPL2 and OPL3 FM synths.
+ * These tables are indexed by the General MIDI instrument number.
+ */
+struct opl_operators opl3_instrs[OPL_NINSTR] = {
+{ 1, { 0x23, 0x01, 0x15, 0x00, 0xfd, 0x84, 0x7c, 0xf5, 0x03, 0x00, 0x10,
+ 0x03, 0x01, 0x5d, 0x00, 0xf2, 0xf4, 0x35, 0xf5, 0x00, 0x04, 0x11, } },
+{ 1, { 0x03, 0x01, 0x7d, 0x00, 0xf3, 0xf3, 0xf5, 0xf5, 0x00, 0x04, 0x10,
+ 0x03, 0x01, 0x55, 0x00, 0xf2, 0xf2, 0xf5, 0xf5, 0x00, 0x04, 0x11, } },
+{ 1, { 0x03, 0x01, 0x4d, 0x00, 0xfb, 0xf3, 0x55, 0xc5, 0x04, 0x04, 0x20,
+ 0x03, 0x01, 0xce, 0x00, 0xf3, 0xf3, 0x55, 0xd5, 0x00, 0x04, 0x21, } },
+{ 1, { 0x03, 0x01, 0xd7, 0x00, 0xf3, 0xf2, 0xf5, 0xf5, 0x04, 0x04, 0x20,
+ 0x03, 0x01, 0xd5, 0x00, 0xf3, 0xf3, 0xf5, 0xf5, 0x00, 0x04, 0x21, } },
+{ 1, { 0x16, 0x01, 0x57, 0x00, 0xff, 0xf3, 0x8a, 0x66, 0x00, 0x00, 0x2c,
+ 0x0b, 0x81, 0x2b, 0x00, 0xe5, 0xe2, 0xb5, 0x86, 0x00, 0x00, 0x21, } },
+{ 1, { 0x0a, 0x01, 0x5f, 0x00, 0xf4, 0xf4, 0x87, 0x86, 0x00, 0x00, 0x10,
+ 0x03, 0x01, 0xcc, 0x00, 0xf2, 0xe2, 0x86, 0x86, 0x00, 0x00, 0x11, } },
+{ 1, { 0x22, 0x01, 0xd1, 0x80, 0xe3, 0xf3, 0x79, 0xa7, 0x04, 0x04, 0x34,
+ 0x22, 0x01, 0x96, 0x00, 0xf2, 0xf3, 0x79, 0xa7, 0x04, 0x04, 0x31, } },
+{ 1, { 0x22, 0x01, 0x9c, 0x00, 0xf4, 0xf3, 0x19, 0xa6, 0x05, 0x05, 0x10,
+ 0x22, 0x01, 0x97, 0x00, 0xf4, 0xf3, 0x19, 0xe6, 0x04, 0x04, 0x11, } },
+{ 1, { 0x1b, 0x19, 0x5a, 0x00, 0xf4, 0xe3, 0xf6, 0xa2, 0x00, 0x00, 0x30,
+ 0x1a, 0x11, 0x57, 0x00, 0xf3, 0xf2, 0xb2, 0xa3, 0x00, 0x00, 0x31, } },
+{ 1, { 0x1b, 0x17, 0x5a, 0x00, 0xd6, 0xf3, 0x53, 0x53, 0x00, 0x00, 0x20,
+ 0x1a, 0x11, 0x49, 0x00, 0xd1, 0xf3, 0x52, 0x52, 0x00, 0x00, 0x21, } },
+{ 1, { 0x1b, 0x14, 0x5a, 0x00, 0xf6, 0x63, 0xf6, 0xa3, 0x00, 0x00, 0x30,
+ 0x1b, 0x11, 0x52, 0x00, 0xd3, 0xf2, 0xb2, 0xa3, 0x00, 0x00, 0x31, } },
+{ 1, { 0x8b, 0x84, 0x5a, 0x00, 0xd7, 0xf1, 0x15, 0x95, 0x00, 0x00, 0x30,
+ 0x9b, 0x81, 0x49, 0x00, 0xdc, 0xd2, 0x25, 0xb5, 0x00, 0x00, 0x31, } },
+{ 1, { 0x08, 0x01, 0xc0, 0x00, 0xfd, 0xf6, 0x56, 0x68, 0x00, 0x00, 0x20,
+ 0x95, 0x81, 0x40, 0x00, 0xfe, 0xf0, 0x27, 0x05, 0x00, 0x00, 0x21, } },
+{ 1, { 0x08, 0x03, 0xc0, 0x00, 0xfa, 0xf8, 0x56, 0x66, 0x00, 0x00, 0x30,
+ 0x97, 0x81, 0x40, 0x00, 0xdf, 0xf8, 0x26, 0x06, 0x00, 0x00, 0x31, } },
+{ 1, { 0x03, 0x00, 0x95, 0x80, 0xf3, 0xf3, 0x33, 0x23, 0x00, 0x00, 0x30,
+ 0x03, 0x00, 0x8c, 0x80, 0xf4, 0xf3, 0x23, 0x03, 0x00, 0x00, 0x31, } },
+{ 1, { 0x01, 0x00, 0x8b, 0x00, 0xa7, 0x94, 0xf9, 0x36, 0x06, 0x05, 0x30,
+ 0x02, 0x81, 0x18, 0x80, 0xf6, 0xf4, 0x79, 0x55, 0x04, 0x04, 0x31, } },
+{ 1, { 0x24, 0x24, 0x40, 0x00, 0xfd, 0xfb, 0xfd, 0x0e, 0x00, 0x00, 0x20,
+ 0x20, 0x20, 0x95, 0x00, 0xfb, 0xf6, 0x0e, 0x0e, 0x00, 0x00, 0x21, } },
+{ 1, { 0x04, 0x24, 0x17, 0x00, 0xfe, 0xf7, 0xb7, 0x67, 0x00, 0x00, 0x20,
+ 0x20, 0xa0, 0x14, 0x00, 0xf9, 0xf6, 0x06, 0x07, 0x00, 0x00, 0x21, } },
+{ 1, { 0xa2, 0x20, 0x1e, 0x00, 0xb9, 0xa9, 0x36, 0x0e, 0x00, 0x00, 0x30,
+ 0xb4, 0x20, 0x1a, 0x00, 0x79, 0x77, 0x51, 0x4c, 0x04, 0x00, 0x31, } },
+{ 1, { 0x25, 0xa1, 0x23, 0x00, 0x74, 0x60, 0x11, 0x05, 0x00, 0x00, 0x12,
+ 0xb0, 0xb0, 0xd3, 0x00, 0x74, 0x60, 0x12, 0x05, 0x04, 0x01, 0x11, } },
+{ 1, { 0x22, 0x21, 0x24, 0x40, 0x76, 0x76, 0x06, 0x06, 0x04, 0x04, 0x10,
+ 0x20, 0x21, 0x21, 0x00, 0x76, 0x66, 0x06, 0x06, 0x00, 0x02, 0x11, } },
+{ 1, { 0x22, 0x21, 0x1b, 0x00, 0x76, 0x76, 0x07, 0x07, 0x00, 0x04, 0x30,
+ 0x21, 0x21, 0x19, 0x00, 0x76, 0x66, 0x07, 0x07, 0x00, 0x02, 0x31, } },
+{ 1, { 0x21, 0x21, 0x20, 0x00, 0x93, 0x73, 0x09, 0x09, 0x04, 0x04, 0x30,
+ 0x21, 0x21, 0x27, 0x00, 0x76, 0x76, 0x09, 0x09, 0x04, 0x04, 0x31, } },
+{ 1, { 0x21, 0x21, 0x1e, 0x00, 0x76, 0x66, 0x09, 0x19, 0x04, 0x05, 0x30,
+ 0x21, 0x21, 0x22, 0x00, 0x76, 0x66, 0x29, 0x19, 0x04, 0x04, 0x31, } },
+{ 1, { 0x1b, 0x11, 0x4c, 0x00, 0xfe, 0xf2, 0xfe, 0xe3, 0x04, 0x00, 0x10,
+ 0x31, 0x11, 0x4c, 0x00, 0xf2, 0xf2, 0x45, 0xf4, 0x04, 0x00, 0x11, } },
+{ 1, { 0x30, 0x05, 0x00, 0x0b, 0xf2, 0xfe, 0x49, 0x43, 0x02, 0x01, 0x21,
+ 0x01, 0x00, 0x00, 0x00, 0xf2, 0xf3, 0xe7, 0x9d, 0x01, 0x02, 0x21, } },
+{ 1, { 0x34, 0x04, 0x00, 0x16, 0xf2, 0xfd, 0x49, 0x43, 0x00, 0x00, 0x31,
+ 0x01, 0x01, 0x00, 0x00, 0xf2, 0xf3, 0xe7, 0x9d, 0x00, 0x00, 0x31, } },
+{ 1, { 0x03, 0x23, 0x00, 0x00, 0xfb, 0xfc, 0x49, 0x64, 0x06, 0x00, 0x19,
+ 0x01, 0x01, 0x00, 0x00, 0xf4, 0xf6, 0xc4, 0xc4, 0x02, 0x06, 0x11, } },
+{ 1, { 0x01, 0x01, 0x06, 0x00, 0xf6, 0xf3, 0x27, 0xe7, 0x05, 0x01, 0x30,
+ 0x02, 0x01, 0x05, 0x00, 0xfa, 0x65, 0x96, 0x9b, 0x04, 0x04, 0x31, } },
+{ 1, { 0x21, 0x21, 0xc1, 0x40, 0xf2, 0xf3, 0x13, 0x16, 0x00, 0x04, 0x30,
+ 0x21, 0x21, 0x03, 0x00, 0x97, 0x96, 0xae, 0x26, 0x03, 0x05, 0x31, } },
+{ 1, { 0x21, 0x21, 0xc1, 0x00, 0xf2, 0xf2, 0x16, 0x16, 0x00, 0x04, 0x30,
+ 0x21, 0x20, 0x03, 0x00, 0xc7, 0x90, 0x46, 0x16, 0x03, 0x03, 0x31, } },
+{ 1, { 0x0b, 0x01, 0x40, 0x40, 0x65, 0xf2, 0x1a, 0x3e, 0x00, 0x03, 0x2c,
+ 0x05, 0x0a, 0x00, 0x40, 0xe2, 0x54, 0x1a, 0x1a, 0x02, 0x01, 0x21, } },
+{ 0, { 0x21, 0x21, 0x12, 0x00, 0xe4, 0xd3, 0x15, 0xa6, 0x00, 0x00, 0x30, } },
+{ 1, { 0x21, 0x01, 0x00, 0x0b, 0xf2, 0xf2, 0x49, 0x97, 0x04, 0x05, 0x31,
+ 0x01, 0x01, 0x00, 0x00, 0xf6, 0xf3, 0xe7, 0x9d, 0x01, 0x04, 0x31, } },
+{ 1, { 0x21, 0x01, 0x00, 0x08, 0xf2, 0xf2, 0x49, 0x97, 0x04, 0x05, 0x11,
+ 0x01, 0x01, 0x00, 0x00, 0xf6, 0xf3, 0xe7, 0x9d, 0x01, 0x04, 0x11, } },
+{ 1, { 0x01, 0x01, 0xc0, 0x08, 0xf2, 0xc4, 0x6a, 0x97, 0x00, 0x00, 0x39,
+ 0x01, 0x01, 0x00, 0x00, 0x91, 0xf2, 0xe7, 0x6d, 0x00, 0x00, 0x31, } },
+{ 1, { 0x01, 0x0b, 0x00, 0x08, 0xfd, 0xfa, 0x49, 0x87, 0x06, 0x04, 0x11,
+ 0x01, 0x01, 0x00, 0x00, 0xf3, 0xf3, 0xb7, 0x9d, 0x04, 0x04, 0x11, } },
+{ 0, { 0x26, 0x21, 0x24, 0x00, 0xf6, 0xf2, 0x87, 0xf7, 0x04, 0x04, 0x30, } },
+{ 1, { 0x21, 0x01, 0x08, 0x40, 0xf5, 0xf2, 0x47, 0xf7, 0x00, 0x00, 0x20,
+ 0x21, 0x01, 0x07, 0x40, 0xf5, 0xf2, 0x47, 0xf7, 0x00, 0x00, 0x29, } },
+{ 1, { 0xc1, 0x01, 0x00, 0x21, 0xf2, 0xf2, 0x48, 0x97, 0x00, 0x00, 0x21,
+ 0x01, 0x01, 0x0a, 0x00, 0xf2, 0xf2, 0x97, 0x77, 0x00, 0x00, 0x20, } },
+{ 1, { 0x22, 0x21, 0xca, 0x00, 0xb4, 0x44, 0x26, 0x06, 0x04, 0x04, 0x3c,
+ 0x22, 0x01, 0xcc, 0x00, 0x89, 0x5d, 0x16, 0x06, 0x04, 0x04, 0x31, } },
+{ 1, { 0x24, 0x21, 0xcb, 0x00, 0x88, 0x66, 0x26, 0x16, 0x04, 0x04, 0x3c,
+ 0x34, 0x21, 0xc4, 0x00, 0x86, 0x66, 0x66, 0x06, 0x04, 0x04, 0x31, } },
+{ 1, { 0x22, 0x01, 0xcb, 0x00, 0x72, 0x5f, 0x46, 0x86, 0x04, 0x04, 0x36,
+ 0x22, 0x21, 0xcd, 0x00, 0x76, 0x54, 0x36, 0x06, 0x04, 0x04, 0x31, } },
+{ 1, { 0x22, 0x01, 0xff, 0x00, 0x86, 0x6f, 0x06, 0x08, 0x04, 0x04, 0x36,
+ 0x22, 0x21, 0xd2, 0x00, 0x74, 0x54, 0x16, 0x06, 0x04, 0x04, 0x31, } },
+{ 1, { 0x60, 0x61, 0x00, 0x09, 0x68, 0x53, 0x04, 0x45, 0x02, 0x03, 0x11,
+ 0x61, 0x60, 0x00, 0x00, 0x54, 0x78, 0x54, 0x35, 0x01, 0x03, 0x11, } },
+{ 1, { 0x00, 0x00, 0x07, 0x00, 0xf9, 0xf6, 0xf1, 0x34, 0x03, 0x02, 0x16,
+ 0x00, 0x00, 0x0c, 0x00, 0x89, 0xb5, 0xf1, 0x34, 0x03, 0x02, 0x11, } },
+{ 1, { 0x12, 0x01, 0xd0, 0x00, 0xb5, 0xc3, 0x23, 0xe3, 0x04, 0x00, 0x30,
+ 0x12, 0x11, 0xd9, 0x00, 0xe5, 0xa2, 0x15, 0xf3, 0x04, 0x00, 0x31, } },
+{ 1, { 0x11, 0x10, 0xd0, 0x00, 0xe4, 0xd3, 0xe4, 0xf4, 0x01, 0x00, 0x30,
+ 0x14, 0x10, 0x14, 0x00, 0xf6, 0xf3, 0xf4, 0xf4, 0x02, 0x02, 0x31, } },
+{ 1, { 0x21, 0x21, 0x1b, 0xc0, 0xa9, 0x63, 0x23, 0x25, 0x00, 0x04, 0x3e,
+ 0x21, 0x21, 0x22, 0x40, 0xa9, 0x43, 0x23, 0x24, 0x00, 0x04, 0x31, } },
+{ 1, { 0x21, 0x21, 0x1f, 0xc0, 0xa9, 0x33, 0x23, 0x15, 0x00, 0x04, 0x3e,
+ 0x21, 0x21, 0x23, 0x80, 0x60, 0x33, 0x23, 0x25, 0x00, 0x04, 0x31, } },
+{ 1, { 0x20, 0x01, 0x00, 0x0c, 0x52, 0x50, 0xb6, 0x15, 0x02, 0x01, 0x31,
+ 0x21, 0x20, 0x00, 0x40, 0x44, 0x41, 0x04, 0x27, 0x01, 0x02, 0x31, } },
+{ 1, { 0x22, 0x01, 0x40, 0xc2, 0x51, 0x31, 0xa4, 0xf4, 0x04, 0x01, 0x11,
+ 0x21, 0x21, 0x00, 0x40, 0x70, 0x34, 0xf4, 0x74, 0x01, 0x04, 0x11, } },
+{ 1, { 0x21, 0x21, 0x10, 0x00, 0x61, 0x66, 0x04, 0x45, 0x00, 0x04, 0x3a,
+ 0x20, 0x21, 0x1c, 0x00, 0x63, 0x63, 0x05, 0x04, 0x00, 0x00, 0x31, } },
+{ 1, { 0x21, 0x21, 0x16, 0x00, 0xa6, 0x77, 0x66, 0x06, 0x00, 0x00, 0x10,
+ 0x20, 0x21, 0xd8, 0x00, 0x66, 0x68, 0x36, 0x06, 0x00, 0x00, 0x11, } },
+{ 1, { 0x21, 0x21, 0x12, 0x00, 0x75, 0x67, 0x66, 0x06, 0x00, 0x00, 0x10,
+ 0x21, 0x21, 0x2d, 0x00, 0x62, 0x68, 0x36, 0x06, 0x00, 0x00, 0x11, } },
+{ 1, { 0x02, 0x01, 0x0e, 0x00, 0x76, 0x64, 0x34, 0x35, 0x00, 0x04, 0x10,
+ 0x01, 0x00, 0x2d, 0x00, 0x66, 0x63, 0x35, 0x04, 0x04, 0x00, 0x11, } },
+{ 1, { 0x21, 0x21, 0x23, 0x00, 0x72, 0x72, 0x9b, 0x3b, 0x01, 0x04, 0x30,
+ 0x21, 0x21, 0x23, 0x00, 0x82, 0x92, 0x9b, 0x3b, 0x01, 0x04, 0x31, } },
+{ 1, { 0x21, 0x21, 0x23, 0x00, 0x63, 0x62, 0x9b, 0x3b, 0x01, 0x04, 0x30,
+ 0x21, 0x21, 0x21, 0x00, 0x73, 0x82, 0x9b, 0x3b, 0x01, 0x04, 0x31, } },
+{ 1, { 0x01, 0x01, 0x14, 0x00, 0x62, 0xe6, 0x0b, 0x2b, 0x05, 0x05, 0x26,
+ 0x21, 0x22, 0x13, 0x00, 0x55, 0x72, 0x1b, 0x2b, 0x04, 0x00, 0x21, } },
+{ 1, { 0x01, 0x21, 0x11, 0x00, 0x60, 0x62, 0xfb, 0x7b, 0x05, 0x00, 0x10,
+ 0x01, 0x21, 0x10, 0x00, 0x60, 0x62, 0x3b, 0x7b, 0x05, 0x00, 0x11, } },
+{ 0, { 0x21, 0x21, 0x23, 0x00, 0x41, 0x81, 0x94, 0xf6, 0x00, 0x00, 0x2e, } },
+{ 1, { 0x22, 0x61, 0x4c, 0x40, 0x75, 0xf1, 0x37, 0xb7, 0x01, 0x05, 0x20,
+ 0x21, 0x20, 0x4d, 0x00, 0x56, 0x72, 0x07, 0x17, 0x05, 0x02, 0x21, } },
+{ 1, { 0x21, 0x21, 0x04, 0x00, 0x82, 0x71, 0xcb, 0x2b, 0x01, 0x01, 0x26,
+ 0x21, 0x21, 0x11, 0x00, 0x75, 0x80, 0x8b, 0x3b, 0x00, 0x00, 0x21, } },
+{ 1, { 0x21, 0x21, 0x83, 0x40, 0x84, 0xa2, 0x3b, 0x3b, 0x01, 0x00, 0x26,
+ 0x21, 0x21, 0x0e, 0x00, 0x74, 0x73, 0x7b, 0x3b, 0x00, 0x00, 0x21, } },
+{ 1, { 0x01, 0x02, 0x15, 0x00, 0x70, 0x70, 0xe7, 0xe8, 0x05, 0x00, 0x10,
+ 0x01, 0x00, 0x42, 0x00, 0x70, 0x70, 0xf8, 0xe8, 0x07, 0x02, 0x11, } },
+{ 1, { 0x01, 0x01, 0x13, 0x00, 0x70, 0x70, 0xe9, 0xe9, 0x05, 0x00, 0x10,
+ 0x01, 0x40, 0x47, 0x40, 0x70, 0x70, 0xe9, 0xe9, 0x07, 0x02, 0x11, } },
+{ 1, { 0x01, 0x01, 0x15, 0x00, 0x70, 0x70, 0xeb, 0xea, 0x05, 0x00, 0x10,
+ 0x01, 0x40, 0x09, 0x00, 0x70, 0x70, 0xeb, 0xeb, 0x07, 0x02, 0x11, } },
+{ 1, { 0x01, 0x04, 0x11, 0x00, 0xa4, 0x67, 0xbb, 0x6a, 0x00, 0x00, 0x20,
+ 0x01, 0x02, 0x0c, 0x00, 0xd0, 0x80, 0xeb, 0xeb, 0x01, 0x02, 0x21, } },
+{ 1, { 0x11, 0x34, 0x17, 0x00, 0x70, 0x61, 0x29, 0x29, 0x00, 0x00, 0x30,
+ 0x31, 0x34, 0xff, 0x40, 0x60, 0x60, 0x09, 0x09, 0x00, 0x02, 0x31, } },
+{ 1, { 0x01, 0x24, 0x11, 0x00, 0xf0, 0x80, 0x29, 0x09, 0x00, 0x00, 0x10,
+ 0x31, 0x24, 0xda, 0x00, 0x80, 0x80, 0x09, 0x09, 0x00, 0x00, 0x11, } },
+{ 1, { 0x01, 0x24, 0x13, 0x00, 0x60, 0x80, 0x22, 0x09, 0x00, 0x00, 0x10,
+ 0x31, 0x24, 0x86, 0x00, 0x80, 0x80, 0x05, 0x09, 0x00, 0x00, 0x11, } },
+{ 1, { 0x32, 0x31, 0x1d, 0x00, 0xa2, 0x51, 0x16, 0x26, 0x04, 0x00, 0x3a,
+ 0x32, 0x31, 0x45, 0x00, 0xfe, 0x55, 0x52, 0x15, 0x04, 0x00, 0x31, } },
+{ 1, { 0x24, 0xa2, 0x20, 0x00, 0x67, 0x65, 0xf6, 0x06, 0x00, 0x00, 0x10,
+ 0x24, 0xa2, 0x1c, 0x00, 0x7f, 0x67, 0x27, 0x06, 0x00, 0x00, 0x11, } },
+{ 1, { 0x22, 0xa1, 0x26, 0x00, 0x65, 0x67, 0x66, 0x06, 0x00, 0x00, 0x10,
+ 0x02, 0x21, 0x2a, 0x00, 0xa2, 0x6f, 0x36, 0x06, 0x00, 0x00, 0x11, } },
+{ 1, { 0x21, 0x31, 0x11, 0x00, 0x85, 0x68, 0x66, 0x06, 0x00, 0x00, 0x10,
+ 0x32, 0x31, 0x19, 0x00, 0xd5, 0x68, 0x39, 0x06, 0x00, 0x00, 0x11, } },
+{ 1, { 0x20, 0xa0, 0x00, 0x00, 0x77, 0x77, 0x08, 0x58, 0x00, 0x00, 0x2e,
+ 0x24, 0x21, 0xd3, 0x00, 0x76, 0x76, 0xa9, 0x08, 0x04, 0x00, 0x21, } },
+{ 1, { 0x2b, 0x26, 0x12, 0x00, 0x73, 0x67, 0x68, 0x97, 0x00, 0x00, 0x1e,
+ 0x22, 0x21, 0x14, 0x00, 0x66, 0x60, 0x46, 0xb6, 0x00, 0x00, 0x11, } },
+{ 1, { 0x61, 0xa1, 0x16, 0x00, 0x67, 0x77, 0x56, 0x06, 0x02, 0x00, 0x30,
+ 0x21, 0x01, 0x15, 0x00, 0xd7, 0x40, 0x66, 0xb6, 0x02, 0x00, 0x31, } },
+{ 1, { 0x61, 0xa1, 0x31, 0x00, 0xc4, 0x50, 0x56, 0xb6, 0x02, 0x00, 0x20,
+ 0x61, 0x81, 0x30, 0x00, 0xc4, 0x50, 0x66, 0xb6, 0x01, 0x00, 0x21, } },
+{ 1, { 0x31, 0x31, 0x2b, 0x00, 0x57, 0x68, 0x46, 0x06, 0x04, 0x00, 0x30,
+ 0x32, 0x31, 0x30, 0x00, 0x47, 0x68, 0x69, 0x06, 0x04, 0x00, 0x31, } },
+{ 1, { 0x21, 0x21, 0x00, 0x0d, 0xd4, 0xc2, 0x1b, 0x26, 0x04, 0x06, 0x21,
+ 0x21, 0x21, 0x00, 0x00, 0xc6, 0xd0, 0x19, 0x27, 0x04, 0x06, 0x21, } },
+{ 1, { 0x21, 0x20, 0x11, 0x00, 0xd4, 0xc2, 0x1b, 0x36, 0x04, 0x03, 0x10,
+ 0x21, 0x21, 0x10, 0x00, 0xc9, 0xd0, 0x49, 0x37, 0x04, 0x01, 0x11, } },
+{ 1, { 0x22, 0xa1, 0x0e, 0x00, 0x76, 0x67, 0x66, 0x06, 0x00, 0x00, 0x26,
+ 0x22, 0x21, 0x1e, 0x00, 0x75, 0x75, 0x06, 0x06, 0x02, 0x00, 0x21, } },
+{ 1, { 0xd1, 0xa0, 0x00, 0x00, 0xb7, 0x87, 0x66, 0x06, 0x02, 0x02, 0x20,
+ 0x01, 0x60, 0x14, 0x00, 0x75, 0xb5, 0x66, 0x06, 0x02, 0x02, 0x21, } },
+{ 1, { 0x30, 0x22, 0x0c, 0x00, 0xf4, 0x62, 0xa0, 0x0e, 0x00, 0x00, 0x10,
+ 0x20, 0x21, 0x14, 0x00, 0x77, 0x90, 0x4e, 0x1c, 0x00, 0x00, 0x11, } },
+{ 1, { 0x20, 0x32, 0x1a, 0x00, 0x76, 0x47, 0x64, 0x05, 0x00, 0x00, 0x16,
+ 0x31, 0x21, 0x1b, 0x00, 0x75, 0x75, 0x03, 0x05, 0x00, 0x00, 0x11, } },
+{ 1, { 0x03, 0x06, 0x00, 0x3f, 0xf2, 0xf0, 0xa6, 0xfb, 0x00, 0x00, 0x17,
+ 0x01, 0x00, 0x15, 0x00, 0xf0, 0xf3, 0xf8, 0xc8, 0x00, 0x00, 0x10, } },
+{ 1, { 0x02, 0x21, 0x0b, 0x00, 0xf3, 0xf1, 0xfb, 0x2b, 0x01, 0x01, 0x16,
+ 0x01, 0x21, 0xe1, 0x00, 0xf3, 0xf0, 0xfb, 0x2b, 0x05, 0x00, 0x11, } },
+{ 1, { 0x12, 0x12, 0xc0, 0x00, 0xf2, 0xe2, 0x23, 0x55, 0x00, 0x00, 0x10,
+ 0x31, 0x30, 0x1c, 0x00, 0x69, 0x52, 0x33, 0x15, 0x02, 0x02, 0x11, } },
+{ 1, { 0x01, 0x31, 0x18, 0x00, 0x21, 0x22, 0x53, 0x55, 0x00, 0x00, 0x30,
+ 0x11, 0x31, 0xd4, 0x00, 0x21, 0x21, 0x53, 0x45, 0x01, 0x00, 0x31, } },
+{ 1, { 0x20, 0x01, 0x00, 0x00, 0xc3, 0xf0, 0xf4, 0xf5, 0x02, 0x00, 0x10,
+ 0x01, 0x21, 0x08, 0x00, 0x32, 0x20, 0x14, 0x04, 0x05, 0x00, 0x11, } },
+{ 0, { 0x30, 0x20, 0xd1, 0x00, 0xa2, 0x63, 0x40, 0x48, 0x00, 0x00, 0x20, } },
+{ 1, { 0x06, 0x21, 0x08, 0x00, 0xf0, 0x45, 0xe4, 0x36, 0x00, 0x00, 0x30,
+ 0x01, 0x21, 0x46, 0x00, 0xe5, 0x40, 0x34, 0x05, 0x04, 0x00, 0x31, } },
+{ 1, { 0x21, 0x21, 0x40, 0x00, 0x63, 0x30, 0x83, 0x13, 0x00, 0x00, 0x10,
+ 0x21, 0x21, 0x17, 0x00, 0x63, 0x40, 0xa3, 0x13, 0x05, 0x04, 0x11, } },
+{ 1, { 0x31, 0x30, 0x00, 0xc4, 0x60, 0x64, 0x15, 0xf8, 0x00, 0x02, 0x35,
+ 0x31, 0x31, 0x00, 0x00, 0xb0, 0xd0, 0xc5, 0x45, 0x00, 0x00, 0x31, } },
+{ 1, { 0x31, 0x12, 0x00, 0x8c, 0x44, 0x12, 0xf4, 0xb3, 0x00, 0x00, 0x25,
+ 0x10, 0x30, 0x00, 0x00, 0x30, 0x74, 0xb4, 0x04, 0x01, 0x01, 0x21, } },
+{ 1, { 0x08, 0x83, 0xc0, 0x00, 0xfb, 0xf5, 0x66, 0x68, 0x00, 0x00, 0x10,
+ 0x21, 0x21, 0x14, 0x00, 0xf0, 0xde, 0x25, 0x05, 0x00, 0x00, 0x11, } },
+{ 1, { 0x08, 0x01, 0x01, 0x00, 0x33, 0x31, 0xf2, 0xf2, 0x00, 0x00, 0x20,
+ 0x01, 0x01, 0x04, 0x00, 0x31, 0x32, 0xf2, 0xf2, 0x01, 0x00, 0x21, } },
+{ 1, { 0x17, 0x91, 0xc0, 0x00, 0xf1, 0xf1, 0x31, 0x22, 0x00, 0x00, 0x18,
+ 0x95, 0x91, 0x9b, 0x00, 0xf1, 0xf1, 0x21, 0x23, 0x00, 0x00, 0x11, } },
+{ 1, { 0x01, 0x17, 0x00, 0x00, 0xd2, 0xd8, 0x24, 0x34, 0x00, 0x00, 0x20,
+ 0x01, 0x20, 0x17, 0x00, 0xea, 0xe1, 0x34, 0x14, 0x02, 0x02, 0x21, } },
+{ 1, { 0x06, 0x01, 0x08, 0x00, 0xf0, 0xf5, 0xe4, 0x34, 0x00, 0x00, 0x30,
+ 0x01, 0xa0, 0x44, 0x00, 0xe5, 0xe0, 0x34, 0x44, 0x02, 0x02, 0x31, } },
+{ 1, { 0x04, 0x01, 0x02, 0x00, 0x11, 0x21, 0x32, 0x22, 0x00, 0x00, 0x18,
+ 0x01, 0x01, 0x41, 0x00, 0x11, 0x11, 0x24, 0x23, 0x00, 0x00, 0x11, } },
+{ 1, { 0x05, 0x01, 0xc0, 0x00, 0xf8, 0xe1, 0xd3, 0x03, 0x00, 0x00, 0x20,
+ 0x21, 0x21, 0x10, 0x00, 0x69, 0x52, 0x33, 0x13, 0x01, 0x00, 0x21, } },
+{ 1, { 0x02, 0x21, 0x00, 0x00, 0x83, 0x61, 0xf3, 0x23, 0x01, 0x00, 0x16,
+ 0x01, 0x21, 0x0b, 0x00, 0x73, 0x52, 0xf3, 0x23, 0x05, 0x00, 0x11, } },
+{ 1, { 0x25, 0x01, 0x12, 0x00, 0xf7, 0xf8, 0x44, 0x04, 0x04, 0x04, 0x30,
+ 0xa7, 0x01, 0x17, 0x00, 0x80, 0xf3, 0x64, 0x74, 0x04, 0x04, 0x31, } },
+{ 1, { 0x01, 0x05, 0x00, 0x25, 0xf4, 0xf8, 0xa6, 0xfb, 0x04, 0x00, 0x35,
+ 0x01, 0x02, 0x10, 0x00, 0xf4, 0xf6, 0xfb, 0xc7, 0x00, 0x04, 0x30, } },
+{ 1, { 0x04, 0x07, 0x09, 0x00, 0xfa, 0xf8, 0xa6, 0xfb, 0x00, 0x00, 0x24,
+ 0x01, 0x01, 0x16, 0x00, 0xf3, 0xf3, 0x95, 0xc5, 0x04, 0x04, 0x21, } },
+{ 1, { 0x01, 0x05, 0x00, 0x25, 0xf4, 0xfa, 0xa4, 0xfb, 0x04, 0x04, 0x25,
+ 0x01, 0x01, 0x18, 0x00, 0xf4, 0xf3, 0xf5, 0xc5, 0x04, 0x04, 0x20, } },
+{ 1, { 0x09, 0x03, 0x00, 0x00, 0xf8, 0xf8, 0x6e, 0x6e, 0x04, 0x04, 0x20,
+ 0x01, 0x86, 0x00, 0x00, 0xf4, 0xf7, 0x16, 0xea, 0x00, 0x00, 0x21, } },
+{ 1, { 0x11, 0x32, 0x0c, 0x00, 0xd0, 0x80, 0xf3, 0x05, 0x00, 0x00, 0x30,
+ 0x31, 0x24, 0xc9, 0x00, 0x40, 0x50, 0x09, 0x09, 0x00, 0x04, 0x31, } },
+{ 1, { 0x24, 0x20, 0xc9, 0x00, 0xaa, 0x95, 0x58, 0x08, 0x04, 0x03, 0x30,
+ 0x24, 0x20, 0xc9, 0x00, 0xc7, 0x72, 0x88, 0x28, 0x05, 0x03, 0x31, } },
+{ 1, { 0x11, 0x32, 0x0c, 0x00, 0xd0, 0x80, 0xf3, 0x05, 0x00, 0x00, 0x10,
+ 0x31, 0x24, 0xcc, 0x00, 0x60, 0x60, 0x06, 0x06, 0x00, 0x04, 0x11, } },
+{ 1, { 0x16, 0x19, 0x4f, 0x00, 0xf6, 0xf3, 0x53, 0x53, 0x00, 0x00, 0x30,
+ 0x15, 0x14, 0x41, 0x00, 0xf1, 0xf3, 0x52, 0x52, 0x06, 0x06, 0x31, } },
+{ 1, { 0x17, 0x12, 0x00, 0x00, 0xfa, 0xf5, 0x57, 0x58, 0x00, 0x00, 0x10,
+ 0x14, 0x12, 0x40, 0x00, 0xf7, 0xf5, 0x52, 0x59, 0x06, 0x06, 0x11, } },
+{ 1, { 0x08, 0x01, 0x1f, 0x00, 0xc6, 0x82, 0x37, 0x95, 0x00, 0x00, 0x36,
+ 0x05, 0x11, 0x0f, 0x00, 0x65, 0x52, 0x55, 0x75, 0x00, 0x00, 0x31, } },
+{ 1, { 0x02, 0x01, 0x09, 0x00, 0xfc, 0xf7, 0xd6, 0xf7, 0x02, 0x00, 0x20,
+ 0x07, 0x03, 0x3f, 0xc0, 0xfa, 0xf5, 0x4e, 0xfe, 0x00, 0x00, 0x21, } },
+{ 1, { 0x1a, 0x30, 0x00, 0x00, 0xfb, 0xf3, 0x57, 0x54, 0x00, 0x01, 0x11,
+ 0x11, 0x10, 0x40, 0x00, 0xc5, 0xc5, 0x52, 0x57, 0x01, 0x00, 0x11, } },
+{ 1, { 0x12, 0x30, 0x01, 0x00, 0xfb, 0xf3, 0xa7, 0x53, 0x00, 0x00, 0x30,
+ 0x10, 0x10, 0xff, 0x00, 0xf4, 0xc4, 0x52, 0x57, 0x00, 0x00, 0x31, } },
+{ 1, { 0x2b, 0x0b, 0x00, 0x00, 0xff, 0xf7, 0x0e, 0xfe, 0x00, 0x00, 0x3e,
+ 0x00, 0x20, 0xc0, 0x00, 0xf6, 0xff, 0xfe, 0x0c, 0x02, 0x00, 0x31, } },
+{ 1, { 0x2a, 0x0b, 0x00, 0x00, 0xff, 0x2f, 0x0e, 0x0e, 0x04, 0x04, 0x2e,
+ 0x28, 0x09, 0x00, 0x00, 0xf9, 0x29, 0x0e, 0x0e, 0x04, 0x04, 0x21, } },
+{ 1, { 0x0b, 0x0b, 0x00, 0x00, 0x64, 0x77, 0xf8, 0xf8, 0x04, 0x04, 0x1e,
+ 0x0b, 0x09, 0x10, 0x00, 0x56, 0x59, 0xf8, 0xe8, 0x04, 0x04, 0x11, } },
+{ 1, { 0x2b, 0x25, 0x05, 0x00, 0x79, 0x77, 0x05, 0xa5, 0x00, 0x00, 0x2e,
+ 0x26, 0x01, 0x10, 0x00, 0x66, 0x76, 0xb9, 0xde, 0x04, 0x00, 0x21, } },
+{ 0, { 0x30, 0x10, 0x00, 0x00, 0x11, 0x11, 0x00, 0x32, 0x00, 0x03, 0x3e, } },
+{ 0, { 0x0a, 0x09, 0x00, 0x00, 0x59, 0x69, 0xfe, 0xfe, 0x00, 0x00, 0x21, } },
+{ 1, { 0x0a, 0x02, 0x0b, 0x00, 0xe5, 0xe4, 0xf5, 0xf5, 0x05, 0x00, 0x30,
+ 0x08, 0x02, 0x43, 0x00, 0xf5, 0xf4, 0xf5, 0xf5, 0x03, 0x00, 0x31, } },
+{ 1, { 0x0b, 0x04, 0x00, 0x80, 0x82, 0x77, 0xfa, 0xfa, 0x00, 0x05, 0x2e,
+ 0x20, 0x20, 0x11, 0x00, 0xf7, 0xfa, 0xfa, 0xfb, 0x00, 0x00, 0x21, } },
+{ 1, { 0x2b, 0x27, 0x00, 0x00, 0xf0, 0x23, 0x01, 0x13, 0x00, 0x05, 0x3e,
+ 0x20, 0x20, 0x7f, 0x00, 0xfb, 0xf4, 0xe5, 0xf5, 0x00, 0x00, 0x31, } },
+{ 1, { 0x0b, 0x01, 0x40, 0xc0, 0xf5, 0xf7, 0x67, 0x64, 0x00, 0x00, 0x1e,
+ 0x07, 0x01, 0x3f, 0x00, 0xf7, 0xfa, 0x34, 0x9e, 0x04, 0x04, 0x11, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x52, 0x11, 0x1b, 0x00, 0x68, 0xd6, 0x1c, 0x43, 0x05, 0x00, 0x2a, } },
+{ 0, { 0x40, 0x01, 0x18, 0x00, 0x68, 0xd6, 0x19, 0x46, 0x02, 0x00, 0x1e, } },
+{ 0, { 0x02, 0x04, 0x07, 0x00, 0xfa, 0xda, 0xbb, 0xbe, 0x00, 0x00, 0x38, } },
+{ 1, { 0x12, 0x01, 0xc0, 0x00, 0xf3, 0xf6, 0xf0, 0xf6, 0x07, 0x00, 0x3e,
+ 0x10, 0x10, 0x0c, 0x00, 0xf0, 0x91, 0x00, 0x05, 0x03, 0x06, 0x30, } },
+{ 0, { 0x01, 0x05, 0x07, 0x00, 0x9a, 0x9a, 0xb6, 0xbd, 0x02, 0x00, 0x3e, } },
+{ 1, { 0x17, 0x01, 0xc0, 0x00, 0xf3, 0xf8, 0xf0, 0xb7, 0x00, 0x00, 0x1e,
+ 0x10, 0x10, 0x0c, 0x00, 0xf0, 0xd1, 0x60, 0x75, 0x00, 0x06, 0x10, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf7, 0x00, 0x00, 0x16, } },
+{ 0, { 0x2f, 0x31, 0x07, 0x00, 0x73, 0xc4, 0xc2, 0xb4, 0x00, 0x00, 0x2a, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf7, 0x01, 0x00, 0x36, } },
+{ 0, { 0x13, 0x10, 0xcd, 0x80, 0xf5, 0xd5, 0x92, 0xd4, 0x01, 0x00, 0x1a, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf5, 0x00, 0x00, 0x16, } },
+{ 0, { 0x3c, 0x31, 0x90, 0x00, 0x73, 0xc4, 0xb1, 0xf3, 0x00, 0x00, 0x2a, } },
+};
+
+struct opl_operators opl2_instrs[OPL_NINSTR] = {
+{ 0, { 0x01, 0x10, 0x1b, 0x00, 0xc3, 0x92, 0x23, 0x62, 0x02, 0x01, 0x1e, } },
+{ 0, { 0x03, 0x01, 0x7d, 0x00, 0xf3, 0xf3, 0xf5, 0xf5, 0x00, 0x04, 0x30, } },
+{ 0, { 0x03, 0x01, 0x61, 0x00, 0xfb, 0xf5, 0xf5, 0xf5, 0x04, 0x04, 0x30, } },
+{ 0, { 0x03, 0x01, 0xd7, 0x00, 0xf3, 0xf2, 0xf5, 0xf5, 0x04, 0x04, 0x20, } },
+{ 0, { 0x35, 0x12, 0xd4, 0x00, 0x94, 0x92, 0x91, 0x62, 0x02, 0x00, 0x2e, } },
+{ 0, { 0x11, 0x10, 0x00, 0x00, 0xe1, 0x92, 0x63, 0x72, 0x02, 0x00, 0x17, } },
+{ 0, { 0x22, 0x01, 0x8a, 0x00, 0xe3, 0xf4, 0x79, 0xa8, 0x05, 0x04, 0x24, } },
+{ 0, { 0x22, 0x01, 0x9c, 0x00, 0xf4, 0xf3, 0x18, 0x55, 0x05, 0x05, 0x30, } },
+{ 0, { 0x02, 0x01, 0x00, 0x00, 0x93, 0xb6, 0x74, 0x45, 0x00, 0x00, 0x25, } },
+{ 0, { 0x1b, 0x17, 0x5a, 0x00, 0xd6, 0xf3, 0x53, 0x53, 0x00, 0x00, 0x20, } },
+{ 0, { 0x1b, 0x14, 0x5a, 0x00, 0xf6, 0x63, 0xf6, 0x73, 0x00, 0x00, 0x20, } },
+{ 0, { 0x8b, 0x84, 0x5a, 0x00, 0xd8, 0xf4, 0x16, 0xe5, 0x00, 0x00, 0x30, } },
+{ 0, { 0x08, 0x01, 0xc0, 0x00, 0xfd, 0xf6, 0x56, 0x68, 0x00, 0x00, 0x30, } },
+{ 0, { 0x08, 0x03, 0xc0, 0x00, 0xf9, 0xf7, 0x56, 0x68, 0x00, 0x00, 0x30, } },
+{ 0, { 0x35, 0x11, 0xcd, 0x00, 0xf2, 0xf2, 0xf1, 0xf2, 0x00, 0x00, 0x34, } },
+{ 0, { 0x18, 0x02, 0x9a, 0x00, 0xb3, 0xf0, 0x8a, 0xd3, 0x01, 0x01, 0x1c, } },
+{ 0, { 0x24, 0x61, 0xd4, 0x00, 0x81, 0x61, 0x06, 0xa6, 0x03, 0x00, 0x12, } },
+{ 0, { 0xa3, 0x21, 0x95, 0x00, 0x81, 0xd1, 0xf9, 0x0d, 0x01, 0x00, 0x12, } },
+{ 0, { 0x25, 0x61, 0xd2, 0x00, 0x81, 0xd1, 0x06, 0x35, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x27, 0x21, 0x23, 0x00, 0x74, 0x60, 0x11, 0x05, 0x00, 0x00, 0x22, } },
+{ 0, { 0x22, 0x21, 0x24, 0x00, 0x76, 0x76, 0x06, 0x06, 0x04, 0x04, 0x30, } },
+{ 0, { 0x22, 0x21, 0x1b, 0x00, 0x66, 0x66, 0x05, 0x06, 0x00, 0x04, 0x30, } },
+{ 0, { 0x22, 0xb2, 0x15, 0x00, 0x41, 0x31, 0x04, 0x04, 0x03, 0x01, 0x22, } },
+{ 0, { 0x21, 0x21, 0x1e, 0x00, 0x76, 0x66, 0x04, 0x17, 0x04, 0x05, 0x10, } },
+{ 0, { 0x01, 0x11, 0xc0, 0x00, 0xb5, 0xd2, 0x52, 0x72, 0x01, 0x00, 0x20, } },
+{ 0, { 0x23, 0x11, 0x8a, 0x00, 0x85, 0xd2, 0x54, 0x73, 0x01, 0x00, 0x28, } },
+{ 0, { 0x04, 0x01, 0x12, 0x00, 0xfd, 0xf2, 0x43, 0xa6, 0x00, 0x00, 0x20, } },
+{ 0, { 0x23, 0x01, 0x00, 0x00, 0xfc, 0xf4, 0x67, 0xc6, 0x03, 0x02, 0x20, } },
+{ 0, { 0x01, 0x01, 0x06, 0x00, 0xf6, 0xf6, 0x27, 0x25, 0x04, 0x01, 0x10, } },
+{ 0, { 0x21, 0x21, 0xc1, 0x00, 0xf2, 0xf2, 0x13, 0x16, 0x00, 0x04, 0x30, } },
+{ 0, { 0x21, 0x21, 0xc1, 0x00, 0xf2, 0xf2, 0x14, 0x15, 0x00, 0x04, 0x10, } },
+{ 0, { 0x0b, 0x01, 0x40, 0x00, 0x65, 0xf2, 0x1a, 0x3e, 0x00, 0x03, 0x3c, } },
+{ 0, { 0x01, 0x01, 0x0f, 0x00, 0xd8, 0x82, 0x96, 0x66, 0x00, 0x00, 0x10, } },
+{ 0, { 0x01, 0x01, 0x0b, 0x00, 0xf2, 0xf6, 0x97, 0xe6, 0x04, 0x01, 0x20, } },
+{ 0, { 0x01, 0x01, 0x04, 0x00, 0xf2, 0xf6, 0x95, 0xe6, 0x04, 0x01, 0x10, } },
+{ 0, { 0x01, 0x01, 0x48, 0x00, 0xc7, 0x91, 0x96, 0xe6, 0x00, 0x00, 0x30, } },
+{ 0, { 0x0b, 0x01, 0x00, 0x00, 0xfa, 0xf3, 0x86, 0xb6, 0x06, 0x01, 0x10, } },
+{ 0, { 0x0b, 0x01, 0x00, 0x00, 0xfa, 0xf3, 0x87, 0xb7, 0x02, 0x01, 0x10, } },
+{ 0, { 0xc1, 0x01, 0x00, 0x00, 0xe5, 0xf5, 0x65, 0x95, 0x00, 0x00, 0x21, } },
+{ 0, { 0xc1, 0x01, 0x00, 0x00, 0xf2, 0xf2, 0x45, 0x96, 0x00, 0x00, 0x21, } },
+{ 0, { 0x62, 0x61, 0xca, 0x00, 0xb4, 0x44, 0x25, 0x06, 0x04, 0x04, 0x3e, } },
+{ 0, { 0x24, 0x21, 0xcb, 0x00, 0x88, 0x66, 0x24, 0x15, 0x04, 0x04, 0x1e, } },
+{ 0, { 0x24, 0x21, 0xd3, 0x00, 0x88, 0x66, 0x24, 0x16, 0x04, 0x04, 0x1e, } },
+{ 0, { 0x71, 0x61, 0x23, 0x00, 0x51, 0x52, 0x43, 0x15, 0x00, 0x00, 0x1e, } },
+{ 0, { 0xa2, 0xa1, 0xcb, 0x00, 0x84, 0x51, 0x13, 0x55, 0x00, 0x02, 0x2a, } },
+{ 0, { 0xf1, 0xe2, 0x00, 0x80, 0xf5, 0xfd, 0xa8, 0xac, 0x00, 0x00, 0x37, } },
+{ 0, { 0x22, 0x02, 0x00, 0x00, 0xd4, 0xc4, 0x34, 0x26, 0x01, 0x00, 0x29, } },
+{ 0, { 0x10, 0x10, 0x55, 0x00, 0x30, 0xb0, 0x09, 0x04, 0x03, 0x03, 0x2a, } },
+{ 0, { 0x62, 0xa2, 0x8b, 0x40, 0x71, 0x43, 0x33, 0xe5, 0x01, 0x00, 0x24, } },
+{ 0, { 0x61, 0x21, 0x8b, 0x40, 0x71, 0x43, 0x33, 0xe5, 0x01, 0x00, 0x14, } },
+{ 0, { 0x61, 0x22, 0x8b, 0x40, 0x71, 0x43, 0x33, 0xe5, 0x01, 0x00, 0x26, } },
+{ 0, { 0x01, 0x21, 0x13, 0x00, 0x51, 0x44, 0x15, 0x04, 0x02, 0x01, 0x10, } },
+{ 0, { 0xf3, 0xc1, 0x95, 0x00, 0x32, 0x43, 0x40, 0x46, 0x02, 0x01, 0x3e, } },
+{ 0, { 0xf3, 0xc1, 0x51, 0x00, 0xa2, 0x62, 0xa4, 0x84, 0x00, 0x01, 0x1e, } },
+{ 0, { 0xe0, 0xe3, 0x4d, 0x00, 0x52, 0x65, 0x51, 0x35, 0x02, 0x00, 0x36, } },
+{ 0, { 0x20, 0x00, 0x07, 0x00, 0xf7, 0x96, 0xb5, 0x46, 0x00, 0x00, 0x20, } },
+{ 0, { 0x21, 0xa1, 0x1c, 0x00, 0x53, 0x52, 0x14, 0x35, 0x00, 0x00, 0x1c, } },
+{ 0, { 0x21, 0xa2, 0x1a, 0x80, 0x53, 0x52, 0x19, 0x39, 0x00, 0x00, 0x2a, } },
+{ 0, { 0x21, 0x21, 0x21, 0x00, 0x63, 0x85, 0x8c, 0x2c, 0x00, 0x00, 0x3c, } },
+{ 0, { 0xe1, 0xe3, 0x98, 0x00, 0x71, 0x81, 0xa5, 0x96, 0x01, 0x00, 0x1c, } },
+{ 0, { 0x31, 0x21, 0x55, 0x00, 0x53, 0xaa, 0x54, 0x15, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x21, 0xa2, 0x1b, 0x80, 0x53, 0x52, 0x15, 0x36, 0x00, 0x00, 0x3a, } },
+{ 0, { 0x21, 0x21, 0x20, 0x00, 0x83, 0x81, 0x75, 0x86, 0x05, 0x04, 0x1e, } },
+{ 0, { 0x21, 0x21, 0x8e, 0x80, 0x9b, 0x90, 0x25, 0x05, 0x00, 0x00, 0x18, } },
+{ 0, { 0x01, 0x02, 0x15, 0x00, 0x70, 0x70, 0xe5, 0xe6, 0x05, 0x00, 0x20, } },
+{ 0, { 0x01, 0x01, 0x14, 0x00, 0x80, 0x70, 0xe5, 0xe6, 0x05, 0x00, 0x30, } },
+{ 0, { 0x01, 0x01, 0x12, 0x00, 0x80, 0x70, 0xe5, 0xe6, 0x05, 0x00, 0x30, } },
+{ 0, { 0x01, 0xa3, 0x91, 0x00, 0x51, 0x52, 0x57, 0x77, 0x01, 0x00, 0x2a, } },
+{ 0, { 0x71, 0x64, 0xc9, 0x00, 0x6e, 0x8b, 0x13, 0x07, 0x00, 0x01, 0x12, } },
+{ 0, { 0xa1, 0xa3, 0x25, 0x00, 0x71, 0x82, 0xa5, 0x97, 0x00, 0x00, 0x10, } },
+{ 0, { 0x01, 0x24, 0x13, 0x00, 0xf0, 0x80, 0x22, 0x07, 0x00, 0x00, 0x20, } },
+{ 0, { 0x32, 0x31, 0x1d, 0x00, 0xa2, 0x51, 0x14, 0x24, 0x04, 0x00, 0x3a, } },
+{ 0, { 0x21, 0xa1, 0x20, 0x00, 0x77, 0x65, 0x43, 0x06, 0x00, 0x00, 0x20, } },
+{ 0, { 0x01, 0xa1, 0xa4, 0x00, 0x6a, 0x63, 0x64, 0x66, 0x02, 0x00, 0x20, } },
+{ 0, { 0x22, 0x21, 0xac, 0x00, 0x67, 0x65, 0x89, 0x28, 0x00, 0x00, 0x2e, } },
+{ 0, { 0xe3, 0xa1, 0xe9, 0x00, 0x6d, 0x65, 0x8d, 0x29, 0x00, 0x00, 0x1e, } },
+{ 0, { 0x20, 0x26, 0x10, 0x00, 0xd8, 0x68, 0x68, 0x97, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x22, 0x21, 0x6c, 0x00, 0x47, 0x65, 0x0f, 0x2a, 0x00, 0x00, 0x1e, } },
+{ 0, { 0xe1, 0xe2, 0xff, 0x00, 0x70, 0x62, 0x0c, 0xfb, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x31, 0x31, 0x2b, 0x00, 0x57, 0x68, 0x46, 0x06, 0x04, 0x00, 0x20, } },
+{ 0, { 0x91, 0x13, 0x97, 0x80, 0x2a, 0x42, 0x02, 0xf3, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0xa2, 0x91, 0x00, 0x51, 0x52, 0x53, 0x76, 0x01, 0x00, 0x3e, } },
+{ 0, { 0x23, 0x21, 0xd8, 0x00, 0x50, 0x72, 0x00, 0xf8, 0x03, 0x00, 0x1e, } },
+{ 0, { 0xd1, 0xa0, 0x00, 0x00, 0xb7, 0x87, 0x66, 0x06, 0x02, 0x02, 0x10, } },
+{ 0, { 0x00, 0x15, 0x4f, 0x00, 0x71, 0x52, 0x53, 0x74, 0x00, 0x00, 0x26, } },
+{ 0, { 0xe0, 0xe1, 0xc5, 0x00, 0x52, 0x65, 0xa1, 0x35, 0x00, 0x00, 0x36, } },
+{ 0, { 0xb0, 0xb1, 0x00, 0x00, 0xd5, 0x26, 0x13, 0x13, 0x01, 0x00, 0x35, } },
+{ 0, { 0x21, 0xa1, 0x1d, 0x80, 0x53, 0x52, 0x14, 0x35, 0x00, 0x00, 0x2a, } },
+{ 0, { 0x21, 0xa1, 0x1b, 0x00, 0x51, 0x82, 0x15, 0x45, 0x01, 0x00, 0x10, } },
+{ 0, { 0xe1, 0xa1, 0xa3, 0x00, 0x6e, 0x65, 0x8f, 0x06, 0x01, 0x00, 0x2e, } },
+{ 0, { 0x20, 0x01, 0x00, 0x00, 0xc3, 0xf0, 0xf4, 0xf5, 0x02, 0x00, 0x10, } },
+{ 0, { 0xf1, 0xc2, 0x51, 0x00, 0xa2, 0x63, 0x40, 0x46, 0x00, 0x00, 0x3e, } },
+{ 0, { 0xe1, 0xa2, 0x4d, 0x00, 0x71, 0x43, 0x33, 0xe5, 0x01, 0x00, 0x16, } },
+{ 0, { 0x21, 0x21, 0x40, 0x00, 0x63, 0x30, 0x83, 0x15, 0x00, 0x00, 0x10, } },
+{ 0, { 0x24, 0x21, 0x24, 0x00, 0x67, 0x65, 0x8f, 0x2a, 0x02, 0x00, 0x3e, } },
+{ 0, { 0x24, 0x21, 0x15, 0x00, 0x27, 0x65, 0x88, 0x26, 0x02, 0x00, 0x1e, } },
+{ 0, { 0x08, 0x83, 0xc0, 0x00, 0xfb, 0xf5, 0x66, 0x66, 0x00, 0x00, 0x10, } },
+{ 0, { 0xf4, 0xe1, 0x54, 0x00, 0x25, 0xf0, 0xbd, 0x47, 0x00, 0x01, 0x10, } },
+{ 0, { 0xb4, 0xa1, 0x0a, 0x00, 0x67, 0x65, 0x88, 0x2a, 0x02, 0x00, 0x20, } },
+{ 0, { 0x23, 0x21, 0xdb, 0x00, 0x47, 0x65, 0x8f, 0x2a, 0x02, 0x00, 0x1e, } },
+{ 0, { 0x24, 0x21, 0x22, 0x00, 0x47, 0x65, 0x8f, 0x2a, 0x02, 0x00, 0x1e, } },
+{ 0, { 0xe6, 0x30, 0x0b, 0x00, 0x25, 0xf0, 0xb5, 0x45, 0x00, 0x00, 0x28, } },
+{ 0, { 0xe3, 0x70, 0x50, 0x80, 0x25, 0xf0, 0xb0, 0x45, 0x00, 0x00, 0x30, } },
+{ 0, { 0xe6, 0xe0, 0x15, 0x00, 0x70, 0x62, 0x07, 0xf7, 0x00, 0x00, 0x2e, } },
+{ 0, { 0x25, 0x01, 0x12, 0x00, 0xf7, 0xf8, 0x43, 0x05, 0x04, 0x04, 0x30, } },
+{ 0, { 0x01, 0x00, 0x00, 0x00, 0xf4, 0xf8, 0xa6, 0x35, 0x04, 0x00, 0x35, } },
+{ 0, { 0x04, 0x07, 0x09, 0x00, 0xfa, 0xf8, 0xa6, 0xfb, 0x00, 0x00, 0x14, } },
+{ 0, { 0x00, 0x01, 0x13, 0x00, 0xf2, 0xf4, 0x13, 0xf5, 0x00, 0x00, 0x18, } },
+{ 0, { 0x00, 0x01, 0x0f, 0x00, 0xf2, 0xf4, 0x13, 0xf5, 0x00, 0x00, 0x30, } },
+{ 0, { 0x11, 0x32, 0x0c, 0x00, 0xd0, 0x80, 0xf2, 0x05, 0x00, 0x00, 0x10, } },
+{ 0, { 0x10, 0x21, 0x43, 0x40, 0x9b, 0x69, 0x30, 0x0e, 0x03, 0x05, 0x30, } },
+{ 0, { 0x11, 0x32, 0x0c, 0x00, 0xd0, 0x80, 0xf3, 0x05, 0x00, 0x00, 0x20, } },
+{ 0, { 0x16, 0x17, 0x4f, 0x00, 0xf6, 0xf3, 0x53, 0x53, 0x00, 0x00, 0x20, } },
+{ 0, { 0x17, 0x12, 0x00, 0x00, 0xfa, 0xf5, 0x57, 0x58, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x0d, 0x00, 0xa8, 0xd6, 0x4b, 0x4a, 0x00, 0x01, 0x28, } },
+{ 0, { 0x32, 0x10, 0x4a, 0x00, 0xf8, 0xf5, 0xff, 0x7f, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x00, 0x00, 0x0d, 0x00, 0xa8, 0xd6, 0x4c, 0x4f, 0x00, 0x00, 0x10, } },
+{ 0, { 0x12, 0x30, 0x01, 0x00, 0xfb, 0xf3, 0xa7, 0x53, 0x00, 0x00, 0x10, } },
+{ 0, { 0x2b, 0x0b, 0x00, 0x00, 0xff, 0xf7, 0x0e, 0xfe, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x01, 0x10, 0x07, 0x00, 0xf5, 0x54, 0xb5, 0x2f, 0x00, 0x00, 0x26, } },
+{ 0, { 0x00, 0x18, 0x80, 0x00, 0xb3, 0xaf, 0x3f, 0xf0, 0x00, 0x00, 0x1a, } },
+{ 0, { 0x60, 0xef, 0x40, 0x00, 0xb1, 0xb2, 0x73, 0x9b, 0x02, 0x03, 0x3e, } },
+{ 0, { 0xaf, 0xb0, 0x40, 0x00, 0xa1, 0x52, 0x53, 0x73, 0x00, 0x00, 0x3e, } },
+{ 0, { 0x00, 0x07, 0x2e, 0x00, 0xf0, 0x5f, 0xf0, 0xf0, 0x00, 0x00, 0x1e, } },
+{ 0, { 0xe5, 0x70, 0x13, 0x00, 0x70, 0x62, 0x0f, 0xff, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x10, 0x00, 0x00, 0x68, 0xa5, 0xcf, 0x6b, 0x02, 0x00, 0x2e, } },
+{ 0, { 0x2b, 0x27, 0x00, 0x00, 0x82, 0x77, 0x0a, 0x0a, 0x00, 0x05, 0x2e, } },
+{ 0, { 0x00, 0x00, 0x0b, 0x00, 0xfa, 0xf6, 0x6f, 0x8f, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, } },
+{ 0, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, } },
+{ 0, { 0x42, 0x01, 0x1b, 0x00, 0x68, 0xd6, 0x1c, 0x45, 0x03, 0x00, 0x2e, } },
+{ 0, { 0x40, 0x01, 0x18, 0x00, 0x68, 0xd6, 0x19, 0x46, 0x02, 0x00, 0x2e, } },
+{ 0, { 0x02, 0x04, 0x07, 0x00, 0xfa, 0xda, 0xbb, 0xbe, 0x00, 0x00, 0x38, } },
+{ 0, { 0x17, 0x00, 0x00, 0x00, 0xf3, 0xf8, 0xf0, 0xb7, 0x02, 0x00, 0x1e, } },
+{ 0, { 0x01, 0x05, 0x07, 0x00, 0x9a, 0x9a, 0xb6, 0xb9, 0x02, 0x00, 0x3e, } },
+{ 0, { 0x17, 0x03, 0x00, 0x00, 0xf1, 0xf7, 0xf0, 0xb7, 0x02, 0x00, 0x1e, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf7, 0x00, 0x00, 0x16, } },
+{ 0, { 0x2f, 0x31, 0x07, 0x00, 0x73, 0xc4, 0xc2, 0xb4, 0x00, 0x00, 0x3a, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf7, 0x01, 0x00, 0x36, } },
+{ 0, { 0x13, 0x10, 0xcd, 0x80, 0xf5, 0xd5, 0x92, 0xd4, 0x01, 0x00, 0x2a, } },
+{ 0, { 0x01, 0x01, 0x0d, 0x00, 0xe8, 0xa5, 0xec, 0xf5, 0x00, 0x00, 0x16, } },
+{ 0, { 0x3c, 0x31, 0x0a, 0x40, 0x73, 0xc4, 0xb1, 0xf3, 0x00, 0x00, 0x1a, } },
+};
diff --git a/sys/dev/ic/oplreg.h b/sys/dev/ic/oplreg.h
new file mode 100644
index 00000000000..25a168e0f60
--- /dev/null
+++ b/sys/dev/ic/oplreg.h
@@ -0,0 +1,146 @@
+/* $OpenBSD: oplreg.h,v 1.1 1999/01/02 00:02:40 niklas Exp $ */
+/* $NetBSD: oplreg.h,v 1.3 1998/11/25 22:17:06 augustss Exp $ */
+
+/*
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Offsets from base address */
+#define OPL_L 0
+#define OPL_R 2
+
+/* Offsets from base+[OPL_L|OPL_R] */
+#define OPL_STATUS 0
+#define OPL_STATUS_IRQ 0x80
+#define OPL_STATUS_FT1 0x40
+#define OPL_STATUS_FT2 0x20
+#define OPL_STATUS_MASK 0xE0
+#define OPL_ADDR 0
+#define OPL_DATA 1
+
+#define OPL_TEST 0x01
+#define OPL_ENABLE_WAVE_SELECT 0x20
+
+#define OPL_TIMER1 0x02
+#define OPL_TIMER2 0x03
+
+#define OPL_TIMER_CONTROL 0x04 /* Left */
+#define OPL_TIMER1_START 0x01
+#define OPL_TIMER2_START 0x02
+#define OPL_TIMER2_MASK 0x20
+#define OPL_TIMER1_MASK 0x40
+#define OPL_IRQ_RESET 0x80
+
+#define OPL_CONNECTION_SELECT 0x04 /* Right */
+#define OPL_NOCONNECTION 0x00
+#define OPL_R_4OP_0 0x01
+#define OPL_R_4OP_1 0x02
+#define OPL_R_4OP_2 0x04
+#define OPL_L_4OP_0 0x08
+#define OPL_L_4OP_1 0x10
+#define OPL_L_4OP_2 0x20
+
+#define OPL_MODE 0x05 /* Right */
+#define OPL3_ENABLE 0x01
+#define OPL4_ENABLE 0x02
+
+#define OPL_KBD_SPLIT 0x08 /* Left */
+#define OPL_KEYBOARD_SPLIT 0x40
+#define OPL_COMPOSITE_SINE_WAVE_MODE 0x80
+
+#define OPL_PERCUSSION 0xbd /* Left */
+#define OPL_NOPERCUSSION 0x00
+#define OPL_HIHAT 0x01
+#define OPL_CYMBAL 0x02
+#define OPL_TOMTOM 0x04
+#define OPL_SNAREDRUM 0x08
+#define OPL_BASSDRUM 0x10
+#define OPL_PERCUSSION_ENABLE 0x20
+#define OPL_VIBRATO_DEPTH 0x40
+#define OPL_TREMOLO_DEPTH 0x80
+
+/*
+ * Offsets to the register banks for operators.
+ */
+/* AM/VIB/EG/KSR/Multiple (0x20 to 0x35) */
+#define OPL_AM_VIB 0x20
+#define OPL_KSR 0x10
+#define OPL_SUSTAIN 0x20
+#define OPL_VIBRATO 0x40
+#define OPL_TREMOLO 0x80
+#define OPL_MULTIPLE_MASK 0x0f
+
+/* KSL/Total level (0x40 to 0x55) */
+#define OPL_KSL_LEVEL 0x40
+#define OPL_KSL_MASK 0xc0 /* Envelope scaling bits */
+#define OPL_TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */
+
+/* Attack / Decay rate (0x60 to 0x75) */
+#define OPL_ATTACK_DECAY 0x60
+#define OPL_ATTACK_MASK 0xf0
+#define DECAY_MASK 0x0f
+
+/* Sustain level / Release rate (0x80 to 0x95) */
+#define OPL_SUSTAIN_RELEASE 0x80
+#define OPL_SUSTAIN_MASK 0xf0
+#define OPL_RELEASE_MASK 0x0f
+
+/* Wave select (0xE0 to 0xF5) */
+#define OPL_WAVE_SELECT 0xe0
+
+#define OPL_MAXREG 0xf5
+
+/*
+ * Offsets to the register banks for voices.
+ */
+/* F-Number low bits (0xA0 to 0xA8). */
+#define OPL_FNUM_LOW 0xa0
+
+/* F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) */
+#define OPL_KEYON_BLOCK 0xb0
+#define OPL_KEYON_BIT 0x20
+#define OPL_BLOCKNUM_MASK 0x1c
+#define OPL_FNUM_HIGH_MASK 0x03
+
+/* Feedback / Connection (0xc0 to 0xc8) */
+#define OPL_FEEDBACK_CONNECTION 0xc0
+#define OPL_FEEDBACK_MASK 0x0e
+#define OPL_CONNECTION_BIT 0x01
+#define OPL_STEREO_BITS 0x30 /* OPL-3 only */
+#define OPL_VOICE_TO_LEFT 0x10
+#define OPL_VOICE_TO_RIGHT 0x20
+
+#define OPL2_NVOICE 9
+#define OPL3_NVOICE 18
diff --git a/sys/dev/ic/oplvar.h b/sys/dev/ic/oplvar.h
new file mode 100644
index 00000000000..ad0585b3884
--- /dev/null
+++ b/sys/dev/ic/oplvar.h
@@ -0,0 +1,92 @@
+/* $OpenBSD: oplvar.h,v 1.1 1999/01/02 00:02:41 niklas Exp $ */
+/* $NetBSD: oplvar.h,v 1.3 1998/11/25 22:17:06 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dev/midivar.h>
+#include <dev/midisynvar.h>
+
+struct opl_voice {
+ int voiceno;
+ int iooffs;
+ u_int8_t op[4];
+ struct opl_operators *patch;
+ u_int8_t rB0;
+};
+
+struct opl_softc {
+ struct midi_softc mididev;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int offs;
+ int model;
+#define OPL_2 2
+#define OPL_3 3
+ struct midisyn syn;
+
+ struct opl_voice voices[OPL3_NVOICE];
+ int volume;
+
+ int (*spkrctl)__P((void *, int));
+ void *spkrarg;
+};
+
+struct opl_attach_arg {
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int offs;
+ int done;
+};
+
+struct opl_operators {
+ u_int8_t opl3;
+ u_int8_t ops[22];
+#define OO_CHARS 0
+#define OO_KSL_LEV 2
+#define OO_ATT_DEC 4
+#define OO_SUS_REL 6
+#define OO_WAV_SEL 8
+#define OO_FB_CONN 10
+#define OO_4OP_OFFS 11
+};
+
+#define OPL_NINSTR 256
+extern struct opl_operators opl2_instrs[];
+extern struct opl_operators opl3_instrs[];
+
+int opl_find __P((struct opl_softc *));
+void opl_attach __P((struct opl_softc *));
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index 62da4a6e5a1..eb45fe2bf1e 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,7 +1,7 @@
-# $OpenBSD: files.isa,v 1.48 1998/12/27 09:41:56 deraadt Exp $
+# $OpenBSD: files.isa,v 1.49 1999/01/02 00:02:45 niklas Exp $
# $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $
#
-# Config.new file and device description for machine-independent ISA code.
+# Config file and device description for machine-independent ISA code.
# Included by ports that need it. Requires that the SCSI files be
# defined first.
@@ -231,17 +231,24 @@ file dev/isa/if_sm_isa.c sm_isa
# ISA Sound hardware
#
+# MPU401 MIDI UART compatibles
+define mpu401
+file dev/isa/mpu401.c mpu401 & midi
+
# the SoundBlaster DSP, or close likenesses; used by other drivers
-define sbdsp
+define sbdsp { }
file dev/isa/sbdsp.c sbdsp
# SoundBlaster family
-device sb: audio, isa_dma, sbdsp, mulaw, opti, auconv
+device sb: audio, isa_dma, sbdsp, mulaw, opti, auconv, mpu401, midibus
file dev/isa/sb.c sb needs-flag
attach sb at isa with sb_isa
file dev/isa/sb_isa.c sb & (sb_isa | sb_isapnp) needs-flag
+attach opl at sbdsp with opl_sb
+file dev/isa/opl_sb.c opl_sb
+
# Soundcards based on Sierra's Aria chipset.
# Such as the Prometheus Aria 16 or the Diamond
# sonic sound.
@@ -286,6 +293,20 @@ device gus: audio, isa_dma, ics2101, ad1848, mulaw, auconv
attach gus at isa
file dev/isa/gus.c gus needs-flag
+# Yamaha OPL2/OPL3 FM synth
+attach opl at isa with opl_isa
+file dev/isa/opl_isa.c opl_isa
+
+# PC PPI + TIMER 1 (speaker interface)
+device pcppi {}
+attach pcppi at isa
+file dev/isa/pcppi.c pcppi needs-flag
+device spkr
+attach spkr at pcppi
+file dev/isa/spkr.c spkr needs-flag
+attach midi at pcppi with midi_pcppi: midisyn
+file dev/isa/midi_pcppi.c midi_pcppi
+
#
# PCMCIA PCIC (i82365SL and compatibles):
#
@@ -296,4 +317,3 @@ file dev/isa/gus.c gus needs-flag
#file dev/isa/pcmcia_pcic.c pcic | pcicmaster
#file dev/isa/pcmcia_isa.c pcmcia
-
diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c
index 50a6de1db83..d7e244e246a 100644
--- a/sys/dev/isa/gus.c
+++ b/sys/dev/isa/gus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gus.c,v 1.18 1998/11/03 21:14:59 downsj Exp $ */
+/* $OpenBSD: gus.c,v 1.19 1999/01/02 00:02:45 niklas Exp $ */
/* $NetBSD: gus.c,v 1.51 1998/01/25 23:48:06 mycroft Exp $ */
/*-
@@ -1039,7 +1039,8 @@ gusattach(parent, self, aux)
* Attach to the generic audio layer
*/
- audio_attach_mi(&gus_hw_if, 0, HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc, &sc->sc_dev);
+ audio_attach_mi(&gus_hw_if,
+ HAS_CODEC(sc) ? (void *)&sc->sc_codec : (void *)sc, &sc->sc_dev);
}
int
diff --git a/sys/dev/isa/midi_pcppi.c b/sys/dev/isa/midi_pcppi.c
new file mode 100644
index 00000000000..c42ae87fe5d
--- /dev/null
+++ b/sys/dev/isa/midi_pcppi.c
@@ -0,0 +1,165 @@
+/* $OpenBSD: midi_pcppi.c,v 1.1 1999/01/02 00:02:42 niklas Exp $ */
+/* $NetBSD: midi_pcppi.c,v 1.4 1998/11/25 22:17:06 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/select.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+
+#include <dev/isa/pcppivar.h>
+
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+#include <dev/midivar.h>
+#include <dev/midisynvar.h>
+
+#define MAX_DURATION 30 /* turn off sound automagically after 30 s */
+
+struct midi_pcppi_softc {
+ struct midi_softc sc_mididev;
+ midisyn sc_midisyn;
+};
+
+#define __BROKEN_INDIRECT_CONFIG /* XXX */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int midi_pcppi_match __P((struct device *, void *, void *));
+#else
+int midi_pcppi_match __P((struct device *, struct cfdata *, void *));
+#endif
+void midi_pcppi_attach __P((struct device *, struct device *, void *));
+
+void midi_pcppi_on __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void midi_pcppi_off __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+void midi_pcppi_close __P((midisyn *));
+
+struct cfattach midi_pcppi_ca = {
+ sizeof(struct midi_pcppi_softc), midi_pcppi_match, midi_pcppi_attach
+};
+
+struct midisyn_methods midi_pcppi_hw = {
+ 0, /* open */
+ midi_pcppi_close,
+ 0, /* ioctl */
+ 0, /* allocv */
+ midi_pcppi_on,
+ midi_pcppi_off,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+int midi_pcppi_attached = 0; /* Not very nice */
+
+int
+midi_pcppi_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ return (!midi_pcppi_attached);
+}
+
+void
+midi_pcppi_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct midi_pcppi_softc *sc = (struct midi_pcppi_softc *)self;
+ struct pcppi_attach_args *pa = (struct pcppi_attach_args *)aux;
+ midisyn *ms;
+
+ ms = &sc->sc_midisyn;
+ ms->mets = &midi_pcppi_hw;
+ strcpy(ms->name, "PC speaker");
+ ms->nvoice = 1;
+ ms->flags = MS_DOALLOC | MS_FREQXLATE;
+ ms->data = pa->pa_cookie;
+
+ midi_pcppi_attached++;
+
+ midisyn_attach(&sc->sc_mididev, ms);
+ midi_attach(&sc->sc_mididev, parent);
+}
+
+void
+midi_pcppi_on(ms, chan, note, vel)
+ midisyn *ms;
+ u_int32_t chan, note, vel;
+{
+ pcppi_tag_t t = ms->data;
+
+ /*printf("ON %p %d\n", t, MIDISYN_FREQ_TO_HZ(note));*/
+ pcppi_bell(t, MIDISYN_FREQ_TO_HZ(note), MAX_DURATION * hz, 0);
+}
+
+void
+midi_pcppi_off(ms, chan, note, vel)
+ midisyn *ms;
+ u_int32_t chan, note, vel;
+{
+ pcppi_tag_t t = ms->data;
+
+ /*printf("OFF %p %d\n", t, note >> 16);*/
+ pcppi_bell(t, 0, 0, 0);
+}
+
+void
+midi_pcppi_close(ms)
+ midisyn *ms;
+{
+ pcppi_tag_t t = ms->data;
+
+ /* Make sure we are quiet. */
+ pcppi_bell(t, 0, 0, 0);
+}
diff --git a/sys/dev/isa/mpu401.c b/sys/dev/isa/mpu401.c
new file mode 100644
index 00000000000..6463690724a
--- /dev/null
+++ b/sys/dev/isa/mpu401.c
@@ -0,0 +1,226 @@
+/* $OpenBSD: mpu401.c,v 1.1 1999/01/02 00:02:42 niklas Exp $ */
+/* $NetBSD: mpu401.c,v 1.3 1998/11/25 22:17:06 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <vm/vm.h>
+
+#include <machine/cpu.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/midi_if.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
+
+#include <dev/isa/mpu401var.h>
+
+#define splaudio() splbio() /* XXX found in audio_if.h normally */
+
+#ifdef AUDIO_DEBUG
+#define DPRINTF(x) if (mpu401debug) printf x
+#define DPRINTFN(n,x) if (mpu401debug >= (n)) printf x
+int mpu401debug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define MPU401_NPORT 2
+#define MPU_DATA 0
+#define MPU_COMMAND 1
+#define MPU_RESET 0xff
+#define MPU_UART_MODE 0x3f
+#define MPU_ACK 0xfe
+#define MPU_STATUS 1
+#define MPU_OUTPUT_BUSY 0x40
+#define MPU_INPUT_EMPTY 0x80
+
+#define MPU_MAXWAIT 10000 /* usec/10 to wait */
+
+#define MPU_GETSTATUS(iot, ioh) (bus_space_read_1(iot, ioh, MPU_STATUS))
+
+int mpu401_reset(struct mpu401_softc *);
+static __inline int mpu401_waitready(struct mpu401_softc *);
+void mpu401_readinput(struct mpu401_softc *);
+
+int
+mpu401_find(sc)
+ struct mpu401_softc *sc;
+{
+ if (MPU_GETSTATUS(sc->iot, sc->ioh) == 0xff) {
+ DPRINTF(("mpu401_find: No status\n"));
+ goto bad;
+ }
+ sc->open = 0;
+ sc->intr = 0;
+ if (mpu401_reset(sc) == 0)
+ return 1;
+bad:
+ return 0;
+}
+
+static __inline int
+mpu401_waitready(sc)
+ struct mpu401_softc *sc;
+{
+ int i;
+
+ for(i = 0; i < MPU_MAXWAIT; i++) {
+ if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
+ return 0;
+ delay(10);
+ }
+ return 1;
+}
+
+int
+mpu401_reset(sc)
+ struct mpu401_softc *sc;
+{
+ bus_space_tag_t iot = sc->iot;
+ bus_space_handle_t ioh = sc->ioh;
+ int i;
+ int s;
+
+ if (mpu401_waitready(sc)) {
+ DPRINTF(("mpu401_reset: not ready\n"));
+ return EIO;
+ }
+ s = splaudio(); /* Don't let the interrupt get our ACK. */
+ bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
+ for(i = 0; i < 2*MPU_MAXWAIT; i++) {
+ if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
+ bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
+ splx(s);
+ return 0;
+ }
+ }
+ splx(s);
+ DPRINTF(("mpu401_reset: No ACK\n"));
+ return EIO;
+}
+
+int
+mpu401_open(sc, flags, iintr, ointr, arg)
+ struct mpu401_softc *sc;
+ int flags;
+ void (*iintr)__P((void *, int));
+ void (*ointr)__P((void *));
+ void *arg;
+{
+ DPRINTF(("mpu401_open: sc=%p\n", sc));
+
+ if (sc->open)
+ return EBUSY;
+ if (mpu401_reset(sc) != 0)
+ return EIO;
+
+ bus_space_write_1(sc->iot, sc->ioh, MPU_COMMAND, MPU_UART_MODE);
+ sc->open = 1;
+ sc->intr = iintr;
+ sc->arg = arg;
+ return 0;
+}
+
+void
+mpu401_close(sc)
+ struct mpu401_softc *sc;
+{
+ DPRINTF(("mpu401_close: sc=%p\n", sc));
+
+ sc->open = 0;
+ sc->intr = 0;
+ mpu401_reset(sc); /* exit UART mode */
+}
+
+void
+mpu401_readinput(sc)
+ struct mpu401_softc *sc;
+{
+ bus_space_tag_t iot = sc->iot;
+ bus_space_handle_t ioh = sc->ioh;
+ int data;
+
+ while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
+ data = bus_space_read_1(iot, ioh, MPU_DATA);
+ DPRINTFN(3, ("mpu401_rea: sc=%p 0x%02x\n", sc, data));
+ if (sc->intr)
+ sc->intr(sc->arg, data);
+ }
+}
+
+int
+mpu401_output(sc, d)
+ struct mpu401_softc *sc;
+ int d;
+{
+ int s;
+
+ DPRINTFN(3, ("mpu401_output: sc=%p 0x%02x\n", sc, d));
+ if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
+ s = splaudio();
+ mpu401_readinput(sc);
+ splx(s);
+ }
+ if (mpu401_waitready(sc)) {
+ DPRINTF(("mpu401_output: not ready\n"));
+ return EIO;
+ }
+ bus_space_write_1(sc->iot, sc->ioh, MPU_DATA, d);
+ return 0;
+}
+
+void
+mpu401_intr(sc)
+ struct mpu401_softc *sc;
+{
+ if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
+ DPRINTF(("mpu401_intr: no data\n"));
+ return;
+ }
+ mpu401_readinput(sc);
+}
diff --git a/sys/dev/isa/mpu401var.h b/sys/dev/isa/mpu401var.h
new file mode 100644
index 00000000000..a197e4f6184
--- /dev/null
+++ b/sys/dev/isa/mpu401var.h
@@ -0,0 +1,57 @@
+/* $OpenBSD: mpu401var.h,v 1.1 1999/01/02 00:02:43 niklas Exp $ */
+/* $NetBSD: mpu401var.h,v 1.3 1998/11/25 22:17:06 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct mpu401_softc {
+ bus_space_tag_t iot; /* tag */
+ bus_space_handle_t ioh; /* handle */
+ int iobase;
+ int open;
+ void (*intr)__P((void*, int)); /* midi input intr handler */
+ void *arg; /* arg for intr() */
+};
+
+struct midi_hw_if mpu401_midi_hw_if;
+
+void mpu401_intr __P((struct mpu401_softc *));
+int mpu401_find __P((struct mpu401_softc *));
+int mpu401_open __P((struct mpu401_softc *, int,
+ void (*iintr)__P((void *, int)),
+ void (*ointr)__P((void *)), void *arg));
+void mpu401_close __P((struct mpu401_softc *));
+int mpu401_output __P((struct mpu401_softc *, int));
diff --git a/sys/dev/isa/opl_isa.c b/sys/dev/isa/opl_isa.c
new file mode 100644
index 00000000000..ff326b6ede5
--- /dev/null
+++ b/sys/dev/isa/opl_isa.c
@@ -0,0 +1,105 @@
+/* $OpenBSD: opl_isa.c,v 1.1 1999/01/02 00:02:44 niklas Exp $ */
+/* $NetBSD: opl_isa.c,v 1.1 1998/08/26 13:33:59 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Author: Lennart Augustsson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/select.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+
+#include <machine/bus.h>
+
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+
+#include <dev/ic/oplreg.h>
+#include <dev/ic/oplvar.h>
+
+#include <dev/isa/isavar.h>
+
+#define OPL_SIZE 4
+
+int opl_isa_match __P((struct device *, struct cfdata *, void *));
+void opl_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach opl_isa_ca = {
+ sizeof (struct opl_softc), opl_isa_match, opl_isa_attach
+};
+
+int
+opl_isa_match(parent, match, aux)
+ struct device *parent;
+ struct cfdata *match;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ struct opl_softc sc;
+ int r;
+
+ memset(&sc, 0, sizeof sc);
+ sc.iot = ia->ia_iot;
+ if (bus_space_map(sc.iot, ia->ia_iobase, OPL_SIZE, 0, &sc.ioh))
+ return (0);
+ r = opl_find(&sc);
+ bus_space_unmap(sc.iot, sc.ioh, OPL_SIZE);
+ return (r);
+}
+
+void
+opl_isa_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct opl_softc *sc = (struct opl_softc *)self;
+ struct isa_attach_args *ia = aux;
+
+ if (bus_space_map(sc->iot, ia->ia_iobase, OPL_SIZE, 0, &sc->ioh)) {
+ printf("opl_isa_attach: bus_space_map failed\n");
+ return;
+ }
+ sc->offs = 0;
+
+ opl_attach(sc);
+}
diff --git a/sys/dev/isa/opl_sb.c b/sys/dev/isa/opl_sb.c
new file mode 100644
index 00000000000..b2a41c3fe92
--- /dev/null
+++ b/sys/dev/isa/opl_sb.c
@@ -0,0 +1,113 @@
+/* $OpenBSD: opl_sb.c,v 1.1 1999/01/02 00:02:45 niklas Exp $ */
+/* $NetBSD: opl_sb.c,v 1.4 1998/12/08 14:26:57 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/select.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+
+#include <machine/bus.h>
+
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+#include <dev/ic/oplreg.h>
+#include <dev/ic/oplvar.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/sbdspvar.h>
+
+#define __BROKEN_INDIRECT_CONFIG /* XXX */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int opl_sb_match __P((struct device *, void *, void *));
+#else
+int opl_sb_match __P((struct device *, struct cfdata *, void *));
+#endif
+void opl_sb_attach __P((struct device *, struct device *, void *));
+
+struct cfattach opl_sb_ca = {
+ sizeof (struct opl_softc), opl_sb_match, opl_sb_attach
+};
+
+int
+opl_sb_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct audio_attach_args *aa = (struct audio_attach_args *)aux;
+ struct sbdsp_softc *ssc = (struct sbdsp_softc *)parent;
+ struct opl_softc sc;
+
+ if (aa->type != AUDIODEV_TYPE_OPL)
+ return (0);
+ memset(&sc, 0, sizeof sc);
+ sc.ioh = ssc->sc_ioh;
+ sc.iot = ssc->sc_iot;
+ return (opl_find(&sc));
+}
+
+void
+opl_sb_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct sbdsp_softc *ssc = (struct sbdsp_softc *)parent;
+ struct opl_softc *sc = (struct opl_softc *)self;
+
+ sc->ioh = ssc->sc_ioh;
+ sc->iot = ssc->sc_iot;
+ sc->offs = 0;
+ sc->spkrctl = sbdsp_speaker_ctl;
+ sc->spkrarg = ssc;
+ strcpy(sc->syn.name, "SB ");
+
+ opl_attach(sc);
+}
diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c
index 771bf81ad58..77a3108b062 100644
--- a/sys/dev/isa/pas.c
+++ b/sys/dev/isa/pas.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pas.c,v 1.17 1998/11/03 21:15:00 downsj Exp $ */
+/* $OpenBSD: pas.c,v 1.18 1999/01/02 00:02:46 niklas Exp $ */
/* $NetBSD: pas.c,v 1.37 1998/01/12 09:43:43 thorpej Exp $ */
/*
@@ -62,6 +62,7 @@
#include <sys/audioio.h>
#include <dev/audio_if.h>
+#include <dev/midi_if.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
@@ -113,20 +114,20 @@ void pasconf __P((int, int, int, int));
struct audio_hw_if pas_hw_if = {
sbdsp_open,
sbdsp_close,
- NULL,
+ 0,
sbdsp_query_encoding,
sbdsp_set_params,
sbdsp_round_blocksize,
- NULL,
- sbdsp_dma_init_output,
- sbdsp_dma_init_input,
- sbdsp_dma_output,
- sbdsp_dma_input,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
sbdsp_haltdma,
sbdsp_haltdma,
sbdsp_speaker_ctl,
pas_getdev,
- NULL,
+ 0,
sbdsp_mixer_set_port,
sbdsp_mixer_get_port,
sbdsp_mixer_query_devinfo,
@@ -135,8 +136,8 @@ struct audio_hw_if pas_hw_if = {
sb_round,
sb_mappage,
sbdsp_get_props,
- NULL,
- NULL
+ sbdsp_trigger_output,
+ sbdsp_trigger_input
};
/* The Address Translation code is used to convert I/O register addresses to
@@ -459,7 +460,7 @@ pasattach(parent, self, aux)
sprintf(pas_device.name, "pas,%s", pasnames[sc->model]);
sprintf(pas_device.version, "%d", sc->rev);
- audio_attach_mi(&pas_hw_if, 0, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev);
+ audio_attach_mi(&pas_hw_if, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev);
}
int
diff --git a/sys/dev/isa/pcppi.c b/sys/dev/isa/pcppi.c
new file mode 100644
index 00000000000..3fdba2b4dcb
--- /dev/null
+++ b/sys/dev/isa/pcppi.c
@@ -0,0 +1,235 @@
+/* $OpenBSD: pcppi.c,v 1.1 1999/01/02 00:02:44 niklas Exp $ */
+/* $NetBSD: pcppi.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+
+#include <machine/bus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <dev/isa/pcppireg.h>
+#include <dev/isa/pcppivar.h>
+
+#include <dev/ic/i8253reg.h>
+
+struct pcppi_softc {
+ struct device sc_dv;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ppi_ioh, sc_pit1_ioh;
+
+ int sc_bellactive, sc_bellpitch;
+ int sc_slp;
+};
+
+#define __BROKEN_INDIRECT_CONFIG /* XXX */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int pcppi_match __P((struct device *, void *, void *));
+#else
+int pcppi_match __P((struct device *, struct cfdata *, void *));
+#endif
+void pcppi_attach __P((struct device *, struct device *, void *));
+
+struct cfattach pcppi_ca = {
+ sizeof(struct pcppi_softc), pcppi_match, pcppi_attach,
+};
+
+struct cfdriver pcppi_cd = {
+ NULL, "pcppi", DV_DULL
+};
+
+static void pcppi_bell_stop __P((void*));
+
+#define PCPPIPRI (PZERO - 1)
+
+int
+pcppi_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ bus_space_handle_t ppi_ioh, pit1_ioh;
+ int have_pit1, have_ppi, rv;
+ u_int8_t v, nv;
+
+ /* If values are hardwired to something that they can't be, punt. */
+ if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_PPI) ||
+ ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 ||
+ ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK)
+ return (0);
+
+ rv = 0;
+ have_pit1 = have_ppi = 0;
+
+ if (bus_space_map(ia->ia_iot, IO_TIMER1, 4, 0, &pit1_ioh))
+ goto lose;
+ have_pit1 = 1;
+ if (bus_space_map(ia->ia_iot, IO_PPI, 1, 0, &ppi_ioh))
+ goto lose;
+ have_ppi = 1;
+
+ /*
+ * Check for existence of PPI. Realistically, this is either going to
+ * be here or nothing is going to be here.
+ *
+ * We don't want to have any chance of changing speaker output (which
+ * this test might, if it crashes in the middle, or something;
+ * normally it's be to quick to produce anthing audible), but
+ * many "combo chip" mock-PPI's don't seem to support the top bit
+ * of Port B as a settable bit. The bottom bit has to be settable,
+ * since the speaker driver hardware still uses it.
+ */
+ v = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
+ bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v ^ 0x01); /* XXX */
+ nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
+ if (((nv ^ v) & 0x01) == 0x01)
+ rv = 1;
+ bus_space_write_1(ia->ia_iot, ppi_ioh, 0, v); /* XXX */
+ nv = bus_space_read_1(ia->ia_iot, ppi_ioh, 0); /* XXX */
+ if (((nv ^ v) & 0x01) != 0x00) {
+ rv = 0;
+ goto lose;
+ }
+
+ /*
+ * We assume that the programmable interval timer is there.
+ */
+
+lose:
+ if (have_pit1)
+ bus_space_unmap(ia->ia_iot, pit1_ioh, 4);
+ if (have_ppi)
+ bus_space_unmap(ia->ia_iot, ppi_ioh, 1);
+ if (rv) {
+ ia->ia_iobase = IO_PPI;
+ ia->ia_iosize = 0x1;
+ ia->ia_msize = 0x0;
+ }
+ return (rv);
+}
+
+void
+pcppi_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pcppi_softc *sc = (struct pcppi_softc *)self;
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t iot;
+ struct pcppi_attach_args pa;
+
+ sc->sc_iot = iot = ia->ia_iot;
+
+ if (bus_space_map(iot, IO_TIMER1, 4, 0, &sc->sc_pit1_ioh) ||
+ bus_space_map(iot, IO_PPI, 1, 0, &sc->sc_ppi_ioh))
+ panic("pcppi_attach: couldn't map");
+
+ printf("\n");
+
+ sc->sc_bellactive = sc->sc_bellpitch = sc->sc_slp = 0;
+
+ pa.pa_cookie = sc;
+ while (config_found(self, &pa, 0));
+}
+
+void
+pcppi_bell(self, pitch, period, slp)
+ pcppi_tag_t self;
+ int pitch, period;
+ int slp;
+{
+ struct pcppi_softc *sc = self;
+ int s1, s2;
+
+ s1 = spltty(); /* ??? */
+ if (sc->sc_bellactive) {
+ untimeout(pcppi_bell_stop, sc);
+ if (sc->sc_slp)
+ wakeup(pcppi_bell_stop);
+ }
+ if (pitch == 0 || period == 0) {
+ pcppi_bell_stop(sc);
+ sc->sc_bellpitch = 0;
+ splx(s1);
+ return;
+ }
+ if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) {
+ s2 = splhigh();
+ bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_MODE,
+ TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
+ bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2,
+ TIMER_DIV(pitch) % 256);
+ bus_space_write_1(sc->sc_iot, sc->sc_pit1_ioh, TIMER_CNTR2,
+ TIMER_DIV(pitch) / 256);
+ splx(s2);
+ /* enable speaker */
+ bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0,
+ bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0)
+ | PIT_SPKR);
+ }
+ sc->sc_bellpitch = pitch;
+
+ sc->sc_bellactive = 1;
+ timeout(pcppi_bell_stop, sc, period);
+ if (slp) {
+ sc->sc_slp = 1;
+ tsleep(pcppi_bell_stop, PCPPIPRI | PCATCH, "bell", 0);
+ sc->sc_slp = 0;
+ }
+ splx(s1);
+}
+
+static void
+pcppi_bell_stop(arg)
+ void *arg;
+{
+ struct pcppi_softc *sc = arg;
+ int s;
+
+ s = spltty(); /* ??? */
+ /* disable bell */
+ bus_space_write_1(sc->sc_iot, sc->sc_ppi_ioh, 0,
+ bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0)
+ & ~PIT_SPKR);
+ sc->sc_bellactive = 0;
+ if (sc->sc_slp)
+ wakeup(pcppi_bell_stop);
+ splx(s);
+}
diff --git a/sys/dev/isa/pcppireg.h b/sys/dev/isa/pcppireg.h
new file mode 100644
index 00000000000..8667ab80e6d
--- /dev/null
+++ b/sys/dev/isa/pcppireg.h
@@ -0,0 +1,11 @@
+/* $OpenBSD: pcppireg.h,v 1.1 1999/01/02 00:02:44 niklas Exp $ */
+/* $NetBSD: pcppireg.h,v 1.1 1998/04/15 20:26:18 drochner Exp $ */
+
+/*
+ * PPI speaker control values
+ */
+
+#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */
+#define PIT_SPKRDATA 0x02 /* Direct to speaker */
+
+#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA)
diff --git a/sys/dev/isa/pcppivar.h b/sys/dev/isa/pcppivar.h
new file mode 100644
index 00000000000..fb61b38e9fa
--- /dev/null
+++ b/sys/dev/isa/pcppivar.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: pcppivar.h,v 1.1 1999/01/02 00:02:45 niklas Exp $ */
+/* $NetBSD: pcppivar.h,v 1.1 1998/04/15 20:26:18 drochner Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+typedef void *pcppi_tag_t;
+
+struct pcppi_attach_args {
+ pcppi_tag_t pa_cookie;
+};
+
+void pcppi_bell __P((pcppi_tag_t, int, int, int));
diff --git a/sys/dev/isa/pss.c b/sys/dev/isa/pss.c
index 0013819440a..acbc6b2e1b1 100644
--- a/sys/dev/isa/pss.c
+++ b/sys/dev/isa/pss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pss.c,v 1.16 1998/11/03 21:15:01 downsj Exp $ */
+/* $OpenBSD: pss.c,v 1.17 1999/01/02 00:02:46 niklas Exp $ */
/* $NetBSD: pss.c,v 1.38 1998/01/12 09:43:44 thorpej Exp $ */
/*
@@ -1050,7 +1050,7 @@ pssattach(parent, self, aux)
(void)pss_set_treble(sc, AUDIO_MAX_GAIN/2);
(void)pss_set_bass(sc, AUDIO_MAX_GAIN/2);
- audio_attach_mi(&pss_audio_if, 0, sc->ad1848_sc, &sc->ad1848_sc->sc_dev);
+ audio_attach_mi(&pss_audio_if, sc->ad1848_sc, &sc->ad1848_sc->sc_dev);
}
void
diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c
index 46ee9b33aaa..10306436c48 100644
--- a/sys/dev/isa/sb.c
+++ b/sys/dev/isa/sb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sb.c,v 1.16 1998/11/03 21:15:01 downsj Exp $ */
+/* $OpenBSD: sb.c,v 1.17 1999/01/02 00:02:47 niklas Exp $ */
/* $NetBSD: sb.c,v 1.57 1998/01/12 09:43:46 thorpej Exp $ */
/*
@@ -35,6 +35,8 @@
*
*/
+#include "midi.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
@@ -50,6 +52,7 @@
#include <sys/audioio.h>
#include <dev/audio_if.h>
+#include <dev/midi_if.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
@@ -62,6 +65,31 @@ struct cfdriver sb_cd = {
NULL, "sb", DV_DULL
};
+#if NMIDI > 0
+int sb_mpu401_open __P((void *, int,
+ void (*iintr)__P((void *, int)),
+ void (*ointr)__P((void *)), void *arg));
+void sb_mpu401_close __P((void *));
+int sb_mpu401_output __P((void *, int));
+void sb_mpu401_getinfo __P((void *, struct midi_info *));
+
+struct midi_hw_if sb_midi_hw_if = {
+ sbdsp_midi_open,
+ sbdsp_midi_close,
+ sbdsp_midi_output,
+ sbdsp_midi_getinfo,
+ 0, /* ioctl */
+};
+
+struct midi_hw_if sb_mpu401_hw_if = {
+ sb_mpu401_open,
+ sb_mpu401_close,
+ sb_mpu401_output,
+ sb_mpu401_getinfo,
+ 0, /* ioctl */
+};
+#endif
+
struct audio_device sb_device = {
"SoundBlaster",
"x",
@@ -77,20 +105,20 @@ int sb_getdev __P((void *, struct audio_device *));
struct audio_hw_if sb_hw_if = {
sbdsp_open,
sbdsp_close,
- NULL,
+ 0,
sbdsp_query_encoding,
sbdsp_set_params,
sbdsp_round_blocksize,
- NULL,
- sbdsp_dma_init_output,
- sbdsp_dma_init_input,
- sbdsp_dma_output,
- sbdsp_dma_input,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
sbdsp_haltdma,
sbdsp_haltdma,
sbdsp_speaker_ctl,
sb_getdev,
- NULL,
+ 0,
sbdsp_mixer_set_port,
sbdsp_mixer_get_port,
sbdsp_mixer_query_devinfo,
@@ -99,8 +127,8 @@ struct audio_hw_if sb_hw_if = {
sb_round,
sb_mappage,
sbdsp_get_props,
- NULL,
- NULL
+ sbdsp_trigger_output,
+ sbdsp_trigger_input
};
#ifdef AUDIO_DEBUG
@@ -249,41 +277,35 @@ void
sbattach(sc)
struct sbdsp_softc *sc;
{
+ struct audio_attach_args arg;
+#if NMIDI > 0
+ struct midi_hw_if *mhw = &sb_midi_hw_if;
+#endif
+
sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq, IST_EDGE,
IPL_AUDIO, sbdsp_intr, sc, sc->sc_dev.dv_xname);
sbdsp_attach(sc);
- audio_attach_mi(&sb_hw_if, 0, sc, &sc->sc_dev);
-}
-
-#ifdef NEWCONFIG
-void
-sbforceintr(aux)
- void *aux;
-{
- static char dmabuf;
- struct sbdsp_softc *sc = aux;
-
- /*
- * Set up a DMA read of one byte.
- * XXX Note that at this point we haven't called
- * at_setup_dmachan(). This is okay because it just
- * allocates a buffer in case it needs to make a copy,
- * and it won't need to make a copy for a 1 byte buffer.
- * (I think that calling at_setup_dmachan() should be optional;
- * if you don't call it, it will be called the first time
- * it is needed (and you pay the latency). Also, you might
- * never need the buffer anyway.)
- */
- at_dma(DMAMODE_READ, &dmabuf, 1, sc->sc_drq8);
- if (sbdsp_wdsp(sc, SB_DSP_RDMA) == 0) {
- (void)sbdsp_wdsp(sc, 0);
- (void)sbdsp_wdsp(sc, 0);
+#if NMIDI > 0
+ sc->sc_hasmpu = 0;
+ if (ISSB16CLASS(sc) && sc->sc_mpu_sc.iobase != 0) {
+ sc->sc_mpu_sc.iot = sc->sc_iot;
+ if (mpu401_find(&sc->sc_mpu_sc)) {
+ sc->sc_hasmpu = 1;
+ mhw = &sb_mpu401_hw_if;
+ }
}
-}
+ midi_attach_mi(mhw, sc, &sc->sc_dev);
#endif
+ audio_attach_mi(&sb_hw_if, sc, &sc->sc_dev);
+
+ arg.type = AUDIODEV_TYPE_OPL;
+ arg.hwif = 0;
+ arg.hdl = 0;
+ (void)config_found(&sc->sc_dev, &arg, audioprint);
+}
/*
* Various routines to interface to higher level audio driver
@@ -313,3 +335,43 @@ sb_getdev(addr, retp)
return 0;
}
+
+#if NMIDI > 0
+
+#define SBMPU(a) (&((struct sbdsp_softc *)addr)->sc_mpu_sc)
+
+int
+sb_mpu401_open(addr, flags, iintr, ointr, arg)
+ void *addr;
+ int flags;
+ void (*iintr)__P((void *, int));
+ void (*ointr)__P((void *));
+ void *arg;
+{
+ return mpu401_open(SBMPU(addr), flags, iintr, ointr, arg);
+}
+
+int
+sb_mpu401_output(addr, d)
+ void *addr;
+ int d;
+{
+ return mpu401_output(SBMPU(addr), d);
+}
+
+void
+sb_mpu401_close(addr)
+ void *addr;
+{
+ mpu401_close(SBMPU(addr));
+}
+
+void
+sb_mpu401_getinfo(addr, mi)
+ void *addr;
+ struct midi_info *mi;
+{
+ mi->name = "SB MPU-401 UART";
+ mi->props = 0;
+}
+#endif
diff --git a/sys/dev/isa/sb_isapnp.c b/sys/dev/isa/sb_isapnp.c
index 774052dd5f7..c3b70a3a0e4 100644
--- a/sys/dev/isa/sb_isapnp.c
+++ b/sys/dev/isa/sb_isapnp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sb_isapnp.c,v 1.5 1998/05/13 20:07:47 deraadt Exp $ */
+/* $OpenBSD: sb_isapnp.c,v 1.6 1999/01/02 00:02:47 niklas Exp $ */
/* $NetBSD: sb_isa.c,v 1.3 1997/03/20 11:03:11 mycroft Exp $ */
/*
@@ -45,6 +45,7 @@
#include <sys/audioio.h>
#include <dev/audio_if.h>
+#include <dev/midi_if.h>
#include <dev/mulaw.h>
#include <dev/isa/isavar.h>
@@ -107,14 +108,22 @@ sb_isapnp_attach(parent, self, aux)
} else
sc->sc_drq16 = DRQUNK;
- /*
- * isapnp is a child if isa, and we needs isa for the dma
- * routines
- */
- sc->sc_isa = parent->dv_parent;
+#if NMIDI > 0
+ if (ia->ipa_nio > 1) {
+ sc->sc_mpu_sc.iobase = ia->ipa_io[1].base;
+ sc->sc_mpu_sc.ioh = ia->ipa_io[1].h;
+ } else
+ sc->sc_mpu_sc.iobase = 0;
+#endif
- if (!sbmatch(sc))
+ if (!sbmatch(sc)) {
+ printf("%s: sbmatch failed\n", sc->sc_dev.dv_xname);
return;
+ }
+
+ printf("%s: %s %s", sc->sc_dev.dv_xname, ia->ipa_devident,
+ ia->ipa_devclass);
+ sc->sc_isa = parent;
sbattach(sc);
}
diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c
index 89cda5647d9..e3c6de44cc4 100644
--- a/sys/dev/isa/sbdsp.c
+++ b/sys/dev/isa/sbdsp.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: sbdsp.c,v 1.12 1998/04/26 21:02:59 provos Exp $ */
-/* $NetBSD: sbdsp.c,v 1.78 1998/01/30 11:55:36 bouyer Exp $ */
+/* $OpenBSD: sbdsp.c,v 1.13 1999/01/02 00:02:47 niklas Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -45,6 +44,8 @@
* Linux drivers.
*/
+#include "midi.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
@@ -61,6 +62,7 @@
#include <sys/audioio.h>
#include <dev/audio_if.h>
+#include <dev/midi_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
@@ -70,11 +72,14 @@
#include <dev/isa/sbreg.h>
#include <dev/isa/sbdspvar.h>
+
#ifdef AUDIO_DEBUG
#define DPRINTF(x) if (sbdspdebug) printf x
+#define DPRINTFN(n,x) if (sbdspdebug >= (n)) printf x
int sbdspdebug = 0;
#else
#define DPRINTF(x)
+#define DPRINTFN(n,x)
#endif
#ifndef SBDSP_NPOLL
@@ -180,12 +185,14 @@ int sbdsp_set_in_ports __P((struct sbdsp_softc *, int));
void sbdsp_set_ifilter __P((void *, int));
int sbdsp_get_ifilter __P((void *));
-static int sbdsp_dma_setup_input __P((struct sbdsp_softc *sc));
-static int sbdsp_dma_setup_output __P((struct sbdsp_softc *sc));
+int sbdsp_block_output __P((void *));
+int sbdsp_block_input __P((void *));
static int sbdsp_adjust __P((int, int));
+int sbdsp_midi_intr __P((void *));
+
#ifdef AUDIO_DEBUG
-void sb_printsc __P((struct sbdsp_softc *));
+void sb_printsc __P((struct sbdsp_softc *));
void
sb_printsc(sc)
@@ -524,13 +531,33 @@ sbdsp_set_params(addr, setmode, usemode, play, rec)
struct audio_params *p;
int mode;
+ if (sc->sc_open == SB_OPEN_MIDI)
+ return EBUSY;
+
model = sc->sc_model;
if (model > SB_16)
model = SB_16; /* later models work like SB16 */
+ /*
+ * Prior to the SB16, we have only one clock, so make the sample
+ * rates match.
+ */
+ if (!ISSB16CLASS(sc) &&
+ play->sample_rate != rec->sample_rate &&
+ usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
+ if (setmode == AUMODE_PLAY) {
+ rec->sample_rate = play->sample_rate;
+ setmode |= AUMODE_RECORD;
+ } else if (setmode == AUMODE_RECORD) {
+ play->sample_rate = rec->sample_rate;
+ setmode |= AUMODE_PLAY;
+ } else
+ return (EINVAL);
+ }
+
/* Set first record info, then play info */
- for(mode = AUMODE_RECORD; mode != -1;
- mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
+ for (mode = AUMODE_RECORD; mode != -1;
+ mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
if ((setmode & mode) == 0)
continue;
@@ -664,6 +691,7 @@ sbdsp_set_params(addr, setmode, usemode, play, rec)
p->encoding, tc, m->cmd, bmode, m->cmdchan, swcode, factor));
}
+
/*
* XXX
* Should wait for chip to be idle.
@@ -672,9 +700,9 @@ sbdsp_set_params(addr, setmode, usemode, play, rec)
sc->sc_o.run = SB_NOTRUNNING;
if (sc->sc_fullduplex &&
- (usemode & (AUMODE_PLAY | AUMODE_RECORD)) == (AUMODE_PLAY | AUMODE_RECORD) &&
+ usemode == (AUMODE_PLAY | AUMODE_RECORD) &&
sc->sc_i.dmachan == sc->sc_o.dmachan) {
- DPRINTF(("sbdsp_commit: fd=%d, usemode=%d, idma=%d, odma=%d\n", sc->sc_fullduplex, usemode, sc->sc_i.dmachan, sc->sc_o.dmachan));
+ DPRINTF(("sbdsp_set_params: fd=%d, usemode=%d, idma=%d, odma=%d\n", sc->sc_fullduplex, usemode, sc->sc_i.dmachan, sc->sc_o.dmachan));
if (sc->sc_o.dmachan == sc->sc_drq8) {
/* Use 16 bit DMA for playing by expanding the samples. */
play->sw_code = linear8_to_linear16;
@@ -685,7 +713,8 @@ sbdsp_set_params(addr, setmode, usemode, play, rec)
return EINVAL;
}
}
- DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n", sc->sc_i.dmachan, sc->sc_o.dmachan));
+ DPRINTF(("sbdsp_set_params ichan=%d, ochan=%d\n",
+ sc->sc_i.dmachan, sc->sc_o.dmachan));
return 0;
}
@@ -742,6 +771,9 @@ sbdsp_set_in_ports(sc, mask)
int bitsl, bitsr;
int sbport;
+ if (sc->sc_open == SB_OPEN_MIDI)
+ return EBUSY;
+
DPRINTF(("sbdsp_set_in_ports: model=%d, mask=%x\n",
sc->sc_mixer_model, mask));
@@ -786,7 +818,6 @@ sbdsp_set_in_ports(sc, mask)
sbdsp_mix_write(sc, SBP_RECORD_SOURCE_R, bitsr);
break;
}
-
sc->in_mask = mask;
return 0;
@@ -799,6 +830,9 @@ sbdsp_speaker_ctl(addr, newstate)
{
struct sbdsp_softc *sc = addr;
+ if (sc->sc_open == SB_OPEN_MIDI)
+ return EBUSY;
+
if ((newstate == SPKR_ON) &&
(sc->spkr_state == SPKR_OFF)) {
sbdsp_spkron(sc);
@@ -817,8 +851,7 @@ sbdsp_round_blocksize(addr, blk)
void *addr;
int blk;
{
- blk &= -4; /* round to biggest sample size */
- return blk;
+ return blk & -4; /* round to biggest sample size */
}
int
@@ -830,12 +863,14 @@ sbdsp_open(addr, flags)
DPRINTF(("sbdsp_open: sc=%p\n", sc));
- if (sc->sc_open != 0 || sbdsp_reset(sc) != 0)
- return ENXIO;
+ if (sc->sc_open != SB_CLOSED)
+ return EBUSY;
+ if (sbdsp_reset(sc) != 0)
+ return EIO;
- sc->sc_open = 1;
+ sc->sc_open = SB_OPEN_AUDIO;
sc->sc_openflags = flags;
- sc->sc_mintr = 0;
+ sc->sc_intrm = 0;
if (ISSBPRO(sc) &&
sbdsp_wdsp(sc, SB_DSP_RECORD_MONO) < 0) {
DPRINTF(("sbdsp_open: can't set mono mode\n"));
@@ -861,12 +896,12 @@ sbdsp_close(addr)
DPRINTF(("sbdsp_close: sc=%p\n", sc));
- sc->sc_open = 0;
+ sc->sc_open = SB_CLOSED;
sbdsp_spkroff(sc);
sc->spkr_state = SPKR_OFF;
sc->sc_intr8 = 0;
sc->sc_intr16 = 0;
- sc->sc_mintr = 0;
+ sc->sc_intrm = 0;
sbdsp_haltdma(sc);
DPRINTF(("sbdsp_close: closed\n"));
@@ -1079,7 +1114,7 @@ sbversion(sc)
sc->sc_model = SB_64;
else
#endif
- sc->sc_model = SB_16;
+ sc->sc_model = SB_16;
break;
}
}
@@ -1128,345 +1163,272 @@ sbdsp16_set_rate(sc, cmd, rate)
}
int
-sbdsp_dma_init_input(addr, buf, cc)
+sbdsp_trigger_input(addr, start, end, blksize, intr, arg, param)
void *addr;
- void *buf;
- int cc;
+ void *start, *end;
+ int blksize;
+ void (*intr) __P((void *));
+ void *arg;
+ struct audio_params *param;
{
struct sbdsp_softc *sc = addr;
+ int stereo = param->channels == 2;
+ int width = param->precision * param->factor;
+ int filter;
- if (sc->sc_model == SB_1)
- return 0;
- sc->sc_i.run = SB_DMARUNNING;
- DPRINTF(("sbdsp: dma start loop input addr=%p cc=%d chan=%d\n",
- buf, cc, sc->sc_i.dmachan));
- isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, buf,
- cc, NULL, DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT);
- return 0;
-}
+#ifdef DIAGNOSTIC
+ if (stereo && (blksize & 1)) {
+ DPRINTF(("stereo record odd bytes (%d)\n", blksize));
+ return (EIO);
+ }
+#endif
-static int
-sbdsp_dma_setup_input(sc)
- struct sbdsp_softc *sc;
-{
- int stereo = sc->sc_i.modep->channels == 2;
- int filter;
+ sc->sc_intrr = intr;
+ sc->sc_argr = arg;
+
+ if (width == 8) {
+#ifdef DIAGNOSTIC
+ if (sc->sc_i.dmachan != sc->sc_drq8) {
+ printf("sbdsp_trigger_input: width=%d bad chan %d\n",
+ width, sc->sc_i.dmachan);
+ return (EIO);
+ }
+#endif
+ sc->sc_intr8 = sbdsp_block_input;
+ sc->sc_arg8 = addr;
+ } else {
+#ifdef DIAGNOSTIC
+ if (sc->sc_i.dmachan != sc->sc_drq16) {
+ printf("sbdsp_trigger_input: width=%d bad chan %d\n",
+ width, sc->sc_i.dmachan);
+ return (EIO);
+ }
+#endif
+ sc->sc_intr16 = sbdsp_block_input;
+ sc->sc_arg16 = addr;
+ }
+
+ if ((sc->sc_model == SB_JAZZ) ? (sc->sc_i.dmachan > 3) : (width == 16))
+ blksize >>= 1;
+ --blksize;
+ sc->sc_i.blksize = blksize;
- /* Initialize the PCM */
if (ISSBPRO(sc)) {
if (sbdsp_wdsp(sc, sc->sc_i.modep->cmdchan) < 0)
- return 0;
+ return (EIO);
filter = stereo ? SBP_FILTER_OFF : sc->in_filter;
sbdsp_mix_write(sc, SBP_INFILTER,
- (sbdsp_mix_read(sc, SBP_INFILTER) &
- ~SBP_IFILTER_MASK) | filter);
+ (sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK) |
+ filter);
}
if (ISSB16CLASS(sc)) {
- if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE,
- sc->sc_i.rate)) {
- DPRINTF(("sbdsp_dma_setup_input: rate=%d set failed\n",
+ if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, sc->sc_i.rate)) {
+ DPRINTF(("sbdsp_trigger_input: rate=%d set failed\n",
sc->sc_i.rate));
- return 0;
+ return (EIO);
}
} else {
if (sbdsp_set_timeconst(sc, sc->sc_i.tc)) {
- DPRINTF(("sbdsp_dma_setup_input: tc=%d set failed\n",
+ DPRINTF(("sbdsp_trigger_input: tc=%d set failed\n",
sc->sc_i.rate));
- return 0;
+ return (EIO);
}
}
- return 1;
+
+ DPRINTF(("sbdsp: dma start loop input start=%p end=%p chan=%d\n",
+ start, end, sc->sc_i.dmachan));
+ isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, start, end - start,
+ NULL, DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT);
+
+ return sbdsp_block_input(addr);
}
int
-sbdsp_dma_input(addr, p, cc, intr, arg)
+sbdsp_block_input(addr)
void *addr;
- void *p;
- int cc;
- void (*intr) __P((void *));
- void *arg;
{
struct sbdsp_softc *sc = addr;
+ int cc = sc->sc_i.blksize;
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 1)
- printf("sbdsp_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n",
- addr, p, cc, intr, arg);
-#endif
-#ifdef DIAGNOSTIC
- if (sc->sc_i.modep->channels == 2 && (cc & 1)) {
- DPRINTF(("stereo record odd bytes (%d)\n", cc));
- return EIO;
- }
-#endif
+ DPRINTFN(2, ("sbdsp_block_input: sc=%p cc=%d\n", addr, cc));
- if (sc->sc_i.modep->precision == 8) {
-#ifdef DIAGNOSTIC
- if (sc->sc_i.dmachan != sc->sc_drq8) {
- printf("sbdsp_dma_input: prec=%d bad chan %d\n",
- sc->sc_i.modep->precision, sc->sc_i.dmachan);
- return EIO;
- }
-#endif
- sc->sc_intr8 = intr;
- sc->sc_arg8 = arg;
- } else {
-#ifdef DIAGNOSTIC
- if (sc->sc_i.dmachan != sc->sc_drq16) {
- printf("sbdsp_dma_input: prec=%d bad chan %d\n",
- sc->sc_i.modep->precision, sc->sc_i.dmachan);
- return EIO;
- }
-#endif
- sc->sc_intr16 = intr;
- sc->sc_arg16 = arg;
- }
-
- switch(sc->sc_i.run) {
- case SB_NOTRUNNING:
- /* Non-looping mode, not initialized */
- sc->sc_i.run = SB_RUNNING;
- if (!sbdsp_dma_setup_input(sc))
- goto giveup;
- /* fall into */
- case SB_RUNNING:
+ if (sc->sc_i.run != SB_NOTRUNNING)
+ sc->sc_intrr(sc->sc_argr);
+
+ if (sc->sc_model == SB_1) {
/* Non-looping mode, start DMA */
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 2)
- printf("sbdsp_dma_input: dmastart buf=%p cc=%d chan=%d\n",
- p, cc, sc->sc_i.dmachan);
-#endif
- isa_dmastart(sc->sc_isa, sc->sc_i.dmachan, p,
- cc, NULL, DMAMODE_READ, BUS_DMA_NOWAIT);
-
- /* Start PCM in non-looping mode */
- if ((sc->sc_model == SB_JAZZ && sc->sc_i.dmachan > 3) ||
- (sc->sc_model != SB_JAZZ && sc->sc_i.modep->precision == 16))
- cc >>= 1;
- --cc;
if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_input: SB1 DMA start failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_input: SB1 DMA start failed\n"));
+ return (EIO);
}
- break;
- case SB_DMARUNNING:
- /* Looping mode, not initialized */
- sc->sc_i.run = SB_PCMRUNNING;
- if (!sbdsp_dma_setup_input(sc))
- goto giveup;
- if ((sc->sc_model == SB_JAZZ && sc->sc_i.dmachan > 3) ||
- (sc->sc_model != SB_JAZZ && sc->sc_i.modep->precision == 16))
- cc >>= 1;
- --cc;
+ sc->sc_i.run = SB_RUNNING;
+ } else if (sc->sc_i.run == SB_NOTRUNNING) {
/* Initialize looping PCM */
if (ISSB16CLASS(sc)) {
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 2)
- printf("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n",
- sc->sc_i.modep->cmd, sc->sc_i.bmode, cc);
-#endif
+ DPRINTFN(3, ("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n",
+ sc->sc_i.modep->cmd, sc->sc_i.bmode, cc));
if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0 ||
sbdsp_wdsp(sc, sc->sc_i.bmode) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_input: SB16 DMA start failed\n"));
- DPRINTF(("sbdsp16 input command cmd=0x%02x bmode=0x%02x cc=%d\n",
- sc->sc_i.modep->cmd, sc->sc_i.bmode, cc));
- goto giveup;
+ DPRINTF(("sbdsp_block_input: SB16 DMA start failed\n"));
+ return (EIO);
}
} else {
- DPRINTF(("sbdsp_dma_input: set blocksize=%d\n", cc));
+ DPRINTF(("sbdsp_block_input: set blocksize=%d\n", cc));
if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_input: SB2 DMA blocksize failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_input: SB2 DMA blocksize failed\n"));
+ return (EIO);
}
if (sbdsp_wdsp(sc, sc->sc_i.modep->cmd) < 0) {
- DPRINTF(("sbdsp_dma_input: SB2 DMA start failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_input: SB2 DMA start failed\n"));
+ return (EIO);
}
}
- break;
- case SB_PCMRUNNING:
- /* Looping mode, nothing to do */
- break;
+ sc->sc_i.run = SB_LOOPING;
}
- return 0;
-giveup:
- sbdsp_reset(sc);
- return EIO;
+ return (0);
}
int
-sbdsp_dma_init_output(addr, buf, cc)
+sbdsp_trigger_output(addr, start, end, blksize, intr, arg, param)
void *addr;
- void *buf;
- int cc;
+ void *start, *end;
+ int blksize;
+ void (*intr) __P((void *));
+ void *arg;
+ struct audio_params *param;
{
struct sbdsp_softc *sc = addr;
+ int stereo = param->channels == 2;
+ int width = param->precision * param->factor;
+ int cmd;
- if (sc->sc_model == SB_1)
- return 0;
- sc->sc_o.run = SB_DMARUNNING;
- DPRINTF(("sbdsp: dma start loop output buf=%p cc=%d chan=%d\n",
- buf, cc, sc->sc_o.dmachan));
- isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, buf,
- cc, NULL, DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
- return 0;
-}
+#ifdef DIAGNOSTIC
+ if (stereo && (blksize & 1)) {
+ DPRINTF(("stereo playback odd bytes (%d)\n", blksize));
+ return (EIO);
+ }
+#endif
-static int
-sbdsp_dma_setup_output(sc)
- struct sbdsp_softc *sc;
-{
- int stereo = sc->sc_o.modep->channels == 2;
- int cmd;
+ sc->sc_intrp = intr;
+ sc->sc_argp = arg;
+
+ if (width == 8) {
+#ifdef DIAGNOSTIC
+ if (sc->sc_o.dmachan != sc->sc_drq8) {
+ printf("sbdsp_trigger_output: width=%d bad chan %d\n",
+ width, sc->sc_o.dmachan);
+ return (EIO);
+ }
+#endif
+ sc->sc_intr8 = sbdsp_block_output;
+ sc->sc_arg8 = addr;
+ } else {
+#ifdef DIAGNOSTIC
+ if (sc->sc_o.dmachan != sc->sc_drq16) {
+ printf("sbdsp_trigger_output: width=%d bad chan %d\n",
+ width, sc->sc_o.dmachan);
+ return (EIO);
+ }
+#endif
+ sc->sc_intr16 = sbdsp_block_output;
+ sc->sc_arg16 = addr;
+ }
+
+ if ((sc->sc_model == SB_JAZZ) ? (sc->sc_o.dmachan > 3) : (width == 16))
+ blksize >>= 1;
+ --blksize;
+ sc->sc_o.blksize = blksize;
if (ISSBPRO(sc)) {
/* make sure we re-set stereo mixer bit when we start output. */
sbdsp_mix_write(sc, SBP_STEREO,
- (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) |
- (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
+ (sbdsp_mix_read(sc, SBP_STEREO) & ~SBP_PLAYMODE_MASK) |
+ (stereo ? SBP_PLAYMODE_STEREO : SBP_PLAYMODE_MONO));
cmd = sc->sc_o.modep->cmdchan;
if (cmd && sbdsp_wdsp(sc, cmd) < 0)
- return 0;
+ return (EIO);
}
if (ISSB16CLASS(sc)) {
- if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE,
- sc->sc_o.rate)) {
- DPRINTF(("sbdsp_dma_setup_output: rate=%d set failed\n",
+ if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, sc->sc_o.rate)) {
+ DPRINTF(("sbdsp_trigger_output: rate=%d set failed\n",
sc->sc_o.rate));
- return 0;
+ return (EIO);
}
} else {
if (sbdsp_set_timeconst(sc, sc->sc_o.tc)) {
- DPRINTF(("sbdsp_dma_setup_output: tc=%d set failed\n",
+ DPRINTF(("sbdsp_trigger_output: tc=%d set failed\n",
sc->sc_o.rate));
- return 0;
+ return (EIO);
}
}
- return 1;
+
+ DPRINTF(("sbdsp: dma start loop output start=%p end=%p chan=%d\n",
+ start, end, sc->sc_o.dmachan));
+ isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, start, end - start,
+ NULL, DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
+
+ return sbdsp_block_output(addr);
}
int
-sbdsp_dma_output(addr, p, cc, intr, arg)
+sbdsp_block_output(addr)
void *addr;
- void *p;
- int cc;
- void (*intr) __P((void *));
- void *arg;
{
struct sbdsp_softc *sc = addr;
+ int cc = sc->sc_o.blksize;
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 1)
- printf("sbdsp_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n", addr, p, cc, intr, arg);
-#endif
-#ifdef DIAGNOSTIC
- if (sc->sc_o.modep->channels == 2 && (cc & 1)) {
- DPRINTF(("stereo playback odd bytes (%d)\n", cc));
- return EIO;
- }
-#endif
+ DPRINTFN(2, ("sbdsp_block_output: sc=%p cc=%d\n", addr, cc));
- if (sc->sc_o.modep->precision == 8) {
-#ifdef DIAGNOSTIC
- if (sc->sc_o.dmachan != sc->sc_drq8) {
- printf("sbdsp_dma_output: prec=%d bad chan %d\n",
- sc->sc_o.modep->precision, sc->sc_o.dmachan);
- return EIO;
- }
-#endif
- sc->sc_intr8 = intr;
- sc->sc_arg8 = arg;
- } else {
-#ifdef DIAGNOSTIC
- if (sc->sc_o.dmachan != sc->sc_drq16) {
- printf("sbdsp_dma_output: prec=%d bad chan %d\n",
- sc->sc_o.modep->precision, sc->sc_o.dmachan);
- return EIO;
- }
-#endif
- sc->sc_intr16 = intr;
- sc->sc_arg16 = arg;
- }
+ if (sc->sc_o.run != SB_NOTRUNNING)
+ sc->sc_intrp(sc->sc_argp);
- switch(sc->sc_o.run) {
- case SB_NOTRUNNING:
- /* Non-looping mode, not initialized */
- sc->sc_o.run = SB_RUNNING;
- if (!sbdsp_dma_setup_output(sc))
- goto giveup;
- /* fall into */
- case SB_RUNNING:
+ if (sc->sc_model == SB_1) {
/* Non-looping mode, initialized. Start DMA and PCM */
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 2)
- printf("sbdsp: start dma out addr=%p, cc=%d, chan=%d\n",
- p, cc, sc->sc_o.dmachan);
-#endif
- isa_dmastart(sc->sc_isa, sc->sc_o.dmachan, p,
- cc, NULL, DMAMODE_WRITE, BUS_DMA_NOWAIT);
- if ((sc->sc_model == SB_JAZZ && sc->sc_o.dmachan > 3) ||
- (sc->sc_model != SB_JAZZ && sc->sc_o.modep->precision == 16))
- cc >>= 1;
- --cc;
if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_output: SB1 DMA start failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_output: SB1 DMA start failed\n"));
+ return (EIO);
}
- break;
- case SB_DMARUNNING:
- /* Looping mode, not initialized */
- sc->sc_o.run = SB_PCMRUNNING;
- if (!sbdsp_dma_setup_output(sc))
- goto giveup;
- if ((sc->sc_model == SB_JAZZ && sc->sc_o.dmachan > 3) ||
- (sc->sc_model != SB_JAZZ && sc->sc_o.modep->precision == 16))
- cc >>= 1;
- --cc;
+ sc->sc_o.run = SB_RUNNING;
+ } else if (sc->sc_o.run == SB_NOTRUNNING) {
/* Initialize looping PCM */
if (ISSB16CLASS(sc)) {
- DPRINTF(("sbdsp_dma_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n",
- sc->sc_o.modep->cmd,sc->sc_o.bmode, cc));
+ DPRINTF(("sbdsp_block_output: SB16 cmd=0x%02x bmode=0x%02x cc=%d\n",
+ sc->sc_o.modep->cmd,sc->sc_o.bmode, cc));
if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0 ||
sbdsp_wdsp(sc, sc->sc_o.bmode) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_output: SB16 DMA start failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_output: SB16 DMA start failed\n"));
+ return (EIO);
}
} else {
- DPRINTF(("sbdsp_dma_output: set blocksize=%d\n", cc));
+ DPRINTF(("sbdsp_block_output: set blocksize=%d\n", cc));
if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 ||
sbdsp_wdsp(sc, cc) < 0 ||
sbdsp_wdsp(sc, cc >> 8) < 0) {
- DPRINTF(("sbdsp_dma_output: SB2 DMA blocksize failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_output: SB2 DMA blocksize failed\n"));
+ return (EIO);
}
if (sbdsp_wdsp(sc, sc->sc_o.modep->cmd) < 0) {
- DPRINTF(("sbdsp_dma_output: SB2 DMA start failed\n"));
- goto giveup;
+ DPRINTF(("sbdsp_block_output: SB2 DMA start failed\n"));
+ return (EIO);
}
}
- break;
- case SB_PCMRUNNING:
- /* Looping mode, nothing to do */
- break;
+ sc->sc_o.run = SB_LOOPING;
}
- return 0;
-giveup:
- sbdsp_reset(sc);
- return EIO;
+ return (0);
}
/*
@@ -1484,94 +1446,44 @@ sbdsp_intr(arg)
void *arg;
{
struct sbdsp_softc *sc = arg;
- int loop = sc->sc_model != SB_1;
u_char irq;
-#ifdef AUDIO_DEBUG
- if (sbdspdebug > 1)
- printf("sbdsp_intr: intr8=%p, intr16=%p\n",
- sc->sc_intr8, sc->sc_intr16);
-#endif
+ DPRINTFN(2, ("sbdsp_intr: intr8=%p, intr16=%p\n",
+ sc->sc_intr8, sc->sc_intr16));
if (ISSB16CLASS(sc)) {
irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS);
- if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16)) == 0) {
+ if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16 | SBP_IRQ_MPU401)) == 0) {
DPRINTF(("sbdsp_intr: Spurious interrupt 0x%x\n", irq));
return 0;
}
} else {
- if (!loop && !isa_dmafinished(sc->sc_isa, sc->sc_drq8))
- return 0;
+ /* XXXX CHECK FOR INTERRUPT */
irq = SBP_IRQ_DMA8;
}
+
sc->sc_interrupts++;
delay(10); /* XXX why? */
-#if 0
- if (sc->sc_mintr != 0) {
- x = sbdsp_rdsp(sc);
- (*sc->sc_mintr)(sc->sc_arg, x);
- } else
-#endif
- if (sc->sc_intr8 == 0 && sc->sc_intr16 == 0) {
- DPRINTF(("sbdsp_intr: Unexpected interrupt 0x%x\n", irq));
- /* XXX return 0;*/ /* Did not expect an interrupt */
- }
/* clear interrupt */
if (irq & SBP_IRQ_DMA8) {
bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK8);
- if (!loop)
- isa_dmadone(sc->sc_isa, sc->sc_drq8);
if (sc->sc_intr8)
- (*sc->sc_intr8)(sc->sc_arg8);
+ sc->sc_intr8(sc->sc_arg8);
}
if (irq & SBP_IRQ_DMA16) {
bus_space_read_1(sc->sc_iot, sc->sc_ioh, SBP_DSP_IRQACK16);
if (sc->sc_intr16)
- (*sc->sc_intr16)(sc->sc_arg16);
+ sc->sc_intr16(sc->sc_arg16);
}
+#if NMIDI > 0
+ if ((irq & SBP_IRQ_MPU401) && sc->sc_hasmpu) {
+ mpu401_intr(&sc->sc_mpu_sc);
+ }
+#endif
return 1;
}
-#if 0
-/*
- * Enter midi uart mode and arrange for read interrupts
- * to vector to `intr'. This puts the card in a mode
- * which allows only midi I/O; the card must be reset
- * to leave this mode. Unfortunately, the card does not
- * use transmit interrupts, so bytes must be output
- * using polling. To keep the polling overhead to a
- * minimum, output should be driven off a timer.
- * This is a little tricky since only 320us separate
- * consecutive midi bytes.
- */
-void
-sbdsp_set_midi_mode(sc, intr, arg)
- struct sbdsp_softc *sc;
- void (*intr)();
- void *arg;
-{
-
- sbdsp_wdsp(sc, SB_MIDI_UART_INTR);
- sc->sc_mintr = intr;
- sc->sc_intr = 0;
- sc->sc_arg = arg;
-}
-
-/*
- * Write a byte to the midi port, when in midi uart mode.
- */
-void
-sbdsp_midi_output(sc, v)
- struct sbdsp_softc *sc;
- int v;
-{
-
- if (sbdsp_wdsp(sc, v) < 0)
- ++sberr.wmidi;
-}
-#endif
-
-/* Mask a value 0-255, but round it first */
+/* Like val & mask, but make sure the result is correctly rounded. */
#define MAXVAL 256
static int
sbdsp_adjust(val, mask)
@@ -1698,6 +1610,9 @@ sbdsp_mixer_set_port(addr, cp)
int lmask, rmask, lbits, rbits;
int mute, swap;
+ if (sc->sc_open == SB_OPEN_MIDI)
+ return EBUSY;
+
DPRINTF(("sbdsp_mixer_set_port: port=%d num_channels=%d\n", cp->dev,
cp->un.value.num_channels));
@@ -1882,6 +1797,9 @@ sbdsp_mixer_get_port(addr, cp)
{
struct sbdsp_softc *sc = addr;
+ if (sc->sc_open == SB_OPEN_MIDI)
+ return EBUSY;
+
DPRINTF(("sbdsp_mixer_get_port: port=%d\n", cp->dev));
if (sc->sc_mixer_model == SBM_NONE)
@@ -2175,7 +2093,7 @@ sbdsp_mixer_query_devinfo(addr, dip)
dip->type = AUDIO_MIXER_ENUM;
dip->mixer_class = SB_INPUT_CLASS;
dip->prev = dip->next = AUDIO_MIXER_LAST;
- strcpy(dip->label.name, "AGC");
+ strcpy(dip->label.name, "agc");
dip->un.e.num_mem = 2;
strcpy(dip->un.e.member[0].label.name, AudioNoff);
dip->un.e.member[0].ord = 0;
@@ -2315,6 +2233,91 @@ sbdsp_get_props(addr)
void *addr;
{
struct sbdsp_softc *sc = addr;
- return AUDIO_PROP_MMAP |
+ return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
(sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0);
}
+
+#if NMIDI > 0
+/*
+ * MIDI related routines.
+ */
+
+int
+sbdsp_midi_open(addr, flags, iintr, ointr, arg)
+ void *addr;
+ int flags;
+ void (*iintr)__P((void *, int));
+ void (*ointr)__P((void *));
+ void *arg;
+{
+ struct sbdsp_softc *sc = addr;
+
+ DPRINTF(("sbdsp_midi_open: sc=%p\n", sc));
+
+ if (sc->sc_open != SB_CLOSED)
+ return EBUSY;
+ if (sbdsp_reset(sc) != 0)
+ return EIO;
+
+ if (sc->sc_model >= SB_20)
+ if (sbdsp_wdsp(sc, SB_MIDI_UART_INTR)) /* enter UART mode */
+ return EIO;
+ sc->sc_open = SB_OPEN_MIDI;
+ sc->sc_openflags = flags;
+ sc->sc_intr8 = sbdsp_midi_intr;
+ sc->sc_arg8 = addr;
+ sc->sc_intrm = iintr;
+ sc->sc_argm = arg;
+ return 0;
+}
+
+void
+sbdsp_midi_close(addr)
+ void *addr;
+{
+ struct sbdsp_softc *sc = addr;
+
+ DPRINTF(("sbdsp_midi_close: sc=%p\n", sc));
+
+ if (sc->sc_model >= SB_20)
+ sbdsp_reset(sc); /* exit UART mode */
+ sc->sc_open = SB_CLOSED;
+ sc->sc_intrm = 0;
+}
+
+int
+sbdsp_midi_output(addr, d)
+ void *addr;
+ int d;
+{
+ struct sbdsp_softc *sc = addr;
+
+ if (sc->sc_model < SB_20 && sbdsp_wdsp(sc, SB_MIDI_WRITE))
+ return EIO;
+ if (sbdsp_wdsp(sc, d))
+ return EIO;
+ return 0;
+}
+
+void
+sbdsp_midi_getinfo(addr, mi)
+ void *addr;
+ struct midi_info *mi;
+{
+ struct sbdsp_softc *sc = addr;
+
+ mi->name = sc->sc_model < SB_20 ? "SB MIDI cmd" : "SB MIDI UART";
+ mi->props = MIDI_PROP_CAN_INPUT;
+}
+
+int
+sbdsp_midi_intr(addr)
+ void *addr;
+{
+ struct sbdsp_softc *sc = addr;
+
+ sc->sc_intrm(sc->sc_argm, sbdsp_rdsp(sc));
+ return (0);
+}
+
+#endif
diff --git a/sys/dev/isa/sbdspvar.h b/sys/dev/isa/sbdspvar.h
index c70a012f447..3f8e5b5cb7e 100644
--- a/sys/dev/isa/sbdspvar.h
+++ b/sys/dev/isa/sbdspvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: sbdspvar.h,v 1.8 1998/04/26 21:03:01 provos Exp $ */
-/* $NetBSD: sbdspvar.h,v 1.33 1997/10/19 07:42:44 augustss Exp $ */
+/* $OpenBSD: sbdspvar.h,v 1.9 1999/01/02 00:02:47 niklas Exp $ */
+/* $NetBSD: sbdspvar.h,v 1.37 1998/08/10 00:20:39 mycroft Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -35,6 +35,11 @@
*
*/
+#include "midi.h"
+#if NMIDI > 0
+#include <dev/isa/mpu401var.h>
+#endif
+
#define SB_MASTER_VOL 0
#define SB_MIDI_VOL 1
#define SB_CD_VOL 2
@@ -94,15 +99,18 @@ struct sbdsp_softc {
bus_space_tag_t sc_iot; /* tag */
bus_space_handle_t sc_ioh; /* handle */
void *sc_ih; /* interrupt vectoring */
+ struct device *sc_isa;
int sc_iobase; /* I/O port base address */
int sc_irq; /* interrupt */
+ int sc_ist; /* interrupt share type */
int sc_drq8; /* DMA (8-bit) */
int sc_drq16; /* DMA (16-bit) */
- struct device *sc_isa; /* pointer to ISA parent */
-
- u_short sc_open; /* reference count of open calls */
+ int sc_open; /* reference count of open calls */
+#define SB_CLOSED 0
+#define SB_OPEN_AUDIO 1
+#define SB_OPEN_MIDI 2
int sc_openflags; /* flags used on open */
u_char sc_fullduplex; /* can do full duplex */
@@ -123,19 +131,25 @@ struct sbdsp_softc {
struct sbmode *modep;
u_char bmode;
int dmachan; /* DMA channel */
+ int blksize; /* Block size, preadjusted */
u_char run;
#define SB_NOTRUNNING 0 /* Not running, not initialized */
-#define SB_DMARUNNING 1 /* DMA has been initialized */
-#define SB_PCMRUNNING 2 /* DMA&PCM running (looping mode) */
#define SB_RUNNING 3 /* non-looping mode */
+#define SB_LOOPING 2 /* DMA&PCM running (looping mode) */
} sc_i, sc_o; /* Input and output state */
u_long sc_interrupts; /* number of interrupts taken */
- void (*sc_intr8)(void*); /* dma completion intr handler */
+
+ int (*sc_intr8)(void*); /* dma completion intr handler */
void *sc_arg8; /* arg for sc_intr8() */
- void (*sc_intr16)(void*); /* dma completion intr handler */
+ int (*sc_intr16)(void*); /* dma completion intr handler */
void *sc_arg16; /* arg for sc_intr16() */
- void (*sc_mintr)(void*, int);/* midi input intr handler */
+ void (*sc_intrp)(void*); /* PCM output intr handler */
+ void *sc_argp; /* arg for sc_intrp() */
+ void (*sc_intrr)(void*); /* PCM input intr handler */
+ void *sc_argr; /* arg for sc_intrr() */
+ void (*sc_intrm)(void*, int);/* midi input intr handler */
+ void *sc_argm; /* arg for sc_intrm() */
u_int sc_mixer_model;
#define SBM_NONE 0
@@ -161,6 +175,11 @@ struct sbdsp_softc {
u_int sc_version; /* DSP version */
#define SBVER_MAJOR(v) (((v)>>8) & 0xff)
#define SBVER_MINOR(v) ((v)&0xff)
+
+#if NMIDI > 0
+ int sc_hasmpu;
+ struct mpu401_softc sc_mpu_sc; /* MPU401 Uart state */
+#endif
};
#define ISSBPRO(sc) ((sc)->sc_model == SB_PRO || (sc)->sc_model == SB_JAZZ)
@@ -190,10 +209,10 @@ int sbdsp_get_avail_out_ports __P((void *));
int sbdsp_speaker_ctl __P((void *, int));
int sbdsp_commit __P((void *));
-int sbdsp_dma_init_input __P((void *, void *, int));
-int sbdsp_dma_init_output __P((void *, void *, int));
-int sbdsp_dma_output __P((void *, void *, int, void (*)(void *), void*));
-int sbdsp_dma_input __P((void *, void *, int, void (*)(void *), void*));
+int sbdsp_trigger_output __P((void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *));
+int sbdsp_trigger_input __P((void *, void *, void *, int, void (*)(void *),
+ void *, struct audio_params *));
int sbdsp_haltdma __P((void *));
@@ -225,4 +244,11 @@ int sb_mappage __P((void *, void *, int, int));
int sbdsp_get_props __P((void *));
+
+int sbdsp_midi_open __P((void *, int,
+ void (*iintr)__P((void *, int)),
+ void (*ointr)__P((void *)), void *arg));
+void sbdsp_midi_close __P((void *));
+int sbdsp_midi_output __P((void *, int));
+void sbdsp_midi_getinfo __P((void *, struct midi_info *));
#endif
diff --git a/sys/arch/i386/isa/spkr.c b/sys/dev/isa/spkr.c
index c37be3b7bdc..09b2181861e 100644
--- a/sys/arch/i386/isa/spkr.c
+++ b/sys/dev/isa/spkr.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: spkr.c,v 1.12 1997/10/24 00:00:01 mickey Exp $ */
-/* $NetBSD: spkr.c,v 1.23.4.1 1996/07/15 22:15:11 fvdl Exp $ */
+/* $OpenBSD: spkr.c,v 1.1 1999/01/02 00:02:43 niklas Exp $ */
+/* $NetBSD: spkr.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */
/*
* spkr.c -- device driver for console speaker on 80386
@@ -10,32 +10,24 @@
* use hz value from param.c
*/
-#include "spkr.h"
-#if NSPKR > 0
-#if NSPKR > 1
-#error only one speaker device per system
-#endif
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/device.h>
-#include <sys/buf.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/conf.h>
+
+#include <dev/isa/pcppivar.h>
-#include <machine/cpu.h>
-#include <machine/pio.h>
-#include <machine/spkr.h>
-#include <machine/conf.h>
+#include <dev/isa/spkrio.h>
-#include <dev/isa/isareg.h>
-#include <dev/isa/isavar.h>
-#include <i386/isa/timerreg.h>
-#include <i386/isa/spkrreg.h>
+cdev_decl(spkr);
-int spkrprobe __P((struct device *, void *, void *));
+int spkrprobe __P((struct device *, struct cfdata *, void *));
void spkrattach __P((struct device *, struct device *, void *));
struct spkr_softc {
@@ -46,81 +38,22 @@ struct cfattach spkr_ca = {
sizeof(struct spkr_softc), spkrprobe, spkrattach
};
-struct cfdriver spkr_cd = {
- NULL, "spkr", DV_TTY
-};
+static pcppi_tag_t ppicookie;
-/**************** MACHINE DEPENDENT PART STARTS HERE *************************
- *
- * This section defines a function tone() which causes a tone of given
- * frequency and duration from the 80x86's console speaker.
- * Another function endtone() is defined to force sound off, and there is
- * also a rest() entry point to do pauses.
- *
- * Audible sound is generated using the Programmable Interval Timer (PIT) and
- * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
- * PPI controls whether sound is passed through at all; the PIT's channel 2 is
- * used to generate clicks (a square wave) of whatever frequency is desired.
- */
+#define SPKRPRI (PZERO - 1)
-/*
- * Magic numbers for timer control.
- */
-#define PIT_MODE (TIMER_SEL2|TIMER_16BIT|TIMER_SQWAVE)
-
-static void endtone __P((void *));
static void tone __P((u_int, u_int));
-static void endrest __P((void *));
static void rest __P((int));
static void playinit __P((void));
static void playtone __P((int, int, int));
static void playstring __P((char *, int));
-static void
-endtone(v)
- void *v;
-{
- wakeup(endtone);
- outb(PITAUX_PORT, inb(PITAUX_PORT) & ~PIT_SPKR);
-}
-
static
void tone(hz, ticks)
/* emit tone of frequency hz for given number of ticks */
u_int hz, ticks;
{
- u_int divisor = TIMER_DIV(hz);
- int sps;
-
-#ifdef SPKR_DEBUG
- printf("tone: hz=%d ticks=%d\n", hz, ticks);
-#endif /* SPKR_DEBUG */
-
- /* set timer to generate clicks at given frequency in Hertz */
- sps = spltty();
- outb(TIMER_MODE, PIT_MODE); /* prepare timer */
- outb(TIMER_CNTR2, (unsigned char) divisor); /* send lo byte */
- outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
- splx(sps);
-
- /* turn the speaker on */
- outb(PITAUX_PORT, inb(PITAUX_PORT) | PIT_SPKR);
-
- /*
- * Set timeout to endtone function, then give up the timeslice.
- * This is so other processes can execute while the tone is being
- * emitted.
- */
- timeout(endtone, NULL, ticks);
- sleep(endtone, PZERO - 1);
-}
-
-static void
-endrest(v)
-/* end a rest */
- void *v;
-{
- wakeup(endrest);
+ pcppi_bell(ppicookie, hz, ticks, 1);
}
static void
@@ -133,11 +66,11 @@ rest(ticks)
* This is so other processes can execute while the rest is being
* waited out.
*/
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("rest: %d\n", ticks);
-#endif /* SPKR_DEBUG */
- timeout(endrest, NULL, ticks);
- sleep(endrest, PZERO - 1);
+#endif /* SPKRDEBUG */
+ if (ticks > 0)
+ tsleep(rest, SPKRPRI | PCATCH, "rest", ticks);
}
/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
@@ -236,10 +169,10 @@ playtone(pitch, value, sustain)
- (whole * (FILLTIME - fill)) / (value * FILLTIME);
silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
- pitch, sound, silence);
-#endif /* SPKR_DEBUG */
+ pitch, sound, silence);
+#endif /* SPKRDEBUG */
tone(pitchtab[pitch], sound);
if (fill != LEGATO)
@@ -255,16 +188,16 @@ playstring(cp, slen)
{
int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
-#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+#define GETNUM(cp, v) for(v=0; slen > 0 && isdigit(cp[1]); ) \
{v = v * 10 + (*++cp - '0'); slen--;}
for (; slen--; cp++)
{
int sustain, timeval, tempo;
register char c = toupper(*cp);
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("playstring: %c (%x)\n", c, c);
-#endif /* SPKR_DEBUG */
+#endif /* SPKRDEBUG */
switch (c)
{
@@ -427,58 +360,27 @@ playstring(cp, slen)
*/
static int spkr_active; /* exclusion flag */
-static struct buf *spkr_inbuf; /* incoming buf */
+static void *spkr_inbuf;
+
+static int spkr_attached = 0;
int
spkrprobe (parent, match, aux)
struct device *parent;
- void *match;
+ struct cfdata *match;
void *aux;
{
- struct cfdata *cf = match;
-#include "vt.h"
-#include "pc.h"
-#if NPC > 0
- extern struct cfattach pc_ca;
-#endif
-#if NVT > 0
- extern struct cfattach vt_ca;
-#endif
- /*
- * We only attach to the keyboard controller via
- * the console drivers. (We really wish we could be the
- * child of a real keyboard controller driver.)
- */
- if ((parent == NULL) || (parent->dv_cfdata == NULL) ||
- (
-#if NPC > 0
- (parent->dv_cfdata->cf_attach != &pc_ca)
-#endif
-#if NPC > 0 && NVT > 0 /* XXX could we have both of them ??? */
- &&
-#endif
-#if NVT > 0
- (parent->dv_cfdata->cf_attach != &vt_ca)
-#endif
-#if NPC == 0 && NVT == 0
- 1
-#endif
- ))
- return (0);
- if (cf->cf_loc[1] != PITAUX_PORT)
- return (0);
- return (1);
+ return (!spkr_attached);
}
-static int spkr_attached = 0;
-
void
spkrattach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
{
- printf(" port 0x%x\n", self->dv_cfdata->cf_loc[1]);
+ printf("\n");
+ ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
spkr_attached = 1;
}
@@ -489,9 +391,9 @@ spkropen(dev, flags, mode, p)
int mode;
struct proc *p;
{
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("spkropen: entering with dev = %x\n", dev);
-#endif /* SPKR_DEBUG */
+#endif /* SPKRDEBUG */
if (minor(dev) != 0 || !spkr_attached)
return(ENXIO);
@@ -500,7 +402,7 @@ spkropen(dev, flags, mode, p)
else
{
playinit();
- spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_inbuf = malloc(DEV_BSIZE, M_DEVBUF, M_WAITOK);
spkr_active = 1;
}
return(0);
@@ -513,22 +415,20 @@ spkrwrite(dev, uio, flags)
int flags;
{
register int n;
- char *cp;
int error;
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("spkrwrite: entering with dev = %x, count = %d\n",
dev, uio->uio_resid);
-#endif /* SPKR_DEBUG */
+#endif /* SPKRDEBUG */
- if (minor(dev) != 0 || !spkr_attached)
+ if (minor(dev) != 0)
return(ENXIO);
else
{
n = min(DEV_BSIZE, uio->uio_resid);
- cp = spkr_inbuf->b_data;
- error = uiomove(cp, n, uio);
+ error = uiomove(spkr_inbuf, n, uio);
if (!error)
- playstring(cp, n);
+ playstring((char *)spkr_inbuf, n);
return(error);
}
}
@@ -539,16 +439,16 @@ int spkrclose(dev, flags, mode, p)
int mode;
struct proc *p;
{
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("spkrclose: entering with dev = %x\n", dev);
-#endif /* SPKR_DEBUG */
+#endif /* SPKRDEBUG */
if (minor(dev) != 0)
return(ENXIO);
else
{
- endtone(NULL);
- brelse(spkr_inbuf);
+ tone(0, 0);
+ free(spkr_inbuf, M_DEVBUF);
spkr_active = 0;
}
return(0);
@@ -561,9 +461,9 @@ int spkrioctl(dev, cmd, data, flag, p)
int flag;
struct proc *p;
{
-#ifdef SPKR_DEBUG
+#ifdef SPKRDEBUG
printf("spkrioctl: entering with dev = %x, cmd = %lx\n", dev, cmd);
-#endif /* SPKR_DEBUG */
+#endif /* SPKRDEBUG */
if (minor(dev) != 0)
return(ENXIO);
@@ -599,5 +499,4 @@ int spkrioctl(dev, cmd, data, flag, p)
return(0);
}
-#endif /* NSPEAKER > 0 */
/* spkr.c ends here */
diff --git a/sys/dev/isa/spkrio.h b/sys/dev/isa/spkrio.h
new file mode 100644
index 00000000000..a852cf0782f
--- /dev/null
+++ b/sys/dev/isa/spkrio.h
@@ -0,0 +1,19 @@
+/* $OpenBSD: spkrio.h,v 1.1 1999/01/02 00:02:43 niklas Exp $ */
+/* $NetBSD: spkrio.h,v 1.1 1998/04/15 20:26:19 drochner Exp $ */
+
+/*
+ * spkr.h -- interface definitions for speaker ioctl()
+ */
+
+#ifndef _DEV_ISA_SPKR_H_
+#define _DEV_ISA_SPKR_H_
+
+#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
+#define SPKRTUNE _IO('S', 2) /* emit tone sequence */
+
+typedef struct {
+ int frequency; /* in hertz */
+ int duration; /* in 1/100ths of a second */
+} tone_t;
+
+#endif /* _DEV_ISA_SPKR_H_ */
diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c
index 9476f45fb4e..c49eb337d44 100644
--- a/sys/dev/isa/wss.c
+++ b/sys/dev/isa/wss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wss.c,v 1.17 1998/11/03 21:15:01 downsj Exp $ */
+/* $OpenBSD: wss.c,v 1.18 1999/01/02 00:02:48 niklas Exp $ */
/* $NetBSD: wss.c,v 1.42 1998/01/19 22:18:23 augustss Exp $ */
/*
@@ -153,7 +153,7 @@ wssattach(sc)
sc->sc_ad1848.parent = sc;
- audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev);
+ audio_attach_mi(&wss_hw_if, &sc->sc_ad1848, &sc->sc_dev);
}
int
diff --git a/sys/dev/isa/ym.c b/sys/dev/isa/ym.c
index a4eb9551466..04611a1c815 100644
--- a/sys/dev/isa/ym.c
+++ b/sys/dev/isa/ym.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ym.c,v 1.3 1998/12/29 09:10:30 deraadt Exp $ */
+/* $OpenBSD: ym.c,v 1.4 1999/01/02 00:02:48 niklas Exp $ */
/*
@@ -134,7 +134,7 @@ ym_attach(sc)
sc->mic_mute = 1;
ym_mute(sc, SA3_MIC, sc->mic_mute);
- audio_attach_mi(&ym_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev);
+ audio_attach_mi(&ym_hw_if, &sc->sc_ad1848, &sc->sc_dev);
}
static __inline int
diff --git a/sys/dev/midi.c b/sys/dev/midi.c
new file mode 100644
index 00000000000..565b1a7b4a3
--- /dev/null
+++ b/sys/dev/midi.c
@@ -0,0 +1,771 @@
+/* $OpenBSD: midi.c,v 1.1 1999/01/02 00:02:32 niklas Exp $ */
+/* $NetBSD: midi.c,v 1.10 1998/12/20 14:26:44 drochner Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "midi.h"
+#include "sequencer.h"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/conf.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+#include <sys/device.h>
+
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+#include <dev/midivar.h>
+
+#if NMIDI > 0
+
+#ifdef AUDIO_DEBUG
+#define DPRINTF(x) if (mididebug) printf x
+#define DPRINTFN(n,x) if (mididebug >= (n)) printf x
+int mididebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+int midi_wait;
+
+void midi_in __P((void *, int));
+void midi_out __P((void *));
+int midi_start_output __P((struct midi_softc *, int));
+int midi_sleep_timo __P((int *, char *, int));
+int midi_sleep __P((int *, char *));
+void midi_wakeup __P((int *));
+void midi_initbuf __P((struct midi_buffer *));
+void midi_timeout __P((void *));
+
+#define __BROKEN_INDIRECT_CONFIG /* XXX */
+#ifdef __BROKEN_INDIRECT_CONFIG
+int midiprobe __P((struct device *, void *, void *));
+#else
+int midiprobe __P((struct device *, struct cfdata *, void *));
+#endif
+void midiattach __P((struct device *, struct device *, void *));
+
+struct cfattach midi_ca = {
+ sizeof(struct midi_softc), midiprobe, midiattach
+};
+
+struct cfdriver midi_cd = {
+ NULL, "midi", DV_DULL
+};
+
+#ifdef MIDI_SAVE
+#define MIDI_SAVE_SIZE 100000
+int midicnt;
+struct {
+ int cnt;
+ u_char buf[MIDI_SAVE_SIZE];
+} midisave;
+#define MIDI_GETSAVE _IOWR('m', 100, int)
+
+#endif
+
+extern struct cfdriver midi_cd;
+
+int
+midiprobe(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct audio_attach_args *sa = aux;
+
+ DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n",
+ sa->type, sa, sa->hwif));
+ return ((sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0);
+}
+
+void
+midiattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct midi_softc *sc = (void *)self;
+ struct audio_attach_args *sa = aux;
+ struct midi_hw_if *hwp = sa->hwif;
+ void *hdlp = sa->hdl;
+
+ DPRINTFN(6, ("MIDI attach\n"));
+
+#ifdef DIAGNOSTIC
+ if (hwp == 0 ||
+ hwp->open == 0 ||
+ hwp->close == 0 ||
+ hwp->output == 0 ||
+ hwp->getinfo == 0) {
+ printf("midi: missing method\n");
+ return;
+ }
+#endif
+ sc->hw_if = hwp;
+ sc->hw_hdl = hdlp;
+ midi_attach(sc, parent);
+}
+
+void
+midi_attach(sc, parent)
+ struct midi_softc *sc;
+ struct device *parent;
+{
+ struct midi_info mi;
+
+ sc->isopen = 0;
+
+ midi_wait = MIDI_WAIT * hz / 1000000;
+ if (midi_wait == 0)
+ midi_wait = 1;
+
+ sc->sc_dev = parent;
+ sc->hw_if->getinfo(sc->hw_hdl, &mi);
+ sc->props = mi.props;
+ printf(": <%s>\n", mi.name);
+}
+
+int
+midi_unit_count()
+{
+ return (midi_cd.cd_ndevs);
+}
+
+void
+midi_initbuf(mb)
+ struct midi_buffer *mb;
+{
+ mb->used = 0;
+ mb->usedhigh = MIDI_BUFSIZE;
+ mb->end = mb->start + mb->usedhigh;
+ mb->inp = mb->outp = mb->start;
+}
+
+int
+midi_sleep_timo(chan, label, timo)
+ int *chan;
+ char *label;
+ int timo;
+{
+ int st;
+
+ if (!label)
+ label = "midi";
+
+ DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
+ *chan = 1;
+ st = tsleep(chan, PWAIT | PCATCH, label, timo);
+ *chan = 0;
+#ifdef MIDI_DEBUG
+ if (st != 0)
+ printf("midi_sleep: %d\n", st);
+#endif
+ return (st);
+}
+
+int
+midi_sleep(chan, label)
+ int *chan;
+ char *label;
+{
+ return (midi_sleep_timo(chan, label, 0));
+}
+
+void
+midi_wakeup(chan)
+ int *chan;
+{
+ if (*chan) {
+ DPRINTFN(5, ("midi_wakeup: %p\n", chan));
+ wakeup(chan);
+ *chan = 0;
+ }
+}
+
+static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
+/* Number of bytes in a MIDI command */
+#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
+
+void
+midi_in(addr, data)
+ void *addr;
+ int data;
+{
+ struct midi_softc *sc = addr;
+ struct midi_buffer *mb = &sc->inbuf;
+ int i;
+
+ if (!sc->isopen)
+ return;
+ if (data == MIDI_ACK)
+ return;
+ DPRINTFN(3, ("midi_in: %p 0x%02x\n", sc, data));
+ if (!(sc->flags & FREAD))
+ return; /* discard data if not reading */
+
+ switch(sc->in_state) {
+ case MIDI_IN_START:
+ if (MIDI_IS_STATUS(data)) {
+ switch(data) {
+ case 0xf0: /* Sysex */
+ sc->in_state = MIDI_IN_SYSEX;
+ break;
+ case 0xf1: /* MTC quarter frame */
+ case 0xf3: /* Song select */
+ sc->in_state = MIDI_IN_DATA;
+ sc->in_msg[0] = data;
+ sc->in_pos = 1;
+ sc->in_left = 1;
+ break;
+ case 0xf2: /* Song position pointer */
+ sc->in_state = MIDI_IN_DATA;
+ sc->in_msg[0] = data;
+ sc->in_pos = 1;
+ sc->in_left = 2;
+ break;
+ default:
+ if (MIDI_IS_COMMON(data)) {
+ sc->in_msg[0] = data;
+ sc->in_pos = 1;
+ goto deliver;
+ } else {
+ sc->in_state = MIDI_IN_DATA;
+ sc->in_msg[0] = sc->in_status = data;
+ sc->in_pos = 1;
+ sc->in_left =
+ MIDI_LENGTH(sc->in_status);
+ }
+ break;
+ }
+ } else {
+ if (MIDI_IS_STATUS(sc->in_status)) {
+ sc->in_state = MIDI_IN_DATA;
+ sc->in_msg[0] = sc->in_status;
+ sc->in_msg[1] = data;
+ sc->in_pos = 2;
+ sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
+ }
+ }
+ return;
+ case MIDI_IN_DATA:
+ sc->in_msg[sc->in_pos++] = data;
+ if (--sc->in_left <= 0)
+ break; /* deliver data */
+ return;
+ case MIDI_IN_SYSEX:
+ if (data == MIDI_SYSEX_END)
+ sc->in_state = MIDI_IN_START;
+ return;
+ }
+deliver:
+ sc->in_state = MIDI_IN_START;
+#if NSEQUENCER > 0
+ if (sc->seqopen) {
+ extern void midiseq_in __P((struct midi_dev *,u_char *,int));
+ midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos);
+ return;
+ }
+#endif
+
+ if (mb->used + sc->in_pos > mb->usedhigh) {
+ DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
+ sc->in_msg[0]));
+ return;
+ }
+ for (i = 0; i < sc->in_pos; i++) {
+ *mb->inp++ = sc->in_msg[i];
+ if (mb->inp >= mb->end)
+ mb->inp = mb->start;
+ mb->used++;
+ }
+ midi_wakeup(&sc->rchan);
+ selwakeup(&sc->rsel);
+ if (sc->async)
+ psignal(sc->async, SIGIO);
+}
+
+void
+midi_out(addr)
+ void *addr;
+{
+ struct midi_softc *sc = addr;
+
+ if (!sc->isopen)
+ return;
+ DPRINTFN(3, ("midi_out: %p\n", sc));
+ midi_start_output(sc, 1);
+}
+
+int
+midiopen(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc;
+ struct midi_hw_if *hw;
+ int error;
+
+ if (unit >= midi_cd.cd_ndevs ||
+ (sc = midi_cd.cd_devs[unit]) == NULL)
+ return (ENXIO);
+ DPRINTF(("midiopen %p\n", sc));
+
+ hw = sc->hw_if;
+ if (!hw)
+ return (ENXIO);
+ if (sc->isopen)
+ return (EBUSY);
+ sc->in_state = MIDI_IN_START;
+ sc->in_status = 0;
+ error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
+ if (error)
+ return (error);
+ sc->isopen++;
+ midi_initbuf(&sc->outbuf);
+ midi_initbuf(&sc->inbuf);
+ sc->flags = flags;
+ sc->rchan = 0;
+ sc->wchan = 0;
+ sc->pbus = 0;
+ sc->async = 0;
+
+#ifdef MIDI_SAVE
+ if (midicnt != 0) {
+ midisave.cnt = midicnt;
+ midicnt = 0;
+ }
+#endif
+
+ return (0);
+}
+
+int
+midiclose(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_hw_if *hw = sc->hw_if;
+ int s, error;
+
+ DPRINTF(("midiclose %p\n", sc));
+
+ midi_start_output(sc, 0);
+ error = 0;
+ s = splaudio();
+ while (sc->outbuf.used > 0 && !error) {
+ DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
+ error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
+ }
+ splx(s);
+ sc->isopen = 0;
+ hw->close(sc->hw_hdl);
+#if NSEQUENCER > 0
+ sc->seqopen = 0;
+ sc->seq_md = 0;
+#endif
+ return (0);
+}
+
+int
+midiread(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_buffer *mb = &sc->inbuf;
+ int error;
+ u_char *outp;
+ int used, cc, n, resid;
+ int s;
+
+ DPRINTF(("midiread: %p, count=%d\n", sc, uio->uio_resid));
+
+ error = 0;
+ resid = uio->uio_resid;
+ while (uio->uio_resid == resid && !error) {
+ s = splaudio();
+ while (mb->used <= 0) {
+ if (ioflag & IO_NDELAY) {
+ splx(s);
+ return (EWOULDBLOCK);
+ }
+ error = midi_sleep(&sc->rchan, "mid rd");
+ if (error) {
+ splx(s);
+ return (error);
+ }
+ }
+ used = mb->used;
+ outp = mb->outp;
+ splx(s);
+ cc = used; /* maximum to read */
+ n = mb->end - outp;
+ if (n < cc)
+ cc = n; /* don't read beyond end of buffer */
+ if (uio->uio_resid < cc)
+ cc = uio->uio_resid; /* and no more than we want */
+ DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
+ error = uiomove(outp, cc, uio);
+ if (error)
+ break;
+ used -= cc;
+ outp += cc;
+ if (outp >= mb->end)
+ outp = mb->start;
+ s = splaudio();
+ mb->outp = outp;
+ mb->used = used;
+ splx(s);
+ }
+ return (error);
+}
+
+void
+midi_timeout(arg)
+ void *arg;
+{
+ struct midi_softc *sc = arg;
+
+ DPRINTFN(3,("midi_timeout: %p\n", sc));
+ midi_start_output(sc, 1);
+}
+
+int
+midi_start_output(sc, intr)
+ struct midi_softc *sc;
+ int intr;
+{
+ struct midi_buffer *mb = &sc->outbuf;
+ u_char *outp;
+ int error;
+ int s;
+ int i, mmax;
+
+ error = 0;
+ mmax = sc->props & MIDI_PROP_OUT_INTR ? 1 : MIDI_MAX_WRITE;
+ s = splaudio();
+ if (sc->pbus && !intr) {
+ DPRINTFN(4, ("midi_start_output: busy\n"));
+ splx(s);
+ return (0);
+ }
+ sc->pbus = 1;
+ for (i = 0; i < mmax && mb->used > 0 && !error; i++) {
+ outp = mb->outp;
+ splx(s);
+ DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n",
+ sc, i, *outp));
+#ifdef MIDI_SAVE
+ midisave.buf[midicnt] = *outp;
+ midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
+#endif
+ error = sc->hw_if->output(sc->hw_hdl, *outp++);
+ if (outp >= mb->end)
+ outp = mb->start;
+ s = splaudio();
+ mb->outp = outp;
+ mb->used--;
+ }
+ midi_wakeup(&sc->wchan);
+ selwakeup(&sc->wsel);
+ if (sc->async)
+ psignal(sc->async, SIGIO);
+ if (mb->used > 0) {
+ if (!(sc->props & MIDI_PROP_OUT_INTR))
+ timeout(midi_timeout, sc, midi_wait);
+ } else
+ sc->pbus = 0;
+ splx(s);
+ return (error);
+}
+
+int
+midiwrite(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_buffer *mb = &sc->outbuf;
+ int error;
+ u_char *inp;
+ int used, cc, n;
+ int s;
+
+ DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%d\n", sc, unit,
+ uio->uio_resid));
+
+ error = 0;
+ while (uio->uio_resid > 0 && !error) {
+ s = splaudio();
+ if (mb->used >= mb->usedhigh) {
+ DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n",
+ mb->used, mb->usedhigh));
+ if (ioflag & IO_NDELAY) {
+ splx(s);
+ return (EWOULDBLOCK);
+ }
+ error = midi_sleep(&sc->wchan, "mid wr");
+ if (error) {
+ splx(s);
+ return (error);
+ }
+ }
+ used = mb->used;
+ inp = mb->inp;
+ splx(s);
+ cc = mb->usedhigh - used; /* maximum to write */
+ n = mb->end - inp;
+ if (n < cc)
+ cc = n; /* don't write beyond end of buffer */
+ if (uio->uio_resid < cc)
+ cc = uio->uio_resid; /* and no more than we have */
+ error = uiomove(inp, cc, uio);
+#ifdef MIDI_DEBUG
+ if (error)
+ printf("midi_write:(1) uiomove failed %d; "
+ "cc=%d inp=%p\n",
+ error, cc, inp);
+#endif
+ if (error)
+ break;
+ inp = mb->inp + cc;
+ if (inp >= mb->end)
+ inp = mb->start;
+ s = splaudio();
+ mb->inp = inp;
+ mb->used += cc;
+ splx(s);
+ error = midi_start_output(sc, 0);
+ }
+ return (error);
+}
+
+/*
+ * This write routine is only called from sequencer code and expects
+ * a write that is smaller than the MIDI buffer.
+ */
+int
+midi_writebytes(unit, buf, cc)
+ int unit;
+ u_char *buf;
+ int cc;
+{
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_buffer *mb = &sc->outbuf;
+ int n, s;
+
+ DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
+ DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2]));
+
+ s = splaudio();
+ if (mb->used + cc >= mb->usedhigh) {
+ splx(s);
+ return (EWOULDBLOCK);
+ }
+ n = mb->end - mb->inp;
+ if (cc < n)
+ n = cc;
+ mb->used += cc;
+ bcopy(buf, mb->inp, n);
+ mb->inp += n;
+ if (mb->inp >= mb->end) {
+ mb->inp = mb->start;
+ cc -= n;
+ if (cc > 0) {
+ bcopy(buf + n, mb->inp, cc);
+ mb->inp += cc;
+ }
+ }
+ splx(s);
+ return (midi_start_output(sc, 0));
+}
+
+int
+midiioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ struct midi_hw_if *hw = sc->hw_if;
+ int error;
+
+ DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
+ error = 0;
+ switch (cmd) {
+ case FIONBIO:
+ /* All handled in the upper FS layer. */
+ break;
+
+ case FIOASYNC:
+ if (*(int *)addr) {
+ if (sc->async)
+ return (EBUSY);
+ sc->async = p;
+ DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
+ } else
+ sc->async = 0;
+ break;
+
+#if 0
+ case MIDI_PRETIME:
+ /* XXX OSS
+ * This should set up a read timeout, but that's
+ * why we have poll(), so there's nothing yet. */
+ error = EINVAL;
+ break;
+#endif
+
+#ifdef MIDI_SAVE
+ case MIDI_GETSAVE:
+ error = copyout(&midisave, *(void **)addr, sizeof midisave);
+ break;
+#endif
+
+ default:
+ if (hw->ioctl)
+ error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
+ else
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+int
+midiselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc = midi_cd.cd_devs[unit];
+ int s = splaudio();
+
+ DPRINTF(("midiselect: %p rw=0x%x\n", sc, rw));
+
+ switch (rw) {
+ case FREAD:
+ if (sc->inbuf.used > 0) {
+ splx(s);
+ return (1);
+ }
+ selrecord(p, &sc->rsel);
+ break;
+
+ case FWRITE:
+ if (sc->outbuf.used < sc->outbuf.usedhigh) {
+ splx(s);
+ return (1);
+ }
+ selrecord(p, &sc->wsel);
+ break;
+ }
+
+ splx(s);
+ return (0);
+}
+
+void
+midi_getinfo(dev, mi)
+ dev_t dev;
+ struct midi_info *mi;
+{
+ int unit = MIDIUNIT(dev);
+ struct midi_softc *sc;
+
+ if (unit >= midi_cd.cd_ndevs ||
+ (sc = midi_cd.cd_devs[unit]) == NULL)
+ return;
+ sc->hw_if->getinfo(sc->hw_hdl, mi);
+}
+
+#endif /* NMIDI > 0 */
+
+#if NMIDI > 0 || NMIDIBUS > 0
+
+int audioprint __P((void *, const char *));
+
+void
+midi_attach_mi(mhwp, hdlp, dev)
+ struct midi_hw_if *mhwp;
+ void *hdlp;
+ struct device *dev;
+{
+ struct audio_attach_args arg;
+
+#ifdef DIAGNOSTIC
+ if (mhwp == NULL) {
+ printf("midi_attach_mi: NULL\n");
+ return;
+ }
+#endif
+ arg.type = AUDIODEV_TYPE_MIDI;
+ arg.hwif = mhwp;
+ arg.hdl = hdlp;
+ (void)config_found(dev, &arg, audioprint);
+}
+
+#endif /* NMIDI > 0 || NMIDIBUS > 0 */
diff --git a/sys/dev/midi_if.h b/sys/dev/midi_if.h
new file mode 100644
index 00000000000..d46aaa217d6
--- /dev/null
+++ b/sys/dev/midi_if.h
@@ -0,0 +1,70 @@
+/* $OpenBSD: midi_if.h,v 1.1 1999/01/02 00:02:37 niklas Exp $ */
+/* $NetBSD: midi_if.h,v 1.3 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_DEV_MIDI_IF_H_
+#define _SYS_DEV_MIDI_IF_H_
+
+struct midi_info {
+ char *name; /* Name of MIDI hardware */
+ int props;
+};
+#define MIDI_PROP_OUT_INTR 1
+#define MIDI_PROP_CAN_INPUT 2
+
+struct midi_softc;
+
+struct midi_hw_if {
+ int (*open)__P((void *, int, /* open hardware */
+ void (*)__P((void *, int)), /* input callback */
+ void (*)__P((void *)), /* output callback */
+ void *));
+ void (*close)__P((void *)); /* close hardware */
+ int (*output)__P((void *, int)); /* output a byte */
+ void (*getinfo)__P((void *, struct midi_info *));
+ int (*ioctl)__P((void *, u_long, caddr_t, int, struct proc *));
+};
+
+void midi_attach __P((struct midi_softc *, struct device *));
+void midi_attach_mi __P((struct midi_hw_if *, void *, struct device *));
+
+int midi_unit_count __P((void));
+void midi_getinfo __P((dev_t, struct midi_info *));
+int midi_writebytes __P((int, u_char *, int));
+
+#endif /* _SYS_DEV_MIDI_IF_H_ */
diff --git a/sys/dev/midisyn.c b/sys/dev/midisyn.c
new file mode 100644
index 00000000000..0eb3bbf075a
--- /dev/null
+++ b/sys/dev/midisyn.c
@@ -0,0 +1,428 @@
+/* $OpenBSD: midisyn.c,v 1.1 1999/01/02 00:02:37 niklas Exp $ */
+/* $NetBSD: midisyn.c,v 1.5 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+#include <sys/device.h>
+
+#include <dev/audio_if.h>
+#include <dev/midi_if.h>
+#include <dev/midivar.h>
+#include <dev/midisynvar.h>
+
+#ifdef AUDIO_DEBUG
+#define DPRINTF(x) if (midisyndebug) printf x
+#define DPRINTFN(n,x) if (midisyndebug >= (n)) printf x
+int midisyndebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+int midisyn_findvoice __P((midisyn *, int, int));
+void midisyn_freevoice __P((midisyn *, int));
+int midisyn_allocvoice __P((midisyn *, u_int32_t, u_int32_t));
+u_int32_t midisyn_note_to_freq __P((int));
+u_int32_t midisyn_finetune __P((u_int32_t, int, int, int));
+
+int midisyn_open __P((void *, int,
+ void (*iintr)__P((void *, int)),
+ void (*ointr)__P((void *)), void *arg));
+void midisyn_close __P((void *));
+int midisyn_output __P((void *, int));
+void midisyn_getinfo __P((void *, struct midi_info *));
+int midisyn_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
+
+struct midi_hw_if midisyn_hw_if = {
+ midisyn_open,
+ midisyn_close,
+ midisyn_output,
+ midisyn_getinfo,
+ midisyn_ioctl,
+};
+
+static int midi_lengths[] = { 3,3,3,3,2,2,3,1 };
+/* Number of bytes in a MIDI command, including status */
+#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
+
+int
+midisyn_open(addr, flags, iintr, ointr, arg)
+ void *addr;
+ int flags;
+ void (*iintr)__P((void *, int));
+ void (*ointr)__P((void *));
+ void *arg;
+{
+ midisyn *ms = addr;
+
+ DPRINTF(("midisyn_open: ms=%p ms->mets=%p\n", ms, ms->mets));
+ if (ms->mets->open)
+ return (ms->mets->open(ms, flags));
+ else
+ return (0);
+}
+
+void
+midisyn_close(addr)
+ void *addr;
+{
+ midisyn *ms = addr;
+ struct midisyn_methods *fs;
+ int v;
+
+ DPRINTF(("midisyn_close: ms=%p ms->mets=%p\n", ms, ms->mets));
+ fs = ms->mets;
+ for (v = 0; v < ms->nvoice; v++)
+ if (ms->voices[v].inuse) {
+ fs->noteoff(ms, v, 0, 0);
+ midisyn_freevoice(ms, v);
+ }
+ if (fs->close)
+ fs->close(ms);
+}
+
+void
+midisyn_getinfo(addr, mi)
+ void *addr;
+ struct midi_info *mi;
+{
+ midisyn *ms = addr;
+
+ mi->name = ms->name;
+ mi->props = 0;
+}
+
+int
+midisyn_ioctl(maddr, cmd, addr, flag, p)
+ void *maddr;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ midisyn *ms = maddr;
+
+ if (ms->mets->ioctl)
+ return (ms->mets->ioctl(ms, cmd, addr, flag, p));
+ else
+ return (EINVAL);
+}
+
+int
+midisyn_findvoice(ms, chan, note)
+ midisyn *ms;
+ int chan, note;
+{
+ u_int cn;
+ int v;
+
+ if (!(ms->flags & MS_DOALLOC))
+ return (chan);
+ cn = MS_CHANNOTE(chan, note);
+ for (v = 0; v < ms->nvoice; v++)
+ if (ms->voices[v].chan_note == cn && ms->voices[v].inuse)
+ return (v);
+ return (-1);
+}
+
+void
+midisyn_attach(sc, ms)
+ struct midi_softc *sc;
+ midisyn *ms;
+{
+ if (ms->flags & MS_DOALLOC) {
+ ms->voices = malloc(ms->nvoice * sizeof (struct voice),
+ M_DEVBUF, M_WAITOK);
+ memset(ms->voices, 0, ms->nvoice * sizeof (struct voice));
+ ms->seqno = 1;
+ if (ms->mets->allocv == 0)
+ ms->mets->allocv = &midisyn_allocvoice;
+ }
+ sc->hw_if = &midisyn_hw_if;
+ sc->hw_hdl = ms;
+ DPRINTF(("midisyn_attach: ms=%p\n", sc->hw_hdl));
+}
+
+void
+midisyn_freevoice(ms, voice)
+ midisyn *ms;
+ int voice;
+{
+ if (!(ms->flags & MS_DOALLOC))
+ return;
+ ms->voices[voice].inuse = 0;
+}
+
+int
+midisyn_allocvoice(ms, chan, note)
+ midisyn *ms;
+ u_int32_t chan, note;
+{
+ int bestv, v;
+ u_int bestseq, s;
+
+ if (!(ms->flags & MS_DOALLOC))
+ return (chan);
+ /* Find a free voice, or if no free voice is found the oldest. */
+ bestv = 0;
+ bestseq = ms->voices[0].seqno + (ms->voices[0].inuse ? 0x40000000 : 0);
+ for (v = 1; v < ms->nvoice; v++) {
+ s = ms->voices[v].seqno;
+ if (ms->voices[v].inuse)
+ s += 0x40000000;
+ if (s < bestseq) {
+ bestseq = s;
+ bestv = v;
+ }
+ }
+ DPRINTFN(10,("midisyn_allocvoice: v=%d seq=%d cn=%x inuse=%d\n",
+ bestv, ms->voices[bestv].seqno,
+ ms->voices[bestv].chan_note,
+ ms->voices[bestv].inuse));
+#ifdef AUDIO_DEBUG
+ if (ms->voices[bestv].inuse)
+ DPRINTFN(1,("midisyn_allocvoice: steal %x\n",
+ ms->voices[bestv].chan_note));
+#endif
+ ms->voices[bestv].chan_note = MS_CHANNOTE(chan, note);
+ ms->voices[bestv].seqno = ms->seqno++;
+ ms->voices[bestv].inuse = 1;
+ return (bestv);
+}
+
+int
+midisyn_output(addr, b)
+ void *addr;
+ int b;
+{
+ midisyn *ms = addr;
+ u_int8_t status, chan;
+ int voice = 0; /* initialize to keep gcc quiet */
+ struct midisyn_methods *fs;
+ u_int32_t note, vel;
+
+ DPRINTF(("midisyn_output: ms=%p b=0x%02x\n", ms, b));
+ fs = ms->mets;
+ if (ms->pos < 0) {
+ /* Doing SYSEX */
+ DPRINTF(("midisyn_output: sysex 0x%02x\n", b));
+ if (fs->sysex)
+ fs->sysex(ms, b);
+ if (b == MIDI_SYSEX_END)
+ ms->pos = 0;
+ return (0);
+ }
+ if (ms->pos == 0 && !MIDI_IS_STATUS(b))
+ ms->pos++; /* repeat last status byte */
+ ms->buf[ms->pos++] = b;
+ status = ms->buf[0];
+ if (ms->pos < MIDI_LENGTH(status))
+ return (0);
+ /* Decode the MIDI command */
+ chan = MIDI_GET_CHAN(status);
+ note = ms->buf[1];
+ if (ms->flags & MS_FREQXLATE)
+ note = midisyn_note_to_freq(note);
+ vel = ms->buf[2];
+ switch (MIDI_GET_STATUS(status)) {
+ case MIDI_NOTEOFF:
+ voice = midisyn_findvoice(ms, chan, ms->buf[1]);
+ if (voice >= 0) {
+ fs->noteoff(ms, voice, note, vel);
+ midisyn_freevoice(ms, voice);
+ }
+ break;
+ case MIDI_NOTEON:
+ voice = fs->allocv(ms, chan, ms->buf[1]);
+ fs->noteon(ms, voice, note, vel);
+ break;
+ case MIDI_KEY_PRESSURE:
+ if (fs->keypres) {
+ voice = midisyn_findvoice(ms, voice, ms->buf[1]);
+ if (voice >= 0)
+ fs->keypres(ms, voice, note, vel);
+ }
+ break;
+ case MIDI_CTL_CHANGE:
+ if (fs->ctlchg)
+ fs->ctlchg(ms, chan, ms->buf[1], vel);
+ break;
+ case MIDI_PGM_CHANGE:
+ if (fs->pgmchg)
+ fs->pgmchg(ms, chan, ms->buf[1]);
+ break;
+ case MIDI_CHN_PRESSURE:
+ if (fs->chnpres) {
+ voice = midisyn_findvoice(ms, chan, ms->buf[1]);
+ if (voice >= 0)
+ fs->chnpres(ms, voice, note);
+ }
+ break;
+ case MIDI_PITCH_BEND:
+ if (fs->pitchb) {
+ voice = midisyn_findvoice(ms, chan, ms->buf[1]);
+ if (voice >= 0)
+ fs->pitchb(ms, chan, note, vel);
+ }
+ break;
+ case MIDI_SYSTEM_PREFIX:
+ if (fs->sysex)
+ fs->sysex(ms, status);
+ ms->pos = -1;
+ return (0);
+ }
+ ms->pos = 0;
+ return (0);
+}
+
+/*
+ * Convert a MIDI note to the corresponding frequency.
+ * The frequency is scaled by 2^16.
+ */
+u_int32_t
+midisyn_note_to_freq(note)
+ int note;
+{
+ int o, n, f;
+#define BASE_OCTAVE 5
+ static u_int32_t notes[] = {
+ 17145893, 18165441, 19245614, 20390018, 21602472, 22887021,
+ 24247954, 25689813, 27217409, 28835840, 30550508, 32367136
+ };
+
+
+ o = note / 12;
+ n = note % 12;
+
+ f = notes[n];
+
+ if (o < BASE_OCTAVE)
+ f >>= (BASE_OCTAVE - o);
+ else if (o > BASE_OCTAVE)
+ f <<= (o - BASE_OCTAVE);
+ return (f);
+}
+
+u_int32_t
+midisyn_finetune(base_freq, bend, range, vibrato_cents)
+ u_int32_t base_freq;
+ int bend;
+ int range;
+ int vibrato_cents;
+{
+ static u_int16_t semitone_tuning[24] =
+ {
+/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
+/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
+/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
+ };
+ static u_int16_t cent_tuning[100] =
+ {
+/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
+/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
+/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134,
+/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181,
+/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228,
+/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275,
+/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323,
+/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371,
+/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419,
+/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467,
+/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515,
+/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
+/* 96 */ 10570, 10576, 10582, 10589
+ };
+ u_int32_t amount;
+ int negative, semitones, cents, multiplier;
+
+ if (range == 0)
+ return base_freq;
+
+ if (base_freq == 0)
+ return base_freq;
+
+ if (range >= 8192)
+ range = 8192;
+
+ bend = bend * range / 8192;
+ bend += vibrato_cents;
+
+ if (bend == 0)
+ return base_freq;
+
+ if (bend < 0) {
+ bend = -bend;
+ negative = 1;
+ } else
+ negative = 0;
+
+ if (bend > range)
+ bend = range;
+
+ multiplier = 1;
+ while (bend > 2399) {
+ multiplier *= 4;
+ bend -= 2400;
+ }
+
+ semitones = bend / 100;
+ if (semitones > 99)
+ semitones = 99;
+ cents = bend % 100;
+
+ amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents]
+ / 10000;
+
+ if (negative)
+ return (base_freq * 10000 / amount); /* Bend down */
+ else
+ return (base_freq * amount / 10000); /* Bend up */
+}
+
diff --git a/sys/dev/midisynvar.h b/sys/dev/midisynvar.h
new file mode 100644
index 00000000000..4d259a22b32
--- /dev/null
+++ b/sys/dev/midisynvar.h
@@ -0,0 +1,98 @@
+/* $OpenBSD: midisynvar.h,v 1.1 1999/01/02 00:02:37 niklas Exp $ */
+/* $NetBSD: midisynvar.h,v 1.3 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_DEV_MIDISYNVAR_H_
+#define _SYS_DEV_MIDISYNVAR_H_
+
+typedef struct midisyn midisyn;
+
+struct midisyn_methods {
+ int (*open) __P((midisyn *, int));
+ void (*close) __P((midisyn *));
+ int (*ioctl) __P((midisyn *, u_long, caddr_t, int, struct proc *));
+ int (*allocv) __P((midisyn *, u_int32_t, u_int32_t));
+ void (*noteon) __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+ void (*noteoff) __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+ void (*keypres) __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+ void (*ctlchg) __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+ void (*pgmchg) __P((midisyn *, u_int32_t, u_int32_t));
+ void (*chnpres) __P((midisyn *, u_int32_t, u_int32_t));
+ void (*pitchb) __P((midisyn *, u_int32_t, u_int32_t, u_int32_t));
+ void (*sysex) __P((midisyn *, u_int32_t));
+};
+
+struct voice {
+ u_int chan_note; /* channel and note */
+#define MS_CHANNOTE(chan, note) ((chan) * 256 + (note))
+#define MS_GETCHAN(v) ((v)->chan_note >> 8)
+ u_int seqno; /* allocation index (increases with time) */
+ u_char inuse;
+};
+
+#define MIDI_MAX_CHANS 16
+
+struct midisyn {
+ /* Filled by synth driver */
+ struct midisyn_methods *mets;
+ char name[32];
+ int nvoice;
+ int flags;
+#define MS_DOALLOC 1
+#define MS_FREQXLATE 2
+ void *data;
+
+ /* Used by midisyn driver */
+ u_int8_t buf[3];
+ int pos;
+ struct voice *voices;
+ u_int seqno;
+ u_int16_t pgms[MIDI_MAX_CHANS];
+};
+
+#define MS_GETPGM(ms, vno) ((ms)->pgms[MS_GETCHAN(&(ms)->voices[vno])])
+
+struct midi_softc;
+
+extern struct midi_hw_if midisyn_hw_if;
+
+void midisyn_attach __P((struct midi_softc *, midisyn *));
+
+#define MIDISYN_FREQ_TO_HZ(f) ((f) >> 16)
+
+#endif /* _SYS_DEV_MIDISYNVAR_H_ */
diff --git a/sys/dev/midivar.h b/sys/dev/midivar.h
new file mode 100644
index 00000000000..da3e1518d0f
--- /dev/null
+++ b/sys/dev/midivar.h
@@ -0,0 +1,94 @@
+/* $OpenBSD: midivar.h,v 1.1 1999/01/02 00:02:38 niklas Exp $ */
+/* $NetBSD: midivar.h,v 1.6 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_DEV_MIDIVAR_H_
+#define _SYS_DEV_MIDIVAR_H_
+
+#define MIDI_BUFSIZE 1024
+
+#include "sequencer.h"
+
+struct midi_buffer {
+ u_char *inp;
+ u_char *outp;
+ u_char *end;
+ int used;
+ int usedhigh;
+ u_char start[MIDI_BUFSIZE];
+};
+
+#define MIDI_MAX_WRITE 32 /* max bytes written with busy wait */
+#define MIDI_WAIT 10000 /* microseconds to wait after busy wait */
+
+struct midi_softc {
+ struct device dev;
+ void *hw_hdl; /* Hardware driver handle */
+ struct midi_hw_if *hw_if; /* Hardware interface */
+ struct device *sc_dev; /* Hardware device struct */
+ int isopen; /* Open indicator */
+ int flags; /* Open flags */
+ struct midi_buffer outbuf;
+ struct midi_buffer inbuf;
+ int props;
+ int rchan, wchan;
+ int pbus;
+ struct selinfo wsel; /* write selector */
+ struct selinfo rsel; /* read selector */
+ struct proc *async; /* process who wants audio SIGIO */
+
+ /* MIDI input state machine */
+ int in_state;
+#define MIDI_IN_START 0
+#define MIDI_IN_DATA 1
+#define MIDI_IN_SYSEX 2
+ u_char in_msg[3];
+ u_char in_status;
+ u_int in_left;
+ u_int in_pos;
+
+#if NSEQUENCER > 0
+ /* Synthesizer emulation stuff */
+ int seqopen;
+ struct midi_dev *seq_md; /* structure that links us with the seq. */
+#endif
+};
+
+#define MIDIUNIT(d) ((d) & 0xff)
+
+#endif /* _SYS_DEV_MIDIVAR_H_ */
diff --git a/sys/dev/pci/eap.c b/sys/dev/pci/eap.c
index 9e435ce0a8b..63393898840 100644
--- a/sys/dev/pci/eap.c
+++ b/sys/dev/pci/eap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: eap.c,v 1.3 1998/11/03 21:06:39 downsj Exp $ */
+/* $OpenBSD: eap.c,v 1.4 1999/01/02 00:02:49 niklas Exp $ */
/* $NetBSD: eap.c,v 1.17 1998/08/25 04:56:01 thorpej Exp $ */
/*
@@ -478,7 +478,7 @@ eap_attach(parent, self, aux)
ctl.un.mask = 1 << EAP_MIC_VOL;
eap_mixer_set_port(sc, &ctl);
- audio_attach_mi(&eap_hw_if, 0, sc, &sc->sc_dev);
+ audio_attach_mi(&eap_hw_if, sc, &sc->sc_dev);
}
int
diff --git a/sys/dev/pci/sv.c b/sys/dev/pci/sv.c
index 06342133a46..b7deed5e7ea 100644
--- a/sys/dev/pci/sv.c
+++ b/sys/dev/pci/sv.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sv.c,v 1.5 1998/11/03 21:05:07 downsj Exp $ */
+/* $OpenBSD: sv.c,v 1.6 1999/01/02 00:02:49 niklas Exp $ */
/*
* Copyright (c) 1998 Constantine Paul Sapuntzakis
@@ -412,7 +412,7 @@ sv_attach(parent, self, aux)
sv_init_mixer(sc);
- audio_attach_mi(&sv_hw_if, 0, sc, &sc->sc_dev);
+ audio_attach_mi(&sv_hw_if, sc, &sc->sc_dev);
}
#ifdef AUDIO_DEBUG
diff --git a/sys/dev/sequencer.c b/sys/dev/sequencer.c
new file mode 100644
index 00000000000..9f2f9090a3c
--- /dev/null
+++ b/sys/dev/sequencer.c
@@ -0,0 +1,1382 @@
+/* $OpenBSD: sequencer.c,v 1.1 1999/01/02 00:02:38 niklas Exp $ */
+/* $NetBSD: sequencer.c,v 1.13 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sequencer.h"
+#if NSEQUENCER > 0
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/select.h>
+#include <sys/poll.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/syslog.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+#include <sys/conf.h>
+#include <sys/audioio.h>
+#include <sys/midiio.h>
+#include <sys/device.h>
+
+#include <dev/midi_if.h>
+#include <dev/midivar.h>
+#include <dev/sequencervar.h>
+
+#define splaudio() splbio() /* XXX found in audio_if.h normally */
+
+#define ADDTIMEVAL(a, b) ( \
+ (a)->tv_sec += (b)->tv_sec, \
+ (a)->tv_usec += (b)->tv_usec, \
+ (a)->tv_usec > 1000000 ? ((a)->tv_sec++, (a)->tv_usec -= 1000000) : 0\
+ )
+
+#define SUBTIMEVAL(a, b) ( \
+ (a)->tv_sec -= (b)->tv_sec, \
+ (a)->tv_usec -= (b)->tv_usec, \
+ (a)->tv_usec < 0 ? ((a)->tv_sec--, (a)->tv_usec += 1000000) : 0\
+ )
+
+#ifdef AUDIO_DEBUG
+#define DPRINTF(x) if (sequencerdebug) printf x
+#define DPRINTFN(n,x) if (sequencerdebug >= (n)) printf x
+int sequencerdebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define SEQ_CMD(b) ((b)->arr[0])
+
+#define SEQ_EDEV(b) ((b)->arr[1])
+#define SEQ_ECMD(b) ((b)->arr[2])
+#define SEQ_ECHAN(b) ((b)->arr[3])
+#define SEQ_ENOTE(b) ((b)->arr[4])
+#define SEQ_EPARM(b) ((b)->arr[5])
+
+#define SEQ_EP1(b) ((b)->arr[4])
+#define SEQ_EP2(b) ((b)->arr[5])
+
+#define SEQ_XCMD(b) ((b)->arr[1])
+#define SEQ_XDEV(b) ((b)->arr[2])
+#define SEQ_XCHAN(b) ((b)->arr[3])
+#define SEQ_XNOTE(b) ((b)->arr[4])
+#define SEQ_XVEL(b) ((b)->arr[5])
+
+#define SEQ_TCMD(b) ((b)->arr[1])
+#define SEQ_TPARM(b) ((b)->arr[4])
+
+#define SEQ_NOTE_MAX 128
+#define SEQ_NOTE_XXX 255
+#define SEQ_VEL_OFF 0
+
+#define RECALC_TICK(t) ((t)->tick = 60 * 1000000L / ((t)->tempo * (t)->timebase))
+
+struct sequencer_softc seqdevs[NSEQUENCER];
+
+void sequencerattach __P((int));
+void seq_reset __P((struct sequencer_softc *));
+int seq_do_command __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_extcommand __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_chnvoice __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_chncommon __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_timing __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_local __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_sysex __P((struct sequencer_softc *, seq_event_rec *));
+int seq_do_fullsize __P((struct sequencer_softc *, seq_event_rec *,
+ struct uio *));
+int seq_timer __P((struct sequencer_softc *, int, int, seq_event_rec *));
+static int seq_input_event __P((struct sequencer_softc *, seq_event_rec *));
+int seq_drain __P((struct sequencer_softc *));
+void seq_startoutput __P((struct sequencer_softc *));
+void seq_timeout __P((void *));
+int seq_to_new __P((seq_event_rec *, struct uio *));
+static int seq_sleep_timo(int *, char *, int);
+static int seq_sleep(int *, char *);
+static void seq_wakeup(int *);
+
+struct midi_softc;
+int midiseq_out __P((struct midi_dev *, u_char *, u_int, int));
+struct midi_dev *midiseq_open __P((int, int));
+void midiseq_close __P((struct midi_dev *));
+void midiseq_reset __P((struct midi_dev *));
+int midiseq_noteon __P((struct midi_dev *, int, int, int));
+int midiseq_noteoff __P((struct midi_dev *, int, int, int));
+int midiseq_keypressure __P((struct midi_dev *, int, int, int));
+int midiseq_pgmchange __P((struct midi_dev *, int, int));
+int midiseq_chnpressure __P((struct midi_dev *, int, int));
+int midiseq_ctlchange __P((struct midi_dev *, int, int, int));
+int midiseq_pitchbend __P((struct midi_dev *, int, int));
+int midiseq_loadpatch __P((struct midi_dev *, struct sysex_info *,
+ struct uio *));
+int midiseq_putc __P((struct midi_dev *, int));
+void midiseq_in __P((struct midi_dev *, u_char *, int));
+
+void
+sequencerattach(n)
+ int n;
+{
+}
+
+int
+sequenceropen(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ int unit = SEQUENCERUNIT(dev);
+ struct sequencer_softc *sc;
+ struct midi_dev *md;
+ int nmidi;
+
+ DPRINTF(("sequenceropen\n"));
+
+ if (unit >= NSEQUENCER)
+ return (ENXIO);
+ sc = &seqdevs[unit];
+ if (sc->isopen)
+ return (EBUSY);
+ if (SEQ_IS_OLD(unit))
+ sc->mode = SEQ_OLD;
+ else
+ sc->mode = SEQ_NEW;
+ sc->isopen++;
+ sc->flags = flags & (FREAD|FWRITE);
+ sc->rchan = 0;
+ sc->wchan = 0;
+ sc->pbus = 0;
+ sc->async = 0;
+ sc->input_stamp = ~0;
+
+ sc->nmidi = 0;
+ nmidi = midi_unit_count();
+
+ sc->devs = malloc(nmidi * sizeof(struct midi_dev *),
+ M_DEVBUF, M_WAITOK);
+ for (unit = 0; unit < nmidi; unit++) {
+ md = midiseq_open(unit, flags);
+ if (md) {
+ sc->devs[sc->nmidi++] = md;
+ md->seq = sc;
+ }
+ }
+
+ sc->timer.timebase = 100;
+ sc->timer.tempo = 60;
+ sc->doingsysex = 0;
+ RECALC_TICK(&sc->timer);
+ sc->timer.last = 0;
+ microtime(&sc->timer.start);
+
+ SEQ_QINIT(&sc->inq);
+ SEQ_QINIT(&sc->outq);
+ sc->lowat = SEQ_MAXQ / 2;
+
+ seq_reset(sc);
+
+ DPRINTF(("sequenceropen: mode=%d, nmidi=%d\n", sc->mode, sc->nmidi));
+ return (0);
+}
+
+static int
+seq_sleep_timo(chan, label, timo)
+ int *chan;
+ char *label;
+ int timo;
+{
+ int st;
+
+ if (!label)
+ label = "seq";
+
+ DPRINTFN(5, ("seq_sleep_timo: %p %s %d\n", chan, label, timo));
+ *chan = 1;
+ st = tsleep(chan, PWAIT | PCATCH, label, timo);
+ *chan = 0;
+#ifdef MIDI_DEBUG
+ if (st != 0)
+ printf("seq_sleep: %d\n", st);
+#endif
+ return (st);
+}
+
+static int
+seq_sleep(chan, label)
+ int *chan;
+ char *label;
+{
+ return (seq_sleep_timo(chan, label, 0));
+}
+
+static void
+seq_wakeup(chan)
+ int *chan;
+{
+ if (*chan) {
+ DPRINTFN(5, ("seq_wakeup: %p\n", chan));
+ wakeup(chan);
+ *chan = 0;
+ }
+}
+
+int
+seq_drain(sc)
+ struct sequencer_softc *sc;
+{
+ int error;
+
+ DPRINTFN(3, ("seq_drain: %p, len=%d\n", sc, SEQ_QLEN(&sc->outq)));
+ seq_startoutput(sc);
+ error = 0;
+ while(!SEQ_QEMPTY(&sc->outq) && !error)
+ error = seq_sleep_timo(&sc->wchan, "seq_dr", 60*hz);
+ return (error);
+}
+
+void
+seq_timeout(addr)
+ void *addr;
+{
+ struct sequencer_softc *sc = addr;
+ DPRINTFN(4, ("seq_timeout: %p\n", sc));
+ sc->timeout = 0;
+ seq_startoutput(sc);
+ if (SEQ_QLEN(&sc->outq) < sc->lowat) {
+ seq_wakeup(&sc->wchan);
+ selwakeup(&sc->wsel);
+ if (sc->async)
+ psignal(sc->async, SIGIO);
+ }
+
+}
+
+void
+seq_startoutput(sc)
+ struct sequencer_softc *sc;
+{
+ struct sequencer_queue *q = &sc->outq;
+ seq_event_rec cmd;
+
+ if (sc->timeout)
+ return;
+ DPRINTFN(4, ("seq_startoutput: %p, len=%d\n", sc, SEQ_QLEN(q)));
+ while(!SEQ_QEMPTY(q) && !sc->timeout) {
+ SEQ_QGET(q, cmd);
+ seq_do_command(sc, &cmd);
+ }
+}
+
+int
+sequencerclose(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+ int n, s;
+
+ DPRINTF(("sequencerclose: %p\n", sc));
+
+ seq_drain(sc);
+ s = splaudio();
+ if (sc->timeout) {
+ untimeout(seq_timeout, sc);
+ sc->timeout = 0;
+ }
+ splx(s);
+
+ for (n = 0; n < sc->nmidi; n++)
+ midiseq_close(sc->devs[n]);
+ free(sc->devs, M_DEVBUF);
+ sc->isopen = 0;
+ return (0);
+}
+
+static int
+seq_input_event(sc, cmd)
+ struct sequencer_softc *sc;
+ seq_event_rec *cmd;
+{
+ struct sequencer_queue *q = &sc->inq;
+
+ DPRINTFN(2, ("seq_input_event: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ cmd->arr[0], cmd->arr[1], cmd->arr[2], cmd->arr[3],
+ cmd->arr[4], cmd->arr[5], cmd->arr[6], cmd->arr[7]));
+ if (SEQ_QFULL(q))
+ return (ENOMEM);
+ SEQ_QPUT(q, *cmd);
+ seq_wakeup(&sc->rchan);
+ selwakeup(&sc->rsel);
+ if (sc->async)
+ psignal(sc->async, SIGIO);
+ return (0);
+}
+
+void
+seq_event_intr(addr, iev)
+ void *addr;
+ seq_event_rec *iev;
+{
+ struct sequencer_softc *sc = addr;
+ union {
+ u_int32_t l;
+ u_int8_t b[4];
+ } u;
+ u_long t;
+ struct timeval now;
+ seq_event_rec ev;
+
+ microtime(&now);
+ SUBTIMEVAL(&now, &sc->timer.start);
+ t = now.tv_sec * 1000000 + now.tv_usec;
+ t /= sc->timer.tick;
+ if (t != sc->input_stamp) {
+ ev.arr[0] = SEQ_TIMING;
+ ev.arr[1] = TMR_WAIT_ABS;
+ ev.arr[2] = 0;
+ ev.arr[3] = 0;
+ u.l = t;
+ ev.arr[4] = u.b[0];
+ ev.arr[5] = u.b[1];
+ ev.arr[6] = u.b[2];
+ ev.arr[7] = u.b[3];
+ seq_input_event(sc, &ev);
+ sc->input_stamp = t;
+ }
+ seq_input_event(sc, iev);
+}
+
+int
+sequencerread(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+ struct sequencer_queue *q = &sc->inq;
+ seq_event_rec ev;
+ int error, s;
+
+ DPRINTFN(20, ("sequencerread: %p, count=%d, ioflag=%x\n",
+ sc, uio->uio_resid, ioflag));
+
+ if (sc->mode == SEQ_OLD) {
+ DPRINTFN(-1,("sequencerread: old read\n"));
+ return (EINVAL); /* XXX unimplemented */
+ }
+
+ error = 0;
+ while (SEQ_QEMPTY(q)) {
+ if (ioflag & IO_NDELAY)
+ return (EWOULDBLOCK);
+ else {
+ error = seq_sleep(&sc->rchan, "seq rd");
+ if (error)
+ return (error);
+ }
+ }
+ s = splaudio();
+ while (uio->uio_resid >= sizeof ev && !error && !SEQ_QEMPTY(q)) {
+ SEQ_QGET(q, ev);
+ error = uiomove((caddr_t)&ev, sizeof ev, uio);
+ }
+ splx(s);
+ return (error);
+}
+
+int
+sequencerwrite(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+ struct sequencer_queue *q = &sc->outq;
+ int error;
+ seq_event_rec cmdbuf;
+ int size;
+
+ DPRINTFN(2, ("sequencerwrite: %p, count=%d\n", sc, uio->uio_resid));
+
+ error = 0;
+ size = sc->mode == SEQ_NEW ? sizeof cmdbuf : SEQOLD_CMDSIZE;
+ while (uio->uio_resid >= size) {
+ error = uiomove((caddr_t)&cmdbuf, size, uio);
+ if (error)
+ break;
+ if (sc->mode == SEQ_OLD)
+ if (seq_to_new(&cmdbuf, uio))
+ continue;
+ if (SEQ_CMD(&cmdbuf) == SEQ_FULLSIZE) {
+ /* We do it like OSS does, asynchronously */
+ error = seq_do_fullsize(sc, &cmdbuf, uio);
+ if (error)
+ break;
+ continue;
+ }
+ while (SEQ_QFULL(q)) {
+ seq_startoutput(sc);
+ if (SEQ_QFULL(q)) {
+ if (ioflag & IO_NDELAY)
+ return (EWOULDBLOCK);
+ error = seq_sleep(&sc->wchan, "seq_wr");
+ if (error)
+ return (error);
+ }
+ }
+ SEQ_QPUT(q, cmdbuf);
+ }
+ seq_startoutput(sc);
+
+#ifdef SEQUENCER_DEBUG
+ if (error)
+ DPRINTFN(2, ("sequencerwrite: error=%d\n", error));
+#endif
+ return (error);
+}
+
+int
+sequencerioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+ struct synth_info *si;
+ struct midi_dev *md;
+ int devno;
+ int error;
+ int t;
+
+ DPRINTFN(2, ("sequencerioctl: %p cmd=0x%08lx\n", sc, cmd));
+
+ error = 0;
+ switch (cmd) {
+ case FIONBIO:
+ /* All handled in the upper FS layer. */
+ break;
+
+ case FIOASYNC:
+ if (*(int *)addr) {
+ if (sc->async)
+ return (EBUSY);
+ sc->async = p;
+ DPRINTF(("sequencer_ioctl: FIOASYNC %p\n", p));
+ } else
+ sc->async = 0;
+ break;
+
+ case SEQUENCER_RESET:
+ seq_reset(sc);
+ break;
+
+ case SEQUENCER_PANIC:
+ seq_reset(sc);
+ /* Do more? OSS doesn't */
+ break;
+
+ case SEQUENCER_SYNC:
+ if (sc->flags == FREAD)
+ return (0);
+ seq_drain(sc);
+ error = 0;
+ break;
+
+ case SEQUENCER_INFO:
+ si = (struct synth_info*)addr;
+ devno = si->device;
+ if (devno < 0 || devno >= sc->nmidi)
+ return (EINVAL);
+ md = sc->devs[devno];
+ strncpy(si->name, md->name, sizeof si->name);
+ si->synth_type = SYNTH_TYPE_MIDI;
+ si->synth_subtype = md->subtype;
+ si->nr_voices = md->nr_voices;
+ si->instr_bank_size = md->instr_bank_size;
+ si->capabilities = md->capabilities;
+ break;
+
+ case SEQUENCER_NRSYNTHS:
+ *(int *)addr = sc->nmidi;
+ break;
+
+ case SEQUENCER_NRMIDIS:
+ *(int *)addr = sc->nmidi;
+ break;
+
+ case SEQUENCER_OUTOFBAND:
+ DPRINTFN(3, ("sequencer_ioctl: OOB=%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ *(u_char *)addr, *(u_char *)(addr+1),
+ *(u_char *)(addr+2), *(u_char *)(addr+3),
+ *(u_char *)(addr+4), *(u_char *)(addr+5),
+ *(u_char *)(addr+6), *(u_char *)(addr+7)));
+ error = seq_do_command(sc, (seq_event_rec *)addr);
+ break;
+
+ case SEQUENCER_TMR_TIMEBASE:
+ t = *(int *)addr;
+ if (t < 1)
+ t = 1;
+ if (t > 1000)
+ t = 1000;
+ sc->timer.timebase = t;
+ *(int *)addr = t;
+ RECALC_TICK(&sc->timer);
+ break;
+
+ case SEQUENCER_TMR_START:
+ error = seq_timer(sc, TMR_START, 0, 0);
+ break;
+
+ case SEQUENCER_TMR_STOP:
+ error = seq_timer(sc, TMR_STOP, 0, 0);
+ break;
+
+ case SEQUENCER_TMR_CONTINUE:
+ error = seq_timer(sc, TMR_CONTINUE, 0, 0);
+ break;
+
+ case SEQUENCER_TMR_TEMPO:
+ t = *(int *)addr;
+ if (t < 8)
+ t = 8;
+ if (t > 250)
+ t = 250;
+ sc->timer.tempo = t;
+ *(int *)addr = t;
+ RECALC_TICK(&sc->timer);
+ break;
+
+ case SEQUENCER_TMR_SOURCE:
+ *(int *)addr = SEQUENCER_TMR_INTERNAL;
+ break;
+
+ case SEQUENCER_TMR_METRONOME:
+ /* noop */
+ break;
+
+ case SEQUENCER_THRESHOLD:
+ t = SEQ_MAXQ - *(int *)addr / sizeof (seq_event_rec);
+ if (t < 1)
+ t = 1;
+ if (t > SEQ_MAXQ)
+ t = SEQ_MAXQ;
+ sc->lowat = t;
+ break;
+
+ case SEQUENCER_CTRLRATE:
+ *(int *)addr = (sc->timer.tempo*sc->timer.timebase + 30) / 60;
+ break;
+
+ case SEQUENCER_GETTIME:
+ {
+ struct timeval now;
+ u_long t;
+ microtime(&now);
+ SUBTIMEVAL(&now, &sc->timer.start);
+ t = now.tv_sec * 1000000 + now.tv_usec;
+ t /= sc->timer.tick;
+ *(int *)addr = t;
+ break;
+ }
+
+ default:
+ DPRINTFN(-1,("sequencer_ioctl: unimpl %08lx\n", cmd));
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+int
+sequencerselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+
+ DPRINTF(("sequencerselect: %p rw=0x%x\n", sc, rw));
+
+ switch (rw) {
+ case FREAD:
+ if (!SEQ_QEMPTY(&sc->inq))
+ return (1);
+ selrecord(p, &sc->rsel);
+ break;
+
+ case FWRITE:
+ if (SEQ_QLEN(&sc->outq) < sc->lowat)
+ return (1);
+ selrecord(p, &sc->wsel);
+ break;
+ }
+
+ return (0);
+}
+
+void
+seq_reset(sc)
+ struct sequencer_softc *sc;
+{
+ int i, chn;
+ struct midi_dev *md;
+
+ for (i = 0; i < sc->nmidi; i++) {
+ md = sc->devs[i];
+ midiseq_reset(md);
+ for (chn = 0; chn < MAXCHAN; chn++) {
+ midiseq_ctlchange(md, chn, MIDI_CTRL_ALLOFF, 0);
+ midiseq_ctlchange(md, chn, MIDI_CTRL_RESET, 0);
+ midiseq_pitchbend(md, chn, MIDI_BEND_NEUTRAL);
+ }
+ }
+}
+
+int
+seq_do_command(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ int dev;
+
+ DPRINTFN(4, ("seq_do_command: %p cmd=0x%02x\n", sc, SEQ_CMD(b)));
+
+ switch(SEQ_CMD(b)) {
+ case SEQ_LOCAL:
+ return (seq_do_local(sc, b));
+ case SEQ_TIMING:
+ return (seq_do_timing(sc, b));
+ case SEQ_CHN_VOICE:
+ return (seq_do_chnvoice(sc, b));
+ case SEQ_CHN_COMMON:
+ return (seq_do_chncommon(sc, b));
+ case SEQ_SYSEX:
+ return (seq_do_sysex(sc, b));
+ /* COMPAT */
+ case SEQOLD_MIDIPUTC:
+ dev = b->arr[2];
+ if (dev < 0 || dev >= sc->nmidi)
+ return (ENXIO);
+ return (midiseq_putc(sc->devs[dev], b->arr[1]));
+ default:
+ DPRINTFN(-1,("seq_do_command: unimpl command %02x\n",
+ SEQ_CMD(b)));
+ return (EINVAL);
+ }
+}
+
+int
+seq_do_chnvoice(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ int cmd, dev, chan, note, parm, voice;
+ int error;
+ struct midi_dev *md;
+
+ dev = SEQ_EDEV(b);
+ if (dev < 0 || dev >= sc->nmidi)
+ return (ENXIO);
+ md = sc->devs[dev];
+ cmd = SEQ_ECMD(b);
+ chan = SEQ_ECHAN(b);
+ note = SEQ_ENOTE(b);
+ parm = SEQ_EPARM(b);
+ DPRINTFN(2,("seq_do_chnvoice: cmd=%02x dev=%d chan=%d note=%d parm=%d\n",
+ cmd, dev, chan, note, parm));
+ voice = chan;
+ if (cmd == MIDI_NOTEON && parm == 0) {
+ cmd = MIDI_NOTEOFF;
+ parm = MIDI_HALF_VEL;
+ }
+ switch(cmd) {
+ case MIDI_NOTEON:
+ DPRINTFN(5, ("seq_do_chnvoice: noteon %p %d %d %d\n",
+ md, voice, note, parm));
+ error = midiseq_noteon(md, voice, note, parm);
+ break;
+ case MIDI_NOTEOFF:
+ error = midiseq_noteoff(md, voice, note, parm);
+ break;
+ case MIDI_KEY_PRESSURE:
+ error = midiseq_keypressure(md, voice, note, parm);
+ break;
+ default:
+ DPRINTFN(-1,("seq_do_chnvoice: unimpl command %02x\n", cmd));
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+int
+seq_do_chncommon(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ int cmd, dev, chan, p1, w14;
+ int error;
+ struct midi_dev *md;
+ union {
+ int16_t s;
+ u_int8_t b[2];
+ } u;
+
+ dev = SEQ_EDEV(b);
+ if (dev < 0 || dev >= sc->nmidi)
+ return (ENXIO);
+ md = sc->devs[dev];
+ cmd = SEQ_ECMD(b);
+ chan = SEQ_ECHAN(b);
+ p1 = SEQ_EP1(b);
+ u.b[0] = b->arr[6];
+ u.b[1] = b->arr[7];
+ w14 = u.s;
+ DPRINTFN(2,("seq_do_chncommon: %02x\n", cmd));
+
+ error = 0;
+ switch(cmd) {
+ case MIDI_PGM_CHANGE:
+ error = midiseq_pgmchange(md, chan, p1);
+ break;
+ case MIDI_CTL_CHANGE:
+ if (chan > 15 || p1 > 127)
+ return (0); /* EINVAL */
+ error = midiseq_ctlchange(md, chan, p1, w14);
+ break;
+ case MIDI_PITCH_BEND:
+ error = midiseq_pitchbend(md, chan, w14);
+ break;
+ case MIDI_CHN_PRESSURE:
+ error = midiseq_chnpressure(md, chan, p1);
+ break;
+ default:
+ DPRINTFN(-1,("seq_do_chncommon: unimpl command %02x\n", cmd));
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+int
+seq_do_timing(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ union {
+ int32_t i;
+ u_int8_t b[4];
+ } u;
+
+ u.b[0] = b->arr[4];
+ u.b[1] = b->arr[5];
+ u.b[2] = b->arr[6];
+ u.b[3] = b->arr[7];
+ return (seq_timer(sc, SEQ_TCMD(b), u.i, b));
+}
+
+int
+seq_do_local(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ return (EINVAL);
+}
+
+int
+seq_do_sysex(sc, b)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+{
+ int dev, i;
+ struct midi_dev *md;
+ u_int8_t c, *buf = &b->arr[2];
+
+ dev = SEQ_EDEV(b);
+ if (dev < 0 || dev >= sc->nmidi)
+ return (ENXIO);
+ DPRINTF(("seq_do_sysex: dev=%d\n", dev));
+ md = sc->devs[dev];
+
+ if (!sc->doingsysex) {
+ c = MIDI_SYSEX_START;
+ midiseq_out(md, &c, 1, 0);
+ sc->doingsysex = 1;
+ }
+
+ for (i = 0; i < 6 && buf[i] != 0xff; i++)
+ ;
+ midiseq_out(md, buf, i, 0);
+ if (i < 6 || (i > 0 && buf[i-1] == MIDI_SYSEX_END))
+ sc->doingsysex = 0;
+ return (0);
+}
+
+int
+seq_timer(sc, cmd, parm, b)
+ struct sequencer_softc *sc;
+ int cmd, parm;
+ seq_event_rec *b;
+{
+ struct syn_timer *t = &sc->timer;
+ struct timeval when;
+ int ticks;
+ int error;
+ long long usec;
+
+ DPRINTFN(2,("seq_timer: %02x %d\n", cmd, parm));
+
+ error = 0;
+ switch(cmd) {
+ case TMR_WAIT_REL:
+ parm += t->last;
+ /* fall into */
+ case TMR_WAIT_ABS:
+ t->last = parm;
+ usec = (long long)parm * (long long)t->tick; /* convert to usec */
+ when.tv_sec = usec / 1000000;
+ when.tv_usec = usec % 1000000;
+ DPRINTFN(4, ("seq_timer: parm=%d, sleep when=%ld.%06ld", parm,
+ when.tv_sec, when.tv_usec));
+ ADDTIMEVAL(&when, &t->start); /* abstime for end */
+ ticks = hzto(&when);
+ DPRINTFN(4, (" when+start=%ld.%06ld, tick=%d\n",
+ when.tv_sec, when.tv_usec, ticks));
+ if (ticks > 0) {
+#ifdef DIAGNOSTIC
+ if (ticks > 20 * hz) {
+ /* Waiting more than 20s */
+ printf("seq_timer: funny ticks=%d, usec=%lld, parm=%d, tick=%ld\n",
+ ticks, usec, parm, t->tick);
+ }
+#endif
+ sc->timeout = 1;
+ timeout(seq_timeout, sc, ticks);
+ }
+#ifdef SEQUENCER_DEBUG
+ else if (tick < 0)
+ DPRINTF(("seq_timer: ticks = %d\n", ticks));
+#endif
+ break;
+ case TMR_START:
+ microtime(&t->start);
+ t->running = 1;
+ break;
+ case TMR_STOP:
+ microtime(&t->stop);
+ t->running = 0;
+ break;
+ case TMR_CONTINUE:
+ microtime(&when);
+ SUBTIMEVAL(&when, &t->stop);
+ ADDTIMEVAL(&t->start, &when);
+ t->running = 1;
+ break;
+ case TMR_TEMPO:
+ /* parm is ticks per minute / timebase */
+ if (parm < 8)
+ parm = 8;
+ if (parm > 360)
+ parm = 360;
+ t->tempo = parm;
+ RECALC_TICK(t);
+ break;
+ case TMR_ECHO:
+ error = seq_input_event(sc, b);
+ break;
+ case TMR_RESET:
+ t->last = 0;
+ microtime(&t->start);
+ break;
+ default:
+ DPRINTF(("seq_timer: unknown %02x\n", cmd));
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+int
+seq_do_fullsize(sc, b, uio)
+ struct sequencer_softc *sc;
+ seq_event_rec *b;
+ struct uio *uio;
+{
+ struct sysex_info sysex;
+ u_int dev;
+
+#ifdef DIAGNOSTIC
+ if (sizeof(seq_event_rec) != SEQ_SYSEX_HDRSIZE) {
+ printf("seq_do_fullsize: sysex size ??\n");
+ return (EINVAL);
+ }
+#endif
+ memcpy(&sysex, b, sizeof sysex);
+ dev = sysex.device_no;
+ DPRINTFN(2, ("seq_do_fullsize: fmt=%04x, dev=%d, len=%d\n",
+ sysex.key, dev, sysex.len));
+ return (midiseq_loadpatch(sc->devs[dev], &sysex, uio));
+}
+
+/* Convert an old sequencer event to a new one. */
+int
+seq_to_new(ev, uio)
+ seq_event_rec *ev;
+ struct uio *uio;
+{
+ int cmd, chan, note, parm;
+ u_int32_t delay;
+ int error;
+
+ cmd = SEQ_CMD(ev);
+ chan = ev->arr[1];
+ note = ev->arr[2];
+ parm = ev->arr[3];
+ DPRINTFN(3, ("seq_to_new: 0x%02x %d %d %d\n", cmd, chan, note, parm));
+
+ if (cmd >= 0x80) {
+ /* Fill the event record */
+ if (uio->uio_resid >= sizeof *ev - SEQOLD_CMDSIZE) {
+ error = uiomove(&ev->arr[SEQOLD_CMDSIZE],
+ sizeof *ev - SEQOLD_CMDSIZE, uio);
+ if (error)
+ return (error);
+ } else
+ return (EINVAL);
+ }
+
+ switch(cmd) {
+ case SEQOLD_NOTEOFF:
+ note = 255;
+ SEQ_ECMD(ev) = MIDI_NOTEOFF;
+ goto onoff;
+ case SEQOLD_NOTEON:
+ SEQ_ECMD(ev) = MIDI_NOTEON;
+ onoff:
+ SEQ_CMD(ev) = SEQ_CHN_VOICE;
+ SEQ_EDEV(ev) = 0;
+ SEQ_ECHAN(ev) = chan;
+ SEQ_ENOTE(ev) = note;
+ SEQ_EPARM(ev) = parm;
+ break;
+ case SEQOLD_WAIT:
+ delay = *(u_int32_t *)ev->arr >> 8;
+ SEQ_CMD(ev) = SEQ_TIMING;
+ SEQ_TCMD(ev) = TMR_WAIT_REL;
+ *(u_int32_t *)&ev->arr[4] = delay;
+ break;
+ case SEQOLD_SYNCTIMER:
+ SEQ_CMD(ev) = SEQ_TIMING;
+ SEQ_TCMD(ev) = TMR_RESET;
+ break;
+ case SEQOLD_PGMCHANGE:
+ SEQ_ECMD(ev) = MIDI_PGM_CHANGE;
+ SEQ_CMD(ev) = SEQ_CHN_COMMON;
+ SEQ_EDEV(ev) = 0;
+ SEQ_ECHAN(ev) = chan;
+ SEQ_EP1(ev) = note;
+ break;
+ case SEQOLD_MIDIPUTC:
+ break; /* interpret in normal mode */
+ case SEQOLD_ECHO:
+ case SEQOLD_PRIVATE:
+ case SEQOLD_EXTENDED:
+ default:
+ DPRINTF(("seq_to_new: not impl 0x%02x\n", cmd));
+ return (EINVAL);
+ /* In case new events show up */
+ case SEQ_TIMING:
+ case SEQ_CHN_VOICE:
+ case SEQ_CHN_COMMON:
+ case SEQ_FULLSIZE:
+ break;
+ }
+ return (0);
+}
+
+/**********************************************/
+
+void
+midiseq_in(md, msg, len)
+ struct midi_dev *md;
+ u_char *msg;
+ int len;
+{
+ int unit = md->unit;
+ seq_event_rec ev;
+ int status, chan;
+
+ DPRINTFN(2, ("midiseq_in: %p %02x %02x %02x\n",
+ md, msg[0], msg[1], msg[2]));
+
+ status = MIDI_GET_STATUS(msg[0]);
+ chan = MIDI_GET_CHAN(msg[0]);
+ switch (status) {
+ case MIDI_NOTEON:
+ if (msg[2] == 0) {
+ status = MIDI_NOTEOFF;
+ msg[2] = MIDI_HALF_VEL;
+ }
+ /* fall into */
+ case MIDI_NOTEOFF:
+ case MIDI_KEY_PRESSURE:
+ SEQ_MK_CHN_VOICE(&ev, unit, status, chan, msg[1], msg[2]);
+ break;
+ case MIDI_CTL_CHANGE:
+ SEQ_MK_CHN_COMMON(&ev, unit, status, chan, msg[1], 0, msg[2]);
+ break;
+ case MIDI_PGM_CHANGE:
+ case MIDI_CHN_PRESSURE:
+ SEQ_MK_CHN_COMMON(&ev, unit, status, chan, msg[1], 0, 0);
+ break;
+ case MIDI_PITCH_BEND:
+ SEQ_MK_CHN_COMMON(&ev, unit, status, chan, 0, 0,
+ (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7));
+ break;
+ default:
+ return;
+ }
+ seq_event_intr(md->seq, &ev);
+}
+
+struct midi_dev *
+midiseq_open(unit, flags)
+ int unit;
+ int flags;
+{
+ extern struct cfdriver midi_cd;
+ int error;
+ struct midi_dev *md;
+ struct midi_softc *sc;
+ struct midi_info mi;
+
+ DPRINTFN(2, ("midiseq_open: %d %d\n", unit, flags));
+ error = midiopen(makedev(0, unit), flags, 0, 0);
+ if (error)
+ return (0);
+ sc = midi_cd.cd_devs[unit];
+ sc->seqopen = 1;
+ md = malloc(sizeof *md, M_DEVBUF, M_WAITOK);
+ sc->seq_md = md;
+ memset(md, 0, sizeof *md);
+ md->msc = sc;
+ midi_getinfo(makedev(0, unit), &mi);
+ md->unit = unit;
+ md->name = mi.name;
+ md->subtype = 0;
+ md->nr_voices = 128; /* XXX */
+ md->instr_bank_size = 128; /* XXX */
+ if (mi.props & MIDI_PROP_CAN_INPUT)
+ md->capabilities |= SYNTH_CAP_INPUT;
+ return (md);
+}
+
+void
+midiseq_close(md)
+ struct midi_dev *md;
+{
+ DPRINTFN(2, ("midiseq_close: %d\n", md->unit));
+ midiclose(makedev(0, md->unit), 0, 0, 0);
+ free(md, M_DEVBUF);
+}
+
+void
+midiseq_reset(md)
+ struct midi_dev *md;
+{
+ /* XXX send GM reset? */
+ DPRINTFN(3, ("midiseq_reset: %d\n", md->unit));
+}
+
+int
+midiseq_out(md, buf, cc, chk)
+ struct midi_dev *md;
+ u_char *buf;
+ u_int cc;
+ int chk;
+{
+ DPRINTFN(5, ("midiseq_out: m=%p, unit=%d, buf[0]=0x%02x, cc=%d\n",
+ md->msc, md->unit, buf[0], cc));
+
+ /* The MIDI "status" byte does not have to be repeated. */
+ if (chk && md->last_cmd == buf[0])
+ buf++, cc--;
+ else
+ md->last_cmd = buf[0];
+ return (midi_writebytes(md->unit, buf, cc));
+}
+
+int
+midiseq_noteon(md, chan, note, vel)
+ struct midi_dev *md;
+ int chan, note, vel;
+{
+ u_char buf[3];
+
+ DPRINTFN(6, ("midiseq_noteon 0x%02x %d %d\n",
+ MIDI_NOTEON | chan, note, vel));
+ if (chan < 0 || chan > 15 ||
+ note < 0 || note > 127)
+ return (EINVAL);
+ if (vel < 0) vel = 0;
+ if (vel > 127) vel = 127;
+ buf[0] = MIDI_NOTEON | chan;
+ buf[1] = note;
+ buf[2] = vel;
+ return (midiseq_out(md, buf, 3, 1));
+}
+
+int
+midiseq_noteoff(md, chan, note, vel)
+ struct midi_dev *md;
+ int chan, note, vel;
+{
+ u_char buf[3];
+
+ if (chan < 0 || chan > 15 ||
+ note < 0 || note > 127)
+ return (EINVAL);
+ if (vel < 0) vel = 0;
+ if (vel > 127) vel = 127;
+ buf[0] = MIDI_NOTEOFF | chan;
+ buf[1] = note;
+ buf[2] = vel;
+ return (midiseq_out(md, buf, 3, 1));
+}
+
+int
+midiseq_keypressure(md, chan, note, vel)
+ struct midi_dev *md;
+ int chan, note, vel;
+{
+ u_char buf[3];
+
+ if (chan < 0 || chan > 15 ||
+ note < 0 || note > 127)
+ return (EINVAL);
+ if (vel < 0) vel = 0;
+ if (vel > 127) vel = 127;
+ buf[0] = MIDI_KEY_PRESSURE | chan;
+ buf[1] = note;
+ buf[2] = vel;
+ return (midiseq_out(md, buf, 3, 1));
+}
+
+int
+midiseq_pgmchange(md, chan, parm)
+ struct midi_dev *md;
+ int chan, parm;
+{
+ u_char buf[2];
+
+ if (chan < 0 || chan > 15 ||
+ parm < 0 || parm > 127)
+ return (EINVAL);
+ buf[0] = MIDI_PGM_CHANGE | chan;
+ buf[1] = parm;
+ return (midiseq_out(md, buf, 2, 1));
+}
+
+int
+midiseq_chnpressure(md, chan, parm)
+ struct midi_dev *md;
+ int chan, parm;
+{
+ u_char buf[2];
+
+ if (chan < 0 || chan > 15 ||
+ parm < 0 || parm > 127)
+ return (EINVAL);
+ buf[0] = MIDI_CHN_PRESSURE | chan;
+ buf[1] = parm;
+ return (midiseq_out(md, buf, 2, 1));
+}
+
+int
+midiseq_ctlchange(md, chan, parm, w14)
+ struct midi_dev *md;
+ int chan, parm, w14;
+{
+ u_char buf[3];
+
+ if (chan < 0 || chan > 15 ||
+ parm < 0 || parm > 127)
+ return (EINVAL);
+ buf[0] = MIDI_CTL_CHANGE | chan;
+ buf[1] = parm;
+ buf[2] = w14 & 0x7f;
+ return (midiseq_out(md, buf, 3, 1));
+}
+
+int
+midiseq_pitchbend(md, chan, parm)
+ struct midi_dev *md;
+ int chan, parm;
+{
+ u_char buf[3];
+
+ if (chan < 0 || chan > 15)
+ return (EINVAL);
+ buf[0] = MIDI_PITCH_BEND | chan;
+ buf[1] = parm & 0x7f;
+ buf[2] = (parm >> 7) & 0x7f;
+ return (midiseq_out(md, buf, 3, 1));
+}
+
+int
+midiseq_loadpatch(md, sysex, uio)
+ struct midi_dev *md;
+ struct sysex_info *sysex;
+ struct uio *uio;
+{
+ u_char c, buf[128];
+ int i, cc, error;
+
+ if (sysex->key != SEQ_SYSEX_PATCH) {
+ DPRINTFN(-1,("midiseq_loadpatch: bad patch key 0x%04x\n",
+ sysex->key));
+ return (EINVAL);
+ }
+ if (uio->uio_resid < sysex->len)
+ /* adjust length, should be an error */
+ sysex->len = uio->uio_resid;
+
+ DPRINTFN(2, ("midiseq_loadpatch: len=%d\n", sysex->len));
+ if (sysex->len == 0)
+ return (EINVAL);
+ error = uiomove(&c, 1, uio);
+ if (error)
+ return error;
+ if (c != MIDI_SYSEX_START) /* must start like this */
+ return (EINVAL);
+ error = midiseq_out(md, &c, 1, 0);
+ if (error)
+ return (error);
+ --sysex->len;
+ while (sysex->len > 0) {
+ cc = sysex->len;
+ if (cc > sizeof buf)
+ cc = sizeof buf;
+ error = uiomove(buf, cc, uio);
+ if (error)
+ break;
+ for(i = 0; i < cc && !MIDI_IS_STATUS(buf[i]); i++)
+ ;
+ error = midiseq_out(md, buf, i, 0);
+ if (error)
+ break;
+ sysex->len -= i;
+ if (i != cc)
+ break;
+ }
+ /* Any leftover data in uio is rubbish;
+ * the SYSEX should be one write ending in SYSEX_END.
+ */
+ uio->uio_resid = 0;
+ c = MIDI_SYSEX_END;
+ return (midiseq_out(md, &c, 1, 0));
+}
+
+int
+midiseq_putc(md, data)
+ struct midi_dev *md;
+ int data;
+{
+ u_char c = data;
+ DPRINTFN(4,("midiseq_putc: 0x%02x\n", data));
+ return (midiseq_out(md, &c, 1, 0));
+}
+
+#include "midi.h"
+#if NMIDI == 0
+/*
+ * If someone has a sequencer, but no midi devices there will
+ * be unresolved references, so we provide little stubs.
+ */
+
+int
+midi_unit_count()
+{
+ return (0);
+}
+
+int
+midiopen(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ return (ENXIO);
+}
+
+struct cfdriver midi_cd;
+
+void
+midi_getinfo(dev, mi)
+ dev_t dev;
+ struct midi_info *mi;
+{
+}
+
+int
+midiclose(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ return (ENXIO);
+}
+
+int
+midi_writebytes(unit, buf, cc)
+ int unit;
+ u_char *buf;
+ int cc;
+{
+ return (ENXIO);
+}
+#endif /* NMIDI == 0 */
+
+#endif /* NSEQUENCER > 0 */
+
diff --git a/sys/dev/sequencervar.h b/sys/dev/sequencervar.h
new file mode 100644
index 00000000000..0d952867eeb
--- /dev/null
+++ b/sys/dev/sequencervar.h
@@ -0,0 +1,111 @@
+/* $OpenBSD: sequencervar.h,v 1.1 1999/01/02 00:02:39 niklas Exp $ */
+/* $NetBSD: sequencervar.h,v 1.5 1998/11/25 22:17:07 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+struct midi_softc;
+
+struct syn_timer {
+ struct timeval start, stop;
+ int tempo, timebase;
+ u_long last;
+ u_long tick;
+ int running;
+};
+
+#define SEQ_MAXQ 256
+struct sequencer_queue {
+ seq_event_rec buf[SEQ_MAXQ];
+ u_int in; /* input index in buf */
+ u_int out; /* output index in buf */
+ u_int count; /* filled slots in buf */
+};
+#define SEQ_QINIT(q) ((q)->in = (q)->out = (q)->count = 0)
+#define SEQ_QEMPTY(q) ((q)->count == 0)
+#define SEQ_QFULL(q) ((q)->count >= SEQ_MAXQ)
+#define SEQ_QPUT(q, e) ((q)->buf[(q)->in++] = (e), (q)->in %= SEQ_MAXQ, (q)->count++)
+#define SEQ_QGET(q, e) ((e) = (q)->buf[(q)->out++], (q)->out %= SEQ_MAXQ, (q)->count--)
+#define SEQ_QLEN(q) ((q)->count)
+
+struct sequencer_softc;
+
+#define MAXCHAN 16
+struct midi_dev {
+ char *name;
+ int subtype;
+ int capabilities;
+ int nr_voices;
+ int instr_bank_size;
+ int unit;
+ u_char last_cmd;
+ struct sequencer_softc *seq;
+ struct midi_softc *msc;
+};
+
+struct sequencer_softc {
+ struct device dev;
+ struct device *sc_dev; /* Hardware device struct */
+ int isopen; /* Open indicator */
+ int flags; /* Open flags */
+ int mode;
+#define SEQ_OLD 0
+#define SEQ_NEW 1
+ int rchan, wchan;
+ int pbus;
+ struct selinfo wsel; /* write selector */
+ struct selinfo rsel; /* read selector */
+ struct proc *async; /* process who wants audio SIGIO */
+
+ char doingsysex; /* doing a SEQ_SYSEX */
+
+ int nmidi; /* number of MIDI devices */
+ struct midi_dev **devs;
+ struct syn_timer timer;
+
+ struct sequencer_queue outq; /* output event queue */
+ u_int lowat; /* output queue low water mark */
+ char timeout; /* timeout has been set */
+
+ struct sequencer_queue inq; /* input event queue */
+ u_long input_stamp;
+};
+
+void seq_event_intr __P((void *, seq_event_rec *));
+
+#define SEQUENCERUNIT(d) ((d) & 0x7f)
+#define SEQ_IS_OLD(d) ((d) & 0x80)
+
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index d09649190b3..ddb9a0782ce 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.27 1998/08/30 17:11:33 art Exp $ */
+/* $OpenBSD: conf.h,v 1.28 1999/01/02 00:02:56 niklas Exp $ */
/* $NetBSD: conf.h,v 1.33 1996/05/03 20:03:32 christos Exp $ */
/*-
@@ -317,8 +317,16 @@ extern struct cdevsw cdevsw[];
/* open, close, read, write, ioctl */
#define cdev_audio_init(c,n) { \
dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
- dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
- 0, dev_init(c,n,select), dev_init(c,n,mmap) }
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,select), \
+ dev_init(c,n,mmap) }
+
+/* open, close, read, write, ioctl, poll */
+#define cdev_midi_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,select), \
+ (dev_type_mmap((*))) enodev }
#define cdev_svr4_net_init(c,n) { \
dev_init(c,n,open), (dev_type_close((*))) enodev, \
@@ -425,6 +433,8 @@ cdev_decl(ptc);
cdev_decl(ctty);
cdev_decl(audio);
+cdev_decl(midi);
+cdev_decl(sequencer);
cdev_decl(cn);
diff --git a/sys/sys/midiio.h b/sys/sys/midiio.h
new file mode 100644
index 00000000000..3afe9342923
--- /dev/null
+++ b/sys/sys/midiio.h
@@ -0,0 +1,253 @@
+/* $OpenBSD: midiio.h,v 1.1 1999/01/02 00:02:56 niklas Exp $ */
+/* $NetBSD: midiio.h,v 1.7 1998/11/25 22:17:07 augustss Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (augustss@netbsd.org).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_MIDIIO_H_
+#define _SYS_MIDIIO_H_
+
+/*
+ * The API defined here is compatible with the OSS MIDI API except
+ * for naming.
+ */
+
+#ifndef _POSIX_SOURCE
+#define __MIDIIO_UNSET_POSIX_SOURCE
+#define _POSIX_SOURCE /* make sure we don't get all the gunk */
+#endif
+#include <machine/endian.h>
+#ifdef __MIDIIO_UNSET_POSIX_SOURCE
+#undef _POSIX_SOURCE
+#undef __MIDIIO_UNSET_POSIX_SOURCE
+#endif
+
+/*
+ * ioctl() commands for /dev/midi##
+ */
+typedef struct {
+ unsigned char cmd;
+ char nr_args, nr_returns;
+ unsigned char data[30];
+} mpu_command_rec;
+
+#define MIDI_PRETIME _IOWR('m', 0, int)
+#define MIDI_MPUMODE _IOWR('m', 1, int)
+#define MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec)
+
+
+/* The MPU401 command acknowledge and active sense command */
+#define MIDI_ACK 0xfe
+
+
+/* Sequencer */
+#define SEQUENCER_RESET _IO ('Q', 0)
+#define SEQUENCER_SYNC _IO ('Q', 1)
+#define SEQUENCER_INFO _IOWR('Q', 2, struct synth_info)
+#define SEQUENCER_CTRLRATE _IOWR('Q', 3, int)
+#define SEQUENCER_GETOUTCOUNT _IOR ('Q', 4, int)
+#define SEQUENCER_GETINCOUNT _IOR ('Q', 5, int)
+/*#define SEQUENCER_PERCMODE _IOW ('Q', 6, int)*/
+/*#define SEQUENCER_TESTMIDI _IOW ('Q', 8, int)*/
+#define SEQUENCER_RESETSAMPLES _IOW ('Q', 9, int)
+#define SEQUENCER_NRSYNTHS _IOR ('Q',10, int)
+#define SEQUENCER_NRMIDIS _IOR ('Q',11, int)
+/*#define SEQUENCER_MIDI_INFO _IOWR('Q',12, struct midi_info)*/
+#define SEQUENCER_THRESHOLD _IOW ('Q',13, int)
+#define SEQUENCER_MEMAVL _IOWR('Q',14, int)
+/*#define SEQUENCER_FM_4OP_ENABLE _IOW ('Q',15, int)*/
+#define SEQUENCER_PANIC _IO ('Q',17)
+#define SEQUENCER_OUTOFBAND _IOW ('Q',18, struct seq_event_rec)
+#define SEQUENCER_GETTIME _IOR ('Q',19, int)
+/*#define SEQUENCER_ID _IOWR('Q',20, struct synth_info)*/
+/*#define SEQUENCER_CONTROL _IOWR('Q',21, struct synth_control)*/
+/*#define SEQUENCER_REMOVESAMPLE _IOWR('Q',22, struct remove_sample)*/
+
+#if 0
+typedef struct synth_control {
+ int devno; /* Synthesizer # */
+ char data[4000]; /* Device specific command/data record */
+} synth_control;
+
+typedef struct remove_sample {
+ int devno; /* Synthesizer # */
+ int bankno; /* MIDI bank # (0=General MIDI) */
+ int instrno; /* MIDI instrument number */
+} remove_sample;
+#endif
+
+#define CMDSIZE 8
+typedef struct seq_event_rec {
+ u_char arr[CMDSIZE];
+} seq_event_rec;
+
+struct synth_info {
+ char name[30];
+ int device;
+ int synth_type;
+#define SYNTH_TYPE_FM 0
+#define SYNTH_TYPE_SAMPLE 1
+#define SYNTH_TYPE_MIDI 2
+
+ int synth_subtype;
+#define SYNTH_SUB_FM_TYPE_ADLIB 0x00
+#define SYNTH_SUB_FM_TYPE_OPL3 0x01
+#define SYNTH_SUB_MIDI_TYPE_MPU401 0x401
+
+#define SYNTH_SUB_SAMPLE_TYPE_BASIC 0x10
+#define SYNTH_SUB_SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC
+
+ int nr_voices;
+ int instr_bank_size;
+ u_int capabilities;
+#define SYNTH_CAP_OPL3 0x00000002
+#define SYNTH_CAP_INPUT 0x00000004
+};
+
+/* Sequencer timer */
+#define SEQUENCER_TMR_TIMEBASE _IOWR('T', 1, int)
+#define SEQUENCER_TMR_START _IO ('T', 2)
+#define SEQUENCER_TMR_STOP _IO ('T', 3)
+#define SEQUENCER_TMR_CONTINUE _IO ('T', 4)
+#define SEQUENCER_TMR_TEMPO _IOWR('T', 5, int)
+#define SEQUENCER_TMR_SOURCE _IOWR('T', 6, int)
+# define SEQUENCER_TMR_INTERNAL 0x00000001
+#if 0
+# define SEQUENCER_TMR_EXTERNAL 0x00000002
+# define SEQUENCER_TMR_MODE_MIDI 0x00000010
+# define SEQUENCER_TMR_MODE_FSK 0x00000020
+# define SEQUENCER_TMR_MODE_CLS 0x00000040
+# define SEQUENCER_TMR_MODE_SMPTE 0x00000080
+#endif
+#define SEQUENCER_TMR_METRONOME _IOW ('T', 7, int)
+#define SEQUENCER_TMR_SELECT _IOW ('T', 8, int)
+
+
+#define MIDI_CTRL_ALLOFF 123
+#define MIDI_CTRL_RESET 121
+#define MIDI_BEND_NEUTRAL (1<<13)
+
+#define MIDI_NOTEOFF 0x80
+#define MIDI_NOTEON 0x90
+#define MIDI_KEY_PRESSURE 0xA0
+#define MIDI_CTL_CHANGE 0xB0
+#define MIDI_PGM_CHANGE 0xC0
+#define MIDI_CHN_PRESSURE 0xD0
+#define MIDI_PITCH_BEND 0xE0
+#define MIDI_SYSTEM_PREFIX 0xF0
+
+#define MIDI_IS_STATUS(d) ((d) >= 0x80)
+#define MIDI_IS_COMMON(d) ((d) >= 0xf0)
+
+#define MIDI_SYSEX_START 0xF0
+#define MIDI_SYSEX_END 0xF7
+
+#define MIDI_GET_STATUS(d) ((d) & 0xf0)
+#define MIDI_GET_CHAN(d) ((d) & 0x0f)
+
+#define MIDI_HALF_VEL 64
+
+#define SEQ_LOCAL 0x80
+#define SEQ_TIMING 0x81
+#define SEQ_CHN_COMMON 0x92
+#define SEQ_CHN_VOICE 0x93
+#define SEQ_SYSEX 0x94
+#define SEQ_FULLSIZE 0xfd
+
+#define SEQ_MK_CHN_VOICE(e, unit, cmd, chan, key, vel) (\
+ (e)->arr[0] = SEQ_CHN_VOICE, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
+ (e)->arr[3] = (chan), (e)->arr[4] = (key), (e)->arr[5] = (vel),\
+ (e)->arr[6] = 0, (e)->arr[7] = 0)
+#define SEQ_MK_CHN_COMMON(e, unit, cmd, chan, p1, p2, w14) (\
+ (e)->arr[0] = SEQ_CHN_COMMON, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
+ (e)->arr[3] = (chan), (e)->arr[4] = (p1), (e)->arr[5] = (p2),\
+ *(short*)&(e)->arr[6] = (w14))
+
+#if _QUAD_LOWWORD == 1
+/* big endian */
+#define SEQ_PATCHKEY(id) (0xfd00|id)
+#else
+/* little endian */
+#define SEQ_PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+struct sysex_info {
+ u_int16_t key; /* Use SYSEX_PATCH or MAUI_PATCH here */
+#define SEQ_SYSEX_PATCH SEQ_PATCHKEY(0x05)
+#define SEQ_MAUI_PATCH SEQ_PATCHKEY(0x06)
+ int16_t device_no; /* Synthesizer number */
+ int32_t len; /* Size of the sysex data in bytes */
+ u_char data[1]; /* Sysex data starts here */
+};
+#define SEQ_SYSEX_HDRSIZE ((u_long)((struct sysex_info *)0)->data)
+
+typedef unsigned char sbi_instr_data[32];
+struct sbi_instrument {
+ u_int16_t key; /* FM_PATCH or OPL3_PATCH */
+#define SBI_FM_PATCH SEQ_PATCHKEY(0x01)
+#define SBI_OPL3_PATCH SEQ_PATCHKEY(0x03)
+ int16_t device;
+ int32_t channel;
+ sbi_instr_data operators;
+};
+
+#define TMR_RESET 0
+#define TMR_WAIT_REL 1 /* Time relative to the prev time */
+#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */
+#define TMR_STOP 3
+#define TMR_START 4
+#define TMR_CONTINUE 5
+#define TMR_TEMPO 6
+#define TMR_ECHO 8
+#define TMR_CLOCK 9 /* MIDI clock */
+#define TMR_SPP 10 /* Song position pointer */
+#define TMR_TIMESIG 11 /* Time signature */
+
+/* Old sequencer definitions */
+#define SEQOLD_CMDSIZE 4
+
+#define SEQOLD_NOTEOFF 0
+#define SEQOLD_NOTEON 1
+#define SEQOLD_WAIT TMR_WAIT_ABS
+#define SEQOLD_PGMCHANGE 3
+#define SEQOLD_SYNCTIMER TMR_START
+#define SEQOLD_MIDIPUTC 5
+#define SEQOLD_ECHO TMR_ECHO
+#define SEQOLD_AFTERTOUCH 9
+#define SEQOLD_CONTROLLER 10
+#define SEQOLD_PRIVATE 0xfe
+#define SEQOLD_EXTENDED 0xff
+
+#endif /* !_SYS_MIDIIO_H_ */