Home | History | Annotate | Line # | Download | only in tc
stic.c revision 1.8
      1 /*	$NetBSD: stic.c,v 1.8 2001/03/04 13:32:25 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 
     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/vmparam.h>
     93 #include <machine/bus.h>
     94 #include <machine/intr.h>
     95 
     96 #include <dev/wscons/wsconsio.h>
     97 #include <dev/wscons/wsdisplayvar.h>
     98 
     99 #include <dev/wsfont/wsfont.h>
    100 
    101 #include <dev/ic/bt459reg.h>
    102 
    103 #include <dev/tc/tcvar.h>
    104 #include <dev/tc/sticreg.h>
    105 #include <dev/tc/sticvar.h>
    106 
    107 #define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff))
    108 #define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff))
    109 #define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff))
    110 
    111 #define PACK(p, o) ((p)[(o)] | ((p)[(o)+1] << 16))
    112 
    113 #if defined(pmax)
    114 #define	machine_btop(x)		mips_btop(x)
    115 #elif defined(alpha)
    116 #define machine_btop(x)		alpha_btop(x)
    117 #endif
    118 
    119 /*
    120  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
    121  * obscure register layout such as 2nd and 3rd Bt459 registers are
    122  * adjacent each other in a word, i.e.,
    123  *	struct bt459triplet {
    124  * 		struct {
    125  *			u_int8_t u0;
    126  *			u_int8_t u1;
    127  *			u_int8_t u2;
    128  *			unsigned :8;
    129  *		} bt_lo;
    130  *		struct {
    131  *
    132  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
    133  *	struct bt459reg {
    134  *		   u_int32_t	   bt_lo;
    135  *		   u_int32_t	   bt_hi;
    136  *		   u_int32_t	   bt_reg;
    137  *		   u_int32_t	   bt_cmap;
    138  *	};
    139  *
    140  */
    141 
    142 /* Bt459 hardware registers */
    143 #define bt_lo	0
    144 #define bt_hi	1
    145 #define bt_reg	2
    146 #define bt_cmap 3
    147 
    148 #define REG(base, index)	*((u_int32_t *)(base) + (index))
    149 #define SELECT(vdac, regno) do {		\
    150 	REG(vdac, bt_lo) = DUPBYTE0(regno);	\
    151 	REG(vdac, bt_hi) = DUPBYTE1(regno);	\
    152 	tc_wmb();				\
    153    } while (0)
    154 
    155 static int sticioctl(void *, u_long, caddr_t, int, struct proc *);
    156 static paddr_t sticmmap(void *, off_t, int);
    157 static int stic_alloc_screen(void *, const struct wsscreen_descr *,
    158 			     void **, int *, int *, long *);
    159 static void stic_free_screen(void *, void *);
    160 static int stic_show_screen(void *, void *, int,
    161 			    void (*) (void *, int, int), void *);
    162 static void stic_do_switch(void *);
    163 static void stic_setup_backing(struct stic_info *, struct stic_screen *);
    164 static void stic_setup_vdac(struct stic_info *si);
    165 
    166 static int stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *);
    167 static int stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *);
    168 static int stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *);
    169 static int stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *);
    170 static void stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *);
    171 static void stic_set_hwcurpos(struct stic_info *);
    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 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT
    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_wmb();
    297 
    298 	/* Now reset the VDAC. */
    299 	*si->si_vdac_reset = 0;
    300 	tc_wmb();
    301 	tc_syncbus();
    302 	DELAY(1000);
    303 
    304 	/* Finish the initalization. */
    305 	SELECT(vdac, BT459_IREG_COMMAND_1);
    306 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    307 	REG(vdac, bt_reg) = 0x00c2c2c2; tc_wmb();
    308 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    309 
    310 	for (i = 0; i < 7; i++) {
    311 		REG(vdac, bt_reg) = 0x00000000;
    312 		tc_wmb();
    313 	}
    314 
    315 	/* Set cursor colormap. */
    316 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    317 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    318 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    319 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    320 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    321 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    322 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
    323 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    324 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    325 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
    326 
    327 	/* Get a font and set up screen metrics. */
    328 	wsfont_init();
    329 	cookie = wsfont_find(NULL, 0, 0, 0);
    330 
    331 	if (wsfont_lock(cookie, &si->si_font,
    332 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0)
    333 		panic("stic_init: couldn't lock font\n");
    334 
    335 	si->si_fontw = si->si_font->fontwidth;
    336 	si->si_fonth = si->si_font->fontheight;
    337 	si->si_consw = (1280 / si->si_fontw) & ~1;
    338 	si->si_consh = 1024 / si->si_fonth;
    339 	stic_stdscreen.ncols = si->si_consw;
    340 	stic_stdscreen.nrows = si->si_consh;
    341 
    342 #ifdef DIAGNOSTIC
    343 	if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
    344 		panic("stic_init: unusable font");
    345 #endif
    346 
    347 	stic_setup_vdac(si);
    348 }
    349 
    350 void
    351 stic_reset(struct stic_info *si)
    352 {
    353 	int modtype, xconfig, yconfig, config;
    354 	volatile struct stic_regs *sr;
    355 
    356 	sr = si->si_stic;
    357 
    358 	/*
    359 	 * Initialize the interface chip registers.
    360 	 */
    361 	sr->sr_sticsr = 0x00000030;	/* Get the STIC's attention. */
    362 	tc_wmb();
    363 	tc_syncbus();
    364 	DELAY(4000);			/* wait 4ms for STIC to respond. */
    365 	sr->sr_sticsr = 0x00000000;	/* Hit the STIC's csr again... */
    366 	tc_wmb();
    367 	sr->sr_buscsr = 0xffffffff;	/* and bash its bus-acess csr. */
    368 	tc_wmb();
    369 	tc_syncbus();			/* Blam! */
    370 	DELAY(20000);			/* wait until the stic recovers... */
    371 
    372 	modtype = sr->sr_modcl;
    373 	xconfig = (modtype & 0x800) >> 11;
    374 	yconfig = (modtype & 0x600) >> 9;
    375 	config = (yconfig << 1) | xconfig;
    376 	si->si_stampw = (xconfig ? 5 : 4);
    377 	si->si_stamph = (1 << yconfig);
    378 #ifdef notyet
    379 	si->si_option = (char)((modtype >> 12) & 3);
    380 #endif
    381 
    382 	/* First PixelStamp */
    383 	si->si_stamp[0x000b0] = config;
    384 	si->si_stamp[0x000b4] = 0x0;
    385 
    386 	/* Second PixelStamp */
    387 	if (yconfig > 0) {
    388 		si->si_stamp[0x100b0] = config | 8;
    389 		si->si_stamp[0x100b4] = 0;
    390 	}
    391 
    392 	/*
    393 	 * Initialize STIC video registers.
    394 	 */
    395 	sr->sr_vblank = (1024 << 16) | 1063;
    396 	sr->sr_vsync = (1027 << 16) | 1030;
    397 	sr->sr_hblank = (255 << 16) | 340;
    398 	sr->sr_hsync2 = 245;
    399 	sr->sr_hsync = (261 << 16) | 293;
    400 	sr->sr_ipdvint = STIC_INT_CLR | STIC_INT_WE | STIC_INT_P;
    401 	sr->sr_sticsr = 8;
    402 	tc_wmb();
    403 	tc_syncbus();
    404 }
    405 
    406 void
    407 stic_attach(struct device *self, struct stic_info *si, int console)
    408 {
    409 	struct wsemuldisplaydev_attach_args waa;
    410 
    411 	callout_init(&si->si_switch_callout);
    412 
    413 	/*
    414 	 * Allocate backing for the console.  We could trawl back through
    415 	 * msgbuf and and fill the backing, but it's not worth the hassle.
    416 	 * We could also grab backing using pmap_steal_memory() early on,
    417 	 * but that's a little ugly.
    418 	 */
    419 	if (console)
    420 		stic_setup_backing(si, &stic_consscr);
    421 
    422 	waa.console = console;
    423 	waa.scrdata = &stic_screenlist;
    424 	waa.accessops = &stic_accessops;
    425 	waa.accesscookie = si;
    426 	config_found(self, &waa, wsemuldisplaydevprint);
    427 }
    428 
    429 void
    430 stic_cnattach(struct stic_info *si)
    431 {
    432 	struct stic_screen *ss;
    433 	long defattr;
    434 
    435 	ss = &stic_consscr;
    436 	si->si_curscreen = ss;
    437 	ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
    438 	ss->ss_si = si;
    439 
    440 	si->si_flags |= SI_CURENB_CHANGED;
    441 	stic_flush(si);
    442 
    443 	stic_alloc_attr(ss, 0, 0, 0, &defattr);
    444 	stic_eraserows(ss, 0, si->si_consh, 0);
    445 	wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
    446 }
    447 
    448 static void
    449 stic_setup_vdac(struct stic_info *si)
    450 {
    451 	u_int8_t *ip, *mp;
    452 	int r, c, o, b, i;
    453 
    454 	ip = (u_int8_t *)si->si_cursor.cc_image;
    455 	mp = ip + (sizeof(si->si_cursor.cc_image) >> 1);
    456 	memset(ip, 0, sizeof(si->si_cursor.cc_image));
    457 
    458 	for (r = 0; r < si->si_fonth; r++) {
    459 		for (c = 0; c < si->si_fontw; c++) {
    460 			o = c >> 3;
    461 			b = 1 << (c & 7);
    462 			ip[o] |= b;
    463 			mp[o] |= b;
    464 		}
    465 
    466 		ip += 16;
    467 		mp += 16;
    468 	}
    469 
    470 	si->si_cursor.cc_size.x = 64;
    471 	si->si_cursor.cc_size.y = si->si_fonth;
    472 	si->si_cursor.cc_hot.x = 0;
    473 	si->si_cursor.cc_hot.y = 0;
    474 
    475 	si->si_cursor.cc_color[0] = 0xff;
    476 	si->si_cursor.cc_color[2] = 0xff;
    477 	si->si_cursor.cc_color[4] = 0xff;
    478 	si->si_cursor.cc_color[1] = 0x00;
    479 	si->si_cursor.cc_color[3] = 0x00;
    480 	si->si_cursor.cc_color[5] = 0x00;
    481 
    482 	memset(&si->si_cmap, 0, sizeof(si->si_cmap));
    483 	for (i = 0; i < 16; i++) {
    484 		si->si_cmap.r[i] = stic_cmap[i*3 + 0];
    485 		si->si_cmap.g[i] = stic_cmap[i*3 + 1];
    486 		si->si_cmap.b[i] = stic_cmap[i*3 + 2];
    487 	}
    488 
    489 	si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
    490 	    SI_CURCMAP_CHANGED;
    491 }
    492 
    493 static int
    494 sticioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
    495 {
    496 	struct stic_info *si;
    497 	struct stic_xinfo *sxi;
    498 
    499 	si = v;
    500 
    501 	switch (cmd) {
    502 	case WSDISPLAYIO_GTYPE:
    503 		*(u_int *)data = si->si_disptype;
    504 		return (0);
    505 
    506 	case WSDISPLAYIO_GINFO:
    507 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    508 		wsd_fbip->height = 1024;
    509 		wsd_fbip->width = 1280;
    510 		wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
    511 		wsd_fbip->cmsize = CMAP_SIZE;
    512 #undef fbt
    513 		return (0);
    514 
    515 	case WSDISPLAYIO_GETCMAP:
    516 		return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
    517 
    518 	case WSDISPLAYIO_PUTCMAP:
    519 		return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
    520 
    521 	case WSDISPLAYIO_SVIDEO:
    522 #if 0 /* XXX later */
    523 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    524 		if ((si->si_blanked == 0) ^ turnoff)
    525 			si->si_blanked = turnoff;
    526 #endif
    527 		return (0);
    528 
    529 	case WSDISPLAYIO_GVIDEO:
    530 #if 0 /* XXX later */
    531 		*(u_int *)data = si->si_blanked ?
    532 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    533 #endif
    534 		return (0);
    535 
    536 	case WSDISPLAYIO_GCURPOS:
    537 		*(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
    538 		return (0);
    539 
    540 	case WSDISPLAYIO_SCURPOS:
    541 		stic_set_curpos(si, (struct wsdisplay_curpos *)data);
    542 		return (0);
    543 
    544 	case WSDISPLAYIO_GCURMAX:
    545 		((struct wsdisplay_curpos *)data)->x =
    546 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    547 		return (0);
    548 
    549 	case WSDISPLAYIO_GCURSOR:
    550 		return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
    551 
    552 	case WSDISPLAYIO_SCURSOR:
    553 		return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
    554 
    555 	case WSDISPLAYIO_SMODE:
    556 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    557 			stic_setup_vdac(si);
    558 			stic_flush(si);
    559 			stic_do_switch(si->si_curscreen);
    560 		}
    561 		return (0);
    562 
    563 	case STICIO_RESET:
    564 		stic_reset(si);
    565 		return (0);
    566 
    567 	case STICIO_GXINFO:
    568 		sxi = (struct stic_xinfo *)data;
    569 		sxi->sxi_stampw = si->si_stampw;
    570 		sxi->sxi_stamph = si->si_stamph;
    571 		sxi->sxi_buf_size = si->si_buf_size;
    572 		sxi->sxi_buf_phys = (u_long)si->si_buf_phys;
    573 		return (0);
    574 	}
    575 
    576 	if (si->si_ioctl != NULL)
    577 		return ((*si->si_ioctl)(si, cmd, data, flag, p));
    578 
    579 	return (ENOTTY);
    580 }
    581 
    582 static paddr_t
    583 sticmmap(void *v, off_t offset, int prot)
    584 {
    585 	struct stic_info *si;
    586 	struct stic_xmap sxm;
    587 	paddr_t pa;
    588 
    589 	si = v;
    590 
    591 	if (offset < 0)
    592 		return ((paddr_t)-1L);
    593 
    594 	if (offset < sizeof(sxm.sxm_stic)) {
    595 		pa = STIC_KSEG_TO_PHYS(si->si_stic);
    596 		return (machine_btop(pa + offset));
    597 	}
    598 	offset -= sizeof(sxm.sxm_stic);
    599 
    600 	if (offset < sizeof(sxm.sxm_poll)) {
    601 		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
    602 		return (machine_btop(pa + offset));
    603 	}
    604 	offset -= sizeof(sxm.sxm_poll);
    605 
    606 	if (offset < si->si_buf_size)
    607 		return (machine_btop(si->si_buf_phys + offset));
    608 
    609 	return ((paddr_t)-1L);
    610 }
    611 
    612 static void
    613 stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
    614 {
    615 	int size;
    616 
    617 	size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
    618 	ss->ss_backing = malloc(size, M_DEVBUF, M_NOWAIT);
    619 	memset(ss->ss_backing, 0, size);
    620 }
    621 
    622 static int
    623 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    624 		  int *curxp, int *curyp, long *attrp)
    625 {
    626 	struct stic_info *si;
    627 	struct stic_screen *ss;
    628 
    629 	si = (struct stic_info *)v;
    630 
    631 	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
    632 		ss = &stic_consscr;
    633 	else {
    634 		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK);
    635 		memset(ss, 0, sizeof(*ss));
    636 	}
    637 	stic_setup_backing(si, ss);
    638 
    639 	ss->ss_si = si;
    640 	ss->ss_flags = SS_ALLOCED | SS_CURENB;
    641 
    642 	*cookiep = ss;
    643 	*curxp = 0;
    644 	*curyp = 0;
    645 
    646 	stic_alloc_attr(ss, 0, 0, 0, attrp);
    647 	return (0);
    648 }
    649 
    650 static void
    651 stic_free_screen(void *v, void *cookie)
    652 {
    653 	struct stic_screen *ss;
    654 
    655 	ss = cookie;
    656 
    657 #ifdef DIAGNOSTIC
    658 	if (ss == &stic_consscr)
    659 		panic("stic_free_screen: console");
    660 	if (ss == ((struct stic_info *)v)->si_curscreen)
    661 		panic("stic_free_screen: freeing current screen");
    662 #endif
    663 
    664 	free(ss->ss_backing, M_DEVBUF);
    665 	free(ss, M_DEVBUF);
    666 }
    667 
    668 static int
    669 stic_show_screen(void *v, void *cookie, int waitok,
    670 		 void (*cb)(void *, int, int), void *cbarg)
    671 {
    672 	struct stic_info *si;
    673 
    674 	si = (struct stic_info *)v;
    675 	if (si->si_switchcbarg != NULL)
    676 		return (EAGAIN);
    677 	si->si_switchcb = cb;
    678 	si->si_switchcbarg = cbarg;
    679 
    680 	if (cb != NULL) {
    681 		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
    682 		    cookie);
    683 		return (EAGAIN);
    684 	}
    685 
    686 	stic_do_switch(cookie);
    687 	return (0);
    688 }
    689 
    690 static void
    691 stic_do_switch(void *cookie)
    692 {
    693 	struct stic_screen *ss;
    694 	struct stic_info *si;
    695 	u_int r, c, nr, nc;
    696 	u_int16_t *p, *sp;
    697 
    698 	ss = cookie;
    699 	si = ss->ss_si;
    700 
    701 #ifdef DIAGNOSTIC
    702 	if (ss->ss_backing == NULL)
    703 		panic("stic_do_switch: screen not backed");
    704 #endif
    705 
    706 	/* Swap in the new screen, and temporarily disable its backing. */
    707 	si->si_curscreen->ss_flags ^= SS_ACTIVE;
    708 	si->si_curscreen = ss;
    709 	ss->ss_flags |= SS_ACTIVE;
    710 	sp = ss->ss_backing;
    711 	ss->ss_backing = NULL;
    712 
    713 	/*
    714 	 * We assume that most of the screen is blank and blast it with
    715 	 * eraserows(), because eraserows() is cheap.
    716 	 */
    717 	nr = si->si_consh;
    718 	stic_eraserows(ss, 0, nr, 0);
    719 
    720 	nc = si->si_consw;
    721 	p = sp;
    722 	for (r = 0; r < nr; r++)
    723 		for (c = 0; c < nc; c += 2, p += 2) {
    724 			if ((p[0] & 0xfff0) != 0)
    725 				stic_putchar(ss, r, c, p[0] >> 8,
    726 				    p[0] & 0x00ff);
    727 			if ((p[1] & 0xfff0) != 0)
    728 				stic_putchar(ss, r, c + 1, p[1] >> 8,
    729 				    p[1] & 0x00ff);
    730 		}
    731 
    732 	/*
    733 	 * Re-enable the screen's backing, and move the cursor to the
    734 	 * correct spot.
    735 	 */
    736 	ss->ss_backing = sp;
    737 	si->si_cursor.cc_pos.x = ss->ss_curx;
    738 	si->si_cursor.cc_pos.y = ss->ss_cury;
    739 	stic_set_hwcurpos(si);
    740 	si->si_flags |= SI_CURENB_CHANGED;
    741 
    742 	/*
    743 	 * XXX Since we don't yet receive vblank interrupts from the
    744 	 * PXG, we must flush immediatley.
    745 	 */
    746 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
    747 		stic_flush(si);
    748 
    749 	/* Tell wscons that we're done. */
    750 	if (si->si_switchcbarg != NULL) {
    751 		cookie = si->si_switchcbarg;
    752 		si->si_switchcbarg = NULL;
    753 		(*si->si_switchcb)(cookie, 0, 0);
    754 	}
    755 }
    756 
    757 static int
    758 stic_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
    759 {
    760 	long tmp;
    761 
    762 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
    763 		return (EINVAL);
    764 
    765 	if ((flags & WSATTR_WSCOLORS) == 0) {
    766 		fg = 7;
    767 		bg = 0;
    768 	}
    769 
    770 	if ((flags & WSATTR_HILIT) != 0)
    771 		fg += 8;
    772 
    773 	tmp = fg | (bg << 4);
    774 	*attr = tmp | (tmp << 16);
    775 	return (0);
    776 }
    777 
    778 static void
    779 stic_erasecols(void *cookie, int row, int col, int num, long attr)
    780 {
    781 	struct stic_info *si;
    782 	struct stic_screen *ss;
    783 	u_int32_t *pb;
    784 	u_int i, linewidth;
    785 	u_int16_t *p;
    786 
    787 	ss = cookie;
    788 	si = ss->ss_si;
    789 
    790 	if (ss->ss_backing != NULL) {
    791 		p = ss->ss_backing + row * si->si_consw + col;
    792 		for (i = num; i != 0; i--)
    793 			*p++ = (u_int16_t)attr;
    794 	}
    795 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    796 		return;
    797 
    798 	col = (col * si->si_fontw) << 19;
    799 	num = (num * si->si_fontw) << 19;
    800 	row = row * si->si_fonth;
    801 	attr = (attr & 0xf0) >> 4;
    802 	linewidth = (si->si_fonth << 2) - 1;
    803 	row = (row << 3) + linewidth;
    804 
    805 	pb = (*si->si_pbuf_get)(si);
    806 
    807 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    808 	pb[1] = 0x01ffffff;
    809 	pb[2] = 0;
    810 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    811 	pb[4] = linewidth;
    812 	pb[5] = DUPBYTE0(attr);
    813 	pb[6] = col | row;
    814 	pb[7] = (col + num) | row;
    815 
    816 	(*si->si_pbuf_post)(si, pb);
    817 }
    818 
    819 static void
    820 stic_eraserows(void *cookie, int row, int num, long attr)
    821 {
    822 	struct stic_info *si;
    823 	struct stic_screen *ss;
    824 	u_int linewidth, i;
    825 	u_int32_t *pb;
    826 
    827 	ss = cookie;
    828 	si = ss->ss_si;
    829 
    830 	if (ss->ss_backing != NULL) {
    831 		pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
    832 		for (i = si->si_consw * num; i > 0; i -= 2)
    833 			*pb++ = (u_int32_t)attr;
    834 	}
    835 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    836 		return;
    837 
    838 	row *= si->si_fonth;
    839 	num *= si->si_fonth;
    840 	attr = (attr & 0xf0) >> 4;
    841 	linewidth = (num << 2) - 1;
    842 	row = (row << 3) + linewidth;
    843 
    844 	pb = (*si->si_pbuf_get)(si);
    845 
    846 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    847 	pb[1] = 0x01ffffff;
    848 	pb[2] = 0;
    849 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    850 	pb[4] = linewidth;
    851 	pb[5] = DUPBYTE0(attr);
    852 	pb[6] = row;
    853 	pb[7] = (1280 << 19) | row;
    854 
    855 	(*si->si_pbuf_post)(si, pb);
    856 }
    857 
    858 static void
    859 stic_copyrows(void *cookie, int src, int dst, int height)
    860 {
    861 	struct stic_info *si;
    862 	struct stic_screen *ss;
    863 	u_int32_t *pb, *pbs;
    864 	u_int num, inc, adj;
    865 
    866 	ss = cookie;
    867 	si = ss->ss_si;
    868 
    869 	if (ss->ss_backing != NULL)
    870 		bcopy(ss->ss_backing + src * si->si_consw,
    871 		    ss->ss_backing + dst * si->si_consw,
    872 		    si->si_consw * sizeof(*ss->ss_backing) * height);
    873 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    874 		return;
    875 
    876 	/*
    877 	 * We need to do this in reverse if the destination row is below
    878 	 * the source.
    879 	 */
    880 	if (dst > src) {
    881 		src += height;
    882 		dst += height;
    883 		inc = -8;
    884 		adj = -1;
    885 	} else {
    886 		inc = 8;
    887 		adj = 0;
    888 	}
    889 
    890 	src = (src * si->si_fonth + adj) << 3;
    891 	dst = (dst * si->si_fonth + adj) << 3;
    892 	height *= si->si_fonth;
    893 
    894 	while (height > 0) {
    895 		num = (height < 255 ? height : 255);
    896 		height -= num;
    897 
    898 		pbs = (*si->si_pbuf_get)(si);
    899 		pb = pbs;
    900 
    901 		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    902 		pb[1] = (num << 24) | 0xffffff;
    903 		pb[2] = 0x0;
    904 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
    905 		    STAMP_COPYSPAN_ALIGNED;
    906 		pb[4] = 1; /* linewidth */
    907 
    908 		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
    909 			pb[5] = 1280 << 3;
    910 			pb[6] = src;
    911 			pb[7] = dst;
    912 		}
    913 
    914 	    	(*si->si_pbuf_post)(si, pbs);
    915 	}
    916 }
    917 
    918 static void
    919 stic_copycols(void *cookie, int row, int src, int dst, int num)
    920 {
    921 	struct stic_info *si;
    922 	struct stic_screen *ss;
    923 	u_int height, updword;
    924 	u_int32_t *pb, *pbs;
    925 
    926 	ss = cookie;
    927 	si = ss->ss_si;
    928 
    929 	if (ss->ss_backing != NULL)
    930 		bcopy(ss->ss_backing + row * si->si_consw + src,
    931 		    ss->ss_backing + row * si->si_consw + dst,
    932 		    num * sizeof(*ss->ss_backing));
    933 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    934 		return;
    935 
    936 	/*
    937 	 * The stamp reads and writes left -> right only, so we need to
    938 	 * buffer the span if the source and destination regions overlap
    939 	 * and the source is left of the destination.
    940 	 */
    941 	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
    942 
    943 	if (src < dst && src + num > dst)
    944 		updword |= STAMP_HALF_BUFF;
    945 
    946 	row = (row * si->si_fonth) << 3;
    947 	num = (num * si->si_fontw) << 3;
    948 	src = row | ((src * si->si_fontw) << 19);
    949 	dst = row | ((dst * si->si_fontw) << 19);
    950 	height = si->si_fonth;
    951 
    952 	pbs = (*si->si_pbuf_get)(si);
    953 	pb = pbs;
    954 
    955 	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    956 	pb[1] = (height << 24) | 0xffffff;
    957 	pb[2] = 0x0;
    958 	pb[3] = updword;
    959 	pb[4] = 1; /* linewidth */
    960 
    961 	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
    962 		pb[5] = num;
    963 		pb[6] = src;
    964 		pb[7] = dst;
    965 	}
    966 
    967 	(*si->si_pbuf_post)(si, pbs);
    968 }
    969 
    970 static void
    971 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
    972 {
    973 	struct wsdisplay_font *font;
    974 	struct stic_screen *ss;
    975 	struct stic_info *si;
    976 	u_int i, bgcolor, fgcolor;
    977 	u_int *pb, v1, v2, xya;
    978 	u_short *fr;
    979 
    980 	ss = cookie;
    981 	si = ss->ss_si;
    982 
    983 	/* It's cheaper to use erasecols() to blit blanks. */
    984 	if (uc == 0) {
    985 		stic_erasecols(cookie, r, c, 1, attr);
    986 		return;
    987 	}
    988 
    989 	if (ss->ss_backing != NULL)
    990 		ss->ss_backing[r * si->si_consw + c] =
    991 		    (u_short)((attr & 0xff) | (uc << 8));
    992 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    993 		return;
    994 
    995 	font = si->si_font;
    996 	pb = (*si->si_pbuf_get)(si);
    997 
    998 	/*
    999 	 * Create a mask from the glyph.  Squeeze the foreground color
   1000 	 * through the mask, and then squeeze the background color through
   1001 	 * the inverted mask.  We may well read outside the glyph when
   1002 	 * creating the mask, but it's bounded by the hardware so it
   1003 	 * shouldn't matter a great deal...
   1004 	 */
   1005 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
   1006 	    STAMP_LW_PERPRIMATIVE;
   1007 	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
   1008 	pb[2] = 0x0;
   1009 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
   1010 
   1011 	r *= font->fontheight;
   1012 	c *= font->fontwidth;
   1013 	uc = (uc - font->firstchar) * font->stride * font->fontheight;
   1014 	fr = (u_short *)((caddr_t)font->data + uc);
   1015 	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
   1016 	fgcolor = DUPBYTE0(attr & 0x0f);
   1017 
   1018 	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
   1019 	v1 = (c << 19) | ((r << 3) + i);
   1020 	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1021 	xya = XYMASKADDR(si->si_stampw, si->si_stamph, c, r, 0, 0);
   1022 
   1023 	pb[4] = PACK(fr, 0);
   1024 	pb[5] = PACK(fr, 2);
   1025 	pb[6] = PACK(fr, 4);
   1026 	pb[7] = PACK(fr, 6);
   1027 	pb[8] = PACK(fr, 8);
   1028 	pb[9] = PACK(fr, 10);
   1029 	pb[10] = PACK(fr, 12);
   1030 	pb[11] = PACK(fr, 14);
   1031 	pb[12] = xya;
   1032 	pb[13] = v1;
   1033 	pb[14] = v2;
   1034 	pb[15] = i;
   1035 	pb[16] = fgcolor;
   1036 
   1037 	pb[17] = ~pb[4];
   1038 	pb[18] = ~pb[5];
   1039 	pb[19] = ~pb[6];
   1040 	pb[20] = ~pb[7];
   1041 	pb[21] = ~pb[8];
   1042 	pb[22] = ~pb[9];
   1043 	pb[23] = ~pb[10];
   1044 	pb[24] = ~pb[11];
   1045 	pb[25] = xya;
   1046 	pb[26] = v1;
   1047 	pb[27] = v2;
   1048 	pb[28] = i;
   1049 	pb[29] = bgcolor;
   1050 
   1051 	/* Two more squeezes for the lower part of the character. */
   1052 	if (font->fontheight > 16) {
   1053 		i = ((font->fontheight - 16) << 2) - 1;
   1054 		r += 16;
   1055 		v1 = (c << 19) | ((r << 3) + i);
   1056 		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1057 
   1058 		pb[30] = PACK(fr, 16);
   1059 		pb[31] = PACK(fr, 18);
   1060 		pb[32] = PACK(fr, 20);
   1061 		pb[33] = PACK(fr, 22);
   1062 		pb[34] = PACK(fr, 24);
   1063 		pb[35] = PACK(fr, 26);
   1064 		pb[36] = PACK(fr, 28);
   1065 		pb[37] = PACK(fr, 30);
   1066 		pb[38] = xya;
   1067 		pb[39] = v1;
   1068 		pb[40] = v2;
   1069 		pb[41] = i;
   1070 		pb[42] = fgcolor;
   1071 
   1072 		pb[43] = ~pb[30];
   1073 		pb[44] = ~pb[31];
   1074 		pb[45] = ~pb[32];
   1075 		pb[46] = ~pb[33];
   1076 		pb[47] = ~pb[34];
   1077 		pb[48] = ~pb[35];
   1078 		pb[49] = ~pb[36];
   1079 		pb[50] = ~pb[37];
   1080 		pb[51] = xya;
   1081 		pb[52] = v1;
   1082 		pb[53] = v2;
   1083 		pb[54] = i;
   1084 		pb[55] = bgcolor;
   1085 	}
   1086 
   1087 	(*si->si_pbuf_post)(si, pb);
   1088 }
   1089 
   1090 static int
   1091 stic_mapchar(void *cookie, int c, u_int *cp)
   1092 {
   1093 	struct stic_info *si;
   1094 
   1095 	si = ((struct stic_screen *)cookie)->ss_si;
   1096 
   1097 	if (c < si->si_font->firstchar || c == ' ') {
   1098 		*cp = 0;
   1099 		return (0);
   1100 	}
   1101 
   1102 	if (c - si->si_font->firstchar >= si->si_font->numchars) {
   1103 		*cp = 0;
   1104 		return (0);
   1105 	}
   1106 
   1107 	*cp = c;
   1108 	return (5);
   1109 }
   1110 
   1111 static void
   1112 stic_cursor(void *cookie, int on, int row, int col)
   1113 {
   1114 	struct stic_screen *ss;
   1115 	struct stic_info *si;
   1116 
   1117 	ss = cookie;
   1118 	si = ss->ss_si;
   1119 
   1120 	ss->ss_curx = col * si->si_fontw;
   1121 	ss->ss_cury = row * si->si_fonth;
   1122 
   1123 	if (on)
   1124 		ss->ss_flags |= SS_CURENB;
   1125 	else
   1126 		ss->ss_flags &= ~SS_CURENB;
   1127 
   1128 	if ((ss->ss_flags & SS_ACTIVE) != 0) {
   1129 		si->si_cursor.cc_pos.x = ss->ss_curx;
   1130 		si->si_cursor.cc_pos.y = ss->ss_cury;
   1131 		si->si_flags |= SI_CURENB_CHANGED;
   1132 		stic_set_hwcurpos(si);
   1133 
   1134 		/*
   1135 		 * XXX Since we don't yet receive vblank interrupts from the
   1136 		 * PXG, we must flush immediatley.
   1137 		 */
   1138 		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1139 			stic_flush(si);
   1140 	}
   1141 }
   1142 
   1143 void
   1144 stic_flush(struct stic_info *si)
   1145 {
   1146 	volatile u_int32_t *vdac;
   1147 	int v;
   1148 
   1149 	if ((si->si_flags & SI_ALL_CHANGED) == 0)
   1150 		return;
   1151 
   1152 	vdac = si->si_vdac;
   1153 	v = si->si_flags;
   1154 	si->si_flags &= ~SI_ALL_CHANGED;
   1155 
   1156 	if ((v & SI_CURENB_CHANGED) != 0) {
   1157 		SELECT(vdac, BT459_IREG_CCR);
   1158 		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
   1159 			REG(vdac, bt_reg) = 0x00c0c0c0;
   1160 		else
   1161 			REG(vdac, bt_reg) = 0x00000000;
   1162 		tc_wmb();
   1163 	}
   1164 
   1165 	if ((v & SI_CURCMAP_CHANGED) != 0) {
   1166 		u_int8_t *cp;
   1167 
   1168 		cp = si->si_cursor.cc_color;
   1169 
   1170 		SELECT(vdac, BT459_IREG_CCOLOR_2);
   1171 		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
   1172 		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
   1173 		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
   1174 		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
   1175 		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
   1176 		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
   1177 	}
   1178 
   1179 	if ((v & SI_CURSHAPE_CHANGED) != 0) {
   1180 		u_int8_t *ip, *mp, img, msk;
   1181 		u_int8_t u;
   1182 		int bcnt;
   1183 
   1184 		ip = (u_int8_t *)si->si_cursor.cc_image;
   1185 		mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
   1186 
   1187 		bcnt = 0;
   1188 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
   1189 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
   1190 		while (bcnt < si->si_cursor.cc_size.y * 16) {
   1191 			/* pad right half 32 pixel when smaller than 33 */
   1192 			if ((bcnt & 0x8) && si->si_cursor.cc_size.x < 33) {
   1193 				REG(vdac, bt_reg) = 0; tc_wmb();
   1194 				REG(vdac, bt_reg) = 0; tc_wmb();
   1195 			} else {
   1196 				img = *ip++;
   1197 				msk = *mp++;
   1198 				img &= msk;	/* cookie off image */
   1199 				u = (msk & 0x0f) << 4 | (img & 0x0f);
   1200 				REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1201 				tc_wmb();
   1202 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
   1203 				REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1204 				tc_wmb();
   1205 			}
   1206 			bcnt += 2;
   1207 		}
   1208 		/* pad unoccupied scan lines */
   1209 		while (bcnt < CURSOR_MAX_SIZE * 16) {
   1210 			REG(vdac, bt_reg) = 0; tc_wmb();
   1211 			REG(vdac, bt_reg) = 0; tc_wmb();
   1212 			bcnt += 2;
   1213 		}
   1214 	}
   1215 
   1216 	if ((v & SI_CMAP_CHANGED) != 0) {
   1217 		struct stic_hwcmap256 *cm;
   1218 		int index;
   1219 
   1220 		cm = &si->si_cmap;
   1221 
   1222 		SELECT(vdac, 0);
   1223 		SELECT(vdac, 0);
   1224 		for (index = 0; index < CMAP_SIZE; index++) {
   1225 			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
   1226 			tc_wmb();
   1227 			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
   1228 			tc_wmb();
   1229 			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
   1230 			tc_wmb();
   1231 		}
   1232 	}
   1233 }
   1234 
   1235 static int
   1236 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1237 {
   1238 	u_int index, count;
   1239 
   1240 	index = p->index;
   1241 	count = p->count;
   1242 
   1243 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
   1244 		return (EINVAL);
   1245 
   1246 	if (!uvm_useracc(p->red, count, B_WRITE) ||
   1247 	    !uvm_useracc(p->green, count, B_WRITE) ||
   1248 	    !uvm_useracc(p->blue, count, B_WRITE))
   1249 		return (EFAULT);
   1250 
   1251 	copyout(&si->si_cmap.r[index], p->red, count);
   1252 	copyout(&si->si_cmap.g[index], p->green, count);
   1253 	copyout(&si->si_cmap.b[index], p->blue, count);
   1254 	return (0);
   1255 }
   1256 
   1257 static int
   1258 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1259 {
   1260 	u_int index, count;
   1261 
   1262 	index = p->index;
   1263 	count = p->count;
   1264 
   1265 	if ((index + count) > CMAP_SIZE)
   1266 		return (EINVAL);
   1267 
   1268 	if (!uvm_useracc(p->red, count, B_READ) ||
   1269 	    !uvm_useracc(p->green, count, B_READ) ||
   1270 	    !uvm_useracc(p->blue, count, B_READ))
   1271 		return (EFAULT);
   1272 
   1273 	copyin(p->red, &si->si_cmap.r[index], count);
   1274 	copyin(p->green, &si->si_cmap.g[index], count);
   1275 	copyin(p->blue, &si->si_cmap.b[index], count);
   1276 
   1277 	si->si_flags |= SI_CMAP_CHANGED;
   1278 
   1279 	/*
   1280 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1281 	 * must flush immediatley.
   1282 	 */
   1283 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1284 		stic_flush(si);
   1285 
   1286 	return (0);
   1287 }
   1288 
   1289 static int
   1290 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1291 {
   1292 #define	cc (&si->si_cursor)
   1293 	int v, index, count, icount;
   1294 	struct stic_screen *ss;
   1295 
   1296 	v = p->which;
   1297 	ss = si->si_curscreen;
   1298 
   1299 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1300 		index = p->cmap.index;
   1301 		count = p->cmap.count;
   1302 		if (index >= 2 || (index + count) > 2)
   1303 			return (EINVAL);
   1304 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
   1305 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
   1306 		    !uvm_useracc(p->cmap.blue, count, B_READ))
   1307 			return (EFAULT);
   1308 	}
   1309 
   1310 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1311 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
   1312 			return (EINVAL);
   1313 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
   1314 		if (!uvm_useracc(p->image, icount, B_READ) ||
   1315 		    !uvm_useracc(p->mask, icount, B_READ))
   1316 			return (EFAULT);
   1317 	}
   1318 
   1319 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
   1320 		if (v & WSDISPLAY_CURSOR_DOCUR)
   1321 			cc->cc_hot = p->hot;
   1322 		if (v & WSDISPLAY_CURSOR_DOPOS)
   1323 			stic_set_curpos(si, &p->pos);
   1324 	}
   1325 
   1326 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
   1327 		if (p->enable)
   1328 			ss->ss_flags |= SS_CURENB;
   1329 		else
   1330 			ss->ss_flags &= ~SS_CURENB;
   1331 		si->si_flags |= SI_CURENB_CHANGED;
   1332 	}
   1333 
   1334 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1335 		copyin(p->cmap.red, &cc->cc_color[index], count);
   1336 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
   1337 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
   1338 		si->si_flags |= SI_CURCMAP_CHANGED;
   1339 	}
   1340 
   1341 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1342 		cc->cc_size = p->size;
   1343 		memset(cc->cc_image, 0, sizeof cc->cc_image);
   1344 		copyin(p->image, cc->cc_image, icount);
   1345 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
   1346 		si->si_flags |= SI_CURSHAPE_CHANGED;
   1347 	}
   1348 
   1349 	/*
   1350 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1351 	 * must flush immediatley.
   1352 	 */
   1353 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1354 		stic_flush(si);
   1355 
   1356 	return (0);
   1357 #undef cc
   1358 }
   1359 
   1360 static int
   1361 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1362 {
   1363 
   1364 	/* XXX */
   1365 	return (ENOTTY);
   1366 }
   1367 
   1368 static void
   1369 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
   1370 {
   1371 	int x, y;
   1372 
   1373 	x = curpos->x;
   1374 	y = curpos->y;
   1375 
   1376 	if (y < 0)
   1377 		y = 0;
   1378 	else if (y > 1023)
   1379 		y = 1023;
   1380 	if (x < 0)
   1381 		x = 0;
   1382 	else if (x > 1279)
   1383 		x = 1279;
   1384 
   1385 	si->si_cursor.cc_pos.x = x;
   1386 	si->si_cursor.cc_pos.y = y;
   1387 	stic_set_hwcurpos(si);
   1388 }
   1389 
   1390 static void
   1391 stic_set_hwcurpos(struct stic_info *si)
   1392 {
   1393 	volatile u_int32_t *vdac;
   1394 	int x, y, s;
   1395 
   1396 	vdac = si->si_vdac;
   1397 
   1398 	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
   1399 	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
   1400 	x += STIC_MAGIC_X;
   1401 	y += STIC_MAGIC_Y;
   1402 
   1403 	s = spltty();
   1404 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
   1405 	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
   1406 	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
   1407 	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
   1408 	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
   1409 	splx(s);
   1410 }
   1411