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