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