Home | History | Annotate | Line # | Download | only in tc
stic.c revision 1.11
      1 /*	$NetBSD: stic.c,v 1.11 2001/09/18 19:51:23 ad Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
     41  *
     42  * Redistribution and use in source and binary forms, with or without
     43  * modification, are permitted provided that the following conditions
     44  * are met:
     45  * 1. Redistributions of source code must retain the above copyright
     46  *    notice, this list of conditions and the following disclaimer.
     47  * 2. Redistributions in binary form must reproduce the above copyright
     48  *    notice, this list of conditions and the following disclaimer in the
     49  *    documentation and/or other materials provided with the distribution.
     50  * 3. All advertising materials mentioning features or use of this software
     51  *    must display the following acknowledgement:
     52  *      This product includes software developed by Tohru Nishimura
     53  *	for the NetBSD Project.
     54  * 4. The name of the author may not be used to endorse or promote products
     55  *    derived from this software without specific prior written permission
     56  *
     57  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     58  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     59  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     60  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     61  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     62  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     63  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     64  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     65  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     66  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     67  */
     68 
     69 /*
     70  * Driver for the DEC PixelStamp interface chip (STIC).
     71  *
     72  * XXX The bt459 interface shouldn't be replicated here.
     73  */
     74 
     75 #include <sys/param.h>
     76 #include <sys/systm.h>
     77 #include <sys/kernel.h>
     78 #include <sys/device.h>
     79 #include <sys/malloc.h>
     80 #include <sys/buf.h>
     81 #include <sys/ioctl.h>
     82 #include <sys/callout.h>
     83 #include <sys/conf.h>
     84 
     85 #include <uvm/uvm_extern.h>
     86 
     87 #if defined(pmax)
     88 #include <mips/cpuregs.h>
     89 #elif defined(alpha)
     90 #include <alpha/alpha_cpu.h>
     91 #endif
     92 
     93 #include <machine/vmparam.h>
     94 #include <machine/bus.h>
     95 #include <machine/intr.h>
     96 
     97 #include <dev/wscons/wsconsio.h>
     98 #include <dev/wscons/wsdisplayvar.h>
     99 
    100 #include <dev/wsfont/wsfont.h>
    101 
    102 #include <dev/ic/bt459reg.h>
    103 
    104 #include <dev/tc/tcvar.h>
    105 #include <dev/tc/sticreg.h>
    106 #include <dev/tc/sticio.h>
    107 #include <dev/tc/sticvar.h>
    108 
    109 #define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff))
    110 #define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff))
    111 #define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff))
    112 
    113 #define PACK(p, o) ((p)[(o)] | ((p)[(o)+1] << 16))
    114 
    115 #if defined(pmax)
    116 #define	machine_btop(x)		mips_btop(x)
    117 #elif defined(alpha)
    118 #define machine_btop(x)		alpha_btop(x)
    119 #endif
    120 
    121 /*
    122  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
    123  * obscure register layout such as 2nd and 3rd Bt459 registers are
    124  * adjacent each other in a word, i.e.,
    125  *	struct bt459triplet {
    126  * 		struct {
    127  *			u_int8_t u0;
    128  *			u_int8_t u1;
    129  *			u_int8_t u2;
    130  *			unsigned :8;
    131  *		} bt_lo;
    132  *		struct {
    133  *
    134  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
    135  *	struct bt459reg {
    136  *		   u_int32_t	   bt_lo;
    137  *		   u_int32_t	   bt_hi;
    138  *		   u_int32_t	   bt_reg;
    139  *		   u_int32_t	   bt_cmap;
    140  *	};
    141  *
    142  */
    143 
    144 /* Bt459 hardware registers */
    145 #define bt_lo	0
    146 #define bt_hi	1
    147 #define bt_reg	2
    148 #define bt_cmap 3
    149 
    150 #define REG(base, index)	*((u_int32_t *)(base) + (index))
    151 #define SELECT(vdac, regno) do {		\
    152 	REG(vdac, bt_lo) = DUPBYTE0(regno);	\
    153 	REG(vdac, bt_hi) = DUPBYTE1(regno);	\
    154 	tc_wmb();				\
    155    } while (0)
    156 
    157 int	sticioctl(void *, u_long, caddr_t, int, struct proc *);
    158 int	stic_alloc_screen(void *, const struct wsscreen_descr *, void **,
    159 			  int *, int *, long *);
    160 void	stic_free_screen(void *, void *);
    161 int	stic_show_screen(void *, void *, int, void (*)(void *, int, int),
    162 			 void *);
    163 
    164 int	sticopen(dev_t, int, int, struct proc *);
    165 int	sticclose(dev_t, int, int, struct proc *);
    166 paddr_t	sticmmap(dev_t, off_t, int);
    167 
    168 void	stic_do_switch(void *);
    169 void	stic_setup_backing(struct stic_info *, struct stic_screen *);
    170 void	stic_setup_vdac(struct stic_info *);
    171 void	stic_clear_screen(struct stic_info *);
    172 
    173 int	stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *);
    174 int	stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *);
    175 int	stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *);
    176 int	stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *);
    177 void	stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *);
    178 void	stic_set_hwcurpos(struct stic_info *);
    179 
    180 void	stic_cursor(void *, int, int, int);
    181 void	stic_copycols(void *, int, int, int, int);
    182 void	stic_copyrows(void *, int, int, int);
    183 void	stic_erasecols(void *, int, int, int, long);
    184 void	stic_eraserows(void *, int, int, long);
    185 int	stic_mapchar(void *, int, u_int *);
    186 void	stic_putchar(void *, int, int, u_int, long);
    187 int	stic_alloc_attr(void *, int, int, int, long *);
    188 
    189 /* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity. */
    190 static const u_int8_t stic_cmap[16*3] = {
    191 	0x00, 0x00, 0x00, /* black */
    192 	0x7f, 0x00, 0x00, /* red */
    193 	0x00, 0x7f, 0x00, /* green */
    194 	0x7f, 0x7f, 0x00, /* brown */
    195 	0x00, 0x00, 0x7f, /* blue */
    196 	0x7f, 0x00, 0x7f, /* magenta */
    197 	0x00, 0x7f, 0x7f, /* cyan */
    198 	0xc7, 0xc7, 0xc7, /* white */
    199 
    200 	0x7f, 0x7f, 0x7f, /* black */
    201 	0xff, 0x00, 0x00, /* red */
    202 	0x00, 0xff, 0x00, /* green */
    203 	0xff, 0xff, 0x00, /* brown */
    204 	0x00, 0x00, 0xff, /* blue */
    205 	0xff, 0x00, 0xff, /* magenta */
    206 	0x00, 0xff, 0xff, /* cyan */
    207 	0xff, 0xff, 0xff, /* white */
    208 };
    209 
    210 /*
    211  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    212  *   M M M M I I I I		M I M I M I M I
    213  *	[ before ]		   [ after ]
    214  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    215  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    216  */
    217 static const u_int8_t shuffle[256] = {
    218 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    219 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    220 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    221 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    222 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    223 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    224 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    225 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    226 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    227 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    228 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    229 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    230 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    231 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    232 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    233 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    234 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    235 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    236 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    237 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    238 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    239 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    240 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    241 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    242 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    243 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    244 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    245 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    246 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    247 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    248 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    249 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    250 };
    251 
    252 static const struct wsdisplay_accessops stic_accessops = {
    253 	sticioctl,
    254 	NULL,			/* mmap */
    255 	stic_alloc_screen,
    256 	stic_free_screen,
    257 	stic_show_screen,
    258 	NULL,			/* load_font */
    259 };
    260 
    261 static const struct wsdisplay_emulops stic_emulops = {
    262 	stic_cursor,
    263 	stic_mapchar,
    264 	stic_putchar,
    265 	stic_copycols,
    266 	stic_erasecols,
    267 	stic_copyrows,
    268 	stic_eraserows,
    269 	stic_alloc_attr
    270 };
    271 
    272 static struct wsscreen_descr stic_stdscreen = {
    273 	"std",
    274 	0, 0,
    275 	&stic_emulops,
    276 	0, 0,
    277 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT
    278 };
    279 
    280 static const struct wsscreen_descr *_stic_scrlist[] = {
    281 	&stic_stdscreen,
    282 };
    283 
    284 static const struct wsscreen_list stic_screenlist = {
    285 	sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist
    286 };
    287 
    288 struct	stic_info stic_consinfo;
    289 static struct	stic_screen stic_consscr;
    290 static struct	stic_info *stic_info[STIC_MAXDV];
    291 static int	stic_unit;
    292 
    293 void
    294 stic_init(struct stic_info *si)
    295 {
    296 	volatile u_int32_t *vdac;
    297 	int i, cookie;
    298 
    299 	/* Reset the STIC & stamp(s). */
    300 	stic_reset(si);
    301 	vdac = si->si_vdac;
    302 
    303 	/* Hit it... */
    304 	SELECT(vdac, BT459_IREG_COMMAND_0);
    305 	REG(vdac, bt_reg) = 0x00c0c0c0; tc_wmb();
    306 
    307 	/* Now reset the VDAC. */
    308 	*si->si_vdac_reset = 0;
    309 	tc_wmb();
    310 	tc_syncbus();
    311 	DELAY(1000);
    312 
    313 	/* Finish the initialization. */
    314 	SELECT(vdac, BT459_IREG_COMMAND_1);
    315 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    316 	REG(vdac, bt_reg) = 0x00c2c2c2; tc_wmb();
    317 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    318 
    319 	for (i = 0; i < 7; i++) {
    320 		REG(vdac, bt_reg) = 0x00000000;
    321 		tc_wmb();
    322 	}
    323 
    324 	/* Set cursor colormap. */
    325 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    326 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    327 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    328 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    329 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    330 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    331 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    332 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    333 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    334 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    335 
    336 	/* Get a font and set up screen metrics. */
    337 	wsfont_init();
    338 	cookie = wsfont_find(NULL, 0, 0, 0);
    339 
    340 	if (wsfont_lock(cookie, &si->si_font,
    341 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0)
    342 		panic("stic_init: couldn't lock font\n");
    343 
    344 	si->si_fontw = si->si_font->fontwidth;
    345 	si->si_fonth = si->si_font->fontheight;
    346 	si->si_consw = (1280 / si->si_fontw) & ~1;
    347 	si->si_consh = 1024 / si->si_fonth;
    348 	stic_stdscreen.ncols = si->si_consw;
    349 	stic_stdscreen.nrows = si->si_consh;
    350 
    351 #ifdef DIAGNOSTIC
    352 	if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
    353 		panic("stic_init: unusable font");
    354 #endif
    355 
    356 	stic_setup_vdac(si);
    357 	stic_clear_screen(si);
    358 	si->si_dispmode = WSDISPLAYIO_MODE_EMUL;
    359 }
    360 
    361 void
    362 stic_reset(struct stic_info *si)
    363 {
    364 	int modtype, xconfig, yconfig, config;
    365 	volatile struct stic_regs *sr;
    366 
    367 	sr = si->si_stic;
    368 
    369 	/*
    370 	 * Initialize the interface chip registers.
    371 	 */
    372 	sr->sr_sticsr = 0x00000030;	/* Get the STIC's attention. */
    373 	tc_wmb();
    374 	tc_syncbus();
    375 	DELAY(2000);			/* wait 2ms for STIC to respond. */
    376 	sr->sr_sticsr = 0x00000000;	/* Hit the STIC's csr again... */
    377 	tc_wmb();
    378 	sr->sr_buscsr = 0xffffffff;	/* and bash its bus-acess csr. */
    379 	tc_wmb();
    380 	tc_syncbus();			/* Blam! */
    381 	DELAY(20000);			/* wait until the stic recovers... */
    382 
    383 	modtype = sr->sr_modcl;
    384 	xconfig = (modtype & 0x800) >> 11;
    385 	yconfig = (modtype & 0x600) >> 9;
    386 	config = (yconfig << 1) | xconfig;
    387 	si->si_stampw = (xconfig ? 5 : 4);
    388 	si->si_stamph = (1 << yconfig);
    389 #ifdef notyet
    390 	si->si_option = (char)((modtype >> 12) & 3);
    391 #endif
    392 
    393 	/* First PixelStamp */
    394 	si->si_stamp[0x000b0] = config;
    395 	si->si_stamp[0x000b4] = 0x0;
    396 
    397 	/* Second PixelStamp */
    398 	if (yconfig > 0) {
    399 		si->si_stamp[0x100b0] = config | 8;
    400 		si->si_stamp[0x100b4] = 0;
    401 	}
    402 
    403 	/*
    404 	 * Initialize STIC video registers.  Enable error and vertical
    405 	 * retrace interrupts.  Set the packet done flag so the Xserver will
    406 	 * not time-out on the first packet submitted.
    407 	 */
    408 	sr->sr_vblank = (1024 << 16) | 1063;
    409 	sr->sr_vsync = (1027 << 16) | 1030;
    410 	sr->sr_hblank = (255 << 16) | 340;
    411 	sr->sr_hsync2 = 245;
    412 	sr->sr_hsync = (261 << 16) | 293;
    413 	sr->sr_ipdvint =
    414 	    STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN;
    415 	sr->sr_sticsr = 8;
    416 	tc_wmb();
    417 	tc_syncbus();
    418 }
    419 
    420 void
    421 stic_attach(struct device *self, struct stic_info *si, int console)
    422 {
    423 	struct wsemuldisplaydev_attach_args waa;
    424 
    425 	if (stic_unit < STIC_MAXDV) {
    426 		stic_info[stic_unit] = si;
    427 		si->si_unit = stic_unit++;
    428 	} else
    429 		si->si_unit = -1;
    430 
    431 	callout_init(&si->si_switch_callout);
    432 
    433 	/*
    434 	 * Allocate backing for the console.  We could trawl back through
    435 	 * msgbuf and and fill the backing, but it's not worth the hassle.
    436 	 * We could also grab backing using pmap_steal_memory() early on,
    437 	 * but that's a little ugly.
    438 	 */
    439 	if (console)
    440 		stic_setup_backing(si, &stic_consscr);
    441 
    442 	waa.console = console;
    443 	waa.scrdata = &stic_screenlist;
    444 	waa.accessops = &stic_accessops;
    445 	waa.accesscookie = si;
    446 
    447 	config_found(self, &waa, wsemuldisplaydevprint);
    448 }
    449 
    450 void
    451 stic_cnattach(struct stic_info *si)
    452 {
    453 	struct stic_screen *ss;
    454 	long defattr;
    455 
    456 	ss = &stic_consscr;
    457 	si->si_curscreen = ss;
    458 	ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
    459 	ss->ss_si = si;
    460 
    461 	si->si_flags |= SI_CURENB_CHANGED;
    462 	stic_flush(si);
    463 
    464 	stic_alloc_attr(ss, 0, 0, 0, &defattr);
    465 	stic_eraserows(ss, 0, si->si_consh, 0);
    466 	wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
    467 }
    468 
    469 void
    470 stic_setup_vdac(struct stic_info *si)
    471 {
    472 	u_int8_t *ip, *mp;
    473 	int r, c, o, b, i, s;
    474 
    475 	s = spltty();
    476 
    477 	ip = (u_int8_t *)si->si_cursor.cc_image;
    478 	mp = ip + (sizeof(si->si_cursor.cc_image) >> 1);
    479 	memset(ip, 0, sizeof(si->si_cursor.cc_image));
    480 
    481 	for (r = 0; r < si->si_fonth; r++) {
    482 		for (c = r & 1; c < si->si_fontw; c += 2) {
    483 			o = c >> 3;
    484 			b = 1 << (c & 7);
    485 			ip[o] |= b;
    486 			mp[o] |= b;
    487 		}
    488 
    489 		ip += 8;
    490 		mp += 8;
    491 	}
    492 
    493 	si->si_cursor.cc_size.x = 64;
    494 	si->si_cursor.cc_size.y = si->si_fonth;
    495 	si->si_cursor.cc_hot.x = 0;
    496 	si->si_cursor.cc_hot.y = 0;
    497 
    498 	si->si_cursor.cc_color[0] = 0xff;
    499 	si->si_cursor.cc_color[2] = 0xff;
    500 	si->si_cursor.cc_color[4] = 0xff;
    501 	si->si_cursor.cc_color[1] = 0x00;
    502 	si->si_cursor.cc_color[3] = 0x00;
    503 	si->si_cursor.cc_color[5] = 0x00;
    504 
    505 	memset(&si->si_cmap, 0, sizeof(si->si_cmap));
    506 	for (i = 0; i < 16; i++) {
    507 		si->si_cmap.r[i] = stic_cmap[i*3 + 0];
    508 		si->si_cmap.g[i] = stic_cmap[i*3 + 1];
    509 		si->si_cmap.b[i] = stic_cmap[i*3 + 2];
    510 	}
    511 
    512 	si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
    513 	    SI_CURCMAP_CHANGED;
    514 
    515 	splx(s);
    516 }
    517 
    518 void
    519 stic_clear_screen(struct stic_info *si)
    520 {
    521 	u_int32_t *pb;
    522 	int i;
    523 
    524 	/*
    525 	 * Do this twice, since the first packet after a reset may be
    526 	 * silently ignored.
    527 	 */
    528 	for (i = 0; i < 2; i++) {
    529 		pb = (*si->si_pbuf_get)(si);
    530 
    531 		pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    532 		pb[1] = 0x01ffffff;
    533 		pb[2] = 0;
    534 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    535 		pb[4] = (1024 << 2) - 1;
    536 		pb[5] = 0;
    537 		pb[6] = 0;
    538 		pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]);
    539 
    540 		(*si->si_pbuf_post)(si, pb);
    541 	}
    542 }
    543 
    544 int
    545 sticioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
    546 {
    547 	struct stic_info *si;
    548 
    549 	si = v;
    550 
    551 	switch (cmd) {
    552 	case WSDISPLAYIO_GTYPE:
    553 		*(u_int *)data = si->si_disptype;
    554 		return (0);
    555 
    556 	case WSDISPLAYIO_GINFO:
    557 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    558 		wsd_fbip->height = 1024;
    559 		wsd_fbip->width = 1280;
    560 		wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
    561 		wsd_fbip->cmsize = CMAP_SIZE;
    562 #undef fbt
    563 		return (0);
    564 
    565 	case WSDISPLAYIO_GETCMAP:
    566 		return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
    567 
    568 	case WSDISPLAYIO_PUTCMAP:
    569 		return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
    570 
    571 	case WSDISPLAYIO_SVIDEO:
    572 #if 0 /* XXX later */
    573 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    574 		if ((si->si_blanked == 0) ^ turnoff)
    575 			si->si_blanked = turnoff;
    576 #endif
    577 		return (0);
    578 
    579 	case WSDISPLAYIO_GVIDEO:
    580 #if 0 /* XXX later */
    581 		*(u_int *)data = si->si_blanked ?
    582 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    583 #endif
    584 		return (0);
    585 
    586 	case WSDISPLAYIO_GCURPOS:
    587 		*(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
    588 		return (0);
    589 
    590 	case WSDISPLAYIO_SCURPOS:
    591 		stic_set_curpos(si, (struct wsdisplay_curpos *)data);
    592 		return (0);
    593 
    594 	case WSDISPLAYIO_GCURMAX:
    595 		((struct wsdisplay_curpos *)data)->x =
    596 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    597 		return (0);
    598 
    599 	case WSDISPLAYIO_GCURSOR:
    600 		return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
    601 
    602 	case WSDISPLAYIO_SCURSOR:
    603 		return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
    604 
    605 	case WSDISPLAYIO_SMODE:
    606 		si->si_dispmode = *(int *)data;
    607 		if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) {
    608 			(*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, p);
    609 			stic_setup_vdac(si);
    610 			stic_flush(si);
    611 			stic_clear_screen(si);
    612 			stic_do_switch(si->si_curscreen);
    613 		}
    614 		return (0);
    615 
    616 	case STICIO_RESET:
    617 		stic_reset(si);
    618 		return (0);
    619 	}
    620 
    621 	if (si->si_ioctl != NULL)
    622 		return ((*si->si_ioctl)(si, cmd, data, flag, p));
    623 
    624 	return (ENOTTY);
    625 }
    626 
    627 void
    628 stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
    629 {
    630 	int size;
    631 
    632 	size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
    633 	ss->ss_backing = malloc(size, M_DEVBUF, M_NOWAIT);
    634 	memset(ss->ss_backing, 0, size);
    635 }
    636 
    637 int
    638 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    639 		  int *curxp, int *curyp, long *attrp)
    640 {
    641 	struct stic_info *si;
    642 	struct stic_screen *ss;
    643 
    644 	si = (struct stic_info *)v;
    645 
    646 	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
    647 		ss = &stic_consscr;
    648 	else {
    649 		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK);
    650 		memset(ss, 0, sizeof(*ss));
    651 	}
    652 	stic_setup_backing(si, ss);
    653 
    654 	ss->ss_si = si;
    655 	ss->ss_flags = SS_ALLOCED | SS_CURENB;
    656 
    657 	*cookiep = ss;
    658 	*curxp = 0;
    659 	*curyp = 0;
    660 
    661 	stic_alloc_attr(ss, 0, 0, 0, attrp);
    662 	return (0);
    663 }
    664 
    665 void
    666 stic_free_screen(void *v, void *cookie)
    667 {
    668 	struct stic_screen *ss;
    669 
    670 	ss = cookie;
    671 
    672 #ifdef DIAGNOSTIC
    673 	if (ss == &stic_consscr)
    674 		panic("stic_free_screen: console");
    675 	if (ss == ((struct stic_info *)v)->si_curscreen)
    676 		panic("stic_free_screen: freeing current screen");
    677 #endif
    678 
    679 	free(ss->ss_backing, M_DEVBUF);
    680 	free(ss, M_DEVBUF);
    681 }
    682 
    683 int
    684 stic_show_screen(void *v, void *cookie, int waitok,
    685 		 void (*cb)(void *, int, int), void *cbarg)
    686 {
    687 	struct stic_info *si;
    688 
    689 	si = (struct stic_info *)v;
    690 	if (si->si_switchcbarg != NULL)
    691 		return (EAGAIN);
    692 	si->si_switchcb = cb;
    693 	si->si_switchcbarg = cbarg;
    694 
    695 	if (cb != NULL) {
    696 		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
    697 		    cookie);
    698 		return (EAGAIN);
    699 	}
    700 
    701 	stic_do_switch(cookie);
    702 	return (0);
    703 }
    704 
    705 void
    706 stic_do_switch(void *cookie)
    707 {
    708 	struct stic_screen *ss;
    709 	struct stic_info *si;
    710 	u_int r, c, nr, nc;
    711 	u_int16_t *p, *sp;
    712 
    713 	ss = cookie;
    714 	si = ss->ss_si;
    715 
    716 #ifdef DIAGNOSTIC
    717 	if (ss->ss_backing == NULL)
    718 		panic("stic_do_switch: screen not backed");
    719 #endif
    720 
    721 	/* Swap in the new screen, and temporarily disable its backing. */
    722 	if (si->si_curscreen != NULL)
    723 		si->si_curscreen->ss_flags ^= SS_ACTIVE;
    724 	si->si_curscreen = ss;
    725 	ss->ss_flags |= SS_ACTIVE;
    726 	sp = ss->ss_backing;
    727 	ss->ss_backing = NULL;
    728 
    729 	/*
    730 	 * We assume that most of the screen is blank and blast it with
    731 	 * eraserows(), because eraserows() is cheap.
    732 	 */
    733 	nr = si->si_consh;
    734 	stic_eraserows(ss, 0, nr, 0);
    735 
    736 	nc = si->si_consw;
    737 	p = sp;
    738 	for (r = 0; r < nr; r++)
    739 		for (c = 0; c < nc; c += 2, p += 2) {
    740 			if ((p[0] & 0xfff0) != 0)
    741 				stic_putchar(ss, r, c, p[0] >> 8,
    742 				    p[0] & 0x00ff);
    743 			if ((p[1] & 0xfff0) != 0)
    744 				stic_putchar(ss, r, c + 1, p[1] >> 8,
    745 				    p[1] & 0x00ff);
    746 		}
    747 
    748 	/*
    749 	 * Re-enable the screen's backing, and move the cursor to the
    750 	 * correct spot.
    751 	 */
    752 	ss->ss_backing = sp;
    753 	si->si_cursor.cc_pos.x = ss->ss_curx;
    754 	si->si_cursor.cc_pos.y = ss->ss_cury;
    755 	stic_set_hwcurpos(si);
    756 	si->si_flags |= SI_CURENB_CHANGED;
    757 
    758 	/*
    759 	 * XXX Since we don't yet receive vblank interrupts from the
    760 	 * PXG, we must flush immediatley.
    761 	 */
    762 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
    763 		stic_flush(si);
    764 
    765 	/* Tell wscons that we're done. */
    766 	if (si->si_switchcbarg != NULL) {
    767 		cookie = si->si_switchcbarg;
    768 		si->si_switchcbarg = NULL;
    769 		(*si->si_switchcb)(cookie, 0, 0);
    770 	}
    771 }
    772 
    773 int
    774 stic_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
    775 {
    776 	long tmp;
    777 
    778 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
    779 		return (EINVAL);
    780 
    781 	if ((flags & WSATTR_WSCOLORS) == 0) {
    782 		fg = 7;
    783 		bg = 0;
    784 	}
    785 
    786 	if ((flags & WSATTR_HILIT) != 0)
    787 		fg += 8;
    788 
    789 	tmp = fg | (bg << 4);
    790 	*attr = tmp | (tmp << 16);
    791 	return (0);
    792 }
    793 
    794 void
    795 stic_erasecols(void *cookie, int row, int col, int num, long attr)
    796 {
    797 	struct stic_info *si;
    798 	struct stic_screen *ss;
    799 	u_int32_t *pb;
    800 	u_int i, linewidth;
    801 	u_int16_t *p;
    802 
    803 	ss = cookie;
    804 	si = ss->ss_si;
    805 
    806 	if (ss->ss_backing != NULL) {
    807 		p = ss->ss_backing + row * si->si_consw + col;
    808 		for (i = num; i != 0; i--)
    809 			*p++ = (u_int16_t)attr;
    810 	}
    811 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    812 		return;
    813 
    814 	col = (col * si->si_fontw) << 19;
    815 	num = (num * si->si_fontw) << 19;
    816 	row = row * si->si_fonth;
    817 	attr = (attr & 0xf0) >> 4;
    818 	linewidth = (si->si_fonth << 2) - 1;
    819 	row = (row << 3) + linewidth;
    820 
    821 	pb = (*si->si_pbuf_get)(si);
    822 
    823 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    824 	pb[1] = 0x01ffffff;
    825 	pb[2] = 0;
    826 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    827 	pb[4] = linewidth;
    828 	pb[5] = DUPBYTE0(attr);
    829 	pb[6] = col | row;
    830 	pb[7] = (col + num) | row;
    831 
    832 	(*si->si_pbuf_post)(si, pb);
    833 }
    834 
    835 void
    836 stic_eraserows(void *cookie, int row, int num, long attr)
    837 {
    838 	struct stic_info *si;
    839 	struct stic_screen *ss;
    840 	u_int linewidth, i;
    841 	u_int32_t *pb;
    842 
    843 	ss = cookie;
    844 	si = ss->ss_si;
    845 
    846 	if (ss->ss_backing != NULL) {
    847 		pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
    848 		for (i = si->si_consw * num; i > 0; i -= 2)
    849 			*pb++ = (u_int32_t)attr;
    850 	}
    851 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    852 		return;
    853 
    854 	row *= si->si_fonth;
    855 	num *= si->si_fonth;
    856 	attr = (attr & 0xf0) >> 4;
    857 	linewidth = (num << 2) - 1;
    858 	row = (row << 3) + linewidth;
    859 
    860 	pb = (*si->si_pbuf_get)(si);
    861 
    862 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    863 	pb[1] = 0x01ffffff;
    864 	pb[2] = 0;
    865 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    866 	pb[4] = linewidth;
    867 	pb[5] = DUPBYTE0(attr);
    868 	pb[6] = row;
    869 	pb[7] = (1280 << 19) | row;
    870 
    871 	(*si->si_pbuf_post)(si, pb);
    872 }
    873 
    874 void
    875 stic_copyrows(void *cookie, int src, int dst, int height)
    876 {
    877 	struct stic_info *si;
    878 	struct stic_screen *ss;
    879 	u_int32_t *pb, *pbs;
    880 	u_int num, inc, adj;
    881 
    882 	ss = cookie;
    883 	si = ss->ss_si;
    884 
    885 	if (ss->ss_backing != NULL)
    886 		bcopy(ss->ss_backing + src * si->si_consw,
    887 		    ss->ss_backing + dst * si->si_consw,
    888 		    si->si_consw * sizeof(*ss->ss_backing) * height);
    889 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    890 		return;
    891 
    892 	/*
    893 	 * We need to do this in reverse if the destination row is below
    894 	 * the source.
    895 	 */
    896 	if (dst > src) {
    897 		src += height;
    898 		dst += height;
    899 		inc = -8;
    900 		adj = -1;
    901 	} else {
    902 		inc = 8;
    903 		adj = 0;
    904 	}
    905 
    906 	src = (src * si->si_fonth + adj) << 3;
    907 	dst = (dst * si->si_fonth + adj) << 3;
    908 	height *= si->si_fonth;
    909 
    910 	while (height > 0) {
    911 		num = (height < 255 ? height : 255);
    912 		height -= num;
    913 
    914 		pbs = (*si->si_pbuf_get)(si);
    915 		pb = pbs;
    916 
    917 		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    918 		pb[1] = (num << 24) | 0xffffff;
    919 		pb[2] = 0x0;
    920 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
    921 		    STAMP_COPYSPAN_ALIGNED;
    922 		pb[4] = 1; /* linewidth */
    923 
    924 		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
    925 			pb[5] = 1280 << 3;
    926 			pb[6] = src;
    927 			pb[7] = dst;
    928 		}
    929 
    930 	    	(*si->si_pbuf_post)(si, pbs);
    931 	}
    932 }
    933 
    934 void
    935 stic_copycols(void *cookie, int row, int src, int dst, int num)
    936 {
    937 	struct stic_info *si;
    938 	struct stic_screen *ss;
    939 	u_int height, updword;
    940 	u_int32_t *pb, *pbs;
    941 
    942 	ss = cookie;
    943 	si = ss->ss_si;
    944 
    945 	if (ss->ss_backing != NULL)
    946 		bcopy(ss->ss_backing + row * si->si_consw + src,
    947 		    ss->ss_backing + row * si->si_consw + dst,
    948 		    num * sizeof(*ss->ss_backing));
    949 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    950 		return;
    951 
    952 	/*
    953 	 * The stamp reads and writes left -> right only, so we need to
    954 	 * buffer the span if the source and destination regions overlap
    955 	 * and the source is left of the destination.
    956 	 */
    957 	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
    958 
    959 	if (src < dst && src + num > dst)
    960 		updword |= STAMP_HALF_BUFF;
    961 
    962 	row = (row * si->si_fonth) << 3;
    963 	num = (num * si->si_fontw) << 3;
    964 	src = row | ((src * si->si_fontw) << 19);
    965 	dst = row | ((dst * si->si_fontw) << 19);
    966 	height = si->si_fonth;
    967 
    968 	pbs = (*si->si_pbuf_get)(si);
    969 	pb = pbs;
    970 
    971 	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    972 	pb[1] = (height << 24) | 0xffffff;
    973 	pb[2] = 0x0;
    974 	pb[3] = updword;
    975 	pb[4] = 1; /* linewidth */
    976 
    977 	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
    978 		pb[5] = num;
    979 		pb[6] = src;
    980 		pb[7] = dst;
    981 	}
    982 
    983 	(*si->si_pbuf_post)(si, pbs);
    984 }
    985 
    986 void
    987 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
    988 {
    989 	struct wsdisplay_font *font;
    990 	struct stic_screen *ss;
    991 	struct stic_info *si;
    992 	u_int i, bgcolor, fgcolor;
    993 	u_int *pb, v1, v2, xya;
    994 	u_short *fr;
    995 
    996 	ss = cookie;
    997 	si = ss->ss_si;
    998 
    999 	/* It's cheaper to use erasecols() to blit blanks. */
   1000 	if (uc == 0) {
   1001 		stic_erasecols(cookie, r, c, 1, attr);
   1002 		return;
   1003 	}
   1004 
   1005 	if (ss->ss_backing != NULL)
   1006 		ss->ss_backing[r * si->si_consw + c] =
   1007 		    (u_short)((attr & 0xff) | (uc << 8));
   1008 	if ((ss->ss_flags & SS_ACTIVE) == 0)
   1009 		return;
   1010 
   1011 	font = si->si_font;
   1012 	pb = (*si->si_pbuf_get)(si);
   1013 
   1014 	/*
   1015 	 * Create a mask from the glyph.  Squeeze the foreground color
   1016 	 * through the mask, and then squeeze the background color through
   1017 	 * the inverted mask.  We may well read outside the glyph when
   1018 	 * creating the mask, but it's bounded by the hardware so it
   1019 	 * shouldn't matter a great deal...
   1020 	 */
   1021 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
   1022 	    STAMP_LW_PERPRIMATIVE;
   1023 	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
   1024 	pb[2] = 0x0;
   1025 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
   1026 
   1027 	r *= font->fontheight;
   1028 	c *= font->fontwidth;
   1029 	uc = (uc - font->firstchar) * font->stride * font->fontheight;
   1030 	fr = (u_short *)((caddr_t)font->data + uc);
   1031 	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
   1032 	fgcolor = DUPBYTE0(attr & 0x0f);
   1033 
   1034 	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
   1035 	v1 = (c << 19) | ((r << 3) + i);
   1036 	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1037 	xya = XYMASKADDR(si->si_stampw, si->si_stamph, c, r, 0, 0);
   1038 
   1039 	pb[4] = PACK(fr, 0);
   1040 	pb[5] = PACK(fr, 2);
   1041 	pb[6] = PACK(fr, 4);
   1042 	pb[7] = PACK(fr, 6);
   1043 	pb[8] = PACK(fr, 8);
   1044 	pb[9] = PACK(fr, 10);
   1045 	pb[10] = PACK(fr, 12);
   1046 	pb[11] = PACK(fr, 14);
   1047 	pb[12] = xya;
   1048 	pb[13] = v1;
   1049 	pb[14] = v2;
   1050 	pb[15] = i;
   1051 	pb[16] = fgcolor;
   1052 
   1053 	pb[17] = ~pb[4];
   1054 	pb[18] = ~pb[5];
   1055 	pb[19] = ~pb[6];
   1056 	pb[20] = ~pb[7];
   1057 	pb[21] = ~pb[8];
   1058 	pb[22] = ~pb[9];
   1059 	pb[23] = ~pb[10];
   1060 	pb[24] = ~pb[11];
   1061 	pb[25] = xya;
   1062 	pb[26] = v1;
   1063 	pb[27] = v2;
   1064 	pb[28] = i;
   1065 	pb[29] = bgcolor;
   1066 
   1067 	/* Two more squeezes for the lower part of the character. */
   1068 	if (font->fontheight > 16) {
   1069 		i = ((font->fontheight - 16) << 2) - 1;
   1070 		r += 16;
   1071 		v1 = (c << 19) | ((r << 3) + i);
   1072 		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1073 
   1074 		pb[30] = PACK(fr, 16);
   1075 		pb[31] = PACK(fr, 18);
   1076 		pb[32] = PACK(fr, 20);
   1077 		pb[33] = PACK(fr, 22);
   1078 		pb[34] = PACK(fr, 24);
   1079 		pb[35] = PACK(fr, 26);
   1080 		pb[36] = PACK(fr, 28);
   1081 		pb[37] = PACK(fr, 30);
   1082 		pb[38] = xya;
   1083 		pb[39] = v1;
   1084 		pb[40] = v2;
   1085 		pb[41] = i;
   1086 		pb[42] = fgcolor;
   1087 
   1088 		pb[43] = ~pb[30];
   1089 		pb[44] = ~pb[31];
   1090 		pb[45] = ~pb[32];
   1091 		pb[46] = ~pb[33];
   1092 		pb[47] = ~pb[34];
   1093 		pb[48] = ~pb[35];
   1094 		pb[49] = ~pb[36];
   1095 		pb[50] = ~pb[37];
   1096 		pb[51] = xya;
   1097 		pb[52] = v1;
   1098 		pb[53] = v2;
   1099 		pb[54] = i;
   1100 		pb[55] = bgcolor;
   1101 	}
   1102 
   1103 	(*si->si_pbuf_post)(si, pb);
   1104 }
   1105 
   1106 int
   1107 stic_mapchar(void *cookie, int c, u_int *cp)
   1108 {
   1109 	struct stic_info *si;
   1110 
   1111 	si = ((struct stic_screen *)cookie)->ss_si;
   1112 
   1113 	if (c < si->si_font->firstchar || c == ' ') {
   1114 		*cp = 0;
   1115 		return (0);
   1116 	}
   1117 
   1118 	if (c - si->si_font->firstchar >= si->si_font->numchars) {
   1119 		*cp = 0;
   1120 		return (0);
   1121 	}
   1122 
   1123 	*cp = c;
   1124 	return (5);
   1125 }
   1126 
   1127 void
   1128 stic_cursor(void *cookie, int on, int row, int col)
   1129 {
   1130 	struct stic_screen *ss;
   1131 	struct stic_info *si;
   1132 	int s;
   1133 
   1134 	ss = cookie;
   1135 	si = ss->ss_si;
   1136 
   1137 	ss->ss_curx = col * si->si_fontw;
   1138 	ss->ss_cury = row * si->si_fonth;
   1139 
   1140 	s = spltty();
   1141 
   1142 	if (on)
   1143 		ss->ss_flags |= SS_CURENB;
   1144 	else
   1145 		ss->ss_flags &= ~SS_CURENB;
   1146 
   1147 	if ((ss->ss_flags & SS_ACTIVE) != 0) {
   1148 		si->si_cursor.cc_pos.x = ss->ss_curx;
   1149 		si->si_cursor.cc_pos.y = ss->ss_cury;
   1150 		si->si_flags |= SI_CURENB_CHANGED;
   1151 		stic_set_hwcurpos(si);
   1152 
   1153 		/*
   1154 		 * XXX Since we don't yet receive vblank interrupts from the
   1155 		 * PXG, we must flush immediatley.
   1156 		 */
   1157 		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1158 			stic_flush(si);
   1159 	}
   1160 
   1161 	splx(s);
   1162 }
   1163 
   1164 void
   1165 stic_flush(struct stic_info *si)
   1166 {
   1167 	volatile u_int32_t *vdac;
   1168 	int v;
   1169 
   1170 	if ((si->si_flags & SI_ALL_CHANGED) == 0)
   1171 		return;
   1172 
   1173 	vdac = si->si_vdac;
   1174 	v = si->si_flags;
   1175 	si->si_flags &= ~SI_ALL_CHANGED;
   1176 
   1177 	if ((v & SI_CURENB_CHANGED) != 0) {
   1178 		SELECT(vdac, BT459_IREG_CCR);
   1179 		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
   1180 			REG(vdac, bt_reg) = 0x00c0c0c0;
   1181 		else
   1182 			REG(vdac, bt_reg) = 0x00000000;
   1183 		tc_wmb();
   1184 	}
   1185 
   1186 	if ((v & SI_CURCMAP_CHANGED) != 0) {
   1187 		u_int8_t *cp;
   1188 
   1189 		cp = si->si_cursor.cc_color;
   1190 
   1191 		SELECT(vdac, BT459_IREG_CCOLOR_2);
   1192 		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
   1193 		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
   1194 		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
   1195 		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
   1196 		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
   1197 		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
   1198 	}
   1199 
   1200 	if ((v & SI_CURSHAPE_CHANGED) != 0) {
   1201 		u_int8_t *ip, *mp, img, msk;
   1202 		u_int8_t u;
   1203 		int bcnt;
   1204 
   1205 		ip = (u_int8_t *)si->si_cursor.cc_image;
   1206 		mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
   1207 
   1208 		bcnt = 0;
   1209 		SELECT(vdac, BT459_IREG_CRAM_BASE);
   1210 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
   1211 		while (bcnt < CURSOR_MAX_SIZE * 16) {
   1212 			img = *ip++;
   1213 			msk = *mp++;
   1214 			img &= msk;	/* cookie off image */
   1215 			u = (msk & 0x0f) << 4 | (img & 0x0f);
   1216 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1217 			tc_wmb();
   1218 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
   1219 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1220 			tc_wmb();
   1221 			bcnt += 2;
   1222 		}
   1223 	}
   1224 
   1225 	if ((v & SI_CMAP_CHANGED) != 0) {
   1226 		struct stic_hwcmap256 *cm;
   1227 		int index;
   1228 
   1229 		cm = &si->si_cmap;
   1230 
   1231 		SELECT(vdac, 0);
   1232 		SELECT(vdac, 0);
   1233 		for (index = 0; index < CMAP_SIZE; index++) {
   1234 			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
   1235 			tc_wmb();
   1236 			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
   1237 			tc_wmb();
   1238 			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
   1239 			tc_wmb();
   1240 		}
   1241 	}
   1242 }
   1243 
   1244 int
   1245 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1246 {
   1247 	u_int index, count;
   1248 
   1249 	index = p->index;
   1250 	count = p->count;
   1251 
   1252 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
   1253 		return (EINVAL);
   1254 
   1255 	if (!uvm_useracc(p->red, count, B_WRITE) ||
   1256 	    !uvm_useracc(p->green, count, B_WRITE) ||
   1257 	    !uvm_useracc(p->blue, count, B_WRITE))
   1258 		return (EFAULT);
   1259 
   1260 	copyout(&si->si_cmap.r[index], p->red, count);
   1261 	copyout(&si->si_cmap.g[index], p->green, count);
   1262 	copyout(&si->si_cmap.b[index], p->blue, count);
   1263 	return (0);
   1264 }
   1265 
   1266 int
   1267 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1268 {
   1269 	u_int index, count;
   1270 	int s;
   1271 
   1272 	index = p->index;
   1273 	count = p->count;
   1274 
   1275 	if ((index + count) > CMAP_SIZE)
   1276 		return (EINVAL);
   1277 
   1278 	if (!uvm_useracc(p->red, count, B_READ) ||
   1279 	    !uvm_useracc(p->green, count, B_READ) ||
   1280 	    !uvm_useracc(p->blue, count, B_READ))
   1281 		return (EFAULT);
   1282 
   1283 	s = spltty();
   1284 	copyin(p->red, &si->si_cmap.r[index], count);
   1285 	copyin(p->green, &si->si_cmap.g[index], count);
   1286 	copyin(p->blue, &si->si_cmap.b[index], count);
   1287 	si->si_flags |= SI_CMAP_CHANGED;
   1288 	splx(s);
   1289 
   1290 	/*
   1291 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1292 	 * must flush immediatley.
   1293 	 */
   1294 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1295 		stic_flush(si);
   1296 
   1297 	return (0);
   1298 }
   1299 
   1300 int
   1301 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1302 {
   1303 #define	cc (&si->si_cursor)
   1304 	u_int v, index, count, icount;
   1305 	struct stic_screen *ss;
   1306 	int s;
   1307 
   1308 	v = p->which;
   1309 	ss = si->si_curscreen;
   1310 
   1311 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1312 		index = p->cmap.index;
   1313 		count = p->cmap.count;
   1314 		if (index >= 2 || (index + count) > 2)
   1315 			return (EINVAL);
   1316 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
   1317 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
   1318 		    !uvm_useracc(p->cmap.blue, count, B_READ))
   1319 			return (EFAULT);
   1320 	}
   1321 
   1322 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1323 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
   1324 			return (EINVAL);
   1325 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
   1326 		if (!uvm_useracc(p->image, icount, B_READ) ||
   1327 		    !uvm_useracc(p->mask, icount, B_READ))
   1328 			return (EFAULT);
   1329 	}
   1330 
   1331 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
   1332 		if (v & WSDISPLAY_CURSOR_DOCUR)
   1333 			cc->cc_hot = p->hot;
   1334 		if (v & WSDISPLAY_CURSOR_DOPOS)
   1335 			stic_set_curpos(si, &p->pos);
   1336 	}
   1337 
   1338 	s = spltty();
   1339 
   1340 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
   1341 		if (p->enable)
   1342 			ss->ss_flags |= SS_CURENB;
   1343 		else
   1344 			ss->ss_flags &= ~SS_CURENB;
   1345 		si->si_flags |= SI_CURENB_CHANGED;
   1346 	}
   1347 
   1348 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1349 		copyin(p->cmap.red, &cc->cc_color[index], count);
   1350 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
   1351 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
   1352 		si->si_flags |= SI_CURCMAP_CHANGED;
   1353 	}
   1354 
   1355 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1356 		memset(cc->cc_image, 0, sizeof(cc->cc_image));
   1357 		copyin(p->image, cc->cc_image, icount);
   1358 		copyin(p->mask, cc->cc_image + CURSOR_MAX_SIZE, icount);
   1359 		si->si_flags |= SI_CURSHAPE_CHANGED;
   1360 	}
   1361 
   1362 	splx(s);
   1363 
   1364 	/*
   1365 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1366 	 * must flush immediatley.
   1367 	 */
   1368 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1369 		stic_flush(si);
   1370 
   1371 	return (0);
   1372 #undef cc
   1373 }
   1374 
   1375 int
   1376 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1377 {
   1378 
   1379 	/* XXX */
   1380 	return (ENOTTY);
   1381 }
   1382 
   1383 void
   1384 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
   1385 {
   1386 	int x, y;
   1387 
   1388 	x = curpos->x;
   1389 	y = curpos->y;
   1390 
   1391 	if (y < 0)
   1392 		y = 0;
   1393 	else if (y > 1023)
   1394 		y = 1023;
   1395 	if (x < 0)
   1396 		x = 0;
   1397 	else if (x > 1279)
   1398 		x = 1279;
   1399 
   1400 	si->si_cursor.cc_pos.x = x;
   1401 	si->si_cursor.cc_pos.y = y;
   1402 	stic_set_hwcurpos(si);
   1403 }
   1404 
   1405 void
   1406 stic_set_hwcurpos(struct stic_info *si)
   1407 {
   1408 	volatile u_int32_t *vdac;
   1409 	int x, y, s;
   1410 
   1411 	vdac = si->si_vdac;
   1412 
   1413 	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
   1414 	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
   1415 	x += STIC_MAGIC_X;
   1416 	y += STIC_MAGIC_Y;
   1417 
   1418 	s = spltty();
   1419 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
   1420 	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
   1421 	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
   1422 	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
   1423 	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
   1424 	splx(s);
   1425 }
   1426 
   1427 /*
   1428  * STIC control inteface.  We have a seperate device for mapping the board,
   1429  * because access to the DMA engine means that it's possible to circumvent
   1430  * the securelevel mechanism.  Given the way devices work in the BSD kernel,
   1431  * and given the unfortunate design of the mmap() call it's near impossible
   1432  * to protect against this using a shared device (i.e. wsdisplay).
   1433  *
   1434  * This is a gross hack... Hopefully not too many other devices will need
   1435  * it.
   1436  */
   1437 int
   1438 sticopen(dev_t dev, int flag, int mode, struct proc *p)
   1439 {
   1440 	struct stic_info *si;
   1441 	int s;
   1442 
   1443 	if (securelevel > 0)
   1444 		return (EPERM);
   1445 	if (minor(dev) >= STIC_MAXDV)
   1446 		return (ENXIO);
   1447 	if ((si = stic_info[minor(dev)]) == NULL)
   1448 		return (ENXIO);
   1449 
   1450 	s = spltty();
   1451 	if ((si->si_flags & SI_DVOPEN) != 0) {
   1452 		splx(s);
   1453 		return (EBUSY);
   1454 	}
   1455 	si->si_flags |= SI_DVOPEN;
   1456 	splx(s);
   1457 
   1458 	return (0);
   1459 }
   1460 
   1461 int
   1462 sticclose(dev_t dev, int flag, int mode, struct proc *p)
   1463 {
   1464 	struct stic_info *si;
   1465 	int s;
   1466 
   1467 	si = stic_info[minor(dev)];
   1468 	s = spltty();
   1469 	si->si_flags &= ~SI_DVOPEN;
   1470 	splx(s);
   1471 
   1472 	return (0);
   1473 }
   1474 
   1475 paddr_t
   1476 sticmmap(dev_t dev, off_t offset, int prot)
   1477 {
   1478 	struct stic_info *si;
   1479 	struct stic_xmap *sxm;
   1480 	paddr_t pa;
   1481 
   1482 	si = stic_info[minor(dev)];
   1483 	sxm = NULL;
   1484 
   1485 	if (securelevel > 0)
   1486 		return (-1L);
   1487 	if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
   1488 		return (-1L);
   1489 
   1490 	if (offset < 0)
   1491 		return ((paddr_t)-1L);
   1492 
   1493 	if (offset < sizeof(sxm->sxm_stic)) {
   1494 		pa = STIC_KSEG_TO_PHYS(si->si_stic);
   1495 		return (machine_btop(pa + offset));
   1496 	}
   1497 	offset -= sizeof(sxm->sxm_stic);
   1498 
   1499 	if (offset < sizeof(sxm->sxm_poll)) {
   1500 		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
   1501 		return (machine_btop(pa + offset));
   1502 	}
   1503 	offset -= sizeof(sxm->sxm_poll);
   1504 
   1505 	if (offset < si->si_buf_size)
   1506 		return (machine_btop(si->si_buf_phys + offset));
   1507 
   1508 	return ((paddr_t)-1L);
   1509 }
   1510