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