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