Subject: port-sparc/29860: Add wscons support to the SPARCbook's pnozz driver
To: None <port-sparc-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <macallan18@earthlink.net>
List: netbsd-bugs
Date: 04/02/2005 01:50:00
>Number:         29860
>Category:       port-sparc
>Synopsis:       Add wscons support to the SPARCbook's pnozz driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-sparc-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Apr 02 01:50:00 +0000 2005
>Originator:     Michael Lorenz
>Release:        -current
>Organization:
>Environment:
NetBSD morgoth 2.99.16 NetBSD 2.99.16 (MORGOTH) #112: Wed Mar  9 16:03:55 EST 2005  root@morgoth:/data/src/sys/arch/sparc/compile/MORGOTH sparc

>Description:
The patch below adds the following things to pnozz:
- wscons support
- virtual consoles
- colour
- full acceleration
Since the SPARCbook keyboard doesn't have a STOP key I also added an #ifdef to use the Alt key for console switching.

kernel config changes:
options         WSEMUL_VT100
options         WS_DEFAULT_FG=WSCOL_BLACK
options         WS_DEFAULT_BG=0x0f
options         WS_KERNEL_FG=WSCOL_GREEN
options         WS_KERNEL_BG=0x0f
options         WSDISPLAY_COMPAT_USL            # VT handling
options         WSDISPLAY_DEFAULTSCREENS=1

options         SPARCBOOK_CMD           # enable screen switching with lAlt-Fn
options         FONT_BOLD8x16           # a somewhat smaller font

# Tadpole 3GX/3GS (P9100 -- P Nine One Zero Zero -> pnozz)
pnozz0 at sbus? slot ? offset ?
wsdisplay*      at pnozz? console ?

... this requires wskbd attaching to kbd which currently only works with a rather grisly hack ( I'll supply it on demand, but it's really gruesome and there are people working on a real solution )

So far it works only in 8bit colour, supporting higher depths shouldn't be problematic though.

>How-To-Repeat:
Install NetBSD on a SPARCbook 3GX

Here's the dmesg output:

Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 2.99.16 (MORGOTH) #112: Wed Mar  9 16:03:55 EST 2005
        root@morgoth:/data/src/sys/arch/sparc/compile/MORGOTH
total memory = 65200 KB
avail memory = 61312 KB
bootpath: /iommu@0,10000000/sbus@0,10001000/espdma@4,8400000/esp@4,8800000/sd@3,
0
mainbus0 (root): Tadpole_S3GX: hostid 80ae2531
cpu0 at mainbus0: MB86904 @ 110 MHz, on-chip FPU
cpu0: 16K instruction (32 b/l), 8K data (16 b/l): cache enabled
obio0 at mainbus0
clock0 at obio0 slot 0 offset 0x202000: mk48t08
timer0 at obio0 slot 0 offset 0xd00000: delay constant 52
zs0 at obio0 slot 0 offset 0x100000 level 12 powered via auxio2 softpri 6
zstty0 at zs0 channel 0
zstty1 at zs0 channel 1
zs1 at obio0 slot 0 offset 0x0 level 12 softpri 6
kbd0 at zs1 channel 0: baud rate 1200 (console input)
wskbd0 at kbd0: console keyboard
ms0 at zs1 channel 1: baud rate 1200
wssunkbd_enable
open...
kbd_sun_open
init...
slavioconfig at obio0 slot 0 offset 0x800000 not configured
auxreg0 at obio0 slot 0 offset 0x900000
auxiotwo0 at obio0 slot 0 offset 0x910000
tctrl0 at obio0 slot 0 offset 0xd1000020 level 11
tctrl0: main power available
clk-ctrl at obio0 slot 0 offset 0x3c0000 not configured
com0 at obio0 slot 0 offset 0x3a0000 level 13: ns16550a, working fifo
iommu0 at mainbus0 addr 0x10000000: version 0x4/0x0, page-size 4096, range 64MB
sbus0 at iommu0: clock = 22 MHz
pnozz0 at sbus0 slot 0 offset 0x8000000 level 2: rev 4, 800x600, depth 8 (consol
e)
wsdisplay0 at pnozz0 kbdmux 1: console (default, vt100 emulation), using wskbd0
wsmux1: connecting to wsdisplay0
pnozz0: attached to /dev/fb
dma0 at sbus0 slot 4 offset 0x8400000: DMA rev 2
esp0 at dma0 slot 4 offset 0x8800000 level 4: ESP200, 40MHz, SCSI ID 7
scsibus0 at esp0: 8 targets, 8 luns per target
SUNW,bpp at sbus0 slot 4 offset 0xc800000 level 3 not configured
ledma0 at sbus0 slot 4 offset 0x8400010: DMA rev 2
le0 at ledma0 slot 4 offset 0x8c00000 level 6: address 00:00:83:ae:25:31
le0: 8 receive buffers, 2 transmit buffers
ts102 at sbus0 slot 1 offset 0x2000000 level 11 not configured
dbri0 at sbus0 slot 2 offset 0x40 level 9
dbri0: need to power up first....done
scsibus0: waiting 2 seconds for devices to settle...
sd0 at scsibus0 target 3 lun 0: <ADTX, AXSITS2532U 011D, K2.1> disk fixed
sd0: fabricating a geometry
sd0: 6194 MB, 6194 cyl, 64 head, 32 sec, 512 bytes/sect x 12685680 sectors
sd0: sync (200.00ns offset 7), 8-bit (5.000MB/s) transfers
root on sd0a dumps on sd0b
sd0: fabricating a geometry
sd0: fabricating a geometry
root file system type: ffs
WARNING: clock gained 17 days -- CHECK AND RESET THE DATE!
wsdisplay0: screen 1 added (default, vt100 emulation)
wsdisplay0: screen 2 added (default, vt100 emulation)
wsdisplay0: screen 3 added (default, vt100 emulation)
wsdisplay0: screen 4 added (default, vt100 emulation)

>Fix:
Index: wskbdmap_sun.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sun/wskbdmap_sun.c,v
retrieving revision 1.5
diff -u -w -r1.5 wskbdmap_sun.c
--- wskbdmap_sun.c      27 Feb 2005 00:27:49 -0000      1.5
+++ wskbdmap_sun.c      2 Apr 2005 01:37:23 -0000
@@ -65,7 +65,11 @@
     KC(0x10), KS_Cmd_Screen6,                          KS_f7,
     KC(0x11), KS_Cmd_Screen7,                          KS_f8,
     KC(0x12), KS_Cmd_Screen8,                          KS_f9,
+#ifdef SPARCBOOK_CMD
+    KC(0x13), KS_Cmd,          KS_Alt_L,
+#else
     KC(0x13),                          KS_Alt_L,
+#endif
     KC(0x14),                          KS_Up,
     KC(0x15),                          KS_Pause,
     KC(0x16),                          KS_Print_Screen,

Index: files.sbus
===================================================================
RCS file: /cvsroot/src/sys/dev/sbus/files.sbus,v
retrieving revision 1.20
diff -u -w -r1.20 files.sbus
--- files.sbus	27 Feb 2005 00:27:48 -0000	1.20
+++ files.sbus	2 Apr 2005 01:33:19 -0000

@@ -121,6 +126,6 @@
 file	dev/sbus/zx.c			zx
 
 # Tadpole 3GX/3GS (P9100 -- P Nine One Zero Zero -> pnozz)
-device	pnozz: fb, bt_dac, rasops8, rasops16, rasops32
+device	pnozz: fb, bt_dac, rasops8, rasops16, rasops32, wsemuldisplaydev
 attach	pnozz at sbus
 file	dev/sbus/p9100.c		pnozz needs-flag
Index: p9100.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sbus/p9100.c,v
retrieving revision 1.20
diff -u -w -r1.20 p9100.c
--- p9100.c	27 Feb 2005 00:27:48 -0000	1.20
+++ p9100.c	2 Apr 2005 01:33:20 -0000
@@ -64,12 +64,18 @@
 #include <dev/sun/fbvar.h>
 #include <dev/sun/btreg.h>
 #include <dev/sun/btvar.h>
-#if 0
+
 #include <dev/sbus/p9100reg.h>
-#endif
 
 #include <dev/sbus/sbusvar.h>
 
+/*#include <dev/wscons/wsdisplayvar.h>*/
+#include <dev/wscons/wsconsio.h>
+#include <dev/wsfont/wsfont.h>
+#include <dev/rasops/rasops.h>
+
+#include "opt_wsemul.h"
+
 #include "tctrl.h"
 #if NTCTRL > 0
 #include <machine/tctrl.h>
@@ -96,24 +102,64 @@
 	bus_space_handle_t sc_fb_memh;	/*   bus space handle */
 
 	uint32_t sc_junk;
+	uint32_t sc_mono_width;	/* for setup_mono */
 
+	uint32_t sc_width, sc_height;	/* panel width / height */
+	uint32_t sc_stride, sc_depth;
 	union	bt_cmap sc_cmap;	/* Brooktree color map */
+
+#ifdef PNOZZ_SOFT_PUTCHAR
+	void (*putchar)(void *c, int row, int col, u_int uc, long attr);
+#endif
+	int sc_mode;
+	uint32_t sc_bg;
+	void (*switchcb)(void *, int, int);
+	void *switchcbarg;
+	struct callout switch_callout;
+	LIST_HEAD(, p9100_screen) screens;
+	struct p9100_screen *active, *wanted;
+	const struct wsscreen_descr *currenttype;
+
 };
 
-/* The Tadpole 3GX Technical Reference Manual lies.  The ramdac registers
- * are map in 4 byte increments, not 8.
- */
-#define	SCRN_RPNT_CTL_1	0x0138	/* Screen Respaint Timing Control 1 */
-#define	VIDEO_ENABLED	0x00000020
-#define	PWRUP_CNFG	0x0194	/* Power Up Configuration */
-#define	DAC_CMAP_WRIDX	0x0200	/* IBM RGB528 Palette Address (Write) */
-#define	DAC_CMAP_DATA	0x0204	/* IBM RGB528 Palette Data */
-#define	DAC_PXL_MASK	0x0208	/* IBM RGB528 Pixel Mask */
-#define	DAC_CMAP_RDIDX	0x020c	/* IBM RGB528 Palette Address (Read) */
-#define	DAC_INDX_LO	0x0210	/* IBM RGB528 Index Low */
-#define	DAC_INDX_HI	0x0214	/* IBM RGB528 Index High */
-#define	DAC_INDX_DATA	0x0218	/* IBM RGB528 Index Data (Indexed Registers) */
-#define	DAC_INDX_CTL	0x021c	/* IBM RGB528 Index Control */
+struct p9100_screen {
+	struct rasops_info ri;
+	LIST_ENTRY(p9100_screen) next;
+	struct p9100_softc *sc;
+	const struct wsscreen_descr *type;
+	int active;
+	u_int16_t *chars;
+	long *attrs;
+	int dispoffset;
+	int mindispoffset;
+	int maxdispoffset;
+
+	int cursoron;
+	int cursorcol;
+	int cursorrow;
+	int cursordrawn;
+};
+
+static struct p9100_screen p9100_console_screen;
+
+extern const u_char rasops_cmap[768];
+
+struct wsscreen_descr p9100_defscreendesc = {
+	"default",
+	0, 0,
+	NULL,
+	8, 16,
+	WSSCREEN_WSCOLORS,
+};
+
+const struct wsscreen_descr *_p9100_scrlist[] = {
+	&p9100_defscreendesc,
+	/* XXX other formats, graphics screen? */
+};
+
+struct wsscreen_list p9100_screenlist = {
+	sizeof(_p9100_scrlist) / sizeof(struct wsscreen_descr *), _p9100_scrlist
+};
 
 /* autoconfiguration driver */
 static int	p9100_sbus_match(struct device *, struct cfdata *, void *);
@@ -147,10 +193,59 @@
 static int p9100_get_video(struct p9100_softc *);
 static uint32_t p9100_ctl_read_4(struct p9100_softc *, bus_size_t);
 static void p9100_ctl_write_4(struct p9100_softc *, bus_size_t, uint32_t);
-#if 0
-static uint8_t p9100_ramdac_read(struct p9100_softc *, bus_size_t);
-#endif
-static void p9100_ramdac_write(struct p9100_softc *, bus_size_t, uint8_t);
+uint8_t p9100_ramdac_read(struct p9100_softc *, bus_size_t);
+void p9100_ramdac_write(struct p9100_softc *, bus_size_t, uint8_t);
+
+static void p9100_sync(struct p9100_softc *);
+void p9100_bitblt(struct p9100_softc *, int, int, int, int, int, int, uint32_t);	/* coordinates, rasop */
+void p9100_rectfill(struct p9100_softc *, int, int, int, int, uint32_t);			/* coordinates, colour */
+static void p9100_init_engine(struct p9100_softc *);
+void	p9100_setup_mono(struct p9100_softc *, int, int, int, int, uint32_t, uint32_t); 
+void	p9100_feed_line(struct p9100_softc *, int, uint8_t *);
+static void	p9100_set_color_reg(struct p9100_softc *, int, int32_t);
+
+void	p9100_cursor(void *, int, int, int);
+int		p9100_mapchar(void *, int, u_int *);
+void	p9100_putchar(void *, int, int, u_int, long);
+void	p9100_copycols(void *, int, int, int, int);
+void	p9100_erasecols(void *, int, int, int, long);
+void	p9100_copyrows(void *, int, int, int);
+void	p9100_eraserows(void *, int, int, long);
+int		p9100_allocattr(void *, int, int, int, long *);
+
+void	p9100_scroll(void *, void *, int);
+
+int		p9100_putcmap(struct p9100_softc *, struct wsdisplay_cmap *);
+int 	p9100_getcmap(struct p9100_softc *, struct wsdisplay_cmap *);
+int		p9100_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t	p9100_mmap(void *, off_t, int);
+int		p9100_alloc_screen(void *, const struct wsscreen_descr *, void **, int *, int *, long *);
+void	p9100_free_screen(void *, void *);
+int		p9100_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
+void	p9100_switch_screen(struct p9100_softc *);
+void	p9100_restore_screen(struct p9100_screen *, const struct wsscreen_descr *, u_int16_t *);
+void	p9100_clearscreen(struct p9100_softc *);
+		
+int		p9100_load_font(void *, void *, struct wsdisplay_font *);
+
+void	p9100_init_screen(struct p9100_softc *, struct p9100_screen *, int, long *);
+
+int		p9100_intr(void *);
+
+struct wsdisplay_accessops p9100_accessops = {
+	p9100_ioctl,
+	p9100_mmap,
+	p9100_alloc_screen,
+	p9100_free_screen,
+	p9100_show_screen,
+	NULL,	/* load_font */
+	NULL,	/* polls */
+	NULL,	/* getwschar */
+	NULL,	/* putwschar */
+	NULL,	/* scroll */
+	NULL,	/* getborder */
+	NULL	/* setborder */
+};
 
 /*
  * Match a p9100.
@@ -175,7 +270,10 @@
 	struct fbdevice *fb = &sc->sc_fb;
 	int isconsole;
 	int node;
-	int i;
+	int i,j;
+	struct wsemuldisplaydev_attach_args aa;
+	struct rasops_info *ri;
+	unsigned long defattr;
 
 	/* Remember cookies for p9100_mmap() */
 	sc->sc_bustag = sa->sa_bustag;
@@ -197,6 +295,16 @@
 	fb->fb_type.fb_type = FBTYPE_SUN3COLOR;
 	fb->fb_pixels = NULL;
 
+	sc->sc_mode=WSDISPLAYIO_MODE_EMUL;
+#ifdef PNOZZ_SOFT_PUTCHAR
+	sc->putchar=NULL;
+#endif
+
+	LIST_INIT(&sc->screens);
+	sc->active = NULL;
+	sc->currenttype = &p9100_defscreendesc;
+	callout_init(&sc->switch_callout);
+
 	node = sa->sa_node;
 	isconsole = fb_is_console(node);
 	if (!isconsole) {
@@ -213,21 +321,13 @@
 	if (sbus_bus_map(sc->sc_bustag,
 			 sa->sa_reg[0].oa_space,
 			 sa->sa_reg[0].oa_base,
-			 sc->sc_ctl_psize,
+			 /* XXX for some reason the SBus resources don't cover all registers, so we just map what we need */
+			 /*sc->sc_ctl_psize*/ 0x8000,
 			 BUS_SPACE_MAP_LINEAR, &sc->sc_ctl_memh) != 0) {
 		printf("%s: cannot map control registers\n", self->dv_xname);
 		return;
 	}
 
-	if (sbus_bus_map(sc->sc_bustag,
-			 sa->sa_reg[1].oa_space,
-			 sa->sa_reg[1].oa_base,
-			 sc->sc_cmd_psize,
-			 BUS_SPACE_MAP_LINEAR, &sc->sc_cmd_memh) != 0) {
-		printf("%s: cannot map command registers\n", self->dv_xname);
-		return;
-	}
-
 	if (sa->sa_npromvaddrs != 0)
 		fb->fb_pixels = (caddr_t)sa->sa_promvaddrs[0];
 
@@ -255,7 +355,16 @@
 		panic("pnozz: can't determine screen depth (0x%02x)", i);
 	    }
 	}
-	fb_setsize_obp(fb, fb->fb_type.fb_depth, 800, 600, node);
+	sc->sc_depth=(fb->fb_type.fb_depth>>3);
+	
+	/* XXX for some reason I get a kernel trap with this */
+	sc->sc_width=prom_getpropint(node,"width",800);
+	sc->sc_height=prom_getpropint(node,"height",600);
+	sc->sc_stride=prom_getpropint(node,"linebytes",sc->sc_width*(fb->fb_type.fb_depth>>3));
+
+	p9100_init_engine(sc);
+	
+	fb_setsize_obp(fb, fb->fb_type.fb_depth, sc->sc_width, sc->sc_height, node);
 
 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
 
@@ -269,7 +378,16 @@
 		printf(", %d entry colormap", fb->fb_type.fb_cmsize);
 
 	/* Initialize the default color map. */
-	bt_initcmap(&sc->sc_cmap, 256);
+	/*bt_initcmap(&sc->sc_cmap, 256);*/
+	j=0;
+	for(i=0;i<256;i++) {
+		sc->sc_cmap.cm_map[i][0]=rasops_cmap[j];
+		j++;
+		sc->sc_cmap.cm_map[i][1]=rasops_cmap[j];
+		j++;
+		sc->sc_cmap.cm_map[i][2]=rasops_cmap[j];
+		j++;
+	}
 	p9100loadcmap(sc, 0, 256);
 
 	/* make sure we are not blanked */
@@ -284,20 +402,58 @@
 	if (isconsole) {
 		printf(" (console)\n");
 #ifdef RASTERCONSOLE
-		for (i = 0; i < fb->fb_type.fb_size; i++) {
-		     if (fb->fb_pixels[i] == 0) {
-			 fb->fb_pixels[i] = 1;
-		     } else if (fb->fb_pixels[i] == (char) 255) {
-			 fb->fb_pixels[i] = 0;
-		     }
-		}
-		p9100loadcmap(sc, 255, 1);
+		/*p9100loadcmap(sc, 255, 1);*/
 		fbrcons_init(fb);
 #endif
 	} else
 		printf("\n");
 
+	wsfont_init();
+
+	p9100_init_screen(sc,&p9100_console_screen,1,&defattr);
+	p9100_console_screen.active=1;
+	sc->active=&p9100_console_screen;
+	ri=&p9100_console_screen.ri;
+
+	p9100_defscreendesc.nrows = ri->ri_rows;
+	p9100_defscreendesc.ncols = ri->ri_cols;
+	p9100_defscreendesc.textops = &ri->ri_ops;
+	p9100_defscreendesc.capabilities = ri->ri_caps;
+	
+	if(isconsole) {
+		wsdisplay_cnattach(&p9100_defscreendesc, ri, 0, 0, defattr);
+	}
+
+	sc->sc_bg=(defattr>>16)&0xff;
+
+	p9100_clearscreen(sc);
+
+	aa.console = isconsole;
+	aa.scrdata = &p9100_screenlist;
+	aa.accessops = &p9100_accessops;
+	aa.accesscookie = sc;
+
+	config_found(self, &aa, wsemuldisplaydevprint);
+
+	/* attach the fb */
 	fb_attach(fb, isconsole);
+
+#if 0
+	p9100_rectfill(sc,10,10,200,200,0x01);
+	p9100_rectfill(sc,210,10,200,200,0xff);
+	p9100_bitblt(sc,10,10,110,110,400,200,ROP_SRC);
+#endif
+#if 0
+	p9100_setup_mono(sc,750,500,32,1,1,6);
+	{
+		uint32_t ev=0xc3000000, odd=0x3c000000;
+		for(i=0;i<16;i++) { 
+			p9100_feed_line(sc, 1, (uint8_t*)&ev);
+			p9100_feed_line(sc, 1, (uint8_t*)&odd);
+		}
+	}
+	delay(4000000);
+#endif
 }
 
 static void
@@ -306,22 +462,12 @@
 {
 	struct p9100_softc *sc = arg;
 #ifdef RASTERCONSOLE
-	struct fbdevice *fb = &sc->sc_fb;
-	int i;
-
-	for (i = 0; i < fb->fb_type.fb_size; i++) {
-	     if (fb->fb_pixels[i] == 1) {
-		 fb->fb_pixels[i] = 0;
-	     } else if (fb->fb_pixels[i] == 0) {
-		 fb->fb_pixels[i] = 255;
-	     }
-	}
 	sc->sc_cmap.cm_map[0][0] = 0xff;
 	sc->sc_cmap.cm_map[0][1] = 0xff;
 	sc->sc_cmap.cm_map[0][2] = 0xff;
 	sc->sc_cmap.cm_map[1][0] = 0;
 	sc->sc_cmap.cm_map[1][1] = 0;
-	sc->sc_cmap.cm_map[1][2] = 0x80;
+	sc->sc_cmap.cm_map[1][2] = 0x00;
 	p9100loadcmap(sc, 0, 2);
 	sc->sc_cmap.cm_map[255][0] = 0;
 	sc->sc_cmap.cm_map[255][1] = 0;
@@ -409,20 +555,157 @@
 	bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, v);
 }
 
-#if 0
-static uint8_t
+/* wait until the engine is idle */
+static void
+p9100_sync(struct p9100_softc *sc)
+{
+	while((p9100_ctl_read_4(sc,ENGINE_STATUS)&(ENGINE_BUSY|BLITTER_BUSY))!=0);
+}
+
+static void	
+p9100_set_color_reg(struct p9100_softc *sc, int reg, int32_t col)
+{
+	uint32_t out;
+	switch(sc->sc_depth)
+	{
+		case 1:	/* 8 bit */
+			out=(col<<8)|col;
+			out|=out<<16;	
+			break;
+		case 2: /* 16 bit */
+			out=col|(col<<16);	
+			break;
+		default:
+			out=col;
+	}
+	p9100_ctl_write_4(sc,reg,out);
+}
+/* initialize the drawing engine */
+static void
+p9100_init_engine(struct p9100_softc *sc)
+{
+	/* reset clipping rectangles */
+	uint32_t max=((sc->sc_width&0x3fff)<< 16)|(sc->sc_height&0x3fff);
+	p9100_ctl_write_4(sc,WINDOW_OFFSET,0);
+	p9100_ctl_write_4(sc,WINDOW_MIN,0);
+	p9100_ctl_write_4(sc,WINDOW_MAX,max);
+	p9100_ctl_write_4(sc,BYTE_CLIP_MIN,0);
+	p9100_ctl_write_4(sc,BYTE_CLIP_MAX,max);
+	p9100_ctl_write_4(sc,DRAW_MODE,0);
+	p9100_ctl_write_4(sc,PLANE_MASK,0xffffffff);	
+	p9100_ctl_write_4(sc,PATTERN0,0xffffffff);	
+	p9100_ctl_write_4(sc,PATTERN1,0xffffffff);	
+	p9100_ctl_write_4(sc,PATTERN2,0xffffffff);	
+	p9100_ctl_write_4(sc,PATTERN3,0xffffffff);	
+}
+
+/* screen-to-screen blit */
+void 
+p9100_bitblt(struct p9100_softc *sc, int xs, int ys, int xd, int yd, int wi, int he, uint32_t rop)
+{
+	uint32_t src, dst, srcw,dstw, junk;
+	src=((xs&0x3fff)<<16)|(ys&0x3fff);
+	dst=((xd&0x3fff)<<16)|(yd&0x3fff);
+	srcw=(((xs+wi-1)&0x3fff)<<16)|((ys+he-1)&0x3fff);
+	dstw=(((xd+wi-1)&0x3fff)<<16)|((yd+he-1)&0x3fff);
+	p9100_sync(sc);
+	p9100_ctl_write_4(sc,RASTER_OP,rop);
+	
+	p9100_ctl_write_4(sc,ABS_XY0,src);
+	
+	p9100_ctl_write_4(sc,ABS_XY1,srcw);
+	p9100_ctl_write_4(sc,ABS_XY2,dst);
+	p9100_ctl_write_4(sc,ABS_XY3,dstw);
+	junk=p9100_ctl_read_4(sc,COMMAND_BLIT);
+	/*p9100_sync(sc);*/
+}
+
+/* solid rectangle fill */
+void 
+p9100_rectfill(struct p9100_softc *sc, int xs, int ys, int wi, int he, uint32_t col)
+{
+	uint32_t src, srcw, junk;
+	src=((xs&0x3fff)<<16)|(ys&0x3fff);
+	srcw=(((xs+wi)&0x3fff)<<16)|((ys+he)&0x3fff);
+	p9100_sync(sc);
+	p9100_set_color_reg(sc,FOREGROUND_COLOR,col);
+	p9100_set_color_reg(sc,BACKGROUND_COLOR,col);
+	p9100_ctl_write_4(sc,RASTER_OP,ROP_PAT);
+	p9100_ctl_write_4(sc,COORD_INDEX,0);
+	p9100_ctl_write_4(sc,RECT_RTW_XY,src);
+	p9100_ctl_write_4(sc,RECT_RTW_XY,srcw);
+	junk=p9100_ctl_read_4(sc,COMMAND_QUAD);
+	/*p9100_sync(sc);*/
+}
+
+void 
+p9100_setup_mono(struct p9100_softc *sc, int x, int y, int wi, int he, uint32_t fg,
+					uint32_t bg) 
+{
+	p9100_sync(sc);
+	/* this doesn't make any sense to me either, but for some reason the chip
+	   applies the foreground colour to 0 pixels */
+	p9100_set_color_reg(sc,FOREGROUND_COLOR,bg);
+	p9100_set_color_reg(sc,BACKGROUND_COLOR,fg);
+
+	p9100_ctl_write_4(sc,RASTER_OP,ROP_SRC);
+	p9100_ctl_write_4(sc,ABS_X0,x);
+	p9100_ctl_write_4(sc,ABS_XY1,(x<<16)|(y&0xFFFFL));
+	p9100_ctl_write_4(sc,ABS_X2,(x+wi));
+	p9100_ctl_write_4(sc,ABS_Y3,he);
+	/* now feed the data into the chip */
+	sc->sc_mono_width=wi;
+}
+
+void 
+p9100_feed_line(struct p9100_softc *sc, int count, uint8_t *data)
+{
+	int i;
+	uint32_t latch=0, bork;
+	int shift=24;
+	int to_go=sc->sc_mono_width;
+	for(i=0;i<count;i++) {
+		bork=data[i];
+		latch|=(bork<<shift);
+		if(shift==0) {
+			/* check how many bits are significant */
+			if(to_go>31) {
+				p9100_ctl_write_4(sc,(PIXEL_1+(31<<2)),latch);
+				to_go-=32;
+			} else
+			{
+				p9100_ctl_write_4(sc,(PIXEL_1+((to_go-1)<<2)),latch);
+				to_go=0;
+			}
+			latch=0;
+			shift=24;
+		} else
+			shift-=8;
+		}
+	if(shift!=24)
+		p9100_ctl_write_4(sc,(PIXEL_1+((to_go-1)<<2)),latch);
+}	
+
+void
+p9100_clearscreen(struct p9100_softc *sc)
+{
+	p9100_rectfill(sc,0,0,sc->sc_width,sc->sc_height,sc->sc_bg);
+}
+
+uint8_t
 p9100_ramdac_read(struct p9100_softc *sc, bus_size_t off)
 {
 	sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
-	return p9100_ctl_read_4(sc, off) >> 16;
+	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
+	return ((bus_space_read_4(sc->sc_bustag, sc->sc_ctl_memh,off)>>16)&0xff);
 }
-#endif
 
-static void
+void
 p9100_ramdac_write(struct p9100_softc *sc, bus_size_t off, uint8_t v)
 {
 	sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
-	p9100_ctl_write_4(sc, off, v << 16);
+	sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
+	bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, ((uint32_t)v)<<16);
 }
 
 /*
@@ -463,12 +746,13 @@
 static void
 p9100loadcmap(struct p9100_softc *sc, int start, int ncolors)
 {
-	u_char *p;
-
+	int i;
 	p9100_ramdac_write(sc, DAC_CMAP_WRIDX, start);
 
-	for (p = sc->sc_cmap.cm_map[start], ncolors *= 3; ncolors-- > 0; p++) {
-		p9100_ramdac_write(sc, DAC_CMAP_DATA, *p);
+	for (i=0;i<ncolors;i++) {
+		p9100_ramdac_write(sc, DAC_CMAP_DATA, sc->sc_cmap.cm_map[i+start][0]);
+		p9100_ramdac_write(sc, DAC_CMAP_DATA, sc->sc_cmap.cm_map[i+start][1]);
+		p9100_ramdac_write(sc, DAC_CMAP_DATA, sc->sc_cmap.cm_map[i+start][2]);
 	}
 }
 
@@ -524,3 +808,566 @@
 		prot,
 		BUS_SPACE_MAP_LINEAR));
 }
+
+
+/* wscons stuff */
+
+void
+p9100_switch_screen(struct p9100_softc *sc)
+{
+	struct p9100_screen *scr, *oldscr;
+
+	scr = sc->wanted;
+	if (!scr) {
+		printf("p9100_switch_screen: disappeared\n");
+		(*sc->switchcb)(sc->switchcbarg, EIO, 0);
+		return;
+	}
+	oldscr = sc->active; /* can be NULL! */
+#ifdef DIAGNOSTIC
+	if (oldscr) {
+		if (!oldscr->active)
+			panic("p9100_switch_screen: not active");
+	}
+#endif
+	if (scr == oldscr)
+		return;
+
+#ifdef DIAGNOSTIC
+/* XXX: this one bites us at reboot */
+/*	if (scr->active)
+		panic("p9100_switch_screen: active");*/
+#endif
+
+	if (oldscr)
+		oldscr->active = 0;
+#ifdef notyet
+	if (sc->currenttype != type) {
+		p9100_set_screentype(sc, type);
+		sc->currenttype = type;
+	}
+#endif
+
+	/* Clear the entire screen. */		
+
+	scr->active = 1;
+	p9100_restore_screen(scr, &p9100_defscreendesc, scr->chars);
+
+	sc->active = scr;
+	
+	scr->ri.ri_ops.cursor(scr, scr->cursoron, scr->cursorrow, scr->cursorcol);
+
+	sc->wanted = 0;
+	if (sc->switchcb)
+		(*sc->switchcb)(sc->switchcbarg, 0, 0);
+}
+
+void
+p9100_restore_screen(struct p9100_screen *scr,
+    const struct wsscreen_descr *type, u_int16_t *mem)
+{
+	int i, j, offset=0;
+	uint16_t *charptr=scr->chars;
+	long *attrptr=scr->attrs;
+	p9100_clearscreen(scr->sc);
+	for (i = 0; i < scr->ri.ri_rows; i++) {
+		for (j = 0; j < scr->ri.ri_cols; j++) {
+			p9100_putchar(scr, i, j, charptr[offset], attrptr[offset]);
+			offset++;
+		}
+	}
+	scr->cursordrawn=0;
+}
+
+void
+p9100_cursor(void *cookie, int on, int row, int col)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int x,y,wi=ri->ri_font->fontwidth,he=ri->ri_font->fontheight;
+	if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+		x=scr->cursorcol*wi+ri->ri_xorigin;
+		y=scr->cursorrow*he+ri->ri_yorigin;
+		if(scr->cursordrawn) {
+			p9100_bitblt(sc,x,y,x,y,wi,he,(ROP_SRC^0xff));
+			scr->cursordrawn=0;
+		}
+		scr->cursorrow=row;
+		scr->cursorcol=col;
+		if((scr->cursoron=on)!=0)
+		{
+			x=scr->cursorcol*wi+ri->ri_xorigin;
+			y=scr->cursorrow*he+ri->ri_yorigin;
+			p9100_bitblt(sc,x,y,x,y,wi,he,(ROP_SRC^0xff));
+			scr->cursordrawn=1;
+		}
+	} else {
+		scr->cursoron=on;
+		scr->cursorrow=row;
+		scr->cursorcol=col;
+		scr->cursordrawn=0;
+	}
+
+}
+
+#if 0
+int
+p9100_mapchar(void *cookie, int uni, u_int *index)
+{
+	return 0;
+}
+#endif
+
+void
+p9100_putchar(void *cookie, int row, int col, u_int c, long attr)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int pos;
+	if((row>=0) && (row<ri->ri_rows) && (col>=0) && (col<ri->ri_cols)) {
+		pos=col+row*ri->ri_cols;
+		scr->attrs[pos]=attr;
+		scr->chars[pos]=c;
+
+#ifdef PNOZZ_SOFT_PUTCHAR
+		if((sc->putchar!=NULL) && (	scr->active)&& (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+			p9100_sync(sc);
+			sc->putchar(cookie,row,col,c,attr);
+		}
+#else
+		if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+			int fg,bg,uc,i;
+			uint8_t *data;
+			int x,y,wi=ri->ri_font->fontwidth,he=ri->ri_font->fontheight;
+		
+			if (!CHAR_IN_FONT(c, ri->ri_font))
+				return;
+			bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff];
+			fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff];
+			x=ri->ri_xorigin+col*wi;
+			y=ri->ri_yorigin+row*he;
+			if(c==0x20) {
+				p9100_rectfill(sc,x,y,wi,he,bg);
+			} else {
+				uc = c-ri->ri_font->firstchar;
+				data = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale;
+
+				p9100_setup_mono(sc,x,y,wi,1,fg,bg);		
+				for(i=0;i<he;i++) {
+					p9100_feed_line(sc,ri->ri_font->stride,data);
+					data+=ri->ri_font->stride;
+				}
+				/*p9100_sync(sc);*/
+			}
+		}
+#endif
+	}
+}
+
+void
+p9100_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int32_t xs,xd,y,width,height;
+	
+	int from=srccol+row*ri->ri_cols;
+	int to=dstcol+row*ri->ri_cols;
+	memmove(&scr->attrs[to],&scr->attrs[from],ncols*sizeof(long));
+	memmove(&scr->chars[to],&scr->chars[from],ncols*sizeof(uint16_t));
+
+	if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+		xs=ri->ri_xorigin+ri->ri_font->fontwidth*srccol;
+		xd=ri->ri_xorigin+ri->ri_font->fontwidth*dstcol;
+		y=ri->ri_yorigin+ri->ri_font->fontheight*row;
+		width=ri->ri_font->fontwidth*ncols;
+		height=ri->ri_font->fontheight;		
+		p9100_bitblt(sc,xs,y,xd,y,width,height,ROP_SRC);
+	}
+}
+
+void
+p9100_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int32_t x,y,width,height,bg;
+	
+	int start=startcol+row*ri->ri_cols;
+	int end=start+ncols, i;
+	for(i=start;i<end;i++) {
+		scr->attrs[i]=fillattr;
+		scr->chars[i]=0x20;
+	}
+	if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+		x=ri->ri_xorigin+ri->ri_font->fontwidth*startcol;
+		y=ri->ri_yorigin+ri->ri_font->fontheight*row;
+		width=ri->ri_font->fontwidth*ncols;
+		height=ri->ri_font->fontheight;		
+		bg=(fillattr>>16)&0xff;	
+		p9100_rectfill(sc,x,y,width,height,bg);
+	}
+}
+
+void
+p9100_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int32_t x,ys,yd,width,height;
+	
+	int from=ri->ri_cols*srcrow, to=ri->ri_cols*dstrow, len=ri->ri_cols*nrows;
+	memmove(&scr->attrs[to],&scr->attrs[from],len*sizeof(long));
+	memmove(&scr->chars[to],&scr->chars[from],len*sizeof(uint16_t));
+	
+	if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+		x=ri->ri_xorigin;
+		ys=ri->ri_yorigin+ri->ri_font->fontheight*srcrow;
+		yd=ri->ri_yorigin+ri->ri_font->fontheight*dstrow;
+		width=ri->ri_emuwidth;
+		height=ri->ri_font->fontheight*nrows;		
+		p9100_bitblt(sc,x,ys,x,yd,width,height,ROP_SRC);
+	}
+}
+
+void
+p9100_eraserows(void *cookie, int row, int nrows, long fillattr)
+{
+	struct rasops_info *ri=cookie;
+	struct p9100_screen *scr=ri->ri_hw;
+	struct p9100_softc *sc=scr->sc;
+	int32_t x,y,width,height,bg;
+	
+	int start=ri->ri_cols*row, end=ri->ri_cols*(row+nrows),i;
+	for(i=start;i<end;i++) {
+		scr->attrs[i]=fillattr;
+		scr->chars[i]=0x20;
+	}
+
+	if((scr->active) && (sc->sc_mode==WSDISPLAYIO_MODE_EMUL)) {
+		x=ri->ri_xorigin;
+		y=ri->ri_yorigin+ri->ri_font->fontheight*row;
+		width=ri->ri_emuwidth;
+		height=ri->ri_font->fontheight*nrows;		
+		bg=(fillattr>>16)&0xff;		   
+		p9100_rectfill(sc,x,y,width,height,bg);
+	}
+}
+
+int
+p9100_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
+{
+	/*printf("allocattr(%d %d %d)\n",fg,bg,flags);*/
+	if((fg==0)&&(bg==0))
+	{
+		fg=WS_DEFAULT_FG;
+		bg=WS_DEFAULT_BG;
+	}
+	if(flags&WSATTR_REVERSE) {
+		*attrp=(bg&0xff)<<24|(fg&0xff)<<16|(flags&0xff)<<8;
+	} else
+		*attrp=(fg&0xff)<<24|(bg&0xff)<<16|(flags&0xff)<<8;
+	return 0;
+}
+
+/*
+ * wsdisplay_accessops
+ */
+
+int
+p9100_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+	/* we'll probably need to add more stuff here */
+	struct p9100_softc *sc = v;
+	struct wsdisplay_fbinfo *wdf;
+	struct p9100_screen *ms=sc->active;
+	switch (cmd) {
+		case WSDISPLAYIO_GTYPE:
+			*(u_int *)data = WSDISPLAY_TYPE_SB_P9100;
+			return 0;
+	
+		case FBIOGVIDEO:
+		case WSDISPLAYIO_SVIDEO:
+			*(int *)data = p9100_get_video(sc);
+			return 0;
+		case WSDISPLAYIO_GVIDEO:
+		case FBIOSVIDEO:
+			p9100_set_video(sc, *(int *)data);
+			return 0;
+
+		case WSDISPLAYIO_GINFO:
+			wdf = (void *)data;
+			wdf->height = ms->ri.ri_height;
+			wdf->width = ms->ri.ri_width;
+			wdf->depth = ms->ri.ri_depth;
+			wdf->cmsize = 256;
+			return 0;
+
+		case WSDISPLAYIO_GETCMAP:
+			return p9100_getcmap(sc, (struct wsdisplay_cmap *)data);
+
+		case WSDISPLAYIO_PUTCMAP:
+			return p9100_putcmap(sc, (struct wsdisplay_cmap *)data);
+
+		/* PCI config read/write passthrough. */
+		case WSDISPLAYIO_SMODE:
+			{
+				int new_mode=*(int*)data;
+				if(new_mode!=sc->sc_mode)
+				{
+					sc->sc_mode=new_mode;
+					if(new_mode==WSDISPLAYIO_MODE_EMUL)
+					{
+						/* we'll probably want to reset the console into a known state here 
+						   just in case the Xserver crashed or didn't properly clean up after 
+						   itself for whetever reason */
+						p9100_init_engine(sc);	/* who knows what they did to the engine when we weren't looking */
+						p9100_restore_screen(ms, ms->type, ms->chars);
+						p9100_cursor(ms, ms->cursoron, ms->cursorrow, ms->cursorcol);
+					}
+				}
+			}
+	}
+	return EPASSTHROUGH;
+}
+
+paddr_t
+p9100_mmap(void *v, off_t offset, int prot)
+{
+	struct p9100_softc *sc = v;	
+	paddr_t pa;
+	/* 'regular' framebuffer mmap()ing */
+	if(offset<sc->sc_fb_psize) {
+		pa = bus_space_mmap(sc->sc_bustag,sc->sc_fb_paddr+offset,0,prot,BUS_SPACE_MAP_LINEAR);	
+		return pa;
+	}
+
+	if((offset>=sc->sc_fb_paddr) && (offset<(sc->sc_fb_paddr+sc->sc_fb_psize))) {
+		pa = bus_space_mmap(sc->sc_bustag,offset,0,prot,BUS_SPACE_MAP_LINEAR);	
+		return pa;
+	}
+
+	if((offset>=sc->sc_ctl_paddr) && (offset<(sc->sc_ctl_paddr+sc->sc_ctl_psize))) {
+		pa = bus_space_mmap(sc->sc_bustag,offset,0,prot,BUS_SPACE_MAP_LINEAR);	
+		return pa;
+	}
+
+	return -1;
+}
+
+void
+p9100_init_screen(struct p9100_softc *sc, struct p9100_screen *scr,
+    int existing, long *defattr)
+{
+	struct rasops_info *ri=&scr->ri;
+	int cnt;
+	scr->sc = sc;
+	/*scr->type = type;*/
+	scr->dispoffset = 0;
+	scr->cursorcol = 0;
+	scr->cursorrow = 0;
+	scr->cursordrawn=0;
+	   
+	ri->ri_depth = sc->sc_depth<<3;
+	ri->ri_width = sc->sc_width;
+	ri->ri_height = sc->sc_height;
+	ri->ri_stride = sc->sc_stride;
+	ri->ri_flg = RI_CENTER;
+
+	ri->ri_bits = bus_space_vaddr(sc->sc_bustag,sc->sc_fb_memh);
+
+#ifdef DEBUG_P9100
+	printf("addr: %08lx\n",(ulong)ri->ri_bits);
+#endif
+	rasops_init(ri, sc->sc_height/8, sc->sc_width/8);
+	ri->ri_caps=WSSCREEN_WSCOLORS;
+	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
+		    sc->sc_width / ri->ri_font->fontwidth);
+
+	p9100_allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr);
+
+	cnt=ri->ri_rows * ri->ri_cols;
+	scr->attrs=(long *)malloc(cnt*(sizeof(long)+sizeof(uint16_t)),
+	    M_DEVBUF, M_WAITOK);
+	scr->chars=(uint16_t *)&scr->attrs[cnt];
+	/* we allocate both chars and attributes in one chunk, attributes first because
+	   they have the (potentially) bigger alignment */
+
+	/* enable acceleration */
+	ri->ri_hw=scr;
+	ri->ri_ops.copyrows=p9100_copyrows;
+	ri->ri_ops.copycols=p9100_copycols;
+	ri->ri_ops.eraserows=p9100_eraserows;
+	ri->ri_ops.erasecols=p9100_erasecols;
+	ri->ri_ops.cursor=p9100_cursor;
+	ri->ri_ops.allocattr=p9100_allocattr;
+#ifdef PNOZZ_SOFT_PUTCHAR
+	if(sc->putchar==NULL)
+		sc->putchar=ri->ri_ops.putchar;
+#endif
+	ri->ri_ops.putchar=p9100_putchar;
+	
+	if (existing) {
+		scr->active = 1;
+	} else {
+		scr->active = 0;
+	}
+
+	p9100_eraserows(&scr->ri, 0, ri->ri_rows, *defattr);
+
+	LIST_INSERT_HEAD(&sc->screens, scr, next);
+}
+
+int
+p9100_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+    int *curxp, int *curyp, long *defattrp)
+{
+	struct p9100_softc *sc = v;
+	struct p9100_screen *scr;
+
+	scr = malloc(sizeof(struct p9100_screen), M_DEVBUF, M_WAITOK|M_ZERO);
+	p9100_init_screen(sc, scr, 0, defattrp);
+
+	if (sc->active == NULL) {
+		scr->active = 1;
+		sc->active = scr;
+		sc->currenttype = type;
+	}
+
+	*cookiep = scr;
+	*curxp = scr->cursorcol;
+	*curyp = scr->cursorrow;
+	return 0;
+}
+
+void
+p9100_free_screen(void *v, void *cookie)
+{
+	struct p9100_softc *sc = v;
+	struct p9100_screen *scr = cookie;
+
+	LIST_REMOVE(scr, next);
+	if (scr != &p9100_console_screen) {
+		free(scr->attrs, M_DEVBUF);
+		free(scr, M_DEVBUF);
+	} else
+		panic("p9100_free_screen: console");
+
+	if (sc->active == scr)
+		sc->active = 0;
+}
+
+int
+p9100_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg)
+{
+	struct p9100_softc *sc = v;
+	struct p9100_screen *scr, *oldscr;
+
+	scr = cookie;
+	oldscr = sc->active;
+	if (scr == oldscr)
+		return 0;
+
+	sc->wanted = scr;
+	sc->switchcb = cb;
+	sc->switchcbarg = cbarg;
+	if (cb) {
+		callout_reset(&sc->switch_callout, 0,
+		    (void(*)(void *))p9100_switch_screen, sc);
+		return EAGAIN;
+	}
+
+	p9100_switch_screen(sc);
+	return 0;
+}
+
+int
+p9100_putcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm)
+{
+	u_int index = cm->index;
+	u_int count = cm->count;
+	int i, error;
+	u_char rbuf[256], gbuf[256], bbuf[256];
+	u_char *r, *g, *b;
+
+	printf("putcmap: %d %d\n",index, count);
+	if (cm->index >= 256 || cm->count > 256 ||
+	    (cm->index + cm->count) > 256)
+		return EINVAL;
+	error = copyin(cm->red, &rbuf[index], count);
+	if (error)
+		return error;
+	error = copyin(cm->green, &gbuf[index], count);
+	if (error)
+		return error;
+	error = copyin(cm->blue, &bbuf[index], count);
+	if (error)
+		return error;
+
+	r = &rbuf[index];
+	g = &gbuf[index];
+	b = &bbuf[index];
+
+	for (i = 0; i < count; i++) {
+		sc->sc_cmap.cm_map[index][0]=*r;
+		sc->sc_cmap.cm_map[index][1]=*g;
+		sc->sc_cmap.cm_map[index][2]=*b;
+		index++;
+		r++, g++, b++;
+	}
+	p9100loadcmap(sc,0,256);
+	return 0;
+}
+
+int
+p9100_getcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm)
+{
+	u_int index = cm->index;
+	u_int count = cm->count;
+	int error,i;
+	uint8_t red[256],green[256],blue[256];
+
+	if (index >= 255 || count > 256 || index + count > 256)
+		return EINVAL;
+
+	i=index;
+	while(i<(index+count)) {
+		red[i]=sc->sc_cmap.cm_map[i][0];
+		green[i]=sc->sc_cmap.cm_map[i][1];
+		blue[i]=sc->sc_cmap.cm_map[i][2];
+		i++;
+	}
+	error = copyout(&red[index],   cm->red,   count);
+	if (error)
+		return error;
+	error = copyout(&green[index], cm->green, count);
+	if (error)
+		return error;
+	error = copyout(&blue[index],  cm->blue,  count);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+#if 0
+int
+p9100_load_font(void *v, void *cookie, struct wsdisplay_font *data)
+{
+
+	return 0;
+}
+#endif
+int
+p9100_intr(void *arg)
+{
+	//p9100_softc *sc=arg;
+	//printf(".");
+	return 1;
+}

... and put this into p9100reg.h:

/*	$NetBSD: p9100.c,v 1.20 2005/02/27 00:27:48 perry Exp $ */

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


#ifndef P9100_REG_H
#define P9100_REG_H

/* The Tadpole 3GX Technical Reference Manual lies.  The ramdac registers
 * are map in 4 byte increments, not 8.
 */
#define	SCRN_RPNT_CTL_1	0x0138	/* Screen Respaint Timing Control 1 */
#define	VIDEO_ENABLED	0x00000020
#define	PWRUP_CNFG	0x0194	/* Power Up Configuration */
#define	DAC_CMAP_WRIDX	0x0200	/* IBM RGB528 Palette Address (Write) */
#define	DAC_CMAP_DATA	0x0204	/* IBM RGB528 Palette Data */
#define	DAC_PXL_MASK	0x0208	/* IBM RGB528 Pixel Mask */
#define	DAC_CMAP_RDIDX	0x020c	/* IBM RGB528 Palette Address (Read) */
#define	DAC_INDX_LO	0x0210	/* IBM RGB528 Index Low */
#define	DAC_INDX_HI	0x0214	/* IBM RGB528 Index High */
#define	DAC_INDX_DATA	0x0218	/* IBM RGB528 Index Data (Indexed Registers) */
#define	DAC_INDX_CTL	0x021c	/* IBM RGB528 Index Control */

#define ENGINE_STATUS	0x2000	/* drawing engine status register */
	#define BLITTER_BUSY	0x80000000
	#define ENGINE_BUSY		0x40000000
#define COMMAND_BLIT	0x2004
#define COMMAND_QUAD	0x2008
#define PIXEL_1			0x2080	/* pixel data for monochrome colour expansion */
/* apparently bits 2-6 control how many pixels we write - n+1 */

/* drawing engine registers */
#define COORD_INDEX			0x218c
#define WINDOW_OFFSET		0x2190

#define FOREGROUND_COLOR	0x2200
#define BACKGROUND_COLOR	0x2204
#define PLANE_MASK			0x2208
#define DRAW_MODE			0x220c	
#define PATTERN_ORIGIN_X	0x2210
#define PATTERN_ORIGIN_Y	0x2214
#define RASTER_OP			0x2218
	#define ROP_NO_SOLID		0x02000	/* if set use pattern instead of color for quad operations */
	#define ROP_2BIT_PATTERN	0x04000 /* 4-colour pattern instead of mono */
	#define ROP_PIX1_TRANS		0x08000	/* transparent background in mono */
	#define ROP_OVERSIZE		0x10000
	#define ROP_PATTERN			0x20000		/* the manual says pattern enable */
	#define ROP_TRANS			0x20000		/* but XFree86 says trans */
	#define ROP_SRC 			0xCC
	#define ROP_PAT				0xF0
	#define ROP_DST 			0xAA
	#define ROP_SET				0xff

#define PIXEL_8				0x221c
#define WINDOW_MIN			0x2220
#define WINDOW_MAX			0x2224

#define PATTERN0			0x2280
#define PATTERN1			0x2284
#define PATTERN2			0x2288
#define PATTERN3			0x228c
#define USER0				0x2290
#define USER1				0x2294
#define USER2				0x2298
#define USER3				0x229c
#define BYTE_CLIP_MIN		0x22a0
#define BYTE_CLIP_MAX		0x22a4

/* coordinate registers */
#define ABS_X0		0x3008
#define ABS_Y0		0x3010
#define ABS_XY0		0x3018
#define REL_X0		0x3028
#define REL_Y0		0x3030
#define REL_XY0		0x3038

#define ABS_X1		0x3048
#define ABS_Y1		0x3050
#define ABS_XY1		0x3058
#define REL_X1		0x3068
#define REL_Y1		0x3070
#define REL_XY1		0x3078

#define ABS_X2		0x3088
#define ABS_Y2		0x3090
#define ABS_XY2		0x3098
#define REL_X2		0x30a8
#define REL_Y2		0x30b0
#define REL_XY2		0x30b8

#define ABS_X3		0x30c8
#define ABS_Y3		0x30d0
#define ABS_XY3		0x30d8
#define REL_X3		0x30e8
#define REL_Y3		0x30f0
#define REL_XY3		0x30f8

/* meta-coordinates */
#define POINT_RTW_X		0x3208
#define POINT_RTW_Y		0x3210
#define POINT_RTW_XY	0x3218
#define POINT_RTP_X		0x3228
#define POINT_RTP_Y		0x3220
#define POINT_RTP_XY	0x3238

#define LINE_RTW_X		0x3248
#define LINE_RTW_Y		0x3250
#define LINE_RTW_XY		0x3258
#define LINE_RTP_X		0x3268
#define LINE_RTP_Y		0x3260
#define LINE_RTP_XY		0x3278

#define TRIANGLE_RTW_X	0x3288
#define TRIANGLE_RTW_Y	0x3290
#define TRIANGLE_RTW_XY	0x3298
#define TRIANGLE_RTP_X	0x32a8
#define TRIANGLE_RTP_Y	0x32a0
#define TRIANGLE_RTP_XY	0x32b8

#define QUAD_RTW_X		0x32c8
#define QUAD_RTW_Y		0x32d0
#define QUAD_RTW_XY		0x32d8
#define QUAD_RTP_X		0x32e8
#define QUAD_RTP_Y		0x32e0
#define QUAD_RTP_XY		0x32f8

#define RECT_RTW_X		0x3308
#define RECT_RTW_Y		0x3310
#define RECT_RTW_XY		0x3318
#define RECT_RTP_X		0x3328
#define RECT_RTP_Y		0x3320
#define RECT_RTP_XY		0x3338

#endif