code:
/*	$OpenBSD: odyssey.c,v 1.11 2014/03/09 10:01:25 miod Exp $ */
/*
 * Copyright (c) 2009, 2010 Joel Sing <jsing@openbsd.org>
 *
 * 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 SGI VPro (aka Odyssey) Graphics Card.
 */

/*
 * The details regarding the design and operation of this hardware, along with
 * the necessary magic numbers, are only available thanks to the reverse
 * engineering work undertaken by Stanislaw Skowronek <skylark@linux-mips.org>.
 */

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

#include <machine/autoconf.h>

#include <mips64/arcbios.h>

#include <sgi/dev/gl.h>
#include <sgi/xbow/odysseyreg.h>
#include <sgi/xbow/odysseyvar.h>
#include <sgi/xbow/widget.h>
#include <sgi/xbow/xbow.h>
#include <sgi/xbow/xbowdevs.h>

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

/*
 * Colourmap data.
 */
struct  odyssey_cmap {
	u_int8_t cm_red[256];
	u_int8_t cm_green[256];
	u_int8_t cm_blue[256];
};

/*
 * Screen data.
 */
struct odyssey_screen {
	struct device *sc;		/* Back pointer. */

	struct rasops_info ri;		/* Screen raster display info. */
	struct odyssey_cmap cmap;	/* Display colour map. */
	long attr;			/* Rasops attributes. */

	int width;			/* Width in pixels. */
	int height;			/* Height in pixels. */
	int depth;			/* Colour depth in bits. */
	int linebytes;			/* Bytes per line. */
};

struct odyssey_softc {
	struct device		sc_dev;

	struct mips_bus_space	iot_store;
	bus_space_tag_t		iot;
	bus_space_handle_t	ioh;

	int console;				/* Is this the console? */
	int screens;				/* No of screens allocated. */

	struct odyssey_screen	*curscr;	/* Current screen. */
};

int	odyssey_match(struct device *, void *, void *);
void	odyssey_attach(struct device *, struct device *, void *);

int	odyssey_is_console(struct xbow_attach_args *);

void	odyssey_cmd_wait(struct odyssey_softc *);
void	odyssey_data_wait(struct odyssey_softc *);
void	odyssey_cmd_flush(struct odyssey_softc *, int);

void	odyssey_setup(struct odyssey_softc *);
void	odyssey_init_screen(struct odyssey_screen *);

/*
 * Colour map handling for indexed modes.
 */
int	odyssey_getcmap(struct odyssey_cmap *, struct wsdisplay_cmap *);
int	odyssey_putcmap(struct odyssey_cmap *, struct wsdisplay_cmap *);

/*
 * Hardware acceleration for rasops.
 */
void	odyssey_rop(struct odyssey_softc *, int, int, int, int, int, int);
void	odyssey_copyrect(struct odyssey_softc *, int, int, int, int, int, int);
void	odyssey_fillrect(struct odyssey_softc *, int, int, int, int, u_int);
int	odyssey_do_cursor(struct rasops_info *);
int	odyssey_putchar(void *, int, int, u_int, long);
int	odyssey_copycols(void *, int, int, int, int);
int	odyssey_erasecols(void *, int, int, int, long);
int	odyssey_copyrows(void *, int, int, int);
int	odyssey_eraserows(void *, int, int, long);

u_int32_t ieee754_sp(uint);

/*
 * Interfaces for wscons.
 */
int 	odyssey_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t odyssey_mmap(void *, off_t, int);
int	odyssey_alloc_screen(void *, const struct wsscreen_descr *, void **,
	    int *, int *, long *);
void	odyssey_free_screen(void *, void *);
int	odyssey_show_screen(void *, void *, int, void (*)(void *, int, int),
	    void *);
int	odyssey_load_font(void *, void *, struct wsdisplay_font *);
int	odyssey_list_font(void *, struct wsdisplay_font *);

static struct odyssey_screen odyssey_consdata;
static struct odyssey_softc odyssey_cons_sc;

struct wsscreen_descr odyssey_stdscreen = {
	"std",			/* Screen name. */
};

struct wsdisplay_accessops odyssey_accessops = {
	.ioctl = odyssey_ioctl,
	.mmap = odyssey_mmap,
	.alloc_screen = odyssey_alloc_screen,
	.free_screen = odyssey_free_screen,
	.show_screen = odyssey_show_screen,
	.load_font = odyssey_load_font,
	.list_font = odyssey_list_font
};

const struct wsscreen_descr *odyssey_scrlist[] = {
	&odyssey_stdscreen
};

struct wsscreen_list odyssey_screenlist = {
	nitems(odyssey_scrlist), odyssey_scrlist
};

const struct cfattach odyssey_ca = {
	sizeof(struct odyssey_softc), odyssey_match, odyssey_attach,
};

struct cfdriver odyssey_cd = {
	NULL, "odyssey", DV_DULL,
};

int
odyssey_match(struct device *parent, void *match, void *aux)
{
	struct xbow_attach_args *xaa = aux;

	if (xaa->xaa_vendor == XBOW_VENDOR_SGI2 &&
	    xaa->xaa_product == XBOW_PRODUCT_SGI2_ODYSSEY)
		return 1;

	return 0;
}

void
odyssey_attach(struct device *parent, struct device *self, void *aux)
{
	struct xbow_attach_args *xaa = aux;
	struct wsemuldisplaydev_attach_args waa;
	struct odyssey_softc *sc = (void *)self;
	struct odyssey_screen *screen;

	if (strncmp(bios_graphics, "alive", 5) != 0) {
		printf(" device has not been setup by firmware!\n");
		return;
	}

	printf(" revision %d\n", xaa->xaa_revision);

	/*
	 * Create a copy of the bus space tag.
	 */
	bcopy(xaa->xaa_iot, &sc->iot_store, sizeof(struct mips_bus_space));
	sc->iot = &sc->iot_store;

	/* Setup bus space mappings. */
	if (bus_space_map(sc->iot, ODYSSEY_REG_OFFSET, ODYSSEY_REG_SIZE,
	    BUS_SPACE_MAP_LINEAR, &sc->ioh)) {
		printf("failed to map bus space!\n");
		return;
	}

	if (odyssey_is_console(xaa)) {
		/*
		 * Setup has already been done via odyssey_cnattach().
		 */
		screen = &odyssey_consdata;
       		sc->curscr = screen;
		sc->curscr->sc = (void *)sc;
		sc->console = 1;
	} else {
		/*
		 * Setup screen data.
		 */
		sc->curscr = malloc(sizeof(struct odyssey_screen), M_DEVBUF,
		    M_NOWAIT);
		if (sc->curscr == NULL) {
			printf("failed to allocate screen memory!\n");
			return;
		}
		sc->curscr->sc = (void *)sc;
		screen = sc->curscr;

		/* Setup hardware and clear screen. */
		odyssey_setup(sc);
		odyssey_fillrect(sc, 0, 0, 1280, 1024, 0x000000);
		odyssey_cmd_flush(sc, 0);

		/* Set screen defaults. */
		screen->width = 1280;
		screen->height = 1024;
		screen->depth = 32;
		screen->linebytes = screen->width * screen->depth / 8;

		odyssey_init_screen(screen);
	}

	waa.console = sc->console;
	waa.scrdata = &odyssey_screenlist;
	waa.accessops = &odyssey_accessops;
	waa.accesscookie = screen;
	waa.defaultscreens = 0;
	config_found(self, &waa, wsemuldisplaydevprint);
}

void
odyssey_init_screen(struct odyssey_screen *screen)
{
	u_char *colour;
	int i;

	/*
	 * Initialise screen.
	 */

	/* Initialise rasops. */
	memset(&screen->ri, 0, sizeof(struct rasops_info));

	screen->ri.ri_flg = RI_CENTER;
	screen->ri.ri_depth = screen->depth;
	screen->ri.ri_width = screen->width;
	screen->ri.ri_height = screen->height;
	screen->ri.ri_stride = screen->linebytes;

	if (screen->depth == 32) {
		screen->ri.ri_bpos = 16;
		screen->ri.ri_bnum = 8;
		screen->ri.ri_gpos = 8;
		screen->ri.ri_gnum = 8;
		screen->ri.ri_rpos = 0;
		screen->ri.ri_rnum = 8;
	} else if (screen->depth == 16) {
		screen->ri.ri_rpos = 10;
		screen->ri.ri_rnum = 5;
		screen->ri.ri_gpos = 5;
		screen->ri.ri_gnum = 5;
		screen->ri.ri_bpos = 0;
		screen->ri.ri_bnum = 5;
	}

	rasops_init(&screen->ri, screen->height / 8, screen->width / 8);

	/*
	 * Initialise colourmap, if required.
	 */
	if (screen->depth == 8) {
		for (i = 0; i < 16; i++) {
			colour = (u_char *)&rasops_cmap[i * 3];
			screen->cmap.cm_red[i] = colour[0];
			screen->cmap.cm_green[i] = colour[1];
			screen->cmap.cm_blue[i] = colour[2];
		}
		for (i = 240; i < 256; i++) {
			colour = (u_char *)&rasops_cmap[i * 3];
			screen->cmap.cm_red[i] = colour[0];
			screen->cmap.cm_green[i] = colour[1];
			screen->cmap.cm_blue[i] = colour[2];
		}
	}

	screen->ri.ri_hw = screen->sc;

	screen->ri.ri_ops.putchar = odyssey_putchar;
	screen->ri.ri_do_cursor = odyssey_do_cursor;
	screen->ri.ri_ops.copyrows = odyssey_copyrows;
	screen->ri.ri_ops.copycols = odyssey_copycols;
	screen->ri.ri_ops.eraserows = odyssey_eraserows;
	screen->ri.ri_ops.erasecols = odyssey_erasecols;

	odyssey_stdscreen.ncols = screen->ri.ri_cols;
	odyssey_stdscreen.nrows = screen->ri.ri_rows;
	odyssey_stdscreen.textops = &screen->ri.ri_ops;
	odyssey_stdscreen.fontwidth = screen->ri.ri_font->fontwidth;
	odyssey_stdscreen.fontheight = screen->ri.ri_font->fontheight;
	odyssey_stdscreen.capabilities = screen->ri.ri_caps;
}

/*
 * Hardware initialisation.
 */
void
odyssey_setup(struct odyssey_softc *sc)
{
	u_int64_t val;
	int i;

	/* Initialise Buzz Graphics Engine. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x20008003);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x21008010);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x22008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x23008002);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2400800c);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2500800e);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x27008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x28008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x290080d6);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2a0080e0);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2c0080ea);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2e008380);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2f008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x30008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x31008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x32008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x33008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x35008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x310081e0);
	odyssey_cmd_flush(sc, 0);

	/* Initialise Buzz X-Form. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x9080bda2);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0xbf800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4e000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x40400000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4e000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x4d000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x9080bdc8);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008010);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x908091df);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3f800000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x34008000);
	odyssey_cmd_flush(sc, 0);

	/* Initialise Buzz Raster. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001203b);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00001000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001084a);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000080);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000080);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010845);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000ff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000076ff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001141b);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000001);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011c16);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x03000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011023);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ff0ff0);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ff0ff0);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000ff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011017);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000050);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x20004950);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0001204b);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x004ff3ff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00ffffff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	odyssey_cmd_flush(sc, 0);

	/*
	 * Initalise Pixel Blaster & Jammer.
	 */
	for (i = 0; i < 32; i++) {
		if ((i & 0xf) == 0)
			odyssey_data_wait(sc);

		bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
		    ((0x30000001ULL | ((0x2900 + i) << 14)) << 32) |
		    0x905215a6);
	}

	odyssey_data_wait(sc);
	bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
	    ((0x30000001ULL | (0x2581 << 14)) << 32) | 0x0);

	/* Gamma ramp. */
	for (i = 0; i < 0x600; i++) {
		if ((i & 0xf) == 0)
			odyssey_data_wait(sc);

		if (i < 0x200)
			val = i >> 2;
		else if (i < 0x300)
			val = ((i - 0x200) >> 1) + 0x80;
		else
			val = ((i - 0x300) >> 0) + 0x100;

		val = (val << 20) | (val << 10) | val;

		bus_space_write_8(sc->iot, sc->ioh, ODYSSEY_DATA_FIFO,
		    ((0x30000001ULL | ((0x1a00 + i) << 14)) << 32) | val);
	}
}

void
odyssey_cmd_wait(struct odyssey_softc *sc)
{
	u_int32_t val, timeout = 1000000;

	val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_STATUS);
	while ((val & ODYSSEY_STATUS_CMD_FIFO_LOW) == 0) {
		delay(1);
		if (--timeout == 0) {
			printf("odyssey: timeout waiting for command fifo!\n");
			return;
		}
		val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_STATUS);
	}
}

void
odyssey_data_wait(struct odyssey_softc *sc)
{
	u_int32_t val, timeout = 1000000;

	val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_DBE_STATUS);
	while ((val & 0x7f) > 0) {
		delay(1);
		if (--timeout == 0) {
			printf("odyssey: timeout waiting for data fifo!\n");
			return;
		}
		val = bus_space_read_4(sc->iot, sc->ioh, ODYSSEY_DBE_STATUS);
	}
}

void
odyssey_cmd_flush(struct odyssey_softc *sc, int quick)
{

	odyssey_cmd_wait(sc);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000fa);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);

	if (quick)
		return;

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010019);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000096);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010443);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x000000fa);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010046);
}

/*
 * Interfaces for wscons.
 */

int
odyssey_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	struct odyssey_screen *screen = (struct odyssey_screen *)v;
	int rc;

	switch (cmd) {
	case WSDISPLAYIO_GTYPE:
		*(u_int *)data = WSDISPLAY_TYPE_ODYSSEY;
		break;

	case WSDISPLAYIO_GINFO:
	{
		struct wsdisplay_fbinfo *fb = (struct wsdisplay_fbinfo *)data;

		fb->height = screen->height;
		fb->width = screen->width;
		fb->depth = screen->depth;
		fb->cmsize = screen->depth == 8 ? 256 : 0;
	}
		break;

	case WSDISPLAYIO_LINEBYTES:
		*(u_int *)data = screen->linebytes;
		break;

	case WSDISPLAYIO_GETCMAP:
		if (screen->depth == 8) {
			struct wsdisplay_cmap *cm =
			    (struct wsdisplay_cmap *)data;

			rc = odyssey_getcmap(&screen->cmap, cm);
			if (rc != 0)
				return (rc);
		}
		break;

	case WSDISPLAYIO_PUTCMAP:
		if (screen->depth == 8) {
			struct wsdisplay_cmap *cm =
			    (struct wsdisplay_cmap *)data;

			rc = odyssey_putcmap(&screen->cmap, cm);
			if (rc != 0)
				return (rc);
		}
		break;

	case WSDISPLAYIO_GVIDEO:
	case WSDISPLAYIO_SVIDEO:
		/* Handled by the upper layer. */
		break;

	default:
		return (-1);
	}

	return (0);
}

int
odyssey_getcmap(struct odyssey_cmap *cm, struct wsdisplay_cmap *rcm)
{
	u_int index = rcm->index, count = rcm->count;
	int rc;

	if (index >= 256 || count > 256 - index)
		return (EINVAL);

	if ((rc = copyout(&cm->cm_red[index], rcm->red, count)) != 0)
		return (rc);
	if ((rc = copyout(&cm->cm_green[index], rcm->green, count)) != 0)
		return (rc);
	if ((rc = copyout(&cm->cm_blue[index], rcm->blue, count)) != 0)
		return (rc);

	return (0);
}

int
odyssey_putcmap(struct odyssey_cmap *cm, struct wsdisplay_cmap *rcm)
{
	u_int index = rcm->index, count = rcm->count;
	int rc;

	if (index >= 256 || count > 256 - index)
		return (EINVAL);

	if ((rc = copyin(rcm->red, &cm->cm_red[index], count)) != 0)
		return (rc);
	if ((rc = copyin(rcm->green, &cm->cm_green[index], count)) != 0)
		return (rc);
	if ((rc = copyin(rcm->blue, &cm->cm_blue[index], count)) != 0)
		return (rc);

	return (0);
}

paddr_t
odyssey_mmap(void *v, off_t offset, int protection)
{
	return (-1);
}

int
odyssey_alloc_screen(void *v, const struct wsscreen_descr *type,
    void **cookiep, int *curxp, int *curyp, long *attrp)
{
	struct odyssey_screen *screen = (struct odyssey_screen *)v;
	struct odyssey_softc *sc = (struct odyssey_softc *)screen->sc;

	/* We do not allow multiple consoles at the moment. */
	if (sc->screens > 0)
		return (ENOMEM);

	sc->screens++;

	/* Return rasops_info via cookie. */
	*cookiep = &screen->ri;

	/* Move cursor to top left of screen. */
	*curxp = 0;
	*curyp = 0;

	/* Correct screen attributes. */
	screen->ri.ri_ops.alloc_attr(&screen->ri, 0, 0, 0, attrp);
	screen->attr = *attrp;

	return (0);
}

void
odyssey_free_screen(void *v, void *cookie)
{
	/* We do not allow multiple consoles at the moment. */
}

int
odyssey_show_screen(void *v, void *cookie, int waitok,
    void (*cb)(void *, int, int), void *cbarg)
{
	/* We do not allow multiple consoles at the moment. */
	return (0);
}

int
odyssey_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
	struct odyssey_screen *screen = (struct odyssey_screen *)v;

	return rasops_load_font(&screen->ri, emulcookie, font);
}

int
odyssey_list_font(void *v, struct wsdisplay_font *font)
{
	struct odyssey_screen *screen = (struct odyssey_screen *)v;

	return rasops_list_font(&screen->ri, font);
}

/*
 * Hardware accelerated functions.
 */

void
odyssey_rop(struct odyssey_softc *sc, int x, int y, int w, int h, int op, int c)
{
	/* Setup raster operation. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00100000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_LOGIC_OP);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, op);
	odyssey_cmd_flush(sc, 1);

	odyssey_fillrect(sc, x, y, w, h, c);

	/* Return to copy mode. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010404);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00100000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_LOGIC_OP);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
	    OPENGL_LOGIC_OP_COPY);
	odyssey_cmd_flush(sc, 1);
}

void
odyssey_copyrect(struct odyssey_softc *sc, int sx, int sy, int dx, int dy,
    int w, int h)
{
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010658);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00120000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002031);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, sx | (sy << 16));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x80502050);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, w | (h << 16));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x82223042);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, dx | (dy << 16));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x3222204b);

	odyssey_cmd_flush(sc, 1);
}

void
odyssey_fillrect(struct odyssey_softc *sc, int x, int y, int w, int h, u_int c)
{
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_BEGIN);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_QUADS);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_COLOR_3UB);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, c & 0xff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, (c >> 8) & 0xff);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, (c >> 16) & 0xff);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x + w);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x + w);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y + h);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, x);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, y + h);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_END);

	odyssey_cmd_flush(sc, 1);
}

int
odyssey_do_cursor(struct rasops_info *ri)
{
	struct odyssey_softc *sc = ri->ri_hw;
	struct odyssey_screen *screen = sc->curscr;
	int y, x, w, h, fg, bg;

	w = ri->ri_font->fontwidth;
	h = ri->ri_font->fontheight;
	x = ri->ri_xorigin + ri->ri_ccol * w;
	y = ri->ri_yorigin + ri->ri_crow * h;

	ri->ri_ops.unpack_attr(ri, screen->attr, &fg, &bg, NULL);

	odyssey_rop(sc, x, y, w, h, OPENGL_LOGIC_OP_XOR, ri->ri_devcmap[fg]);
	odyssey_cmd_flush(sc, 0);

	return 0;
}

int
odyssey_putchar(void *cookie, int row, int col, u_int uc, long attr)
{
	struct rasops_info *ri = cookie;
	struct odyssey_softc *sc = ri->ri_hw;
	struct wsdisplay_font *font = ri->ri_font;
	int bg, fg, ul, i, j, ci, l;
	uint x, y, w, h;
	u_int8_t *fontbitmap;
	u_int chunk;

	w = ri->ri_font->fontwidth;
	h = ri->ri_font->fontheight;
	x = ri->ri_xorigin + col * w;
	y = ri->ri_yorigin + row * h;

	fontbitmap = (u_int8_t *)(font->data + (uc - font->firstchar) *
	    ri->ri_fontscale);
	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);

	/* Handle spaces with a single fillrect. */
	if (uc == ' ') {
		odyssey_fillrect(sc, x, y, w, h, ri->ri_devcmap[bg]);
		odyssey_cmd_flush(sc, 0);
		return 0;
	}

	odyssey_fillrect(sc, x, y, w, h, 0xff0000);

	/* Setup pixel painting. */
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010405);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002400);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_COLOR_3UB);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011453);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000002);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	odyssey_cmd_flush(sc, 0);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x2900812f);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_BEGIN);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0000000a);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0xcf80a92f);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, ieee754_sp(x));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, ieee754_sp(y));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
	    ieee754_sp(x + font->fontwidth));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
	    ieee754_sp(y + font->fontheight));
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_VERTEX_2I);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00004570);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x0f00104c);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000071);

	for (i = font->fontheight; i != 0; i--) {

		/* Get bitmap for current line. */
		if (font->fontwidth <= 8)
			chunk = *fontbitmap;
		else
			chunk = *(u_int16_t *)fontbitmap;
		fontbitmap += font->stride;

		/* Handle underline. */
		if (ul && i == 1)
			chunk = 0xffff;

		/* Draw character. */
		bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
		    0x00004570);
		bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
		    0x0fd1104c);
		bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO,
		    0x00000071);

		w = font->fontwidth;
		l = 0;

		for (j = 0; j < font->fontwidth; j++) {

			if (l == 0) {

				l = (w > 14 ? 14 : w);
				w -= 14;

				/* Number of pixels. */
				bus_space_write_4(sc->iot, sc->ioh,
				    ODYSSEY_CMD_FIFO, (0x00014011 |
				    (l << 10)));

			}

			if (font->fontwidth > 8)
				ci = (chunk & (1 << (16 - j)) ? fg : bg);
			else
				ci = (chunk & (1 << (8 - j)) ? fg : bg);

			bus_space_write_4(sc->iot, sc->ioh,
			    ODYSSEY_CMD_FIFO, ri->ri_devcmap[ci]);

			l--;
		}
	}

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, OPENGL_END);
	odyssey_cmd_flush(sc, 1);

	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x290080d6);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00011453);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00000000);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00010405);
	bus_space_write_4(sc->iot, sc->ioh, ODYSSEY_CMD_FIFO, 0x00002000);
	odyssey_cmd_flush(sc, 0);

	return 0;
}

int
odyssey_copycols(void *cookie, int row, int src, int dst, int num)
{
	struct rasops_info *ri = cookie;
	struct odyssey_softc *sc = ri->ri_hw;
	int i;

	if (src < dst) {

		/* We cannot control copy direction, so copy col by col. */
		for (i = num - 1; i >= 0; i--)
			odyssey_copyrect(sc,
			    ri->ri_xorigin + (src + i) * ri->ri_font->fontwidth,
			    ri->ri_yorigin + row * ri->ri_font->fontheight,
			    ri->ri_xorigin + (dst + i) * ri->ri_font->fontwidth,
			    ri->ri_yorigin + row * ri->ri_font->fontheight,
			    ri->ri_font->fontwidth, ri->ri_font->fontheight);

	} else {

		odyssey_copyrect(sc,
		    ri->ri_xorigin + src * ri->ri_font->fontwidth,
		    ri->ri_yorigin + row * ri->ri_font->fontheight,
		    ri->ri_xorigin + dst * ri->ri_font->fontwidth,
		    ri->ri_yorigin + row * ri->ri_font->fontheight,
		    num * ri->ri_font->fontwidth, ri->ri_font->fontheight);

	}

	odyssey_cmd_flush(sc, 0);

	return 0;
}

int
odyssey_erasecols(void *cookie, int row, int col, int num, long attr)
{
	struct rasops_info *ri = cookie;
	struct odyssey_softc *sc = ri->ri_hw;
	int bg, fg;

	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);

	row *= ri->ri_font->fontheight;
	col *= ri->ri_font->fontwidth;
	num *= ri->ri_font->fontwidth;

	odyssey_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
	odyssey_cmd_flush(sc, 0);

	return 0;
}

int
odyssey_copyrows(void *cookie, int src, int dst, int num)
{
	struct rasops_info *ri = cookie;
	struct odyssey_softc *sc = ri->ri_hw;
	int i;

	if (src < dst) {

		/* We cannot control copy direction, so copy row by row. */
		for (i = num - 1; i >= 0; i--)
			odyssey_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin +
			    (src + i) * ri->ri_font->fontheight,
			    ri->ri_xorigin, ri->ri_yorigin +
			    (dst + i) * ri->ri_font->fontheight,
			    ri->ri_emuwidth, ri->ri_font->fontheight);

	} else {

		odyssey_copyrect(sc, ri->ri_xorigin,
		    ri->ri_yorigin + src * ri->ri_font->fontheight,
		    ri->ri_xorigin,
		    ri->ri_yorigin + dst * ri->ri_font->fontheight,
		    ri->ri_emuwidth, num * ri->ri_font->fontheight);

	}

	odyssey_cmd_flush(sc, 0);

	return 0;
}

int
odyssey_eraserows(void *cookie, int row, int num, long attr)
{
	struct rasops_info *ri = cookie;
	struct odyssey_softc *sc = ri->ri_hw;
	int x, y, w, bg, fg;

	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);

	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
		num = ri->ri_height;
		x = y = 0;
		w = ri->ri_width;
	} else {
		num *= ri->ri_font->fontheight;
		x = ri->ri_xorigin;
		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
		w = ri->ri_emuwidth;
	}

	odyssey_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
	odyssey_cmd_flush(sc, 0);

	return 0;
}

u_int32_t
ieee754_sp(uint v)
{
	u_int8_t exp = 0;
	int i = 12;	/* 0 <= v < 2048 */

	/*
	 * Convert a small integer to IEEE754 single precision floating point:
	 *
	 * 	Sign - 1 bit
	 * 	Exponent - 8 bits (with 2^(8-1)-1 = 127 bias)
	 * 	Fraction - 23 bits
	 */

	/* Determine shift for fraction. */
	while (i && (v & (1 << --i)) == 0);

	if (v != 0)
		exp = 127 + i;

	return (exp << 23) | ((v << (23 - i)) & 0x7fffff);
}

/*
 * Console support.
 */

int
odyssey_cnprobe()
{
	u_int32_t wid, vendor, product;

	/* Probe for Odyssey graphics card. */
	if (xbow_widget_id(console_output.nasid, console_output.widget,
	    &wid) != 0)
		return 0;

	vendor = WIDGET_ID_VENDOR(wid);
	product = WIDGET_ID_PRODUCT(wid);

	if (vendor != XBOW_VENDOR_SGI2 || product != XBOW_PRODUCT_SGI2_ODYSSEY)
		return 0;

	if (strncmp(bios_graphics, "alive", 5) != 0)
		return 0;

	return 1;
}

int
odyssey_cnattach()
{
	struct odyssey_softc *sc;
	struct odyssey_screen *screen;
	int rc;

	sc = &odyssey_cons_sc;
	screen = &odyssey_consdata;
	sc->curscr = screen;
	sc->curscr->sc = (void *)sc;

	/* Build bus space accessor. */
	xbow_build_bus_space(&sc->iot_store, console_output.nasid,
	    console_output.widget);
	sc->iot = &sc->iot_store;

	/* Setup bus space mappings. */
	rc = bus_space_map(sc->iot, ODYSSEY_REG_OFFSET, ODYSSEY_REG_SIZE,
	    BUS_SPACE_MAP_LINEAR, &sc->ioh);
	if (rc != 0)
		return rc;

	/* Setup hardware and clear screen. */
	odyssey_setup(sc);
	odyssey_fillrect(sc, 0, 0, 1280, 1024, 0x000000);
	odyssey_cmd_flush(sc, 0);

	/* Set screen defaults. */
	screen->width = 1280;
	screen->height = 1024;
	screen->depth = 32;
	screen->linebytes = screen->width * screen->depth / 8;

	odyssey_init_screen(screen);

	/*
	 * Attach wsdisplay.
	 */
	screen->ri.ri_ops.alloc_attr(&screen->ri, 0, 0, 0, &screen->attr);
	wsdisplay_cnattach(&odyssey_stdscreen, &screen->ri, 0, 0, screen->attr);

	return 0;
}

int
odyssey_is_console(struct xbow_attach_args *xaa)
{
	return xaa->xaa_nasid == console_output.nasid &&
	    xaa->xaa_widget == console_output.widget;
}


code:
/*	$OpenBSD: odysseyreg.h,v 1.2 2012/04/16 22:17:16 miod Exp $ */
/*
 * Copyright (c) 2009, 2010 Joel Sing <jsing@openbsd.org>
 *
 * 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.
 */

/*
 * Register details for the SGI VPro (aka Odyssey) Graphics Card.
 */

#define	ODYSSEY_REG_OFFSET		0x00000000
#define	ODYSSEY_REG_SIZE		0x00410000

#define ODYSSEY_STATUS			0x00001064
#define  ODYSSEY_STATUS_CMD_FIFO_HIGH	0x00008000
#define  ODYSSEY_STATUS_CMD_FIFO_LOW	0x00020000
#define ODYSSEY_DBE_STATUS		0x0000106c

#define ODYSSEY_CMD_FIFO		0x00110000
#define ODYSSEY_DATA_FIFO		0x00400000

/*
 * OpenGL Commands.
 */

#define OPENGL_BEGIN			0x00014400
#define OPENGL_END			0x00014001
#define OPENGL_LOGIC_OP			0x00010422
#define OPENGL_VERTEX_2I		0x8080c800
#define OPENGL_COLOR_3UB		0xc580cc08

#define OPENGL_QUADS			0x00000007

license: unknown


code:
/*	$OpenBSD: odysseyvar.h,v 1.2 2010/04/06 19:12:34 miod Exp $	*/
/*
 * Copyright (c) 2010 Joel Sing <jsing@openbsd.org>
 *
 * 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.
 */

int	odyssey_cnprobe(void);
int	odyssey_cnattach(void);


code:
/*	$OpenBSD: widget.h,v 1.2 2010/04/06 19:02:57 miod Exp $	*/

/*
 * Copyright (c) 2008 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.
 */

#ifndef	_WIDGET_H_
#define	_WIDGET_H_

/*
 * Common Widget Registers.  Every widget provides them.
 *
 * Registers are 32 or 64 bit wide (depending on the particular widget
 * or register) on 64 bit boundaries.
 * The widget_{read,write}_[48] functions below hide the addressing
 * games required to perform 32 bit accesses.
 */

#define	WIDGET_ID			0x0000
#define	WIDGET_ID_REV_MASK			0xf0000000
#define	WIDGET_ID_REV_SHIFT			28
#define	WIDGET_ID_REV(wid) \
	(((wid) & WIDGET_ID_REV_MASK) >> WIDGET_ID_REV_SHIFT)
#define	WIDGET_ID_PRODUCT_MASK			0x0ffff000
#define	WIDGET_ID_PRODUCT_SHIFT			12
#define	WIDGET_ID_PRODUCT(wid) \
	(((wid) & WIDGET_ID_PRODUCT_MASK) >> WIDGET_ID_PRODUCT_SHIFT)
#define	WIDGET_ID_VENDOR_MASK			0x00000ffe
#define	WIDGET_ID_VENDOR_SHIFT			1
#define	WIDGET_ID_VENDOR(wid) \
	(((wid) & WIDGET_ID_VENDOR_MASK) >> WIDGET_ID_VENDOR_SHIFT)
#define	WIDGET_STATUS			0x0008
#define	WIDGET_ERR_ADDR_UPPER		0x0010
#define	WIDGET_ERR_ADDR_LOWER		0x0018
#define	WIDGET_CONTROL			0x0020
#define	WIDGET_REQ_TIMEOUT		0x0028
#define	WIDGET_INTDEST_ADDR_UPPER	0x0030
#define	WIDGET_INTDEST_ADDR_LOWER	0x0038
#define	WIDGET_ERR_CMD_WORD		0x0040
#define	WIDGET_LLP_CFG			0x0048
#define	WIDGET_TFLUSH			0x0050

/*
 * Crossbow Specific Registers.
 */

#define	XBOW_WID_ARB_RELOAD		0x0058
#define	XBOW_PERFCNTR_A			0x0060
#define	XBOW_PERFCNTR_B			0x0068
#define	XBOW_NIC			0x0070
#define	XBOW_WIDGET_LINK(w)		(0x0100 + ((w) & 7) * 0x0040)

/*
 * Crossbow Per-widget ``Link'' Register Set.
 */
#define	WIDGET_LINK_IBF			0x0000
#define	WIDGET_LINK_CONTROL		0x0008
#define	WIDGET_CONTROL_ALIVE			0x80000000
#define	WIDGET_LINK_STATUS		0x0010
#define	WIDGET_STATUS_ALIVE			0x80000000
#define	WIDGET_LINK_ARB_UPPER		0x0018
#define	WIDGET_LINK_ARB_LOWER		0x0020
#define	WIDGET_LINK_STATUS_CLEAR	0x0028
#define	WIDGET_LINK_RESET		0x0030
#define	WIDGET_LINK_AUX_STATUS		0x0038

#endif	/* _WIDGET_H_ */


code:
/*	$OpenBSD: xbow.c,v 1.35 2014/09/30 06:51:58 jmatthew Exp $	*/

/*
 * Copyright (c) 2008, 2009, 2011 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) 2004 Opsycon AB  (www.opsycon.se)
 *
 * 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.
 *
 */

/*
 *  XBOW is the mux between two nodes and XIO.
 *
 *  A Crossbow (XBOW) connects two nodeboards via their respective
 *  HUB to up to six different I/O controllers in XIO slots. In a
 *  multiprocessor system all processors have access to the XIO
 *  slots but may need to pass traffic via the routers.
 *
 *  To each XIO port on the XBOW a XIO interface is attached. Such
 *  interfaces can be for example PCI bridges which then add another
 *  level to the hierarchy.
 */

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

#include <mips64/archtype.h>

#include <machine/autoconf.h>
#include <machine/intr.h>
#include <machine/mnode.h>

#include <sgi/xbow/hub.h>
#include <sgi/xbow/widget.h>
#include <sgi/xbow/xbow.h>

#include <sgi/xbow/xbowdevs.h>
#include <sgi/xbow/xbowdevs_data.h>

int	xbowmatch(struct device *, void *, void *);
void	xbowattach(struct device *, struct device *, void *);
int	xbowprint(void *, const char *);
int	xbowsubmatch(struct device *, void *, void *);
int	xbow_attach_widget(struct device *, int16_t, int,
	    int (*)(struct device *, void *, void *), cfprint_t);

int	xbow_kl_search_brd(lboard_t *, void *);
int	xbow_kl_search_mplane(klinfo_t *, void *);

uint32_t xbow_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
uint64_t xbow_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	xbow_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint32_t);
void	xbow_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint64_t);
void	xbow_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint8_t *, bus_size_t);
void	xbow_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    const uint8_t *, bus_size_t);
void	xbow_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint8_t *, bus_size_t);
void	xbow_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    const uint8_t *, bus_size_t);

void	xbow_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
int	xbow_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    bus_size_t, bus_space_handle_t *);
void	*xbow_space_vaddr(bus_space_tag_t, bus_space_handle_t);
void	 xbow_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    bus_size_t, int);

const struct xbow_product *xbow_identify(uint32_t, uint32_t);

struct	xbow_softc {
	struct device	sc_dev;
	int16_t		sc_nasid;
};

const struct cfattach xbow_ca = {
	sizeof(struct xbow_softc), xbowmatch, xbowattach
};

struct cfdriver xbow_cd = {
	NULL, "xbow", DV_DULL
};

static const bus_space_t xbowbus_tag = {
	(bus_addr_t)0,		/* will be modified in widgets bus_space_t */
	NULL,
	xbow_read_1,
	xbow_write_1,
	xbow_read_2,
	xbow_write_2,
	xbow_read_4,
	xbow_write_4,
	xbow_read_8,
	xbow_write_8,
	xbow_read_raw_2,
	xbow_write_raw_2,
	xbow_read_raw_4,
	xbow_write_raw_4,
	xbow_read_raw_8,
	xbow_write_raw_8,
	xbow_space_map,
	xbow_space_unmap,
	xbow_space_region,
	xbow_space_vaddr,
	xbow_space_barrier
};

/*
 * Function pointers to hide widget discovery and mapping differences accross
 * systems.
 */
paddr_t	(*xbow_widget_base)(int16_t, u_int);
paddr_t	(*xbow_widget_map)(int16_t, u_int, bus_addr_t *, bus_size_t *);

int	(*xbow_widget_id)(int16_t, u_int, uint32_t *);

/*
 * Attachment glue.
 */

int
xbowmatch(struct device *parent, void *match, void *aux)
{
	struct mainbus_attach_args *maa = aux;

	if (strcmp(maa->maa_name, xbow_cd.cd_name) != 0)
		return (0);

	switch (sys_config.system_type) {
	case SGI_IP27:
	case SGI_IP35:
	case SGI_OCTANE:
		return (1);
	default:
		return (0);
	}
}

const struct xbow_product *
xbow_identify(uint32_t vendor, uint32_t product)
{
	const struct xbow_product *p;

	for (p = xbow_products; p->productname != NULL; p++)
		if (p->vendor == vendor && p->product == product)
			return p;

	return NULL;
}

int
xbowprint(void *aux, const char *pnp)
{
	struct xbow_attach_args *xaa = aux;
	const struct xbow_product *p;

	p = xbow_identify(xaa->xaa_vendor, xaa->xaa_product);

	if (pnp != NULL) {
		if (p != NULL)
			printf("\"%s\"", p->productname);
		else
			printf("vendor %x product %x",
			    xaa->xaa_vendor, xaa->xaa_product);
		printf(" revision %d at %s",
		    xaa->xaa_revision, pnp);
	}
	printf(" widget %d", xaa->xaa_widget);
	if (pnp == NULL) {
		if (p != NULL)
			printf(": %s", p->productname);
	}

	return (UNCONF);
}

int
xbowsubmatch(struct device *parent, void *vcf, void *aux)
{
	struct xbow_attach_args *xaa = aux;
	struct cfdata *cf = vcf;

	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != xaa->xaa_widget)
		return 0;
	if (cf->cf_loc[1] != -1 && cf->cf_loc[1] != xaa->xaa_vendor)
		return 0;
	if (cf->cf_loc[2] != -1 && cf->cf_loc[2] != xaa->xaa_product)
		return 0;

	return (*cf->cf_attach->ca_match)(parent, vcf, aux);
}

/*
 * Widget probe order for various components
 */

#ifdef TGT_OCTANE
/* Octane: probe Heart first, then onboard devices, then other slots */
const uint8_t xbow_probe_octane[] =
	{ 0x08, 0x0f, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0 };
#endif
#ifdef TGT_ORIGIN
/* Origin 200: probe onboard devices, and there is nothing more */
const uint8_t xbow_probe_singlebridge[] =
	{ 0x08, 0 };
/* Base I/O board: probe onboard devices, then other slots in ascending order */
const uint8_t xbow_probe_baseio[] =
	{ 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0 };
/* I-Brick: probe PCI buses first (starting with the onboard devices) */
const uint8_t xbow_probe_ibrick[] =
	{ 0x0f, 0x0e, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0 };
/* P-Brick: all widgets are PCI buses, probe in recommended order */
const uint8_t xbow_probe_pbrick[] =
	{ 0x09, 0x08, 0x0f, 0x0e, 0x0c, 0x0d, 0x0a, 0x0b, 0 };
/* X-Brick: all widgets are XIO devices, probe in recommended order */
const uint8_t xbow_probe_xbrick[] =
	{ 0x08, 0x09, 0x0c, 0x0d, 0x0a, 0x0b, 0x0e, 0x0f, 0 };
#endif

/*
 * Structures used to carry information between KL and attachment code.
 */

struct xbow_config {
	int	valid;
	int	widgets[WIDGET_MAX + 1 - WIDGET_MIN];
};

struct xbow_kl_config {
	const uint8_t *probe_order;
	struct xbow_config *cfg;
};

void
xbowattach(struct device *parent, struct device *self, void *aux)
{
	struct xbow_softc *sc = (struct xbow_softc *)self;
	struct mainbus_attach_args *maa = aux;
	int16_t nasid = maa->maa_nasid;
	uint32_t wid, vendor, product;
	const struct xbow_product *p;
#ifdef TGT_ORIGIN
	struct xbow_config cfg;
#endif
	struct xbow_kl_config klcfg;
	uint widget;

	sc->sc_nasid = nasid;

	/*
	 * This assumes widget 0 is the XBow itself (or an XXBow).
	 * If it isn't - feel free to haunt my bedroom at night.
	 */
	if (xbow_widget_id(nasid, 0, &wid) != 0)
		panic("no xbow");
	vendor = WIDGET_ID_VENDOR(wid);
	product = WIDGET_ID_PRODUCT(wid);
	p = xbow_identify(vendor, product);
	if (p == NULL)
		printf(": unknown xbow (vendor %x product %x)",
		    vendor, product);
	else
		printf(": %s", p->productname);
	printf(" revision %d\n", WIDGET_ID_REV(wid));

	switch (sys_config.system_type) {
	default:
#ifdef TGT_ORIGIN
		memset(&cfg, 0, sizeof cfg);
		klcfg.cfg = &cfg;

		/*
		 * If widget 0 reports itself as a bridge, this is not a
		 * complete XBow, but only a limited topology. This is
		 * found on at least the Origin 200.
		 */
		if (vendor == XBOW_VENDOR_SGI4 &&
		    product == XBOW_PRODUCT_SGI4_BRIDGE) {
			klcfg.probe_order = xbow_probe_singlebridge;
		} else {
			/*
			 * Get crossbow information from the KL configuration.
			 */
			klcfg.probe_order = NULL;
			kl_scan_node(nasid, KLBRD_ANY, xbow_kl_search_brd,
			    &klcfg);
			if (klcfg.probe_order == NULL)
				klcfg.probe_order = xbow_probe_baseio;

			/* should not happen, but I can't help being paranoid */
			if (cfg.valid == 0) {
				printf("%s: no hub\n", self->dv_xname);
				return;
			}
		}
		break;
#endif
#ifdef TGT_OCTANE
	case SGI_OCTANE:
		klcfg.probe_order = xbow_probe_octane;
		break;
#endif
	}

	for (; *klcfg.probe_order != 0; klcfg.probe_order++) {
		widget = *klcfg.probe_order;
#ifdef TGT_ORIGIN
		if (cfg.valid != 0 &&
		    !ISSET(cfg.widgets[widget - WIDGET_MIN], XBOW_PORT_ENABLE))
			continue;
#endif
		(void)xbow_attach_widget(self, nasid, widget, xbowsubmatch,
		    xbowprint);
	}
}

int
xbow_attach_widget(struct device *self, int16_t nasid, int widget,
    int (*sm)(struct device *, void *, void *), cfprint_t print)
{
	struct xbow_attach_args xaa;
	uint32_t wid;
	struct mips_bus_space bs;
	int rc;

	if ((rc = xbow_widget_id(nasid, widget, &wid)) != 0)
		return rc;

	/*
	 * Build a bus_space_t suitable for this widget.
	 */
	xbow_build_bus_space(&bs, nasid, widget);

	xaa.xaa_nasid = nasid;
	xaa.xaa_widget = widget;
	xaa.xaa_vendor = WIDGET_ID_VENDOR(wid);
	xaa.xaa_product = WIDGET_ID_PRODUCT(wid);
	xaa.xaa_revision = WIDGET_ID_REV(wid);
	xaa.xaa_iot = &bs;

	if (config_found_sm(self, &xaa, print, sm) == NULL)
		return ENOENT;

	return 0;
}

#ifdef TGT_ORIGIN

/*
 * These two functions try to figure out the configuration of the XBow
 * on this node.
 *
 * We are looking for two pieces of information:
 * - the Hub widget, to which memory is attached and interrupts are routed.
 * - what kind of Brick we are.
 *
 * The first information can be obtained easily by looking for a MPLANE type
 * board. However there is no easy way to figure the second part, except for
 * checking what kind of boards are reported.
 *
 * A BaseIO board will report itself once, as a single widget. Bricks, on the
 * other hand, appear for each of the widgets they provide.
 */

int
xbow_kl_search_brd(lboard_t *brd, void *arg)
{
	struct xbow_kl_config *cfg = arg;

	switch (brd->brd_type & IP27_BC_MASK) {
	case IP27_BC_MPLANE:
		if (cfg->cfg->valid == 0)
			kl_scan_board(brd, KLSTRUCT_XBOW, xbow_kl_search_mplane,
			    cfg->cfg);
		break;
	case IP27_BC_IO:
		if (cfg->probe_order == NULL)
			cfg->probe_order = xbow_probe_baseio;
		break;
	case IP27_BC_BRICK:
		if (cfg->probe_order == NULL)
			switch (brd->brd_type) {
			case IP27_BRD_IBRICK:
			case IP27_BRD_IXBRICK:
				cfg->probe_order = xbow_probe_ibrick;
				break;
			case IP27_BRD_PBRICK:
			case IP27_BRD_PXBRICK:
				cfg->probe_order = xbow_probe_pbrick;
				break;
			case IP27_BRD_XBRICK:
				cfg->probe_order = xbow_probe_xbrick;
				break;
			default:
				/* other brick */
				break;
			}
		break;
	}

	if (cfg->cfg->valid != 0 && cfg->probe_order != NULL)
		return 1;	/* stop enumeration */

	return 0;
}

int
xbow_kl_search_mplane(klinfo_t *c, void *arg)
{
	klxbow_t *xbow = (klxbow_t *)c;
	struct xbow_config *cfg = arg;
	uint w;

	cfg->valid = 1;
	for (w = WIDGET_MIN; w <= WIDGET_MAX; w++)
		cfg->widgets[w - WIDGET_MIN] =
		    xbow->xbow_port_info[w - WIDGET_MIN].port_flag;

	return 1;
}

#endif

/*
 * Bus access primitives.
 */

void
xbow_build_bus_space(struct mips_bus_space *bs, int nasid, int widget)
{
	bcopy(&xbowbus_tag, bs, sizeof (*bs));
	bs->bus_base = (*xbow_widget_base)(nasid, widget);
}

uint8_t
xbow_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint8_t *)(h + o);
}

uint16_t
xbow_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint16_t *)(h + o);
}

uint32_t
xbow_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint32_t *)(h + o);
}

uint64_t
xbow_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
{
	return *(volatile uint64_t *)(h + o);
}

void
xbow_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v)
{
	*(volatile uint8_t *)(h + o) = v;
}

void
xbow_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v)
{
	*(volatile uint16_t *)(h + o) = v;
}

void
xbow_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v)
{
	*(volatile uint32_t *)(h + o) = v;
}

void
xbow_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint64_t v)
{
	*(volatile uint64_t *)(h + o) = v;
}

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

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

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

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

void
xbow_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    uint8_t *buf, bus_size_t len)
{
	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
	len >>= 3;
	while (len-- != 0) {
		*(uint64_t *)buf = *addr;
		buf += 8;
	}
}

void
xbow_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o,
    const uint8_t *buf, bus_size_t len)
{
	volatile uint64_t *addr = (volatile uint64_t *)(h + o);
	len >>= 3;
	while (len-- != 0) {
		*addr = *(uint64_t *)buf;
		buf += 8;
	}
}

int
xbow_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
    int flags, bus_space_handle_t *bshp)
{
	bus_addr_t bpa;

	bpa = t->bus_base + offs;

#ifdef DIAGNOSTIC
	/* check that this does not overflow the window */
	if (((bpa + size - 1) >> 24) != (t->bus_base >> 24))
		return (EINVAL);
#endif

	*bshp = bpa;
	return 0;
}

void
xbow_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
{
}

int
xbow_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
    bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
{
#ifdef DIAGNOSTIC
	bus_addr_t bpa;

	bpa = (bus_addr_t)bsh - t->bus_base;
	/* check that this does not overflow the window */
	if (((bpa + offset) >> 24) != (t->bus_base >> 24))
		return (EINVAL);
#endif

	*nbshp = bsh + offset;
	return 0;
}

void *
xbow_space_vaddr(bus_space_tag_t t, bus_space_handle_t h)
{
	return (void *)h;
}

void
xbow_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs,
    bus_size_t len, int flags)
{
	mips_sync();
}

/*
 * Interrupt handling code.
 *
 * Interrupt handling should be done at the Heart/Hub driver level, we only
 * act as a proxy here.
 *
 * Note that, for the time being, interrupt handling is implicitly done at
 * the master nasid; other nodes do not handle interrupts.
 */

uint64_t xbow_intr_address;

int	(*xbow_intr_widget_intr_register)(int, int, int *) = NULL;
int	(*xbow_intr_widget_intr_establish)(int (*)(void *), void *, int, int,
	    const char *, struct intrhand *) = NULL;
void	(*xbow_intr_widget_intr_disestablish)(int) = NULL;
void	(*xbow_intr_widget_intr_set)(int) = NULL;
void	(*xbow_intr_widget_intr_clear)(int) = NULL;

int
xbow_intr_register(int widget, int level, int *intrbit)
{
	if (xbow_intr_widget_intr_register == NULL)
		return EINVAL;

	return (*xbow_intr_widget_intr_register)(widget, level, intrbit);
}

int
xbow_intr_establish(int (*func)(void *), void *arg, int intrbit, int level,
    const char *name, struct intrhand *ihstore)
{
	if (xbow_intr_widget_intr_establish == NULL)
		return EINVAL;

	return (*xbow_intr_widget_intr_establish)(func, arg, intrbit, level,
	    name, ihstore);
}

void
xbow_intr_disestablish(int intrbit)
{
	if (xbow_intr_widget_intr_disestablish == NULL)
		return;

	(*xbow_intr_widget_intr_disestablish)(intrbit);
}

void
xbow_intr_clear(int intrbit)
{
	if (xbow_intr_widget_intr_clear == NULL)
		return;

	(*xbow_intr_widget_intr_clear)(intrbit);
}

void
xbow_intr_set(int intrbit)
{
	if (xbow_intr_widget_intr_set == NULL)
		return;

	(*xbow_intr_widget_intr_set)(intrbit);
}

/*
 * Widget mapping code.
 */

paddr_t
xbow_widget_map_space(struct device *dev, u_int widget, bus_addr_t *offs,
    bus_size_t *len)
{
	struct xbow_softc *sc = (struct xbow_softc *)dev;

	if (xbow_widget_map == NULL)
		return 0UL;

	return (*xbow_widget_map)(sc->sc_nasid, widget, offs, len);
}


code:
/*	$OpenBSD: xbow.h,v 1.12 2011/04/17 17:44:24 miod Exp $	*/

/*
 * Copyright (c) 2008 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.
 */

#ifndef	_XBOW_H_
#define	_XBOW_H_

/*
 * Devices connected to the XBow are called ``widgets'' and are
 * identified by a common widget memory area at the beginning of their
 * memory space.
 *
 * Each widget has its own memory space.  The lowest 16MB are always
 * accessible as a so-called ``short window''.  Other `views' of the
 * widget are possible, depending on the system (the whole widget
 * address space is always visible on Octane, while Origin family
 * systems can only map a few ``large windows'', which are a scarce
 * resource).
 *
 * Apart from the crossbow itself being widget #0, the widgets are divided
 * in two groups: widgets #8 to #b are the ``upper'' widgets, while widgets
 * #c to #f are the ``lower'' widgets.
 *
 * Widgets are uniquely identified with their widget number on the XBow
 * bus. However, the way they are mapped and accessed will depend on the
 * processor (well, the processor board node) requesting access. Hence the
 * two parameters needed to map a widget.
 */

extern	paddr_t (*xbow_widget_base)(int16_t, u_int);
extern	paddr_t	(*xbow_widget_map)(int16_t, u_int, bus_addr_t *, bus_size_t *);

extern	int	(*xbow_widget_id)(int16_t, u_int, uint32_t *);

extern	int	(*xbow_intr_widget_intr_register)(int, int, int *);
extern	int	(*xbow_intr_widget_intr_establish)(int (*)(void *), void *,
		    int, int, const char *, struct intrhand *);
extern	void	(*xbow_intr_widget_intr_disestablish)(int);

extern	void	(*xbow_intr_widget_intr_set)(int);
extern	void	(*xbow_intr_widget_intr_clear)(int);

/*
 * Valid widget values
 */

#define	WIDGET_MIN			8
#define	WIDGET_MAX			15

/* interrupt register address on the master hub */
extern	uint64_t xbow_intr_address;

struct xbow_attach_args {
	int16_t		xaa_nasid;
	int		xaa_widget;

	uint32_t	xaa_vendor;
	uint32_t	xaa_product;
	uint32_t	xaa_revision;

	bus_space_tag_t xaa_iot;
	/*
	 * WARNING! xaa_iot points to memory allocated on the stack,
	 * drivers need to make a copy of it.
	 */
};

void	xbow_build_bus_space(struct mips_bus_space *, int, int);
int	xbow_intr_register(int, int, int *);
int	xbow_intr_establish(int (*)(void *), void *, int, int, const char *,
	    struct intrhand *);
void	xbow_intr_disestablish(int);
void	xbow_intr_clear(int);
void	xbow_intr_set(int);

paddr_t	xbow_widget_map_space(struct device *, u_int,
	    bus_addr_t *, bus_size_t *);

int	xbow_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
	    bus_space_handle_t *);
uint8_t xbow_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
uint16_t xbow_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void	xbow_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    uint8_t *, bus_size_t);
void	xbow_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t);
void	xbow_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t,
	    uint16_t);
void	xbow_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t,
	    const uint8_t *, bus_size_t);

/*
 * Widget register access routines hiding addressing games depending upon
 * the access width.
 */
static __inline__ uint32_t
widget_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a)
{
	return bus_space_read_4(t, h, a | 4);
}
static __inline__ uint64_t
widget_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a)
{
	return bus_space_read_8(t, h, a);
}
static __inline__ void
widget_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a,
    uint32_t v)
{
	bus_space_write_4(t, h, a | 4, v);
}
static __inline__ void
widget_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a,
    uint64_t v)
{
	bus_space_write_8(t, h, a, v);
}

#endif	/* _XBOW_H_ */


code:
$OpenBSD: xbowdevs,v 1.6 2009/10/15 23:42:43 miod Exp $
/*
 * Copyright (c) 2008 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.
 */

vendor	SGI		0x0000
vendor	SGI2		0x0023
vendor	SGI3		0x0024
vendor	SGI4		0x0036
vendor	SGI5		0x02aa

/*
 * List of known products.  Grouped by type.
 */

/*
 * Crossbows
 */

product	SGI	XBOW		0x0000	XBow
product	SGI	XXBOW		0xd000	XXBow
product	SGI	PXBOW		0xd100	PXBow

/*
 * Frame buffers and graphics related devices
 */

product	SGI5	IMPACT		0xc003	ImpactSR
product	SGI2	ODYSSEY		0xc013	Odyssey
product	SGI5	KONA		0xc102	Kona
product	SGI3	TPU		0xc202	TPU

/*
 * Non-XIO bus bridges
 */

product	SGI4	BRIDGE		0xc002	Bridge
product	SGI3	XBRIDGE		0xd002	XBridge
/*
 * PIC is really a single chip but with two widgets headers, and 4 PCI-X
 * slots per widget.
 * The second widget register set uses 0xd112 as the product id.
 */
product	SGI3	PIC		0xd102	PIC
/*
 * TIO apparently is a next-generation XIO framework; TIO:CP being a TIO
 * variant of PIC with two PCI-X buses, and TIO:CA an AGP bridge.
 * Unlike PIC, the two heads of TIO:CP would appear as two distinct TIO
 * widgets.
 * TIO widgets are supposedly only found on SN2 systems onwards (i.e.
 * ia64-based Altix systems), but in case there is a way to connect TIO
 * nodes to XIO nodes, better identify them properly.
 */
product	SGI3	TIOCP0		0xe000	TIO:CP
product	SGI3	TIOCP1		0xe010	TIO:CP
product	SGI3	TIOCA		0xe020	TIO:CA

/*
 * Octane HEART memory and interrupt controller
 */
product	SGI4	HEART		0xc001	Heart

/*
 * Miscellaneous widgets
 */

product	SGI4	HUB		0xc101	Hub
product	SGI4	BEDROCK		0xc110	Bedrock

path: sys/arch/sgi/xbow/xbowdevs


code:
/*
 * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
 *
 * generated from:
 *	OpenBSD: xbowdevs,v 1.6 2009/10/15 23:42:43 miod Exp
 */
/*
 * Copyright (c) 2008 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#define	XBOW_VENDOR_SGI	0x0000
#define	XBOW_VENDOR_SGI2	0x0023
#define	XBOW_VENDOR_SGI3	0x0024
#define	XBOW_VENDOR_SGI4	0x0036
#define	XBOW_VENDOR_SGI5	0x02aa

/*
 * List of known products.  Grouped by type.
 */

/*
 * Crossbows
 */

#define	XBOW_PRODUCT_SGI_XBOW	0x0000		/* XBow */
#define	XBOW_PRODUCT_SGI_XXBOW	0xd000		/* XXBow */
#define	XBOW_PRODUCT_SGI_PXBOW	0xd100		/* PXBow */

/*
 * Frame buffers and graphics related devices
 */

#define	XBOW_PRODUCT_SGI5_IMPACT	0xc003		/* ImpactSR */
#define	XBOW_PRODUCT_SGI2_ODYSSEY	0xc013		/* Odyssey */
#define	XBOW_PRODUCT_SGI5_KONA	0xc102		/* Kona */
#define	XBOW_PRODUCT_SGI3_TPU	0xc202		/* TPU */

/*
 * Non-XIO bus bridges
 */

#define	XBOW_PRODUCT_SGI4_BRIDGE	0xc002		/* Bridge */
#define	XBOW_PRODUCT_SGI3_XBRIDGE	0xd002		/* XBridge */
/*
 * PIC is really a single chip but with two widgets headers, and 4 PCI-X
 * slots per widget.
 * The second widget register set uses 0xd112 as the product id.
 */
#define	XBOW_PRODUCT_SGI3_PIC	0xd102		/* PIC */
/*
 * TIO apparently is a next-generation XIO framework; TIO:CP being a TIO
 * variant of PIC with two PCI-X buses, and TIO:CA an AGP bridge.
 * Unlike PIC, the two heads of TIO:CP would appear as two distinct TIO
 * widgets.
 * TIO widgets are supposedly only found on SN2 systems onwards (i.e.
 * ia64-based Altix systems), but in case there is a way to connect TIO
 * nodes to XIO nodes, better identify them properly.
 */
#define	XBOW_PRODUCT_SGI3_TIOCP0	0xe000		/* TIO:CP */
#define	XBOW_PRODUCT_SGI3_TIOCP1	0xe010		/* TIO:CP */
#define	XBOW_PRODUCT_SGI3_TIOCA	0xe020		/* TIO:CA */

/*
 * Octane HEART memory and interrupt controller
 */
#define	XBOW_PRODUCT_SGI4_HEART	0xc001		/* Heart */

/*
 * Miscellaneous widgets
 */

#define	XBOW_PRODUCT_SGI4_HUB	0xc101		/* Hub */
#define	XBOW_PRODUCT_SGI4_BEDROCK	0xc110		/* Bedrock */


code:
/*
 * THIS FILE AUTOMATICALLY GENERATED.  DO NOT EDIT.
 *
 * generated from:
 *	OpenBSD: xbowdevs,v 1.6 2009/10/15 23:42:43 miod Exp
 */

/*
 * Copyright (c) 2008 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.
 */

/* Descriptions of known devices. */
struct xbow_product {
	uint32_t vendor;
	uint32_t product;
	const char *productname;
};

static const struct xbow_product xbow_products[] = {
	{
	    XBOW_VENDOR_SGI, XBOW_PRODUCT_SGI_XBOW,
	    "XBow",
	},
	{
	    XBOW_VENDOR_SGI, XBOW_PRODUCT_SGI_XXBOW,
	    "XXBow",
	},
	{
	    XBOW_VENDOR_SGI, XBOW_PRODUCT_SGI_PXBOW,
	    "PXBow",
	},
	{
	    XBOW_VENDOR_SGI5, XBOW_PRODUCT_SGI5_IMPACT,
	    "ImpactSR",
	},
	{
	    XBOW_VENDOR_SGI2, XBOW_PRODUCT_SGI2_ODYSSEY,
	    "Odyssey",
	},
	{
	    XBOW_VENDOR_SGI5, XBOW_PRODUCT_SGI5_KONA,
	    "Kona",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_TPU,
	    "TPU",
	},
	{
	    XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_BRIDGE,
	    "Bridge",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_XBRIDGE,
	    "XBridge",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_PIC,
	    "PIC",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_TIOCP0,
	    "TIO:CP",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_TIOCP1,
	    "TIO:CP",
	},
	{
	    XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_TIOCA,
	    "TIO:CA",
	},
	{
	    XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_HEART,
	    "Heart",
	},
	{
	    XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_HUB,
	    "Hub",
	},
	{
	    XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_BEDROCK,
	    "Bedrock",
	},
	{ 0, 0, NULL, }
};