Skip to content

Instantly share code, notes, and snippets.

@ao-kenji
Created December 26, 2014 15:18
Show Gist options
  • Select an option

  • Save ao-kenji/2ae12682e21280499711 to your computer and use it in GitHub Desktop.

Select an option

Save ao-kenji/2ae12682e21280499711 to your computer and use it in GitHub Desktop.
[Merged into the original tree] NEC PC-9801-86 sound board support on OpenBSD/luna88k.
Index: cbus.c
===================================================================
RCS file: /cvs/src/sys/arch/luna88k/cbus/cbus.c,v
retrieving revision 1.1
diff -u -r1.1 cbus.c
--- cbus.c 19 Dec 2014 13:17:35 -0000 1.1
+++ cbus.c 26 Dec 2014 15:08:44 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: cbus.c,v 1.1 2014/12/19 13:17:35 aoyama Exp $ */
+/* $OpenBSD: cbus.c,v 1.1 2014/12/08 13:24:04 aoyama Exp $ */
/*
* Copyright (c) 2014 Kenji Aoyama.
@@ -36,6 +36,15 @@
#define CBUS_DEBUG
#endif
+#include "necsb.h"
+
+static struct cbus_attach_args cbus_devs[] = {
+#if NNECSB > 0
+ { "necsb", -1 }, /* PC-9801-86 sound board */
+#endif
+ { "pcex", -1 } /* C-bus "generic" driver */
+};
+
/*
* C-bus interrupt status register
*/
@@ -86,7 +95,6 @@
{
struct cbus_softc *sc = (struct cbus_softc *)self;
struct mainbus_attach_args *ma = args;
- struct cbus_attach_args caa;
int i;
for (i = 0; i < NCBUSISR; i++) {
@@ -101,8 +109,9 @@
printf("\n");
- caa.intlevel = -1; /* not specified */
- config_found(self, &caa, cbus_print);
+ for (i = 0; i < sizeof(cbus_devs)/sizeof(cbus_devs[0]); i++)
+ config_found(self, &cbus_devs[i], cbus_print);
+
return;
}
@@ -110,12 +119,11 @@
cbus_print(void *aux, const char *pnp)
{
struct cbus_attach_args *caa = aux;
-#if 0 /* not yet */
+
if (pnp)
- printf("%s at %s", caa->name, pnp); /* not configured */
-#endif
- if (caa->intlevel != -1)
- printf(" INT %d", caa->intlevel);
+ printf("%s at %s", caa->ca_name, pnp); /* not configured */
+ if (caa->ca_intlevel != -1)
+ printf(" int %d", caa->ca_intlevel);
return UNCONF;
}
Index: cbusvar.h
===================================================================
RCS file: /cvs/src/sys/arch/luna88k/cbus/cbusvar.h,v
retrieving revision 1.1
diff -u -r1.1 cbusvar.h
--- cbusvar.h 19 Dec 2014 13:17:35 -0000 1.1
+++ cbusvar.h 26 Dec 2014 15:08:44 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: cbusvar.h,v 1.1 2014/12/19 13:17:35 aoyama Exp $ */
+/* $OpenBSD: cbusvar.h,v 1.1 2014/12/08 13:24:04 aoyama Exp $ */
/*
* Copyright (c) 2014 Kenji Aoyama.
@@ -42,5 +42,6 @@
void cbus_isrdispatch(int);
struct cbus_attach_args {
- int intlevel;
+ char *ca_name;
+ int ca_intlevel;
};
Index: nec86.c
===================================================================
RCS file: nec86.c
diff -N nec86.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ nec86.c 26 Dec 2014 15:08:44 -0000
@@ -0,0 +1,260 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86.c,v 1.11 1999/07/23 11:04:39 honda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * nec86.c
+ *
+ * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
+ * Written by NAGAO Tadaaki, Feb 10, 1996.
+ *
+ * Modified by N. Honda, Mar 7, 1998
+ */
+
+#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 <machine/board.h> /* PC_BASE */
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+
+#include <luna88k/cbus/nec86reg.h>
+#include <luna88k/cbus/nec86hwvar.h>
+#include <luna88k/cbus/nec86var.h>
+
+#define NEC_SCR_SIDMASK 0xf0
+#define NEC_SCR_MASK 0x0f
+#define NEC_SCR_EXT_ENABLE 0x01
+
+#define PCEXIO_BASE (PC_BASE + 0x1000000)
+
+struct audio_device nec86_device = {
+ .name = "PC-9801-86",
+ .version = "1.0",
+ .config = "pcm"
+};
+
+/*
+ * Define our interface to the higher level audio driver.
+ */
+
+struct audio_hw_if nec86_hw_if = {
+ .open = nec86hw_open,
+ .close = nec86hw_close,
+ .drain = NULL,
+ .query_encoding = nec86hw_query_encoding,
+ .set_params = nec86hw_set_params,
+ .round_blocksize = nec86hw_round_blocksize,
+ .commit_settings = nec86hw_commit_settings,
+ .init_output = nec86hw_pdma_init_output,
+ .init_input = nec86hw_pdma_init_input,
+ .start_output = nec86hw_pdma_output,
+ .start_input = nec86hw_pdma_input,
+ .halt_output = nec86hw_halt_pdma,
+ .halt_input = nec86hw_halt_pdma,
+ .speaker_ctl = nec86hw_speaker_ctl,
+ .getdev = nec86getdev,
+ .setfd = nec86hw_setfd,
+ .set_port = nec86hw_mixer_set_port,
+ .get_port = nec86hw_mixer_get_port,
+ .query_devinfo = nec86hw_mixer_query_devinfo,
+ .allocm = NULL,
+ .freem = NULL,
+ .round_buffersize = NULL,
+ .mappage = NULL,
+ .get_props = nec86_get_props,
+ .trigger_output = NULL,
+ .trigger_input = NULL,
+ .get_default_params = NULL
+};
+
+/*
+ * YAMAHA YM2608(OPNA) register read/write functions
+ */
+void nec86_opna_read(struct nec86_softc *, u_int8_t, u_int8_t *);
+void nec86_opna_write(struct nec86_softc *, u_int8_t, u_int8_t);
+
+void
+nec86_opna_read(struct nec86_softc *sc, u_int8_t index, u_int8_t *data) {
+ bus_space_write_1(sc->sc_ym2608iot, sc->sc_ym2608ioh, 0, index);
+ delay(100); /* 100 ms */
+ *data = bus_space_read_1(sc->sc_ym2608iot, sc->sc_ym2608ioh, 2);
+ delay(100); /* 100 ms */
+}
+
+void
+nec86_opna_write(struct nec86_softc *sc, u_int8_t index, u_int8_t data) {
+ bus_space_write_1(sc->sc_ym2608iot, sc->sc_ym2608ioh, 0, index);
+ delay(100); /* 100 ms */
+ bus_space_write_1(sc->sc_ym2608iot, sc->sc_ym2608ioh, 2, data);
+ delay(100); /* 100 ms */
+}
+
+/*
+ * Probe for NEC PC-9801-86 SoundBoard hardware.
+ */
+int
+nec86_probesubr(bus_space_tag_t iot, bus_space_handle_t ioh,
+ bus_space_handle_t n86ioh)
+{
+ u_int8_t data;
+
+#ifdef notyet
+ if (nec86hw_probesubr(iot, ioh) != 0)
+ return -1;
+#endif /* notyet */
+
+ if (n86ioh == 0)
+ return -1;
+
+ data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
+
+ switch (data & NEC_SCR_SIDMASK) {
+#if 0 /* XXX - PC-9801-73 not yet supported. */
+ case 0x20:
+ case 0x30:
+ break;
+#endif
+ case 0x40:
+ case 0x50:
+ break;
+ default: /* No supported board found. */
+ return -1;
+ /*NOTREACHED*/
+ }
+
+ return ((data & NEC_SCR_SIDMASK) >> 4) - 2;
+}
+
+/*
+ * Attach hardware to driver, attach hardware driver to audio
+ * pseudo-device driver.
+ */
+#define MODEL0_NAME "PC-9801-73 soundboard"
+#define MODEL1_NAME "PC-9801-86 soundboard"
+
+void
+nec86_attachsubr(struct nec86_softc *sc)
+{
+ struct nec86hw_softc *ysc = &sc->sc_nec86hw;
+ bus_space_tag_t iot = sc->sc_n86iot;
+ bus_space_handle_t n86ioh = sc->sc_n86ioh;
+ char *boardname[] =
+ {MODEL0_NAME, MODEL0_NAME, MODEL1_NAME, MODEL1_NAME};
+ u_int8_t data;
+ int model;
+
+ if ((model = nec86_probesubr(iot, n86ioh, n86ioh)) < 0) {
+ printf("%s: missing hardware\n", ysc->sc_dev.dv_xname);
+ return;
+ }
+ ysc->model = model;
+
+ switch (ysc->model) {
+ case 2: /* I/O ports for OPNA are 0x188 and 0x18a */
+ sc->sc_ym2608ioh = PCEXIO_BASE + OPNA_IOBASE1;
+ break;
+ case 3: /* I/O ports for OPNA are 0x288 and 0x28a */
+ sc->sc_ym2608ioh = PCEXIO_BASE + OPNA_IOBASE2;
+ break;
+ default:
+ /* can not happen */
+ break;
+ }
+
+ data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
+ data &= ~NEC_SCR_MASK;
+ data |= NEC_SCR_EXT_ENABLE;
+ bus_space_write_1(iot, n86ioh, NEC86_SOUND_ID, data);
+
+ /* OPNA I/O port set (IOA:input IOB:output) */
+ nec86_opna_read(sc, 0x07, &data);
+ data &= 0x3f;
+ data |= 0x80;
+ nec86_opna_write(sc, 0x07, data);
+
+ /* OPNA register 0x0e has INT level */
+ nec86_opna_read(sc, 0x0e, &data);
+ switch (data & 0xc0) {
+ case 0x00:
+ sc->sc_intlevel = 0;
+ break;
+ case 0x40:
+ sc->sc_intlevel = 6;
+ break;
+ case 0x80:
+ sc->sc_intlevel = 4;
+ break;
+ case 0xc0:
+ sc->sc_intlevel = 5; /* factory default setting */
+ break;
+ default:
+ /* can not happen */
+ break;
+ }
+
+ printf(" int %d", sc->sc_intlevel);
+
+ /*
+ * reset OPNA timer A/B XXX: need this?
+ * (refer to 'YM2608 application manual' for detail)
+ */
+ data = 0x30;
+ nec86_opna_write(sc, 0x27, data);
+
+ nec86hw_attach(ysc);
+
+ if (sc->sc_attached == 0) {
+ printf(": %s\n", boardname[ysc->model]);
+ audio_attach_mi(&nec86_hw_if, ysc, &ysc->sc_dev);
+ sc->sc_attached = 1;
+ }
+}
+
+/*
+ * Various routines to interface to higher level audio driver.
+ */
+int
+nec86getdev(void *addr, struct audio_device *retp)
+{
+ *retp = nec86_device;
+
+ return 0;
+}
Index: nec86hw.c
===================================================================
RCS file: nec86hw.c
diff -N nec86hw.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ nec86hw.c 26 Dec 2014 15:08:44 -0000
@@ -0,0 +1,1833 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86hw.c,v 1.13 1998/03/14 07:04:54 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * nec86hw.c
+ *
+ * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
+ * Written by NAGAO Tadaaki, Feb 10, 1996.
+ *
+ * Modified by N. Honda, Mar 7, 1998
+ */
+/*
+ * TODO:
+ * - Add PC-9801-73 support.
+ * - Fake the mixer device with electric volumes.
+ */
+
+#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 <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <dev/mulaw.h>
+#include <dev/auconv.h>
+
+#if 0
+#include <dev/ic/ym2203reg.h>
+#endif
+#include <luna88k/cbus/nec86reg.h>
+#include <luna88k/cbus/nec86hwvar.h>
+#include <luna88k/cbus/nec86var.h>
+
+#ifdef AUDIO_DEBUG
+extern void Dprintf(const char *, ...);
+#define DPRINTF(x) if (nec86hwdebug) printf x
+#define DPRINTF2(l, x) if (nec86hwdebug >= l) printf x
+int nec86hwdebug = 3;
+#else /* !AUDIO_DEBUG */
+#define DPRINTF(x)
+#define DPRINTF2(l, x)
+#endif /* AUDIO_DEBUG */
+
+#ifndef VOLUME_DELAY
+/*
+ * XXX - Delaytime in microsecond after an access
+ * to the volume I/O port.
+ */
+#define VOLUME_DELAY 10
+#endif /* !VOLUME_DELAY */
+
+/*
+ * Sampling rates supported by the hardware.
+ */
+static int nec86hw_rate_table[NEC86HW_NRATE_TYPE][NEC86_NRATE] = {
+ /* NEC PC-9801-86 or its full compatibles */
+ { 44100, 33075, 22050, 16538, 11025, 8269, 5513, 4134 },
+ /* Some earlier versions of Q-Vision's WaveMaster */
+ { 44100, 33075, 22050, 16000, 11025, 8000, 5513, 4000 },
+};
+
+int nec86hw_set_output_block(struct nec86hw_softc *, int);
+int nec86hw_set_input_block(struct nec86hw_softc *, int);
+
+/*
+ * Function tables.
+ */
+static struct nec86hw_functable_entry nec86hw_functable[] = {
+ /* precision, channels,
+ output function, input function (without resampling),
+ output function, input function (with resampling) */
+ { 8, 1,
+ nec86fifo_output_mono_8_direct, nec86fifo_input_mono_8_direct,
+ nec86fifo_output_mono_8_resamp, nec86fifo_input_mono_8_resamp },
+ { 16, 1,
+ nec86fifo_output_mono_16_direct, nec86fifo_input_mono_16_direct,
+ nec86fifo_output_mono_16_resamp, nec86fifo_input_mono_16_resamp },
+ { 8, 2,
+ nec86fifo_output_stereo_8_direct, nec86fifo_input_stereo_8_direct,
+ nec86fifo_output_stereo_8_resamp, nec86fifo_input_stereo_8_resamp },
+ { 16, 2,
+ nec86fifo_output_stereo_16_direct, nec86fifo_input_stereo_16_direct,
+ nec86fifo_output_stereo_16_resamp, nec86fifo_input_stereo_16_resamp },
+};
+#define NFUNCTABLEENTRY (sizeof(nec86hw_functable) / sizeof(nec86hw_functable[0]))
+
+/*
+ * Attach hardware to driver, attach hardware driver to audio
+ * pseudo-device driver.
+ */
+void
+nec86hw_attach(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ /* Set default encoding. */
+ sc->func_fifo_output = nec86fifo_output_mono_8_resamp;
+ sc->func_fifo_input = nec86fifo_input_mono_8_resamp;
+ (void) nec86hw_set_params(sc, AUMODE_RECORD, 0,
+ &audio_default, &audio_default);
+ (void) nec86hw_set_params(sc, AUMODE_PLAY, 0,
+ &audio_default, &audio_default);
+
+ /* Set default ports. */
+ (void) nec86hw_set_in_port(sc, NEC86HW_INPUT_MIXER);
+ (void) nec86hw_set_out_port(sc, NEC86HW_OUTPUT_MIXER);
+
+ /* Set default gains. */
+ nec86hw_set_volume(sc, NEC86_VOLUME_PORT_OPNAD, NEC86_MAXVOL);
+ nec86hw_set_volume(sc, NEC86_VOLUME_PORT_OPNAI, NEC86_MAXVOL);
+ nec86hw_set_volume(sc, NEC86_VOLUME_PORT_LINED, NEC86_MAXVOL);
+ nec86hw_set_volume(sc, NEC86_VOLUME_PORT_LINEI, NEC86_MAXVOL);
+ nec86hw_set_volume(sc, NEC86_VOLUME_PORT_PCMD, NEC86_MAXVOL);
+
+ /* Internal Speaker ON */
+ nec86hw_speaker_ctl(sc, SPKR_ON);
+
+ /* Set miscellanous stuffs. */
+ data = bus_space_read_1(iot, ioh, NEC86_CTRL);
+ data &= NEC86_CTRL_MASK_PAN | NEC86_CTRL_MASK_PORT;
+ data |= NEC86_CTRL_PAN_L | NEC86_CTRL_PAN_R;
+ data |= NEC86_CTRL_PORT_STD;
+ bus_space_write_1(iot, ioh, NEC86_CTRL, data);
+}
+
+/*
+ * Various routines to interface to higher level audio driver.
+ */
+
+int
+nec86hw_open(void *arg, int flags)
+{
+ struct nec86hw_softc *sc = arg;
+ DPRINTF(("nec86hw_open: sc=%p\n", sc));
+
+ if (sc->sc_open != 0 || nec86hw_reset(sc) != 0)
+ return ENXIO;
+
+ sc->sc_open = 1;
+ sc->sc_intr = NULL;
+ sc->sc_arg = NULL;
+
+ sc->conv_acc = 0;
+ sc->conv_last0 = 0;
+ sc->conv_last0_l = 0;
+ sc->conv_last0_r = 0;
+ sc->conv_last1 = 0;
+ sc->conv_last1_l = 0;
+ sc->conv_last1_r = 0;
+
+ /*
+ * Leave most things including sampling format and rate as they were.
+ * (See audio_open() in audio.c)
+ */
+
+ DPRINTF(("nec86hw_open: opened\n"));
+
+ return 0;
+}
+
+void
+nec86hw_close(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_close: sc=%p\n", sc));
+
+ sc->sc_open = 0;
+ sc->sc_intr = NULL;
+ (void) nec86hw_reset(sc);
+
+ DPRINTF(("nec86hw_close: closed\n"));
+}
+
+int
+nec86hw_set_params(void *addr, int mode, int usemode, struct audio_params *p,
+ struct audio_params *r)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+ int rate_type = NEC86HW_RATE_TYPE(sc->sc_cfgflags);
+ u_int prec, enc;
+
+ if ((p->channels != 1) && (p->channels != 2))
+ return EINVAL;
+
+ enc = p->encoding;
+ prec = p->precision;
+ switch (enc) {
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_SLINEAR_LE:
+ if (prec == 8)
+ enc = AUDIO_ENCODING_SLINEAR;
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ if (prec == 8)
+ enc = AUDIO_ENCODING_ULINEAR;
+ break;
+ case AUDIO_ENCODING_SLINEAR:
+ if (prec == 16)
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ break;
+ case AUDIO_ENCODING_ULINEAR:
+ if (prec == 16)
+ enc = AUDIO_ENCODING_ULINEAR_LE;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ case AUDIO_ENCODING_ALAW:
+ break;
+ default:
+ return EINVAL;
+ }
+
+ p->sw_code = NULL;
+ r->sw_code = NULL;
+ switch (enc) {
+ case AUDIO_ENCODING_ULAW:
+ p->sw_code = mulaw_to_ulinear8;
+ r->sw_code = ulinear8_to_mulaw;
+ enc = AUDIO_ENCODING_ULINEAR;
+ break;
+ case AUDIO_ENCODING_ALAW:
+ p->sw_code = alaw_to_ulinear8;
+ r->sw_code = ulinear8_to_alaw;
+ enc = AUDIO_ENCODING_ULINEAR;
+ break;
+ case AUDIO_ENCODING_ULINEAR_LE:
+ p->sw_code = r->sw_code = change_sign16;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ p->sw_code = r->sw_code = swap_bytes_change_sign16;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ break;
+ case AUDIO_ENCODING_SLINEAR_BE:
+ p->sw_code = r->sw_code = swap_bytes;
+ enc = AUDIO_ENCODING_SLINEAR_LE;
+ break;
+ case AUDIO_ENCODING_SLINEAR:
+ p->sw_code = r->sw_code = change_sign8;
+ enc = AUDIO_ENCODING_ULINEAR;
+ break;
+ default:
+ break;
+ }
+
+ sc->channels = p->channels;
+ sc->precision = prec;
+ sc->encoding = enc;
+ sc->sc_orate = p->sample_rate;
+ sc->hw_orate_bits = nec86hw_rate_bits(sc, p->sample_rate);
+ sc->hw_orate = nec86hw_rate_table[rate_type][sc->hw_orate_bits];
+ sc->sc_irate = r->sample_rate;
+ sc->hw_irate_bits = nec86hw_rate_bits(sc, r->sample_rate);
+ sc->hw_irate = nec86hw_rate_table[rate_type][sc->hw_irate_bits];
+ return 0;
+}
+
+int
+nec86hw_query_encoding(void *addr, struct audio_encoding *fp)
+{
+
+ switch (fp->index) {
+ case 0:
+ strlcpy(fp->name, AudioEmulaw, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_ULAW;
+ fp->precision = 8;
+ fp->bps = 1;
+ fp->msb = 1;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 1:
+ strlcpy(fp->name, AudioEalaw, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_ALAW;
+ fp->precision = 8;
+ fp->bps = 1;
+ fp->msb = 1;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 2:
+ strlcpy(fp->name, AudioEulinear, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_ULINEAR;
+ fp->precision = 8;
+ fp->bps = 1;
+ fp->msb = 1;
+ fp->flags = 0;
+ break;
+ case 3:
+ strlcpy(fp->name, AudioEslinear, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_SLINEAR;
+ fp->precision = 8;
+ fp->bps = 1;
+ fp->msb = 1;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 4:
+ strlcpy(fp->name, AudioEulinear_le, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
+ fp->precision = 16;
+ fp->bps = 2;
+ fp->msb = 1; /* is this OK? */
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 5:
+ strlcpy(fp->name, AudioEulinear_be, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
+ fp->precision = 16;
+ fp->bps = 2;
+ fp->msb = 1; /* is this OK? */
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ case 6:
+ strlcpy(fp->name, AudioEslinear_le, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
+ fp->precision = 16;
+ fp->bps = 2;
+ fp->msb = 1; /* is this OK? */
+ fp->flags = 0;
+ break;
+ case 7:
+ strlcpy(fp->name, AudioEslinear_be, sizeof(fp->name));
+ fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
+ fp->precision = 16;
+ fp->bps = 2;
+ fp->msb = 1; /* is this OK? */
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+ default:
+ return EINVAL;
+ /*NOTREACHED*/
+ }
+
+ return 0;
+}
+
+int
+nec86hw_round_blocksize(void *addr, int blk)
+{
+ u_int base = NEC86_INTRBLK_UNIT;
+
+ if (blk < NEC86_INTRBLK_UNIT * 2)
+ return NEC86_INTRBLK_UNIT * 2;
+
+ for ( ; base <= blk; base *= 2)
+ ;
+ return base / 2;
+}
+
+int
+nec86hw_set_out_port(void *addr, int port)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_set_out_port:\n"));
+
+ if (port != NEC86HW_OUTPUT_MIXER)
+ return EINVAL;
+
+ sc->out_port = port;
+
+ return 0;
+}
+
+int
+nec86hw_get_out_port(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_get_out_port:\n"));
+
+ return sc->out_port;
+}
+
+int
+nec86hw_set_in_port(void *addr, int port)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_set_in_port:\n"));
+
+ if (port != NEC86HW_INPUT_MIXER)
+ return EINVAL;
+
+ sc->in_port = port;
+
+ return 0;
+}
+
+int
+nec86hw_get_in_port(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_get_in_port:\n"));
+
+ return sc->in_port;
+}
+
+int
+nec86hw_commit_settings(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+ int i;
+
+ /*
+ * Determine which function should be used to write to/read from
+ * the FIFO ring buffer.
+ */
+
+ for (i = 0; i < NFUNCTABLEENTRY; i++) {
+ if ((nec86hw_functable[i].precision == sc->precision)
+ && (nec86hw_functable[i].channels == sc->channels))
+ break;
+ }
+
+ if (i >= NFUNCTABLEENTRY) {
+ /* ??? - This should never happen. */
+ return EINVAL;
+ }
+
+ if (sc->sc_orate == sc->hw_orate) {
+ /* No need to resample. */
+ sc->func_fifo_output =
+ nec86hw_functable[i].func_fifo_output_direct;
+ } else {
+ /* Resampling needed. */
+ sc->func_fifo_output =
+ nec86hw_functable[i].func_fifo_output_resamp;
+ }
+
+ if (sc->sc_irate == sc->hw_irate) {
+ /* No need to resample. */
+ sc->func_fifo_input =
+ nec86hw_functable[i].func_fifo_input_direct;
+ } else {
+ /* Resampling needed. */
+ sc->func_fifo_input =
+ nec86hw_functable[i].func_fifo_input_resamp;
+ }
+
+ return 0;
+}
+
+int
+nec86hw_setfd(void *addr, int flag)
+{
+ DPRINTF(("nec86hw_setfd:\n"));
+
+ /* Can't do full-duplex */
+ return ENOTTY;
+}
+
+int
+nec86hw_mixer_set_port(void *addr, mixer_ctrl_t *cp)
+{
+ DPRINTF(("nec86hw_mixer_set_port:\n"));
+
+ /* not yet implemented */
+ return ENXIO;
+}
+
+int
+nec86hw_mixer_get_port(void *addr, mixer_ctrl_t *cp)
+{
+ DPRINTF(("nec86hw_mixer_get_port:\n"));
+
+ /* not yet implemented */
+ return ENXIO;
+}
+
+int
+nec86hw_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
+{
+ DPRINTF(("nec86hw_mixer_query_devinfo:\n"));
+
+ /* not yet implemented */
+ return ENXIO;
+}
+
+int
+nec86hw_set_output_block(struct nec86hw_softc *sc, int cc)
+{
+ int bpf, hw_blocksize, watermark;
+
+ bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
+ sc->pdma_count = cc / bpf;
+
+ /* Size of the block after the rate-conversion. */
+ hw_blocksize =
+ (sc->pdma_count * sc->hw_orate) / sc->sc_orate
+ * (sc->precision / NBBY * 2);
+
+ /* How many chunks the block should be divided into. */
+ sc->pdma_nchunk =
+ ((hw_blocksize * (WATERMARK_MAX_RATIO + WATERMARK_RATIO_OUT))
+ + (NEC86_BUFFSIZE * WATERMARK_MAX_RATIO - 1))
+ / (NEC86_BUFFSIZE * WATERMARK_MAX_RATIO);
+
+ /* Calculate the watermark. */
+ watermark =
+ (hw_blocksize * WATERMARK_RATIO_OUT)
+ / (sc->pdma_nchunk * WATERMARK_MAX_RATIO);
+ sc->pdma_watermark = nec86hw_round_watermark(watermark);
+
+ /*
+ * If the formula (*1) does not hold, watermark may be less
+ * than the minimum watermark (NEC86_INTRBLK_UNIT) and then
+ * nec86hw_round_watermark() returns that minimum value.
+ * In this case, the ring buffer on the hardware will potentially
+ * overflow.
+ * To avoid such a case, here calculate pdma_nchunk again.
+ *
+ * (*1) NEC86_BUFFSIZE / NEC86_INTRBLK_UNIT
+ * >= WATERMARK_MAX_RATIO / WATERMARK_RATIO_OUT + 1
+ */
+ if (hw_blocksize + sc->pdma_watermark > NEC86_BUFFSIZE) {
+ sc->pdma_nchunk =
+ (hw_blocksize + (NEC86_BUFFSIZE - sc->pdma_watermark - 1))
+ / (NEC86_BUFFSIZE - sc->pdma_watermark);
+ }
+
+ DPRINTF2(2, ("nec86hw_pdma_output: cc=%d count=%d hw_blocksize=%d "
+ "watermark=%d nchunk=%d ptr=%p\n",
+ cc, sc->pdma_count, hw_blocksize, sc->pdma_watermark,
+ sc->pdma_nchunk, sc->pdma_ptr));
+ return 0;
+}
+
+int
+nec86hw_set_input_block(struct nec86hw_softc *sc, int cc)
+{
+ int bpf, hw_blocksize, watermark, maxwatermark;
+
+ bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
+ sc->pdma_count = cc / bpf;
+
+ /* Maximum watermark. */
+ watermark =
+ (NEC86_BUFFSIZE * WATERMARK_RATIO_IN) / WATERMARK_MAX_RATIO;
+ maxwatermark = nec86hw_round_watermark(watermark);
+
+ /* Size of the block before the rate-conversion. */
+ hw_blocksize =
+ (sc->pdma_count * sc->hw_irate + (sc->sc_irate - 1))
+ / sc->sc_irate * (sc->precision / NBBY * 2);
+
+ /* How many chunks the block should be divided into. */
+ sc->pdma_nchunk = (hw_blocksize + (maxwatermark - 1)) / maxwatermark;
+
+ /* Calculate the watermark. */
+ watermark = (hw_blocksize / sc->pdma_nchunk) + (NEC86_INTRBLK_UNIT - 1);
+ sc->pdma_watermark = nec86hw_round_watermark(watermark);
+
+ DPRINTF2(2, ("nec86hw_pdma_input: cc=%d count=%d hw_blocksize=%d "
+ "watermark=%d nchunk=%d ptr=%p\n",
+ cc, sc->pdma_count, hw_blocksize, sc->pdma_watermark,
+ sc->pdma_nchunk, sc->pdma_ptr));
+ return 0;
+}
+
+int
+nec86hw_pdma_init_output(void *addr, void *buf, int cc)
+{
+ struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ nec86hw_halt_pdma(addr);
+ nec86hw_reset_fifo(sc);
+ nec86hw_set_mode_playing(sc);
+ nec86hw_set_rate_real(sc, sc->hw_orate_bits);
+ nec86hw_set_precision_real(sc, sc->precision);
+
+ nec86hw_set_output_block(sc, cc);
+ nec86hw_reset_fifo(sc);
+
+ nec86hw_enable_fifointr(sc);
+ nec86hw_set_watermark(sc, sc->pdma_watermark);
+ nec86hw_disable_fifointr(sc);
+
+ return 0;
+}
+
+int
+nec86hw_pdma_init_input(void *addr, void *buf, int cc)
+{
+ struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ nec86hw_halt_pdma(addr);
+ nec86hw_reset_fifo(sc);
+ nec86hw_set_mode_recording(sc);
+ nec86hw_set_rate_real(sc, sc->hw_irate_bits);
+ nec86hw_set_precision_real(sc, sc->precision);
+
+ nec86hw_set_input_block(sc, cc);
+ nec86hw_reset_fifo(sc);
+
+ nec86hw_enable_fifointr(sc);
+ nec86hw_set_watermark(sc, sc->pdma_watermark);
+ nec86hw_disable_fifointr(sc);
+
+ return 0;
+}
+
+int
+nec86hw_pdma_output(void *addr, void *p, int cc, void (*intr)(void *),
+ void *arg)
+{
+ struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+ int bpf;
+
+ bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
+ if ((cc % bpf) != 0) {
+ DPRINTF(("nec86hw_pdma_output: odd bytes\n"));
+ return EIO;
+ }
+
+ sc->sc_intr = intr;
+ sc->sc_arg = arg;
+
+ /*
+ * We divide the data block into some relatively small chunks if the
+ * block is so large that the ring buffer on the hardware would
+ * overflow.
+ * In this case, we send the first chunk now and the rest in the
+ * interrupt handler.
+ */
+
+ /* Set up for pseudo-DMA. */
+ sc->pdma_ptr = (u_char *) p;
+ sc->pdma_padded = 0;
+ sc->pdma_mode = PDMA_MODE_OUTPUT;
+ if (sc->pdma_count != cc / bpf)
+ nec86hw_set_output_block(sc, cc);
+
+ if (!sc->intr_busy) {
+ nec86hw_set_precision_real(sc, sc->precision);
+ nec86hw_set_rate_real(sc, sc->hw_orate_bits);
+ nec86hw_set_mode_playing(sc);
+ nec86hw_reset_fifo(sc);
+ }
+
+ /*
+ * Send the first chunk. The rest will be sent in the interrupt
+ * handler nec86hw_intr(), if any.
+ */
+ nec86hw_disable_fifointr(sc);
+ nec86hw_output_chunk(sc);
+ nec86hw_enable_fifointr(sc);
+
+ if (!sc->intr_busy) {
+ /* Now start playing. */
+ nec86hw_start_fifo(sc);
+
+ sc->intr_busy = 1;
+ }
+
+ nec86hw_set_watermark(sc, sc->pdma_watermark);
+ return 0;
+}
+
+int
+nec86hw_pdma_input(void *addr, void *p, int cc, void (*intr)(void *),
+ void *arg)
+{
+ struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+ int bpf;
+
+ bpf = (sc->channels * sc->precision) / NBBY; /* bytes per frame */
+ if ((cc % bpf) != 0) {
+ DPRINTF(("nec86hw_pdma_input: odd bytes\n"));
+ return EIO;
+ }
+
+ sc->sc_intr = intr;
+ sc->sc_arg = arg;
+
+ /* Set up for pseudo-DMA. */
+ sc->pdma_ptr = (u_int8_t *) p;
+ sc->pdma_padded = 0; /* Never padded in recording, though. */
+ sc->pdma_mode = PDMA_MODE_INPUT;
+
+ if (sc->pdma_count != cc / bpf)
+ nec86hw_set_input_block(sc, cc);
+
+ if (!sc->intr_busy) {
+ nec86hw_set_precision_real(sc, sc->precision);
+ nec86hw_set_rate_real(sc, sc->hw_irate_bits);
+ nec86hw_set_mode_recording(sc);
+ nec86hw_reset_fifo(sc);
+
+ /* Now start recording. */
+ nec86hw_enable_fifointr(sc);
+ nec86hw_start_fifo(sc);
+
+ sc->intr_busy = 1;
+ }
+
+ nec86hw_set_watermark(sc, sc->pdma_watermark);
+
+ return 0;
+}
+
+int
+nec86hw_halt_pdma(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_halt_pdma: sc=%p\n", sc));
+
+ nec86hw_stop_fifo(sc);
+ nec86hw_disable_fifointr(sc);
+
+ sc->intr_busy = 0;
+
+ return 0;
+}
+
+int
+nec86hw_cont_pdma(void *addr)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+
+ DPRINTF(("nec86hw_cont_pdma: sc=%p\n", sc));
+
+ nec86hw_enable_fifointr(sc);
+ nec86hw_start_fifo(sc);
+
+ sc->intr_busy = 1;
+
+ return 0;
+}
+
+int
+nec86hw_speaker_ctl(void *addr, int onoff)
+{
+ register struct nec86hw_softc *sc = (struct nec86hw_softc *) addr;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ DPRINTF(("nec86hw_speaker_ctl:\n"));
+
+ switch (onoff) {
+ case SPKR_ON:
+ bus_space_write_1(iot, ioh, NEC86_VOLUME, 0x0d1);
+ delay(VOLUME_DELAY);
+ break;
+ case SPKR_OFF:
+ bus_space_write_1(iot, ioh, NEC86_VOLUME, 0x0d0);
+ delay(VOLUME_DELAY);
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+u_int8_t
+nec86hw_rate_bits(struct nec86hw_softc *sc, u_long sr)
+{
+ int i;
+ u_long rval, hr, min;
+ int rate_type = NEC86HW_RATE_TYPE(sc->sc_cfgflags);
+
+ /* Look for the minimum hardware rate equal to or more than sr. */
+ min = 0;
+ rval = 0;
+ for (i = 0; i < NEC86_NRATE; i++) {
+ hr = nec86hw_rate_table[rate_type][i];
+ if ((hr >= sr) && ((min == 0) || (min > hr))) {
+ min = hr;
+ rval = (u_int8_t) i;
+ }
+ }
+
+ return rval;
+}
+
+int
+nec86hw_round_watermark(int wm)
+{
+ wm = (wm / NEC86_INTRBLK_UNIT) * NEC86_INTRBLK_UNIT;
+
+ if (wm < NEC86_INTRBLK_UNIT)
+ wm = NEC86_INTRBLK_UNIT;
+
+ return wm;
+}
+
+/*
+ * Lower-level routines.
+ */
+
+int
+nec86hw_reset(struct nec86hw_softc *sc)
+{
+ nec86hw_stop_fifo(sc);
+ nec86hw_disable_fifointr(sc);
+ nec86hw_clear_intrflg(sc);
+ nec86hw_reset_fifo(sc);
+
+ sc->intr_busy = 0;
+ sc->pdma_mode = PDMA_MODE_NONE;
+
+ if (nec86hw_seeif_intrflg(sc))
+ return -1; /* The hardware vanished? */
+
+ return 0;
+}
+
+/*
+ * Set the mode for playing/recording.
+ */
+void
+nec86hw_set_mode_playing(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data &= ~NEC86_FIFOCTL_RECMODE;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_set_mode_recording(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data |= NEC86_FIFOCTL_RECMODE;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+/*
+ * Set the electric volumes.
+ */
+void
+nec86hw_set_volume(struct nec86hw_softc *sc, int port, u_int8_t vol)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ bus_space_write_1(iot, ioh, NEC86_VOLUME,
+ NEC86_VOL_TO_BITS(port, vol));
+ delay(VOLUME_DELAY);
+}
+
+/*
+ * Control the FIFO ring buffer on the board.
+ */
+void
+nec86hw_start_fifo(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ /* Start playing/recording. */
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data |= NEC86_FIFOCTL_RUN;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_stop_fifo(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ /* Stop playing/recording. */
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data &= ~NEC86_FIFOCTL_RUN;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_enable_fifointr(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data |= NEC86_FIFOCTL_ENBLINTR;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_disable_fifointr(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data &= ~NEC86_FIFOCTL_ENBLINTR;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+int
+nec86hw_seeif_intrflg(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+
+ return (data & NEC86_FIFOCTL_INTRFLG);
+}
+
+void
+nec86hw_clear_intrflg(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data &= ~NEC86_FIFOCTL_INTRFLG;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+ data |= NEC86_FIFOCTL_INTRFLG;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_reset_fifo(struct nec86hw_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data |= NEC86_FIFOCTL_INIT;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+ data &= ~NEC86_FIFOCTL_INIT;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+void
+nec86hw_set_watermark(struct nec86hw_softc *sc, int wm)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ /*
+ * Must be called after nec86hw_start_fifo() and
+ * nec86hw_enable_fifointr() are both called.
+ */
+
+#ifdef DIAGNOSTIC
+ if ((wm < NEC86_INTRBLK_UNIT) || (wm > NEC86_BUFFSIZE)
+ || ((wm % NEC86_INTRBLK_UNIT) != 0))
+ printf("nec86hw_set_watermark: invalid watermark %d\n", wm);
+#endif /* DIAGNOSTIC */
+
+ /*
+ * The interrupt occurs when the number of bytes in the FIFO ring
+ * buffer exceeds this watarmark.
+ */
+ bus_space_write_1(iot, ioh, NEC86_FIFOINTRBLK,
+ (wm / NEC86_INTRBLK_UNIT) - 1);
+}
+
+void
+nec86hw_set_precision_real(struct nec86hw_softc *sc, u_int prec)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_CTRL);
+ data &= ~NEC86_CTRL_8BITS;
+ if (prec == 8)
+ data |= NEC86_CTRL_8BITS;
+ bus_space_write_1(iot, ioh, NEC86_CTRL, data);
+}
+
+void
+nec86hw_set_rate_real(struct nec86hw_softc *sc, u_int8_t bits)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t data;
+
+ data = bus_space_read_1(iot, ioh, NEC86_FIFOCTL);
+ data &= ~NEC86_FIFOCTL_MASK_RATE;
+ data |= bits & NEC86_FIFOCTL_MASK_RATE;
+ bus_space_write_1(iot, ioh, NEC86_FIFOCTL, data);
+}
+
+/*
+ * Write data to the FIFO ring buffer on the board.
+ */
+void
+nec86hw_output_chunk(struct nec86hw_softc *sc)
+{
+ int cc, nbyte;
+
+ if (sc->pdma_nchunk > 0) {
+ /* Update chunksize and then send the chunk to the board. */
+
+ /* chunksize in frames */
+ cc = sc->pdma_count / sc->pdma_nchunk;
+
+ nbyte = (*sc->func_fifo_output)(sc, cc);
+
+ DPRINTF2(3, ("nec86hw_output_chunk: sc->pdma_count=%d "
+ "sc->pdma_nchunk=%d cc=%d nbyte=%d ptr=%p\n",
+ sc->pdma_count, sc->pdma_nchunk, cc, nbyte, sc->pdma_ptr));
+
+ sc->pdma_nchunk--;
+ sc->pdma_count -= cc;
+ sc->pdma_ptr += nbyte;
+ } else {
+ /* ??? - This should never happen. */
+ nbyte = 0;
+ DPRINTF(("nec86hw_output_chunk: sc->pdma_nchunk=%d\n",
+ sc->pdma_nchunk));
+ }
+
+ /*
+ * If size of the sent chunk is not enough, then pad out the buffer
+ * with zero's.
+ */
+ if (nbyte <= sc->pdma_watermark) {
+ nec86fifo_padding(sc, sc->pdma_watermark);
+ sc->pdma_padded = 1;
+
+ DPRINTF(("nec86hw_output_chunk: write padding zero's\n"));
+ }
+}
+
+/*
+ * Routines to write data directly.
+ */
+int
+nec86fifo_output_mono_8_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_int8_t d;
+
+ for (i = 0; i < cc; i++) {
+ d = *p++;
+ d ^= 0x80; /* unsigned -> signed */
+ /* Fake monoral playing by duplicating a sample. */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+ }
+
+ return cc * 2;
+}
+
+int
+nec86fifo_output_mono_16_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+
+ for (i = 0; i < cc; i++) {
+ /* Fake monoral playing by duplicating a sample. */
+#if BYTE_ORDER == BIG_ENDIAN
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+#else /* little endian -> big endian */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+#endif
+ p += 2;
+ }
+
+ return cc * 4;
+}
+
+int
+nec86fifo_output_stereo_8_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+
+ for (i = 0; i < cc; i++) {
+ /* unsigned -> signed (L) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, (*p++) ^ 0x80);
+ /* unsigned -> signed (R) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, (*p++) ^ 0x80);
+ }
+
+ return cc * 2;
+}
+
+int
+nec86fifo_output_stereo_16_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+
+ for (i = 0; i < cc; i++) {
+#if BYTE_ORDER == BIG_ENDIAN
+ /* (L) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ p += 2;
+ /* (R) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ p += 2;
+#else
+ /* little endian -> big endian */
+ /* (L) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ p += 2;
+ /* (R) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *(p + 1));
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, *p);
+ p += 2;
+#endif
+ }
+
+ return cc * 4;
+}
+
+/*
+ * Routines to write data with resampling. (linear interpolation)
+ */
+int
+nec86fifo_output_mono_8_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register int rval;
+ register u_int8_t d;
+ register u_int8_t d0, d1;
+ register u_long acc, orate, hw_orate;
+
+ rval = 0;
+
+ orate = sc->sc_orate;
+ hw_orate = sc->hw_orate;
+ acc = sc->conv_acc;
+ d0 = (u_int8_t) sc->conv_last0;
+ d1 = (u_int8_t) sc->conv_last1;
+
+ for (i = 0; i < cc; i++) {
+ d0 = d1;
+ d1 = *p++;
+
+ while (acc <= hw_orate) {
+ /* Linear interpolation. */
+ d = ((d0 * (hw_orate - acc)) + (d1 * acc)) / hw_orate;
+ /* unsigned -> signed */
+ d ^= 0x80;
+
+ /* Fake monoral playing by duplicating a sample. */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+
+ acc += orate;
+ rval += 2;
+ }
+
+ acc -= hw_orate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0 = (u_short) d0;
+ sc->conv_last1 = (u_short) d1;
+
+ return rval;
+}
+
+int
+nec86fifo_output_mono_16_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register int rval;
+ register u_short d, d0, d1;
+ register u_long acc, orate, hw_orate;
+
+ rval = 0;
+
+ orate = sc->sc_orate;
+ hw_orate = sc->hw_orate;
+ acc = sc->conv_acc;
+ d0 = sc->conv_last0;
+ d1 = sc->conv_last1;
+
+ for (i = 0; i < cc; i++) {
+ d0 = d1;
+ /* little endian signed -> unsigned */
+ d1 = (*p | (*(p + 1) << 8)) ^ 0x8000;
+ p += 2;
+
+ while (acc <= hw_orate) {
+ /* Linear interpolation. */
+ d = ((d0 * (hw_orate - acc)) + (d1 * acc)) / hw_orate;
+ /* unsigned -> signed */
+ d ^= 0x8000;
+
+ /* Fake monoral playing by duplicating a sample. */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA,
+ (d >> 8) & 0xff); /* -> big endian */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA,
+ (d >> 8) & 0xff);
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
+
+ acc += orate;
+ rval += 4;
+ }
+
+ acc -= hw_orate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0 = d0;
+ sc->conv_last1 = d1;
+
+ return rval;
+}
+
+int
+nec86fifo_output_stereo_8_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register int rval;
+ register u_int8_t d, d0_l, d0_r, d1_l, d1_r;
+ register u_long acc, orate, hw_orate;
+
+ rval = 0;
+
+ orate = sc->sc_orate;
+ hw_orate = sc->hw_orate;
+ acc = sc->conv_acc;
+ d0_l = sc->conv_last0_l;
+ d0_r = sc->conv_last0_r;
+ d1_l = sc->conv_last1_l;
+ d1_r = sc->conv_last1_r;
+
+ for (i = 0; i < cc; i++) {
+ d0_l = d1_l;
+ d0_r = d1_r;
+ d1_l = *p++;
+ d1_r = *p++;
+
+ while (acc <= hw_orate) {
+ /* Linear interpolation. (L) */
+ d = ((d0_l * (hw_orate - acc)) + (d1_l * acc))
+ / hw_orate;
+ /* unsigned -> signed (L) */
+ d ^= 0x80;
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+
+ /* Linear interpolation. (R) */
+ d = ((d0_r * (hw_orate - acc)) + (d1_r * acc))
+ / hw_orate;
+ /* unsigned -> signed (R) */
+ d ^= 0x80;
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d);
+
+ acc += orate;
+ rval += 2;
+ }
+
+ acc -= hw_orate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0_l = d0_l;
+ sc->conv_last0_r = d0_r;
+ sc->conv_last1_l = d1_l;
+ sc->conv_last1_r = d1_r;
+
+ return rval;
+}
+
+int
+nec86fifo_output_stereo_16_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register int rval;
+ register u_short d, d0_l, d0_r, d1_l, d1_r;
+ register u_long acc, orate, hw_orate;
+
+ rval = 0;
+
+ orate = sc->sc_orate;
+ hw_orate = sc->hw_orate;
+ acc = sc->conv_acc;
+
+ d0_l = sc->conv_last0_l;
+ d0_r = sc->conv_last0_r;
+ d1_l = sc->conv_last1_l;
+ d1_r = sc->conv_last1_r;
+
+ for (i = 0; i < cc; i++) {
+ d0_l = d1_l;
+ d0_r = d1_r;
+ /* little endian signed -> unsigned (L) */
+ d1_l = (*p | (*(p + 1) << 8)) ^ 0x8000;
+ p += 2;
+ /* little endian signed -> unsigned (R) */
+ d1_r = (*p | (*(p + 1) << 8)) ^ 0x8000;
+ p += 2;
+
+ while (acc <= hw_orate) {
+ /* Linear interpolation. (L) */
+ d = ((d0_l * (hw_orate - acc)) + (d1_l * acc))
+ / hw_orate;
+ /* unsigned -> signed (L) */
+ d ^= 0x8000;
+
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA,
+ (d >> 8) & 0xff); /* -> big endian (L) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
+
+ /* Linear interpolation. (R) */
+ d = ((d0_r * (hw_orate - acc)) + (d1_r * acc))
+ / hw_orate;
+ /* unsigned -> signed (R) */
+ d ^= 0x8000;
+
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA,
+ (d >> 8) & 0xff); /* -> big endian (R) */
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, d & 0xff);
+
+ acc += orate;
+ rval += 4;
+ }
+
+ acc -= hw_orate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0_l = d0_l;
+ sc->conv_last0_r = d0_r;
+ sc->conv_last1_l = d1_l;
+ sc->conv_last1_r = d1_r;
+
+ return rval;
+}
+
+/*
+ * Read data from the FIFO ring buffer on the board.
+ */
+void
+nec86hw_input_chunk(struct nec86hw_softc *sc)
+{
+ int cc, bpf;
+
+ bpf = (sc->channels * sc->precision) / NBBY;
+ if (sc->pdma_nchunk > 0) {
+ /* Update chunksize and then receive the chunk from the board. */
+ /* chunksize in frames */
+ cc = sc->pdma_count / sc->pdma_nchunk;
+ (*sc->func_fifo_input)(sc, cc);
+
+ DPRINTF2(3, ("nec86hw_input_chunk: sc->pdma_count=%d "
+ "sc->pdma_nchunk=%d cc=%d ptr=%p\n",
+ sc->pdma_count, sc->pdma_nchunk, cc, sc->pdma_ptr));
+
+ sc->pdma_nchunk--;
+ sc->pdma_count -= cc;
+ sc->pdma_ptr += (cc * bpf);
+ } else {
+ /* ??? - This should never happen. */
+ cc = 0;
+ DPRINTF(("nec86hw_input_chunk: ??? sc->pdma_nchunk=%d ???",
+ sc->pdma_nchunk));
+ }
+}
+
+/*
+ * Routines to read data directly.
+ */
+void
+nec86fifo_input_mono_8_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_int8_t d_l, d_r;
+
+ for (i = 0; i < cc; i++) {
+ /* signed -> unsigned (L) */
+ d_l = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+ /* signed -> unsigned (R) */
+ d_r = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+
+ /* Fake monoral recording by taking arithmetical mean. */
+ *p++ = (d_l + d_r) / 2;
+ }
+}
+
+void
+nec86fifo_input_mono_16_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_short d, d_l, d_r;
+
+ for (i = 0; i < cc; i++) {
+ /* big endian signed -> unsigned (L) */
+ d_l = (bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80) << 8;
+ d_l |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ /* big endian signed -> unsigned (R) */
+ d_r = (bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80) << 8;
+ d_r |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+
+ /* Fake monoral recording by taking arithmetical mean. */
+ d = (d_l + d_r) / 2;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ /* -> big endian signed */
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+ *p++ = d & 0xff;
+#else
+ /* -> little endian signed */
+ *p++ = d & 0xff;
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+#endif
+ }
+}
+
+void
+nec86fifo_input_stereo_8_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+
+ for (i = 0; i < cc; i++) {
+ /* signed -> unsigned (L) */
+ *p++ = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+ /* signed -> unsigned (R) */
+ *p++ = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+ }
+}
+
+void
+nec86fifo_input_stereo_16_direct(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+
+ for (i = 0; i < cc; i++) {
+#if BYTE_ORDER == BIG_ENDIAN
+ *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (L) */
+ *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ p += 2;
+ *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (R) */
+ *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ p += 2;
+#else /* big endian -> little endian */
+ *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (L) */
+ *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ p += 2;
+ *(p + 1) = bus_space_read_1(iot, ioh, NEC86_FIFODATA);/* (R) */
+ *p = bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ p += 2;
+#endif
+ }
+}
+
+/*
+ * Routines to read data with resampling. (linear interpolation)
+ */
+void
+nec86fifo_input_mono_8_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_int8_t d_l, d_r;
+ register u_int8_t d0, d1;
+ register u_long acc, irate, hw_irate;
+
+ irate = sc->sc_irate;
+ hw_irate = sc->hw_irate;
+ acc = sc->conv_acc;
+ d0 = sc->conv_last0;
+ d1 = sc->conv_last1;
+
+ for (i = 0; i < cc; i++) {
+ while (acc > irate) {
+ d0 = d1;
+ /* signed -> unsigned (L) */
+ d_l = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+ /* signed -> unsigned (R) */
+ d_r = bus_space_read_1(iot, ioh, NEC86_FIFODATA) ^ 0x80;
+ /* Fake monoral recording by taking arithmetical mean. */
+ d1 = (d_l + d_r) / 2;
+
+ acc -= irate;
+ }
+
+ /* Linear interpolation. */
+ *p++ = ((d0 * (irate - acc)) + (d1 * acc)) / irate;
+
+ acc += hw_irate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0 = d0;
+ sc->conv_last1 = d1;
+}
+
+void
+nec86fifo_input_mono_16_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_short d, d_l, d_r;
+ register u_short d0, d1;
+ register u_long acc, irate, hw_irate;
+
+ irate = sc->sc_irate;
+ hw_irate = sc->hw_irate;
+ acc = sc->conv_acc;
+ d0 = sc->conv_last0;
+ d1 = sc->conv_last1;
+
+ for (i = 0; i < cc; i++) {
+ while (acc > irate) {
+ d0 = d1;
+ /* big endian signed -> unsigned (L) */
+ d_l = (bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80) << 8;
+ d_l |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ /* big endian signed -> unsigned (R) */
+ d_r = (bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80) << 8;
+ d_r |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ /* Fake monoral recording by taking arithmetical mean. */
+ d1 = (d_l + d_r) / 2;
+
+ acc -= irate;
+ }
+
+ /* Linear interpolation. */
+ d = ((d0 * (irate - acc)) + (d1 * acc)) / irate;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ /* -> big endian signed */
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+ *p++ = d & 0xff;
+#else
+ /* -> little endian signed */
+ *p++ = d & 0xff;
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+#endif
+
+ acc += hw_irate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0 = d0;
+ sc->conv_last1 = d1;
+}
+
+void
+nec86fifo_input_stereo_8_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_int8_t d0_l, d0_r, d1_l, d1_r;
+ register u_long acc, irate, hw_irate;
+
+ irate = sc->sc_irate;
+ hw_irate = sc->hw_irate;
+ acc = sc->conv_acc;
+ d0_l = sc->conv_last0_l;
+ d0_r = sc->conv_last0_r;
+ d1_l = sc->conv_last1_l;
+ d1_r = sc->conv_last1_r;
+
+ for (i = 0; i < cc; i++) {
+ while (acc > irate) {
+ d0_l = d1_l;
+ d0_r = d1_r;
+ /* signed -> unsigned (L) */
+ d1_l = bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80;
+ /* signed -> unsigned (R) */
+ d1_r = bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80;
+
+ acc -= irate;
+ }
+
+ /* Linear interpolation. (L) */
+ *p++ = ((d0_l * (irate - acc)) + (d1_l * acc)) / irate;
+
+ /* Linear interpolation. (R) */
+ *p++ = ((d0_r * (irate - acc)) + (d1_r * acc)) / irate;
+
+ acc += hw_irate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0_l = d0_l;
+ sc->conv_last0_r = d0_r;
+ sc->conv_last1_l = d1_l;
+ sc->conv_last1_r = d1_r;
+}
+
+void
+nec86fifo_input_stereo_16_resamp(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int8_t *p = sc->pdma_ptr;
+ int i;
+ register u_short d, d0_l, d0_r, d1_l, d1_r;
+ register u_long acc, irate, hw_irate;
+
+ irate = sc->sc_irate;
+ hw_irate = sc->hw_irate;
+ acc = sc->conv_acc;
+ d0_l = sc->conv_last0_l;
+ d0_r = sc->conv_last0_r;
+ d1_l = sc->conv_last1_l;
+ d1_r = sc->conv_last1_r;
+
+ for (i = 0; i < cc; i++) {
+ while (acc > irate) {
+ d0_l = d1_l;
+ d0_r = d1_r;
+ /* big endian signed -> unsigned (L) */
+ d1_l = (bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80) << 8;
+ d1_l |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+ /* big endian signed -> unsigned (R) */
+ d1_r = (bus_space_read_1(iot, ioh, NEC86_FIFODATA)
+ ^ 0x80) << 8;
+ d1_r |= bus_space_read_1(iot, ioh, NEC86_FIFODATA);
+
+ acc -= irate;
+ }
+
+ /* Linear interpolation. (L) */
+ d = ((d0_l * (irate - acc)) + (d1_l * acc)) / irate;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ /* -> big endian signed (L) */
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+ *p++ = d & 0xff;
+#else
+ /* -> little endian signed (L) */
+ *p++ = d & 0xff;
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+#endif
+
+ /* Linear interpolation. (R) */
+ d = ((d0_r * (irate - acc)) + (d1_r * acc)) / irate;
+
+#if BYTE_ORDER == BIG_ENDIAN
+ /* -> big endian signed (R) */
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+ *p++ = d & 0xff;
+#else
+ /* -> little endian signed (R) */
+ *p++ = d & 0xff;
+ *p++ = ((d >> 8) & 0xff) ^ 0x80;
+#endif
+
+ acc += hw_irate;
+ }
+
+ sc->conv_acc = acc;
+ sc->conv_last0_l = d0_l;
+ sc->conv_last0_r = d0_r;
+ sc->conv_last1_l = d1_l;
+ sc->conv_last1_r = d1_r;
+}
+
+/*
+ * Write padding zero's to the FIFO ring buffer on the board.
+ */
+void
+nec86fifo_padding(struct nec86hw_softc *sc, int cc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ register int i;
+
+ DPRINTF2(2, ("nec86fifo_padding: %d\n", cc));
+
+ for (i = 0; i < cc; i++)
+ bus_space_write_1(iot, ioh, NEC86_FIFODATA, 0);
+}
+
+/*
+ * Interrupt handler.
+ */
+int
+nec86hw_intr(void *arg)
+{
+ struct nec86hw_softc *sc = (struct nec86hw_softc *) arg;
+
+ if (!nec86hw_seeif_intrflg(sc)) {
+ /* Seems to be an FM sound interrupt. */
+ DPRINTF(("nec86hw_intr: ??? FM sound interrupt ???\n"));
+ return 0;
+ }
+
+ mtx_enter(&audio_lock);
+ nec86hw_clear_intrflg(sc);
+
+ switch(sc->pdma_mode) {
+ case PDMA_MODE_OUTPUT:
+ if (sc->pdma_padded) {
+ /* Clear the padding zero's. */
+ nec86hw_reset_fifo(sc);
+ sc->pdma_padded = 0;
+ DPRINTF(("nec86hw_intr: clear padding zero's\n"));
+ }
+ if (sc->pdma_count > 0) {
+ /* Send the next chunk. */
+ nec86hw_disable_fifointr(sc);
+ nec86hw_output_chunk(sc);
+ nec86hw_enable_fifointr(sc);
+ } else
+ (*sc->sc_intr)(sc->sc_arg);
+ break;
+ case PDMA_MODE_INPUT:
+ if (sc->pdma_count > 0) {
+ /* Receive the next chunk. */
+ nec86hw_disable_fifointr(sc);
+ nec86hw_input_chunk(sc);
+ nec86hw_enable_fifointr(sc);
+ }
+ if (sc->pdma_count <= 0)
+ (*sc->sc_intr)(sc->sc_arg);
+ break;
+ default:
+ /* This should never happen. */
+ nec86hw_stop_fifo(sc);
+ nec86hw_disable_fifointr(sc);
+ sc->intr_busy = 0;
+
+ DPRINTF(("nec86hw_intr: ??? unexpected interrupt ???\n"));
+
+ mtx_leave(&audio_lock);
+ return 0;
+ }
+
+ mtx_leave(&audio_lock);
+ return 1;
+}
+
+int
+nec86_get_props(void *addr)
+{
+ return 0;
+}
Index: nec86hwvar.h
===================================================================
RCS file: nec86hwvar.h
diff -N nec86hwvar.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ nec86hwvar.h 26 Dec 2014 15:08:44 -0000
@@ -0,0 +1,221 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86hwvar.h,v 1.10 1998/03/14 07:04:55 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * nec86hwvar.h
+ *
+ * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
+ * Written by NAGAO Tadaaki, Feb 10, 1996.
+ */
+
+#ifndef _NEC86HWVAR_H_
+#define _NEC86HWVAR_H_
+
+/* types of function which writes to/reads from FIFO buffer */
+struct nec86hw_softc; /* dummy declaration */
+typedef int (*func_fifo_output_t) (struct nec86hw_softc *, int);
+typedef void (*func_fifo_input_t) (struct nec86hw_softc *, int);
+
+
+struct nec86hw_softc {
+ struct device sc_dev; /* base device */
+
+ bus_space_tag_t sc_iot; /* bus space tag */
+ bus_space_handle_t sc_ioh; /* nec86 core chip space handle */
+
+ u_int sc_cfgflags; /* config flags */
+#define NEC86HW_RATE_TYPE(flags) ((flags) & 1)
+#define NEC86HW_NRATE_TYPE 2
+
+ u_short sc_open; /* reference count of open calls */
+
+ u_long sc_irate; /* sample rate for input */
+ u_long sc_orate; /* sample rate for output */
+
+ u_long hw_irate; /* hardware rate for input */
+ u_char hw_irate_bits;
+ u_long hw_orate; /* hardware rate for output */
+ u_char hw_orate_bits;
+
+ u_int encoding; /* ulaw / linear */
+ u_int precision; /* 8/16 bits */
+ int channels; /* monoral(1) / stereo(2) */
+
+ int in_port; /* Just keep track of it */
+#define NEC86HW_INPUT_MIXER 0
+ int out_port; /* Just keep track of it */
+#define NEC86HW_OUTPUT_MIXER 0
+
+ int model; /* board identification number */
+
+ /* linear interpolation */
+ u_long conv_acc;
+ u_short conv_last0;
+ u_short conv_last0_l;
+ u_short conv_last0_r;
+ u_short conv_last1;
+ u_short conv_last1_l;
+ u_short conv_last1_r;
+
+ void (*sc_intr)(void *); /* DMA completion intr handler */
+ void *sc_arg; /* arg for sc_intr() */
+
+ char intr_busy; /* whether the hardware running */
+
+ /* pseudo-DMA */
+ u_char *pdma_ptr; /* pointer to the data buffer */
+ int pdma_count; /* size of the data in frames */
+ int pdma_nchunk; /* number of chunks to do with */
+ int pdma_watermark; /* interrupt trigger level */
+ char pdma_padded; /* the buffer is padded out with
+ dummy zero's */
+ char pdma_mode; /* input/output indicator */
+#define PDMA_MODE_NONE 0
+#define PDMA_MODE_OUTPUT 1
+#define PDMA_MODE_INPUT 2
+
+ /* function which writes to/reads from FIFO buffer */
+ func_fifo_output_t func_fifo_output;
+ func_fifo_input_t func_fifo_input;
+};
+
+struct nec86hw_functable_entry {
+ int precision;
+ int channels;
+
+ func_fifo_output_t func_fifo_output_direct;
+ func_fifo_input_t func_fifo_input_direct;
+ func_fifo_output_t func_fifo_output_resamp;
+ func_fifo_input_t func_fifo_input_resamp;
+};
+
+/*
+ * Interrupt watermarks for the FIFO ring buffer on the hardware.
+ *
+ * These values must satisfy:
+ * 0 < WATERMARK_RATIO_OUT <= WATERMARK_MAX_RATIO
+ * 0 < WATERMARK_RATIO_IN <= WATERMARK_MAX_RATIO.
+ * (For more details, see also nec86hw_pdma_output() and nec86hw_pdma_input()
+ * in nec86hw.c)
+ */
+#define WATERMARK_MAX_RATIO 100
+#define WATERMARK_RATIO_OUT 50 /* 50% of the blocksize */
+#define WATERMARK_RATIO_IN 50 /* 50% of NEC86_BUFFSIZE */
+
+/*
+ * Declarations of prototypes.
+ */
+#ifdef _KERNEL
+void nec86hw_attach(struct nec86hw_softc *);
+
+int nec86hw_open(void *, int);
+void nec86hw_close(void *);
+
+int nec86hw_set_params(void *, int, int, struct audio_params *,
+ struct audio_params *);
+int nec86hw_query_encoding(void *, struct audio_encoding *);
+
+int nec86hw_round_blocksize(void *, int);
+
+int nec86hw_set_out_port(void *, int);
+int nec86hw_get_out_port(void *);
+int nec86hw_set_in_port(void *, int);
+int nec86hw_get_in_port(void *);
+
+int nec86hw_commit_settings(void *);
+
+int nec86hw_setfd(void *, int);
+
+int nec86hw_mixer_set_port(void *, mixer_ctrl_t *);
+int nec86hw_mixer_get_port(void *, mixer_ctrl_t *);
+int nec86hw_mixer_query_devinfo(void *, mixer_devinfo_t *);
+
+int nec86hw_pdma_init_output(void *, void *, int);
+int nec86hw_pdma_init_input(void *, void *, int);
+int nec86hw_pdma_output(void *, void *, int, void (*)(void *), void *);
+int nec86hw_pdma_input(void *, void *, int, void (*)(void *), void *);
+
+int nec86hw_speaker_ctl(void *, int);
+
+int nec86hw_halt_pdma(void *);
+int nec86hw_cont_pdma(void *);
+
+u_char nec86hw_rate_bits(struct nec86hw_softc *, u_long);
+int nec86hw_round_watermark(int);
+
+int nec86hw_reset(struct nec86hw_softc *);
+void nec86hw_set_mode_playing(struct nec86hw_softc *);
+void nec86hw_set_mode_recording(struct nec86hw_softc *);
+
+void nec86hw_set_volume(struct nec86hw_softc *, int, u_char);
+
+void nec86hw_start_fifo(struct nec86hw_softc *);
+void nec86hw_stop_fifo(struct nec86hw_softc *);
+void nec86hw_enable_fifointr(struct nec86hw_softc *);
+void nec86hw_disable_fifointr(struct nec86hw_softc *);
+int nec86hw_seeif_intrflg(struct nec86hw_softc *);
+void nec86hw_clear_intrflg(struct nec86hw_softc *);
+void nec86hw_reset_fifo(struct nec86hw_softc *);
+void nec86hw_set_watermark(struct nec86hw_softc *, int);
+void nec86hw_set_precision_real(struct nec86hw_softc *, u_int);
+void nec86hw_set_rate_real(struct nec86hw_softc *, u_char);
+
+void nec86hw_output_chunk(struct nec86hw_softc *);
+void nec86hw_input_chunk(struct nec86hw_softc *);
+
+int nec86fifo_output_mono_8_direct(struct nec86hw_softc *, int);
+int nec86fifo_output_mono_16_direct(struct nec86hw_softc *, int);
+int nec86fifo_output_stereo_8_direct(struct nec86hw_softc *, int);
+int nec86fifo_output_stereo_16_direct(struct nec86hw_softc *, int);
+int nec86fifo_output_mono_8_resamp(struct nec86hw_softc *, int);
+int nec86fifo_output_mono_16_resamp(struct nec86hw_softc *, int);
+int nec86fifo_output_stereo_8_resamp(struct nec86hw_softc *, int);
+int nec86fifo_output_stereo_16_resamp(struct nec86hw_softc *, int);
+void nec86fifo_input_mono_8_direct(struct nec86hw_softc *, int);
+void nec86fifo_input_mono_16_direct(struct nec86hw_softc *, int);
+void nec86fifo_input_stereo_8_direct(struct nec86hw_softc *, int);
+void nec86fifo_input_stereo_16_direct(struct nec86hw_softc *, int);
+void nec86fifo_input_mono_8_resamp(struct nec86hw_softc *, int);
+void nec86fifo_input_mono_16_resamp(struct nec86hw_softc *, int);
+void nec86fifo_input_stereo_8_resamp(struct nec86hw_softc *, int);
+void nec86fifo_input_stereo_16_resamp(struct nec86hw_softc *, int);
+
+void nec86fifo_padding(struct nec86hw_softc *, int);
+
+int nec86hw_intr(void *);
+
+int nec86getdev(void *, struct audio_device *);
+int nec86_get_props(void *);
+
+#endif /* _KERNEL */
+#endif /* !_NEC86HWVAR_H_ */
Index: nec86reg.h
===================================================================
RCS file: nec86reg.h
diff -N nec86reg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ nec86reg.h 26 Dec 2014 15:08:44 -0000
@@ -0,0 +1,139 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86reg.h,v 1.5 1998/03/14 07:04:56 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * nec86reg.h
+ *
+ * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
+ * Written by NAGAO Tadaaki, Feb 10, 1996.
+ */
+
+#ifndef _NEC86REG_H_
+#define _NEC86REG_H_
+
+#define NEC86_PORT 16
+
+/*
+ * Offsets from PCM I/O base address
+ */
+#define NEC86_SOUND_ID 0
+
+#define NEC86_COREOFFSET 6 /* core chip base */
+#define NEC86_CORESIZE 7
+#define NEC86_FIFOSTAT 0 /* readonly */
+#define NEC86_VOLUME 0 /* writeonly */
+#define NEC86_FIFOCTL 2
+#define NEC86_CTRL 4 /* when FIFO not running */
+#define NEC86_FIFOINTRBLK 4 /* when FIFO running, writeonly */
+#define NEC86_FIFODATA 6
+
+/*
+ * FIFO status bits
+ */
+#define NEC86_FIFOSTAT_FULL 0x80
+#define NEC86_FIFOSTAT_EMPTY 0x40
+#define NEC86_FIFOSTAT_OVERFLOW 0x20
+#define NEC86_FIFOSTAT_LRCLK 0x01
+
+/*
+ * FIFO control bits
+ */
+#define NEC86_FIFOCTL_RUN 0x80
+#define NEC86_FIFOCTL_RECMODE 0x40
+#define NEC86_FIFOCTL_ENBLINTR 0x20
+#define NEC86_FIFOCTL_INTRFLG 0x10
+#define NEC86_FIFOCTL_INIT 0x08
+
+#define NEC86_FIFOCTL_MASK_RATE 0x07
+#define NEC86_NRATE 8
+
+/*
+ * Card control bits
+ */
+#define NEC86_CTRL_8BITS 0x40
+#define NEC86_CTRL_PAN_L 0x20
+#define NEC86_CTRL_PAN_R 0x10
+
+#define NEC86_CTRL_MASK_PAN 0x30
+#define NEC86_CTRL_MASK_PORT 0x0f
+
+#define NEC86_CTRL_PORT_STD 0x02 /* PC-9801-86 supports only this */
+
+/*
+ * Volume
+ */
+#define NEC86_VOLUME_MASK_PORT 0xe0
+#define NEC86_VOLUME_MASK_VOL 0x0f
+
+#define NEC86_VOLUME_PORT_OPNAD 0 /* OPNA -> LINEOUT */
+#define NEC86_VOLUME_PORT_OPNAI 1 /* OPNA -> ADC */
+#define NEC86_VOLUME_PORT_LINED 2 /* LINEIN (& CDDA) -> LINEOUT */
+#define NEC86_VOLUME_PORT_LINEI 3 /* LINEIN (& CDDA) -> ADC */
+#define NEC86_VOLUME_PORT_CDDAD 4 /* CDDA -> LINEOUT (PC-98GS only) */
+#define NEC86_VOLUME_PORT_PCMD 5 /* DAC -> LINEOUT */
+
+#define NEC86_MINVOL 0
+#define NEC86_MAXVOL 15
+
+#define NEC86_VOL_TO_BITS(p, v) (((p) << 5) | ((v) ^ 0xf))
+
+/*
+ * Unit size of the interrupt watermark (NEC86_FIFOINTRBLK).
+ */
+#define NEC86_INTRBLK_UNIT 128 /* 128 bytes */
+
+/*
+ * Size of the FIFO ring buffer on the board.
+ *
+ * XXX - We define this value a little less than the actual size to work
+ * around the bug at 'buffer full' in Q-Vision's cards.
+ * ... Too paranoid?
+ */
+#define NEC86_BUFFSIZE (32768 - 2 * 2) /* 2(stereo) * 2(16bits sampling) */
+
+/*
+ * I/O base addresses for YAMAHA FM sound chip OPNA (YM2608/YMF288)
+ */
+#define OPNA_IOBASE0 0x088
+#define OPNA_IOBASE1 0x188
+#define OPNA_IOBASE2 0x288
+#define OPNA_IOBASE3 0x388
+
+/*
+ * Macros to detect valid hardware configuration data
+ */
+#define NEC86_IRQ_VALID(irq) (((irq) == 3) || ((irq) == 10) || \
+ ((irq) == 12) || ((irq) == 13))
+#define NEC86_BASE_VALID(base) (((base) == 0xa460) || ((base) == 0xa470) || \
+ ((base) == 0xa480) || ((base) == 0xa490))
+#endif /* !_NEC86REG_H_ */
Index: nec86var.h
===================================================================
RCS file: nec86var.h
diff -N nec86var.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ nec86var.h 26 Dec 2014 15:08:45 -0000
@@ -0,0 +1,65 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86var.h,v 1.6 1998/03/14 07:04:57 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+/*
+ * nec86var.h
+ *
+ * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
+ * Written by NAGAO Tadaaki, Feb 10, 1996.
+ */
+
+#ifndef _NEC86VAR_H_
+#define _NEC86VAR_H_
+
+struct nec86_softc {
+ struct nec86hw_softc sc_nec86hw;
+
+ bus_space_tag_t sc_n86iot;
+ bus_space_handle_t sc_n86ioh;
+
+ bus_space_tag_t sc_ym2608iot;
+ bus_space_handle_t sc_ym2608ioh;
+
+ int sc_attached;
+ int sc_intlevel;
+#if 0
+ int sc_opna_index_off; /* offset of OPNA index */
+ int sc_opna_data_off; /* offset of OPNA data */
+#endif
+};
+
+extern struct audio_hw_if nec86_hw_if;
+int nec86_probesubr(bus_space_tag_t, bus_space_handle_t,
+ bus_space_handle_t);
+void nec86_attachsubr(struct nec86_softc *);
+#endif /* !_NEC86VAR_H_ */
Index: necsb.c
===================================================================
RCS file: necsb.c
diff -N necsb.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ necsb.c 26 Dec 2014 15:08:45 -0000
@@ -0,0 +1,117 @@
+/* $OpenBSD$ */
+/* $NecBSD: nec86_isa.c,v 1.9 1998/09/26 11:31:11 kmatsuda Exp $ */
+/* $NetBSD$ */
+
+/*
+ * [NetBSD for NEC PC-98 series]
+ * Copyright (c) 1995, 1996, 1997, 1998
+ * NetBSD/pc98 porting staff. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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/device.h>
+
+#include <machine/board.h> /* PC_BASE */
+#include <machine/bus.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+
+#include <luna88k/cbus/nec86reg.h>
+#include <luna88k/cbus/nec86hwvar.h>
+#include <luna88k/cbus/nec86var.h>
+
+#include <luna88k/cbus/cbusvar.h> /* cbus_isrlink() */
+
+#define PCEXIO_BASE (PC_BASE + 0x1000000)
+#define NECSB_BASE (PCEXIO_BASE + 0xa460)
+
+int necsb_match(struct device *, void *, void *);
+void necsb_attach(struct device *, struct device *, void *);
+
+struct cfattach necsb_ca = {
+ sizeof(struct nec86_softc), necsb_match, necsb_attach
+};
+
+struct cfdriver necsb_cd = {
+ NULL, "necsb", DV_DULL
+};
+
+/* bus space tag for necsb */
+struct luna88k_bus_space_tag necsb_bst = {
+ 1, /* when reading/writing 1 byte, the stride is 1. */
+ 0,
+ 0,
+ 0,
+};
+
+int
+necsb_match(struct device *parent, void *cf, void *aux)
+{
+ struct cbus_attach_args *caa = aux;
+
+ if (strcmp(caa->ca_name, necsb_cd.cd_name))
+ return 0;
+
+ return 1;
+}
+
+void
+necsb_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct nec86_softc *nsc = (struct nec86_softc *)self;
+ struct nec86hw_softc *ysc = &nsc->sc_nec86hw;
+ struct cbus_attach_args *caa = aux;
+
+ bus_space_tag_t iot = &necsb_bst;
+ bus_space_handle_t coreh, n86h, ym2608h;
+
+ n86h = (bus_space_handle_t)(NECSB_BASE + NEC86_SOUND_ID);
+ coreh = (bus_space_handle_t)(NECSB_BASE + NEC86_COREOFFSET);
+ ym2608h = (bus_space_handle_t)(PCEXIO_BASE); /* should be adjust */
+
+ nsc->sc_n86iot = iot;
+ nsc->sc_n86ioh = n86h;
+ nsc->sc_ym2608iot = iot;
+ nsc->sc_ym2608ioh = ym2608h;
+ ysc->sc_iot = iot;
+ ysc->sc_ioh = coreh;
+ ysc->sc_cfgflags = 0; /* original 'PC-9801-86' */
+
+ nec86_attachsubr(nsc);
+
+ if (nsc->sc_intlevel == -1)
+ return;
+
+ caa->ca_intlevel = nsc->sc_intlevel;
+
+ if ((caa->ca_intlevel < 0) || (caa->ca_intlevel >= NCBUSISR))
+ panic("necsb_attach: bad INT level");
+
+ /* XXX: check return value ? */
+ cbus_isrlink(nec86hw_intr, ysc, caa->ca_intlevel, self->dv_xname);
+}
Index: pcex.c
===================================================================
RCS file: /cvs/src/sys/arch/luna88k/cbus/pcex.c,v
retrieving revision 1.1
diff -u -r1.1 pcex.c
--- pcex.c 19 Dec 2014 13:17:35 -0000 1.1
+++ pcex.c 26 Dec 2014 15:08:45 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcex.c,v 1.1 2014/12/19 13:17:35 aoyama Exp $ */
+/* $OpenBSD: pcex.c,v 1.4 2014/12/08 13:24:04 aoyama Exp $ */
/*
* Copyright (c) 2014 Kenji Aoyama.
@@ -67,7 +67,12 @@
int
pcex_match(struct device *parent, void *cf, void *aux)
{
- return 1; /* XXX: always matched */
+ struct cbus_attach_args *caa = aux;
+
+ if (strcmp(caa->ca_name, pcex_cd.cd_name))
+ return 0;
+
+ return 1;
}
void
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment