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