code:
/*	$OpenBSD: elroy.c,v 1.13 2012/02/25 17:08:49 miod Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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 "cardbus.h"

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

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

#include <arch/hppa/dev/cpudevs.h>

#if NCARDBUS > 0
#include <dev/cardbus/rbus.h>
#endif

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <hppa64/dev/elroyreg.h>
#include <hppa64/dev/elroyvar.h>

#define	ELROY_MEM_CHUNK		0x800000
#define	ELROY_MEM_WINDOW	(2 * ELROY_MEM_CHUNK)

int	elroy_match(struct device *, void *, void *);
void	elroy_attach(struct device *, struct device *, void *);
int	elroy_intr(void *);

struct cfattach elroy_ca = {
	sizeof(struct elroy_softc), elroy_match, elroy_attach
};

struct cfdriver elroy_cd = {
	NULL, "elroy", DV_DULL
};

void		 elroy_attach_hook(struct device *parent, struct device *self,
		    struct pcibus_attach_args *pba);
int		 elroy_maxdevs(void *v, int bus);
pcitag_t	 elroy_make_tag(void *v, int bus, int dev, int func);
void		 elroy_decompose_tag(void *v, pcitag_t tag, int *bus,
		    int *dev, int *func);
int		 elroy_conf_size(void *v, pcitag_t tag);
pcireg_t	 elroy_conf_read(void *v, pcitag_t tag, int reg);
void		 elroy_conf_write(void *v, pcitag_t tag, int reg,
		    pcireg_t data);
int		 elroy_iomap(void *v, bus_addr_t bpa, bus_size_t size,
		    int flags, bus_space_handle_t *bshp);
int		 elroy_memmap(void *v, bus_addr_t bpa, bus_size_t size,
		    int flags, bus_space_handle_t *bshp);
int		 elroy_subregion(void *v, bus_space_handle_t bsh,
		    bus_size_t offset, bus_size_t size,
		    bus_space_handle_t *nbshp);
int		 elroy_ioalloc(void *v, bus_addr_t rstart, bus_addr_t rend,
		    bus_size_t size, bus_size_t align, bus_size_t boundary,
		    int flags, bus_addr_t *addrp, bus_space_handle_t *bshp);
int		 elroy_memalloc(void *v, bus_addr_t rstart, bus_addr_t rend,
		    bus_size_t size, bus_size_t align, bus_size_t boundary,
		    int flags, bus_addr_t *addrp, bus_space_handle_t *bshp);
void		 elroy_unmap(void *v, bus_space_handle_t bsh,
		    bus_size_t size);
void		 elroy_free(void *v, bus_space_handle_t bh, bus_size_t size);
void		 elroy_barrier(void *v, bus_space_handle_t h, bus_size_t o,
		    bus_size_t l, int op);
void *		 elroy_alloc_parent(struct device *self,
		    struct pci_attach_args *pa, int io);
void *		 elroy_vaddr(void *v, bus_space_handle_t h);
u_int8_t	 elroy_r1(void *v, bus_space_handle_t h, bus_size_t o);
u_int16_t	 elroy_r2(void *v, bus_space_handle_t h, bus_size_t o);
u_int32_t	 elroy_r4(void *v, bus_space_handle_t h, bus_size_t o);
u_int64_t	 elroy_r8(void *v, bus_space_handle_t h, bus_size_t o);
void		 elroy_w1(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t vv);
void		 elroy_w2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int16_t vv);
void		 elroy_w4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int32_t vv);
void		 elroy_w8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int64_t vv);
void		 elroy_rm_1(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rm_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int16_t *a, bus_size_t c);
void		 elroy_rm_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int32_t *a, bus_size_t c);
void		 elroy_rm_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int64_t *a, bus_size_t c);
void		 elroy_wm_1(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wm_2(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int16_t *a, bus_size_t c);
void		 elroy_wm_4(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int32_t *a, bus_size_t c);
void		 elroy_wm_8(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int64_t *a, bus_size_t c);
void		 elroy_sm_1(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t vv, bus_size_t c);
void		 elroy_sm_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int16_t vv, bus_size_t c);
void		 elroy_sm_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int32_t vv, bus_size_t c);
void		 elroy_sm_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int64_t vv, bus_size_t c);
void		 elroy_rrm_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rrm_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rrm_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_wrm_2(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wrm_4(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wrm_8(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_rr_1(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rr_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int16_t *a, bus_size_t c);
void		 elroy_rr_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int32_t *a, bus_size_t c);
void		 elroy_rr_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int64_t *a, bus_size_t c);
void		 elroy_wr_1(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wr_2(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int16_t *a, bus_size_t c);
void		 elroy_wr_4(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int32_t *a, bus_size_t c);
void		 elroy_wr_8(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int64_t *a, bus_size_t c);
void		 elroy_rrr_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rrr_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_rrr_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t *a, bus_size_t c);
void		 elroy_wrr_2(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wrr_4(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_wrr_8(void *v, bus_space_handle_t h, bus_size_t o,
		    const u_int8_t *a, bus_size_t c);
void		 elroy_sr_1(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int8_t vv, bus_size_t c);
void		 elroy_sr_2(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int16_t vv, bus_size_t c);
void		 elroy_sr_4(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int32_t vv, bus_size_t c);
void		 elroy_sr_8(void *v, bus_space_handle_t h, bus_size_t o,
		    u_int64_t vv, bus_size_t c);
void		 elroy_cp_1(void *v, bus_space_handle_t h1, bus_size_t o1,
		    bus_space_handle_t h2, bus_size_t o2, bus_size_t c);
void		 elroy_cp_2(void *v, bus_space_handle_t h1, bus_size_t o1,
		    bus_space_handle_t h2, bus_size_t o2, bus_size_t c);
void		 elroy_cp_4(void *v, bus_space_handle_t h1, bus_size_t o1,
		    bus_space_handle_t h2, bus_size_t o2, bus_size_t c);
void		 elroy_cp_8(void *v, bus_space_handle_t h1, bus_size_t o1,
		    bus_space_handle_t h2, bus_size_t o2, bus_size_t c);

int
elroy_match(struct device *parent, void *cfdata, void *aux)
{
	struct confargs *ca = aux;
	/* struct cfdata *cf = cfdata; */

	if ((ca->ca_name && !strcmp(ca->ca_name, "lba")) ||
	    (ca->ca_type.iodc_type == HPPA_TYPE_BRIDGE &&
	     ca->ca_type.iodc_sv_model == HPPA_BRIDGE_DINO &&
	     ca->ca_type.iodc_model == 0x78))
		return (1);

	return (0);
}

void
elroy_write32(volatile u_int32_t *p, u_int32_t v)
{
	*p = v;
}

u_int32_t
elroy_read32(volatile u_int32_t *p)
{
	return *p;
}

void
elroy_attach_hook(struct device *parent, struct device *self,
    struct pcibus_attach_args *pba)
{

}

int
elroy_maxdevs(void *v, int bus)
{
	return (32);
}

pcitag_t
elroy_make_tag(void *v, int bus, int dev, int func)
{
	if (bus > 255 || dev > 31 || func > 7)
		panic("elroy_make_tag: bad request");

	return ((bus << 16) | (dev << 11) | (func << 8));
}

void
elroy_decompose_tag(void *v, pcitag_t tag, int *bus, int *dev, int *func)
{
	if (bus)
		*bus = (tag >> 16) & 0xff;
	if (dev)
		*dev = (tag >> 11) & 0x1f;
	if (func)
		*func= (tag >>  8) & 0x07;
}

int
elroy_conf_size(void *v, pcitag_t tag)
{
	return PCI_CONFIG_SPACE_SIZE;
}

pcireg_t
elroy_conf_read(void *v, pcitag_t tag, int reg)
{
	struct elroy_softc *sc = v;
	volatile struct elroy_regs *r = sc->sc_regs;
	u_int32_t arb_mask, err_cfg, control;
	pcireg_t data, data1;

/* printf("elroy_conf_read(%p, 0x%08x, 0x%x)", v, tag, reg); */
	arb_mask = elroy_read32(&r->arb_mask);
	err_cfg = elroy_read32(&r->err_cfg);
	control = elroy_read32(&r->control);
	if (!arb_mask)
		elroy_write32(&r->arb_mask, htole32(ELROY_ARB_ENABLE));
	elroy_write32(&r->err_cfg, err_cfg |
	    htole32(ELROY_ERRCFG_SMART | ELROY_ERRCFG_CM));
	elroy_write32(&r->control, (control | htole32(ELROY_CONTROL_CE)) &
	    ~htole32(ELROY_CONTROL_HF));

	elroy_write32(&r->pci_conf_addr, htole32(tag | reg));
	data1 = elroy_read32(&r->pci_conf_addr);
	data = elroy_read32(&r->pci_conf_data);

	elroy_write32(&r->control, control |
	    htole32(ELROY_CONTROL_CE|ELROY_CONTROL_CL));
	elroy_write32(&r->control, control);
	elroy_write32(&r->err_cfg, err_cfg);
	if (!arb_mask)
		elroy_write32(&r->arb_mask, arb_mask);

	data = letoh32(data);
/* printf("=0x%08x (@ 0x%08x)\n", data, letoh32(data1)); */
	return (data);
}

void
elroy_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
{
	struct elroy_softc *sc = v;
	volatile struct elroy_regs *r = sc->sc_regs;
	u_int32_t arb_mask, err_cfg, control;
	pcireg_t data1;

/* printf("elroy_conf_write(%p, 0x%08x, 0x%x, 0x%x)\n", v, tag, reg, data); */
	arb_mask = elroy_read32(&r->arb_mask);
	err_cfg = elroy_read32(&r->err_cfg);
	control = elroy_read32(&r->control);
	if (!arb_mask)
		elroy_write32(&r->arb_mask, htole32(ELROY_ARB_ENABLE));
	elroy_write32(&r->err_cfg, err_cfg |
	    htole32(ELROY_ERRCFG_SMART | ELROY_ERRCFG_CM));
	elroy_write32(&r->control, (control | htole32(ELROY_CONTROL_CE)) &
	    ~htole32(ELROY_CONTROL_HF));

	/* fix coalescing config writes errata by interleaving w/ a read */
	elroy_write32(&r->pci_conf_addr, htole32(tag | PCI_ID_REG));
	data1 = elroy_read32(&r->pci_conf_addr);
	data1 = elroy_read32(&r->pci_conf_data);

	elroy_write32(&r->pci_conf_addr, htole32(tag | reg));
	data1 = elroy_read32(&r->pci_conf_addr);
	elroy_write32(&r->pci_conf_data, htole32(data));
	data1 = elroy_read32(&r->pci_conf_addr);

	elroy_write32(&r->control, control |
	    htole32(ELROY_CONTROL_CE|ELROY_CONTROL_CL));
	elroy_write32(&r->control, control);
	elroy_write32(&r->err_cfg, err_cfg);
	if (!arb_mask)
		elroy_write32(&r->arb_mask, arb_mask);
}

int
elroy_iomap(void *v, bus_addr_t bpa, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
	struct elroy_softc *sc = v;
	/* volatile struct elroy_regs *r = sc->sc_regs; */
	int error;

	/* Convert 32-bit PCI address to a 64-bit address. */
	bpa |= (HPPA_IOBEGIN | 0xff00000000UL);

	if ((error = bus_space_map(sc->sc_bt, bpa + sc->sc_iobase, size,
	    flags, bshp)))
		return (error);

	return (0);
}

int
elroy_memmap(void *v, bus_addr_t bpa, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
	struct elroy_softc *sc = v;
	/* volatile struct elroy_regs *r = sc->sc_regs; */
	int error;

	/* Convert 32-bit PCI address to a 64-bit address. */
	bpa |= (HPPA_IOBEGIN | 0xff00000000UL);

	if ((error = bus_space_map(sc->sc_bt, bpa, size, flags, bshp)))
		return (error);

	return (0);
}

int
elroy_subregion(void *v, bus_space_handle_t bsh, bus_size_t offset,
    bus_size_t size, bus_space_handle_t *nbshp)
{
	*nbshp = bsh + offset;
	return (0);
}

int
elroy_ioalloc(void *v, bus_addr_t rstart, bus_addr_t rend, bus_size_t size,
    bus_size_t align, bus_size_t boundary, int flags, bus_addr_t *addrp,
    bus_space_handle_t *bshp)
{
	struct elroy_softc *sc = v;
	volatile struct elroy_regs *r = sc->sc_regs;
	bus_addr_t iostart, ioend;

	iostart = r->io_base & ~htole32(ELROY_BASE_RE);
	ioend = iostart + ~htole32(r->io_mask) + 1;
	if (rstart < iostart || rend > ioend)
		panic("elroy_ioalloc: bad region start/end");

	rstart += sc->sc_iobase;
	rend += sc->sc_iobase;
	if (bus_space_alloc(sc->sc_bt, rstart, rend, size,
	    align, boundary, flags, addrp, bshp))
		return (ENOMEM);

	return (0);
}

int
elroy_memalloc(void *v, bus_addr_t rstart, bus_addr_t rend, bus_size_t size,
    bus_size_t align, bus_size_t boundary, int flags, bus_addr_t *addrp,
    bus_space_handle_t *bshp)
{
	struct elroy_softc *sc = v;
	/* volatile struct elroy_regs *r = sc->sc_regs; */

	if (bus_space_alloc(sc->sc_bt, rstart, rend, size,
	    align, boundary, flags, addrp, bshp))
		return (ENOMEM);

	return (0);
}

void
elroy_unmap(void *v, bus_space_handle_t bsh, bus_size_t size)
{
	struct elroy_softc *sc = v;

	bus_space_free(sc->sc_bt, bsh, size);
}

void
elroy_free(void *v, bus_space_handle_t bh, bus_size_t size)
{
	/* should be enough */
	elroy_unmap(v, bh, size);
}

void
elroy_barrier(void *v, bus_space_handle_t h, bus_size_t o, bus_size_t l, int op)
{
	struct elroy_softc *sc = v;
	volatile struct elroy_regs *r = sc->sc_regs;
	u_int32_t data;

	sync_caches();
	if (op & BUS_SPACE_BARRIER_WRITE) {
		data = r->pci_id;	/* flush write fifo */
		sync_caches();
	}
}

#if NCARDBUS > 0
void *
elroy_alloc_parent(struct device *self, struct pci_attach_args *pa, int io)
{
#if 0	/* TODO */

	struct elroy_softc *sc = pa->pa_pc->_cookie;
	struct extent *ex;
	bus_space_tag_t tag;
	bus_addr_t start;
	bus_size_t size;

	if (io) {
		ex = sc->sc_ioex;
		tag = pa->pa_iot;
		start = 0xa000;
		size = 0x1000;
	} else {
		if (!sc->sc_memex) {
			bus_space_handle_t memh;
			bus_addr_t mem_start;

			if (elroy_memalloc(sc, 0xf0800000, 0xff7fffff,
			    ELROY_MEM_WINDOW, ELROY_MEM_WINDOW, EX_NOBOUNDARY,
			    0, &mem_start, &memh))
				return (NULL);

			snprintf(sc->sc_memexname, sizeof(sc->sc_memexname),
			    "%s_mem", sc->sc_dv.dv_xname);
			if ((sc->sc_memex = extent_create(sc->sc_memexname,
			    mem_start, mem_start + ELROY_MEM_WINDOW, M_DEVBUF,
			    NULL, 0, EX_NOWAIT | EX_MALLOCOK)) == NULL) {
				extent_destroy(sc->sc_ioex);
				bus_space_free(sc->sc_bt, memh,
				    ELROY_MEM_WINDOW);
				return (NULL);
			}
		}
		ex = sc->sc_memex;
		tag = pa->pa_memt;
		start = ex->ex_start;
		size = ELROY_MEM_CHUNK;
	}

	if (extent_alloc_subregion(ex, start, ex->ex_end, size, size, 0,
	    EX_NOBOUNDARY, EX_NOWAIT, &start))
		return (NULL);

	extent_free(ex, start, size, EX_NOWAIT);
	return rbus_new_root_share(tag, ex, start, size);
#else
	return (NULL);
#endif
}
#endif

void *
elroy_vaddr(void *v, bus_space_handle_t h)
{
	return ((void *)h);
}

u_int8_t
elroy_r1(void *v, bus_space_handle_t h, bus_size_t o)
{
	h += o;
	return *(volatile u_int8_t *)h;
}

u_int16_t
elroy_r2(void *v, bus_space_handle_t h, bus_size_t o)
{
	volatile u_int16_t *p;

	h += o;
	p = (volatile u_int16_t *)h;
	return (letoh16(*p));
}

u_int32_t
elroy_r4(void *v, bus_space_handle_t h, bus_size_t o)
{
	u_int32_t data;

	h += o;
	data = *(volatile u_int32_t *)h;
	return (letoh32(data));
}

u_int64_t
elroy_r8(void *v, bus_space_handle_t h, bus_size_t o)
{
	u_int64_t data;

	h += o;
	data = *(volatile u_int64_t *)h;
	return (letoh64(data));
}

void
elroy_w1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv)
{
	h += o;
	*(volatile u_int8_t *)h = vv;
}

void
elroy_w2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv)
{
	volatile u_int16_t *p;

	h += o;
	p = (volatile u_int16_t *)h;
	*p = htole16(vv);
}

void
elroy_w4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv)
{
	h += o;
	vv = htole32(vv);
	*(volatile u_int32_t *)h = vv;
}

void
elroy_w8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv)
{
	h += o;
	*(volatile u_int64_t *)h = htole64(vv);
}

void
elroy_rm_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t *a, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*a++ = *p;
}

void
elroy_rm_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t *a, bus_size_t c)
{
	volatile u_int16_t *p;

	h += o;
	p = (volatile u_int16_t *)h;
	while (c--)
		*a++ = letoh16(*p);
}

void
elroy_rm_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t *a, bus_size_t c)
{
	volatile u_int32_t *p;

	h += o;
	p = (volatile u_int32_t *)h;
	while (c--)
		*a++ = letoh32(*p);
}

void
elroy_rm_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t *a, bus_size_t c)
{
	volatile u_int64_t *p;

	h += o;
	p = (volatile u_int64_t *)h;
	while (c--)
		*a++ = letoh64(*p);
}

void
elroy_wm_1(void *v, bus_space_handle_t h, bus_size_t o, const u_int8_t *a, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*p = *a++;
}

void
elroy_wm_2(void *v, bus_space_handle_t h, bus_size_t o, const u_int16_t *a, bus_size_t c)
{
	volatile u_int16_t *p;

	h += o;
	p = (volatile u_int16_t *)h;
	while (c--)
		*p = htole16(*a++);
}

void
elroy_wm_4(void *v, bus_space_handle_t h, bus_size_t o, const u_int32_t *a, bus_size_t c)
{
	volatile u_int32_t *p;

	h += o;
	p = (volatile u_int32_t *)h;
	while (c--)
		*p = htole32(*a++);
}

void
elroy_wm_8(void *v, bus_space_handle_t h, bus_size_t o, const u_int64_t *a, bus_size_t c)
{
	volatile u_int64_t *p;

	h += o;
	p = (volatile u_int64_t *)h;
	while (c--)
		*p = htole64(*a++);
}

void
elroy_sm_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*p = vv;
}

void
elroy_sm_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv, bus_size_t c)
{
	volatile u_int16_t *p;

	h += o;
	p = (volatile u_int16_t *)h;
	vv = htole16(vv);
	while (c--)
		*p = vv;
}

void
elroy_sm_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv, bus_size_t c)
{
	volatile u_int32_t *p;

	h += o;
	p = (volatile u_int32_t *)h;
	vv = htole32(vv);
	while (c--)
		*p = vv;
}

void
elroy_sm_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv, bus_size_t c)
{
	volatile u_int64_t *p;

	h += o;
	p = (volatile u_int64_t *)h;
	vv = htole64(vv);
	while (c--)
		*p = vv;
}

void
elroy_rrm_2(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int16_t *p, *q = (u_int16_t *)a;

	h += o;
	p = (volatile u_int16_t *)h;
	c /= 2;
	while (c--)
		*q++ = *p;
}

void
elroy_rrm_4(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int32_t *p, *q = (u_int32_t *)a;

	h += o;
	p = (volatile u_int32_t *)h;
	c /= 4;
	while (c--)
		*q++ = *p;
}

void
elroy_rrm_8(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int64_t *p, *q = (u_int64_t *)a;

	h += o;
	p = (volatile u_int64_t *)h;
	c /= 8;
	while (c--)
		*q++ = *p;
}

void
elroy_wrm_2(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int16_t *p;
	const u_int16_t *q = (const u_int16_t *)a;

	h += o;
	p = (volatile u_int16_t *)h;
	c /= 2;
	while (c--)
		*p = *q++;
}

void
elroy_wrm_4(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int32_t *p;
	const u_int32_t *q = (const u_int32_t *)a;

	h += o;
	p = (volatile u_int32_t *)h;
	c /= 4;
	while (c--)
		*p = *q++;
}

void
elroy_wrm_8(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int64_t *p;
	const u_int64_t *q = (const u_int64_t *)a;

	h += o;
	p = (volatile u_int64_t *)h;
	c /= 8;
	while (c--)
		*p = *q++;
}

void
elroy_rr_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t *a, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*a++ = *p++;
}

void
elroy_rr_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t *a, bus_size_t c)
{
	volatile u_int16_t *p, data;

	h += o;
	p = (volatile u_int16_t *)h;
	while (c--) {
		data = *p++;
		*a++ = letoh16(data);
	}
}

void
elroy_rr_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t *a, bus_size_t c)
{
	volatile u_int32_t *p, data;

	h += o;
	p = (volatile u_int32_t *)h;
	while (c--) {
		data = *p++;
		*a++ = letoh32(data);
	}
}

void
elroy_rr_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t *a, bus_size_t c)
{
	volatile u_int64_t *p, data;

	h += o;
	p = (volatile u_int64_t *)h;
	while (c--) {
		data = *p++;
		*a++ = letoh64(data);
	}
}

void
elroy_wr_1(void *v, bus_space_handle_t h, bus_size_t o, const u_int8_t *a, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*p++ = *a++;
}

void
elroy_wr_2(void *v, bus_space_handle_t h, bus_size_t o, const u_int16_t *a, bus_size_t c)
{
	volatile u_int16_t *p, data;

	h += o;
	p = (volatile u_int16_t *)h;
	while (c--) {
		data = *a++;
		*p++ = htole16(data);
	}
}

void
elroy_wr_4(void *v, bus_space_handle_t h, bus_size_t o, const u_int32_t *a, bus_size_t c)
{
	volatile u_int32_t *p, data;

	h += o;
	p = (volatile u_int32_t *)h;
	while (c--) {
		data = *a++;
		*p++ = htole32(data);
	}
}

void
elroy_wr_8(void *v, bus_space_handle_t h, bus_size_t o, const u_int64_t *a, bus_size_t c)
{
	volatile u_int64_t *p, data;

	h += o;
	p = (volatile u_int64_t *)h;
	while (c--) {
		data = *a++;
		*p++ = htole64(data);
	}
}

void
elroy_rrr_2(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int16_t *p, *q = (u_int16_t *)a;

	c /= 2;
	h += o;
	p = (volatile u_int16_t *)h;
	while (c--)
		*q++ = *p++;
}

void
elroy_rrr_4(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int32_t *p, *q = (u_int32_t *)a;

	c /= 4;
	h += o;
	p = (volatile u_int32_t *)h;
	while (c--)
		*q++ = *p++;
}

void
elroy_rrr_8(void *v, bus_space_handle_t h, bus_size_t o,
    u_int8_t *a, bus_size_t c)
{
	volatile u_int64_t *p, *q = (u_int64_t *)a;

	c /= 8;
	h += o;
	p = (volatile u_int64_t *)h;
	while (c--)
		*q++ = *p++;
}

void
elroy_wrr_2(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int16_t *p;
	const u_int16_t *q = (u_int16_t *)a;

	c /= 2;
	h += o;
	p = (volatile u_int16_t *)h;
	while (c--)
		*p++ = *q++;
}

void
elroy_wrr_4(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int32_t *p;
	const u_int32_t *q = (u_int32_t *)a;

	c /= 4;
	h += o;
	p = (volatile u_int32_t *)h;
	while (c--)
		*p++ = *q++;
}

void
elroy_wrr_8(void *v, bus_space_handle_t h, bus_size_t o,
    const u_int8_t *a, bus_size_t c)
{
	volatile u_int64_t *p;
	const u_int64_t *q = (u_int64_t *)a;

	c /= 8;
	h += o;
	p = (volatile u_int64_t *)h;
	while (c--)
		*p++ = *q++;
}

void
elroy_sr_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv, bus_size_t c)
{
	volatile u_int8_t *p;

	h += o;
	p = (volatile u_int8_t *)h;
	while (c--)
		*p++ = vv;
}

void
elroy_sr_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv, bus_size_t c)
{
	volatile u_int16_t *p;

	h += o;
	vv = htole16(vv);
	p = (volatile u_int16_t *)h;
	while (c--)
		*p++ = vv;
}

void
elroy_sr_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv, bus_size_t c)
{
	volatile u_int32_t *p;

	h += o;
	vv = htole32(vv);
	p = (volatile u_int32_t *)h;
	while (c--)
		*p++ = vv;
}

void
elroy_sr_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv, bus_size_t c)
{
	volatile u_int64_t *p;

	h += o;
	vv = htole64(vv);
	p = (volatile u_int64_t *)h;
	while (c--)
		*p++ = vv;
}

void
elroy_cp_1(void *v, bus_space_handle_t h1, bus_size_t o1,
	  bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
{
	while (c--)
		elroy_w1(v, h1, o1++, elroy_r1(v, h2, o2++));
}

void
elroy_cp_2(void *v, bus_space_handle_t h1, bus_size_t o1,
	  bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
{
	while (c--) {
		elroy_w2(v, h1, o1, elroy_r2(v, h2, o2));
		o1 += 2;
		o2 += 2;
	}
}

void
elroy_cp_4(void *v, bus_space_handle_t h1, bus_size_t o1,
	  bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
{
	while (c--) {
		elroy_w4(v, h1, o1, elroy_r4(v, h2, o2));
		o1 += 4;
		o2 += 4;
	}
}

void
elroy_cp_8(void *v, bus_space_handle_t h1, bus_size_t o1,
	  bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
{
	while (c--) {
		elroy_w8(v, h1, o1, elroy_r8(v, h2, o2));
		o1 += 8;
		o2 += 8;
	}
}

const struct hppa64_bus_space_tag elroy_iomemt = {
	NULL,

	NULL, elroy_unmap, elroy_subregion, NULL, elroy_free,
	elroy_barrier, elroy_vaddr,
	elroy_r1,    elroy_r2,    elroy_r4,    elroy_r8,
	elroy_w1,    elroy_w2,    elroy_w4,    elroy_w8,
	elroy_rm_1,  elroy_rm_2,  elroy_rm_4,  elroy_rm_8,
	elroy_wm_1,  elroy_wm_2,  elroy_wm_4,  elroy_wm_8,
	elroy_sm_1,  elroy_sm_2,  elroy_sm_4,  elroy_sm_8,
		     elroy_rrm_2, elroy_rrm_4, elroy_rrm_8,
		     elroy_wrm_2, elroy_wrm_4, elroy_wrm_8,
	elroy_rr_1,  elroy_rr_2,  elroy_rr_4,  elroy_rr_8,
	elroy_wr_1,  elroy_wr_2,  elroy_wr_4,  elroy_wr_8,
		     elroy_rrr_2, elroy_rrr_4, elroy_rrr_8,
		     elroy_wrr_2, elroy_wrr_4, elroy_wrr_8,
	elroy_sr_1,  elroy_sr_2,  elroy_sr_4,  elroy_sr_8,
	elroy_cp_1,  elroy_cp_2,  elroy_cp_4,  elroy_cp_8
};

int		 elroy_dmamap_create(void *v, bus_size_t size,
		    int nsegments, bus_size_t maxsegsz,
		    bus_size_t boundary, int flags,
		    bus_dmamap_t *dmamp);
void		 elroy_dmamap_destroy(void *v, bus_dmamap_t map);
int		 elroy_dmamap_load(void *v, bus_dmamap_t map,
		    void *addr, bus_size_t size,
		    struct proc *p, int flags);
int		 elroy_dmamap_load_mbuf(void *v, bus_dmamap_t map,
		    struct mbuf *m, int flags);
int		 elroy_dmamap_load_uio(void *v, bus_dmamap_t map,
		    struct uio *uio, int flags);
int		 elroy_dmamap_load_raw(void *v, bus_dmamap_t map,
		    bus_dma_segment_t *segs,
		    int nsegs, bus_size_t size, int flags);
void		 elroy_dmamap_unload(void *v, bus_dmamap_t map);
void		 elroy_dmamap_sync(void *v, bus_dmamap_t map, bus_addr_t off,
		    bus_size_t len, int ops);
int		 elroy_dmamem_alloc(void *v, bus_size_t size,
		    bus_size_t alignment, bus_size_t boundary,
		    bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags);
void		 elroy_dmamem_free(void *v, bus_dma_segment_t *segs,
		    int nsegs);
int		 elroy_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs,
		    size_t size, caddr_t *kvap, int flags);
void		 elroy_dmamem_unmap(void *v, caddr_t kva, size_t size);
paddr_t		 elroy_dmamem_mmap(void *v, bus_dma_segment_t *segs,
		    int nsegs, off_t off, int prot, int flags);

int
elroy_dmamap_create(void *v, bus_size_t size, int nsegments,
    bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
{
	struct elroy_softc *sc = v;

	/* TODO check the addresses, boundary, enable dma */

	return (bus_dmamap_create(sc->sc_dmat, size, nsegments,
	    maxsegsz, boundary, flags, dmamp));
}

void
elroy_dmamap_destroy(void *v, bus_dmamap_t map)
{
	struct elroy_softc *sc = v;

	bus_dmamap_destroy(sc->sc_dmat, map);
}

int
elroy_dmamap_load(void *v, bus_dmamap_t map, void *addr, bus_size_t size,
    struct proc *p, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamap_load(sc->sc_dmat, map, addr, size, p, flags));
}

int
elroy_dmamap_load_mbuf(void *v, bus_dmamap_t map, struct mbuf *m, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, flags));
}

int
elroy_dmamap_load_uio(void *v, bus_dmamap_t map, struct uio *uio, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamap_load_uio(sc->sc_dmat, map, uio, flags));
}

int
elroy_dmamap_load_raw(void *v, bus_dmamap_t map, bus_dma_segment_t *segs,
    int nsegs, bus_size_t size, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamap_load_raw(sc->sc_dmat, map, segs, nsegs, size, flags));
}

void
elroy_dmamap_unload(void *v, bus_dmamap_t map)
{
	struct elroy_softc *sc = v;

	bus_dmamap_unload(sc->sc_dmat, map);
}

void
elroy_dmamap_sync(void *v, bus_dmamap_t map, bus_addr_t off,
    bus_size_t len, int ops)
{
	struct elroy_softc *sc = v;

	bus_dmamap_sync(sc->sc_dmat, map, off, len, ops);
}

int
elroy_dmamem_alloc(void *v, bus_size_t size, bus_size_t alignment,
    bus_size_t boundary, bus_dma_segment_t *segs,
    int nsegs, int *rsegs, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamem_alloc(sc->sc_dmat, size, alignment, boundary,
	    segs, nsegs, rsegs, flags));
}

void
elroy_dmamem_free(void *v, bus_dma_segment_t *segs, int nsegs)
{
	struct elroy_softc *sc = v;

	bus_dmamem_free(sc->sc_dmat, segs, nsegs);
}

int
elroy_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size,
    caddr_t *kvap, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamem_map(sc->sc_dmat, segs, nsegs, size, kvap, flags));
}

void
elroy_dmamem_unmap(void *v, caddr_t kva, size_t size)
{
	struct elroy_softc *sc = v;

	bus_dmamem_unmap(sc->sc_dmat, kva, size);
}

paddr_t
elroy_dmamem_mmap(void *v, bus_dma_segment_t *segs, int nsegs, off_t off,
    int prot, int flags)
{
	struct elroy_softc *sc = v;

	return (bus_dmamem_mmap(sc->sc_dmat, segs, nsegs, off, prot, flags));
}

const struct hppa64_bus_dma_tag elroy_dmat = {
	NULL,
	elroy_dmamap_create, elroy_dmamap_destroy,
	elroy_dmamap_load, elroy_dmamap_load_mbuf,
	elroy_dmamap_load_uio, elroy_dmamap_load_raw,
	elroy_dmamap_unload, elroy_dmamap_sync,

	elroy_dmamem_alloc, elroy_dmamem_free, elroy_dmamem_map,
	elroy_dmamem_unmap, elroy_dmamem_mmap
};

const struct hppa64_pci_chipset_tag elroy_pc = {
	NULL,
	elroy_attach_hook, elroy_maxdevs, elroy_make_tag, elroy_decompose_tag,
	elroy_conf_size, elroy_conf_read, elroy_conf_write,
	apic_intr_map, apic_intr_string,
	apic_intr_establish, apic_intr_disestablish,
#if NCARDBUS > 0
	elroy_alloc_parent
#else
	NULL
#endif
};

int		 elroy_print(void *aux, const char *pnp);

int
elroy_print(void *aux, const char *pnp)
{
	struct pcibus_attach_args *pba = aux;

	if (pnp)
		printf("%s at %s\n", pba->pba_busname, pnp);
	return (UNCONF);
}

void
elroy_attach(struct device *parent, struct device *self, void *aux)
{
	struct elroy_softc *sc = (struct elroy_softc *)self;
	struct confargs *ca = (struct confargs *)aux;
	struct pcibus_attach_args pba;
	volatile struct elroy_regs *r;
	const char *p = NULL, *q;
	int i;

	sc->sc_hpa = ca->ca_hpa;
	sc->sc_bt = ca->ca_iot;
	sc->sc_dmat = ca->ca_dmatag;
	if (bus_space_map(sc->sc_bt, ca->ca_hpa, ca->ca_hpasz, 0, &sc->sc_bh)) {
		printf(": can't map space\n");
		return;
	}

	sc->sc_regs = r = bus_space_vaddr(sc->sc_bt, sc->sc_bh);
	elroy_write32(&r->pci_cmdstat, htole32(PCI_COMMAND_IO_ENABLE |
	    PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE));

	elroy_write32(&r->control, elroy_read32(&r->control) &
	    ~htole32(ELROY_CONTROL_RF));
	for (i = 5000; i-- &&
	    elroy_read32(&r->status) & htole32(ELROY_STATUS_RC); DELAY(10));
	if (i < 0) {
		printf(": reset failed; status %b\n",
		    htole32(r->status), ELROY_STATUS_BITS);
		return;
	}

	q = "";
	sc->sc_ver = PCI_REVISION(letoh32(elroy_read32(&r->pci_class)));
	switch ((ca->ca_type.iodc_model << 4) |
	    (ca->ca_type.iodc_revision >> 4)) {
	case 0x782:
		p = "Elroy";
		switch (sc->sc_ver) {
		default:
			q = "+";
		case 5:	sc->sc_ver = 0x40;	break;
		case 4:	sc->sc_ver = 0x30;	break;
		case 3:	sc->sc_ver = 0x22;	break;
		case 2:	sc->sc_ver = 0x21;	break;
		case 1:	sc->sc_ver = 0x20;	break;
		case 0:	sc->sc_ver = 0x10;	break;
		}
		break;

	case 0x783:
		p = "Mercury";
		break;

	case 0x784:
		p = "Quicksilver";
		break;

	default:
		p = "Mojo";
		break;
	}

	printf(": %s TR%d.%d%s", p, sc->sc_ver >> 4, sc->sc_ver & 0xf, q);
	apic_attach(sc);
	printf("\n");

	elroy_write32(&r->imask, htole32(0xffffffff << 30));
	elroy_write32(&r->ibase, htole32(ELROY_BASE_RE));

	/* TODO reserve elroy's pci space ? */

#if 0
printf("lmm %llx/%llx gmm %llx/%llx wlm %llx/%llx wgm %llx/%llx io %llx/%llx eio %llx/%llx\n",
letoh64(r->lmmio_base), letoh64(r->lmmio_mask),
letoh64(r->gmmio_base), letoh64(r->gmmio_mask),
letoh64(r->wlmmio_base), letoh64(r->wlmmio_mask),
letoh64(r->wgmmio_base), letoh64(r->wgmmio_mask),
letoh64(r->io_base), letoh64(r->io_mask),
letoh64(r->eio_base), letoh64(r->eio_mask));
#endif

	/* XXX evil hack! */
	sc->sc_iobase = 0xfee00000;

	sc->sc_iot = elroy_iomemt;
	sc->sc_iot.hbt_cookie = sc;
	sc->sc_iot.hbt_map = elroy_iomap;
	sc->sc_iot.hbt_alloc = elroy_ioalloc;
	sc->sc_memt = elroy_iomemt;
	sc->sc_memt.hbt_cookie = sc;
	sc->sc_memt.hbt_map = elroy_memmap;
	sc->sc_memt.hbt_alloc = elroy_memalloc;
	sc->sc_pc = elroy_pc;
	sc->sc_pc._cookie = sc;
	sc->sc_dmatag = elroy_dmat;
	sc->sc_dmatag._cookie = sc;

	bzero(&pba, sizeof(pba));
	pba.pba_busname = "pci";
	pba.pba_iot = &sc->sc_iot;
	pba.pba_memt = &sc->sc_memt;
	pba.pba_dmat = &sc->sc_dmatag;
	pba.pba_pc = &sc->sc_pc;
	pba.pba_domain = pci_ndomains++;
	pba.pba_bus = 0; /* (letoh32(elroy_read32(&r->busnum)) & 0xff) >> 4; */
	config_found(self, &pba, elroy_print);
}


code:
/*	$OpenBSD: elroyreg.h,v 1.2 2008/04/20 18:41:45 kettenis Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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.
 */

struct elroy_regs {
			/* std PCI bridge header */
	u_int32_t	pci_id;		/* 0x000 rw PCI_ID */
	u_int32_t	pci_cmdstat;	/* 0x004 rw PCI_COMMAND_STATUS_REG */
	u_int32_t	pci_class;	/* 0x008 ro PCI_CLASS_REG */
	u_int32_t	pci_bhlc;	/* 0x00c rw PCI_BHLC_REG */
	u_int32_t	res0[0x30/4];	/* 0x010 */

			/* HW Bridge registers */
	u_int32_t	pci_conf_addr;	/* 0x040 rw config space address */
	u_int32_t	pad040;
	u_int32_t	pci_conf_data;	/* 0x048 rw config space data */
	u_int32_t	pad048;
	u_int64_t	elroy_mtlt;	/* 0x050 */
	u_int32_t	busnum;		/* 0x058 bus number/scratch */
	u_int32_t	par058;
	u_int64_t	res1;		/* 0x060 */
	u_int64_t	rope;		/* 0x068 rope parity, loopback */
	u_int64_t	err_addr;	/* 0x070 error log: address */
	u_int64_t	suspend;	/* 0x078 rw suspend control */
	u_int32_t	arb_mask;	/* 0x080 rw arbitration mask */
	u_int32_t	pad080;
#define	ELROY_ARB_ENABLE	0x01		/* enable arbitration */
#define	ELROY_ARB_PCIDEVA	0x02		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVB	0x04		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVC	0x08		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVD	0x10		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVE	0x20		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVF	0x40		/* PCI device A allow */
#define	ELROY_ARB_PCIDEVG	0x80		/* PCI device A allow */
	u_int64_t	arb_pri;	/* 0x088 arbitration priority */
	u_int64_t	arb_mode;	/* 0x090 arbitration mode */
	u_int64_t	mtlt;		/* 0x098 */
	u_int64_t	res2[12];	/* 0x0a0 */
	u_int64_t	mod_info;	/* 0x100 */
	u_int32_t	control;	/* 0x108 */
#define	ELROY_CONTROL_RF	0x01		/* reset pci */
#define	ELROY_CONTROL_VE	0x08		/* VGA enable */
#define	ELROY_CONTROL_CL	0x10		/* clear error log */
#define	ELROY_CONTROL_CE	0x20		/* clear error log enable */
#define	ELROY_CONTROL_HF	0x40		/* hard fail enable */
	u_int32_t	status;		/* 0x10c */
#define	ELROY_STATUS_RC		0x01		/* reset complete */
#define	ELROY_STATUS_BITS	"\020\01RC"
	u_int64_t	res3[30];	/* 0x110 */
	u_int64_t	lmmio_base;	/* 0x200 */
	u_int64_t	lmmio_mask;	/* 0x208 */
	u_int64_t	gmmio_base;	/* 0x210 */
	u_int64_t	gmmio_mask;	/* 0x218 */
	u_int64_t	wlmmio_base;	/* 0x220 */
	u_int64_t	wlmmio_mask;	/* 0x228 */
	u_int64_t	wgmmio_base;	/* 0x230 */
	u_int64_t	wgmmio_mask;	/* 0x238 */
	u_int32_t	io_base;	/* 0x240 */
	u_int32_t	pad240;
	u_int32_t	io_mask;	/* 0x248 */
	u_int32_t	pad248;
	u_int32_t	res4[4];	/* 0x250 */
	u_int32_t	eio_base;	/* 0x260 */
	u_int32_t	pad260;
	u_int32_t	eio_mask;	/* 0x268 */
	u_int32_t	pad268;
#define	ELROY_BASE_RE	0x01			/* range enable */
	u_int64_t	res5;		/* 0x270 */
	u_int64_t	dmac_ctrl;	/* 0x278 DMA connection control */
	u_int64_t	res6[16];	/* 0x280 */
	u_int32_t	ibase;		/* 0x300 */
	u_int32_t	pad300;
	u_int32_t	imask;		/* 0x308 */
	u_int32_t	pad308;
	u_int64_t	hint_cfg;	/* 0x310 */
	u_int64_t	res7[13];	/* 0x318 */
	u_int64_t	hints[14];	/* 0x380 */
	u_int64_t	res8[2];	/* 0x3f0 */
	u_int64_t	res9[64];	/* 0x400 */
	u_int64_t	pad0;		/* 0x600 */
	u_int64_t	pci_drive;	/* 0x608 */
	u_int64_t	rope_cfg;	/* 0x610 */
	u_int64_t	clk_ctl;	/* 0x618 */
	u_int32_t	pad1;		/* 0x620 */
	u_int32_t	res10[23];	/* 0x624 */
	u_int32_t	err_cfg;	/* 0x680 error config */
	u_int32_t	pad680;
#define	ELROY_ERRCFG_PW		0x01		/* PIO writes parity errors */
#define	ELROY_ERRCFG_PR		0x02		/* PIO reads parity errors */
#define	ELROY_ERRCFG_DW		0x04		/* DMA writes parity errors */
#define	ELROY_ERRCFG_DR		0x08		/* DMA reads parity errors */
#define	ELROY_ERRCFG_CM		0x10		/* no fatal on config space */
#define	ELROY_ERRCFG_SMART	0x20		/* smart bus mode */
	u_int64_t	err_stat;	/* 0x688 error status */
	u_int64_t	err_mid;	/* 0x690 error log: master id */
	u_int64_t	rope_estat;	/* 0x698 rope error status */
	u_int64_t	rope_eclr;	/* 0x6a0 rope error clear */
	u_int64_t	res11[42];	/* 0x6a8 */
	u_int64_t	regbus;		/* 0x7f8 reads 0x3ff */
	u_int32_t	apic_addr;	/* 0x800 APIC address register */
	u_int32_t	pad800;
	u_int64_t	res12;
	u_int32_t	apic_data;	/* 0x810 APIC data register */
	u_int32_t	pad808;
	u_int64_t	res13[5];
	u_int32_t	apic_eoi;	/* 0x840 APIC interrupt ack */
	u_int32_t	pad840;
	u_int32_t	apic_softint;	/* 0x850 write generates softint */
	u_int32_t	pad850;
	u_int64_t	res14[123];	/* 0x858 */
					/*0x1000 */
} __packed;

/* APIC registers */
#define	APIC_VERSION	0x01
#define	APIC_VERSION_MASK	0xff
#define	APIC_VERSION_NENT	0xff0000
#define	APIC_VERSION_NENT_SHIFT	16
#define	APIC_ENT0(i)	(0x10 + (i)*2)
#define	APIC_ENT0_VEC	0x000ff
#define	APIC_ENT0_MOD	0x00700	/* delivery mode */
#define	APIC_ENT0_FXD	0x00000
#define	APIC_ENT0_RDR	0x00100
#define	APIC_ENT0_PMI	0x00200
#define	APIC_ENT0_NMI	0x00400
#define	APIC_ENT0_INI	0x00500
#define	APIC_ENT0_EXT	0x00700
#define	APIC_ENT0_PEND	0x01000	/* int is pending */
#define	APIC_ENT0_LOW	0x02000	/* polarity */
#define	APIC_ENT0_LEV	0x08000	/* edge/level */
#define	APIC_ENT0_MASK	0x10000	/* mask int */
#define	APIC_ENT1(i)	(0x11 + (i)*2)

license: unknown


code:
/*	$OpenBSD: elroyvar.h,v 1.3 2009/08/22 02:54:50 mk Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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 <machine/pdc.h>

struct elroy_softc {
	struct  device sc_dv;

	int sc_ver;
	hppa_hpa_t sc_hpa;
	bus_space_tag_t sc_bt;
	bus_space_handle_t sc_bh;
	bus_dma_tag_t sc_dmat;
	volatile struct elroy_regs *sc_regs;
	bus_addr_t sc_iobase;

	u_int32_t sc_imr;
	int sc_nints;
	int *sc_irq;

	struct pdc_pat_pci_rt *sc_int_tbl;
	int sc_int_tbl_sz;

	struct hppa64_pci_chipset_tag sc_pc;
	struct hppa64_bus_space_tag sc_iot;
	struct hppa64_bus_space_tag sc_memt;
	char sc_memexname[20];
	struct extent *sc_memex;
	struct hppa64_bus_dma_tag sc_dmatag;
};

void apic_attach(struct elroy_softc *sc);
int apic_intr(void *v);
int apic_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp);
const char *apic_intr_string(void *v, pci_intr_handle_t ih);
void *apic_intr_establish(void *v, pci_intr_handle_t ih, int pri,
    int (*handler)(void *), void *arg, const char *name);
void apic_intr_disestablish(void *v, void *cookie);

void elroy_write32(volatile u_int32_t *p, u_int32_t v);
u_int32_t elroy_read32(volatile u_int32_t *p);


code:
/*	$OpenBSD: lpt_ssio.c,v 1.1 2011/08/07 20:36:22 kettenis Exp $	*/

/*
 * Copyright (c) 2007 Mark Kettenis
 *
 * 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 <machine/bus.h>

#include <dev/ic/lptreg.h>
#include <dev/ic/lptvar.h>

#include <hppa64/dev/ssiovar.h>

int lpt_ssio_match(struct device *, void *, void *);
void lpt_ssio_attach(struct device *, struct device *, void *);

struct cfattach lpt_ssio_ca = {
	sizeof(struct lpt_softc), lpt_ssio_match, lpt_ssio_attach
};

int
lpt_ssio_match(struct device *parent, void *match, void *aux)
{
	struct cfdata *cf = match;
	struct ssio_attach_args *saa = aux;

	if (strcmp(saa->saa_name, "lpt") != 0)
		return (0);

	/* Check locators. */
	if (cf->ssiocf_irq != SSIO_UNK_IRQ && cf->ssiocf_irq != saa->saa_irq)
		return (0);

	return (1);
}

void
lpt_ssio_attach(struct device *parent, struct device *self, void *aux)
{
	struct lpt_softc *sc = (void *)self;
	struct ssio_attach_args *saa = aux;

	sc->sc_iot = saa->saa_iot;
	if (bus_space_map(sc->sc_iot, saa->saa_iobase, LPT_NPORTS,
	    0, &sc->sc_ioh)) {
		printf(": cannot map io space\n");
		return;
	}

	lpt_attach_common(sc);

	sc->sc_ih = ssio_intr_establish(IPL_TTY, saa->saa_irq,
	    lptintr, sc, sc->sc_dev.dv_xname);
}


code:
/*	$OpenBSD: mem.c,v 1.9 2015/02/10 22:44:35 miod Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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) 1991,1992,1994, The University of Utah and
 * the Computer Systems Laboratory (CSL).  All rights reserved.
 *
 * Subject to your agreements with CMU,
 * permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
 * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
 * improvements that they make and grant CSL redistribution rights.
 *
 *	Utah $Hdr: mem.c 1.9 94/12/16$
 */
/*
 * Mach Operating System
 * Copyright (c) 1992 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/file.h>

#include <uvm/uvm_extern.h>

#include <machine/conf.h>
#include <machine/bus.h>
#include <machine/iomod.h>
#include <machine/autoconf.h>
#include <machine/pmap.h>

#include <arch/hppa/dev/cpudevs.h>

struct mem_softc {
	struct device sc_dev;
};

int	memmatch(struct device *, void *, void *);
void	memattach(struct device *, struct device *, void *);

struct cfattach mem_ca = {
	sizeof(struct mem_softc), memmatch, memattach
};

struct cfdriver mem_cd = {
	NULL, "mem", DV_DULL
};

caddr_t zeropage;

int
memmatch(parent, cfdata, aux)
	struct device *parent;
	void *cfdata;
	void *aux;
{
	struct confargs *ca = aux;

	if ((ca->ca_name && !strcmp(ca->ca_name, "memory")) ||
	    (ca->ca_type.iodc_type == HPPA_TYPE_MEMORY &&
	     ca->ca_type.iodc_sv_model == HPPA_MEMORY_PDEP))
		return 1;

	return 0;
}

void
memattach(parent, self, aux)
	struct device *parent;
	struct device *self;
	void *aux;
{
	struct pdc_iodc_minit pdc_minit PDC_ALIGNMENT;
	/* struct mem_softc *sc = (struct mem_softc *)self; */
	struct confargs *ca = aux;
	int err;

/* TODO scan the memory regions list */

	if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_NINIT,
	    &pdc_minit, ca->ca_hpa, PAGE0->imm_spa_size)) < 0)
		pdc_minit.max_spa = PAGE0->imm_max_mem;

	printf(": size %d", pdc_minit.max_spa / (1024*1024));
	if (pdc_minit.max_spa % (1024*1024))
		printf(".%d", pdc_minit.max_spa % (1024*1024));
	printf("MB\n");
}

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

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

int
mmrw(dev, uio, flags)
	dev_t dev;
	struct uio *uio;
	int flags;
{
	struct iovec *iov;
	vaddr_t	v, o;
	int error = 0;
	size_t c;

	while (uio->uio_resid > 0 && error == 0) {
		iov = uio->uio_iov;
		if (iov->iov_len == 0) {
			uio->uio_iov++;
			uio->uio_iovcnt--;
			if (uio->uio_iovcnt < 0)
				panic("mmrw");
			continue;
		}
		switch (minor(dev)) {

		case 0:				/*  /dev/mem  */

			/* If the address isn't in RAM, bail. */
			v = uio->uio_offset;
			if (atop(v) > physmem) {
				error = EFAULT;
				/* this will break us out of the loop */
				continue;
			}
			c = ptoa(physmem) - v;
			c = ulmin(c, uio->uio_resid);
			error = uiomove((caddr_t)v, c, uio);
			break;

		case 1:				/*  /dev/kmem  */
			v = uio->uio_offset;
			o = v & PAGE_MASK;
			c = ulmin(uio->uio_resid, (int)(PAGE_SIZE - o));
			if (atop(v) > physmem && !uvm_kernacc((caddr_t)v,
			    c, (uio->uio_rw == UIO_READ) ? B_READ : B_WRITE)) {
				error = EFAULT;
				/* this will break us out of the loop */
				continue;
			}
			error = uiomove((caddr_t)v, c, uio);
			break;

		case 2:				/*  /dev/null  */
			if (uio->uio_rw == UIO_WRITE)
				uio->uio_resid = 0;
			return (0);

		case 12:			/*  /dev/zero  */
			/* Write to /dev/zero is ignored. */
			if (uio->uio_rw == UIO_WRITE) {
				uio->uio_resid = 0;
				return (0);
			}
			/*
			 * On the first call, allocate and zero a page
			 * of memory for use with /dev/zero.
			 */
			if (zeropage == NULL)
				zeropage = malloc(PAGE_SIZE, M_TEMP,
				    M_WAITOK | M_ZERO);
			c = ulmin(iov->iov_len, PAGE_SIZE);
			error = uiomove(zeropage, c, uio);
			break;

		default:
			return (ENXIO);
		}
	}

	return (error);
}

paddr_t
mmmmap(dev, off, prot)
	dev_t dev;
	off_t off;
	int prot;
{
	if (minor(dev) != 0)
		return (-1);

	/*
	 * Allow access only in RAM.
	 */
#if 0
	if (off < ptoa(firstusablepage) ||
	    off >= ptoa(lastusablepage + 1))
		return (-1);
#endif
	return (off);
}

int
mmioctl(dev, cmd, data, flags, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flags;
	struct proc *p;
{
	return (EOPNOTSUPP);
}


code:
/*	$OpenBSD: pdc.c,v 1.11 2011/08/16 17:26:46 kettenis Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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 "com.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/tty.h>
#include <sys/timeout.h>

#include <dev/cons.h>

#include <machine/conf.h>
#include <machine/pdc.h>
#include <machine/iomod.h>
#include <machine/autoconf.h>

typedef
struct pdc_softc {
	struct device sc_dv;
	struct tty *sc_tty;
	struct timeout sc_to;
} pdcsoftc_t;

pdcio_t pdc;
int pdcret[32] PDC_ALIGNMENT;
char pdc_consbuf[IODC_MINIOSIZ] PDC_ALIGNMENT;
iodcio_t pdc_cniodc, pdc_kbdiodc;
pz_device_t *pz_kbd, *pz_cons;

int pdcngetc(dev_t);
void pdcnputc(dev_t, char *);

struct consdev pdccons = { NULL, NULL, pdccngetc, pdccnputc,
     nullcnpollc, NULL, makedev(22, 0), CN_LOWPRI };

int pdcmatch(struct device *, void *, void *);
void pdcattach(struct device *, struct device *, void *);

struct cfattach pdc_ca = {
	sizeof(pdcsoftc_t), pdcmatch, pdcattach
};

struct cfdriver pdc_cd = {
	NULL, "pdc", DV_DULL
};

void pdcstart(struct tty *tp);
void pdctimeout(void *v);
int pdcparam(struct tty *tp, struct termios *);
int pdccnlookc(dev_t dev, int *cp);

#if NCOM > 0
/* serial console speed table */
static int pdc_speeds[] = {
	B50,
	B75,
	B110,
	B150,
	B300,
	B600,
	B1200,
	B2400,
	B4800,
	B7200,
	B9600,
	B19200,
	B38400,
	B57600,
	B115200,
	B230400,
};
#endif

void
pdc_init()
{
	static int kbd_iodc[IODC_MAXSIZE/sizeof(int)];
	static int cn_iodc[IODC_MAXSIZE/sizeof(int)];
	int err;

	/* pdc = (pdcio_t)(long)PAGE0->mem_pdc; */
	pz_kbd = &PAGE0->mem_kbd;
	pz_cons = &PAGE0->mem_cons;

	/* XXX should we reset the console/kbd here?
	   well, /boot did that for us anyway */
	if ((err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, pdcret,
	    pz_cons->pz_hpa, IODC_IO, cn_iodc, (long)IODC_MAXSIZE)) < 0 ||
	    (err = pdc_call((iodcio_t)pdc, 0, PDC_IODC, PDC_IODC_READ, pdcret,
	    pz_kbd->pz_hpa, IODC_IO, kbd_iodc, (long)IODC_MAXSIZE)) < 0) {
#ifdef DEBUG
		printf("pdc_init: failed reading IODC (%d)\n", err);
#endif
	}

	pdc_cniodc = (iodcio_t)cn_iodc;
	pdc_kbdiodc = (iodcio_t)kbd_iodc;

	/* Start out with pdc as the console. */
	cn_tab = &pdccons;

	/* Figure out console settings. */
#if NCOM > 0
	if (PAGE0->mem_cons.pz_class == PCL_DUPLEX) {
		struct pz_device *pzd = &PAGE0->mem_cons;
		extern int comdefaultrate;
#ifdef DEBUG
		printf("console: class %d flags %b ",
		    pzd->pz_class, pzd->pz_flags, PZF_BITS);
		printf("bc %d/%d/%d/%d/%d/%d ",
		    pzd->pz_bc[0], pzd->pz_bc[1], pzd->pz_bc[2],
		    pzd->pz_bc[3], pzd->pz_bc[4], pzd->pz_bc[5]);
		printf("mod %x layers %x/%x/%x/%x/%x/%x hpa %x\n", pzd->pz_mod,
		    pzd->pz_layers[0], pzd->pz_layers[1], pzd->pz_layers[2],
		    pzd->pz_layers[3], pzd->pz_layers[4], pzd->pz_layers[5],
		    pzd->pz_hpa);
#endif

		/* compute correct baud rate */
		if (PZL_SPEED(pzd->pz_layers[0]) <
		    sizeof(pdc_speeds) / sizeof(int))
			comdefaultrate =
			    pdc_speeds[PZL_SPEED(pzd->pz_layers[0])];
		else
			comdefaultrate = B9600;	/* XXX */
	}
#endif
}

int
pdcmatch(parent, cfdata, aux)
	struct device *parent;
	void *cfdata;
	void *aux;
{
	struct cfdata *cf = cfdata;
	struct confargs *ca = aux;

	/* there could be only one */
	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "pdc"))
		return 0;

	return 1;
}

void
pdcattach(parent, self, aux)
	struct device *parent;
	struct device *self;
	void *aux;
{
	struct pdc_softc *sc = (struct pdc_softc *)self;

	if (!pdc)
		pdc_init();

	printf("\n");

	timeout_set(&sc->sc_to, pdctimeout, sc);
}

int
pdcopen(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	int unit = minor(dev);
	struct pdc_softc *sc;
	struct tty *tp;
	int s;
	int error = 0, setuptimeout = 0;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return ENXIO;

	s = spltty();

	if (sc->sc_tty)
		tp = sc->sc_tty;
	else {
		tp = sc->sc_tty = ttymalloc(0);
	}

	tp->t_oproc = pdcstart;
	tp->t_param = pdcparam;
	tp->t_dev = dev;
	if ((tp->t_state & TS_ISOPEN) == 0) {
		ttychars(tp);
		tp->t_iflag = TTYDEF_IFLAG;
		tp->t_oflag = TTYDEF_OFLAG;
		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
		tp->t_lflag = TTYDEF_LFLAG;
		tp->t_ispeed = tp->t_ospeed = B9600;
		ttsetwater(tp);

		setuptimeout = 1;
	} else if (tp->t_state&TS_XCLUDE && suser(p, 0) != 0) {
		splx(s);
		return (EBUSY);
	}
	tp->t_state |= TS_CARR_ON;
	splx(s);

	error = (*linesw[tp->t_line].l_open)(dev, tp, p);
	if (error == 0 && setuptimeout)
		pdctimeout(sc);

	return error;
}

int
pdcclose(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{
	int unit = minor(dev);
	struct tty *tp;
	struct pdc_softc *sc;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return ENXIO;

	tp = sc->sc_tty;
	timeout_del(&sc->sc_to);
	(*linesw[tp->t_line].l_close)(tp, flag, p);
	ttyclose(tp);
	return 0;
}

int
pdcread(dev, uio, flag)
	dev_t dev;
	struct uio *uio;
	int flag;
{
	int unit = minor(dev);
	struct tty *tp;
	struct pdc_softc *sc;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return ENXIO;

	tp = sc->sc_tty;
	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
}

int
pdcwrite(dev, uio, flag)
	dev_t dev;
	struct uio *uio;
	int flag;
{
	int unit = minor(dev);
	struct tty *tp;
	struct pdc_softc *sc;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return ENXIO;

	tp = sc->sc_tty;
	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}

int
pdcioctl(dev, cmd, data, flag, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flag;
	struct proc *p;
{
	int unit = minor(dev);
	int error;
	struct tty *tp;
	struct pdc_softc *sc;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return ENXIO;

	tp = sc->sc_tty;
	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
	if (error >= 0)
		return error;
	error = ttioctl(tp, cmd, data, flag, p);
	if (error >= 0)
		return error;

	return ENOTTY;
}

int
pdcparam(tp, t)
	struct tty *tp;
	struct termios *t;
{

	return 0;
}

void
pdcstart(tp)
	struct tty *tp;
{
	int s;

	s = spltty();
	if (tp->t_state & (TS_TTSTOP | TS_BUSY)) {
		splx(s);
		return;
	}
	ttwakeupwr(tp);
	tp->t_state |= TS_BUSY;
	while (tp->t_outq.c_cc != 0)
		pdccnputc(tp->t_dev, getc(&tp->t_outq));
	tp->t_state &= ~TS_BUSY;
	splx(s);
}

int
pdcstop(tp, flag)
	struct tty *tp;
	int flag;
{
	int s;

	s = spltty();
	if (tp->t_state & TS_BUSY)
		if ((tp->t_state & TS_TTSTOP) == 0)
			tp->t_state |= TS_FLUSH;
	splx(s);
	return 0;
}

void
pdctimeout(v)
	void *v;
{
	struct pdc_softc *sc = v;
	struct tty *tp = sc->sc_tty;
	int c;

	while (pdccnlookc(tp->t_dev, &c)) {
		if (tp->t_state & TS_ISOPEN)
			(*linesw[tp->t_line].l_rint)(c, tp);
	}
	timeout_add(&sc->sc_to, 1);
}

struct tty *
pdctty(dev)
	dev_t dev;
{
	int unit = minor(dev);
	struct pdc_softc *sc;

	if (unit >= pdc_cd.cd_ndevs || (sc = pdc_cd.cd_devs[unit]) == NULL)
		return NULL;

	return sc->sc_tty;
}

int
pdccnlookc(dev, cp)
	dev_t dev;
	int *cp;
{
	int err, l;
	int s = splhigh();

	err = pdc_call(pdc_kbdiodc, 0, pz_kbd->pz_hpa, IODC_IO_CONSIN,
	    pz_kbd->pz_spa, pz_kbd->pz_layers, pdcret, 0, pdc_consbuf,
	    (long)1, (long)0);

	l = pdcret[0];
	*cp = pdc_consbuf[0];
	splx(s);
#ifdef DEBUG
	if (err < 0)
		printf("pdccnlookc: input error: %d\n", err);
#endif

	return l;
}

int
pdccngetc(dev)
	dev_t dev;
{
	int c;

	if (!pdc)
		return 0;

	while(!pdccnlookc(dev, &c))
		;

	return (c);
}

void
pdccnputc(dev, c)
	dev_t dev;
	int c;
{
	register int err;
	int s = splhigh();

	*pdc_consbuf = c;
	err = pdc_call(pdc_cniodc, 0, pz_cons->pz_hpa, IODC_IO_CONSOUT,
	    pz_cons->pz_spa, pz_cons->pz_layers, pdcret, 0, pdc_consbuf,
	    (long)1, (long)0);
	splx(s);

	if (err < 0) {
#ifdef DEBUG
		printf("pdccnputc: output error: %d\n", err);
#endif
	}
}


code:
/*	$OpenBSD: power.c,v 1.4 2014/07/12 20:18:08 uebayasi Exp $	*/

/*
 * Copyright (c) 2005 Michael Shalayeff
 * All rights reserved.
 *
 * 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 MIND, 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/proc.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kthread.h>

#include <machine/reg.h>
#include <machine/pdc.h>
#include <machine/autoconf.h>

struct power_softc {
	struct device sc_dev;
	void *sc_ih;

	struct proc *sc_thread;
	void (*sc_kicker)(void *);

	int sc_dr_cnt;
	paddr_t sc_pwr_reg;
	volatile int sc_interrupted;
};

int	powermatch(struct device *, void *, void *);
void	powerattach(struct device *, struct device *, void *);

struct cfattach power_ca = {
	sizeof(struct power_softc), powermatch, powerattach
};

struct cfdriver power_cd = {
	NULL, "power", DV_DULL
};

void power_thread_create(void *v);
void power_thread_reg(void *v);
void power_cold_hook_reg(int);
int power_intr(void *);

int
powermatch(struct device *parent, void *cfdata, void *aux)
{
	struct cfdata *cf = cfdata;
	struct confargs *ca = aux;

	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power"))
		return (0);

	return (1);
}

void
powerattach(struct device *parent, struct device *self, void *aux)
{
	struct power_softc *sc = (struct power_softc *)self;
	struct confargs *ca = aux;

	if (ca->ca_hpa) {
		extern void (*cold_hook)(int);

		sc->sc_pwr_reg = ca->ca_hpa;
		cold_hook = power_cold_hook_reg;
		sc->sc_kicker = power_thread_reg;
		printf("\n");
	} else
		printf(": not available\n");

	if (ca->ca_irq >= 0)
		sc->sc_ih = cpu_intr_establish(IPL_CLOCK, ca->ca_irq,
		    power_intr, sc, sc->sc_dev.dv_xname);

	if (sc->sc_kicker)
		kthread_create_deferred(power_thread_create, sc);
}

int
power_intr(void *v)
{
	struct power_softc *sc = v;

	sc->sc_interrupted = 1;

	return (1);
}

void
power_thread_create(void *v)
{
	struct power_softc *sc = v;

	if (kthread_create(sc->sc_kicker, sc, &sc->sc_thread,
	    sc->sc_dev.dv_xname))
		printf("WARNING: failed to create kernel power thread\n");
}

void
power_thread_reg(void *v)
{
	struct power_softc *sc = v;
	u_int32_t r;

	for (;;) {
		__asm volatile("ldwas 0(%1), %0"
		    : "=&r" (r) : "r" (sc->sc_pwr_reg));

		if (!(r & 1))
			prsignal(initprocess, SIGUSR2);

		tsleep(v, PWAIT, "regpower", 10);
	}
}

void
power_cold_hook_reg(int on)
{
	extern struct pdc_power_info pdc_power_info;	/* machdep.c */
	int error;

	if ((error = pdc_call((iodcio_t)pdc, 0, PDC_SOFT_POWER,
	    PDC_SOFT_POWER_ENABLE, &pdc_power_info,
	    on == HPPA_COLD_HOT)))
		printf("power_cold_hook_reg: failed (%d)\n", error);
}


code:
/*	$OpenBSD: ssio.c,v 1.1 2011/08/07 20:36:22 kettenis Exp $	*/

/*
 * Copyright (c) 2007 Mark Kettenis
 *
 * 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.
 */

/*
 * Driver for the National Semiconductor PC87560 Legacy I/O chip.
 */

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

#include <machine/bus.h>
#include <machine/iomod.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pciidereg.h>

#include <hppa64/dev/ssiovar.h>

#include "ukbd.h"
#if NUKBD > 0
#include <dev/usb/ohcireg.h>
#include <dev/usb/ukbdvar.h>
#endif

/* PCI config space. */
#define SSIO_PCI_DMA_RC2	0x64
#define SSIO_PCI_INT_TC1	0x67
#define SSIO_PCI_INT_TC2	0x68
#define SSIO_PCI_INT_RC1	0x69
#define SSIO_PCI_INT_RC2	0x6a
#define SSIO_PCI_INT_RC3	0x6b
#define SSIO_PCI_INT_RC4	0x6c
#define SSIO_PCI_INT_RC5	0x6d
#define SSIO_PCI_INT_RC6	0x6e
#define SSIO_PCI_INT_RC7	0x6f
#define SSIO_PCI_INT_RC8	0x70
#define SSIO_PCI_INT_RC9	0x71
#define SSIO_PCI_SP1BAR		0x94
#define SSIO_PCI_SP2BAR		0x98
#define SSIO_PCI_PPBAR		0x9c

#define SSIO_PCI_INT_TC1_MASK	0xff
#define SSIO_PCI_INT_TC1_SHIFT	24

#define SSIO_PCI_INT_TC2_MASK	0xff
#define SSIO_PCI_INT_TC2_SHIFT	0

#define SSIO_PCI_INT_RC1_MASK	0xff
#define SSIO_PCI_INT_RC1_SHIFT	8

#define SSIO_PCI_INT_RC2_MASK	0xff
#define SSIO_PCI_INT_RC2_SHIFT	16

#define SSIO_PCI_INT_RC3_MASK	0xff
#define SSIO_PCI_INT_RC3_SHIFT	24

#define SSIO_PCI_INT_RC4_MASK	0xff
#define SSIO_PCI_INT_RC4_SHIFT	0

#define SSIO_PCI_INT_RC5_MASK	0xff
#define SSIO_PCI_INT_RC5_SHIFT	8

#define SSIO_PCI_INT_RC6_MASK	0xff
#define SSIO_PCI_INT_RC6_SHIFT	16

#define SSIO_PCI_INT_RC7_MASK	0xff
#define SSIO_PCI_INT_RC7_SHIFT	24

#define SSIO_PCI_INT_RC8_MASK	0xff
#define SSIO_PCI_INT_RC8_SHIFT	0

#define SSIO_PCI_INT_RC9_MASK	0xff
#define SSIO_PCI_INT_RC9_SHIFT	8

/* Cascaded i8259-compatible PICs. */
#define SSIO_PIC1	0x20
#define SSIO_PIC2	0xa0
#define SSIO_NINTS	16

int	ssio_match(struct device *, void *, void *);
void	ssio_attach(struct device *, struct device *, void *);

struct ssio_iv {
	int (*handler)(void *);
	void *arg;
};

struct ssio_iv ssio_intr_table[SSIO_NINTS];

struct ssio_softc {
	struct device sc_dev;

	bus_space_tag_t sc_iot;
	bus_space_handle_t sc_ic1h;
	bus_space_handle_t sc_ic2h;
	void *sc_ih;
};

struct cfattach ssio_ca = {
	sizeof(struct ssio_softc), ssio_match, ssio_attach
};

struct cfdriver ssio_cd = {
	NULL, "ssio", DV_DULL
};

const struct pci_matchid ssio_devices[] = {
	{ PCI_VENDOR_NS, PCI_PRODUCT_NS_PC87560 }
};

int	ssio_intr(void *);
int	ssio_print(void *, const char *);

int
ssio_match(struct device *parent, void *match, void *aux)
{
	struct pci_attach_args *pa = aux;
	pcireg_t bhlc, id;
	pcitag_t tag;

	/*
	 * The firmware doesn't always switch the IDE function into native
	 * mode.  So we do that ourselves since it makes life much simpler.
	 * Note that we have to do this in the match function since the
	 * Legacy I/O function attaches after the IDE function.
	 */
	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_PC87415) {
		bhlc = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
		if (!PCI_HDRTYPE_MULTIFN(bhlc))
			return (0);

		tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 1);
		id = pci_conf_read(pa->pa_pc, tag, PCI_ID_REG);
		if (PCI_VENDOR(id) != PCI_VENDOR_NS ||
		    PCI_PRODUCT(id) != PCI_PRODUCT_NS_PC87560)
			return (0);

		pa->pa_class |= PCIIDE_INTERFACE_PCI(0) << PCI_INTERFACE_SHIFT;
		pa->pa_class |= PCIIDE_INTERFACE_PCI(1) << PCI_INTERFACE_SHIFT;
		pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG,
		    pa->pa_class);
		return (0);
	}

	return (pci_matchbyid((struct pci_attach_args *)aux, ssio_devices,
	    sizeof(ssio_devices) / sizeof (ssio_devices[0])));
}

void
ssio_attach(struct device *parent, struct device *self, void *aux)
{
	struct ssio_softc *sc = (void *)self;
	struct pci_attach_args *pa = aux;
	struct ssio_attach_args saa;
	pci_intr_handle_t ih;
	const char *intrstr;
	pcireg_t reg;
#if NUKBD > 0
	pcitag_t tag;
#endif

	sc->sc_iot = pa->pa_iot;
	if (bus_space_map(sc->sc_iot, SSIO_PIC1, 2, 0, &sc->sc_ic1h)) {
		printf(": unable to map PIC1 registers\n");
		return;
	}
	if (bus_space_map(sc->sc_iot, SSIO_PIC2, 2, 0, &sc->sc_ic2h)) {
		printf(": unable to map PIC2 registers\n");
		goto unmap_ic1;
	}

	if (pci_intr_map(pa, &ih)) {
		printf(": unable to map interrupt\n");
		goto unmap_ic2;
	}
	intrstr = pci_intr_string(pa->pa_pc, ih);
	/* XXX Probably should be IPL_NESTED. */
	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_TTY, ssio_intr,
	    sc, sc->sc_dev.dv_xname);
	if (sc->sc_ih == NULL) {
		printf(": couldn't establish interrupt\n");
		goto unmap_ic2;
	}

	printf(": %s\n", intrstr);

	/*
	 * We use the following interrupt mapping:
	 *
	 * USB (INTD#)		IRQ 1
	 * IDE Channel 1	IRQ 5
	 * Serial Port 1	IRQ 4
	 * Serial Port 2	IRQ 3
	 * Parallel Port	IRQ 7
	 *
	 * USB and IDE are set to level triggered, all others to edge
	 * triggered.
	 *
	 * We disable all other interrupts since we don't need them.
	 */
	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_DMA_RC2);
	reg &= ~(SSIO_PCI_INT_TC1_MASK << SSIO_PCI_INT_TC1_SHIFT);
	reg |= 0x22 << SSIO_PCI_INT_TC1_SHIFT;
	pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_DMA_RC2, reg);

	reg = 0;
	reg |= 0x34 << SSIO_PCI_INT_RC1_SHIFT;	/* SP1, SP2 */
	reg |= 0x07 << SSIO_PCI_INT_RC2_SHIFT;	/* PP */
	reg |= 0x05 << SSIO_PCI_INT_RC3_SHIFT;	/* IDE1 */
	pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_INT_TC2, reg);

	reg = 0;
	reg |= 0x10 << SSIO_PCI_INT_RC5_SHIFT;	/* INTD# (USB) */
	pci_conf_write(pa->pa_pc, pa->pa_tag, SSIO_PCI_INT_RC4, reg);

	/* Program PIC1. */
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x11);
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x00);
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x04);
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x01);

	/* Priority (3-7,0-2). */
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0xc2);

	/* Program PIC2. */
	bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 0, 0x11);
	bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x00);
	bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x02);
	bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x01);

	/* Unmask all interrupts. */
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 1, 0x00);
	bus_space_write_1(sc->sc_iot, sc->sc_ic2h, 1, 0x00);

	/* Serial Port 1. */
	saa.saa_name = "com";
	saa.saa_iot = sc->sc_iot;
	saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_SP1BAR);
	saa.saa_iobase &= 0xfffffffe;
	saa.saa_irq = 4;
	config_found(self, &saa, ssio_print);

	/* Serial Port 2. */
	saa.saa_name = "com";
	saa.saa_iot = sc->sc_iot;
	saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_SP2BAR);
	saa.saa_iobase &= 0xfffffffe;
	saa.saa_irq = 3;
	config_found(self, &saa, ssio_print);

	/* Parallel Port. */
	saa.saa_name = "lpt";
	saa.saa_iot = sc->sc_iot;
	saa.saa_iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, SSIO_PCI_PPBAR);
	saa.saa_iobase &= 0xfffffffe;
	saa.saa_irq = 7;
	config_found(self, &saa, ssio_print);

#if NUKBD > 0
	/*
	 * If a USB keybard is used for console input, the firmware passes
	 * the mmio address of the USB controller the keyboard is attached
	 * to.  Since we know the USB controller is function 2 on the same
	 * device and comes right after us (we're function 1 remember),
	 * this is a convenient spot to mark the USB keyboard as console
	 * if the address matches.
	 */
	tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 2);
	reg = pci_conf_read(pa->pa_pc, tag, PCI_CBMEM);

	if (PAGE0->mem_kbd.pz_class == PCL_KEYBD &&
	    PAGE0->mem_kbd.pz_hpa == reg)
		ukbd_cnattach();
#endif

	return;

unmap_ic2:
	bus_space_unmap(sc->sc_iot, sc->sc_ic2h, 2);
unmap_ic1:
	bus_space_unmap(sc->sc_iot, sc->sc_ic1h, 2);
}

int
ssio_intr(void *v)
{
	struct ssio_softc *sc = v;
	struct ssio_iv *iv;
	int claimed = 0;
	int irq, isr;

	/* Poll for interrupt. */
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x0c);
	irq = bus_space_read_1(sc->sc_iot, sc->sc_ic1h, 0);
	irq &= 0x07;

	if (irq  == 7) {
		bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x0b);
		isr = bus_space_read_1(sc->sc_iot, sc->sc_ic1h, 0);
		if ((isr & 0x80) == 0)
			/* Spurious interrupt. */
			return (0);
	}

	iv = &ssio_intr_table[irq];
	if (iv->handler)
		claimed = iv->handler(iv->arg);

	/* Signal EOI. */
	bus_space_write_1(sc->sc_iot, sc->sc_ic1h, 0, 0x60 | (irq & 0x0f));

	return (claimed);
}

void *
ssio_intr_establish(int pri, int irq, int (*handler)(void *), void *arg,
    const char *name)
{
	struct ssio_iv *iv;

	if (irq < 0 || irq >= SSIO_NINTS || ssio_intr_table[irq].handler)
		return (NULL);

	iv = &ssio_intr_table[irq];
	iv->handler = handler;
	iv->arg = arg;

	return (iv);
}

int
ssio_print(void *aux, const char *pnp)
{
	struct ssio_attach_args *saa = aux;

	if (pnp)
		printf("%s at %s", saa->saa_name, pnp);
	if (saa->saa_iobase) {
		printf(" offset %lx", saa->saa_iobase);
		if (!pnp && saa->saa_irq >= 0)
			printf(" irq %d", saa->saa_irq);
	}

	return (UNCONF);
}


code:
/*	$OpenBSD: ssiovar.h,v 1.1 2011/08/07 20:36:22 kettenis Exp $	*/

/*
 * Copyright (c) 2007 Mark Kettenis
 *
 * 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.
 */

struct ssio_attach_args {
	const char *saa_name;
	bus_space_tag_t saa_iot;
	bus_addr_t saa_iobase;
	int saa_irq;
};

#define ssiocf_irq	cf_loc[0]
#define SSIO_UNK_IRQ	-1

void *ssio_intr_establish(int, int, int (*)(void *), void *, const char *);


code:
/*	$OpenBSD: autoconf.c,v 1.23 2014/12/09 06:58:28 doug Exp $	*/

/*
 * Copyright (c) 1998-2005 Michael Shalayeff
 * 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.
 *
 *	@(#)autoconf.c	8.4 (Berkeley) 10/1/93
 */

#include "pci.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/conf.h>
#include <sys/reboot.h>
#include <sys/device.h>
#include <sys/timeout.h>
#include <sys/malloc.h>

#include <machine/iomod.h>
#include <machine/autoconf.h>
#include <machine/reg.h>

#include <dev/cons.h>

#include <hppa/dev/cpudevs.h>

#if NPCI > 0
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#endif

/* device we booted from */
struct device *bootdv;
void	dumpconf(void);
void	print_devpath(const char *label, struct pz_device *pz);

void (*cold_hook)(int); /* see below */

/*
 * LED blinking thing
 */
#ifdef USELEDS
#include <sys/kernel.h>

struct timeout heartbeat_tmo;
void heartbeat(void *);
#endif

#include "cd.h"
#include "sd.h"
#include "st.h"
#include "mpath.h"

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#if NMPATH > 0
#include <scsi/mpathvar.h>
#endif

/*
 * cpu_configure:
 * called at boot time, configure all devices on system
 */
void
cpu_configure(void)
{
	struct confargs ca;

	splhigh();
	bzero(&ca, sizeof(ca));
	if (config_rootfound("mainbus", &ca) == NULL)
		panic("no mainbus found");

	cpu_intr_init();
	spl0();

	if (cold_hook)
		(*cold_hook)(HPPA_COLD_HOT);

#ifdef USELEDS
	timeout_set(&heartbeat_tmo, heartbeat, NULL);
	heartbeat(NULL);
#endif
	cold = 0;
}

void
diskconf(void)
{
	print_devpath("bootpath", &PAGE0->mem_boot);

#if NMPATH > 0
	if (bootdv != NULL)
		bootdv = mpath_bootdv(bootdv);
#endif

	setroot(bootdv, 0, RB_USERREQ);
	dumpconf();
}

#ifdef USELEDS
/*
 * turn the heartbeat alive.
 * right thing would be to pass counter to each subsequent timeout
 * as an argument to heartbeat() incrementing every turn,
 * i.e. avoiding the static hbcnt, but doing timeout_set() on each
 * timeout_add() sounds ugly, guts of struct timeout looks ugly
 * to ponder in even more.
 */
void
heartbeat(void *v)
{
	static u_int hbcnt = 0, ocp_total, ocp_idle;
	int toggle, cp_mask, cp_total, cp_idle;
	struct schedstate_percpu *spc = &(curcpu()->ci_schedstate);

	timeout_add(&heartbeat_tmo, hz / 16);

	cp_idle = spc->spc_cp_time[CP_IDLE];
	cp_total = spc->spc_cp_time[CP_USER] + spc->spc_cp_time[CP_NICE] +
	    spc->spc_cp_time[CP_SYS] + spc->spc_cp_time[CP_INTR] +
	    spc->spc_cp_time[CP_IDLE];
	if (cp_total == ocp_total)
		cp_total = ocp_total + 1;
	if (cp_idle == ocp_idle)
		cp_idle = ocp_idle + 1;
	cp_mask = 0xf0 >> (cp_idle - ocp_idle) * 4 / (cp_total - ocp_total);
	cp_mask &= 0xf0;
	ocp_total = cp_total;
	ocp_idle = cp_idle;
	/*
	 * do this:
	 *
	 *   |~| |~|
	 *  _| |_| |_,_,_,_
	 *   0 1 2 3 4 6 7
	 */
	toggle = 0;
	if (hbcnt++ < 8 && hbcnt & 1)
		toggle = PALED_HEARTBEAT;
	hbcnt &= 15;
	ledctl(cp_mask,
	    (~cp_mask & 0xf0) | PALED_NETRCV | PALED_NETSND | PALED_DISK,
	    toggle);
}
#endif

/*
 * This is called by configure to set dumplo and dumpsize.
 * Dumps always skip the first CLBYTES of disk space
 * in case there might be a disk label stored there.
 * If there is extra space, put dump at the end to
 * reduce the chance that swapping trashes it.
 */
void
dumpconf(void)
{
	extern int dumpsize;
	int nblks, dumpblks;	/* size of dump area */

	if (dumpdev == NODEV ||
	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
		return;
	if (nblks <= ctod(1))
		return;

	dumpblks = cpu_dumpsize();
	if (dumpblks < 0)
		return;
	dumpblks += ctod(physmem);

	/* If dump won't fit (incl. room for possible label), punt. */
	if (dumpblks > (nblks - ctod(1)))
		return;

	/* Put dump at end of partition */
	dumplo = nblks - dumpblks;

	/* dumpsize is in page units, and doesn't include headers. */
	dumpsize = physmem;
}

void
print_devpath(const char *label, struct pz_device *pz)
{
	int i;

	printf("%s: ", label);

	for (i = 0; i < 6; i++)
		if (pz->pz_bc[i] >= 0)
			printf("%d/", pz->pz_bc[i]);

	printf("%d.%x", pz->pz_mod, pz->pz_layers[0]);
	for (i = 1; i < 6 && pz->pz_layers[i]; i++)
		printf(".%x", pz->pz_layers[i]);

	printf(" class=%d flags=%b hpa=0x%08x spa=0x%08x io=0x%08x\n",
	    pz->pz_class, pz->pz_flags, PZF_BITS, pz->pz_hpa, pz->pz_spa,
	    pz->pz_iodc_io);
}

u_int32_t pdc_rt[16 / 4 * sizeof(struct pdc_pat_pci_rt)] PDC_ALIGNMENT;
struct pdc_sysmap_find pdc_find PDC_ALIGNMENT;
struct pdc_iodc_read pdc_iodc_read PDC_ALIGNMENT;
struct pdc_pat_cell_id pdc_pat_cell_id PDC_ALIGNMENT;
struct pdc_pat_cell_module pdc_pat_cell_module PDC_ALIGNMENT;
struct pdc_pat_io_num pdc_pat_io_num PDC_ALIGNMENT;
const char *pat_names[] = {
	"central",
	"cpu",
	"memory",
	"sba",
	"lba",
	"pbc",
	"cfc",
	"fabric"
};

void
pdc_scan(struct device *self, struct confargs *ca)
{
	struct device_path path;
	struct confargs nca;
	u_long	rv[16];
	int	i, err, mod = ca->ca_mod;

	if (pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL, PDC_PAT_CELL_GETID,
	    &pdc_pat_cell_id, 0))
		for (i = 0; !(err = pdc_call((iodcio_t)pdc, 0, PDC_SYSMAP,
		    PDC_SYSMAP_FIND, &pdc_find, &path, i)); i++) {
			if (autoconf_verbose)
				printf(">> hpa %x/%x dp %d/%d/%d/%d/%d/%d.%d\n",
				    pdc_find.hpa, pdc_find.size,
				    path.dp_bc[0], path.dp_bc[1], path.dp_bc[2],
				    path.dp_bc[3], path.dp_bc[4], path.dp_bc[5],
				    path.dp_mod);

			if (path.dp_bc[5] == mod) {
				nca = *ca;
				nca.ca_name = NULL;
				nca.ca_hpa = 0xffffffff00000000ULL |
				    (hppa_hpa_t)pdc_find.hpa;
				nca.ca_hpasz = pdc_find.size;
				nca.ca_mod = path.dp_mod;

				err = pdc_call((iodcio_t)pdc, 0, PDC_IODC,
				    PDC_IODC_READ, &pdc_iodc_read, nca.ca_hpa,
				    IODC_DATA, &nca.ca_type, sizeof(nca.ca_type));
				if (err < 0 || pdc_iodc_read.size < 8) {
					if (autoconf_verbose)
						printf(">> iodc_data error %d\n", err);
					bzero(&nca.ca_type, sizeof(nca.ca_type));
				}

				if (autoconf_verbose) {
					u_int *p = (u_int *)&nca.ca_type;
					printf(">> iodc_data 0x%08x 0x%08x\n",
					    p[0], p[1]);
				}

				config_found(self, &nca, mbprint);
			}
		}

	for (i = 0; !(err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL,
	    PDC_PAT_CELL_MODULE, rv, pdc_pat_cell_id.loc, i,
	    PDC_PAT_PAVIEW, &pdc_pat_cell_module, 0)); i++) {
		if (autoconf_verbose)
			printf(">> chpa %lx info %lx loc %lx "
			    "dp %d/%d/%d/%d/%d/%d.%d\n",
			    pdc_pat_cell_module.chpa, pdc_pat_cell_module.info,
			    pdc_pat_cell_module.loc,
			    pdc_pat_cell_module.dp.dp_bc[0],
			    pdc_pat_cell_module.dp.dp_bc[1],
			    pdc_pat_cell_module.dp.dp_bc[2],
			    pdc_pat_cell_module.dp.dp_bc[3],
			    pdc_pat_cell_module.dp.dp_bc[4],
			    pdc_pat_cell_module.dp.dp_bc[5],
			    pdc_pat_cell_module.dp.dp_mod);

		if (pdc_pat_cell_module.dp.dp_bc[5] == mod) {
			int t;

			t = PDC_PAT_CELL_MODTYPE(pdc_pat_cell_module.info);
			if (t >= sizeof(pat_names)/sizeof(pat_names[0]))
				continue;

			nca = *ca;
			nca.ca_name = pat_names[t];
			nca.ca_hpa = pdc_pat_cell_module.chpa &
			    ~(u_long)PAGE_MASK;
			nca.ca_hpasz =
			    PDC_PAT_CELL_MODSIZE(pdc_pat_cell_module.info);
			nca.ca_mod = pdc_pat_cell_module.dp.dp_mod;

			err = pdc_call((iodcio_t)pdc, 0, PDC_IODC,
			    PDC_IODC_READ, &pdc_iodc_read, nca.ca_hpa,
			    IODC_DATA, &nca.ca_type, sizeof(nca.ca_type));
			if (err < 0 || pdc_iodc_read.size < 8) {
				if (autoconf_verbose)
					printf(">> iodc_data error %d\n", err);
				bzero(&nca.ca_type, sizeof(nca.ca_type));
			}
			if (autoconf_verbose) {
				u_int *p = (u_int *)&nca.ca_type;
				printf(">> iodc_data 0x%08x 0x%08x\n",
				    p[0], p[1]);
			}

			config_found(self, &nca, mbprint);
		}
	}
}

struct pdc_pat_pci_rt *pdc_getirt(int *);

struct pdc_pat_pci_rt *
pdc_getirt(int *pn)
{
	struct pdc_pat_pci_rt *rt;
	int i, num, err;
	long cell;

	cell = -1;
	if (!pdc_call((iodcio_t)pdc, 0, PDC_PAT_CELL, PDC_PAT_CELL_GETID,
	    &pdc_pat_cell_id, 0)) {
		cell = pdc_pat_cell_id.id;

		if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_IO,
		    PDC_PAT_IO_GET_PCI_RTSZ, &pdc_pat_io_num, cell))) {
			printf("irt size error %d\n", err);
			return (NULL);
		}
	} else if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX,
	    PDC_PCI_GET_INT_TBL_SZ, &pdc_pat_io_num, cpu_gethpa(0)))) {
		printf("irt size error %d\n", err);
		return (NULL);
	}

printf("num %d ", pdc_pat_io_num.num);
	*pn = num = pdc_pat_io_num.num;
	if (num > sizeof(pdc_rt) / sizeof(*rt)) {
		printf("\nPCI IRT is too big %d\n", num);
		return (NULL);
	}

	if (!(rt = mallocarray(num, sizeof(*rt), M_DEVBUF, M_NOWAIT)))
		return (NULL);

	if (cell >= 0) {
		if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PAT_IO,
		    PDC_PAT_IO_GET_PCI_RT, rt, cell))) {
			printf("irt fetch error %d\n", err);
			free(rt, M_DEVBUF, 0);
			return (NULL);
		}
	} else if ((err = pdc_call((iodcio_t)pdc, 0, PDC_PCI_INDEX,
	    PDC_PCI_GET_INT_TBL, &pdc_pat_io_num, cpu_gethpa(0), pdc_rt))) {
		printf("irt fetch error %d\n", err);
		free(rt, M_DEVBUF, 0);
		return (NULL);
	}
	bcopy(pdc_rt, rt, num * sizeof(*rt));

for (i = 0; i < num; i++)
printf("\n%d: ty 0x%02x it 0x%02x trig 0x%02x pin 0x%02x bus %d seg %d line %d addr 0x%llx",
i, rt[i].type, rt[i].itype, rt[i].trigger, rt[i].pin, rt[i].bus, rt[i].seg, rt[i].line, rt[i].addr);
	return rt;
}

const struct hppa_mod_info hppa_knownmods[] = {
#include <arch/hppa/dev/cpudevs_data.h>
};

const char *
hppa_mod_info(int type, int sv)
{
	const struct hppa_mod_info *mi;
	static char fakeid[32];

	for (mi = hppa_knownmods; mi->mi_type >= 0 &&
	    (mi->mi_type != type || mi->mi_sv != sv); mi++);

	if (mi->mi_type < 0) {
		snprintf(fakeid, sizeof fakeid, "type %x, sv %x", type, sv);
		return fakeid;
	} else
		return mi->mi_name;
}

void
device_register(struct device *dev, void *aux)
{
#if NPCI > 0
	extern struct cfdriver pci_cd;
#endif
#if NCD > 0 || NSD > 0 || NST > 0
	extern struct cfdriver scsibus_cd;
#endif
	struct confargs *ca = aux;
	static struct device *elder = NULL;

	if (bootdv != NULL)
		return;	/* We already have a winner */

#if NPCI > 0
	if (dev->dv_parent &&
	    dev->dv_parent->dv_cfdata->cf_driver == &pci_cd) {
		struct pci_attach_args *pa = aux;
		pcireg_t addr;
		int reg;

		for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) {
			addr = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
			if (PCI_MAPREG_TYPE(addr) == PCI_MAPREG_TYPE_IO)
				addr = PCI_MAPREG_IO_ADDR(addr);
			else
				addr = PCI_MAPREG_MEM_ADDR(addr);

			if (addr == (pcireg_t)(u_long)PAGE0->mem_boot.pz_hpa) {
				elder = dev;
				break;
			}
		}
	} else
#endif
	if (ca->ca_hpa == (hppa_hpa_t)PAGE0->mem_boot.pz_hpa) {
		/*
		 * If hpa matches, the only thing we know is that the
		 * booted device is either this one or one of its children.
		 * And the children will not necessarily have the correct
		 * hpa value.
		 * Save this elder for now.
		 */
		elder = dev;
	} else if (elder == NULL) {
		return;	/* not the device we booted from */
	}

	/*
	 * Unfortunately, we can not match on pz_class vs dv_class on
	 * older snakes netbooting using the rbootd protocol.
	 * In this case, we'll end up with pz_class == PCL_RANDOM...
	 * Instead, trust the device class from what the kernel attached
	 * now...
	 */
	switch (dev->dv_class) {
	case DV_IFNET:
		/*
		 * Netboot is the top elder
		 */
		if (elder == dev) {
			bootdv = dev;
		}
		return;
	case DV_DISK:
	case DV_DULL:
		if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_RANDOM)
			return;
		break;
	case DV_TAPE:
		if ((PAGE0->mem_boot.pz_class & PCL_CLASS_MASK) != PCL_SEQU)
			return;
		break;
	default:
		/* No idea what we were booted from, but better ask the user */
		return;
	}

	/*
	 * If control goes here, we are booted from a block device and we
	 * matched a block device.
	 *
	 * We only grok SCSI boot currently.  Match on proper device
	 * hierarchy and unit/lun values.
	 */

#if NCD > 0 || NSD > 0 || NST > 0
	if (dev->dv_parent &&
	    dev->dv_parent->dv_cfdata->cf_driver == &scsibus_cd) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *sl = sa->sa_sc_link;

		/*
		 * sd/st/cd is attached to scsibus which is attached to
		 * the controller. Hence the grandparent here should be
		 * the elder.
		 */
		if (dev->dv_parent->dv_parent != elder) {
			return;
		}

		/*
		 * And now check for proper target and lun values
		 */
		if (sl->target == PAGE0->mem_boot.pz_layers[0] &&
		    sl->lun == PAGE0->mem_boot.pz_layers[1]) {
			bootdv = dev;
		}
	}
#endif
}

struct nam2blk nam2blk[] = {
	{ "rd",		3 },
	{ "sd",		4 },
	{ "st",		5 },
	{ "cd",		6 },
#if 0
	{ "wd",		? },
	{ "fd",		7 },
#endif
	{ "vnd",	2 },
	{ NULL,		-1 }
};


code:
/*	$OpenBSD: conf.c,v 1.29 2014/12/11 19:44:17 tedu Exp $	*/

/*-
 * Copyright (c) 1991 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.
 *
 *     @(#)conf.c	7.9 (Berkeley) 5/28/91
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/vnode.h>

#include <machine/conf.h>

#include "vnd.h"
#include "rd.h"
#include "sd.h"
#include "st.h"
#include "cd.h"
#include "ch.h"
#include "uk.h"
#include "wd.h"
bdev_decl(wd);
cdev_decl(wd);
#if 0
#include "fd.h"
#else
#define NFD 0
#endif
bdev_decl(fd);
cdev_decl(fd);

struct bdevsw   bdevsw[] =
{
	bdev_swap_init(1,sw),		/*  0: swap pseudo-device */
	bdev_notdef(),			/*  1: was: concatenated disk driver */
	bdev_disk_init(NVND,vnd),	/*  2: vnode disk driver */
	bdev_disk_init(NRD,rd),		/*  3: RAM disk */
	bdev_disk_init(NSD,sd),		/*  4: SCSI disk */
	bdev_tape_init(NST,st),		/*  5: SCSI tape */
	bdev_disk_init(NCD,cd),		/*  6: SCSI CD-ROM */
	bdev_disk_init(NFD,fd),		/*  7: floppy drive */
	bdev_disk_init(NWD,wd),		/*  8: ST506 drive */
	bdev_notdef(),			/*  9: */
	bdev_notdef(),			/* 10: */
	bdev_notdef(),			/* 11: */
	bdev_notdef(),			/* 12: */
	bdev_notdef(),			/* 13: */
	bdev_notdef(),			/* 14: */
};
int	nblkdev = nitems(bdevsw);

#include "audio.h"
#include "video.h"
#include "bio.h"
#include "pty.h"
#include "wsdisplay.h"
#include "wskbd.h"
#include "wsmouse.h"
#include "wsmux.h"

#include "bpfilter.h"
#include "tun.h"

#include "ksyms.h"

#include "lpt.h"
cdev_decl(lpt);

#include "com.h"
cdev_decl(com);

#include "pf.h"

#include "systrace.h"
#include "hotplug.h"
#include "vscsi.h"
#include "pppx.h"

#ifdef USER_PCICONF
#include "pci.h"
cdev_decl(pci);
#endif

#include "usb.h"
#include "uhid.h"
#include "ugen.h"
#include "ulpt.h"
#include "ucom.h"

#include "fuse.h"

struct cdevsw   cdevsw[] =
{
	cdev_cn_init(1,cn),		/*  0: virtual console */
	cdev_ctty_init(1,ctty),		/*  1: controlling terminal */
	cdev_mm_init(1,mm),		/*  2: /dev/{null,mem,kmem,...} */
	cdev_notdef(),			/*  3 was /dev/drum */
	cdev_tty_init(NPTY,pts),	/*  4: pseudo-tty slave */
	cdev_ptc_init(NPTY,ptc),	/*  5: pseudo-tty master */
	cdev_log_init(1,log),		/*  6: /dev/klog */
	cdev_notdef(),			/*  7: was: concatenated disk */
	cdev_disk_init(NVND,vnd),	/*  8: vnode disk driver */
	cdev_disk_init(NRD,rd),		/*  9: RAM disk */
	cdev_disk_init(NSD,sd),		/* 10: SCSI disk */
	cdev_tape_init(NST,st),		/* 11: SCSI tape */
	cdev_disk_init(NCD,cd),		/* 12: SCSI cd-rom */
	cdev_ch_init(NCH,ch),		/* 13: SCSI changer */
	cdev_notdef(),			/* 14: */
	cdev_uk_init(NUK,uk),		/* 15: SCSI unknown */
	cdev_fd_init(1,filedesc),	/* 16: file descriptor pseudo-device */
	cdev_bpf_init(NBPFILTER,bpf),	/* 17: Berkeley packet filter */
	cdev_tun_init(NTUN,tun),	/* 18: network tunnel */
	cdev_notdef(),			/* 19: was LKM */
	cdev_random_init(1,random),	/* 20: random generator */
	cdev_pf_init(NPF,pf),		/* 21: packet filter */
	cdev_tty_init(1,pdc),		/* 22: PDC device */
	cdev_tty_init(NCOM,com),	/* 23: RS232 */
	cdev_disk_init(NFD,fd),		/* 24: floppy drive */
	cdev_ksyms_init(NKSYMS,ksyms),	/* 25: Kernel symbols device */
	cdev_lpt_init(NLPT,lpt),	/* 26: parallel printer */
	cdev_wsdisplay_init(NWSDISPLAY,	/* 27: workstation console */
	    wsdisplay),
	cdev_mouse_init(NWSKBD,wskbd),	/* 28: keyboards */
	cdev_mouse_init(NWSMOUSE,wsmouse), /* 29: mice */
	cdev_mouse_init(NWSMUX,wsmux),	/* 30: mux */
#ifdef USER_PCICONF
	cdev_pci_init(NPCI,pci),	/* 31: PCI user */
#else
	cdev_notdef(),			/* 31: */
#endif
	cdev_notdef(),
	cdev_video_init(NVIDEO,video),	/* 33: generic video I/O */
	cdev_systrace_init(NSYSTRACE,systrace),	/* 34: system call tracing */
	cdev_audio_init(NAUDIO,audio),	/* 35: /dev/audio */
	cdev_notdef(),			/* 36: was: /dev/crypto */
	cdev_bio_init(NBIO,bio),	/* 37: ioctl tunnel */
	cdev_ptm_init(NPTY,ptm),	/* 38: pseudo-tty ptm device */
	cdev_disk_init(NWD,wd),		/* 39: ST506 disk */
	cdev_usb_init(NUSB,usb),	/* 40: USB controller */
	cdev_usbdev_init(NUHID,uhid),	/* 41: USB generic HID */
	cdev_usbdev_init(NUGEN,ugen),	/* 42: USB generic driver */
	cdev_ulpt_init(NULPT,ulpt),	/* 43: USB printers */
	cdev_notdef(),			/* 44: was urio */
	cdev_tty_init(NUCOM,ucom),	/* 45: USB tty */
	cdev_notdef(),			/* 46: was USB scanners */
	cdev_hotplug_init(NHOTPLUG,hotplug), /* 47: devices hot plugging */
	cdev_notdef(),			/* 48: */
	cdev_notdef(),			/* 49: */
	cdev_notdef(),			/* 50: */
	cdev_notdef(),			/* 51: */
	cdev_notdef(),			/* 52: */
	cdev_notdef(),			/* 53: */
	cdev_vscsi_init(NVSCSI,vscsi),	/* 54: vscsi */
	cdev_notdef(),
	cdev_disk_init(1,diskmap),	/* 56: disk mapper */
	cdev_pppx_init(NPPPX,pppx),	/* 57: pppx */
	cdev_fuse_init(NFUSE,fuse),	/* 58: fuse */
};
int nchrdev = nitems(cdevsw);

int mem_no = 2;		/* major device number of memory special file */

/*
 * Swapdev is a fake device implemented
 * in sw.c used only internally to get to swstrategy.
 * It cannot be provided to the users, because the
 * swstrategy routine munches the b_dev and b_blkno entries
 * before calling the appropriate driver.  This would horribly
 * confuse, e.g. the hashing routines. Instead, /dev/drum is
 * provided as a character (raw) device.
 */
dev_t   swapdev = makedev(0, 0);

int chrtoblktbl[] = {
	/*VCHR*/	/*VBLK*/
	/*  0 */	NODEV,
	/*  1 */	NODEV,
	/*  2 */	NODEV,
	/*  3 */	NODEV,
	/*  4 */	NODEV,
	/*  5 */	NODEV,
	/*  6 */	NODEV,
	/*  7 */	NODEV,
	/*  8 */	2,		/* vnd */
	/*  9 */	3,		/* rd */
	/* 10 */	4,		/* sd */
	/* 11 */	5,		/* st */
	/* 12 */	6,		/* cd */
	/* 13 */	NODEV,
	/* 14 */	NODEV,
	/* 15 */	NODEV,
	/* 16 */	NODEV,
	/* 17 */	NODEV,
	/* 18 */	NODEV,
	/* 19 */	NODEV,
	/* 20 */	NODEV,
	/* 21 */	NODEV,
	/* 22 */	NODEV,
	/* 23 */	NODEV,
	/* 24 */	7,		/* fd */
	/* 25 */	NODEV,
	/* 26 */	NODEV,
	/* 27 */	NODEV,
	/* 28 */	NODEV,
	/* 29 */	NODEV,
	/* 30 */	NODEV,
	/* 31 */	NODEV,
	/* 32 */	NODEV,
	/* 33 */	NODEV,
	/* 34 */	NODEV,
	/* 35 */	NODEV,
	/* 36 */	NODEV,
	/* 37 */	NODEV,
	/* 38 */	NODEV,
	/* 39 */	8,		/* wd */
};
int nchrtoblktbl = nitems(chrtoblktbl);

/*
 * Returns true if dev is /dev/zero.
 */
int
iszerodev(dev_t dev)
{
	return (major(dev) == mem_no && minor(dev) == 12);
}

dev_t
getnulldev(void)
{
	return makedev(mem_no, 2);
}

/*
 * Returns true if dev is /dev/mem or /dev/kmem.
 */
int
iskmemdev(dev_t dev)
{
	return (major(dev) == mem_no && minor(dev) < 2);
}