code:
/*	$OpenBSD: clkbrd.c,v 1.6 2008/01/20 16:41:17 kettenis Exp $	*/

/*
 * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/sensors.h>
#include <sys/systm.h>
#include <sys/timeout.h>

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

#include <sparc64/dev/fhcvar.h>
#include <sparc64/dev/clkbrdreg.h>
#include <sparc64/dev/clkbrdvar.h>

int clkbrd_match(struct device *, void *, void *);
void clkbrd_attach(struct device *, struct device *, void *);
void clkbrd_led_blink(void *, int);
void clkbrd_refresh(void *);

struct cfattach clkbrd_ca = {
	sizeof(struct clkbrd_softc), clkbrd_match, clkbrd_attach
};

struct cfdriver clkbrd_cd = {
	NULL, "clkbrd", DV_DULL
};

int
clkbrd_match(struct device *parent, void *match, void *aux)
{
	struct fhc_attach_args *fa = aux;

	if (strcmp(fa->fa_name, "clock-board") == 0)
		return (1);
	return (0);
}

void
clkbrd_attach(struct device *parent, struct device *self, void *aux)
{
	struct clkbrd_softc *sc = (struct clkbrd_softc *)self;
	struct fhc_attach_args *fa = aux;
	int slots;
	u_int8_t r;

	sc->sc_bt = fa->fa_bustag;

	if (fa->fa_nreg < 2) {
		printf(": no registers\n");
		return;
	}

	if (fhc_bus_map(sc->sc_bt, fa->fa_reg[1].fbr_slot,
	    fa->fa_reg[1].fbr_offset, fa->fa_reg[1].fbr_size, 0,
	    &sc->sc_creg)) {
		printf(": can't map ctrl regs\n");
		return;
	}

	if (fa->fa_nreg > 2) {
		if (fhc_bus_map(sc->sc_bt, fa->fa_reg[2].fbr_slot,
		    fa->fa_reg[2].fbr_offset, fa->fa_reg[2].fbr_size, 0,
		    &sc->sc_vreg)) {
			printf(": can't map vreg\n");
			return;
		}
		sc->sc_has_vreg = 1;
	}

	slots = 4;
	r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_STS1);
	switch (r & 0xc0) {
	case 0x40:
		slots = 16;
		break;
	case 0xc0:
		slots = 8;
		break;
	case 0x80:
		if (sc->sc_has_vreg) {
			r = bus_space_read_1(sc->sc_bt, sc->sc_vreg, 0);
			if (r != 0 && (r & 0x80) == 0)
					slots = 5;
		}
	}

	sc->sc_blink.bl_func = clkbrd_led_blink;
	sc->sc_blink.bl_arg = sc;
	blink_led_register(&sc->sc_blink);

	/* Initialize sensor data. */
	strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
	    sizeof(sc->sc_sensordev.xname));
	sc->sc_sensor.type = SENSOR_TEMP;

	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);

	if (sensor_task_register(sc, clkbrd_refresh, 5) == NULL) {
		printf(": unable to register update task\n");
		return;
	}

	sensordev_install(&sc->sc_sensordev);

	printf(": %d slots\n", slots);
}

void
clkbrd_led_blink(void *vsc, int on)
{
	struct clkbrd_softc *sc = vsc;
	int s;
	u_int8_t r;

	s = splhigh();
	r = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
	if (on)
		r |= CLK_CTRL_RLED;
	else
		r &= ~CLK_CTRL_RLED;
	bus_space_write_1(sc->sc_bt, sc->sc_creg, CLK_CTRL, r);
	bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_CTRL);
	splx(s);
}

/*
 * Calibration table for temperature sensor.
 */
int8_t clkbrd_temp[] = {
	 0,  0,  0,  0,  0,  0,  0,  0,
	 0,  0,  0,  0,  1,  2,  4,  5,
	 7,  8, 10, 11, 12, 13, 14, 15,
	17, 18, 19, 20, 21, 22, 23, 24,
	24, 25, 26, 27, 28, 29, 29, 30,
	31, 32, 32, 33, 34, 35, 35, 36,
	37, 38, 38, 39, 40, 40, 41, 42,
	42, 43, 44, 44, 45, 46, 46, 47,
	48, 48, 49, 50, 50, 51, 52, 52,
	53, 54, 54, 55, 56, 57, 57, 58,
	59, 59, 60, 60, 61, 62, 63, 63,
	64, 65, 65, 66, 67, 68, 68, 69,
	70, 70, 71, 72, 73, 74, 74, 75,
	76, 77, 78, 78, 79, 80, 81, 82
};

const int8_t clkbrd_temp_warn = 60;
const int8_t clkbrd_temp_crit = 68;

void
clkbrd_refresh(void *arg)
{
	struct clkbrd_softc *sc = arg;
	u_int8_t val;
	int8_t temp;

	val = bus_space_read_1(sc->sc_bt, sc->sc_creg, CLK_TEMP);
	if (val == 0xff) {
		sc->sc_sensor.flags |= SENSOR_FINVALID;
		return;
	}

	if (val < sizeof(clkbrd_temp))
		temp = clkbrd_temp[val];
	else
		temp = clkbrd_temp[sizeof(clkbrd_temp) - 1];

	sc->sc_sensor.value = val * 1000000 + 273150000;
	sc->sc_sensor.flags &= ~SENSOR_FINVALID;
	sc->sc_sensor.status = SENSOR_S_OK;
	if (temp >= clkbrd_temp_warn)
		sc->sc_sensor.status = SENSOR_S_WARN;
	if (temp >= clkbrd_temp_crit)
		sc->sc_sensor.status = SENSOR_S_CRIT;
}


code:
/*	$OpenBSD: clkbrdreg.h,v 1.2 2004/10/01 15:36:30 jason Exp $	*/

/*
 * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define	CLK_CTRL	0x00
#define	CLK_STS1	0x10
#define	CLK_STS2	0x20
#define	CLK_PSTS1	0x30
#define	CLK_PPRES	0x40
#define	CLK_TEMP	0x50
#define	CLK_IRQ		0x60
#define	CLK_PSTS2	0x70

#define	CLK_CTRL_IEN_FAN	0x80	/* intr enable: fan failure */
#define	CLK_CTRL_IEN_DC		0x40	/* intr enable: pwr supply DC */
#define	CLK_CTRL_IEN_AC		0x20	/* intr enable: AC pwr supply */
#define	CLK_CTRL_IEN_BRD	0x10	/* intr enable: board insert */
#define	CLK_CTRL_POFF		0x08	/* turn off system power */
#define	CLK_CTRL_LLED		0x04	/* left led (reversed) */
#define	CLK_CTRL_MLED		0x02	/* middle led */
#define	CLK_CTRL_RLED		0x01	/* right led */

license: unknown


code:
/*	$OpenBSD: clkbrdvar.h,v 1.3 2008/01/20 16:41:17 kettenis Exp $	*/

/*
 * Copyright (c) 2004 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

struct clkbrd_softc {
	struct device sc_dv;
	bus_space_tag_t sc_bt;
	bus_space_handle_t sc_creg;
	bus_space_handle_t sc_vreg;
	int sc_node;
	int sc_has_vreg;
	struct blink_led sc_blink;
	struct ksensor sc_sensor;
	struct ksensordev sc_sensordev;
};


code:
/*	$OpenBSD: cmp.c,v 1.2 2008/07/11 13:47:20 kettenis Exp $	*/
/*
 * Copyright (c) 2008 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/device.h>
#include <sys/systm.h>

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

int	cmp_match(struct device *, void *, void *);
void	cmp_attach(struct device *, struct device *, void *);

struct cfattach cmp_ca = {
	sizeof(struct device), cmp_match, cmp_attach
};

struct cfdriver cmp_cd = {
	NULL, "cmp", DV_DULL
};

int	cmp_print(void *, const char *);

int
cmp_match(struct device *parent, void *match, void *aux)
{
	struct mainbus_attach_args *ma = aux;

	if (strcmp(ma->ma_name, "cmp") == 0)
		return (1);

	return (0);
}

void
cmp_attach(struct device *parent, struct device *self, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	struct mainbus_attach_args nma;
	char buf[32];
	int node;

	printf("\n");

	for (node = OF_child(ma->ma_node); node; node = OF_peer(node)) {
		if (!checkstatus(node))
			continue;

		OF_getprop(node, "name", buf, sizeof(buf));
		if (strcmp(buf, "cpu") == 0)
			OF_getprop(node, "compatible", buf, sizeof(buf));

		bzero(&nma, sizeof(nma));
		nma.ma_node = node;
		nma.ma_name = buf;
		config_found(self, &nma, cmp_print);
	}
}

int
cmp_print(void *aux, const char *name)
{
	struct mainbus_attach_args *ma = aux;

	if (name)
		printf("\"%s\" at %s", ma->ma_name, name);
	return (UNCONF);
}


code:
/*	$OpenBSD: com_ebus.c,v 1.21 2011/09/28 11:02:37 dlg Exp $	*/
/*	$NetBSD: com_ebus.c,v 1.6 2001/07/24 19:27:10 eeh Exp $	*/

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

/*
 * NS Super I/O PC87332VLJ "com" to ebus attachment
 */

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

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

#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>

#include <dev/cons.h>
#include <dev/ic/comvar.h>

cdev_decl(com); /* XXX this belongs elsewhere */

int	com_ebus_match(struct device *, void *, void *);
void	com_ebus_attach(struct device *, struct device *, void *);
int	com_ebus_speed(struct ebus_attach_args *);

struct cfattach com_ebus_ca = {
	sizeof(struct com_softc), com_ebus_match, com_ebus_attach
};

static char *com_names[] = {
	"su",
	"su_pnp",
	"rsc-console",
	"lom-console",
	NULL
};

int
com_ebus_match(struct device *parent, void *match, void *aux)
{
	struct ebus_attach_args *ea = aux;
	int i;

	for (i=0; com_names[i]; i++)
		if (strcmp(ea->ea_name, com_names[i]) == 0)
			return (1);

	if (strcmp(ea->ea_name, "serial") == 0) {
		char compat[80];

		/* Could be anything. */
		if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
			OF_getprop(ea->ea_node, "compatible", compat,
				sizeof(compat)) == i) {
			if (strcmp(compat, "su16552") == 0 ||
			    strcmp(compat, "su16550") == 0 ||
			    strcmp(compat, "FJSV,su") == 0 ||
			    strcmp(compat, "su") == 0) {
				return (1);
			}
		}
	}
	return (0);
}

/* XXXART - was 1846200 */
#define BAUD_BASE       (1843200)

void
com_ebus_attach(struct device *parent, struct device *self, void *aux)
{
	struct com_softc *sc = (void *)self;
	struct ebus_attach_args *ea = aux;
	int i, com_is_input, com_is_output;
	int node, port;
	char buf[32];

	sc->sc_iobase = EBUS_PADDR_FROM_REG(&ea->ea_regs[0]);
	/*
	 * Addresses that should be supplied by the prom:
	 *	- normal com registers
	 *	- ns873xx configuration registers
	 *	- DMA space
	 * The `com' driver does not use DMA accesses, so we can
	 * ignore that for now.  We should enable the com port in
	 * the ns873xx registers here. XXX
	 *
	 * Use the prom address if there.
	 */
	if (ea->ea_nvaddrs) {
		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
		    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) != 0) {
			printf(": can't map register space\n");
			return;
		}
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_memtag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_iotag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_iotag;
	} else {
		printf(": can't map register space\n");
               	return;
	}
	sc->sc_hwflags = 0;
	sc->sc_swflags = 0;
	sc->sc_frequency = BAUD_BASE;

	for (i = 0; i < ea->ea_nintrs; i++)
		bus_intr_establish(sc->sc_iot, ea->ea_intrs[i],
		    IPL_TTY, 0, comintr, sc, self->dv_xname);

	/*
	 * Figure out if we're the console.
	 *
	 * The Fujitsu SPARC Enterprise M4000/M5000/M8000/M9000 has a
	 * serial port on each I/O board and a pseudo console that is
	 * redirected to one of these serial ports.  The board number
	 * of the serial port in question is encoded in the "tty-port#"
	 * property of the pseudo console, so we figure out what our
	 * board number is by walking up the device tree, and check
	 * for a match.
	 */

	node = OF_instance_to_package(OF_stdin());
	com_is_input = (ea->ea_node == node);
	if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
	    strcmp(buf, "pseudo-console") == 0) {
		port = getpropint(node, "tty-port#", -1);
		node = OF_parent(OF_parent(ea->ea_node));
		com_is_input = (getpropint(node, "board#", -2) == port);
	}

	node = OF_instance_to_package(OF_stdout());
	com_is_output = (ea->ea_node == node);
	if (OF_getprop(node, "name", buf, sizeof(buf)) > 0 &&
	    strcmp(buf, "pseudo-console") == 0) {
		port = getpropint(node, "tty-port#", -1);
		node = OF_parent(OF_parent(ea->ea_node));
		com_is_output = (getpropint(node, "board#", -2) == port);
	}

	if (com_is_input || com_is_output) {
		struct consdev *cn_orig;
		int speed;

		speed = com_ebus_speed(ea);

		comconsioh = sc->sc_ioh;
		cn_orig = cn_tab;
		/* Attach com as the console. */
		if (comcnattach(sc->sc_iot, sc->sc_iobase, speed,
		    sc->sc_frequency,
		    ((TTYDEF_CFLAG & ~(CSIZE | PARENB))|CREAD | CS8 | HUPCL))) {
			printf("Error: comcnattach failed\n");
		}
		cn_tab = cn_orig;
		if (com_is_input) {
			cn_tab->cn_dev = /*XXX*/makedev(36, sc->sc_dev.dv_unit);
			cn_tab->cn_probe = comcnprobe;
			cn_tab->cn_init = comcninit;
			cn_tab->cn_getc = comcngetc;
			cn_tab->cn_pollc = comcnpollc;
		}
		if (com_is_output)
			cn_tab->cn_putc = comcnputc;
	}

	/*
	 * Apparently shoving too much data down the TX FIFO on the
	 * Fujitsu SPARC Enterprise M4000/M5000 causes a hardware
	 * fault.  Avoid this issue by setting the FIFO depth to 1.
	 * This will effectively disable the TX FIFO, but will still
	 * enable the RX FIFO, which is what we really care about.
	 */
	if (OF_getprop(ea->ea_node, "compatible", buf, sizeof(buf)) > 0 &&
	    strcmp(buf, "FJSV,su") == 0)
		sc->sc_uarttype = COM_UART_16550;

        if (OF_getproplen(ea->ea_node, "keyboard") == 0)
		printf(": keyboard");
	else if (OF_getproplen(ea->ea_node, "mouse") == 0)
		printf(": mouse");

	/* Now attach the driver */
	com_attach_subr(sc);
}

int
com_ebus_speed(struct ebus_attach_args *ea)
{
	char buf[128];
	char *name = NULL;
	int aliases, options;

	if (strcmp(ea->ea_name, "rsc-console") == 0)
		return 115200;

	aliases = OF_finddevice("/aliases");
	if (OF_getprop(aliases, "ttya", buf, sizeof(buf)) != -1 &&
	    OF_finddevice(buf) == ea->ea_node)
		name = "ttya-mode";
	if (OF_getprop(aliases, "ttyb", buf, sizeof(buf)) != -1 &&
	    OF_finddevice(buf) == ea->ea_node)
		name = "ttyb-mode";

	if (name == NULL)
		return TTYDEF_SPEED;

	options = OF_finddevice("/options");
	return (getpropspeed(options, name));
}


code:
/*	$OpenBSD: comkbd_ebus.c,v 1.21 2011/03/18 21:01:17 miod Exp $	*/

/*
 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Effort sponsored in part by the Defense Advanced Research Projects
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/tty.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/syslog.h>

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

#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdvar.h>

#include <dev/sun/sunkbdreg.h>
#include <dev/sun/sunkbdvar.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#include <dev/ic/ns16550reg.h>

#include <dev/cons.h>

#define	COMK_RX_RING	64
#define	COMK_TX_RING	64

struct comkbd_softc {
	struct sunkbd_softc	sc_base;

	bus_space_tag_t sc_iot;		/* bus tag */
	bus_space_handle_t sc_ioh;	/* bus handle */
	void *sc_ih, *sc_si;		/* interrupt vectors */

	u_int sc_rxcnt;
	u_int8_t sc_rxbuf[COMK_RX_RING];
	u_int8_t *sc_rxbeg, *sc_rxend, *sc_rxget, *sc_rxput;

	u_int sc_txcnt;
	u_int8_t sc_txbuf[COMK_TX_RING];
	u_int8_t *sc_txbeg, *sc_txend, *sc_txget, *sc_txput;

	u_int8_t sc_ier;
};

#define	COM_WRITE(sc,r,v) \
    bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
#define	COM_READ(sc,r) \
    bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))

int comkbd_match(struct device *, void *, void *);
void comkbd_attach(struct device *, struct device *, void *);
int comkbd_iskbd(int);

/* wskbd glue */
void comkbd_cnpollc(void *, int);
void comkbd_cngetc(void *, u_int *, int *);

/* internals */
int comkbd_enqueue(void *, u_int8_t *, u_int);
int comkbd_init(struct comkbd_softc *);
void comkbd_putc(struct comkbd_softc *, u_int8_t);
int comkbd_intr(void *);
void comkbd_soft(void *);

struct cfattach comkbd_ca = {
	sizeof(struct comkbd_softc), comkbd_match, comkbd_attach
};

struct cfdriver comkbd_cd = {
	NULL, "comkbd", DV_DULL
};

const char *comkbd_names[] = {
	"su",
	"su_pnp",
	NULL
};

struct wskbd_consops comkbd_consops = {
	comkbd_cngetc,
	comkbd_cnpollc
};

int
comkbd_iskbd(node)
	int node;
{
	if (OF_getproplen(node, "keyboard") == 0)
		return (10);
	return (0);
}

int
comkbd_match(parent, match, aux)
	struct device *parent;
	void *match;
	void *aux;
{
	struct ebus_attach_args *ea = aux;
	int i;

	for (i = 0; comkbd_names[i]; i++)
		if (strcmp(ea->ea_name, comkbd_names[i]) == 0)
			return (comkbd_iskbd(ea->ea_node));

	if (strcmp(ea->ea_name, "serial") == 0) {
		char compat[80];

		if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
		    OF_getprop(ea->ea_node, "compatible", compat,
			sizeof(compat)) == i) {
			if (strcmp(compat, "su16550") == 0 ||
			    strcmp(compat, "su") == 0)
				return (comkbd_iskbd(ea->ea_node));
		}
	}
	return (0);
}

void
comkbd_attach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct comkbd_softc *sc = (void *)self;
	struct sunkbd_softc *ss = (void *)sc;
	struct ebus_attach_args *ea = aux;
	struct wskbddev_attach_args a;
	int console;

	ss->sc_sendcmd = comkbd_enqueue;
	timeout_set(&ss->sc_bellto, sunkbd_bellstop, sc);

	sc->sc_iot = ea->ea_memtag;

	sc->sc_rxget = sc->sc_rxput = sc->sc_rxbeg = sc->sc_rxbuf;
	sc->sc_rxend = sc->sc_rxbuf + COMK_RX_RING;
	sc->sc_rxcnt = 0;

	sc->sc_txget = sc->sc_txput = sc->sc_txbeg = sc->sc_txbuf;
	sc->sc_txend = sc->sc_txbuf + COMK_TX_RING;
	sc->sc_txcnt = 0;

	console = (ea->ea_node == OF_instance_to_package(OF_stdin()));

	sc->sc_si = softintr_establish(IPL_TTY, comkbd_soft, sc);
	if (sc->sc_si == NULL) {
		printf(": can't get soft intr\n");
		return;
	}

	/* Use prom address if available, otherwise map it. */
	if (ea->ea_nvaddrs && bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
	    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_memtag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_iotag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_iotag;
	} else {
		printf(": can't map register space\n");
                return;
	}

	sc->sc_ih = bus_intr_establish(sc->sc_iot,
	    ea->ea_intrs[0], IPL_TTY, 0, comkbd_intr, sc, self->dv_xname);
	if (sc->sc_ih == NULL) {
		printf(": can't get hard intr\n");
		return;
	}

	if (comkbd_init(sc) == 0) {
		return;
	}

	ss->sc_click =
	    strcmp(getpropstring(optionsnode, "keyboard-click?"), "true") == 0;
	sunkbd_setclick(ss, ss->sc_click);

	a.console = console;
	if (ISTYPE5(ss->sc_layout)) {
		a.keymap = &sunkbd5_keymapdata;
#ifndef SUNKBD5_LAYOUT
		if (ss->sc_layout < MAXSUNLAYOUT &&
		    sunkbd_layouts[ss->sc_layout] != -1)
			sunkbd5_keymapdata.layout =
			    sunkbd_layouts[ss->sc_layout];
#endif
	} else {
		a.keymap = &sunkbd_keymapdata;
#ifndef SUNKBD_LAYOUT
		if (ss->sc_layout < MAXSUNLAYOUT &&
		    sunkbd_layouts[ss->sc_layout] != -1)
			sunkbd_keymapdata.layout =
			    sunkbd_layouts[ss->sc_layout];
#endif
	}
	a.accessops = &sunkbd_accessops;
	a.accesscookie = sc;

	if (console) {
		cn_tab->cn_dev = makedev(77, ss->sc_dev.dv_unit); /* XXX */
		cn_tab->cn_pollc = wskbd_cnpollc;
		cn_tab->cn_getc = wskbd_cngetc;
		wskbd_cnattach(&comkbd_consops, sc, a.keymap);
		sc->sc_ier = IER_ETXRDY | IER_ERXRDY;
		COM_WRITE(sc, com_ier, sc->sc_ier);
		COM_READ(sc, com_iir);
		COM_WRITE(sc, com_mcr, MCR_IENABLE | MCR_DTR | MCR_RTS);
	}

	sunkbd_attach(ss, &a);
}

void
comkbd_cnpollc(vsc, on)
	void *vsc;
	int on;
{
}

void
comkbd_cngetc(v, type, data)
	void *v;
	u_int *type;
	int *data;
{
	struct comkbd_softc *sc = v;
	int s;
	u_int8_t c;

	s = splhigh();
	while (1) {
		if (COM_READ(sc, com_lsr) & LSR_RXRDY)
			break;
	}
	c = COM_READ(sc, com_data);
	COM_READ(sc, com_iir);
	splx(s);

	sunkbd_decode(c, type, data);
}

void
comkbd_putc(sc, c)
	struct comkbd_softc *sc;
	u_int8_t c;
{
	int s, timo;

	s = splhigh();

	timo = 150000;
	while (--timo) {
		if (COM_READ(sc, com_lsr) & LSR_TXRDY)
			break;
	}

	COM_WRITE(sc, com_data, c);
	bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, COM_NPORTS,
	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);

	timo = 150000;
	while (--timo) {
		if (COM_READ(sc, com_lsr) & LSR_TXRDY)
			break;
	}

	splx(s);
}

int
comkbd_enqueue(v, buf, buflen)
	void *v;
	u_int8_t *buf;
	u_int buflen;
{
	struct comkbd_softc *sc = v;
	int s;
	u_int i;

	s = spltty();

	/* See if there is room... */
	if ((sc->sc_txcnt + buflen) > COMK_TX_RING) {
		splx(s);
		return (-1);
	}

	for (i = 0; i < buflen; i++) {
		*sc->sc_txget = *buf;
		buf++;
		sc->sc_txcnt++;
		sc->sc_txget++;
		if (sc->sc_txget == sc->sc_txend)
			sc->sc_txget = sc->sc_txbeg;
	}

	comkbd_soft(sc);

	splx(s);
	return (0);
}

void
comkbd_soft(vsc)
	void *vsc;
{
	struct comkbd_softc *sc = vsc;
	struct sunkbd_softc *ss = (void *)sc;
	u_int8_t cbuf[SUNKBD_MAX_INPUT_SIZE], *cptr;
	u_int8_t c;

	cptr = cbuf;
	while (sc->sc_rxcnt) {
		*cptr++ = *sc->sc_rxget;
		if (++sc->sc_rxget == sc->sc_rxend)
			sc->sc_rxget = sc->sc_rxbeg;
		sc->sc_rxcnt--;
		if (cptr - cbuf == sizeof cbuf) {
			sunkbd_input(ss, cbuf, cptr - cbuf);
			cptr = cbuf;
		}
	}
	if (cptr != cbuf)
		sunkbd_input(ss, cbuf, cptr - cbuf);

	if (sc->sc_txcnt) {
		c = sc->sc_ier | IER_ETXRDY;
		if (c != sc->sc_ier) {
			COM_WRITE(sc, com_ier, c);
			sc->sc_ier = c;
		}
		if (COM_READ(sc, com_lsr) & LSR_TXRDY) {
			sc->sc_txcnt--;
			COM_WRITE(sc, com_data, *sc->sc_txput);
			if (++sc->sc_txput == sc->sc_txend)
				sc->sc_txput = sc->sc_txbeg;
		}
	}
}

int
comkbd_intr(vsc)
	void *vsc;
{
	struct comkbd_softc *sc = vsc;
	u_int8_t iir, lsr, data;
	int needsoft = 0;

	/* Nothing to do */
	iir = COM_READ(sc, com_iir);
	if (iir & IIR_NOPEND)
		return (0);

	for (;;) {
		lsr = COM_READ(sc, com_lsr);
		if (lsr & LSR_RXRDY) {
			needsoft = 1;

			do {
				data = COM_READ(sc, com_data);
				if (sc->sc_rxcnt != COMK_RX_RING) {
					*sc->sc_rxput = data;
					if (++sc->sc_rxput == sc->sc_rxend)
						sc->sc_rxput = sc->sc_rxbeg;
					sc->sc_rxcnt++;
				}
				lsr = COM_READ(sc, com_lsr);
			} while (lsr & LSR_RXRDY);
		}

		if (lsr & LSR_TXRDY) {
			if (sc->sc_txcnt == 0) {
				/* Nothing further to send */
				sc->sc_ier &= ~IER_ETXRDY;
				COM_WRITE(sc, com_ier, sc->sc_ier);
			} else
				needsoft = 1;
		}

		iir = COM_READ(sc, com_iir);
		if (iir & IIR_NOPEND)
			break;
	}

	if (needsoft)
		softintr_schedule(sc->sc_si);

	return (1);
}

int
comkbd_init(sc)
	struct comkbd_softc *sc;
{
	struct sunkbd_softc *ss = (void *)sc;
	u_int8_t stat, c;
	int tries;

	for (tries = 5; tries != 0; tries--) {
		int ltries;

		ss->sc_leds = 0;
		ss->sc_layout = -1;

		/* Send reset request */
		comkbd_putc(sc, SKBD_CMD_RESET);

		ltries = 1000;
		while (--ltries > 0) {
			stat = COM_READ(sc,com_lsr);
			if (stat & LSR_RXRDY) {
				c = COM_READ(sc, com_data);

				sunkbd_raw(ss, c);
				if (ss->sc_kbdstate == SKBD_STATE_RESET)
					break;
			}
			DELAY(1000);
		}
		if (ltries == 0)
			continue;

		/* Wait for reset to finish. */
		ltries = 1000;
		while (--ltries > 0) {
			stat = COM_READ(sc, com_lsr);
			if (stat & LSR_RXRDY) {
				c = COM_READ(sc, com_data);
				sunkbd_raw(ss, c);
				if (ss->sc_kbdstate == SKBD_STATE_GETKEY)
					break;
			}
			DELAY(1000);
		}
		if (ltries == 0)
			continue;

		/* Some Sun<=>PS/2 converters need some delay here */
		DELAY(5000);

		/* Send layout request */
		comkbd_putc(sc, SKBD_CMD_LAYOUT);

		ltries = 1000;
		while (--ltries > 0) {
			stat = COM_READ(sc, com_lsr);
			if (stat & LSR_RXRDY) {
				c = COM_READ(sc, com_data);
				sunkbd_raw(ss, c);
				if (ss->sc_layout != -1)
					break;
			}
			DELAY(1000);
		}
		if (ltries != 0)
			break;
	}
	if (tries == 0)
		printf(": no keyboard\n");
	else
		printf(": layout %d\n", ss->sc_layout);

	return tries;
}


code:
/*	$OpenBSD: comms_ebus.c,v 1.2 2009/06/17 06:48:38 matthieu Exp $	*/

/*
 * Copyright (c) 2009 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*
 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Effort sponsored in part by the Defense Advanced Research Projects
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
 *
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/tty.h>

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

#include <sparc64/dev/ebusreg.h>
#include <sparc64/dev/ebusvar.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>

#include <dev/sun/sunmsvar.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#include <dev/ic/ns16550reg.h>
#define	com_lcr com_cfcr

#include <dev/cons.h>

/* should match com_ebus.c */
#define	BAUD_BASE	(1843200)

#define	COMMS_RX_RING	64

struct comms_softc {
	struct	sunms_softc sc_base;

	u_int	sc_ier;

	bus_space_tag_t sc_iot;		/* bus tag */
	bus_space_handle_t sc_ioh;	/* bus handle */
	void *sc_ih, *sc_si;		/* interrupt vectors */

	u_int sc_rxcnt;
	u_int8_t sc_rxbuf[COMMS_RX_RING];
	u_int8_t *sc_rxbeg, *sc_rxend, *sc_rxget, *sc_rxput;
};

#define	COM_WRITE(sc,r,v) \
    bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
#define	COM_READ(sc,r) \
    bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))

/*
 * autoconf glue.
 */

int	comms_match(struct device *, void *, void *);
void	comms_attach(struct device *, struct device *, void *);

const struct cfattach comms_ca = {
	sizeof(struct comms_softc), comms_match, comms_attach
};

struct cfdriver comms_cd = {
	NULL, "comms", DV_DULL
};

/*
 * wsmouse accessops.
 */

void	comms_disable(void *);
int	comms_enable(void *);

const struct wsmouse_accessops comms_accessops = {
	comms_enable,
	sunms_ioctl,
	comms_disable
};

/*
 *  com glue.
 */

int	comms_hardintr(void *);
int	comms_ismouse(int);
void	comms_softintr(void *);
void	comms_speed_change(void *, uint);

/*
 * autoconf glue.
 */

static const char *comms_names[] = {
	"su",
	"su_pnp",
	NULL
};

int
comms_ismouse(int node)
{
	if (OF_getproplen(node, "mouse") == 0)
		return 10;
	return 0;
}

int
comms_match(struct device *parent, void *match, void *aux)
{
	struct ebus_attach_args *ea = aux;
	int i;

	for (i = 0; comms_names[i]; i++)
		if (strcmp(ea->ea_name, comms_names[i]) == 0)
			return comms_ismouse(ea->ea_node);

	if (strcmp(ea->ea_name, "serial") == 0) {
		char compat[80];

		if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
		    OF_getprop(ea->ea_node, "compatible", compat,
			sizeof(compat)) == i) {
			if (strcmp(compat, "su16550") == 0 ||
			    strcmp(compat, "su") == 0)
				return comms_ismouse(ea->ea_node);
		}
	}
	return 0;
}

void
comms_attach(struct device *parent, struct device *self, void *aux)
{
	struct comms_softc *sc = (void *)self;
	struct ebus_attach_args *ea = aux;

	sc->sc_iot = ea->ea_memtag;

	sc->sc_rxget = sc->sc_rxput = sc->sc_rxbeg = sc->sc_rxbuf;
	sc->sc_rxend = sc->sc_rxbuf + COMMS_RX_RING;
	sc->sc_rxcnt = 0;

	/* we really want IPL_TTY here. */
	sc->sc_si = softintr_establish(IPL_TTY, comms_softintr, sc);
	if (sc->sc_si == NULL) {
		printf(": can't get soft intr\n");
		return;
	}

	/* Use prom address if available, otherwise map it. */
	if (ea->ea_nvaddrs && bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
	    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_memtag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_memtag;
	} else if (ebus_bus_map(ea->ea_iotag, 0,
	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
		sc->sc_iot = ea->ea_iotag;
	} else {
		printf(": can't map register space\n");
                return;
	}

	sc->sc_ih = bus_intr_establish(sc->sc_iot,
	    ea->ea_intrs[0], IPL_TTY, 0, comms_hardintr, sc, self->dv_xname);
	if (sc->sc_ih == NULL) {
		printf(": can't get hard intr\n");
		return;
	}

	/* Initialize hardware. */
	sc->sc_ier = 0;
	comms_speed_change(sc, INIT_SPEED);

	sc->sc_base.sc_speed_change = comms_speed_change;

	sunms_attach(&sc->sc_base, &comms_accessops);
}

/*
 * wsmouse accessops.
 */

void
comms_disable(void *v)
{
	struct comms_softc *sc = v;
	int s;

	s = spltty();
	sc->sc_ier = 0;
	COM_WRITE(sc, com_ier, sc->sc_ier);
	splx(s);
}

int
comms_enable(void *v)
{
	struct comms_softc *sc = v;
	int s;

	s = spltty();
	sc->sc_ier = IER_ERXRDY;
	COM_WRITE(sc, com_ier, sc->sc_ier);
	splx(s);

	return 0;
}

/*
 * com glue.
 */

void
comms_softintr(void *v)
{
	struct comms_softc *sc = v;
	uint8_t c;

	/*
	 * If we have a baud rate change pending, do it now.
	 * This will reset the rx ring, so we can proceed safely.
	 */
	if (sc->sc_base.sc_state == STATE_RATE_CHANGE) {
		sunms_speed_change(&sc->sc_base);
	}

	/*
	 * Copy data from the receive ring, if any, to the event layer.
	 */
	while (sc->sc_rxcnt) {
		c = *sc->sc_rxget;
		if (++sc->sc_rxget == sc->sc_rxend)
			sc->sc_rxget = sc->sc_rxbeg;
		sc->sc_rxcnt--;
		sunms_input(&sc->sc_base, c);
	}
}

int
comms_hardintr(void *v)
{
	struct comms_softc *sc = v;
	u_int8_t iir, lsr, data;
	int needsoft = 0;

	/* Nothing to do */
	iir = COM_READ(sc, com_iir);
	if (ISSET(iir, IIR_NOPEND))
		return 0;

	for (;;) {
		lsr = COM_READ(sc, com_lsr);

		if (ISSET(lsr, LSR_BI)) {
			if (sc->sc_base.sc_state != STATE_RATE_CHANGE &&
			    ++sc->sc_base.sc_brk > 1) {
				sc->sc_base.sc_state = STATE_RATE_CHANGE;
				needsoft = 1;
#ifdef DEBUG
				printf("%s: break detected, changing speed\n",
				    sc->sc_base.sc_dev.dv_xname);
#endif
			}
		}

		if (ISSET(lsr, LSR_RXRDY)) {
			needsoft = 1;

			do {
				data = COM_READ(sc, com_data);
				if (sc->sc_base.sc_state != STATE_RATE_CHANGE &&
				    sc->sc_rxcnt != COMMS_RX_RING) {
					*sc->sc_rxput = data;
					if (++sc->sc_rxput == sc->sc_rxend)
						sc->sc_rxput = sc->sc_rxbeg;
					sc->sc_rxcnt++;
				}
				lsr = COM_READ(sc, com_lsr);
			} while (ISSET(lsr, LSR_RXRDY));
		}

		iir = COM_READ(sc, com_iir);
		if (ISSET(iir, IIR_NOPEND))
			break;
	}

	if (needsoft)
		softintr_schedule(sc->sc_si);

	return 1;
}

/*
 * Reinitialize the line to a different speed.  Invoked at spltty().
 */
void
comms_speed_change(void *v, uint bps)
{
	struct comms_softc *sc = v;
	int ospeed;

	/*
	 * Eat everything on the line.
	 */
	while (ISSET(COM_READ(sc, com_lsr), LSR_RXRDY))
		COM_READ(sc, com_data);

	ospeed = comspeed(BAUD_BASE, bps);

	/* disable interrupts while the chip is reprogrammed */
	COM_WRITE(sc, com_ier, 0);

	COM_WRITE(sc, com_lcr, LCR_DLAB);
	COM_WRITE(sc, com_dlbl, ospeed);
	COM_WRITE(sc, com_dlbh, ospeed >> 8);
	/* 8 data bits, no parity, 2 stop bits */
	COM_WRITE(sc, com_lcr, LCR_8BITS | LCR_PNONE | LCR_STOPB);
	COM_READ(sc, com_iir);

	COM_WRITE(sc, com_mcr, MCR_IENABLE | MCR_DTR | MCR_RTS);
	/* XXX do something about the FIFO? */

	COM_WRITE(sc, com_ier, sc->sc_ier);
}


code:
/*	$OpenBSD: cons.h,v 1.3 2007/03/07 06:23:04 miod Exp $	*/
/*	$NetBSD: cons.h,v 1.3 2000/05/19 05:26:17 eeh Exp $	*/

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

/* These are shared with the consinit OBP console */
extern int stdin, stdout;
void pcons_cnpollc(dev_t dev, int on);

struct consdev;
struct zs_chanstate;

extern void *zs_conschan;

extern void nullcnprobe(struct consdev *);

extern int  zs_getc(void *arg);
extern void zs_putc(void *arg, int c);

struct zschan *
zs_get_chan_addr(int zsc_unit, int channel);

#ifdef	KGDB
void zs_kgdb_init(void);
void zskgdb(struct zs_chanstate *);
#endif


code:
/*	$OpenBSD: consinit.c,v 1.14 2011/04/13 00:56:25 deraadt Exp $	*/
/*	$NetBSD: consinit.c,v 1.9 2000/10/20 05:32:35 mrg Exp $	*/

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

#include "pcons.h"
#include "ukbd.h"

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/time.h>
#include <sys/syslog.h>

#include <machine/autoconf.h>
#include <machine/openfirm.h>
#include <machine/conf.h>
#include <machine/cpu.h>
#include <machine/psl.h>
#include <machine/z8530var.h>
#include <machine/sparc64.h>

#include <dev/cons.h>

#include <sparc64/dev/cons.h>

#include <dev/usb/ukbdvar.h>

cons_decl(prom_);

int stdin = 0, stdout = 0;

/*
 * The console is set to this one initially,
 * which lets us use the PROM until consinit()
 * is called to select a real console.
 */
struct consdev consdev_prom = {
	prom_cnprobe,
	prom_cninit,
	prom_cngetc,
	prom_cnputc,
	prom_cnpollc,
	NULL
};

/*
 * The console table pointer is statically initialized
 * to point to the PROM (output only) table, so that
 * early calls to printf will work.
 */
struct consdev *cn_tab = &consdev_prom;

void
prom_cnprobe(struct consdev *cd)
{
#if NPCONS > 0
	int maj;

	for (maj = 0; maj < nchrdev; maj++)
		if (cdevsw[maj].d_open == pconsopen)
			break;
	cd->cn_dev = makedev(maj, 0);
	cd->cn_pri = CN_MIDPRI;
#endif
}

int
prom_cngetc(dev_t dev)
{
	unsigned char ch = '\0';
	int l;
#ifdef DDB
	static int nplus = 0;
#endif

	while ((l = OF_read(stdin, &ch, 1)) != 1)
		/* void */;
#ifdef DDB
	if (ch == '+') {
		if (nplus++ > 3)
			Debugger();
	} else
		nplus = 0;
#endif
	if (ch == '\r')
		ch = '\n';
	if (ch == '\b')
		ch = '\177';
	return ch;
}

void
prom_cninit(struct consdev *cn)
{
	if (!stdin) stdin = OF_stdin();
	if (!stdout) stdout = OF_stdout();
}

/*
 * PROM console output putchar.
 */
void
prom_cnputc(dev_t dev, int c)
{
	int s;
	char c0 = (c & 0x7f);

#if 0
	if (!stdout) stdout = OF_stdout();
#endif
	s = splhigh();
	OF_write(stdout, &c0, 1);
	splx(s);
}

void
prom_cnpollc(dev_t dev, int on)
{
	if (on) {
                /* Entering debugger. */
                fb_unblank();
	} else {
                /* Resuming kernel. */
	}
#if NPCONS > 0
	pcons_cnpollc(dev, on);
#endif
}

/*****************************************************************/

#ifdef	DEBUG
#define	DBPRINT(x)	prom_printf x
#else
#define	DBPRINT(x)
#endif

/*
 * This function replaces sys/dev/cninit.c
 * Determine which device is the console using
 * the PROM "input source" and "output sink".
 */
void
consinit()
{
	register int chosen;
	char buffer[128];
	extern int stdinnode, fbnode;
	char *consname = "unknown";

	DBPRINT(("consinit()\r\n"));
	if (cn_tab != &consdev_prom) return;

	DBPRINT(("setting up stdin\r\n"));
	chosen = OF_finddevice("/chosen");
	OF_getprop(chosen, "stdin",  &stdin, sizeof(stdin));
	DBPRINT(("stdin instance = %x\r\n", stdin));

	if ((stdinnode = OF_instance_to_package(stdin)) == 0) {
		printf("WARNING: no PROM stdin\n");
	}
#if NUKBD > 0
	else {
		if (OF_getprop(stdinnode, "compatible", buffer,
		    sizeof(buffer)) != -1 && strncmp("usb", buffer, 3) == 0)
			ukbd_cnattach();
	}
#endif

	DBPRINT(("setting up stdout\r\n"));
	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));

	DBPRINT(("stdout instance = %x\r\n", stdout));

	if ((fbnode = OF_instance_to_package(stdout)) == 0)
		printf("WARNING: no PROM stdout\n");

	DBPRINT(("stdout package = %x\r\n", fbnode));

	if (stdinnode && (OF_getproplen(stdinnode,"keyboard") >= 0)) {
		consname = "keyboard/display";
	} else if (fbnode &&
		   (OF_instance_to_path(stdin, buffer, sizeof(buffer)) >= 0)) {
		consname = buffer;
	}
	printf("console is %s\n", consname);

	/* Initialize PROM console */
	(*cn_tab->cn_probe)(cn_tab);
	(*cn_tab->cn_init)(cn_tab);
}


code:
/*	$OpenBSD: core.c,v 1.1 2008/07/11 14:23:53 kettenis Exp $	*/
/*
 * Copyright (c) 2008 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/device.h>
#include <sys/systm.h>

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

int	core_match(struct device *, void *, void *);
void	core_attach(struct device *, struct device *, void *);

struct cfattach core_ca = {
	sizeof(struct device), core_match, core_attach
};

struct cfdriver core_cd = {
	NULL, "core", DV_DULL
};

int	core_print(void *, const char *);

int
core_match(struct device *parent, void *match, void *aux)
{
	struct mainbus_attach_args *ma = aux;

	if (strcmp(ma->ma_name, "core") == 0)
		return (1);

	return (0);
}

void
core_attach(struct device *parent, struct device *self, void *aux)
{
	struct mainbus_attach_args *ma = aux;
	struct mainbus_attach_args nma;
	char buf[32];
	int node;

	printf("\n");

	for (node = OF_child(ma->ma_node); node; node = OF_peer(node)) {
		if (!checkstatus(node))
			continue;

		OF_getprop(node, "name", buf, sizeof(buf));
		if (strcmp(buf, "cpu") == 0)
			OF_getprop(ma->ma_node, "compatible", buf, sizeof(buf));

		bzero(&nma, sizeof(nma));
		nma.ma_node = node;
		nma.ma_name = buf;
		config_found(self, &nma, core_print);
	}
}

int
core_print(void *aux, const char *name)
{
	struct mainbus_attach_args *ma = aux;

	if (name)
		printf("\"%s\" at %s", ma->ma_name, name);
	return (UNCONF);
}


code:
/*	$OpenBSD: creator.c,v 1.49 2015/01/26 20:25:38 miod Exp $	*/

/*
 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

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

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <machine/fbvar.h>

#include <sparc64/dev/creatorreg.h>
#include <sparc64/dev/creatorvar.h>

int	creator_match(struct device *, void *, void *);
void	creator_attach(struct device *, struct device *, void *);
int	creator_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t creator_mmap(void *, off_t, int);

void	creator_ras_fifo_wait(struct creator_softc *, int);
void	creator_ras_wait(struct creator_softc *);
void	creator_ras_init(struct creator_softc *);
int	creator_ras_copyrows(void *, int, int, int);
int	creator_ras_erasecols(void *, int, int, int, long int);
int	creator_ras_eraserows(void *, int, int, long int);
void	creator_ras_fill(struct creator_softc *);
void	creator_ras_setfg(struct creator_softc *, int32_t);

int	creator_setcursor(struct creator_softc *, struct wsdisplay_cursor *);
int	creator_updatecursor(struct creator_softc *, u_int);
void	creator_curs_enable(struct creator_softc *, u_int);

#ifndef SMALL_KERNEL
void	creator_load_firmware(void *);
#endif /* SMALL_KERNEL */
void	creator_load_sram(struct creator_softc *, u_int32_t *, u_int32_t);

struct wsdisplay_accessops creator_accessops = {
	.ioctl = creator_ioctl,
	.mmap = creator_mmap
};

struct cfdriver creator_cd = {
	NULL, "creator", DV_DULL
};

struct cfattach creator_ca = {
	sizeof(struct creator_softc), creator_match, creator_attach
};

int
creator_match(parent, match, aux)
	struct device *parent;
	void *match, *aux;
{
	struct mainbus_attach_args *ma = aux;

	if (strcmp(ma->ma_name, "SUNW,ffb") == 0 ||
	    strcmp(ma->ma_name, "SUNW,afb") == 0)
		return (1);
	return (0);
}

void
creator_attach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct creator_softc *sc = (struct creator_softc *)self;
	struct mainbus_attach_args *ma = aux;
	extern int fbnode;
	int i, nregs;
	char *model;
	int btype;

	sc->sc_bt = ma->ma_bustag;

	nregs = min(ma->ma_nreg, FFB_NREGS);

	if (nregs <= FFB_REG_DFB24) {
		printf(": no dfb24 regs found\n");
		return;
	}

	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DFB24].ur_paddr,
	    ma->ma_reg[FFB_REG_DFB24].ur_len, BUS_SPACE_MAP_LINEAR,
	    &sc->sc_pixel_h)) {
		printf(": failed to map dfb24\n");
		return;
	}

	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_FBC].ur_paddr,
	    ma->ma_reg[FFB_REG_FBC].ur_len, 0, &sc->sc_fbc_h)) {
		printf(": failed to map fbc\n");
		goto unmap_dfb24;
	}

	if (bus_space_map(sc->sc_bt, ma->ma_reg[FFB_REG_DAC].ur_paddr,
	    ma->ma_reg[FFB_REG_DAC].ur_len, 0, &sc->sc_dac_h)) {
		printf(": failed to map dac\n");
		goto unmap_fbc;
	}

	for (i = 0; i < nregs; i++) {
		sc->sc_addrs[i] = ma->ma_reg[i].ur_paddr;
		sc->sc_sizes[i] = ma->ma_reg[i].ur_len;
	}
	sc->sc_nreg = nregs;

	sc->sc_console = (fbnode == ma->ma_node);
	sc->sc_node = ma->ma_node;

	if (strcmp(ma->ma_name, "SUNW,afb") == 0)
		sc->sc_type = FFB_AFB;

	/*
	 * Prom reports only the length of the fcode header, we need
	 * the whole thing.
	 */
	sc->sc_sizes[0] = 0x00400000;

	if (sc->sc_type == FFB_CREATOR) {
		btype = getpropint(sc->sc_node, "board_type", 0);
		if ((btype & 7) == 3)
			printf(": Creator3D");
		else
			printf(": Creator");
	} else
		printf(": Elite3D");

	model = getpropstring(sc->sc_node, "model");
	if (model == NULL || strlen(model) == 0)
		model = "unknown";

	DAC_WRITE(sc, FFB_DAC_TYPE, DAC_TYPE_GETREV);
	sc->sc_dacrev = DAC_READ(sc, FFB_DAC_VALUE) >> 28;

	printf(", model %s, dac %u", model, sc->sc_dacrev);

	if (sc->sc_type == FFB_AFB)
		sc->sc_dacrev = 10;

	fb_setsize(&sc->sc_sunfb, 32, 1152, 900, sc->sc_node, 0);
	/* linesize has a fixed value, compensate */
	sc->sc_sunfb.sf_linebytes = 8192;
	sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height * 8192;

	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);

	sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bt,
	    sc->sc_pixel_h);
	sc->sc_sunfb.sf_ro.ri_hw = sc;
	fbwscons_init(&sc->sc_sunfb, 0, sc->sc_console);

	if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CREATOR_CFFLAG_NOACCEL)
	    == 0) {
		sc->sc_sunfb.sf_ro.ri_ops.eraserows = creator_ras_eraserows;
		sc->sc_sunfb.sf_ro.ri_ops.erasecols = creator_ras_erasecols;
		sc->sc_sunfb.sf_ro.ri_ops.copyrows = creator_ras_copyrows;
		creator_ras_init(sc);

#ifndef SMALL_KERNEL
		/*
		 * Elite3D cards need a firmware for accelerated X to
		 * work.  Console framebuffer acceleration will work
		 * without it though, so doing this late should be
		 * fine.
		 */
		if (sc->sc_type == FFB_AFB)
			mountroothook_establish(creator_load_firmware, sc);
#endif /* SMALL_KERNEL */
	}

	if (sc->sc_console)
		fbwscons_console_init(&sc->sc_sunfb, -1);

	fbwscons_attach(&sc->sc_sunfb, &creator_accessops, sc->sc_console);
	return;

unmap_fbc:
	bus_space_unmap(sc->sc_bt, sc->sc_fbc_h,
	    ma->ma_reg[FFB_REG_FBC].ur_len);
unmap_dfb24:
	bus_space_unmap(sc->sc_bt, sc->sc_pixel_h,
	    ma->ma_reg[FFB_REG_DFB24].ur_len);
}

int
creator_ioctl(v, cmd, data, flags, p)
	void *v;
	u_long cmd;
	caddr_t data;
	int flags;
	struct proc *p;
{
	struct creator_softc *sc = v;
	struct wsdisplay_cursor *curs;
	struct wsdisplay_fbinfo *wdf;
	struct wsdisplay_curpos *pos;
	u_char r[2], g[2], b[2];
	int error;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_SUNFFB;
		break;
	case WSDISPLAYIO_SMODE:
		sc->sc_mode = *(u_int *)data;
		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
			struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
			long attr;

			if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags &
			    CREATOR_CFFLAG_NOACCEL) == 0)
				creator_ras_init(sc);

			/* Clear screen. */
			ri->ri_ops.alloc_attr(ri,
			    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &attr);
			ri->ri_ops.eraserows(ri, 0, ri->ri_rows, attr);
		}
		break;
	case WSDISPLAYIO_GINFO:
		wdf = (void *)data;
		wdf->height = sc->sc_sunfb.sf_height;
		wdf->width  = sc->sc_sunfb.sf_width;
		wdf->depth  = 32;
		wdf->cmsize = 0;
		break;
	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
		*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
		break;
	case WSDISPLAYIO_LINEBYTES:
		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
		break;
	case WSDISPLAYIO_GCURSOR:
		curs = (struct wsdisplay_cursor *)data;
		if (curs->which & WSDISPLAY_CURSOR_DOCUR)
			curs->enable = sc->sc_curs_enabled;
		if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
			curs->pos.x = sc->sc_curs_pos.x;
			curs->pos.y = sc->sc_curs_pos.y;
		}
		if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
			curs->hot.x = sc->sc_curs_hot.x;
			curs->hot.y = sc->sc_curs_hot.y;
		}
		if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
			curs->cmap.index = 0;
			curs->cmap.count = 2;
			r[0] = sc->sc_curs_fg >> 0;
			g[0] = sc->sc_curs_fg >> 8;
			b[0] = sc->sc_curs_fg >> 16;
			r[1] = sc->sc_curs_bg >> 0;
			g[1] = sc->sc_curs_bg >> 8;
			b[1] = sc->sc_curs_bg >> 16;
			error = copyout(r, curs->cmap.red, sizeof(r));
			if (error)
				return (error);
			error = copyout(g, curs->cmap.green, sizeof(g));
			if (error)
				return (error);
			error = copyout(b, curs->cmap.blue, sizeof(b));
			if (error)
				return (error);
		}
		if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
			size_t l;

			curs->size.x = sc->sc_curs_size.x;
			curs->size.y = sc->sc_curs_size.y;
			l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
			error = copyout(sc->sc_curs_image, curs->image, l);
			if (error)
				return (error);
			error = copyout(sc->sc_curs_mask, curs->mask, l);
			if (error)
				return (error);
		}
		break;
	case WSDISPLAYIO_SCURPOS:
		pos = (struct wsdisplay_curpos *)data;
		sc->sc_curs_pos.x = pos->x;
		sc->sc_curs_pos.y = pos->y;
		creator_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
		break;
	case WSDISPLAYIO_GCURPOS:
		pos = (struct wsdisplay_curpos *)data;
		pos->x = sc->sc_curs_pos.x;
		pos->y = sc->sc_curs_pos.y;
		break;
	case WSDISPLAYIO_SCURSOR:
		curs = (struct wsdisplay_cursor *)data;
		return (creator_setcursor(sc, curs));
	case WSDISPLAYIO_GCURMAX:
		pos = (struct wsdisplay_curpos *)data;
		pos->x = CREATOR_CURS_MAX;
		pos->y = CREATOR_CURS_MAX;
		break;
	case WSDISPLAYIO_SVIDEO:
	case WSDISPLAYIO_GVIDEO:
		break;

	case WSDISPLAYIO_GETCMAP:
	case WSDISPLAYIO_PUTCMAP:
	default:
		return -1; /* not supported yet */
        }

	return (0);
}

int
creator_setcursor(struct creator_softc *sc, struct wsdisplay_cursor *curs)
{
	u_int8_t r[2], g[2], b[2], image[128], mask[128];
	int error;
	size_t imcount;

	/*
	 * Do stuff that can generate errors first, then we'll blast it
	 * all at once.
	 */
	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
		if (curs->cmap.count < 2)
			return (EINVAL);
		error = copyin(curs->cmap.red, r, sizeof(r));
		if (error)
			return (error);
		error = copyin(curs->cmap.green, g, sizeof(g));
		if (error)
			return (error);
		error = copyin(curs->cmap.blue, b, sizeof(b));
		if (error)
			return (error);
	}

	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
		if (curs->size.x > CREATOR_CURS_MAX ||
		    curs->size.y > CREATOR_CURS_MAX)
			return (EINVAL);
		imcount = (curs->size.x * curs->size.y) / NBBY;
		error = copyin(curs->image, image, imcount);
		if (error)
			return (error);
		error = copyin(curs->mask, mask, imcount);
		if (error)
			return (error);
	}

	/*
	 * Ok, everything is in kernel space and sane, update state.
	 */

	if (curs->which & WSDISPLAY_CURSOR_DOCUR)
		sc->sc_curs_enabled = curs->enable;
	if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
		sc->sc_curs_pos.x = curs->pos.x;
		sc->sc_curs_pos.y = curs->pos.y;
	}
	if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
		sc->sc_curs_hot.x = curs->hot.x;
		sc->sc_curs_hot.y = curs->hot.y;
	}
	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
		sc->sc_curs_fg = ((r[0] << 0) | (g[0] << 8) | (b[0] << 16));
		sc->sc_curs_bg = ((r[1] << 0) | (g[1] << 8) | (b[1] << 16));
	}
	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
		sc->sc_curs_size.x = curs->size.x;
		sc->sc_curs_size.y = curs->size.y;
		bcopy(image, sc->sc_curs_image, imcount);
		bcopy(mask, sc->sc_curs_mask, imcount);
	}

	creator_updatecursor(sc, curs->which);

	return (0);
}

void
creator_curs_enable(struct creator_softc *sc, u_int ena)
{
	u_int32_t v;

	DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSENAB);
	if (sc->sc_dacrev <= 2)
		v = ena ? 3 : 0;
	else
		v = ena ? 0 : 3;
	DAC_WRITE(sc, FFB_DAC_VALUE2, v);
}

int
creator_updatecursor(struct creator_softc *sc, u_int which)
{
	creator_curs_enable(sc, 0);

	if (which & WSDISPLAY_CURSOR_DOCMAP) {
		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSCMAP);
		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_fg);
		DAC_WRITE(sc, FFB_DAC_VALUE2, sc->sc_curs_bg);
	}

	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
		u_int32_t x, y;

		x = sc->sc_curs_pos.x + CREATOR_CURS_MAX - sc->sc_curs_hot.x;
		y = sc->sc_curs_pos.y + CREATOR_CURS_MAX - sc->sc_curs_hot.y;
		DAC_WRITE(sc, FFB_DAC_TYPE2, DAC_TYPE2_CURSPOS);
		DAC_WRITE(sc, FFB_DAC_VALUE2,
		    ((x & 0xffff) << 16) | (y & 0xffff));
	}

	if (which & WSDISPLAY_CURSOR_DOCUR)
		creator_curs_enable(sc, sc->sc_curs_enabled);

	return (0);
}

const struct creator_mappings {
	bus_addr_t uoff;
	bus_addr_t poff;
	bus_size_t ulen;
} creator_map[] = {
	{ FFB_VOFF_SFB8R, FFB_POFF_SFB8R, FFB_VLEN_SFB8R },
	{ FFB_VOFF_SFB8G, FFB_POFF_SFB8G, FFB_VLEN_SFB8G },
	{ FFB_VOFF_SFB8B, FFB_POFF_SFB8B, FFB_VLEN_SFB8B },
	{ FFB_VOFF_SFB8X, FFB_POFF_SFB8X, FFB_VLEN_SFB8X },
	{ FFB_VOFF_SFB32, FFB_POFF_SFB32, FFB_VLEN_SFB32 },
	{ FFB_VOFF_SFB64, FFB_POFF_SFB64, FFB_VLEN_SFB64 },
	{ FFB_VOFF_FBC_REGS, FFB_POFF_FBC_REGS, FFB_VLEN_FBC_REGS },
	{ FFB_VOFF_BM_FBC_REGS, FFB_POFF_BM_FBC_REGS, FFB_VLEN_BM_FBC_REGS },
	{ FFB_VOFF_DFB8R, FFB_POFF_DFB8R, FFB_VLEN_DFB8R },
	{ FFB_VOFF_DFB8G, FFB_POFF_DFB8G, FFB_VLEN_DFB8G },
	{ FFB_VOFF_DFB8B, FFB_POFF_DFB8B, FFB_VLEN_DFB8B },
	{ FFB_VOFF_DFB8X, FFB_POFF_DFB8X, FFB_VLEN_DFB8X },
	{ FFB_VOFF_DFB24, FFB_POFF_DFB24, FFB_VLEN_DFB24 },
	{ FFB_VOFF_DFB32, FFB_POFF_DFB32, FFB_VLEN_DFB32 },
	{ FFB_VOFF_DFB422A, FFB_POFF_DFB422A, FFB_VLEN_DFB422A },
	{ FFB_VOFF_DFB422AD, FFB_POFF_DFB422AD, FFB_VLEN_DFB422AD },
	{ FFB_VOFF_DFB24B, FFB_POFF_DFB24B, FFB_VLEN_DFB24B },
	{ FFB_VOFF_DFB422B, FFB_POFF_DFB422B, FFB_VLEN_DFB422B },
	{ FFB_VOFF_DFB422BD, FFB_POFF_DFB422BD, FFB_VLEN_DFB422BD },
	{ FFB_VOFF_SFB16Z, FFB_POFF_SFB16Z, FFB_VLEN_SFB16Z },
	{ FFB_VOFF_SFB8Z, FFB_POFF_SFB8Z, FFB_VLEN_SFB8Z },
	{ FFB_VOFF_SFB422, FFB_POFF_SFB422, FFB_VLEN_SFB422 },
	{ FFB_VOFF_SFB422D, FFB_POFF_SFB422D, FFB_VLEN_SFB422D },
	{ FFB_VOFF_FBC_KREGS, FFB_POFF_FBC_KREGS, FFB_VLEN_FBC_KREGS },
	{ FFB_VOFF_DAC, FFB_POFF_DAC, FFB_VLEN_DAC },
	{ FFB_VOFF_PROM, FFB_POFF_PROM, FFB_VLEN_PROM },
	{ FFB_VOFF_EXP, FFB_POFF_EXP, FFB_VLEN_EXP },
};
#define	CREATOR_NMAPPINGS       nitems(creator_map)

paddr_t
creator_mmap(vsc, off, prot)
	void *vsc;
	off_t off;
	int prot;
{
	paddr_t x;
	struct creator_softc *sc = vsc;
	int i;

	switch (sc->sc_mode) {
	case WSDISPLAYIO_MODE_MAPPED:
		/* Turn virtual offset into physical offset */
		for (i = 0; i < CREATOR_NMAPPINGS; i++) {
			if (off >= creator_map[i].uoff &&
			    off < (creator_map[i].uoff + creator_map[i].ulen))
				break;
		}
		if (i == CREATOR_NMAPPINGS)
			break;

		off -= creator_map[i].uoff;
		off += creator_map[i].poff;
		off += sc->sc_addrs[0];

		/* Map based on physical offset */
		for (i = 0; i < sc->sc_nreg; i++) {
			/* Before this set? */
			if (off < sc->sc_addrs[i])
				continue;
			/* After this set? */
			if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
				continue;

			x = bus_space_mmap(sc->sc_bt, 0, off, prot,
			    BUS_SPACE_MAP_LINEAR);
			return (x);
		}
		break;
	case WSDISPLAYIO_MODE_DUMBFB:
		if (sc->sc_nreg <= FFB_REG_DFB24)
			break;
		if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
			return (bus_space_mmap(sc->sc_bt,
			    sc->sc_addrs[FFB_REG_DFB24], off, prot,
			    BUS_SPACE_MAP_LINEAR));
		break;
	}

	return (-1);
}

void
creator_ras_fifo_wait(sc, n)
	struct creator_softc *sc;
	int n;
{
	int32_t cache = sc->sc_fifo_cache;

	if (cache < n) {
		do {
			cache = FBC_READ(sc, FFB_FBC_UCSR);
			cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
		} while (cache < n);
	}
	sc->sc_fifo_cache = cache - n;
}

void
creator_ras_wait(sc)
	struct creator_softc *sc;
{
	u_int32_t ucsr, r;

	while (1) {
		ucsr = FBC_READ(sc, FFB_FBC_UCSR);
		if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
			break;
		r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
		if (r != 0)
			FBC_WRITE(sc, FFB_FBC_UCSR, r);
	}
}

void
creator_ras_init(sc)
	struct creator_softc *sc;
{
	creator_ras_fifo_wait(sc, 7);
	FBC_WRITE(sc, FFB_FBC_PPC,
	    FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
	    FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
	FBC_WRITE(sc, FFB_FBC_FBC,
	    FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
	    FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
	FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
	FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
	sc->sc_fg_cache = 0;
	FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
	creator_ras_wait(sc);
}

int
creator_ras_eraserows(cookie, row, n, attr)
	void *cookie;
	int row, n;
	long int attr;
{
	struct rasops_info *ri = cookie;
	struct creator_softc *sc = ri->ri_hw;
	int bg, fg;

	if (row < 0) {
		n += row;
		row = 0;
	}
	if (row + n > ri->ri_rows)
		n = ri->ri_rows - row;
	if (n <= 0)
		return 0;

	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
	creator_ras_fill(sc);
	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
	creator_ras_fifo_wait(sc, 4);
	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
		FBC_WRITE(sc, FFB_FBC_BY, 0);
		FBC_WRITE(sc, FFB_FBC_BX, 0);
		FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
	} else {
		row *= ri->ri_font->fontheight;
		FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
		FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
		FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
	}
	creator_ras_wait(sc);

	return 0;
}

int
creator_ras_erasecols(cookie, row, col, n, attr)
	void *cookie;
	int row, col, n;
	long int attr;
{
	struct rasops_info *ri = cookie;
	struct creator_softc *sc = ri->ri_hw;
	int fg, bg;

	if ((row < 0) || (row >= ri->ri_rows))
		return 0;
	if (col < 0) {
		n += col;
		col = 0;
	}
	if (col + n > ri->ri_cols)
		n = ri->ri_cols - col;
	if (n <= 0)
		return 0;
	n *= ri->ri_font->fontwidth;
	col *= ri->ri_font->fontwidth;
	row *= ri->ri_font->fontheight;

	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
	creator_ras_fill(sc);
	creator_ras_setfg(sc, ri->ri_devcmap[bg]);
	creator_ras_fifo_wait(sc, 4);
	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
	FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
	FBC_WRITE(sc, FFB_FBC_BW, n - 1);
	creator_ras_wait(sc);

	return 0;
}

void
creator_ras_fill(sc)
	struct creator_softc *sc;
{
	creator_ras_fifo_wait(sc, 2);
	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
	creator_ras_wait(sc);
}

int
creator_ras_copyrows(cookie, src, dst, n)
	void *cookie;
	int src, dst, n;
{
	struct rasops_info *ri = cookie;
	struct creator_softc *sc = ri->ri_hw;

	if (dst == src)
		return 0;
	if (src < 0) {
		n += src;
		src = 0;
	}
	if ((src + n) > ri->ri_rows)
		n = ri->ri_rows - src;
	if (dst < 0) {
		n += dst;
		dst = 0;
	}
	if ((dst + n) > ri->ri_rows)
		n = ri->ri_rows - dst;
	if (n <= 0)
		return 0;
	n *= ri->ri_font->fontheight;
	src *= ri->ri_font->fontheight;
	dst *= ri->ri_font->fontheight;

	creator_ras_fifo_wait(sc, 8);
	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
	FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
	FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
	FBC_WRITE(sc, FFB_FBC_BH, n);
	FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
	creator_ras_wait(sc);

	return 0;
}

void
creator_ras_setfg(sc, fg)
	struct creator_softc *sc;
	int32_t fg;
{
	creator_ras_fifo_wait(sc, 1);
	if (fg == sc->sc_fg_cache)
		return;
	sc->sc_fg_cache = fg;
	FBC_WRITE(sc, FFB_FBC_FG, fg);
	creator_ras_wait(sc);
}

#ifndef SMALL_KERNEL
struct creator_firmware {
	char		fw_ident[8];
	u_int32_t	fw_size;
	u_int32_t	fw_reserved[2];
	u_int32_t	fw_ucode[0];
};

#define CREATOR_FIRMWARE_REV	0x101

void
creator_load_firmware(void *vsc)
{
	struct creator_softc *sc = vsc;
	struct creator_firmware *fw;
	u_int32_t ascr;
	size_t buflen;
	u_char *buf;
	int error;

	error = loadfirmware("afb", &buf, &buflen);
	if (error) {
		printf("%s: error %d, could not read firmware %s\n",
		       sc->sc_sunfb.sf_dev.dv_xname, error, "afb");
		return;
	}

	fw = (struct creator_firmware *)buf;
	if (sizeof(*fw) > buflen ||
	    fw->fw_size * sizeof(u_int32_t) > (buflen - sizeof(*fw))) {
		printf("%s: corrupt firmware\n", sc->sc_sunfb.sf_dev.dv_xname);
		free(buf, M_DEVBUF, 0);
		return;
	}

	printf("%s: firmware rev %d.%d.%d\n", sc->sc_sunfb.sf_dev.dv_xname,
	       (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 16) & 0xff,
	       (fw->fw_ucode[CREATOR_FIRMWARE_REV] >> 8) & 0xff,
	       fw->fw_ucode[CREATOR_FIRMWARE_REV] & 0xff);

	ascr = FBC_READ(sc, FFB_FBC_ASCR);

	/* Stop all floats. */
	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
	FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_STOP);

	creator_ras_wait(sc);

	/* Load firmware into all secondary floats. */
	if (ascr & 0x3e) {
		FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3e);
		creator_load_sram(sc, fw->fw_ucode, fw->fw_size);
	}

	/* Load firmware into primary float. */
	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x01);
	creator_load_sram(sc, fw->fw_ucode, fw->fw_size);

	/* Restart all floats. */
	FBC_WRITE(sc, FFB_FBC_FEM, ascr & 0x3f);
	FBC_WRITE(sc, FFB_FBC_ASCR, FBC_ASCR_RESTART);

	creator_ras_wait(sc);

	free(buf, M_DEVBUF, 0);
}
#endif /* SMALL_KERNEL */

void
creator_load_sram(struct creator_softc *sc, u_int32_t *ucode, u_int32_t size)
{
	uint64_t pstate, fprs;
	caddr_t sram;

	sram = bus_space_vaddr(sc->sc_bt, sc->sc_fbc_h) + FFB_FBC_SRAM36;

	/*
	 * Apparently, loading the firmware into SRAM needs to be done
	 * using block copies.  And block copies use the
	 * floating-point registers.  Generally, using the FPU in the
	 * kernel is verboten.  But since we load the firmware before
	 * userland processes are started, thrashing the
	 * floating-point registers is fine.  We do need to enable the
	 * FPU before we access them though, otherwise we'll trap.
	 */
	pstate = sparc_rdpr(pstate);
	sparc_wrpr(pstate, pstate | PSTATE_PEF, 0);
	fprs = sparc_rd(fprs);
	sparc_wr(fprs, FPRS_FEF, 0);

	FBC_WRITE(sc, FFB_FBC_SRAMAR, 0);

	while (size > 0) {
		creator_ras_fifo_wait(sc, 16);

		__asm__ volatile("ld	[%0 + 0x00], %%f1\n\t"
				     "ld	[%0 + 0x04], %%f0\n\t"
				     "ld	[%0 + 0x08], %%f3\n\t"
				     "ld	[%0 + 0x0c], %%f2\n\t"
				     "ld	[%0 + 0x10], %%f5\n\t"
				     "ld	[%0 + 0x14], %%f4\n\t"
				     "ld	[%0 + 0x18], %%f7\n\t"
				     "ld	[%0 + 0x1c], %%f6\n\t"
				     "ld	[%0 + 0x20], %%f9\n\t"
				     "ld	[%0 + 0x24], %%f8\n\t"
				     "ld	[%0 + 0x28], %%f11\n\t"
				     "ld	[%0 + 0x2c], %%f10\n\t"
				     "ld	[%0 + 0x30], %%f13\n\t"
				     "ld	[%0 + 0x34], %%f12\n\t"
				     "ld	[%0 + 0x38], %%f15\n\t"
				     "ld	[%0 + 0x3c], %%f14\n\t"
				     "membar	#Sync\n\t"
				     "stda	%%f0, [%1] 240\n\t"
				     "membar	#Sync"
				     : : "r" (ucode), "r" (sram));

		ucode += 16;
		size -= 16;
	}

	sparc_wr(fprs, fprs, 0);
	sparc_wrpr(pstate, pstate, 0);

	creator_ras_wait(sc);
}


code:
/*	$OpenBSD: creatorreg.h,v 1.9 2009/11/30 23:32:57 kettenis Exp $	*/

/*
 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* Number of register sets */
#define	FFB_NREGS		24

/* Register set numbers */
#define	FFB_REG_PROM		0
#define	FFB_REG_DAC		1
#define	FFB_REG_FBC		2
#define	FFB_REG_DFB8R		3
#define	FFB_REG_DFB8G		4
#define	FFB_REG_DFB8B		5
#define	FFB_REG_DFB8X		6
#define	FFB_REG_DFB24		7
#define	FFB_REG_DFB32		8
#define	FFB_REG_SFB8R		9
#define	FFB_REG_SFB8G		10
#define	FFB_REG_SFB8B		11
#define	FFB_REG_SFB8X		12
#define	FFB_REG_SFB32		13
#define	FFB_REG_SFB64		14
#define	FFB_REG_DFB422A		15

/* Virtual offsets */
#define	FFB_VOFF_SFB8R		0x00000000UL
#define	FFB_VOFF_SFB8G		0x00400000UL
#define	FFB_VOFF_SFB8B		0x00800000UL
#define	FFB_VOFF_SFB8X		0x00c00000UL
#define	FFB_VOFF_SFB32		0x01000000UL
#define	FFB_VOFF_SFB64		0x02000000UL
#define	FFB_VOFF_FBC_REGS	0x04000000UL
#define	FFB_VOFF_BM_FBC_REGS	0x04002000UL
#define	FFB_VOFF_DFB8R		0x04004000UL
#define	FFB_VOFF_DFB8G		0x04404000UL
#define	FFB_VOFF_DFB8B		0x04804000UL
#define	FFB_VOFF_DFB8X		0x04c04000UL
#define	FFB_VOFF_DFB24		0x05004000UL
#define	FFB_VOFF_DFB32		0x06004000UL
#define	FFB_VOFF_DFB422A	0x07004000UL	/* DFB 422 mode write to A */
#define	FFB_VOFF_DFB422AD	0x07804000UL	/* DFB 422 mode with line doubling */
#define	FFB_VOFF_DFB24B		0x08004000UL	/* DFB 24bit mode write to B */
#define	FFB_VOFF_DFB422B	0x09004000UL	/* DFB 422 mode write to B */
#define	FFB_VOFF_DFB422BD	0x09804000UL	/* DFB 422 mode with line doubling */
#define	FFB_VOFF_SFB16Z		0x0a004000UL	/* 16bit mode Z planes */
#define	FFB_VOFF_SFB8Z		0x0a404000UL	/* 8bit mode Z planes */
#define	FFB_VOFF_SFB422		0x0ac04000UL	/* SFB 422 mode write to A/B */
#define	FFB_VOFF_SFB422D	0x0b404000UL	/* SFB 422 mode with line doubling */
#define	FFB_VOFF_FBC_KREGS	0x0bc04000UL
#define	FFB_VOFF_DAC		0x0bc06000UL
#define	FFB_VOFF_PROM		0x0bc08000UL
#define	FFB_VOFF_EXP		0x0bc18000UL

/* Virtual lengths */
#define	FFB_VLEN_SFB8R		0x0400000
#define	FFB_VLEN_SFB8G		0x0400000
#define	FFB_VLEN_SFB8B		0x0400000
#define	FFB_VLEN_SFB8X		0x0400000
#define	FFB_VLEN_SFB32		0x1000000
#define	FFB_VLEN_SFB64		0x2000000
#define	FFB_VLEN_FBC_REGS	0x0002000
#define	FFB_VLEN_BM_FBC_REGS	0x0002000
#define	FFB_VLEN_DFB8R		0x0400000
#define	FFB_VLEN_DFB8G		0x0400000
#define	FFB_VLEN_DFB8B		0x0400000
#define	FFB_VLEN_DFB8X		0x0400000
#define	FFB_VLEN_DFB24		0x1000000
#define	FFB_VLEN_DFB32		0x1000000
#define	FFB_VLEN_DFB422A	0x0800000
#define	FFB_VLEN_DFB422AD	0x0800000
#define	FFB_VLEN_DFB24B		0x1000000
#define	FFB_VLEN_DFB422B	0x0800000
#define	FFB_VLEN_DFB422BD	0x0800000
#define	FFB_VLEN_SFB16Z		0x0800000
#define	FFB_VLEN_SFB8Z		0x0800000
#define	FFB_VLEN_SFB422		0x0800000
#define	FFB_VLEN_SFB422D	0x0800000
#define	FFB_VLEN_FBC_KREGS	0x0002000
#define	FFB_VLEN_DAC		0x0002000
#define	FFB_VLEN_PROM		0x0010000
#define	FFB_VLEN_EXP		0x0002000

/* Physical offsets */
#define	FFB_POFF_SFB8R		0x04000000UL
#define	FFB_POFF_SFB8G		0x04400000UL
#define	FFB_POFF_SFB8B		0x04800000UL
#define	FFB_POFF_SFB8X		0x04c00000UL
#define	FFB_POFF_SFB32		0x05000000UL
#define	FFB_POFF_SFB64		0x06000000UL
#define	FFB_POFF_FBC_REGS	0x00600000UL
#define	FFB_POFF_BM_FBC_REGS	0x00600000UL
#define	FFB_POFF_DFB8R		0x01000000UL
#define	FFB_POFF_DFB8G		0x01400000UL
#define	FFB_POFF_DFB8B		0x01800000UL
#define	FFB_POFF_DFB8X		0x01c00000UL
#define	FFB_POFF_DFB24		0x02000000UL
#define	FFB_POFF_DFB32		0x03000000UL
#define	FFB_POFF_FBC_KREGS	0x00610000UL
#define	FFB_POFF_DAC		0x00400000UL
#define	FFB_POFF_PROM		0x00000000UL
#define	FFB_POFF_EXP		0x00200000UL
#define	FFB_POFF_DFB422A	0x09000000UL
#define	FFB_POFF_DFB422AD	0x09800000UL
#define	FFB_POFF_DFB24B		0x0a000000UL
#define	FFB_POFF_DFB422B	0x0b000000UL
#define	FFB_POFF_DFB422BD	0x0b800000UL
#define	FFB_POFF_SFB16Z		0x0c800000UL
#define	FFB_POFF_SFB8Z		0x0c000000UL
#define	FFB_POFF_SFB422		0x0d000000UL
#define	FFB_POFF_SFB422D	0x0d800000UL

#define	FFB_FBC_ALPHA		0x00c
#define	FFB_FBC_RED		0x010
#define	FFB_FBC_GREEN		0x014
#define	FFB_FBC_BLUE		0x018
#define	FFB_FBC_DEPTH		0x01c
#define	FFB_FBC_Y		0x020
#define	FFB_FBC_X		0x024
#define	FFB_FBC_RYF		0x030
#define	FFB_FBC_RXF		0x034
#define	FFB_FBC_DMYF		0x040
#define	FFB_FBC_DMXF		0x044
#define	FFB_FBC_EBYI		0x050
#define	FFB_FBC_EBXI		0x054
#define	FFB_FBC_BY		0x060
#define	FFB_FBC_BX		0x064
#define	FFB_FBC_DY		0x068
#define	FFB_FBC_DX		0x06c
#define	FFB_FBC_BH		0x070
#define	FFB_FBC_BW		0x074
#define	FFB_FBC_SUVTX		0x100
#define	FFB_FBC_PPC		0x200	/* pixel processor control */
#define	FFB_FBC_WID		0x204
#define	FFB_FBC_FG		0x208
#define	FFB_FBC_BG		0x20c
#define	FFB_FBC_CONSTY		0x210
#define	FFB_FBC_CONSTZ		0x214
#define	FFB_FBC_XCLIP		0x218
#define	FFB_FBC_DCSS		0x21c
#define	FFB_FBC_VCLIPMIN	0x220
#define	FFB_FBC_VCLIPMAX	0x224
#define	FFB_FBC_VCLIPZMIN	0x228
#define	FFB_FBC_VCLIPZMAX	0x22c
#define	FFB_FBC_DCSF		0x230
#define	FFB_FBC_DCSB		0x234
#define	FFB_FBC_DCZF		0x238
#define	FFB_FBC_DCZB		0x23c
#define	FFB_FBC_BLENDC		0x244
#define	FFB_FBC_BLENDC1		0x248
#define	FFB_FBC_BLENDC2		0x24c
#define	FFB_FBC_FBRAMITC	0x250
#define	FFB_FBC_FBC		0x254	/* Frame Buffer Control	*/
#define	FFB_FBC_ROP		0x258	/* Raster OPeration */
#define	FFB_FBC_CMP		0x25c	/* Frame Buffer Compare */
#define	FFB_FBC_MATCHAB		0x260	/* Buffer AB Match Mask	*/
#define	FFB_FBC_MATCHC		0x264
#define	FFB_FBC_MAGNAB		0x268	/* Buffer AB Magnitude Mask */
#define	FFB_FBC_MAGNC		0x26c
#define	FFB_FBC_FBCFG0		0x270
#define	FFB_FBC_FBCFG1		0x274
#define	FFB_FBC_FBCFG2		0x278
#define	FFB_FBC_FBCFG3		0x27c
#define	FFB_FBC_PPCFG		0x280
#define	FFB_FBC_PICK		0x284
#define	FFB_FBC_FILLMODE	0x288
#define	FFB_FBC_FBRAMWAC	0x28c
#define	FFB_FBC_PMASK		0x290	/* RGB Plane Mask */
#define	FFB_FBC_XPMASK		0x294	/* X PlaneMask */
#define	FFB_FBC_YPMASK		0x298
#define	FFB_FBC_ZPMASK		0x29c
#define	FFB_FBC_CLIP0MIN	0x2a0
#define	FFB_FBC_CLIP0MAX	0x2a4
#define	FFB_FBC_CLIP1MIN	0x2a8
#define	FFB_FBC_CLIP1MAX	0x2ac
#define	FFB_FBC_CLIP2MIN	0x2b0
#define	FFB_FBC_CLIP2MAX	0x2b4
#define	FFB_FBC_CLIP3MIN	0x2b8
#define	FFB_FBC_CLIP3MAX	0x2bc
#define	FFB_FBC_RAWBLEND2	0x2c0
#define	FFB_FBC_RAWPREBLEND	0x2c4
#define	FFB_FBC_RAWSTENCIL	0x2c8
#define	FFB_FBC_RAWSTENCILCTL	0x2cc
#define	FFB_FBC_THREEDRAM1	0x2d0
#define	FFB_FBC_THREEDRAM2	0x2d4
#define	FFB_FBC_PASSIN		0x2d8
#define	FFB_FBC_RAWCLRDEPTH	0x2dc
#define	FFB_FBC_RAWPMASK	0x2e0
#define	FFB_FBC_RAWCSRC		0x2e4
#define	FFB_FBC_RAWMATCH	0x2e8
#define	FFB_FBC_RAWMAGN		0x2ec
#define	FFB_FBC_RAWROPBLEND	0x2f0
#define	FFB_FBC_RAWCMP		0x2f4
#define	FFB_FBC_RAWWAC		0x2f8
#define	FFB_FBC_FBRAMID		0x2fc
#define	FFB_FBC_DRAWOP		0x300	/* Draw OPeration */
#define	FFB_FBC_FONTLPAT	0x30c
#define	FFB_FBC_FONTXY		0x314
#define	FFB_FBC_FONTW		0x318	/* Font Width */
#define	FFB_FBC_FONTINC		0x31c	/* Font Increment */
#define	FFB_FBC_FONT		0x320
#define	FFB_FBC_BLEND2		0x330
#define	FFB_FBC_PREBLEND	0x334
#define	FFB_FBC_STENCIL		0x338
#define	FFB_FBC_STENCILCTL	0x33c
#define	FFB_FBC_DCSS1		0x350
#define	FFB_FBC_DCSS2		0x354
#define	FFB_FBC_DCSS3		0x358
#define	FFB_FBC_WIDPMASK	0x35c
#define	FFB_FBC_DCS2		0x360
#define	FFB_FBC_DCS3		0x364
#define	FFB_FBC_DCS4		0x368
#define	FFB_FBC_DCD2		0x370
#define	FFB_FBC_DCD3		0x374
#define	FFB_FBC_DCD4		0x378
#define	FFB_FBC_PATTERN		0x380
#define	FFB_FBC_DEVID		0x800
#define	FFB_FBC_UCSR		0x900	/* User Control & Status */
#define	FFB_FBC_MER		0x980

#define	FFB_FBC_FEM		0x1540
#define	FFB_FBC_SRAMAR		0x1550

#define	FFB_FBC_ASCR		0x10800
#define	FFB_FBC_KCSR		0x10900
#define	FFB_FBC_SRAM36		0x114c0

#define	FFB_FBC_WB_A		0x20000000
#define	FFB_FBC_WM_COMBINED	0x00080000
#define	FFB_FBC_RB_A		0x00004000
#define	FFB_FBC_SB_BOTH		0x00003000
#define	FFB_FBC_ZE_OFF		0x00000400
#define	FFB_FBC_YE_OFF		0x00000100
#define	FFB_FBC_XE_ON		0x00000080
#define	FFB_FBC_XE_OFF		0x00000040
#define	FFB_FBC_RGBE_ON		0x0000002a
#define	FFB_FBC_RGBE_MASK	0x0000003f

#define	FBC_PPC_FW_DIS		0x00800000	/* force wid disable */
#define	FBC_PPC_FW_ENA		0x00c00000	/* force wid enable */
#define	FBC_PPC_ACE_DIS		0x00040000	/* aux clip disable */
#define	FBC_PPC_ACE_AUXSUB	0x00080000	/* aux clip add */
#define	FBC_PPC_ACE_AUXADD	0x000c0000	/* aux clip subtract */
#define	FBC_PPC_DCE_DIS		0x00020000	/* depth cue disable */
#define	FBC_PPC_DCE_ENA		0x00020000	/* depth cue enable */
#define	FBC_PPC_ABE_DIS		0x00008000	/* alpha blend disable */
#define	FBC_PPC_ABE_ENA		0x0000c000	/* alpha blend enable */
#define	FBC_PPC_VCE_DIS		0x00001000	/* view clip disable */
#define	FBC_PPC_VCE_2D		0x00002000	/* view clip 2d */
#define	FBC_PPC_VCE_3D		0x00003000	/* view clip 3d */
#define	FBC_PPC_APE_DIS		0x00000800	/* area pattern disable */
#define	FBC_PPC_APE_ENA		0x00000c00	/* area pattern enable */
#define	FBC_PPC_TBE_OPAQUE	0x00000200	/* opaque background */
#define	FBC_PPC_TBE_TRANSPAR	0x00000300	/* transparent background */
#define	FBC_PPC_ZS_VAR		0x00000080	/* z source ??? */
#define	FBC_PPC_ZS_CONST	0x000000c0	/* z source ??? */
#define	FBC_PPC_YS_VAR		0x00000020	/* y source ??? */
#define	FBC_PPC_YS_CONST	0x00000030	/* y source ??? */
#define	FBC_PPC_XS_WID		0x00000004	/* x source ??? */
#define	FBC_PPC_XS_VAR		0x00000008	/* x source ??? */
#define	FBC_PPC_XS_CONST	0x0000000c	/* x source ??? */
#define	FBC_PPC_CS_VAR		0x00000002	/* color source ??? */
#define	FBC_PPC_CS_CONST	0x00000003	/* color source ??? */

#define	FBC_ROP_NEW		0x83
#define	FBC_ROP_OLD		0x85

#define	FBC_UCSR_FIFO_MASK	0x00000fff
#define	FBC_UCSR_FB_BUSY	0x01000000
#define	FBC_UCSR_RP_BUSY	0x02000000
#define	FBC_UCSR_READ_ERR	0x40000000
#define	FBC_UCSR_FIFO_OVFL	0x80000000

#define	FBC_ASCR_STOP		0x00020000
#define	FBC_ASCR_RESTART	0x00040000

#define	FBC_DRAWOP_DOT		0x00
#define	FBC_DRAWOP_AADOT	0x01
#define	FBC_DRAWOP_BRLINECAP	0x02
#define	FBC_DRAWOP_BRLINEOPEN	0x03
#define	FBC_DRAWOP_DDLINE	0x04
#define	FBC_DRAWOP_AALINE	0x05
#define	FBC_DRAWOP_TRIANGLE	0x06
#define	FBC_DRAWOP_POLYGON	0x07
#define	FBC_DRAWOP_RECTANGLE	0x08
#define	FBC_DRAWOP_FASTFILL	0x09
#define	FBC_DRAWOP_BCOPY	0x0a	/* block copy: not implemented */
#define	FBC_DRAWOP_VSCROLL	0x0b	/* vertical scroll */

#define	FFB_DAC_TYPE		0x00
#define	FFB_DAC_VALUE		0x04
#define	FFB_DAC_TYPE2		0x08
#define	FFB_DAC_VALUE2		0x0c

#define	DAC_TYPE_CMAP		0x2000	/* load cmap */
#define	DAC_TYPE_BLANK		0x6000	/* blank/unblank */
#define	DAC_TYPE_GETREV		0x8000	/* get dac revision */

#define	DAC_TYPE2_CURSENAB	0x100	/* cursor enable */
#define	DAC_TYPE2_CURSCMAP	0x102	/* set cursor colormap */
#define	DAC_TYPE2_CURSPOS	0x104	/* set cursor position */

#define	DAC_BLANK_VIDEO_ENABLE		0x00000001
#define	DAC_BLANK_HSYNC_DISABLE		0x00000004
#define	DAC_BLANK_VSYNC_DISABLE		0x00000008


code:
/*	$OpenBSD: creatorvar.h,v 1.11 2006/05/15 21:38:36 miod Exp $	*/

/*
 * Copyright (c) 2002 Jason L. Wright (jason@thought.net),
 *  Federico G. Schwindt (fgsch@openbsd.org)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/* device types */
#define FFB_CREATOR		0	/* Creator/Creator3d */
#define FFB_AFB			1	/* Elite3D */

#define	CREATOR_CFFLAG_NOACCEL	0x1

struct creator_softc {
	struct sunfb sc_sunfb;
	bus_space_tag_t sc_bt;
	bus_space_handle_t sc_pixel_h;
	bus_space_handle_t sc_fbc_h;
	bus_space_handle_t sc_dac_h;
	bus_addr_t sc_addrs[FFB_NREGS];
	bus_size_t sc_sizes[FFB_NREGS];
	int sc_nscreens, sc_nreg;
	int sc_console;
	int sc_node;
	int sc_type;
	u_int sc_mode;
	int32_t sc_fifo_cache, sc_fg_cache;
	u_int32_t sc_dacrev;
	u_int sc_curs_enabled, sc_curs_fg, sc_curs_bg;
	struct wsdisplay_curpos sc_curs_pos, sc_curs_hot, sc_curs_size;
	u_char sc_curs_image[512], sc_curs_mask[512];
};

#define	CREATOR_CURS_MAX	64

#define	FBC_WRITE(sc,r,v) \
    bus_space_write_4((sc)->sc_bt, (sc)->sc_fbc_h, (r), (v))
#define	FBC_READ(sc,r) \
    bus_space_read_4((sc)->sc_bt, (sc)->sc_fbc_h, (r))

#define	DAC_WRITE(sc,r,v) \
    bus_space_write_4((sc)->sc_bt, (sc)->sc_dac_h, (r), (v))
#define	DAC_READ(sc,r) \
    bus_space_read_4((sc)->sc_bt, (sc)->sc_dac_h, (r))