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