code:
/*	$OpenBSD: dma.c,v 1.3 2014/12/24 22:48:27 miod Exp $	*/

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * 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.
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/queue.h>

#include <uvm/uvm.h>

#include <machine/autoconf.h>
#include <machine/board.h>

#include <aviion/dev/sysconvar.h>

#include <aviion/dev/dmareg.h>
#include <aviion/dev/dmavar.h>

/*
 * DMA request information structure.
 */
struct dmareq {
	TAILQ_ENTRY(dmareq)	chain;

	vaddr_t	mem;
	size_t	len;
	uint	dir;

	size_t	lastcnt;

	void	*cbarg;
	void	(*cbstart)(void *);
	void	(*cbdone)(void *);
};

struct dma_softc {
	struct device	sc_dev;

	struct intrhand	sc_ih;

	TAILQ_HEAD(, dmareq) sc_req;
};

int	dma_match(struct device *, void *, void *);
void	dma_attach(struct device *, struct device *, void *);

const struct cfattach dma_ca = {
	sizeof(struct dma_softc), dma_match, dma_attach
};

struct cfdriver dma_cd = {
	NULL, "dma", DV_DULL
};

int	dma_intr(void *);
void	dma_start(struct dma_softc *);

int
dma_match(struct device *parent, void *match, void *aux)
{
	struct confargs *ca = aux;

	switch (cpuid) {
#ifdef AV400
	case AVIION_300_310:
	case AVIION_400_4000:
	case AVIION_410_4100:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
	case AVIION_4300_25:
	case AVIION_4300_20:
	case AVIION_4300_16:
		if (ca->ca_paddr == DMA_MAP)
			return 1;
		/* FALLTHROUGH */
#endif
	default:
		return 0;
	}
}

void
dma_attach(struct device *parent, struct device *self, void *aux)
{
	struct dma_softc *sc = (struct dma_softc *)self;

	printf("\n");

	*(volatile uint32_t *)DMA_COUNT = 0;	/* clear possibly pending int */

	TAILQ_INIT(&sc->sc_req);

	sc->sc_ih.ih_fn = dma_intr;
	sc->sc_ih.ih_arg = sc;
	sc->sc_ih.ih_flags = 0;
	sc->sc_ih.ih_ipl = IPL_BIO;
	sysconintr_establish(INTSRC_DMA, &sc->sc_ih, self->dv_xname);
}

int
dma_intr(void *v)
{
	struct dma_softc *sc = v;
	struct dmareq *req;
	size_t tc;

	req = TAILQ_FIRST(&sc->sc_req);
	if (req == NULL) {
		printf("%s: interrupt but no active request?\n", __func__);
		*(volatile uint32_t *)DMA_STOP = DMASTOP_INHIBIT;
		return -1;
	}

	tc = *(volatile uint32_t *)DMA_COUNT;
	if (tc != 0)
		printf("%s: unexpected intr, TC = %x\n", __func__, tc);
	req->len -= req->lastcnt;
	if (req->len == 0) {
		/* this transfer is over */
		TAILQ_REMOVE(&sc->sc_req, req, chain);

		if (req->cbdone != NULL)
			(*req->cbdone)(req->cbarg);

		free(req, M_DEVBUF, sizeof *req);
	} else {
		req->mem += req->lastcnt;
	}
	dma_start(sc);

	return 1;
}

int
dma_req(void *vaddr, size_t sz, int dir, void (*cbstart)(void *),
    void (*cbdone)(void *), void *cbarg)
{
	struct dma_softc *sc;
	struct dmareq *req;
	int run;
	int s;

	if (dma_cd.cd_devs == NULL ||
	    (sc = (struct dma_softc *)dma_cd.cd_devs[0]) == NULL)
		return ENXIO;
	req = malloc(sizeof *req, M_DEVBUF, M_NOWAIT | M_CANFAIL);
	if (req == NULL)
		return ENOMEM;

	req->mem = (vaddr_t)vaddr;
	req->len = sz;
	req->dir = dir;
	req->cbstart = cbstart;
	req->cbdone = cbdone;
	req->cbarg = cbarg;
	req->lastcnt = 0;

	s = splbio();
	run = TAILQ_EMPTY(&sc->sc_req);
	TAILQ_INSERT_TAIL(&sc->sc_req, req, chain);
	if (run)
		dma_start(sc);
	splx(s);

	return 0;
}

void
dma_start(struct dma_softc *sc)
{
	struct dmareq *req;
	paddr_t pa, paoff;

	req = TAILQ_FIRST(&sc->sc_req);
	if (req == NULL) {
		*(volatile uint32_t *)DMA_STOP = DMASTOP_INHIBIT;
		return;
	}

	if (pmap_extract(pmap_kernel(), req->mem, &pa) == FALSE)
		panic("%s: pmap_extract(%p) failed",
		    __func__, (void *)req->mem);

	paoff = pa & ~DMAMAP_MASK;

	req->lastcnt = DMA_BOUNDARY - paoff;
	if (req->lastcnt > req->len)
		req->lastcnt = req->len;

	*(volatile uint32_t *)DMA_DIR = req->dir;
	*(volatile uint32_t *)DMA_COUNT = req->lastcnt;
	*(volatile uint32_t *)DMA_OFF = paoff;
	*(volatile uint32_t *)DMA_MAP = (pa & DMAMAP_MASK) |
	    DMAMAP_G | DMAMAP_V;
	*(volatile uint32_t *)DMA_CLR_INVALID = DMACLR;
	*(volatile uint32_t *)DMA_STOP = DMASTOP_RESTART;

	if (req->cbstart != NULL)
		(*req->cbstart)(req->cbarg);
}


code:
/*	$OpenBSD: dmareg.h,v 1.1 2013/10/23 10:07:14 miod Exp $	*/

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * 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.
 */

/*
 * AV400 family DMA controller definitions
 */

#define	DMA_BOUNDARY	0x1000

#define	DMA_MAP		0xfff8b000
#define	DMAMAP_MASK		0xfffff000
#define	DMAMAP_G		0x00000080
#define	DMAMAP_RO		0x00000004
#define	DMAMAP_V		0x00000001
#define	DMA_OFF		0xfff8b004
#define	DMAOFF_MASK		0x00000ffe
#define	DMA_COUNT	0xfff8b008
#define	DMACOUNTC_MASK		0x00001ffe
#define	DMA_DIR		0xfff8b00c
#define	DMA_CLR_INVALID	0xfff8b010
#define	DMA_CLR_WP	0xfff8b014
#define	DMACLR			0x00000000
#define	DMA_STOP	0xfff8b018
#define	DMASTOP_RESTART		0x00000000	/* restart DMA */
#define	DMASTOP_INHIBIT		0x00000001	/* do not restart DMA */

license: unknown


code:
/*	$OpenBSD: dmavar.h,v 1.1 2013/10/23 10:07:14 miod Exp $	*/

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * 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.
 */

#define	DMADIR_TO_DEVICE	0x00000001	/* DMA from memory to device */
#define	DMADIR_FROM_DEVICE	0x00000000	/* DMA from device to memory */

int	dma_req(void *, size_t, int,
	    void (*)(void *), void (*)(void *), void *);


code:
/*	$OpenBSD: if_le_syscon.c,v 1.17 2014/12/22 02:26:53 tedu Exp $	*/

/*-
 * Copyright (c) 1996 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Adam Glass and Gordon W. Ross.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/device.h>

#include <uvm/uvm.h>

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net/if_media.h>

#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/cpu.h>

#ifdef AV400
#include <machine/av400.h>
#endif
#ifdef AV530
#include <machine/av530.h>
#endif

#include <aviion/dev/sysconvar.h>

#include <dev/ic/lancereg.h>
#include <dev/ic/lancevar.h>
#include <dev/ic/am7990reg.h>
#include <dev/ic/am7990var.h>
/* #include <dev/ic/am79900reg.h> */
#include <dev/ic/am79900var.h>

/*
 * LANCE or ILACC registers. Although these are 16 bit registers, on the AV400
 * design, they need to be accessed as 32 bit registers. Bus magic...
 */
struct av_lereg {
	volatile uint32_t	ler1_rdp;	/* data port */
	volatile uint32_t	ler1_rap;	/* register select port */

	/* The following fields are only found on ILACC designs */
	volatile uint32_t	unused[2];
	volatile uint32_t	enaddr[6];
	volatile uint32_t	cksum[2];
};

struct le_softc {
	union {	/* glue to MI code */
		struct	lance_softc	sc_lance;
		struct	am7990_softc	sc_am7990;
		struct	am79900_softc	sc_am79900;
	} u;

	int	sc_ilacc;
	struct	av_lereg *sc_r1;	/* LANCE or ILACC registers */
	struct	intrhand sc_ih;
};

int	le_syscon_match(struct device *, void *, void *);
void	le_syscon_attach(struct device *, struct device *, void *);

struct cfattach le_syscon_ca = {
	sizeof(struct le_softc), le_syscon_match, le_syscon_attach
};

void	le_syscon_hwinit_ilacc(struct lance_softc *);
int	le_syscon_intr_ilacc(void *);
int	le_syscon_intr_lance(void *);
uint16_t le_syscon_rdcsr(struct lance_softc *, uint16_t);
void	le_syscon_wrcsr(struct lance_softc *, uint16_t, uint16_t);
void	le_syscon_wrcsr_interrupt(struct lance_softc *, uint16_t, uint16_t);

int
le_syscon_match(struct device *parent, void *cf, void *aux)
{
	struct confargs *ca = aux;
#ifdef AV530
	paddr_t fuse = 0;
#endif

	switch (cpuid) {
#ifdef AV400
	case AVIION_300_310:
	case AVIION_400_4000:
	case AVIION_410_4100:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
	case AVIION_4300_25:
	case AVIION_4300_20:
	case AVIION_4300_16:
		switch (ca->ca_paddr) {
		case AV400_LAN:
			break;
		default:
			return 0;
		}
		break;
#endif
#ifdef AV530
	case AVIION_4600_530:
		switch (ca->ca_paddr) {
		case AV530_LAN1:
			fuse = AV530_IOFUSE0;
			break;
		case AV530_LAN2:
			fuse = AV530_IOFUSE1;
			break;
		default:
			return 0;
		}
		break;
#endif
	default:
		return 0;
	}

#ifdef AV530
	if (fuse != 0) {
		/* check IOFUSE register */
		if (badaddr(fuse, 1) != 0)
			return 0;

		/* check fuse status */
		return ISSET(*(volatile uint8_t *)fuse, AV530_IOFUSE_LAN);
	}
#endif

	return 1;
}

void
le_syscon_attach(struct device *parent, struct device *self, void *aux)
{
	struct le_softc *lesc = (struct le_softc *)self;
	struct lance_softc *sc = &lesc->u.sc_lance;
	struct confargs *ca = aux;
	u_int etherpages;
	struct pglist pglist;
	vm_page_t pg;
	int i, rc;
	paddr_t pa, pamask;
	vaddr_t va;
	int intsrc;
	uint8_t *enaddr;

	switch (cpuid) {
#ifdef AV530
	case AVIION_4600_530:
		lesc->sc_ilacc = 1;
		pamask = 0xffffffff;
		intsrc = ca->ca_paddr == AV530_LAN1 ?
		    INTSRC_ETHERNET1 : INTSRC_ETHERNET2;
		break;
#endif
	default:
		lesc->sc_ilacc = 0;
		pamask = 0x00ffffff;
		intsrc = INTSRC_ETHERNET1;
		break;
	}

	/*
	 * Allocate contiguous pages (in the first 16MB if not ILACC)
	 * to use as buffers. We aim towards 256KB, which is as much as
	 * the VME LANCE boards provide.
	 */
	if (physmem >= atop(32 * 1024 * 1024))
		etherpages = atop(256 * 1024);
	else if (physmem >= atop(16 * 1024 * 1024))
		etherpages = atop(128 * 1024);
	else
		etherpages = atop(64 * 1024);
	for (;;) {
		TAILQ_INIT(&pglist);
		rc = uvm_pglistalloc(ptoa(etherpages), 0, pamask,
		    0, 0, &pglist, 1, UVM_PLA_NOWAIT);
		if (rc == 0)
			break;

		etherpages >>= 1;
		if (etherpages <= 2) {
			printf(": no available memory, kernel is too large\n");
			return;
		}
	}

	va = uvm_km_valloc(kernel_map, ptoa(etherpages));
	if (va == 0) {
		printf(": can't map descriptor memory\n");
		uvm_pglistfree(&pglist);
		return;
	}

	pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));

	sc->sc_mem = (void *)va;
	sc->sc_addr = (u_long)pa & pamask;
	sc->sc_memsize = ptoa(etherpages);

	TAILQ_FOREACH(pg, &pglist, pageq) {
		pmap_enter(pmap_kernel(), va, pa,
		    PROT_READ | PROT_WRITE,
		    PROT_READ | PROT_WRITE | PMAP_WIRED);
		va += PAGE_SIZE;
		pa += PAGE_SIZE;
	}
	pmap_cache_ctrl((vaddr_t)sc->sc_mem,
	    (vaddr_t)sc->sc_mem + sc->sc_memsize, CACHE_INH);
	pmap_update(pmap_kernel());

	lesc->sc_r1 = (struct av_lereg *)ca->ca_paddr;

	/*
	 * Get the device Ethernet address.
	 */
	enaddr = sc->sc_arpcom.ac_enaddr;
	if (lesc->sc_ilacc) {
		for (i = 0; i < ETHER_ADDR_LEN; i++)
			enaddr[i] = lesc->sc_r1->enaddr[i] >> 24;
		/*
		 * If the checksum is invalid, don't trust the address,
		 * and force a hopefully unique one to be generated with
		 * ether_fakeaddr() at interface attachment time.
		 */
		if ((lesc->sc_r1->cksum[0] >> 24) !=
		    ((enaddr[0] + enaddr[2] + enaddr[4]) & 0xff) ||
		    (lesc->sc_r1->cksum[1] >> 24) !=
		    ((enaddr[1] + enaddr[3] + enaddr[5]) & 0xff))
			enaddr[0] = 0xff;
	} else
		myetheraddr(enaddr);

	sc->sc_conf3 = LE_C3_BSWP;

	sc->sc_copytodesc = lance_copytobuf_contig;
	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
	sc->sc_copytobuf = lance_copytobuf_contig;
	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
	sc->sc_zerobuf = lance_zerobuf_contig;

	sc->sc_rdcsr = le_syscon_rdcsr;
	sc->sc_wrcsr = le_syscon_wrcsr;
	sc->sc_hwreset = NULL;
	if (lesc->sc_ilacc)
		sc->sc_hwinit = le_syscon_hwinit_ilacc;
	else
		sc->sc_hwinit = NULL;

	if (lesc->sc_ilacc) {
		le_syscon_hwinit_ilacc(sc);
		am79900_config(&lesc->u.sc_am79900);
	} else
		am7990_config(&lesc->u.sc_am7990);

	if (lesc->sc_ilacc)
		lesc->sc_ih.ih_fn = le_syscon_intr_ilacc;
	else
		lesc->sc_ih.ih_fn = le_syscon_intr_lance;
	lesc->sc_ih.ih_arg = sc;
	lesc->sc_ih.ih_flags = 0;
	lesc->sc_ih.ih_ipl = IPL_NET;

	sysconintr_establish(intsrc, &lesc->sc_ih, self->dv_xname);
}

void
le_syscon_hwinit_ilacc(struct lance_softc *sc)
{
	le_syscon_wrcsr(sc, LE_CSR4,
	    LE_C4_DMAPLUS | LE_C4_UINT | LE_C4_TXSTRTM);
}

int
le_syscon_intr_ilacc(void *v)
{
	struct le_softc *lesc = (struct le_softc *)v;
	struct lance_softc *sc = &lesc->u.sc_lance;
	uint16_t csr4;

	/* Acknowledge TX start. XXX how to disable this? */
	csr4 = le_syscon_rdcsr(sc, LE_CSR4);
	if (csr4 & LE_C4_TXSTRT) {
		le_syscon_wrcsr(sc, LE_CSR4, csr4 | LE_C4_TXSTRTM);
		return 1;
	}

	return am79900_intr(v);
}

int
le_syscon_intr_lance(void *v)
{
	struct le_softc *lesc = (struct le_softc *)v;
	struct lance_softc *sc = &lesc->u.sc_lance;
	int rc;

	/*
	 * Syscon expects edge interrupts, while LANCE does level
	 * interrupts. To avoid missing interrupts while servicing,
	 * we disable further device interrupts while servicing.
	 *
	 * However, am7990_intr() will flip the interrupt enable bit
	 * itself; we override wrcsr with a specific version during
	 * servicing, so as not to reenable interrupts accidentally...
	 */
	sc->sc_wrcsr = le_syscon_wrcsr_interrupt;

	rc = am7990_intr(v);

	sc->sc_wrcsr = le_syscon_wrcsr;
	/*
	 * ...but we should not forget to reenable interrupts at this point!
	 */
	le_syscon_wrcsr(sc, LE_CSR0, LE_C0_INEA | le_syscon_rdcsr(sc, LE_CSR0));

	return rc;
}

uint16_t
le_syscon_rdcsr(struct lance_softc *sc, uint16_t port)
{
	struct av_lereg *ler1 = ((struct le_softc *)sc)->sc_r1;
	uint16_t val;

	ler1->ler1_rap = port;
	val = ler1->ler1_rdp;
	return val;
}

void
le_syscon_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
{
	struct av_lereg *ler1 = ((struct le_softc *)sc)->sc_r1;

	ler1->ler1_rap = port;
	ler1->ler1_rdp = val;
}

void
le_syscon_wrcsr_interrupt(struct lance_softc *sc, uint16_t port, uint16_t val)
{
	if (port == LE_CSR0)
		val &= ~LE_C0_INEA;

	le_syscon_wrcsr(sc, port, val);
}


code:
/*	$OpenBSD: if_le_vme.c,v 1.5 2014/12/22 02:26:53 tedu Exp $	*/

/*-
 * Copyright (c) 1982, 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)if_le.c	8.2 (Berkeley) 10/30/93
 */

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

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <net/if_media.h>

#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/cpu.h>

#include <dev/ic/lancereg.h>
#include <dev/ic/lancevar.h>
#include <dev/ic/am7990reg.h>
#include <dev/ic/am7990var.h>

#include <aviion/dev/if_le_vmereg.h>
#include <aviion/dev/vmevar.h>

struct	le_softc {
	struct am7990_softc	sc_am7990;	/* glue to MI code */

	bus_space_tag_t		sc_memt;	/* dual-ported memory access */
	bus_space_handle_t	sc_memh;

	bus_space_tag_t		sc_iot;		/* short io access */
	bus_space_handle_t	sc_ioh;

	struct intrhand		sc_ih;		/* interrupt vectoring */
	u_int			sc_csr;		/* CSR image */
	u_int			sc_ipl;
	u_int			sc_vec;
};

void  le_vme_attach(struct device *, struct device *, void *);
int   le_vme_match(struct device *, void *, void *);

struct cfattach le_vme_ca = {
	sizeof(struct le_softc), le_vme_match, le_vme_attach
};

void	le_vme_wrcsr(struct lance_softc *, uint16_t, uint16_t);
uint16_t le_vme_rdcsr(struct lance_softc *, uint16_t);
void	nvram_cmd(struct lance_softc *, u_int, u_int);
uint16_t nvram_read(struct lance_softc *, u_int);
void	le_vme_etheraddr(struct lance_softc *);
void	le_vme_init(struct lance_softc *);
void	le_vme_reset(struct lance_softc *);
int	le_vme_intr(void *);
#if 0
void	le_vme_copyfrombuf_contig(struct lance_softc *, void *, int, int);
void	le_vme_copytobuf_contig(struct lance_softc *, void *, int, int);
void	le_vme_zerobuf_contig(struct lance_softc *, int, int);
#endif

/* send command to the nvram controller */
void
nvram_cmd(struct lance_softc *sc, u_int cmd, u_int addr)
{
	struct le_softc *lesc = (void *)sc;
	int i;

	for (i = 0; i < 8; i++) {
		bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LEREG_EAR,
		    (cmd | (addr << 1)) >> i);
		CDELAY;
	}
}

/* read nvram one bit at a time */
uint16_t
nvram_read(struct lance_softc *sc, u_int nvram_addr)
{
	struct le_softc *lesc = (void *)sc;
	u_int val = 0, mask = 0x04000;
	uint16_t wbit;

	lesc->sc_csr = HW_RS | NVRAM_EN | 0x07;
	ENABLE_NVRAM;
	nvram_cmd(sc, NVRAM_RCL, 0);
	DISABLE_NVRAM;
	CDELAY;
	ENABLE_NVRAM;
	nvram_cmd(sc, NVRAM_READ, nvram_addr);
	for (wbit = 0; wbit < 15; wbit++) {
		if (bus_space_read_2(lesc->sc_iot, lesc->sc_ioh,
		    LEREG_EAR) & 0x01)
			val |= mask;
		else
			val &= ~mask;
		mask = mask >> 1;
		CDELAY;
	}
	if (bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LEREG_EAR) & 0x01)
		val |= 0x8000;
	else
		val &= 0x7fff;
	CDELAY;
	DISABLE_NVRAM;
	return (val);
}

void
le_vme_etheraddr(struct lance_softc *sc)
{
	u_char *cp = sc->sc_arpcom.ac_enaddr;
	uint16_t ival[3];
	int i;

	for (i = 0; i < 3; i++) {
		ival[i] = nvram_read(sc, i);
	}
	memcpy(cp, &ival[0], 6);
}

void
le_vme_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
{
	struct le_softc *lesc = (void *)sc;

	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LEREG_RAP, port);
	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LEREG_RDP, val);
}

uint16_t
le_vme_rdcsr(struct lance_softc *sc, uint16_t port)
{
	struct le_softc *lesc = (void *)sc;

	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LEREG_RAP, port);
	return (bus_space_read_2(lesc->sc_iot, lesc->sc_ioh, LEREG_RDP));
}

/* init board, set ipl and vec */
void
le_vme_init(struct lance_softc *sc)
{
	struct le_softc *lesc = (void *)sc;

	lesc->sc_csr = 0x4f;
	WRITE_CSR_AND(lesc->sc_ipl);
	SET_VEC(lesc->sc_vec);
	return;
}

/* board reset */
void
le_vme_reset(struct lance_softc *sc)
{
	struct le_softc *lesc = (void *)sc;

	RESET_HW;
#ifdef LEDEBUG
	if (sc->sc_debug)
		printf("%s: hardware reset\n", sc->sc_dev.dv_xname);
#endif
	SYSFAIL_CL;
}

int
le_vme_intr(void *arg)
{
	struct le_softc *lesc = arg;
	struct lance_softc *sc = &lesc->sc_am7990.lsc;
	int rc;

	rc = am7990_intr(sc);
	ENABLE_INTR;
	return (rc);
}

#if 0
void
le_vme_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
{
	struct le_softc *lesc = (void *)sc;

	bus_space_write_region_1(lesc->sc_memt, lesc->sc_memh, boff, from, len);
}

void
le_vme_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
{
	struct le_softc *lesc = (void *)sc;

	bus_space_read_region_1(lesc->sc_memt, lesc->sc_memh, boff, to, len);
}

void
le_vme_zerobuf_contig(struct lance_softc *sc, int boff, int len)
{
	struct le_softc *lesc = (void *)sc;

	bus_space_set_region_1(lesc->sc_memt, lesc->sc_memh, boff, 0, len);
}
#endif

int
le_vme_match(struct device *parent, void *vcf, void *args)
{
	struct vme_attach_args *vaa = args;
	bus_space_tag_t iot, memt;
	bus_space_handle_t ioh;
	int rc;

	/* we expect a32 and a16 locators */
	if (vaa->vaa_addr_a16 == (vme_addr_t)-1 ||
	    vaa->vaa_addr_a32 == (vme_addr_t)-1)
		return (0);

	/* check the dual ported memory */
	if (vmebus_get_bst(parent, VME_A32, VME_D32, &memt) != 0)
		return (0);
	if (bus_space_map(memt, vaa->vaa_addr_a32, PAGE_SIZE, 0, &ioh) != 0)
		return (0);
	rc = badaddr((vaddr_t)bus_space_vaddr(memt, ioh), 2);
	bus_space_unmap(memt, ioh, PAGE_SIZE);
	vmebus_release_bst(parent, memt);

	/* check the control space */
	if (vmebus_get_bst(parent, VME_A16, VME_D16, &iot) != 0)
		return (0);
	if (bus_space_map(iot, vaa->vaa_addr_a16, PAGE_SIZE, 0, &ioh) != 0)
		return (0);
	rc |= badaddr((vaddr_t)bus_space_vaddr(iot, ioh), 2);
	bus_space_unmap(iot, ioh, PAGE_SIZE);
	vmebus_release_bst(parent, iot);

	return (rc == 0);
}

void
le_vme_attach(struct device *parent, struct device *self, void *aux)
{
	struct le_softc *lesc = (struct le_softc *)self;
	struct lance_softc *sc = &lesc->sc_am7990.lsc;
	struct vme_attach_args *vaa = aux;

	/*
	 * Allocate an interrupt vector.
	 */
	lesc->sc_ipl = vaa->vaa_ipl == 0 ? IPL_NET : vaa->vaa_ipl;
	if (vmeintr_allocate(1, VMEINTR_ANY | VMEINTR_SHARED, lesc->sc_ipl,
	    &lesc->sc_vec) != 0) {
		printf(": no more interrupts!\n");
		return;
	}
	printf(" vec %x", lesc->sc_vec);

	/*
	 * Map the dual-ported memory.
	 */
	if (vmebus_get_bst(parent, VME_A32, VME_D32, &lesc->sc_memt) != 0) {
		printf(": can't map memory\n");
		return;
	}
	if (bus_space_map(lesc->sc_memt, vaa->vaa_addr_a32, VLEMEMSIZE,
	    BUS_SPACE_MAP_LINEAR, &lesc->sc_memh) != 0) {
		printf(": can't map memory\n");
		goto fail3;
	}

	/*
	 * Map the control space.
	 */
	if (vmebus_get_bst(parent, VME_A16, VME_D16, &lesc->sc_iot) != 0) {
		printf(": can't map registers\n");
		goto fail2;
	}
	if (bus_space_map(lesc->sc_iot, vaa->vaa_addr_a16, PAGE_SIZE,
	    0, &lesc->sc_ioh) != 0) {
		printf(": can't map registers\n");
		goto fail1;
	}

	sc->sc_mem = (void *)bus_space_vaddr(lesc->sc_memt, lesc->sc_memh);
	sc->sc_memsize = VLEMEMSIZE;
	sc->sc_addr = vaa->vaa_addr_a32 & 0x00ffffff;
	sc->sc_conf3 = LE_C3_BSWP;
	sc->sc_hwreset = le_vme_reset;
	sc->sc_rdcsr = le_vme_rdcsr;
	sc->sc_wrcsr = le_vme_wrcsr;
	sc->sc_hwinit = le_vme_init;
#if 0
	sc->sc_copytodesc = le_vme_copytobuf_contig;
	sc->sc_copyfromdesc = le_vme_copyfrombuf_contig;
	sc->sc_copytobuf = le_vme_copytobuf_contig;
	sc->sc_copyfrombuf = le_vme_copyfrombuf_contig;
	sc->sc_zerobuf = le_vme_zerobuf_contig;
#else
	sc->sc_copytodesc = lance_copytobuf_contig;
	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
	sc->sc_copytobuf = lance_copytobuf_contig;
	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
	sc->sc_zerobuf = lance_zerobuf_contig;
#endif

	/* get Ethernet address */
	le_vme_etheraddr(sc);

	am7990_config(&lesc->sc_am7990);

	/* connect the interrupt */
	lesc->sc_ih.ih_fn = le_vme_intr;
	lesc->sc_ih.ih_arg = sc;
	lesc->sc_ih.ih_flags = 0;
	lesc->sc_ih.ih_ipl = lesc->sc_ipl;
	vmeintr_establish(lesc->sc_vec, &lesc->sc_ih, self->dv_xname);

	return;

fail1:
	vmebus_release_bst(parent, lesc->sc_iot);
fail2:
	bus_space_unmap(lesc->sc_memt, lesc->sc_memh, VLEMEMSIZE);
fail3:
	vmebus_release_bst(parent, lesc->sc_memt);
}


code:
/*	$OpenBSD: if_le_vmereg.h,v 1.1.1.1 2006/05/09 18:25:00 miod Exp $ */

/*-
 * Copyright (c) 1982, 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * @(#)if_lereg.h	8.2 (Berkeley) 10/30/93
 */

#define	VLEMEMSIZE	0x00040000	/* 256 KB */

/*
 * LANCE registers for Interphase 3207 Hawk
 */

#define	LEREG_CSR	0x00
#define	LEREG_VEC	0x02
#define	LEREG_RDP	0x04
#define	LEREG_RAP	0x06
#define	LEREG_EAR	0x08

/* CSR bits */
#define	NVRAM_EN	0x0008	/* NVRAM enable bit (active low) */
#define	INTR_EN		0x0010	/* interrupt enable bit (active low) */
#define	PARITYB		0x0020	/* parity error clear bit */
#define	HW_RS		0x0040	/* hardware reset bit (active low) */
#define	SYSFAILB	0x0080	/* SYSFAIL bit */

#define	NVRAM_RWEL	0xe0	/* Reset write enable latch      */
#define	NVRAM_STO	0x60	/* Store ram to eeprom           */
#define	NVRAM_SLP	0xa0	/* Novram into low power mode    */
#define	NVRAM_WRITE	0x20	/* Writes word from location x   */
#define	NVRAM_SWEL	0xc0	/* Set write enable latch        */
#define	NVRAM_RCL	0x40	/* Recall eeprom data into ram   */
#define	NVRAM_READ	0x00	/* Reads word from location x    */

#define	CDELAY		delay(10000)
#define	WRITE_CSR_OR(x) \
	do { \
		lesc->sc_csr |= (x); \
		bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, \
		    LEREG_CSR, lesc->sc_csr); \
	} while (0)
#define	WRITE_CSR_AND(x) \
	do { \
		lesc->sc_csr &= ~(x); \
		bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, \
		    LEREG_CSR, lesc->sc_csr); \
	} while (0)
#define	ENABLE_NVRAM	WRITE_CSR_AND(NVRAM_EN)
#define	DISABLE_NVRAM	WRITE_CSR_OR(NVRAM_EN)
#define	ENABLE_INTR	WRITE_CSR_AND(INTR_EN)
#define	DISABLE_INTR	WRITE_CSR_OR(INTR_EN)
#define	RESET_HW \
	do { \
		WRITE_CSR_AND(HW_RS); \
		CDELAY; \
	} while (0)
#define	SET_VEC(x) \
	bus_space_write_2(lesc->sc_iot, lesc->sc_ioh, LEREG_VEC, (x))
#define	SYSFAIL_CL	WRITE_CSR_AND(SYSFAILB)


code:
/*	$OpenBSD: mainbus.c,v 1.8 2014/05/08 22:17:33 miod Exp $ */
/*
 * Copyright (c) 1998 Steve Murphree, Jr.
 * Copyright (c) 2004, Miodrag Vallat.
 *
 * 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.
 *
 * 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/reboot.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/extent.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/prom.h>

void	mainbus_attach(struct device *, struct device *, void *);
int 	mainbus_match(struct device *, void *, void *);
int	mainbus_print(void *, const char *);
int	mainbus_scan(struct device *, void *, void *);

/*
 * bus_space routines for 1:1 obio mappings
 */

int	mainbus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
void	mainbus_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
int	mainbus_subregion(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    bus_size_t, bus_space_handle_t *);
void	*mainbus_vaddr(bus_space_tag_t, bus_space_handle_t);

const struct aviion_bus_space_tag mainbus_bustag = {
	._space_map = mainbus_map,
	._space_unmap = mainbus_unmap,
	._space_subregion = mainbus_subregion,
	._space_vaddr = mainbus_vaddr,
	._space_read_1 = generic_space_read_1,
	._space_write_1 = generic_space_write_1,
	._space_read_2 = generic_space_read_2,
	._space_write_2 = generic_space_write_2,
	._space_read_4 = generic_space_read_4,
	._space_write_4 = generic_space_write_4,
	._space_read_raw_2 = generic_space_read_raw_2,
	._space_write_raw_2 = generic_space_write_raw_2,
	._space_read_raw_4 = generic_space_read_raw_4,
	._space_write_raw_4 = generic_space_write_raw_4,
};

/*
 * Obio (internal IO) space is mapped 1:1 (see pmap_bootstrap() for details).
 */

int
mainbus_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, int flags,
    bus_space_handle_t *ret)
{
	*ret = (bus_space_handle_t)addr;
	return 0;
}

void
mainbus_unmap(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
{
	/* nothing to do */
}

int
mainbus_subregion(bus_space_tag_t tag, bus_space_handle_t handle,
    bus_addr_t offset, bus_size_t size, bus_space_handle_t *ret)
{
	*ret = handle + offset;
	return (0);
}

void *
mainbus_vaddr(bus_space_tag_t tag, bus_space_handle_t handle)
{
	return (void *)handle;
}

/*
 * Configuration glue
 */

struct cfattach mainbus_ca = {
	sizeof(struct device), mainbus_match, mainbus_attach
};

struct cfdriver mainbus_cd = {
	NULL, "mainbus", DV_DULL
};

int
mainbus_match(struct device *parent, void *cf, void *args)
{
	return (mainbus_cd.cd_ndevs == 0);
}

void
mainbus_attach(struct device *parent, struct device *self, void *args)
{
	extern void cpu_setup_secondary_processors(void);
	extern char cpu_model[];

	printf(": %s, cpuid 0x%04x", cpu_model, cpuid);
	printf("\n");

	/*
	 * Display cpu/mmu details for the main processor.
	 */
	cpu_configuration_print(1);

#ifdef MULTIPROCESSOR
	/*
	 * Let secondary processors initialize further and print
	 * their configuration information now.
	 */
	cpu_setup_secondary_processors();
#endif

	(void)config_search(mainbus_scan, self, args);
}

int
mainbus_scan(struct device *parent, void *child, void *args)
{
	struct cfdata *cf = child;
	struct confargs oca;

	oca.ca_iot = &mainbus_bustag;
	oca.ca_paddr = (paddr_t)cf->cf_loc[0];
	oca.ca_offset = (paddr_t)-1;
	oca.ca_ipl = (u_int)-1;

	if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0)
		return (0);

	config_attach(parent, cf, &oca, mainbus_print);
	return (1);
}

int
mainbus_print(void *args, const char *bus)
{
	struct confargs *ca = args;

	if (ca->ca_paddr != (paddr_t)-1)
		printf(" addr 0x%08lx", ca->ca_paddr);
	return (UNCONF);
}


code:
/*	$OpenBSD: nvram.c,v 1.12 2015/06/13 07:16:36 jsg Exp $ */

/*
 * Copyright (c) 1995 Theo de Raadt
 *
 * 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.
 *
 * 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/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/timetc.h>

#include <machine/autoconf.h>
#include <machine/conf.h>
#include <machine/cpu.h>
#include <machine/mioctl.h>
#include <machine/psl.h>
#include <machine/vmparam.h>

#include <uvm/uvm_param.h>

#include <aviion/dev/nvramreg.h>

struct nvramsoftc {
	struct device           sc_dev;
	paddr_t			sc_base;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	bus_addr_t		sc_regs;
	size_t			sc_len;
	u_int8_t		*sc_nvram;
};

void    nvramattach(struct device *, struct device *, void *);
int     nvrammatch(struct device *, void *, void *);

struct cfattach nvram_ca = {
	sizeof(struct nvramsoftc), nvrammatch, nvramattach
};

struct cfdriver nvram_cd = {
	NULL, "nvram", DV_DULL
};

time_t	chiptotime(int, int, int, int, int, int);
int	nvramrw(caddr_t, size_t, struct uio *, int);

int
nvrammatch(parent, vcf, args)
	struct device *parent;
	void *vcf, *args;
{
	struct confargs *ca = args;
	bus_space_handle_t ioh;
	int rc;

	if (bus_space_map(ca->ca_iot, ca->ca_paddr, PAGE_SIZE, 0, &ioh) != 0)
		return (0);
	rc = badaddr((vaddr_t)bus_space_vaddr(ca->ca_iot, ioh), 1) == 0;
	bus_space_unmap(ca->ca_iot, ioh, PAGE_SIZE);
	return (rc);
}

void
nvramattach(parent, self, args)
	struct device *parent, *self;
	void *args;
{
	struct confargs *ca = args;
	struct nvramsoftc *sc = (struct nvramsoftc *)self;
	bus_space_handle_t ioh;
	vsize_t maplen;

	sc->sc_len = MK48T02_SIZE;
	sc->sc_regs = AV_NVRAM_TOD_OFF;

	sc->sc_iot = ca->ca_iot;
	sc->sc_base = ca->ca_paddr;

	/*
	 * The NK48T02 is mapped as one byte per longword,
	 * thus spans four times as much address space.
	 */
	maplen = sc->sc_len * 4;

	if (bus_space_map(sc->sc_iot, sc->sc_base, round_page(maplen),
	    BUS_SPACE_MAP_LINEAR, &ioh) != 0) {
		printf(": can't map memory!\n");
		return;
	}

	sc->sc_ioh = ioh;

	printf(": MK48T0%zu\n", sc->sc_len / 1024);
}

#define	LEAPYEAR(y)	(((y) & 3) == 0)

/*
 * This code is defunct after 2068.
 * Will Unix still be here then??
 */
const int dayyr[12] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

time_t
chiptotime(sec, min, hour, day, mon, year)
	int sec, min, hour, day, mon, year;
{
	int days, yr;

	sec = FROMBCD(sec);
	min = FROMBCD(min);
	hour = FROMBCD(hour);
	day = FROMBCD(day);
	mon = FROMBCD(mon);
	year = FROMBCD(year) + YEAR0;

	/* simple sanity checks */
	if (year>164 || mon<1 || mon>12 || day<1 || day>31)
		return (0);
	yr = 70;
	days = 0;

	if (year < 70) {		/* 2000 <= year */
		for (; yr < 100; yr++)	/* deal with first 30 years */
			days += LEAPYEAR(yr) ? 366 : 365;
		yr = 0;
	}

	for (; yr < year; yr++)	/* deal with years left */
		days += LEAPYEAR(yr) ? 366 : 365;

	days += dayyr[mon - 1] + day - 1;

	if (LEAPYEAR(yr) && mon > 2)
		days++;

	/* now have days since Jan 1, 1970; the rest is easy... */
	return ((time_t)days * SECDAY + hour * 3600 + min * 60 + sec);
}

struct chiptime {
	int     sec;
	int     min;
	int     hour;
	int     wday;
	int     day;
	int     mon;
	int     year;
};

void timetochip(struct chiptime *c);

void
timetochip(c)
	struct chiptime *c;
{
	time_t t2, now = time_second;
	int t, t3;

	/* January 1 1970 was a Thursday (4 in unix wdays) */
	/* compute the days since the epoch */
	t2 = now / SECDAY;

	t3 = (t2 + 4) % 7;	/* day of week */
	c->wday = TOBCD(t3 + 1);

	/* compute the year */
	t = 69;
	while (t2 >= 0) {	/* whittle off years */
		t3 = t2;
		t++;
		t2 -= LEAPYEAR(t) ? 366 : 365;
	}
	c->year = t;

	/* t3 = month + day; separate */
	t = LEAPYEAR(t);
	for (t2 = 1; t2 < 12; t2++)
		if (t3 < (dayyr[t2] + ((t && (t2 > 1)) ? 1:0)))
			break;

	/* t2 is month */
	c->mon = t2;
	c->day = t3 - dayyr[t2 - 1] + 1;
	if (t && t2 > 2)
		c->day--;

	/* the rest is easy */
	t = now % SECDAY;
	c->hour = t / 3600;
	t %= 3600;
	c->min = t / 60;
	c->sec = t % 60;

	c->sec = TOBCD(c->sec);
	c->min = TOBCD(c->min);
	c->hour = TOBCD(c->hour);
	c->day = TOBCD(c->day);
	c->mon = TOBCD(c->mon);
	c->year = TOBCD((c->year - YEAR0) % 100);
}

/*
 * Set up the system's time, given a `reasonable' time value.
 */

void
inittodr(base)
	time_t base;
{
	struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
	int sec, min, hour, day, mon, year;
	int badbase = 0, waszero = base == 0;
	struct timespec ts;

	ts.tv_sec = ts.tv_nsec = 0;

	if (base < 36 * SECYR) { /* this code did not exist until 2006 */
		/*
		 * If base is 0, assume filesystem time is just unknown
		 * in stead of preposterous. Don't bark.
		 */
		if (base != 0)
			printf("WARNING: preposterous time in file system\n");
		/* not going to use it anyway, if the chip is readable */
		base = 36 * SECYR + 109 * SECDAY + 22 * 3600;
		badbase = 1;
	}

	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_CSR << 2), CLK_READ |
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	      sc->sc_regs + (CLK_CSR << 2)));
	sec = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_SEC << 2)) & 0xff;
	min = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_MIN << 2)) & 0xff;
	hour = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_HOUR << 2)) & 0xff;
	day = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_DAY << 2)) & 0xff;
	mon = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_MONTH << 2)) & 0xff;
	year = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_YEAR << 2)) & 0xff;
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_CSR << 2),
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	      sc->sc_regs + (CLK_CSR << 2)) & ~CLK_READ);

	if ((ts.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
		printf("WARNING: bad date in nvram");
#ifdef DEBUG
		printf("\nday = %d, mon = %d, year = %d, hour = %d, min = %d, sec = %d",
		       FROMBCD(day), FROMBCD(mon), FROMBCD(year) + YEAR0,
		       FROMBCD(hour), FROMBCD(min), FROMBCD(sec));
#endif
		/*
		 * Believe the time in the file system for lack of
		 * anything better, resetting the clock.
		 */
		ts.tv_sec = base;
		if (!badbase)
			resettodr();
	} else {
		int deltat = ts.tv_sec - base;

		if (deltat < 0)
			deltat = -deltat;
		if (waszero || deltat < 2 * SECDAY)
			goto done;
		printf("WARNING: clock %s %ld days",
		       ts.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
	}
	printf(" -- CHECK AND RESET THE DATE!\n");
done:
	tc_setclock(&ts);
}

/*
 * Reset the clock based on the current time.
 * Used when the current clock is preposterous, when the time is changed,
 * and when rebooting.  Do nothing if the time is not yet known, e.g.,
 * when crashing during autoconfig.
 */
void
resettodr()
{
	struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0];
	struct chiptime c;

	if (time_second == 1 || sc == NULL)
		return;
	timetochip(&c);

	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_CSR << 2), CLK_WRITE |
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	      sc->sc_regs + (CLK_CSR << 2)));
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_SEC << 2), c.sec);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_MIN << 2), c.min);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_HOUR << 2), c.hour);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_WDAY << 2), c.wday);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_DAY << 2), c.day);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_MONTH << 2), c.mon);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_YEAR << 2), c.year);
	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
	    sc->sc_regs + (CLK_CSR << 2),
	    bus_space_read_4(sc->sc_iot, sc->sc_ioh,
	      sc->sc_regs + (CLK_CSR << 2)) & ~CLK_WRITE);
}

/*ARGSUSED*/
int
nvramopen(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	if (minor(dev) >= nvram_cd.cd_ndevs ||
	    nvram_cd.cd_devs[minor(dev)] == NULL)
		return (ENODEV);

	return (0);
}

/*ARGSUSED*/
int
nvramclose(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	/*
	 * It might be worth free()ing the NVRAM copy here.
	 */
	return (0);
}

/*ARGSUSED*/
int
nvramioctl(dev, cmd, data, flag, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flag;
	struct proc *p;
{
	int unit = minor(dev);
	struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
	int error = 0;

	switch (cmd) {
	case MIOCGSIZ:
		*(int *)data = sc->sc_len;
		break;
	default:
		error = ENOTTY;
		break;
	}
	return (error);
}

paddr_t
nvrammmap(dev, off, prot)
	dev_t dev;
	off_t off;
	int prot;
{
#if 0
	int unit = minor(dev);
	struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];

	if (minor(dev) != 0)
		return (-1);

	/* allow access only in RAM */
	if (off < 0 || off >= round_page(sc->sc_len))
		return (-1);
	return (sc->sc_base + off);
#else
	/* disallow mmap due to non-linear layout */
	return (-1);
#endif
}

int	read_nvram(struct nvramsoftc *);

/*
 * Build a local copy of the NVRAM contents.
 */
int
read_nvram(struct nvramsoftc *sc)
{
	u_int cnt;
	u_int8_t *dest;
	u_int32_t *src;

	if (sc->sc_nvram == NULL) {
		sc->sc_nvram = (u_int8_t *)malloc(sc->sc_len, M_DEVBUF,
		    M_WAITOK | M_CANFAIL);
		if (sc->sc_nvram == NULL)
			return (EAGAIN);
	}

	dest = sc->sc_nvram;
	src = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
	cnt = sc->sc_len;
	while (cnt-- != 0)
		*dest++ = (u_int8_t)*src++;

	return (0);
}

/*ARGSUSED*/
int
nvramrw(caddr_t base, size_t len, struct uio *uio, int flags)
{
	vaddr_t v;
	size_t c;
	struct iovec *iov;
	int error = 0;

	if (uio->uio_offset < 0)
		return EINVAL;

	while (uio->uio_resid > 0 && error == 0) {
		iov = uio->uio_iov;
		if (iov->iov_len == 0) {
			uio->uio_iov++;
			uio->uio_iovcnt--;
#ifdef DIAGNOSTIC
			if (uio->uio_iovcnt < 0)
			 	panic("nvramrw");
#endif
			continue;
		}

		v = uio->uio_offset;
		if (v <= len) {
			c = ulmin(iov->iov_len, MAXPHYS);
			if (c > len - v)
				c = len - v;	/* till end of dev */
		} else
			c = 0;
		if (c == 0)
			return (0);
		error = uiomove(base + v, c, uio);
	}
	return (error);
}

int
nvramread(dev_t dev, struct uio *uio, int flags)
{
	int unit = minor(dev);
	struct nvramsoftc *sc = (struct nvramsoftc *)nvram_cd.cd_devs[unit];
	int rc;

	/*
	 * Get a copy of the NVRAM contents.
	 */
	rc = read_nvram(sc);
	if (rc != 0)
		return (rc);

	/*
	 * Move data from our NVRAM copy to the user.
	 */
	return (nvramrw(sc->sc_nvram, sc->sc_len, uio, flags));
}

int
nvramwrite(dev_t dev, struct uio *uio, int flags)
{
	int unit = minor(dev);
	struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[unit];
	u_int cnt;
	u_int8_t *src;
	u_int32_t *dest;
	int rc;

	/*
	 * Get a copy of the NVRAM contents.
	 */
	rc = read_nvram(sc);
	if (rc != 0)
		return (rc);

	/*
	 * Move data from the user to our NVRAM copy.
	 */
	rc = nvramrw(sc->sc_nvram, sc->sc_len, uio, flags);
	if (rc != 0) {
		/* reset NVRAM copy contents */
		read_nvram(sc);
		return (rc);
	}

	/*
	 * Update the NVRAM. This could be optimized by only working on
	 * the areas which have been modified by the user.
	 */
	src = sc->sc_nvram;
	dest = (u_int32_t *)bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
	cnt = sc->sc_len;
	while (cnt-- != 0) {
		if ((*dest & 0xff) != *src) {
			*dest = (u_int32_t)*src;
			/*
			 * A jumper on the motherboard may write-protect
			 * the 0x80 bytes at offset 0x80 (i.e. addresses
			 * 0x200-0x3ff), so check our write had successed.
			 * If it failed, discard the remainder of the changes
			 * and return EROFS.
			 */
			if ((*dest & 0xff) != *src)
				rc = EROFS;
		}
		dest++;
		src++;
	}

	if (rc != 0) {
		/* reset NVRAM copy contents */
		read_nvram(sc);
	}

	return (rc);
}


code:
/*	$OpenBSD: nvramreg.h,v 1.3 2007/04/10 17:47:54 miod Exp $ */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * 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. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)clockreg.h	8.1 (Berkeley) 6/11/93
 */

/*
 * Mostek TOD clock/NVRAM
 */

/*
 * Mostek MK48T08 clock.
 *
 * This chip is 8k in size.
 * The first TOD clock starts at offset 0x1FF8. The following structure
 * describes last 2K of its 8K address space. The first 6K of the NVRAM
 * space is used for various things as follows:
 * 	0000-0fff	User Area
 *	1000-10ff	Networking Area
 *	1100-16f7	Operating System Area
 *	16f8-1ef7	ROM Debugger Area
 *	1ef8-1ff7	Configuration Area (Ethernet address etc)
 *	1ff8-1fff	TOD clock
 */

/*
 * On the AViiON, these offsets need shifting two bits, as they are 32 bit
 * registers.
 */
#define	CLK_CSR		0		/* control register */
#define	CLK_SEC		1		/* seconds (0..59; BCD) */
#define	CLK_MIN		2		/* minutes (0..59; BCD) */
#define	CLK_HOUR	3		/* hour (0..23; BCD) */
#define	CLK_WDAY	4		/* weekday (1..7) */
#define	CLK_DAY		5		/* day in month (1..31; BCD) */
#define	CLK_MONTH	6		/* month (1..12; BCD) */
#define	CLK_YEAR	7		/* year (0..99; BCD) */
#define	CLK_NREG	8

/* csr bits */
#define	CLK_WRITE	0x80		/* want to write */
#define	CLK_READ	0x40		/* want to read (freeze clock) */

/*
 * Data General, following Motorola, chose the year `1900' as their base count.
 * It has already wrapped by now...
 */
#define	YEAR0	00

#define AV_NVRAM_TOD_OFF	0x1fe0 /* offset of tod in NVRAM space */
#define MK48T02_SIZE	2 * 1024


code:
/*	$OpenBSD: oaic_syscon.c,v 1.2 2013/10/23 10:07:14 miod Exp $	*/

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * 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.
 */

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

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/av400.h>

#include <aviion/dev/sysconvar.h>

#include <dev/ic/aic6250reg.h>
#include <dev/ic/aic6250var.h>
#if 0
#include <aviion/dev/dmavar.h>
#endif

int	oaic_syscon_match(struct device *, void *, void *);
void	oaic_syscon_attach(struct device *, struct device *, void *);

struct oaic_syscon_softc {
	struct aic6250_softc	sc_base;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	struct intrhand		sc_ih;
#if 0
	uint8_t			sc_dmac;
#endif
};

const struct cfattach oaic_syscon_ca = {
	sizeof(struct oaic_syscon_softc),
	oaic_syscon_match, oaic_syscon_attach
};

uint8_t	oaic_read(struct aic6250_softc *, uint);
void	oaic_write(struct aic6250_softc *, uint, uint8_t);

#if 0
int	oaic_dmastart(struct aic6250_softc *, void *, size_t, int);
int	oaic_dmadone(struct aic6250_softc *);
void	oaic_dmago(void *);
void	oaic_dmastop(void *);
#endif

int
oaic_syscon_match(struct device *parent, void *match, void *aux)
{
	struct confargs *ca = aux;

	switch (cpuid) {
#ifdef AV400
	case AVIION_300_310:
	case AVIION_400_4000:
	case AVIION_410_4100:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
	case AVIION_4300_25:
	case AVIION_4300_20:
	case AVIION_4300_16:
		switch (ca->ca_paddr) {
		case AV400_SCSI:
			break;
		default:
			return 0;
		}
		break;
#endif
	default:
		return 0;
	}

	return 1;
}

void
oaic_syscon_attach(struct device *parent, struct device *self, void *aux)
{
	struct oaic_syscon_softc *ssc = (struct oaic_syscon_softc *)self;
	struct aic6250_softc *sc = (struct aic6250_softc *)self;
	struct confargs *ca = aux;
	bus_space_handle_t ioh;
	int intsrc;

	if (bus_space_map(ca->ca_iot, ca->ca_paddr, AIC_NREG << 2, 0,
	    &ioh) != 0) {
		printf(": can't map registers\n");
		return;
	}
	ssc->sc_iot = ca->ca_iot;
	ssc->sc_ioh = ioh;

	/*
	 * Do NOT ask any question about this.
	 */
	*(volatile uint32_t *)0xfff840c0 = 0x6e;

	/*
	 * According to the hardware manual (chapter 10 ``Programming the
	 * Small Computer System Interface'', page 10-2), the ``Clock
	 * Frequency Mode'' bit in control register #1 must be clear. This
	 * hints the AIC6250 runs at 10MHz.
	 */
	sc->sc_freq = 10;
	sc->sc_initiator = 7;

	/* port A is an output port, single-ended mode */
	sc->sc_cr0 = AIC_CR0_EN_PORT_A;
	/* port B used as the upper 8 bits of the 16-bit DMA path */
	sc->sc_cr1 = AIC_CR1_ENABLE_16BIT_MEM_BUS;

	sc->sc_read = oaic_read;
	sc->sc_write = oaic_write;

#if 0
	sc->sc_dma_start = oaic_dmastart;
	sc->sc_dma_done = oaic_dmadone;
#endif

	aic6250_attach(sc);

	ssc->sc_ih.ih_fn = (int(*)(void *))aic6250_intr;
	ssc->sc_ih.ih_arg = sc;
	ssc->sc_ih.ih_flags = 0;
	ssc->sc_ih.ih_ipl = IPL_BIO;
	intsrc = INTSRC_SCSI1;
	sysconintr_establish(intsrc, &ssc->sc_ih, self->dv_xname);
}

uint8_t
oaic_read(struct aic6250_softc *sc, uint reg)
{
	struct oaic_syscon_softc *ssc = (struct oaic_syscon_softc *)sc;
	uint32_t rc;

	rc = bus_space_read_4(ssc->sc_iot, ssc->sc_ioh, reg << 2);
	return rc & 0xff;
}

void
oaic_write(struct aic6250_softc *sc, uint reg, uint8_t val)
{
	struct oaic_syscon_softc *ssc = (struct oaic_syscon_softc *)sc;

	bus_space_write_4(ssc->sc_iot, ssc->sc_ioh, reg << 2, val);
}

#if 0
int
oaic_dmastart(struct aic6250_softc *sc, void *addr, size_t size, int datain)
{
	struct oaic_syscon_softc *osc = (struct oaic_syscon_softc *)sc;
	char *vaddr = (char *)addr;

	/*
	 * The DMA engine can only operate on 16-bit words.
	 */
	if (size & 1)
		return EINVAL;

	osc->sc_dmac = AIC_DC_DMA_XFER_EN | (datain ? 0 : AIC_DC_TRANSFER_DIR);
	if ((vaddr_t)vaddr & 1) {
		if (datain) {
			/*
			 * The AIC_DC_ODD_XFER_START bit ought to have been
			 * set before changing phase to DATA IN.
			 */
			return EINVAL;
		}
		vaddr--;
		osc->sc_dmac |= AIC_DC_ODD_XFER_START;
	}

	return dma_req(vaddr, size,
	    datain ? DMADIR_FROM_DEVICE : DMADIR_TO_DEVICE,
	    oaic_dmago, oaic_dmastop, sc);
}

void
oaic_dmago(void *v)
{
	struct aic6250_softc *sc = (struct aic6250_softc *)v;
	struct oaic_syscon_softc *osc = (struct oaic_syscon_softc *)sc;

	sc->sc_flags |= AIC_DOINGDMA;

	oaic_write(sc, AIC_DMA_BYTE_COUNT_H, sc->sc_dleft >> 16);
	oaic_write(sc, AIC_DMA_BYTE_COUNT_M, sc->sc_dleft >> 8);
	oaic_write(sc, AIC_DMA_BYTE_COUNT_L, sc->sc_dleft);
	oaic_write(sc, AIC_DMA_CNTRL, osc->sc_dmac);
}

void
oaic_dmastop(void *v)
{
	struct aic6250_softc *sc = (struct aic6250_softc *)v;

	sc->sc_flags &= ~AIC_DOINGDMA;
}

int
oaic_dmadone(struct aic6250_softc *sc)
{
	int resid;

	resid = oaic_read(sc, AIC_DMA_BYTE_COUNT_H) << 16 |
	    oaic_read(sc, AIC_DMA_BYTE_COUNT_M) << 8 |
	    oaic_read(sc, AIC_DMA_BYTE_COUNT_L);

	sc->sc_dp += sc->sc_dleft - resid;
	sc->sc_dleft = resid;

	return 0;
}
#endif


code:
/*	$OpenBSD: oosiop_syscon.c,v 1.5 2013/09/16 16:30:51 miod Exp $	*/

/*
 * Copyright (c) 2010 Miodrag Vallat.
 *
 * 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.
 */

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

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/av530.h>

#include <aviion/dev/sysconvar.h>

#include <dev/ic/oosiopreg.h>
#include <dev/ic/oosiopvar.h>

int	oosiop_syscon_match(struct device *, void *, void *);
void	oosiop_syscon_attach(struct device *, struct device *, void *);

struct oosiop_syscon_softc {
	struct oosiop_softc	sc_base;
	struct intrhand		sc_ih;
};

const struct cfattach oosiop_syscon_ca = {
	sizeof(struct oosiop_syscon_softc),
	oosiop_syscon_match, oosiop_syscon_attach
};

int
oosiop_syscon_match(struct device *parent, void *match, void *aux)
{
	struct confargs *ca = aux;
	paddr_t fuse;

	switch (cpuid) {
	case AVIION_4600_530:
		break;
	default:
		return 0;
	}

	switch (ca->ca_paddr) {
	case AV530_SCSI1:
		fuse = AV530_IOFUSE0;
		break;
	case AV530_SCSI2:
		fuse = AV530_IOFUSE1;
		break;
	default:
		return 0;
	}

	/* check IOFUSE register */
	if (badaddr(fuse, 1) != 0)
		return 0;

	/* check fuse status */
	return ISSET(*(volatile uint8_t *)fuse, AV530_IOFUSE_SCSI);
}

void
oosiop_syscon_attach(struct device *parent, struct device *self, void *aux)
{
	struct oosiop_syscon_softc *ssc = (struct oosiop_syscon_softc *)self;
	struct oosiop_softc *sc = (struct oosiop_softc *)self;
	struct confargs *ca = aux;
	bus_space_handle_t ioh;
	int intsrc;

	if (bus_space_map(ca->ca_iot, ca->ca_paddr, OOSIOP_NREGS, 0,
	    &ioh) != 0) {
		printf(": can't map registers\n");
		return;
	}
	sc->sc_bst = ca->ca_iot;
	sc->sc_bsh = ioh;
	sc->sc_dmat = 0;	/* no real use of tag yet */

	sc->sc_freq = 33333333;	/* XXX 25MHz models? */
	sc->sc_chip = OOSIOP_700;
	sc->sc_id = 7;		/* XXX */

	sc->sc_scntl0 = OOSIOP_SCNTL0_EPC | OOSIOP_SCNTL0_EPG;
	sc->sc_dmode = OOSIOP_DMODE_BL_4;
	sc->sc_dwt = 0x4f;	/* maximum DMA timeout allowable */
	sc->sc_ctest7 = OOSIOP_CTEST7_DC;

	oosiop_attach(sc);

	ssc->sc_ih.ih_fn = (int(*)(void *))oosiop_intr;
	ssc->sc_ih.ih_arg = sc;
	ssc->sc_ih.ih_flags = 0;
	ssc->sc_ih.ih_ipl = IPL_BIO;
	intsrc = ca->ca_paddr == AV530_SCSI1 ? INTSRC_SCSI1 : INTSRC_SCSI2;
	sysconintr_establish(intsrc, &ssc->sc_ih, self->dv_xname);
}


code:
/*	$OpenBSD: syscon.c,v 1.10 2014/05/17 12:20:55 miod Exp $ */
/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * 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, this permission notice, and the disclaimer below
 * 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.
 */
/*
 * Copyright (c) 1999 Steve Murphree, Jr.
 * 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.
 *
 * 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/conf.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>

#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/cpu.h>

#include <machine/avcommon.h>
#include <aviion/dev/sysconvar.h>

struct sysconsoftc {
	struct device	sc_dev;

	struct intrhand sc_abih;	/* `abort' switch */
	struct intrhand sc_acih;	/* `ac fail' */
	struct intrhand sc_sfih;	/* `sys fail' */
};

void	sysconattach(struct device *, struct device *, void *);
int	sysconmatch(struct device *, void *, void *);

int	syscon_print(void *, const char *);
int	syscon_scan(struct device *, void *, void *);
int	sysconabort(void *);
int	sysconacfail(void *);
int	sysconsysfail(void *);

struct cfattach syscon_ca = {
	sizeof(struct sysconsoftc), sysconmatch, sysconattach
};

struct cfdriver syscon_cd = {
	NULL, "syscon", DV_DULL
};

int
sysconmatch(struct device *parent, void *cf, void *args)
{
	return (syscon_cd.cd_ndevs == 0);
}

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

	printf("\n");

	/*
	 * Set up interrupt handlers.
	 */
	for (i = 0; i < NINTSRC_SYSCON; i++)
		SLIST_INIT(&sysconintr_handlers[i]);

	/*
	 * Clear SYSFAIL if lit.
	 */
	*(volatile u_int32_t *)AV_UCSR |= UCSR_DRVSFBIT;
	*(volatile u_int32_t *)AV_CLRINT = ISTATE_SYSFAIL;

	sc->sc_abih.ih_fn = sysconabort;
	sc->sc_abih.ih_arg = 0;
	sc->sc_abih.ih_flags = INTR_WANTFRAME;
	sc->sc_abih.ih_ipl = IPL_ABORT;

	sc->sc_acih.ih_fn = sysconacfail;
	sc->sc_acih.ih_arg = 0;
	sc->sc_acih.ih_flags = INTR_WANTFRAME;
	sc->sc_acih.ih_ipl = IPL_ABORT;

	sc->sc_sfih.ih_fn = sysconsysfail;
	sc->sc_sfih.ih_arg = 0;
	sc->sc_sfih.ih_flags = INTR_WANTFRAME;
	sc->sc_sfih.ih_ipl = IPL_ABORT;

	sysconintr_establish(INTSRC_ABORT, &sc->sc_abih, "abort");
	sysconintr_establish(INTSRC_ACFAIL, &sc->sc_acih, "acfail");
	sysconintr_establish(INTSRC_SYSFAIL, &sc->sc_sfih, "sysfail");

	config_search(syscon_scan, self, args);
}

int
syscon_scan(struct device *parent, void *child, void *args)
{
	struct cfdata *cf = child;
	struct confargs oca, *ca = args;

	bzero(&oca, sizeof oca);
	oca.ca_iot = ca->ca_iot;
	oca.ca_offset = (paddr_t)cf->cf_loc[0];
	if (oca.ca_offset != (paddr_t)-1)
		oca.ca_paddr = ca->ca_paddr + oca.ca_offset;
	else
		oca.ca_paddr = (paddr_t)-1;

	if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0)
		return (0);

	config_attach(parent, cf, &oca, syscon_print);
	return (1);
}

int
syscon_print(void *args, const char *pnp)
{
	struct confargs *ca = args;

	if (ca->ca_offset != (paddr_t)-1)
		printf(" offset 0x%lx", ca->ca_offset);
	return (UNCONF);
}

/*
 * Interrupt related code
 */

intrhand_t sysconintr_handlers[NINTSRC_SYSCON];

int
sysconintr_establish(u_int intsrc, struct intrhand *ih, const char *name)
{
	intrhand_t *list;

	list = &sysconintr_handlers[intsrc];
	if (!SLIST_EMPTY(list)) {
#ifdef DIAGNOSTIC
		printf("%s: interrupt source %u already registered\n",
		    __func__, intsrc);
#endif
		return (EINVAL);
	}

	evcount_attach(&ih->ih_count, name, &ih->ih_ipl);
	SLIST_INSERT_HEAD(list, ih, ih_link);

	intsrc_enable(intsrc, ih->ih_ipl);

	return (0);
}

void
sysconintr_disestablish(u_int intsrc, struct intrhand *ih)
{
	intrhand_t *list;

	list = &sysconintr_handlers[intsrc];
	evcount_detach(&ih->ih_count);
	SLIST_REMOVE(list, ih, intrhand, ih_link);

	intsrc_disable(intsrc);
}

int
sysconabort(void *eframe)
{
	*(volatile u_int32_t *)AV_CLRINT = ISTATE_ABORT;
	nmihand(eframe);
	return (1);
}

int
sysconsysfail(void *eframe)
{
	*(volatile u_int32_t *)AV_CLRINT = ISTATE_SYSFAIL;
	printf("SYSFAIL* ASSERTED\n");
	return (1);
}

int
sysconacfail(void *eframe)
{
	*(volatile u_int32_t *)AV_CLRINT = ISTATE_ACFAIL;
	printf("ACFAIL* ASSERTED\n");
	return (1);
}


code:
/*	$OpenBSD: sysconvar.h,v 1.2 2010/04/21 19:33:47 miod Exp $	*/

/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * 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, this permission notice, and the disclaimer below
 * 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.
 */

extern intrhand_t sysconintr_handlers[NINTSRC_SYSCON];

int	sysconintr_establish(u_int, struct intrhand *, const char *);
void	sysconintr_disestablish(u_int, struct intrhand *);


code:
/*	$OpenBSD: vme.c,v 1.18 2015/02/10 22:42:35 miod Exp $	*/
/*
 * Copyright (c) 2006, 2007, 2010 Miodrag Vallat.
 *
 * 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.
 *
 * 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/kernel.h>
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/uio.h>

#include <machine/board.h>
#include <machine/bus.h>
#include <machine/conf.h>

#include <uvm/uvm_extern.h>

#include <aviion/dev/vmevar.h>

#include <machine/avcommon.h>

struct vme_softc {
	struct device	sc_dev;

	struct extent	*sc_ext_a16;
	struct extent	*sc_ext_a24;
	struct extent	*sc_ext_a32;

	const struct vme_range *sc_ranges;
};

int	vmematch(struct device *, void *, void *);
void	vmeattach(struct device *, struct device *, void *);

const struct cfattach vme_ca = {
	sizeof(struct vme_softc), vmematch, vmeattach
};

struct cfdriver vme_cd = {
	NULL, "vme", DV_DULL
};

/* minor device number encoding */
#define	AWIDTH_FIELD(minor)	(minor & 0x0f)
#define	AWIDTH(w)		((w) << 3)
#define	DWIDTH_FIELD(minor)	((minor & 0xf0) >> 4)
#define	DWIDTH(w)		((w) << 3)

uint16_t vme_d8_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	vme_d8_read_raw_2(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, uint8_t *, bus_size_t);
void	vme_d8_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint16_t);
void	vme_d8_write_raw_2(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, const uint8_t *, bus_size_t);
uint32_t vme_d8_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	vme_d8_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint32_t);
void	vme_d8_read_raw_4(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, uint8_t *, bus_size_t);
void	vme_d8_write_raw_4(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, const uint8_t *, bus_size_t);

uint32_t vme_d16_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	vme_d16_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint32_t);
void	vme_d16_read_raw_4(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, uint8_t *, bus_size_t);
void	vme_d16_write_raw_4(bus_space_tag_t, bus_space_handle_t,
	    bus_addr_t, const uint8_t *, bus_size_t);

int	vme_a16_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
void	vme_a16_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
int	vme_a24_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
void	vme_a24_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
int	vme_a32_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
void	vme_a32_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
int	vme_subregion(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    bus_size_t, bus_space_handle_t *);
void *	vme_vaddr(bus_space_tag_t, bus_space_handle_t);

int	vme_map(struct vme_softc *, struct extent *, u_int,
	    bus_addr_t, bus_size_t, int, vaddr_t *);
int	vme_map_r(const struct vme_range *, paddr_t, psize_t, int, vm_prot_t,
	    vaddr_t *);
void	vme_unmap(struct vme_softc *, struct extent *, u_int,
	    vaddr_t, paddr_t, bus_size_t);
int	vmeprint(void *, const char *);
int	vmescan(struct device *, void *, void *);

int	vmerw(struct vme_softc *, int, int, struct uio *, int);

int
vmematch(struct device *parent, void *vcf, void *aux)
{
	return (platform->get_vme_ranges() != NULL && vme_cd.cd_ndevs == 0);
}

void
vmeattach(struct device *parent, struct device *self, void *aux)
{
	struct vme_softc *sc = (struct vme_softc *)self;
	const struct vme_range *r;
	const char *fmt;
	u_int32_t ucsr;
	int i;

	/*
	 * Set up interrupt handlers.
	 */
	for (i = 0; i < NVMEINTR; i++)
		SLIST_INIT(&vmeintr_handlers[i]);

	/*
	 * Initialize extents
	 */
	sc->sc_ext_a16 = extent_create("vme a16", 0, 1 << (16 - PAGE_SHIFT),
	    M_DEVBUF, NULL, 0, EX_NOWAIT);
	if (sc->sc_ext_a16 == NULL)
		goto out1;
	sc->sc_ext_a24 = extent_create("vme a24", 0, 1 << (24 - PAGE_SHIFT),
	    M_DEVBUF, NULL, 0, EX_NOWAIT);
	if (sc->sc_ext_a24 == NULL)
		goto out2;
	sc->sc_ext_a32 = extent_create("vme a32", 0, 1 << (32 - PAGE_SHIFT),
	    M_DEVBUF, NULL, 0, EX_NOWAIT);
	if (sc->sc_ext_a32 == NULL)
		goto out3;

	/*
	 * Force a reasonable timeout for VME data transfers.
	 * We can not disable this, this would cause autoconf to hang
	 * on the first missing device we'll probe.
	 */
	ucsr = *(volatile u_int32_t*)AV_UCSR;
	ucsr = (ucsr & ~VTOSELBITS) | VTO128US;
	*(volatile u_int32_t *)AV_UCSR = ucsr;

	/*
	 * Clear EXTAD to allow VME A24 devices to access the first 16MB
	 * of memory.
	 */
	*(volatile u_int32_t *)AV_EXTAD = 0x00000000;

	/*
	 * Use supervisor data address modifiers for VME accesses.
	 */
	*(volatile u_int32_t *)AV_EXTAM = 0x0d;

	sc->sc_ranges = platform->get_vme_ranges();
	printf("\n");

	/*
	 * Display VME ranges.
	 */
	for (r = sc->sc_ranges; r->vr_width != 0; r++) {
		switch (r->vr_width) {
		default:
		case VME_A32:
			fmt = "%s: A32 %08x-%08x\n";
			break;
		case VME_A24:
			fmt = "%s: A24 %06x-%06x\n";
			break;
		case VME_A16:
			fmt = "%s: A16 %04x-%04x\n";
			break;
		}
		printf(fmt, self->dv_xname, r->vr_start, r->vr_end);
	}

	/* scan for child devices */
	config_search(vmescan, self, aux);
	return;

out3:
	extent_destroy(sc->sc_ext_a24);
out2:
	extent_destroy(sc->sc_ext_a16);
out1:
	printf(": can't allocate memory\n");
}

int
vmescan(struct device *parent, void *vcf, void *aux)
{
	struct cfdata *cf = vcf;
	struct vme_attach_args vaa;

	bzero(&vaa, sizeof vaa);
	vaa.vaa_addr_a16 = (vme_addr_t)cf->cf_loc[0];
	vaa.vaa_addr_a24 = (vme_addr_t)cf->cf_loc[1];
	vaa.vaa_addr_a32 = (vme_addr_t)cf->cf_loc[2];
	vaa.vaa_ipl = (u_int)cf->cf_loc[3];

	if ((*cf->cf_attach->ca_match)(parent, cf, &vaa) == 0)
		return 0;

	config_attach(parent, cf, &vaa, vmeprint);
	return 1;
}

int
vmeprint(void *aux, const char *pnp)
{
	struct vme_attach_args *vaa = aux;

	if (vaa->vaa_addr_a16 != (vme_addr_t)-1)
		printf(" a16 0x%04x", vaa->vaa_addr_a16);
	if (vaa->vaa_addr_a24 != (vme_addr_t)-1)
		printf(" a24 0x%06x", vaa->vaa_addr_a24);
	if (vaa->vaa_addr_a32 != (vme_addr_t)-1)
		printf(" a32 0x%08x", vaa->vaa_addr_a32);
	if (vaa->vaa_ipl != (u_int)-1)
		printf(" ipl %u", vaa->vaa_ipl);

	return UNCONF;
}

/*
 * Interrupt related code
 */

intrhand_t vmeintr_handlers[NVMEINTR];

int
vmeintr_allocate(u_int count, int flags, int ipl, u_int *array)
{
	u_int vec, v;
	struct intrhand *ih;

	if (count > 1 && ISSET(flags, VMEINTR_CONTIGUOUS)) {
		/*
		 * Try to find a range of count unused vectors first.
		 * If there isn't, it is not possible to provide exclusive
		 * contiguous vectors.
		 */
		for (vec = 0; vec <= NVMEINTR - count; vec++) {
			for (v = count; v != 0; v--)
				if (!SLIST_EMPTY(&vmeintr_handlers[vec + v - 1]))
					break;

			if (v == 0) {
				for (v = 0; v < count; v++)
					*array++ = vec++;
				return (0);
			}
		}
		if (ISSET(flags, VMEINTR_EXCLUSIVE))
			return EPERM;

		/*
		 * Try to find a range of count contiguous vectors,
		 * sharing the level we intend to register at. If there
		 * isn't, it is not possible to provide shared contiguous
		 * vectors.
		 */
		for (vec = 0; vec <= NVMEINTR - count; vec++) {
			for (v = count; v != 0; v--) {
				ih = SLIST_FIRST(&vmeintr_handlers[vec + v - 1]);
				if (ih == NULL)
					continue;
				if (ih->ih_ipl != ipl ||
				    ISSET(ih->ih_flags, INTR_EXCLUSIVE))
					break;
			}

			if (v == 0) {
				for (v = 0; v < count; v++)
					*array++ = vec++;
				return 0;
			}
		}
		return EPERM;
	}

	/*
	 * Pick as many unused vectors as possible.
	 */
	for (vec = 0; vec < NVMEINTR; vec++) {
		if (SLIST_EMPTY(&vmeintr_handlers[vec])) {
			*array++ = vec;
			if (--count == 0)
				return 0;
		}
	}

	/*
	 * There are not enough free vectors, so we'll have to share.
	 */
	for (vec = 0; vec < NVMEINTR; vec++) {
		ih = SLIST_FIRST(&vmeintr_handlers[vec]);
		if (ih->ih_ipl == ipl && !ISSET(ih->ih_flags, INTR_EXCLUSIVE)) {
			*array++ = vec;
			if (--count == 0)
				return 0;
		}
	}

	/*
	 * There are not enough vectors to share.
	 */
	return EPERM;
}

int
vmeintr_establish(u_int vec, struct intrhand *ih, const char *name)
{
	struct intrhand *intr;
	intrhand_t *list;

	list = &vmeintr_handlers[vec];
	intr = SLIST_FIRST(list);
	if (intr != NULL) {
		if (intr->ih_ipl != ih->ih_ipl) {
#ifdef DIAGNOSTIC
			printf("%s: can't use ipl %d for vector %x,"
			    " it uses ipl %d\n",
			    __func__, ih->ih_ipl, vec, intr->ih_ipl);
#endif
			return EINVAL;
		}
		if (ISSET(intr->ih_flags, INTR_EXCLUSIVE) ||
		    ISSET(ih->ih_flags, INTR_EXCLUSIVE))  {
#ifdef DIAGNOSTIC
			printf("%s: can't share vector %x\n", __func__, vec);
#endif
			return EINVAL;
		}
	}

	evcount_attach(&ih->ih_count, name, &ih->ih_ipl);
	SLIST_INSERT_HEAD(list, ih, ih_link);

	/*
	 * Enable VME interrupt source for this level.
	 */
	intsrc_enable(INTSRC_VME(ih->ih_ipl), ih->ih_ipl);

	return 0;
}

void
vmeintr_disestablish(u_int vec, struct intrhand *ih)
{
	struct intrhand *intr;
	intrhand_t *list;

	list = &vmeintr_handlers[vec];
	evcount_detach(&ih->ih_count);
	SLIST_REMOVE(list, ih, intrhand, ih_link);

	if (!SLIST_EMPTY(list))
		return;

	/*
	 * Walk the interrupts table to check if this level needs
	 * to be disabled.
	 */
	for (vec = 0; vec < NVMEINTR; vec++) {
		intr = SLIST_FIRST(&vmeintr_handlers[vec]);
		if (intr != NULL && intr->ih_ipl == ih->ih_ipl)
			break;
	}
	if (vec == NVMEINTR)
		intsrc_disable(INTSRC_VME(ih->ih_ipl));
}

/*
 * bus_space specific functions
 */

int
vme_a16_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, int flags,
    bus_space_handle_t *ret)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va;
	int rc;

	rc = vme_map(sc, sc->sc_ext_a16, VME_A16, addr, size, flags, &va);
	*ret = (bus_space_handle_t)va;
	return rc;
}

int
vme_a24_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, int flags,
    bus_space_handle_t *ret)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va;
	int rc;

	rc = vme_map(sc, sc->sc_ext_a24, VME_A24, addr, size, flags, &va);
	*ret = (bus_space_handle_t)va;
	return rc;
}

int
vme_a32_map(bus_space_tag_t tag, bus_addr_t addr, bus_size_t size, int flags,
    bus_space_handle_t *ret)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va;
	int rc;

	rc = vme_map(sc, sc->sc_ext_a32, VME_A32, addr, size, flags, &va);
	*ret = (bus_space_handle_t)va;
	return rc;
}

int
vme_map(struct vme_softc *sc, struct extent *ext, u_int awidth,
    bus_addr_t addr, bus_size_t size, int flags, vaddr_t *rva)
{
	const struct vme_range *r;
	int rc;
	paddr_t pa;
	psize_t offs, len;

	/*
	 * Since we need to map VME address ranges on demand, we will allocate
	 * with a page granularity.
	 */
	pa = trunc_page(addr);
	offs = addr - pa;
	len = round_page(addr + size) - pa;

	/*
	 * Check that the mapping fits within the available address ranges.
	 */
	for (r = sc->sc_ranges; r->vr_width != 0; r++) {
		if (r->vr_width == awidth &&
		    r->vr_start <= addr && r->vr_end >= addr + size - 1)
			break;
	}
	if (r->vr_width == 0)
		return EINVAL;

	/*
	 * Register this range in the per-width extent.
	 */
	if (ext != NULL) {
		rc = extent_alloc_region(ext, atop(pa), atop(len),
		    EX_NOWAIT | EX_MALLOCOK);
		if (rc != 0)
			return rc;
	}

	/*
	 * Allocate virtual memory for the range and map it.
	 */
	rc = vme_map_r(r, pa, len, flags, PROT_READ | PROT_WRITE, rva);
	if (rc != 0) {
		if (ext != NULL)
			(void)extent_free(ext, atop(pa), atop(len),
			    EX_NOWAIT | EX_MALLOCOK);
		return rc;
	}

	*rva += offs;
	return 0;
}

int
vme_map_r(const struct vme_range *r, paddr_t pa, psize_t len, int flags,
    vm_prot_t prot, vaddr_t *rva)
{
	vaddr_t ova, va;
	u_int pg;

	ova = va = uvm_km_valloc(kernel_map, len);
	if (va == 0)
		return ENOMEM;

	pa += r->vr_base;
	for (pg = atop(len); pg != 0; pg--) {
		pmap_kenter_pa(va, pa, prot);
		va += PAGE_SIZE;
		pa += PAGE_SIZE;
	}
	if (flags & BUS_SPACE_MAP_CACHEABLE)
		pmap_cache_ctrl(ova, ova + len, CACHE_GLOBAL);
	pmap_update(pmap_kernel());

	*rva = ova;

	return 0;
}

void
vme_a16_unmap(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va = (vaddr_t)handle;
	paddr_t pa;

	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
		return;

	return vme_unmap(sc, sc->sc_ext_a16, VME_A16, va, pa, size);
}

void
vme_a24_unmap(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va = (vaddr_t)handle;
	paddr_t pa;

	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
		return;

	return vme_unmap(sc, sc->sc_ext_a24, VME_A24, va, pa, size);
}

void
vme_a32_unmap(bus_space_tag_t tag, bus_space_handle_t handle, bus_size_t size)
{
	struct vme_softc *sc = (void *)vme_cd.cd_devs[0];
	vaddr_t va = (vaddr_t)handle;
	paddr_t pa;

	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
		return;

	return vme_unmap(sc, sc->sc_ext_a32, VME_A32, va, pa, size);
}

void
vme_unmap(struct vme_softc *sc, struct extent *ext, u_int awidth,
    vaddr_t vaddr, paddr_t paddr, bus_size_t size)
{
	const struct vme_range *r;
	vaddr_t va;
	paddr_t pa, addr;
	psize_t len;

	va = trunc_page(vaddr);
	pa = trunc_page(paddr);
	len = round_page(paddr + size) - pa;

	/*
	 * Retrieve the address range this mapping comes from.
	 */
	for (r = sc->sc_ranges; r->vr_width != 0; r++) {
		if (r->vr_width != awidth)
			continue;
		addr = paddr - r->vr_base;
		if (r->vr_width == awidth &&
		    r->vr_start <= addr && r->vr_end >= addr + size - 1)
			break;
	}
	if (r->vr_width == 0) {
#ifdef DIAGNOSTIC
		printf("%s: nonsensical A%d mapping at va 0x%08lx pa 0x%08lx\n",
		    __func__, AWIDTH(awidth), vaddr, paddr);
#endif
		return;
	}

	/*
	 * Undo the mapping.
	 */
	pmap_kremove(va, len);
	pmap_update(pmap_kernel());
	uvm_km_free(kernel_map, va, len);

	/*
	 * Unregister mapping.
	 */
	if (ext != NULL) {
		pa -= r->vr_base;
		extent_free(ext, atop(pa), atop(len), EX_NOWAIT | EX_MALLOCOK);
	}
}

int
vme_subregion(bus_space_tag_t tag, bus_space_handle_t handle, bus_addr_t offset,
    bus_size_t size, bus_space_handle_t *ret)
{
	/* since vme_map produces linear mappings, this is safe */
	/* XXX does not check range overflow */
	*ret = handle + offset;
	return 0;
}

void *
vme_vaddr(bus_space_tag_t tag, bus_space_handle_t handle)
{
	return (void *)handle;
}

/*
 * D8 access routines
 */

uint16_t
vme_d8_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	volatile uint8_t *addr = (volatile uint8_t *)(h + o);
	return ((uint16_t)addr[0] << 8) | ((uint16_t)addr[1]);
}

uint32_t
vme_d8_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	volatile uint8_t *addr = (volatile uint8_t *)(h + o);
	return ((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) |
	    ((uint32_t)addr[2] << 8) | ((uint32_t)addr[3]);
}

void
vme_d8_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint16_t v)
{
	volatile uint8_t *addr = (volatile uint8_t *)(h + o);
	addr[0] = v >> 8;
	addr[1] = v;
}

void
vme_d8_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint32_t v)
{
	volatile uint8_t *addr = (volatile uint8_t *)(h + o);
	addr[0] = v >> 24;
	addr[1] = v >> 16;
	addr[2] = v >> 8;
	addr[3] = v;
}

void
vme_d8_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	len >>= 1;
	while (len-- != 0) {
		*(uint16_t *)buf = vme_d8_read_2(t, h, o);
		buf += 2;
	}
}

void
vme_d8_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	len >>= 1;
	while (len-- != 0) {
		vme_d8_write_2(t, h, o, *(uint16_t *)buf);
		buf += 2;
	}
}

void
vme_d8_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	len >>= 2;
	while (len-- != 0) {
		*(uint32_t *)buf = vme_d8_read_4(t, h, o);
		buf += 4;
	}
}

void
vme_d8_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	len >>= 2;
	while (len-- != 0) {
		vme_d8_write_4(t, h, o, *(uint32_t *)buf);
		buf += 4;
	}
}
/*
 * D16 access routines
 */

uint32_t
vme_d16_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
	return ((uint32_t)addr[0] << 16) | ((uint32_t)addr[1]);
}

void
vme_d16_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    uint32_t v)
{
	volatile uint16_t *addr = (volatile uint16_t *)(h + o);
	addr[0] = v >> 16;
	addr[1] = v;
}

void
vme_d16_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	len >>= 2;
	while (len-- != 0) {
		*(uint32_t *)buf = vme_d16_read_4(t, h, o);
		buf += 4;
	}
}

void
vme_d16_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	len >>= 2;
	while (len-- != 0) {
		vme_d16_write_4(t, h, o, *(uint32_t *)buf);
		buf += 4;
	}
}

/*
 * Get a bus_space_tag for the requested address and data access modes.
 */
int
vmebus_get_bst(struct device *vsc, u_int aspace, u_int dspace,
    bus_space_tag_t *bst)
{
	struct aviion_bus_space_tag *tag;

	switch (dspace) {
	case VME_D32:
	case VME_D16:
	case VME_D8:
		break;
	default:
		return EINVAL;
	}

	switch (aspace) {
	case VME_A32:
	case VME_A24:
	case VME_A16:
		break;
	default:
		return EINVAL;
	}

	tag = (struct aviion_bus_space_tag *)malloc(sizeof *tag, M_DEVBUF,
	    M_NOWAIT);
	if (tag == NULL)
		return ENOMEM;

	switch (aspace) {
	default:
	case VME_A32:
		tag->_space_map = vme_a32_map;
		tag->_space_unmap = vme_a32_unmap;
		break;
	case VME_A24:
		tag->_space_map = vme_a24_map;
		tag->_space_unmap = vme_a24_unmap;
		break;
	case VME_A16:
		tag->_space_map = vme_a16_map;
		tag->_space_unmap = vme_a16_unmap;
		break;
	}

	tag->_space_subregion = vme_subregion;
	tag->_space_vaddr = vme_vaddr;
	tag->_space_read_1 = generic_space_read_1;
	tag->_space_write_1 = generic_space_write_1;

	switch (dspace) {
	default:
	case VME_D32:
		tag->_space_read_2 = generic_space_read_2;
		tag->_space_write_2 = generic_space_write_2;
		tag->_space_read_4 = generic_space_read_4;
		tag->_space_write_4 = generic_space_write_4;
		tag->_space_read_raw_2 = generic_space_read_raw_2;
		tag->_space_write_raw_2 = generic_space_write_raw_2;
		tag->_space_read_raw_4 = generic_space_read_raw_4;
		tag->_space_write_raw_4 = generic_space_write_raw_4;
		break;
	case VME_D16:
		tag->_space_read_2 = generic_space_read_2;
		tag->_space_write_2 = generic_space_write_2;
		tag->_space_read_4 = vme_d16_read_4;
		tag->_space_write_4 = vme_d16_write_4;
		tag->_space_read_raw_2 = generic_space_read_raw_2;
		tag->_space_write_raw_2 = generic_space_write_raw_2;
		tag->_space_read_raw_4 = vme_d16_read_raw_4;
		tag->_space_write_raw_4 = vme_d16_write_raw_4;
		break;
	case VME_D8:
		tag->_space_read_2 = vme_d8_read_2;
		tag->_space_write_2 = vme_d8_write_2;
		tag->_space_read_4 = vme_d8_read_4;
		tag->_space_write_4 = vme_d8_write_4;
		tag->_space_read_raw_2 = vme_d8_read_raw_2;
		tag->_space_write_raw_2 = vme_d8_write_raw_2;
		tag->_space_read_raw_4 = vme_d8_read_raw_4;
		tag->_space_write_raw_4 = vme_d8_write_raw_4;
		break;
	}

	*bst = tag;
	return 0;
}

void
vmebus_release_bst(struct device *vsc, bus_space_tag_t b)
{
	free((void *)b, M_DEVBUF, sizeof(struct aviion_bus_space_tag));
}

/*
 * /dev/vme* access routines
 */

int
vmeopen(dev_t dev, int flags, int type, struct proc *p)
{
	struct vme_softc *sc;

	if (minor(dev) >= vme_cd.cd_ndevs ||
	    (sc = vme_cd.cd_devs[minor(dev)]) == NULL)
		return ENODEV;

	if (sc->sc_ranges == NULL)	/* failed attach */
		return ENODEV;

	switch (AWIDTH_FIELD(minor(dev))) {
	case VME_A32:
	case VME_A24:
	case VME_A16:
		break;
	default:
		return ENODEV;
	}

	switch (DWIDTH_FIELD(minor(dev))) {
	case VME_D32:
	case VME_D16:
	case VME_D8:
		break;
	default:
		return ENODEV;
	}

	return 0;
}

int
vmeclose(dev_t dev, int flags, int type, struct proc *p)
{
	return 0;
}

int
vmeread(dev_t dev, struct uio *uio, int flags)
{
	struct vme_softc *sc;
	int awidth, dwidth;

	sc = vme_cd.cd_devs[minor(dev)];
	awidth = AWIDTH_FIELD(minor(dev));
	dwidth = DWIDTH_FIELD(minor(dev));

	return vmerw(sc, awidth, dwidth, uio, flags);
}

int
vmewrite(dev_t dev, struct uio *uio, int flags)
{
	struct vme_softc *sc;
	int awidth, dwidth;

	sc = vme_cd.cd_devs[minor(dev)];
	awidth = AWIDTH_FIELD(minor(dev));
	dwidth = DWIDTH_FIELD(minor(dev));

	return vmerw(sc, awidth, dwidth, uio, flags);
}

int
vmerw(struct vme_softc *sc, int awidth, int dwidth, struct uio *uio, int flags)
{
	const struct vme_range *r;
	struct iovec *iov;
	psize_t delta, len;
	vaddr_t vmepg;
	int rc = 0;

	while (uio->uio_resid > 0) {
		iov = uio->uio_iov;
		if (iov->iov_len == 0) {
			uio->uio_iov++;
			uio->uio_iovcnt--;
			if (uio->uio_iovcnt < 0)
				panic("bogus uio %p", uio);
			continue;
		}

		/*
		 * Figure out which range we will be working on;
		 * if we hit the end of a range we'll report EFAULT.
		 */
		for (r = sc->sc_ranges; r->vr_width != 0; r++) {
			if (r->vr_width != awidth)
				continue;
			if ((off_t)r->vr_start <= uio->uio_offset &&
			    (off_t)r->vr_end >= uio->uio_offset)
				break;
		}
		if (r->vr_width == 0) {
			rc = EFAULT;	/* outside any valid range */
			break;
		}

		delta = uio->uio_offset & PAGE_MASK;
		len = ulmin(uio->uio_resid, PAGE_SIZE - delta);
		/* len = ulmin(len, (off_t)r->vr_end - uio->uio_offset); */

		rc = vme_map_r(r, trunc_page(uio->uio_offset), PAGE_SIZE, 0,
		    uio->uio_rw == UIO_READ ? PROT_READ : PROT_READ | PROT_WRITE,
		    &vmepg);
		if (rc != 0)
			break;

		/* XXX wrap this because of dwidth */
		rc = uiomove((caddr_t)vmepg + delta, len, uio);

		/* inline vme_unmap */
		pmap_kremove(vmepg, PAGE_SIZE);
		pmap_update(pmap_kernel());
		uvm_km_free(kernel_map, vmepg, PAGE_SIZE);

		if (rc != 0)
			break;

		iov->iov_base += len;
		iov->iov_len -= len;
		uio->uio_offset += len;
		uio->uio_resid -= len;
	}

	return rc;
}

int
vmeioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	switch (cmd) {
	default:
		return ENOTTY;
	}
}

paddr_t
vmemmap(dev_t dev, off_t off, int prot)
{
	struct vme_softc *sc;
	const struct vme_range *r;
	int awidth;

	sc = vme_cd.cd_devs[minor(dev)];
	awidth = AWIDTH_FIELD(minor(dev));

	if ((off & PAGE_MASK) != 0)
		return -1;

	/*
	 * Figure out which range we will be working on.
	 */
	for (r = sc->sc_ranges; r->vr_width != 0; r++) {
		if (r->vr_width != awidth)
			continue;
		if ((off_t)r->vr_start <= off &&
		    (off_t)r->vr_end >= off)
			break;
	}
	if (r->vr_width == 0)
		return -1;

	return r->vr_base + (paddr_t)off;
}


code:
/*	$OpenBSD: vmevar.h,v 1.4 2010/04/21 19:33:47 miod Exp $	*/
/*
 * Copyright (c) 2006, 2007, Miodrag Vallat
 *
 * 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.
 *
 * 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.
 */

#ifndef	_AVIION_VME_H_
#define	_AVIION_VME_H_

typedef	u_int32_t vme_addr_t;

/*
 * VME address and data widths
 */

#define	VME_A32			0x04	/* 100..000 */
#define	VME_A24			0x03	/* 011..000 */
#define	VME_A16			0x02	/* 010..000 */
#define	VME_D32			0x04	/* 100..000 */
#define	VME_D16			0x02	/* 010..000 */
#define	VME_D8			0x01	/* 001..000 */

/*
 * VME address range
 */

struct vme_range {
	u_int		vr_width;
	vme_addr_t	vr_start;
	vme_addr_t	vr_end;
	paddr_t		vr_base;
};

/*
 * Attachment information for VME devices.
 *
 * Drivers are supposed to do their interrupt vector allocation
 * themselves.
 */
struct	vme_attach_args {
	/* address locators */
	vme_addr_t	vaa_addr_a16;
	vme_addr_t	vaa_addr_a24;
	vme_addr_t	vaa_addr_a32;
	/* interrupt level if specified */
	u_int		vaa_ipl;
};

/*
 * There are 256 possible vectors for VME devices.
 * One or more vectors may be allocated by vmeintr_allocate(), and then
 * each vector is setup with vmeintr_establish(). Nothing is done to
 * prevent the vector to be used in-between, so make sure no interrupt
 * can occur between the vector allocation and the interrupt handler
 * registration.
 */
#define	NVMEINTR	256
extern intrhand_t vmeintr_handlers[NVMEINTR];

int	vmeintr_allocate(u_int, int, int, u_int *);
#define	VMEINTR_ANY		0x00	/* any vector will do */
#define	VMEINTR_CONTIGUOUS	0x01	/* allocate a contiguous range */
#define	VMEINTR_SHARED		0x00	/* sharing is ok */
#define	VMEINTR_EXCLUSIVE	0x02	/* do not share this vector */
void	vmeintr_disestablish(u_int, struct intrhand *);
int	vmeintr_establish(u_int, struct intrhand *, const char *);

/*
 * VME device drivers need to obtain their bus_space_tag_t with
 * vmebus_get_bst(), specifying the address and data width to use for
 * bus accesses.
 * Resources associated to the tag can be released with vmebus_release_bst()
 * when bus accesses are no longer necessary.
 */
int	vmebus_get_bst(struct device *, u_int, u_int, bus_space_tag_t *);
void	vmebus_release_bst(struct device *, bus_space_tag_t);

#endif	/* _AVIION_VME_H_ */


path: sys/arch/aviion/include/CVS/Entries


code: src/sys/arch/aviion/include

path: sys/arch/aviion/include/CVS/Repository


code:
/*	$OpenBSD: _float.h,v 1.1 2012/06/26 16:12:43 deraadt Exp $ */

#include <m88k/_float.h>


code:
/*	$OpenBSD: _types.h,v 1.4 2012/11/05 19:39:34 miod Exp $	*/

/* public domain */
#include <m88k/_types.h>


code:
/* $OpenBSD: asm_macro.h,v 1.1.1.1 2006/04/18 10:56:59 miod Exp $ */
/* public domain */
#include <m88k/asm_macro.h>


code:
/*	$OpenBSD: atomic.h,v 1.3 2011/03/23 16:54:34 pirofti Exp $	*/

/* Public Domain */

#ifndef _MACHINE_ATOMIC_H_
#define _MACHINE_ATOMIC_H_

#include <m88k/atomic.h>

#endif /* _MACHINE_ATOMIC_H_ */


code:
/*	$OpenBSD: autoconf.h,v 1.3 2013/10/10 21:24:59 miod Exp $ */
/*
 * Copyright (c) 1999, Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * 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 Nivas Madhur.
 * 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.
 *
 */
/*
 * Autoconfiguration information.
 */

#ifndef _MACHINE_AUTOCONF_H_
#define _MACHINE_AUTOCONF_H_

#include <machine/bus.h>

struct confargs {
	bus_space_tag_t	ca_iot;
	paddr_t		ca_paddr;	/* physical address */
	paddr_t		ca_offset;	/* offset from parent */
	u_int		ca_ipl;		/* interrupt level */
};

void	cmdline_parse(void);
void	myetheraddr(u_char *);

extern char bootargs[256];

#endif