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