code:
#	$OpenBSD: Makefile,v 1.6 2014/07/13 09:26:08 jasper Exp $

.include "${.CURDIR}/../Makefile.inc"

LIB=	sa

.PATH:	${.CURDIR}/../../../../lib/libsa

CLEANFILES += machine mips64

CFLAGS+= ${CEXTRAFLAGS} ${SAABI} -nostdinc -mno-abicalls -D_NO_ABICALLS \
	-fno-pie \
	-I${.CURDIR} -I${.CURDIR}/../include -I${.CURDIR}/../.. \
	-I${.CURDIR}/../../.. -I${.CURDIR}/../../../.. \
	-I${.CURDIR}/../../../../lib/libsa \
	-I${.OBJDIR}

# stand routines
SRCS=	alloc.c cons.c ctime.c exit.c getchar.c getfile.c gets.c globals.c \
	memcmp.c memcpy.c memset.c printf.c putchar.c \
	snprintf.c strchr.c strcmp.c strerror.c strncmp.c strncpy.c strtol.c

# io routines
SRCS+=	close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c \
	lseek.c open.c read.c readdir.c stat.c write.c
#SRCS+=	nullfs.c

#SRCS+=	cread.c
#CPPFLAGS+= -D__INTERNAL_LIBSA_CREAD

# boot filesystems
SRCS+=	ufs.c cd9660.c

CFLAGS+=-DNO_NET

SRCS+=	loadfile.c

${OBJS}:	${.CURDIR}/../Makefile.inc

NOPROFILE=
NOPIC=

.if !make(obj)
.BEGIN:
	@([ -h machine ] || ln -s ${.CURDIR}/../../include machine)
	@([ -h mips64 ] || ln -s ${.CURDIR}/../../../mips64/include mips64)
CLEANFILES+=	machine mips64
.endif

install:

.include <bsd.lib.mk>

path: sys/arch/loongson/stand/libsa/Makefile


path: sys/arch/loongson/stand/mbr/CVS/Entries

license: unknown


path: sys/arch/loongson/stand/mbr/CVS/Tag


code:
#	$OpenBSD: Makefile,v 1.2 2010/02/19 01:43:49 deraadt Exp $

.if ${MACHINE} == "loongson"

.include	"${.CURDIR}/../Makefile.inc"
CLEANFILES= mbr

all: mbr

mbr: mbr.uu
	uudecode ${.CURDIR}/mbr.uu

realinstall:
	${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 mbr \
		${DESTDIR}/usr/mdec

.endif

.include <bsd.prog.mk>

path: sys/arch/loongson/stand/mbr/Makefile


code:
/Makefile/1.11/Thu Jan 30 14:30:46 2014//TOPENBSD_5_8_BASE
D/cbus////
D/compile////
D/conf////
D/dev////
D/include////
D/luna88k////
D/stand////


code:
#	$OpenBSD: Makefile,v 1.11 2014/01/30 14:30:46 aoyama Exp $

S=	${.CURDIR}/../..
KFILE=	GENERIC
.if exists(conf/GENERIC.MP)
KFILE=	GENERIC.MP
.endif
TDIRS=	${_arch} include
TAGS=	${.CURDIR}/tags

NOPROG=
NOMAN=
NOOBJ=
SUBDIR=	stand

# config the fattest kernel we can find into a temporary dir
# to create a Makefile.  Then use make to pull some variables
# out and push them into the sub-shell to expand the paths,
# and finally run ctags.
tags::
	TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \
	eval "S=${S}" && \
	config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \
	eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \
	eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \
	eval "_machdir=\$S/arch/$${_mach}" && \
	eval "_archdir=\$S/arch/$${_arch}" && \
	eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \
	eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \
	eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \
	eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \
	ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \
	egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \
	    sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3	\\1	/^\\2(\\3\\4$$/;" \
	    >> ${TAGS} && \
	sort -o ${TAGS} ${TAGS} && \
	rm -rf $${TDIR}

links:
	-for i in conf ${TDIRS}; do \
	    (cd $$i && rm -f tags; ln -s tags tags); done

obj:	_SUBDIRUSE

.include <bsd.prog.mk>


code:
/*	$OpenBSD: cbus.c,v 1.5 2015/03/03 23:50:36 aoyama Exp $	*/

/*
 * Copyright (c) 2014 Kenji Aoyama.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * PC-9801 extension board slot bus ('C-bus') driver for LUNA-88K2.
 */

#include <sys/param.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>

#include <machine/asm_macro.h>	/* ff1() */
#include <machine/autoconf.h>
#include <machine/board.h>	/* PC_BASE */

#include <luna88k/cbus/cbusvar.h>
#include <luna88k/luna88k/isr.h>	/* isrlink_autovec() */

#if 0
#define CBUS_DEBUG
#endif

#include "necsb.h"
#include "pcic.h"

static struct cbus_attach_args cbus_devs[] = {
#if NNECSB > 0
	{ "necsb",	-1 },	/* PC-9801-86 sound board */
#endif
#if NPCIC > 0
	{ "pcic",	-1 },	/* PC-9801-102 & PC-9821X[AE]-01 PCMCIA board */
#endif
	{ "pcex",	-1 }	/* C-bus "generic" driver */
};

/*
 * C-bus interrupt status register
 */
#define CBUS_INTR_STAT_REG	(PC_BASE + 0x1100000)
volatile u_int8_t *cbus_isreg = (u_int8_t *)CBUS_INTR_STAT_REG;

/* autoconf stuff */
int cbus_match(struct device *, void *, void *);
void cbus_attach(struct device *, struct device *, void *);
int cbus_print(void *, const char *);

struct cbus_softc {
	struct device sc_dev;
	struct cbus_isr_t cbus_isr[NCBUSISR];
	u_int8_t registered;
};

const struct cfattach cbus_ca = {
	sizeof(struct cbus_softc), cbus_match, cbus_attach
};

struct cfdriver cbus_cd = {
	NULL, "cbus", DV_DULL
};

/* prototypes */
void cbus_isrdispatch(int);
int cbus_intr(void *);

int
cbus_match(struct device *parent, void *cf, void *aux)
{
	struct mainbus_attach_args *ma = aux;

	if (strcmp(ma->ma_name, cbus_cd.cd_name))
		return 0;
#if 0
	if (badaddr((vaddr_t)ma->ma_addr, 4))
		return 0;
#endif
	return 1;
}

void
cbus_attach(struct device *parent, struct device *self, void *args)
{
	struct cbus_softc *sc = (struct cbus_softc *)self;
	struct mainbus_attach_args *ma = args;
	int i;

	for (i = 0; i < NCBUSISR; i++) {
		struct cbus_isr_t *ci = &sc->cbus_isr[i];
		ci->isr_func = NULL;
		ci->isr_arg = NULL;
		ci->isr_intlevel = ci->isr_ipl = -1;
		/* clearing interrupt flags (INT0-INT6) */
		*cbus_isreg = (u_int8_t)(6 - i);
	}
	sc->registered = 0x00;

	/* register C-bus interrupt service routine on mainbus */
	isrlink_autovec(cbus_intr, (void *)self, ma->ma_ilvl,
	    ISRPRI_TTY, self->dv_xname);

	printf("\n");

	for (i = 0; i < sizeof(cbus_devs)/sizeof(cbus_devs[0]); i++)
		config_found(self, &cbus_devs[i], cbus_print);

	return;
}

int
cbus_print(void *aux, const char *pnp)
{
	struct cbus_attach_args *caa = aux;

	if (pnp)
		printf("%s at %s", caa->ca_name, pnp);	/* not configured */
	if (caa->ca_intlevel != -1)
		printf(" int %d", caa->ca_intlevel);

	return UNCONF;
}

/*
 * Register a C-bus interrupt service routine.
 */
int
cbus_isrlink(int (*func)(void *), void *arg, int intlevel, int ipl,
    const char *name)
{
	struct cbus_softc *sc = NULL;
	struct cbus_isr_t *ci;

	if (cbus_cd.cd_ndevs != 0)
		sc = cbus_cd.cd_devs[0];
	if (sc == NULL)
		panic("cbus_isrlink: can't find cbus_softc");

#ifdef DIAGNOSTIC
	if (intlevel < 0 || intlevel >= NCBUSISR) {
		printf("cbus_isrlink: bad INT level %d\n", intlevel);
		return -1;
	}
#endif

	ci = &sc->cbus_isr[intlevel];

	if (ci->isr_func != NULL) {
		printf("cbus_isrlink: isr already assigned on INT%d\n",
		    intlevel);
		return -1;
	}

	/* set the entry */
	ci->isr_func = func;
	ci->isr_arg = arg;
	ci->isr_intlevel = intlevel;
	ci->isr_ipl = ipl;
	evcount_attach(&ci->isr_count, name, &ci->isr_intlevel);
	sc->registered |= (1 << (6 - intlevel));
#ifdef CBUS_DEBUG
	printf("cbus_isrlink: sc->registered = 0x%02x\n", sc->registered);
#endif

	return 0;
}

/*
 * Unregister a C-bus interrupt service routine.
 */
int
cbus_isrunlink(int (*func)(void *), int intlevel)
{
	struct cbus_softc *sc = NULL;
	struct cbus_isr_t *ci;

	if (cbus_cd.cd_ndevs != 0)
		sc = cbus_cd.cd_devs[0];
	if (sc == NULL)
		panic("cbus_isrunlink: can't find cbus_softc");

#ifdef DIAGNOSTIC
	if (intlevel < 0 || intlevel >= NCBUSISR) {
		printf("cbus_isrunlink: bad INT level %d\n", intlevel);
		return -1;
	}
#endif

	ci = &sc->cbus_isr[intlevel];

	if (ci->isr_func == NULL) {
		printf("cbus_isrunlink: isr not assigned on INT%d\n", intlevel);
		return -1;
	}

	/* reset the entry */
	ci->isr_func = NULL;
	ci->isr_arg = NULL;
	ci->isr_intlevel = ci->isr_ipl = -1;
	evcount_detach(&ci->isr_count);
	sc->registered &= ~(1 << (6 - intlevel));

	/* clear interrupt flags */
	*cbus_isreg = (u_int8_t)(6 - intlevel);
#ifdef CBUS_DEBUG
	printf("cbus_isrunlink: sc->registered = 0x%02x\n", sc->registered);
#endif

	return 0;
}

/*
 * Dispatch C-bus interrupt service routines.
 */
void
cbus_isrdispatch(int intlevel)
{
	int rc, s;
	static int straycount, unexpected;
	struct cbus_softc *sc = NULL;
	struct cbus_isr_t *ci;

	if (cbus_cd.cd_ndevs != 0)
		sc = cbus_cd.cd_devs[0];
	if (sc == NULL)
		panic("cbus_isrdispatch: can't find cbus_softc");

#ifdef DIAGNOSTIC
	if (intlevel < 0 || intlevel >= NCBUSISR)
		panic("cbus_isrdispatch: bad INT level 0x%d", intlevel);
#endif

	ci = &sc->cbus_isr[intlevel];

	if (ci->isr_func == NULL) {
		printf("cbus_isrdispatch: INT%d unexpected\n", intlevel);
		if (++unexpected > 10)
			panic("too many unexpected interrupts");
		return;
	}

	s = raiseipl(ci->isr_ipl);	/* splraise() */
	rc = ci->isr_func(ci->isr_arg);
	splx(s);

	if (rc != 0)
		ci->isr_count.ec_count++;

	if (rc)
		straycount = 0;
	else if (++straycount > 50)
		panic("cbus_isrdispatch: too many stray interrupts");
	else
		printf("cbus_isrdispatch: stray INT%d, IPL=%d\n", intlevel,
		    ci->isr_ipl);
}

/*
 * Return registered status of interrupt service routines.
 */
u_int8_t
cbus_intr_registered(void)
{
	struct cbus_softc *sc = NULL;

	if (cbus_cd.cd_ndevs != 0)
		sc = cbus_cd.cd_devs[0];
	if (sc == NULL)
		panic("cbus_intr_used: can't find cbus_softc");

	return sc->registered;
}

/*
 * Note about interrupt on PC-9801 extension board slot
 *
 * PC-9801 extension board slot bus (so-called 'C-bus' in Japan) use 8 own
 * interrupt levels, INT0-INT6, and NMI.  On LUNA-88K2, they all trigger
 * level 4 interrupt on mainbus, so we need to check the dedicated interrupt
 * status register to know which C-bus interrupt is occurred.
 *
 * The interrupt status register for C-bus is located at
 * (u_int8_t *)CBUS_INTR_STAT. Each bit of the register becomes 0 when
 * corresponding C-bus interrupt has occurred, otherwise 1.
 *
 * bit 7 = NMI(?)
 * bit 6 = INT0
 * bit 5 = INT1
 *  :
 * bit 0 = INT6
 *
 * To clear the C-bus interrupt flag, write the corresponding 'bit' number
 * (as u_int_8) to the register.  For example, if you want to clear INT1,
 * you should write '5' like:
 *   *(u_int8_t *)CBUS_INTR_STAT = 5;
 */

/*
 * Interrupt handler on mainbus.
 */
int
cbus_intr(void *arg)
{
	struct cbus_softc *sc = (struct cbus_softc *)arg;
	u_int8_t intr_status;
	int n;

	/*
	 * LUNA-88K2's interrupt level 4 is shared with other devices,
	 * such as le(4), for example.  So we check:
	 * - the value of our C-bus interrupt status register, and
	 * - if the INT level is what we are looking for.
	 */
	intr_status = *cbus_isreg & sc->registered;
	if (intr_status == sc->registered) return 0;	/* Not for me */

#ifdef CBUS_DEBUG
	printf("cbus_intr: called, *cbus_isreg=0x%02x, registered = 0x%02x\n",
	    *cbus_isreg, sc->registered);
#endif
	/* Make the bit pattern that we should proces */
	intr_status = intr_status ^ sc->registered;
#ifdef CBUS_DEBUG
	printf("cbus_intr: processing 0x%02x\n", intr_status);
#endif

	/* Process, and clear each interrupt flag */
	while ((n = ff1(intr_status)) != 32) {
		cbus_isrdispatch(6 - n);
		*cbus_isreg = (u_int8_t)n;
		intr_status &= ~(1 << n);
	}

	return 1;
}


code:
/*	$OpenBSD: cbusvar.h,v 1.4 2015/02/18 22:42:04 aoyama Exp $	*/

/*
 * Copyright (c) 2014 Kenji Aoyama.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * PC-9801 extension board slot bus ('C-bus') driver for LUNA-88K2.
 */

#include <sys/evcount.h>
#include <sys/queue.h>

/*
 * Currently 7 level C-bus interrupts (INT0 - INT6) are supported.
 */
#define NCBUSISR	7

/*
 * C-bus interrupt handler
 */
struct cbus_isr_t {
	int		(*isr_func)(void *);
	void		*isr_arg;
	int		isr_intlevel;
	int		isr_ipl;
	struct evcount	isr_count;
};

int	cbus_isrlink(int (*)(void *), void *, int, int, const char *);
int	cbus_isrunlink(int (*)(void *), int);
u_int8_t	cbus_intr_registered(void);

struct cbus_attach_args {
	char	*ca_name;
	int	ca_intlevel;
};


code:
/*	$OpenBSD: i82365_cbus.c,v 1.3 2015/03/13 12:12:42 aoyama Exp $	*/
/*	$NetBSD: i82365_isa.c,v 1.11 1998/06/09 07:25:00 thorpej Exp $	*/

/*
 * Copyright (c) 1997 Marc Horowitz.  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 Marc Horowitz.
 * 4. 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.
 */

/*
 * Driver for PC-9801-102 & PC-9821X[AE]-E01 PC Card slot adapter
 *  based on OpenBSD:src/sys/dev/isa/i82365_isa{,subr}.c
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/malloc.h>

#include <machine/board.h>		/* PC_BASE */
#include <machine/bus.h>
#include <machine/intr.h>

#include <arch/luna88k/cbus/cbusvar.h>

#include <dev/pcmcia/pcmciareg.h>
#include <dev/pcmcia/pcmciavar.h>
#include <dev/pcmcia/pcmciachip.h>

#include <dev/ic/i82365reg.h>
#include <dev/ic/i82365var.h>

#ifdef PCICCBUSDEBUG
#define	DPRINTF(arg)	printf arg;
#else
#define	DPRINTF(arg)
#endif

/*
 * XXX:
 * The C-bus expects edge-triggered interrupts, but some PC Cards and
 * the controller itself produce level-triggered interrupts.  This causes
 * spurious interrupts on C-bus.
 * Then, we use CL-PD67XX 'pulse IRQ' feature in this driver.  This seems
 * to solve stray interrupts on C-bus.
 * (BTW, all NEC genuine C-bus PC Card slot adapters use CL-PD67XX)
 */

/* Cirrus Logic CL-PD67XX Misc Control register */
#define PCIC_CIRRUS_MISC_CTL_1			0x16
#define  PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR	0x04
#define  PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ	0x08

/* XXX: should be passed by cbus_attach_args */
#define PCIC_CBUS_IOBASE	0x3e0
#define PCIC_CBUS_MEMBASE	0xd0000

#define PCEXMEM_BASE		PC_BASE
#define PCEXIO_BASE		PC_BASE + 0x1000000

/* prototypes */
void	*pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t,
	    struct pcmcia_function *, int, int (*) (void *), void *, char *);
void	pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
const char *pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t, void *);
int	pcic_cbus_intlevel_find(void);
int	pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t, bus_addr_t,
	    bus_size_t, bus_size_t, struct pcmcia_io_handle *);
void	pcic_cbus_chip_io_free(pcmcia_chipset_handle_t,
	    struct pcmcia_io_handle *);

int	pcic_cbus_probe(struct device *, void *, void *);
void	pcic_cbus_attach(struct device *, struct device *, void *);

/* bus space tag for pcic_cbus */
struct luna88k_bus_space_tag pcic_cbus_io_bst = {
	.bs_stride_1 = 1,
	.bs_stride_2 = 1,
	.bs_stride_4 = 1,
	.bs_stride_8 = 0,	/* not used */
	.bs_offset = PCEXIO_BASE,
	.bs_flags = TAG_LITTLE_ENDIAN
};

struct luna88k_bus_space_tag pcic_cbus_mem_bst = {
	.bs_stride_1 = 1,
	.bs_stride_2 = 1,
	.bs_stride_4 = 1,
	.bs_stride_8 = 0,	/* not used */
	.bs_offset = PCEXMEM_BASE,
	.bs_flags = TAG_LITTLE_ENDIAN
};

struct cfattach pcic_cbus_ca = {
	sizeof(struct pcic_softc), pcic_cbus_probe, pcic_cbus_attach
};

static struct pcmcia_chip_functions pcic_cbus_functions = {
	.mem_alloc	= pcic_chip_mem_alloc,
	.mem_free	= pcic_chip_mem_free,
	.mem_map	= pcic_chip_mem_map,
	.mem_unmap	= pcic_chip_mem_unmap,

	.io_alloc	= pcic_cbus_chip_io_alloc,
	.io_free	= pcic_cbus_chip_io_free,
	.io_map		= pcic_chip_io_map,
	.io_unmap	= pcic_chip_io_unmap,

	.intr_establish		= pcic_cbus_chip_intr_establish,
	.intr_disestablish	= pcic_cbus_chip_intr_disestablish,
	.intr_string		= pcic_cbus_chip_intr_string,

	.socket_enable	= pcic_chip_socket_enable,
	.socket_disable	= pcic_chip_socket_disable,
};

/*
 * NEC PC-9801 architecture uses different IRQ notation from PC-AT
 * architecture, so-called INT.  The MI pcic(4) driver internally uses
 * IRQ, so here is a table to convert INT to IRQ.
 */
static const int pcic_cbus_int2irq[NCBUSISR] = {
	PCIC_INTR_IRQ3,			/* INT 0 */
	PCIC_INTR_IRQ5,			/* INT 1 */
	PCIC_INTR_IRQ_RESERVED6,	/* INT 2 */
	PCIC_INTR_IRQ9,			/* INT 3 */
	PCIC_INTR_IRQ10,		/* INT 4(41) */
	PCIC_INTR_IRQ12,		/* INT 5 */
	PCIC_INTR_IRQ_RESERVED13	/* INT 6 */
};

/* And, a table to convert IRQ to INT */
static const int pcic_cbus_irq2int[] = {
	-1, -1, -1,  0, -1,  1,  2, -1,	/* IRQ 0- 7 */
	-1,  3,  4, -1,  5,  6, -1, -1	/* IRQ 8-15 */
};

struct pcic_ranges pcic_cbus_addr[] = {
	{ 0x340, 0x030 },
	{ 0x300, 0x030 },
	{ 0x390, 0x020 },
	{ 0x400, 0xbff },
	{ 0, 0},	/* terminator */
};

int
pcic_cbus_probe(parent, match, aux)
	struct device *parent;
	void *match, *aux;
{
#if 0	/* should be use cbus_attach_args in the future */
	struct cbus_attach_args *caa = aux;
#endif
	bus_space_tag_t iot = &pcic_cbus_io_bst;
	bus_space_handle_t ioh;
	int val, found;

	SET_TAG_LITTLE_ENDIAN(iot);

	if (bus_space_map(iot, PCIC_CBUS_IOBASE, PCIC_IOSIZE, 0, &ioh))
		return (0);
	found = 0;

	/*
	 * this could be done with a loop, but it would violate the
	 * abstraction
	 */

	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA + PCIC_IDENT);
	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
	if (pcic_ident_ok(val))
		found++;

	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB + PCIC_IDENT);
	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
	if (pcic_ident_ok(val))
		found++;

	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA + PCIC_IDENT);
	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
	if (pcic_ident_ok(val))
		found++;

	bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB + PCIC_IDENT);
	val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
	if (pcic_ident_ok(val))
		found++;

	bus_space_unmap(iot, ioh, PCIC_IOSIZE);

	if (!found)
		return (0);

	return (1);
}

void
pcic_cbus_attach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
#if 0	/* should be use cbus_attach_args in the future */
	struct cbus_attach_args *caa = aux;
#endif
	struct pcic_softc *sc = (void *)self;
	struct pcic_handle *h;
	bus_space_tag_t iot = &pcic_cbus_io_bst;
	bus_space_tag_t memt = &pcic_cbus_mem_bst;
	bus_space_handle_t ioh, memh;
	int intlevel, irq, i, reg;

	SET_TAG_LITTLE_ENDIAN(iot);
	SET_TAG_LITTLE_ENDIAN(memt);

	/* Map i/o space. */
	if (bus_space_map(iot, PCIC_CBUS_IOBASE, PCIC_IOSIZE, 0, &ioh)) {
		printf(": can't map i/o space\n");
		return;
	}

	/* Map mem space. */
	if (bus_space_map(memt, PCIC_CBUS_MEMBASE, PCIC_MEMSIZE, 0, &memh)) {
		printf(": can't map mem space\n");
		return;
	}

	sc->membase = PCIC_CBUS_MEMBASE;
	sc->subregionmask = (1 << (PCIC_MEMSIZE / PCIC_MEM_PAGESIZE)) - 1;

	sc->intr_est = NULL;	/* not used on luna88k */
	sc->pct = (pcmcia_chipset_tag_t)&pcic_cbus_functions;

	sc->iot = iot;
	sc->ioh = ioh;
	sc->memt = memt;
	sc->memh = memh;

	printf("\n");

	pcic_attach(sc);

	sc->ranges = pcic_cbus_addr;
	sc->iobase = 0x0000;
	sc->iosize = 0x1000;
	DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx\n",
	    sc->dev.dv_xname, (long) sc->iobase,
	    (long) sc->iobase + sc->iosize));

	pcic_attach_sockets(sc);

	/*
	 * Allocate an INT.  It will be used by both controllers.  We could
	 * use two different interrupts, but interrupts are relatively
	 * scarce, shareable, and for PCIC controllers, very infrequent.
	 */
	intlevel = pcic_cbus_intlevel_find();
	if (intlevel == -1) {
		printf("pcic_cbus_attach: no free INT found\n");
		return;
	}

	irq = pcic_cbus_int2irq[intlevel];
	cbus_isrlink(pcic_intr, sc, intlevel, IPL_TTY, sc->dev.dv_xname);
	sc->ih = (void *)pcic_intr;
	sc->irq = irq;

	if (irq) {
		printf("%s: INT%d (irq %d), ", sc->dev.dv_xname,
		    intlevel, irq);

		/* Set up the pcic to interrupt on card detect. */
		for (i = 0; i < PCIC_NSLOTS; i++) {
			h = &sc->handle[i];
			if (h->flags & PCIC_FLAG_SOCKETP) {
				/* set 'pulse management interrupt' mode */
				reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
				reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_MGMT_INTR;
				pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);

				pcic_write(h, PCIC_CSC_INTR,
				    (sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
				    PCIC_CSC_INTR_CD_ENABLE);
			}
		}
	} else
		printf("%s: no irq, ", sc->dev.dv_xname);

	printf("polling enabled\n");
	if (sc->poll_established == 0) {
		timeout_set(&sc->poll_timeout, pcic_poll_intr, sc);
		timeout_add_msec(&sc->poll_timeout, 500);
		sc->poll_established = 1;
	}
}

void *
pcic_cbus_chip_intr_establish(pcmcia_chipset_handle_t pch,
	struct pcmcia_function *pf, int ipl, int (*fcl)(void *),
	void *arg, char *xname)
{
	struct pcic_handle *h = (struct pcic_handle *)pch;
#ifdef PCICCBUSDEBUG
	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
#endif
	int intlevel, irq, reg;

#ifdef PCICCBUSDEBUG
	char buf[16];
	if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
		strlcpy(buf, "LEVEL", sizeof(buf));
	else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
		strlcpy(buf, "PULSE", sizeof(buf));
	else
		strlcpy(buf, "EDGE", sizeof(buf));
	printf("pcic_cbus_chip_intr_establish: IST_%s\n", buf);
#endif

	/*
	 * If the PC Card has level-triggered interrupt property,
	 * we use CL-PD67XX 'pulse IRQ' feature.
	 */
	if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL) {
		reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
		reg |= PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ;
		pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
	}

	intlevel = pcic_cbus_intlevel_find();

	if (intlevel == -1) {
		printf("pcic_cbus_chip_intr_establish: no INT found\n");
		return (NULL);
	}

	irq = pcic_cbus_int2irq[intlevel];
	h->ih_irq = irq;

	DPRINTF(("%s: pcic_cbus_chip_intr_establish INT%d (irq %d)\n",
	    sc->dev.dv_xname, intlevel, h->ih_irq));

	cbus_isrlink(fcl, arg, intlevel, ipl, h->pcmcia->dv_xname);

	reg = pcic_read(h, PCIC_INTR);
	reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
	pcic_write(h, PCIC_INTR, reg | irq);

	return (void *)fcl;
}

void
pcic_cbus_chip_intr_disestablish(pcmcia_chipset_handle_t pch, void *ih)
{
	struct pcic_handle *h = (struct pcic_handle *)pch;
#ifdef PCICCBUSDEBUG
	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
#endif
	int intlevel, reg;

	intlevel = pcic_cbus_irq2int[h->ih_irq];

	DPRINTF(("%s: pcic_cbus_chip_intr_disestablish INT%d (irq %d)\n",
	    sc->dev.dv_xname, intlevel, h->ih_irq));

	if (intlevel == -1) {
		printf("pcic_cbus_chip_intr_disestablish: "
		    "strange INT (irq = %d)\n", h->ih_irq);
		return;
	}

	h->ih_irq = 0;

	reg = pcic_read(h, PCIC_INTR);
	reg &= ~(PCIC_INTR_IRQ_MASK | PCIC_INTR_ENABLE);
	pcic_write(h, PCIC_INTR, reg);

	cbus_isrunlink(ih, intlevel);

	/* reset the 'pulse IRQ' mode */
	reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_1);
	reg &= ~PCIC_CIRRUS_MISC_CTL_1_PULSE_SYS_IRQ;
	pcic_write(h, PCIC_CIRRUS_MISC_CTL_1, reg);
}

const char *
pcic_cbus_chip_intr_string(pcmcia_chipset_handle_t pch, void *ih)
{
	struct pcic_handle *h = (struct pcic_handle *)pch;
	static char irqstr[64];

	if (ih == NULL)
		snprintf(irqstr, sizeof(irqstr),
		    "couldn't establish interrupt");
	else
		snprintf(irqstr, sizeof(irqstr), "INT%d (irq %d)",
		    pcic_cbus_irq2int[h->ih_irq], h->ih_irq);
	return(irqstr);
}

/*
 * Find a free and pcic-compliant INT level; searching from highest
 * (=small number) to lowest.
 */
int
pcic_cbus_intlevel_find(void)
{
	int intlevel, irq;
	u_int8_t cbus_not_used = ~cbus_intr_registered();

	for (intlevel = 0; intlevel < NCBUSISR; intlevel++)
		if (cbus_not_used & (1 << (6 - intlevel))) {
			irq = pcic_cbus_int2irq[intlevel];
			if ((1 << irq) & PCIC_INTR_IRQ_VALIDMASK)
				break;
		}

	if (intlevel == NCBUSISR)
		intlevel = -1;	/* not found */

	return intlevel;
}

/*
 * LUNA specific pcic_cbus_chip_io_{alloc,free}
 */
int
pcic_cbus_chip_io_alloc(pcmcia_chipset_handle_t pch, bus_addr_t start,
    bus_size_t size, bus_size_t align, struct pcmcia_io_handle *pcihp)
{
	struct pcic_handle *h = (struct pcic_handle *) pch;
	bus_space_tag_t iot;
	bus_space_handle_t ioh;
	bus_addr_t ioaddr, beg, fin;
	int flags = 0;
	struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
	struct pcic_ranges *range;

	/*
	 * Allocate some arbitrary I/O space.
	 */

	iot = sc->iot;

	if (start) {
		ioaddr = start;
		if (bus_space_map(iot, start, size, 0, &ioh))
			return (1);
		DPRINTF(("pcic_cbus_chip_io_alloc map port %lx+%lx\n",
		    (u_long)ioaddr, (u_long)size));
	} else if (sc->ranges) {
 		/*
		 * In this case, we know the "size" and "align" that
		 * we want.  So we need to start walking down
		 * sc->ranges, searching for a similar space that
		 * is (1) large enough for the size and alignment
		 * (2) then we need to try to allocate
		 * (3) if it fails to allocate, we try next range.
		 *
		 * We must also check that the start/size of each
		 * allocation we are about to do is within the bounds
		 * of "sc->iobase" and "sc->iosize".
		 * (Some pcmcia controllers handle a 12 bits of addressing,
		 * but we want to use the same range structure)
		 */
		for (range = sc->ranges; range->start; range++) {
			/* Potentially trim the range because of bounds. */
			beg = max(range->start, sc->iobase);
			fin = min(range->start + range->len,
			    sc->iobase + sc->iosize);

			/* Short-circuit easy cases. */
			if (fin < beg || fin - beg < size)
				continue;

			DPRINTF(("pcic_cbus_chip_io_alloc beg-fin %lx-%lx\n",
			    (u_long)beg, (u_long)fin));
			if (bus_space_map(iot, beg, size, 0, &ioh) == 0) {
				ioaddr = beg;
				break;
			}
		}
		if (range->start == 0)
			return (1);
		DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n",
		    (u_long)ioaddr, (u_long)size));
	} else {
		if (bus_space_map(iot, sc->iobase, size, 0, &ioh))
			return (1);
		ioaddr = sc->iobase;
		DPRINTF(("pcic_cbus_chip_io_alloc alloc port %lx+%lx\n",
		    (u_long)ioaddr, (u_long)size));
	}

	pcihp->iot = iot;
	pcihp->ioh = ioh;
	pcihp->addr = ioaddr;
	pcihp->size = size;
	pcihp->flags = flags;

	return (0);
}

void
pcic_cbus_chip_io_free(pcmcia_chipset_handle_t pch,
    struct pcmcia_io_handle *pcihp)
{
	bus_space_tag_t iot = pcihp->iot;
	bus_space_handle_t ioh = pcihp->ioh;
	bus_size_t size = pcihp->size;

	bus_space_unmap(iot, ioh, size);
}


code:
/*	$OpenBSD: nec86.c,v 1.1 2014/12/28 13:03:18 aoyama Exp $	*/
/*	$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

struct audio_device nec86_device = {
	.name		= "PC-9801-86",
	.version	= "",
	.config		= "nec86"
};

/*
 * 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
 */
#define YM_INDEX	0
#define YM_DATA		2

void nec86_ym_read(struct nec86_softc *, u_int8_t, u_int8_t *);
void nec86_ym_write(struct nec86_softc *, u_int8_t, u_int8_t);

void
nec86_ym_read(struct nec86_softc *sc, u_int8_t index, u_int8_t *data) {
	bus_space_write_1(sc->sc_ym_iot,
	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
	delay(100);
	*data = bus_space_read_1(sc->sc_ym_iot,
	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA);
	delay(100);
}

void
nec86_ym_write(struct nec86_softc *sc, u_int8_t index, u_int8_t data) {
	bus_space_write_1(sc->sc_ym_iot,
	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
	delay(100);
	bus_space_write_1(sc->sc_ym_iot,
	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA, data);
	delay(100);
}

/*
 * 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;

	/* enable YM2608(ONPA) */
	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);

	switch (ysc->model) {
	case 2:	/* base I/O port for YM2608(OPNA) is 0x188 */
		sc->sc_ym_ioh = OPNA_IOBASE1;
		break;
	case 3:	/* base I/O port for YM2608(OPNA) is 0x288 */
		sc->sc_ym_ioh = OPNA_IOBASE2;
		break;
	default:
		/* can not happen; set to factory default */
		sc->sc_ym_ioh = OPNA_IOBASE1;
		break;
	}

	/* YM2608 I/O port set (IOA:input IOB:output) */
	nec86_ym_read(sc, 0x07, &data);
	data &= 0x3f;
	data |= 0x80;
	nec86_ym_write(sc, 0x07, data);

	/* YM2608 register 0x0e has C-bus interrupt level information */
	nec86_ym_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; set to factory default */
		sc->sc_intlevel = 5;
		break;
	}

	/* reset YM2608 timer A and B: XXX need this? */
	data = 0x30;
	nec86_ym_write(sc, 0x27, data);

	printf(" int %d", sc->sc_intlevel);

	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;
}


code:
/*	$OpenBSD: nec86hw.c,v 1.3 2015/06/25 06:43:45 ratchov Exp $	*/
/*	$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>

#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 },
};

static struct audio_params nec86hw_audio_default =
	{44100, AUDIO_ENCODING_SLINEAR_LE, 16, 2, 1, 2};

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 },
	{ 16, 1,
	    nec86fifo_output_mono_16_direct, nec86fifo_input_mono_16_direct },
	{ 8, 2,
	    nec86fifo_output_stereo_8_direct, nec86fifo_input_stereo_8_direct },
	{ 16, 2,
	    nec86fifo_output_stereo_16_direct, nec86fifo_input_stereo_16_direct },
};
#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_direct;
	sc->func_fifo_input = nec86fifo_input_mono_8_direct;
	(void) nec86hw_set_params(sc, AUMODE_RECORD, 0,
	    &nec86hw_audio_default, &nec86hw_audio_default);
	(void) nec86hw_set_params(sc, AUMODE_PLAY,   0,
	    &nec86hw_audio_default, &nec86hw_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;

	if (p->precision == 8)
		p->encoding = AUDIO_ENCODING_ULINEAR_LE;
	else {
		p->precision = 16;
		p->encoding = AUDIO_ENCODING_SLINEAR_LE;
	}
	sc->channels = p->channels;
	sc->precision = prec;
	sc->encoding = enc;
	sc->hw_orate_bits = nec86hw_rate_bits(sc, p->sample_rate);
	sc->sc_orate = p->sample_rate = sc->hw_orate =
	    nec86hw_rate_table[rate_type][sc->hw_orate_bits];
	sc->hw_irate_bits = nec86hw_rate_bits(sc, r->sample_rate);
	sc->sc_irate = 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, AudioEulinear, sizeof(fp->name));
		fp->encoding = AUDIO_ENCODING_ULINEAR;
		fp->precision = 8;
		fp->bps = 1;
		fp->msb = 1;
		fp->flags = 0;
		break;
	case 1:
		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;
	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;
	}

	sc->func_fifo_output =
	    nec86hw_functable[i].func_fifo_output_direct;
	sc->func_fifo_input =
	    nec86hw_functable[i].func_fifo_input_direct;
	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 */
	hw_blocksize = sc->pdma_count * (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 */
	hw_blocksize = sc->pdma_count * (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;
}

/*
 * 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
	}
}

/*
 * 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;
}


code:
/*	$OpenBSD: nec86hwvar.h,v 1.1 2014/12/28 13:03:18 aoyama Exp $	*/
/*	$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_ */


code:
/*	$OpenBSD: nec86reg.h,v 1.1 2014/12/28 13:03:18 aoyama Exp $	*/
/*	$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_ */


code:
/*	$OpenBSD: nec86var.h,v 1.1 2014/12/28 13:03:18 aoyama Exp $	*/
/*	$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_ym_iot;
	bus_space_handle_t sc_ym_iobase;
	bus_space_handle_t sc_ym_ioh;

	int sc_attached;
	int sc_intlevel;
};

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_ */


code:
/*	$OpenBSD: necsb.c,v 1.3 2015/02/18 22:42:04 aoyama Exp $	*/
/*	$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,
	0,	/* no offset */
};

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;
#if 0
	struct cbus_attach_args *caa = aux;
#endif

	bus_space_tag_t iot = &necsb_bst;

	nsc->sc_n86iot = iot;
	nsc->sc_n86ioh =
	    (bus_space_handle_t)(NECSB_BASE + NEC86_SOUND_ID);

	ysc->sc_iot = iot;
	ysc->sc_ioh =
	    (bus_space_handle_t)(NECSB_BASE + NEC86_COREOFFSET);
	ysc->sc_cfgflags = 0;	/* original 'PC-9801-86' */

	nsc->sc_ym_iot = iot;
	nsc->sc_ym_iobase = (bus_space_handle_t)PCEXIO_BASE;
	nsc->sc_ym_ioh = (bus_space_handle_t)0;	/* default */

	nec86_attachsubr(nsc);

	if (nsc->sc_intlevel == -1)
		return;

	if ((nsc->sc_intlevel < 0) || (nsc->sc_intlevel >= NCBUSISR))
		panic("necsb_attach: bad INT level");

	/* XXX: check return value ? */
	cbus_isrlink(nec86hw_intr, ysc, nsc->sc_intlevel, IPL_AUDIO,
	    self->dv_xname);
}


code:
/*	$OpenBSD: pcex.c,v 1.3 2015/02/18 22:42:04 aoyama Exp $	*/

/*
 * Copyright (c) 2014 Kenji Aoyama.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * PC-9801 extension board slot direct access driver for LUNA-88K2.
 */

#include <sys/param.h>
#include <sys/systm.h>	/* tsleep()/wakeup() */
#include <sys/device.h>
#include <sys/ioctl.h>

#include <machine/autoconf.h>
#include <machine/board.h>	/* PC_BASE */
#include <machine/conf.h>
#include <machine/pcex.h>

#include <luna88k/cbus/cbusvar.h>

extern int hz;

#if 0
#define PCEX_DEBUG
#endif

#define PCEXMEM_BASE	PC_BASE
#define PCEXIO_BASE	(PC_BASE + 0x1000000)

/* autoconf stuff */
int pcex_match(struct device *, void *, void *);
void pcex_attach(struct device *, struct device *, void *);

struct pcex_softc {
	struct device sc_dev;
	int intr_use[NCBUSISR];
};

const struct cfattach pcex_ca = {
	sizeof(struct pcex_softc), pcex_match, pcex_attach
};

struct cfdriver pcex_cd = {
	NULL, "pcex", DV_DULL
};

/* prototypes */
int pcex_intr(void *);
int pcex_set_int(struct pcex_softc *, u_int);
int pcex_reset_int(struct pcex_softc *, u_int);
int pcex_wait_int(struct pcex_softc *, u_int);

int
pcex_match(struct device *parent, void *cf, void *aux)
{
	struct cbus_attach_args *caa = aux;

	if (strcmp(caa->ca_name, pcex_cd.cd_name))
		return 0;

	return 1;
}

void
pcex_attach(struct device *parent, struct device *self, void *args)
{
	struct pcex_softc *sc = (struct pcex_softc *)self;
	int i;

	for (i = 0; i < NCBUSISR; i++)
		sc->intr_use[i] = 0;

	printf("\n");
	return;
}

int
pcexopen(dev_t dev, int flag, int mode, struct proc *p)
{
	switch (minor(dev)) {
	case 0:	/* memory area */
	case 1:	/* I/O port area */
		return 0;
	default:
		return ENXIO;
	}
}

int
pcexclose(dev_t dev, int flag, int mode, struct proc *p)
{
	return (0);
}

paddr_t
pcexmmap(dev_t dev, off_t offset, int prot)
{
	paddr_t cookie = -1;

	switch (minor(dev)) {
	case 0:	/* memory area */
		if (offset >= 0 && offset < 0x1000000)
			cookie = (paddr_t)(PCEXMEM_BASE + offset);
		break;
	case 1:	/* I/O port area */
		if (offset >= 0 && offset < 0x10000)
			cookie = (paddr_t)(PCEXIO_BASE + offset);
		break;
	default:
		break;
	}

	return cookie;
}

int
pcexioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	struct pcex_softc *sc = NULL;
	u_int level;

	if (pcex_cd.cd_ndevs != 0)
		sc = pcex_cd.cd_devs[0];
	if (sc == NULL)
		return ENXIO;

	level = *(u_int *)data;

	switch(cmd) {
	case PCEXSETLEVEL:
		return pcex_set_int(sc, level);

	case PCEXRESETLEVEL:
		return pcex_reset_int(sc, level);

	case PCEXWAITINT:
		return pcex_wait_int(sc, level);

	default:
		return ENOTTY;
	}
}

int
pcex_set_int(struct pcex_softc *sc, u_int level)
{
	if (level > 6)
		return EINVAL;
	if (sc->intr_use[level] != 0)
		return EINVAL;	/* Duplicate */

	sc->intr_use[level] = 1;
	cbus_isrlink(pcex_intr, &(sc->intr_use[level]), level, IPL_NET,
	    sc->sc_dev.dv_xname);

	return 0;
}

int
pcex_reset_int(struct pcex_softc *sc, u_int level)
{
	if (level > 6)
		return EINVAL;
	if (sc->intr_use[level] == 0)
		return EINVAL;	/* Not registered */

	sc->intr_use[level] = 0;
	cbus_isrunlink(pcex_intr, level);

	return 0;
}

int
pcex_wait_int(struct pcex_softc *sc, u_int level)
{
	int ret;

	if (level > 6)
		return EINVAL;
	if (sc->intr_use[level] == 0)
		return EINVAL;	/* Not registered */

	ret = tsleep(&(sc->intr_use[level]), PWAIT | PCATCH, "pcex",
	    hz /* XXX: 1 sec. */);

#ifdef PCEX_DEBUG
	if (ret == EWOULDBLOCK)
		printf("pcex_wait_int: timeout in tsleep\n");
#endif
	return ret;
}

int
pcex_intr(void *arg)
{
#ifdef PCEX_DEBUG
	printf("pcex_intr: called, arg=%p\n", arg);
#endif
	/* Just wakeup(9) for now */
	wakeup(arg);

	return 1;
}


code:
/.cvsignore/1.2/Tue Dec 25 17:00:16 2012//TOPENBSD_5_8_BASE
D


code:
#	$OpenBSD: GENERIC,v 1.20 2015/03/04 14:03:11 aoyama Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

machine		luna88k m88k
include		"../../../conf/GENERIC"
maxusers	64			# estimated number of users

# Processor type
option		M88100		# 88100 support; mandatory

# Number of maximum processors
option		MAX_CPUS=4	# may have up to 4 processors

# Define this if your processor has the xxx.usr bug (mask C82N)
option		ERRATA__XXX_USR

# Options for luna88k hardware
option		WSDISPLAY_COMPAT_RAWKBD	# Provide raw scancodes; needed for X11

config		bsd		swap generic

#
# devices
#

mainbus0	at root
clock0		at mainbus0
lcd0		at mainbus0
le0		at mainbus0
sio0		at mainbus0
siotty0		at sio0
ws0		at sio0
fb0		at mainbus0
spc0		at mainbus0
spc1		at mainbus0

# Workstation Console attachments
wsdisplay*	at fb?
wskbd*		at ws? mux 1
wsmouse*	at ws? mux 0

# PC-9801 extension board slot
cbus0		at mainbus0

# PC-9801 extension board slot 'generic' driver
pcex0		at cbus0

# NEC PC-9801-86 sound board
#necsb*		at cbus?
#audio*		at necsb?

# NEC PC-9801-102 & PC-9821X[AE]-E01 PC Card slot adapter
#pcic*		at cbus?
#pcmcia*	at pcic?

# SCSI devices
scsibus*	at scsi?
sd*		at scsibus?
st*		at scsibus?
cd*		at scsibus?
ch*		at scsibus?
safte*		at scsibus?
ses*		at scsibus?
uk*		at scsibus?

# Pseudo-device
pseudo-device	wsmux 2

# PCMCIA devices
# XXX: malo(4) is not supported, because LUNA-88K does not have DMA.
#com*		at pcmcia?		# PCMCIA modems/serial ports
##aic*		at pcmcia?		# PCMCIA Adaptec 152[02] SCSI (not yet)
#wdc*		at pcmcia?		# IDE controllers
#ne*		at pcmcia?		# PCMCIA based NE2000 ethernet
#ep*		at pcmcia?		# PCMCIA based 3C5xx ethernet
#sm*		at pcmcia?		# PCMCIA based sm ethernet
#xe*		at pcmcia?		# Xircom ethernet
#wi*		at pcmcia?		# WaveLAN IEEE 802.11DS
#an*		at pcmcia?		# Aironet IEEE 802.11DS
#cnw*		at pcmcia?		# Xircom Netwave

# IDE/ATAPI (with PCMCIA)
#wd*		at wdc?	flags 0x0000
#atapiscsi*	at wdc?


code:
#	$OpenBSD: GENERIC.MP,v 1.1 2012/03/01 14:04:03 aoyama Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

include	"arch/luna88k/conf/GENERIC"

option	MULTIPROCESSOR
#option	MP_LOCKDEBUG


code:
#	$OpenBSD: Makefile.luna88k,v 1.59 2015/01/13 01:12:49 deraadt Exp $

# For instructions on building kernels consult the config(8) and options(4)
# manual pages.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
#	IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
# DEBUG is set to -g by config if debugging is requested (config -g).
# PROF is set to -pg by config if profiling is requested (config -p).

.include <bsd.own.mk>

SIZE?=	size
STRIP?=	strip

# source tree is located via $S relative to the compilation directory
.ifndef S
S!=	cd ../../../..; pwd
.endif

_machdir?=	$S/arch/${_mach}
_archdir?=	$S/arch/${_arch}

INCLUDES=	-nostdinc -I$S -I. -I$S/arch
CPPFLAGS=	${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -D__${_mach}__ -MD -MP
CWARNFLAGS=	-Werror -Wall -Wimplicit-function-declaration \
		-Wno-main -Wno-uninitialized \
		-Wframe-larger-than=2047

CMACHFLAGS=	-mno-check-zero-division -mmemcpy
CMACHFLAGS+=	-fno-builtin-printf -fno-builtin-snprintf \
		-fno-builtin-vsnprintf -fno-builtin-log \
		-fno-builtin-log2 -fno-builtin-malloc
.if ${IDENT:M-DNO_PROPOLICE}
CMACHFLAGS+=	-fno-stack-protector
.endif

COPTS?=		-O2
CFLAGS=		${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
AFLAGS=		-D_LOCORE -x assembler-with-cpp ${CWARNFLAGS} ${CMACHFLAGS}
LDSCRIPT=	${_machdir}/conf/ld.script
LINKFLAGS=	-T ${LDSCRIPT} -Ttext 0x80000 -e __start -X -N --warn-common -nopie

.if ${IDENT:M-DDDB_STRUCT}
DB_STRUCTINFO=	db_structinfo.h
.else
DB_STRUCTINFO=
.endif

HOSTCC?=	${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=	${CFLAGS}
HOSTED_C=	${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<

NORMAL_C_NOP=	${CC} ${CFLAGS} ${CPPFLAGS} -c $<
NORMAL_C=	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_S=	${CC} ${AFLAGS} ${CPPFLAGS} -c $<
PROFILE_C=	${CC} -S -c ${CFLAGS} ${CPPFLAGS} $<; \
		sed -e s/_mcount/mcount/ -e s/subrmcount/subr_mcount/ <$*.s | \
		${AS} -o $@; \
		rm -f $*.s

%OBJS

%CFILES

%SFILES

# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP} swapxxx.o
#	${SYSTEM_LD_HEAD}
#	${SYSTEM_LD} swapxxx.o
#	${SYSTEM_LD_TAIL}
SYSTEM_HEAD=	locore.o param.o ioconf.o
SYSTEM_OBJ=	${SYSTEM_HEAD} ${OBJS}
SYSTEM_DEP=	Makefile ${SYSTEM_OBJ} ${LDSCRIPT}
SYSTEM_LD_HEAD=	@rm -f $@
SYSTEM_LD=	@echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \
		${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} vers.o ${OBJS}
SYSTEM_LD_TAIL=	@${SIZE} $@; chmod 755 $@

DEBUG?=
.if ${DEBUG} == "-g"
LINKFLAGS+=	-X
STRIPFLAGS=	-g -x
SYSTEM_LD_TAIL+=; \
		echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \
		echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \
		${STRIP} ${STRIPFLAGS} -o $@ $@.gdb
.else
LINKFLAGS+=	-S -x
.endif

%LOAD

# cc's -MD puts the source and output paths in the dependency file;
# since those are temp files here we need to fix it up.  It also
# puts the file in /tmp, so we use -MF to put it in the current
# directory as assym.P and then generate assym.d from it with a
# good target name
assym.h: $S/kern/genassym.sh Makefile \
	 ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf
	cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \
	    sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -MF assym.P > assym.h.tmp
	sed '1s/.*/assym.h: \\/' assym.P > assym.d
	sort -u assym.h.tmp > assym.h

param.c: $S/conf/param.c
	rm -f param.c
	cp $S/conf/param.c .

param.o: param.c Makefile
	${NORMAL_C}

mcount.o: $S/lib/libkern/mcount.c Makefile
	${NORMAL_C_NOP}

ioconf.o: ioconf.c
	${NORMAL_C}

vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
	sh $S/conf/newvers.sh
	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c

clean::
	rm -f eddep *bsd *bsd.gdb tags *.[dio] [a-z]*.s \
	    [Ee]rrs linterrs assym.h ${DB_STRUCTINFO}

lint:
	@lint -hbxncez -Dvolatile= ${CPPFLAGS} -UKGDB \
	    ${CFILES} ioconf.c param.c | \
	    grep -v 'static function .* unused'

depend:
	@touch $@

tags:
	@echo "see $S/kern/Makefile for tags"

db_structinfo.h: $S/ddb/db_structinfo.c $S/ddb/parse_structinfo.pl
	${CC} ${CFLAGS} ${CPPFLAGS} -MT $@ -gstabs -c $S/ddb/db_structinfo.c
	objdump -g db_structinfo.o | perl $S/ddb/parse_structinfo.pl > $@
	rm -f db_structinfo.o

locore.o: ${_machdir}/${_mach}/locore.S assym.h
eh.o mutex.o process.o subr.o: assym.h

# The install target can be redefined by putting a
# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
MACHINE_NAME!=  uname -n
install: install-kernel-${MACHINE_NAME}
.if !target(install-kernel-${MACHINE_NAME}})
install-kernel-${MACHINE_NAME}:
	cmp -s bsd /bsd || ln -f /bsd /obsd
	cp bsd /nbsd
	mv /nbsd /bsd
.endif

# pull in the dependency information
.if !empty(DB_STRUCTINFO) && !exists(${DB_STRUCTINFO})
 ${SYSTEM_OBJ}: ${DB_STRUCTINFO}
.endif
.ifnmake clean
. for o in ${SYSTEM_OBJ} assym.h ${DB_STRUCTINFO}
.  if exists(${o:R}.d)
.   include "${o:R}.d"
.  elif exists($o)
    .PHONY: $o
.  endif
. endfor
.endif

%RULES


code:
#	$OpenBSD: RAMDISK,v 1.13 2015/07/17 22:52:28 tedu Exp $

machine		luna88k m88k
maxusers	4

option		TIMEZONE=0
option		DST=0
option		SMALL_KERNEL
option		NO_PROPOLICE
option		BOOT_CONFIG

option		MINIROOTSIZE=4096
option		RAMDISK_HOOKS

option		SCSITERSE

option		FFS
option		INET6

config		bsd root rd0a swap on rd0b

option		M88100		# 88100 support; mandatory
option		MAX_CPUS=4	# may have up to 4 processors
option		ERRATA__XXX_USR

mainbus0	at root
clock0		at mainbus0
le0		at mainbus0
sio0		at mainbus0
siotty0		at sio0
ws0		at sio0
fb0		at mainbus0
spc0		at mainbus0
spc1		at mainbus0

wsdisplay*	at fb?
wskbd*		at ws?

scsibus*	at scsi?
sd*		at scsibus?			# SCSI disks
st*		at scsibus?			# SCSI tapes
cd*		at scsibus?			# SCSI CD-ROM

pseudo-device	loop 1
pseudo-device	bpfilter 1
pseudo-device	rd 1