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