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