diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-02 00:02:57 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-02 00:02:57 +0000 |
commit | 16eef665101a8c1334032296ea7d1584ff9c7e57 (patch) | |
tree | 5cc9b881cb0bdd13a85c95e2cbd124b47ddc4645 /sys | |
parent | 890d46b55a21bec77e2f60dbf22d16199ccdbaa7 (diff) |
Midi & sequencer support from NetBSD, mostly by Lennart Augustsson
Diffstat (limited to 'sys')
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_ */ |