Home | History | Annotate | Line # | Download | only in tc
stic.c revision 1.18
      1 /*	$NetBSD: stic.c,v 1.18 2002/07/04 14:37:13 junyoung 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.18 2002/07/04 14:37:13 junyoung 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_allocattr(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_allocattr
    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 
    342 	cookie = wsfont_find(NULL, 12, 0, 2, WSDISPLAY_FONTORDER_R2L,
    343 	    WSDISPLAY_FONTORDER_L2R);
    344 	if (cookie <= 0)
    345 		cookie = wsfont_find(NULL, 0, 0, 2, WSDISPLAY_FONTORDER_R2L,
    346 		    WSDISPLAY_FONTORDER_L2R);
    347 	if (cookie <= 0)
    348 		panic("stic_init: font table is empty\n");
    349 
    350 	if (wsfont_lock(cookie, &si->si_font))
    351 		panic("stic_init: couldn't lock font\n");
    352 
    353 	si->si_fontw = si->si_font->fontwidth;
    354 	si->si_fonth = si->si_font->fontheight;
    355 	si->si_consw = (1280 / si->si_fontw) & ~1;
    356 	si->si_consh = 1024 / si->si_fonth;
    357 	stic_stdscreen.ncols = si->si_consw;
    358 	stic_stdscreen.nrows = si->si_consh;
    359 
    360 #ifdef DIAGNOSTIC
    361 	if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
    362 		panic("stic_init: unusable font");
    363 #endif
    364 
    365 	stic_setup_vdac(si);
    366 	stic_clear_screen(si);
    367 	si->si_dispmode = WSDISPLAYIO_MODE_EMUL;
    368 }
    369 
    370 void
    371 stic_reset(struct stic_info *si)
    372 {
    373 	int modtype, xconfig, yconfig, config;
    374 	volatile struct stic_regs *sr;
    375 
    376 	sr = si->si_stic;
    377 
    378 	/*
    379 	 * Initialize the interface chip registers.
    380 	 */
    381 	sr->sr_sticsr = 0x00000030;	/* Get the STIC's attention. */
    382 	tc_wmb();
    383 	tc_syncbus();
    384 	DELAY(2000);			/* wait 2ms for STIC to respond. */
    385 	sr->sr_sticsr = 0x00000000;	/* Hit the STIC's csr again... */
    386 	tc_wmb();
    387 	sr->sr_buscsr = 0xffffffff;	/* and bash its bus-acess csr. */
    388 	tc_wmb();
    389 	tc_syncbus();			/* Blam! */
    390 	DELAY(20000);			/* wait until the stic recovers... */
    391 
    392 	modtype = sr->sr_modcl;
    393 	xconfig = (modtype & 0x800) >> 11;
    394 	yconfig = (modtype & 0x600) >> 9;
    395 	config = (yconfig << 1) | xconfig;
    396 	si->si_stampw = (xconfig ? 5 : 4);
    397 	si->si_stamph = (1 << yconfig);
    398 	si->si_stamphm = si->si_stamph - 1;
    399 #ifdef notyet
    400 	si->si_option = (char)((modtype >> 12) & 3);
    401 #endif
    402 
    403 	/* First PixelStamp */
    404 	si->si_stamp[0x000b0] = config;
    405 	si->si_stamp[0x000b4] = 0x0;
    406 
    407 	/* Second PixelStamp */
    408 	if (yconfig > 0) {
    409 		si->si_stamp[0x100b0] = config | 8;
    410 		si->si_stamp[0x100b4] = 0;
    411 	}
    412 
    413 	/*
    414 	 * Initialize STIC video registers.  Enable error and vertical
    415 	 * retrace interrupts.  Set the packet done flag so the Xserver will
    416 	 * not time-out on the first packet submitted.
    417 	 */
    418 	sr->sr_vblank = (1024 << 16) | 1063;
    419 	sr->sr_vsync = (1027 << 16) | 1030;
    420 	sr->sr_hblank = (255 << 16) | 340;
    421 	sr->sr_hsync2 = 245;
    422 	sr->sr_hsync = (261 << 16) | 293;
    423 	sr->sr_ipdvint =
    424 	    STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN;
    425 	sr->sr_sticsr = 8;
    426 	tc_wmb();
    427 	tc_syncbus();
    428 }
    429 
    430 void
    431 stic_attach(struct device *self, struct stic_info *si, int console)
    432 {
    433 	struct wsemuldisplaydev_attach_args waa;
    434 
    435 	if (stic_unit < STIC_MAXDV) {
    436 		stic_info[stic_unit] = si;
    437 		si->si_unit = stic_unit++;
    438 	} else
    439 		si->si_unit = -1;
    440 
    441 	callout_init(&si->si_switch_callout);
    442 
    443 	/*
    444 	 * Allocate backing for the console.  We could trawl back through
    445 	 * msgbuf and and fill the backing, but it's not worth the hassle.
    446 	 * We could also grab backing using pmap_steal_memory() early on,
    447 	 * but that's a little ugly.
    448 	 */
    449 	if (console)
    450 		stic_setup_backing(si, &stic_consscr);
    451 
    452 	waa.console = console;
    453 	waa.scrdata = &stic_screenlist;
    454 	waa.accessops = &stic_accessops;
    455 	waa.accesscookie = si;
    456 
    457 	config_found(self, &waa, wsemuldisplaydevprint);
    458 }
    459 
    460 void
    461 stic_cnattach(struct stic_info *si)
    462 {
    463 	struct stic_screen *ss;
    464 	long defattr;
    465 
    466 	ss = &stic_consscr;
    467 	si->si_curscreen = ss;
    468 	ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
    469 	ss->ss_si = si;
    470 
    471 	si->si_flags |= SI_CURENB_CHANGED;
    472 	stic_flush(si);
    473 
    474 	stic_allocattr(ss, 0, 0, 0, &defattr);
    475 	stic_eraserows(ss, 0, si->si_consh, 0);
    476 	wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
    477 }
    478 
    479 void
    480 stic_setup_vdac(struct stic_info *si)
    481 {
    482 	u_int8_t *ip, *mp;
    483 	int r, c, o, b, i, s;
    484 
    485 	s = spltty();
    486 
    487 	ip = (u_int8_t *)si->si_cursor.cc_image;
    488 	mp = ip + (sizeof(si->si_cursor.cc_image) >> 1);
    489 	memset(ip, 0, sizeof(si->si_cursor.cc_image));
    490 
    491 	for (r = 0; r < si->si_fonth; r++) {
    492 		for (c = r & 1; c < si->si_fontw; c += 2) {
    493 			o = c >> 3;
    494 			b = 1 << (c & 7);
    495 			ip[o] |= b;
    496 			mp[o] |= b;
    497 		}
    498 
    499 		ip += 8;
    500 		mp += 8;
    501 	}
    502 
    503 	si->si_cursor.cc_size.x = 64;
    504 	si->si_cursor.cc_size.y = si->si_fonth;
    505 	si->si_cursor.cc_hot.x = 0;
    506 	si->si_cursor.cc_hot.y = 0;
    507 
    508 	si->si_cursor.cc_color[0] = 0xff;
    509 	si->si_cursor.cc_color[2] = 0xff;
    510 	si->si_cursor.cc_color[4] = 0xff;
    511 	si->si_cursor.cc_color[1] = 0x00;
    512 	si->si_cursor.cc_color[3] = 0x00;
    513 	si->si_cursor.cc_color[5] = 0x00;
    514 
    515 	memset(&si->si_cmap, 0, sizeof(si->si_cmap));
    516 	for (i = 0; i < 16; i++) {
    517 		si->si_cmap.r[i] = stic_cmap[i*3 + 0];
    518 		si->si_cmap.g[i] = stic_cmap[i*3 + 1];
    519 		si->si_cmap.b[i] = stic_cmap[i*3 + 2];
    520 	}
    521 
    522 	si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
    523 	    SI_CURCMAP_CHANGED;
    524 
    525 	splx(s);
    526 }
    527 
    528 void
    529 stic_clear_screen(struct stic_info *si)
    530 {
    531 	u_int32_t *pb;
    532 	int i;
    533 
    534 	/*
    535 	 * Do this twice, since the first packet after a reset may be
    536 	 * silently ignored.
    537 	 */
    538 	for (i = 0; i < 2; i++) {
    539 		pb = (*si->si_pbuf_get)(si);
    540 
    541 		pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    542 		pb[1] = 0x01ffffff;
    543 		pb[2] = 0;
    544 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    545 		pb[4] = (1024 << 2) - 1;
    546 		pb[5] = 0;
    547 		pb[6] = 0;
    548 		pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]);
    549 
    550 		(*si->si_pbuf_post)(si, pb);
    551 	}
    552 }
    553 
    554 int
    555 sticioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
    556 {
    557 	struct stic_info *si;
    558 
    559 	si = v;
    560 
    561 	switch (cmd) {
    562 	case WSDISPLAYIO_GTYPE:
    563 		*(u_int *)data = si->si_disptype;
    564 		return (0);
    565 
    566 	case WSDISPLAYIO_GINFO:
    567 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    568 		wsd_fbip->height = 1024;
    569 		wsd_fbip->width = 1280;
    570 		wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
    571 		wsd_fbip->cmsize = CMAP_SIZE;
    572 #undef fbt
    573 		return (0);
    574 
    575 	case WSDISPLAYIO_GETCMAP:
    576 		return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
    577 
    578 	case WSDISPLAYIO_PUTCMAP:
    579 		return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
    580 
    581 	case WSDISPLAYIO_SVIDEO:
    582 #if 0 /* XXX later */
    583 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    584 		if ((si->si_blanked == 0) ^ turnoff)
    585 			si->si_blanked = turnoff;
    586 #endif
    587 		return (0);
    588 
    589 	case WSDISPLAYIO_GVIDEO:
    590 #if 0 /* XXX later */
    591 		*(u_int *)data = si->si_blanked ?
    592 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    593 #endif
    594 		return (0);
    595 
    596 	case WSDISPLAYIO_GCURPOS:
    597 		*(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
    598 		return (0);
    599 
    600 	case WSDISPLAYIO_SCURPOS:
    601 		stic_set_curpos(si, (struct wsdisplay_curpos *)data);
    602 		return (0);
    603 
    604 	case WSDISPLAYIO_GCURMAX:
    605 		((struct wsdisplay_curpos *)data)->x =
    606 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    607 		return (0);
    608 
    609 	case WSDISPLAYIO_GCURSOR:
    610 		return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
    611 
    612 	case WSDISPLAYIO_SCURSOR:
    613 		return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
    614 
    615 	case WSDISPLAYIO_SMODE:
    616 		si->si_dispmode = *(int *)data;
    617 		if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) {
    618 			(*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, p);
    619 			stic_setup_vdac(si);
    620 			stic_flush(si);
    621 			stic_clear_screen(si);
    622 			stic_do_switch(si->si_curscreen);
    623 		}
    624 		return (0);
    625 
    626 	case STICIO_RESET:
    627 		stic_reset(si);
    628 		return (0);
    629 	}
    630 
    631 	if (si->si_ioctl != NULL)
    632 		return ((*si->si_ioctl)(si, cmd, data, flag, p));
    633 
    634 	return (EPASSTHROUGH);
    635 }
    636 
    637 void
    638 stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
    639 {
    640 	int size;
    641 
    642 	size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
    643 	ss->ss_backing = malloc(size, M_DEVBUF, M_NOWAIT|M_ZERO);
    644 }
    645 
    646 int
    647 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    648 		  int *curxp, int *curyp, long *attrp)
    649 {
    650 	struct stic_info *si;
    651 	struct stic_screen *ss;
    652 
    653 	si = (struct stic_info *)v;
    654 
    655 	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
    656 		ss = &stic_consscr;
    657 	else {
    658 		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO);
    659 	}
    660 	stic_setup_backing(si, ss);
    661 
    662 	ss->ss_si = si;
    663 	ss->ss_flags = SS_ALLOCED | SS_CURENB;
    664 
    665 	*cookiep = ss;
    666 	*curxp = 0;
    667 	*curyp = 0;
    668 
    669 	stic_allocattr(ss, 0, 0, 0, attrp);
    670 	return (0);
    671 }
    672 
    673 void
    674 stic_free_screen(void *v, void *cookie)
    675 {
    676 	struct stic_screen *ss;
    677 
    678 	ss = cookie;
    679 
    680 #ifdef DIAGNOSTIC
    681 	if (ss == &stic_consscr)
    682 		panic("stic_free_screen: console");
    683 	if (ss == ((struct stic_info *)v)->si_curscreen)
    684 		panic("stic_free_screen: freeing current screen");
    685 #endif
    686 
    687 	free(ss->ss_backing, M_DEVBUF);
    688 	free(ss, M_DEVBUF);
    689 }
    690 
    691 int
    692 stic_show_screen(void *v, void *cookie, int waitok,
    693 		 void (*cb)(void *, int, int), void *cbarg)
    694 {
    695 	struct stic_info *si;
    696 
    697 	si = (struct stic_info *)v;
    698 	if (si->si_switchcbarg != NULL)
    699 		return (EAGAIN);
    700 	si->si_switchcb = cb;
    701 	si->si_switchcbarg = cbarg;
    702 
    703 	if (cb != NULL) {
    704 		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
    705 		    cookie);
    706 		return (EAGAIN);
    707 	}
    708 
    709 	stic_do_switch(cookie);
    710 	return (0);
    711 }
    712 
    713 void
    714 stic_do_switch(void *cookie)
    715 {
    716 	struct stic_screen *ss;
    717 	struct stic_info *si;
    718 	u_int r, c, nr, nc;
    719 	u_int16_t *p, *sp;
    720 
    721 	ss = cookie;
    722 	si = ss->ss_si;
    723 
    724 #ifdef DIAGNOSTIC
    725 	if (ss->ss_backing == NULL)
    726 		panic("stic_do_switch: screen not backed");
    727 #endif
    728 
    729 	/* Swap in the new screen, and temporarily disable its backing. */
    730 	if (si->si_curscreen != NULL)
    731 		si->si_curscreen->ss_flags ^= SS_ACTIVE;
    732 	si->si_curscreen = ss;
    733 	ss->ss_flags |= SS_ACTIVE;
    734 	sp = ss->ss_backing;
    735 	ss->ss_backing = NULL;
    736 
    737 	/*
    738 	 * We assume that most of the screen is blank and blast it with
    739 	 * eraserows(), because eraserows() is cheap.
    740 	 */
    741 	nr = si->si_consh;
    742 	stic_eraserows(ss, 0, nr, 0);
    743 
    744 	nc = si->si_consw;
    745 	p = sp;
    746 	for (r = 0; r < nr; r++)
    747 		for (c = 0; c < nc; c += 2, p += 2) {
    748 			if ((p[0] & 0xfff0) != 0)
    749 				stic_putchar(ss, r, c, p[0] >> 8,
    750 				    p[0] & 0x00ff);
    751 			if ((p[1] & 0xfff0) != 0)
    752 				stic_putchar(ss, r, c + 1, p[1] >> 8,
    753 				    p[1] & 0x00ff);
    754 		}
    755 
    756 	/*
    757 	 * Re-enable the screen's backing, and move the cursor to the
    758 	 * correct spot.
    759 	 */
    760 	ss->ss_backing = sp;
    761 	si->si_cursor.cc_pos.x = ss->ss_curx;
    762 	si->si_cursor.cc_pos.y = ss->ss_cury;
    763 	stic_set_hwcurpos(si);
    764 	si->si_flags |= SI_CURENB_CHANGED;
    765 
    766 	/*
    767 	 * XXX Since we don't yet receive vblank interrupts from the
    768 	 * PXG, we must flush immediatley.
    769 	 */
    770 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
    771 		stic_flush(si);
    772 
    773 	/* Tell wscons that we're done. */
    774 	if (si->si_switchcbarg != NULL) {
    775 		cookie = si->si_switchcbarg;
    776 		si->si_switchcbarg = NULL;
    777 		(*si->si_switchcb)(cookie, 0, 0);
    778 	}
    779 }
    780 
    781 int
    782 stic_allocattr(void *cookie, int fg, int bg, int flags, long *attr)
    783 {
    784 	long tmp;
    785 
    786 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
    787 		return (EINVAL);
    788 
    789 	if ((flags & WSATTR_WSCOLORS) == 0) {
    790 		fg = 7;
    791 		bg = 0;
    792 	}
    793 
    794 	if ((flags & WSATTR_HILIT) != 0)
    795 		fg += 8;
    796 
    797 	tmp = fg | (bg << 4);
    798 	*attr = tmp | (tmp << 16);
    799 	return (0);
    800 }
    801 
    802 void
    803 stic_erasecols(void *cookie, int row, int col, int num, long attr)
    804 {
    805 	struct stic_info *si;
    806 	struct stic_screen *ss;
    807 	u_int32_t *pb;
    808 	u_int i, linewidth;
    809 	u_int16_t *p;
    810 
    811 	ss = cookie;
    812 	si = ss->ss_si;
    813 
    814 	if (ss->ss_backing != NULL) {
    815 		p = ss->ss_backing + row * si->si_consw + col;
    816 		for (i = num; i != 0; i--)
    817 			*p++ = (u_int16_t)attr;
    818 	}
    819 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    820 		return;
    821 
    822 	col = (col * si->si_fontw) << 19;
    823 	num = (num * si->si_fontw) << 19;
    824 	row = row * si->si_fonth;
    825 	attr = (attr & 0xf0) >> 4;
    826 	linewidth = (si->si_fonth << 2) - 1;
    827 	row = (row << 3) + linewidth;
    828 
    829 	pb = (*si->si_pbuf_get)(si);
    830 
    831 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    832 	pb[1] = 0x01ffffff;
    833 	pb[2] = 0;
    834 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    835 	pb[4] = linewidth;
    836 	pb[5] = DUPBYTE0(attr);
    837 	pb[6] = col | row;
    838 	pb[7] = (col + num) | row;
    839 
    840 	(*si->si_pbuf_post)(si, pb);
    841 }
    842 
    843 void
    844 stic_eraserows(void *cookie, int row, int num, long attr)
    845 {
    846 	struct stic_info *si;
    847 	struct stic_screen *ss;
    848 	u_int linewidth, i;
    849 	u_int32_t *pb;
    850 
    851 	ss = cookie;
    852 	si = ss->ss_si;
    853 
    854 	if (ss->ss_backing != NULL) {
    855 		pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
    856 		for (i = si->si_consw * num; i > 0; i -= 2)
    857 			*pb++ = (u_int32_t)attr;
    858 	}
    859 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    860 		return;
    861 
    862 	row *= si->si_fonth;
    863 	num *= si->si_fonth;
    864 	attr = (attr & 0xf0) >> 4;
    865 	linewidth = (num << 2) - 1;
    866 	row = (row << 3) + linewidth;
    867 
    868 	pb = (*si->si_pbuf_get)(si);
    869 
    870 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
    871 	pb[1] = 0x01ffffff;
    872 	pb[2] = 0;
    873 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
    874 	pb[4] = linewidth;
    875 	pb[5] = DUPBYTE0(attr);
    876 	pb[6] = row;
    877 	pb[7] = (1280 << 19) | row;
    878 
    879 	(*si->si_pbuf_post)(si, pb);
    880 }
    881 
    882 void
    883 stic_copyrows(void *cookie, int src, int dst, int height)
    884 {
    885 	struct stic_info *si;
    886 	struct stic_screen *ss;
    887 	u_int32_t *pb, *pbs;
    888 	u_int num, inc, adj;
    889 
    890 	ss = cookie;
    891 	si = ss->ss_si;
    892 
    893 	if (ss->ss_backing != NULL)
    894 		bcopy(ss->ss_backing + src * si->si_consw,
    895 		    ss->ss_backing + dst * si->si_consw,
    896 		    si->si_consw * sizeof(*ss->ss_backing) * height);
    897 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    898 		return;
    899 
    900 	/*
    901 	 * We need to do this in reverse if the destination row is below
    902 	 * the source.
    903 	 */
    904 	if (dst > src) {
    905 		src += height;
    906 		dst += height;
    907 		inc = -8;
    908 		adj = -1;
    909 	} else {
    910 		inc = 8;
    911 		adj = 0;
    912 	}
    913 
    914 	src = (src * si->si_fonth + adj) << 3;
    915 	dst = (dst * si->si_fonth + adj) << 3;
    916 	height *= si->si_fonth;
    917 
    918 	while (height > 0) {
    919 		num = (height < 255 ? height : 255);
    920 		height -= num;
    921 
    922 		pbs = (*si->si_pbuf_get)(si);
    923 		pb = pbs;
    924 
    925 		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    926 		pb[1] = (num << 24) | 0xffffff;
    927 		pb[2] = 0x0;
    928 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
    929 		    STAMP_COPYSPAN_ALIGNED;
    930 		pb[4] = 1; /* linewidth */
    931 
    932 		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
    933 			pb[5] = 1280 << 3;
    934 			pb[6] = src;
    935 			pb[7] = dst;
    936 		}
    937 
    938 	    	(*si->si_pbuf_post)(si, pbs);
    939 	}
    940 }
    941 
    942 void
    943 stic_copycols(void *cookie, int row, int src, int dst, int num)
    944 {
    945 	struct stic_info *si;
    946 	struct stic_screen *ss;
    947 	u_int height, updword;
    948 	u_int32_t *pb, *pbs;
    949 
    950 	ss = cookie;
    951 	si = ss->ss_si;
    952 
    953 	if (ss->ss_backing != NULL)
    954 		bcopy(ss->ss_backing + row * si->si_consw + src,
    955 		    ss->ss_backing + row * si->si_consw + dst,
    956 		    num * sizeof(*ss->ss_backing));
    957 	if ((ss->ss_flags & SS_ACTIVE) == 0)
    958 		return;
    959 
    960 	/*
    961 	 * The stamp reads and writes left -> right only, so we need to
    962 	 * buffer the span if the source and destination regions overlap
    963 	 * and the source is left of the destination.
    964 	 */
    965 	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
    966 
    967 	if (src < dst && src + num > dst)
    968 		updword |= STAMP_HALF_BUFF;
    969 
    970 	row = (row * si->si_fonth) << 3;
    971 	num = (num * si->si_fontw) << 3;
    972 	src = row | ((src * si->si_fontw) << 19);
    973 	dst = row | ((dst * si->si_fontw) << 19);
    974 	height = si->si_fonth;
    975 
    976 	pbs = (*si->si_pbuf_get)(si);
    977 	pb = pbs;
    978 
    979 	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
    980 	pb[1] = (height << 24) | 0xffffff;
    981 	pb[2] = 0x0;
    982 	pb[3] = updword;
    983 	pb[4] = 1; /* linewidth */
    984 
    985 	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
    986 		pb[5] = num;
    987 		pb[6] = src;
    988 		pb[7] = dst;
    989 	}
    990 
    991 	(*si->si_pbuf_post)(si, pbs);
    992 }
    993 
    994 void
    995 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
    996 {
    997 	struct wsdisplay_font *font;
    998 	struct stic_screen *ss;
    999 	struct stic_info *si;
   1000 	u_int i, bgcolor, fgcolor;
   1001 	u_int *pb, v1, v2, xya;
   1002 	u_short *fr;
   1003 
   1004 	ss = cookie;
   1005 	si = ss->ss_si;
   1006 
   1007 	/* It's cheaper to use erasecols() to blit blanks. */
   1008 	if (uc == 0) {
   1009 		stic_erasecols(cookie, r, c, 1, attr);
   1010 		return;
   1011 	}
   1012 
   1013 	if (ss->ss_backing != NULL)
   1014 		ss->ss_backing[r * si->si_consw + c] =
   1015 		    (u_short)((attr & 0xff) | (uc << 8));
   1016 	if ((ss->ss_flags & SS_ACTIVE) == 0)
   1017 		return;
   1018 
   1019 	font = si->si_font;
   1020 	pb = (*si->si_pbuf_get)(si);
   1021 
   1022 	/*
   1023 	 * Create a mask from the glyph.  Squeeze the foreground color
   1024 	 * through the mask, and then squeeze the background color through
   1025 	 * the inverted mask.  We may well read outside the glyph when
   1026 	 * creating the mask, but it's bounded by the hardware so it
   1027 	 * shouldn't matter a great deal...
   1028 	 */
   1029 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
   1030 	    STAMP_LW_PERPRIMATIVE;
   1031 	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
   1032 	pb[2] = 0x0;
   1033 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
   1034 
   1035 	r *= font->fontheight;
   1036 	c *= font->fontwidth;
   1037 	uc = (uc - font->firstchar) * font->stride * font->fontheight;
   1038 	fr = (u_short *)((caddr_t)font->data + uc);
   1039 	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
   1040 	fgcolor = DUPBYTE0(attr & 0x0f);
   1041 
   1042 	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
   1043 	v1 = (c << 19) | ((r << 3) + i);
   1044 	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1045 	xya = XYMASKADDR(si->si_stampw, si->si_stamphm, c, r, 0, 0);
   1046 
   1047 	pb[4] = PACK(fr, 0);
   1048 	pb[5] = PACK(fr, 2);
   1049 	pb[6] = PACK(fr, 4);
   1050 	pb[7] = PACK(fr, 6);
   1051 	pb[8] = PACK(fr, 8);
   1052 	pb[9] = PACK(fr, 10);
   1053 	pb[10] = PACK(fr, 12);
   1054 	pb[11] = PACK(fr, 14);
   1055 	pb[12] = xya;
   1056 	pb[13] = v1;
   1057 	pb[14] = v2;
   1058 	pb[15] = i;
   1059 	pb[16] = fgcolor;
   1060 
   1061 	pb[17] = ~pb[4];
   1062 	pb[18] = ~pb[5];
   1063 	pb[19] = ~pb[6];
   1064 	pb[20] = ~pb[7];
   1065 	pb[21] = ~pb[8];
   1066 	pb[22] = ~pb[9];
   1067 	pb[23] = ~pb[10];
   1068 	pb[24] = ~pb[11];
   1069 	pb[25] = xya;
   1070 	pb[26] = v1;
   1071 	pb[27] = v2;
   1072 	pb[28] = i;
   1073 	pb[29] = bgcolor;
   1074 
   1075 	/* Two more squeezes for the lower part of the character. */
   1076 	if (font->fontheight > 16) {
   1077 		i = ((font->fontheight - 16) << 2) - 1;
   1078 		r += 16;
   1079 		v1 = (c << 19) | ((r << 3) + i);
   1080 		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
   1081 
   1082 		pb[30] = PACK(fr, 16);
   1083 		pb[31] = PACK(fr, 18);
   1084 		pb[32] = PACK(fr, 20);
   1085 		pb[33] = PACK(fr, 22);
   1086 		pb[34] = PACK(fr, 24);
   1087 		pb[35] = PACK(fr, 26);
   1088 		pb[36] = PACK(fr, 28);
   1089 		pb[37] = PACK(fr, 30);
   1090 		pb[38] = xya;
   1091 		pb[39] = v1;
   1092 		pb[40] = v2;
   1093 		pb[41] = i;
   1094 		pb[42] = fgcolor;
   1095 
   1096 		pb[43] = ~pb[30];
   1097 		pb[44] = ~pb[31];
   1098 		pb[45] = ~pb[32];
   1099 		pb[46] = ~pb[33];
   1100 		pb[47] = ~pb[34];
   1101 		pb[48] = ~pb[35];
   1102 		pb[49] = ~pb[36];
   1103 		pb[50] = ~pb[37];
   1104 		pb[51] = xya;
   1105 		pb[52] = v1;
   1106 		pb[53] = v2;
   1107 		pb[54] = i;
   1108 		pb[55] = bgcolor;
   1109 	}
   1110 
   1111 	(*si->si_pbuf_post)(si, pb);
   1112 }
   1113 
   1114 int
   1115 stic_mapchar(void *cookie, int c, u_int *cp)
   1116 {
   1117 	struct stic_info *si;
   1118 
   1119 	si = ((struct stic_screen *)cookie)->ss_si;
   1120 
   1121 	if (c < si->si_font->firstchar || c == ' ') {
   1122 		*cp = 0;
   1123 		return (0);
   1124 	}
   1125 
   1126 	if (c - si->si_font->firstchar >= si->si_font->numchars) {
   1127 		*cp = 0;
   1128 		return (0);
   1129 	}
   1130 
   1131 	*cp = c;
   1132 	return (5);
   1133 }
   1134 
   1135 void
   1136 stic_cursor(void *cookie, int on, int row, int col)
   1137 {
   1138 	struct stic_screen *ss;
   1139 	struct stic_info *si;
   1140 	int s;
   1141 
   1142 	ss = cookie;
   1143 	si = ss->ss_si;
   1144 
   1145 	ss->ss_curx = col * si->si_fontw;
   1146 	ss->ss_cury = row * si->si_fonth;
   1147 
   1148 	s = spltty();
   1149 
   1150 	if (on)
   1151 		ss->ss_flags |= SS_CURENB;
   1152 	else
   1153 		ss->ss_flags &= ~SS_CURENB;
   1154 
   1155 	if ((ss->ss_flags & SS_ACTIVE) != 0) {
   1156 		si->si_cursor.cc_pos.x = ss->ss_curx;
   1157 		si->si_cursor.cc_pos.y = ss->ss_cury;
   1158 		si->si_flags |= SI_CURENB_CHANGED;
   1159 		stic_set_hwcurpos(si);
   1160 
   1161 		/*
   1162 		 * XXX Since we don't yet receive vblank interrupts from the
   1163 		 * PXG, we must flush immediatley.
   1164 		 */
   1165 		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1166 			stic_flush(si);
   1167 	}
   1168 
   1169 	splx(s);
   1170 }
   1171 
   1172 void
   1173 stic_flush(struct stic_info *si)
   1174 {
   1175 	volatile u_int32_t *vdac;
   1176 	int v;
   1177 
   1178 	if ((si->si_flags & SI_ALL_CHANGED) == 0)
   1179 		return;
   1180 
   1181 	vdac = si->si_vdac;
   1182 	v = si->si_flags;
   1183 	si->si_flags &= ~SI_ALL_CHANGED;
   1184 
   1185 	if ((v & SI_CURENB_CHANGED) != 0) {
   1186 		SELECT(vdac, BT459_IREG_CCR);
   1187 		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
   1188 			REG(vdac, bt_reg) = 0x00c0c0c0;
   1189 		else
   1190 			REG(vdac, bt_reg) = 0x00000000;
   1191 		tc_wmb();
   1192 	}
   1193 
   1194 	if ((v & SI_CURCMAP_CHANGED) != 0) {
   1195 		u_int8_t *cp;
   1196 
   1197 		cp = si->si_cursor.cc_color;
   1198 
   1199 		SELECT(vdac, BT459_IREG_CCOLOR_2);
   1200 		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
   1201 		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
   1202 		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
   1203 		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
   1204 		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
   1205 		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
   1206 	}
   1207 
   1208 	if ((v & SI_CURSHAPE_CHANGED) != 0) {
   1209 		u_int8_t *ip, *mp, img, msk;
   1210 		u_int8_t u;
   1211 		int bcnt;
   1212 
   1213 		ip = (u_int8_t *)si->si_cursor.cc_image;
   1214 		mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
   1215 
   1216 		bcnt = 0;
   1217 		SELECT(vdac, BT459_IREG_CRAM_BASE);
   1218 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
   1219 		while (bcnt < CURSOR_MAX_SIZE * 16) {
   1220 			img = *ip++;
   1221 			msk = *mp++;
   1222 			img &= msk;	/* cookie off image */
   1223 			u = (msk & 0x0f) << 4 | (img & 0x0f);
   1224 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1225 			tc_wmb();
   1226 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
   1227 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
   1228 			tc_wmb();
   1229 			bcnt += 2;
   1230 		}
   1231 	}
   1232 
   1233 	if ((v & SI_CMAP_CHANGED) != 0) {
   1234 		struct stic_hwcmap256 *cm;
   1235 		int index;
   1236 
   1237 		cm = &si->si_cmap;
   1238 
   1239 		SELECT(vdac, 0);
   1240 		SELECT(vdac, 0);
   1241 		for (index = 0; index < CMAP_SIZE; index++) {
   1242 			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
   1243 			tc_wmb();
   1244 			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
   1245 			tc_wmb();
   1246 			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
   1247 			tc_wmb();
   1248 		}
   1249 	}
   1250 }
   1251 
   1252 int
   1253 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1254 {
   1255 	u_int index, count;
   1256 
   1257 	index = p->index;
   1258 	count = p->count;
   1259 
   1260 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
   1261 		return (EINVAL);
   1262 
   1263 	if (!uvm_useracc(p->red, count, B_WRITE) ||
   1264 	    !uvm_useracc(p->green, count, B_WRITE) ||
   1265 	    !uvm_useracc(p->blue, count, B_WRITE))
   1266 		return (EFAULT);
   1267 
   1268 	copyout(&si->si_cmap.r[index], p->red, count);
   1269 	copyout(&si->si_cmap.g[index], p->green, count);
   1270 	copyout(&si->si_cmap.b[index], p->blue, count);
   1271 	return (0);
   1272 }
   1273 
   1274 int
   1275 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
   1276 {
   1277 	u_int index, count;
   1278 	int s;
   1279 
   1280 	index = p->index;
   1281 	count = p->count;
   1282 
   1283 	if ((index + count) > CMAP_SIZE)
   1284 		return (EINVAL);
   1285 
   1286 	if (!uvm_useracc(p->red, count, B_READ) ||
   1287 	    !uvm_useracc(p->green, count, B_READ) ||
   1288 	    !uvm_useracc(p->blue, count, B_READ))
   1289 		return (EFAULT);
   1290 
   1291 	s = spltty();
   1292 	copyin(p->red, &si->si_cmap.r[index], count);
   1293 	copyin(p->green, &si->si_cmap.g[index], count);
   1294 	copyin(p->blue, &si->si_cmap.b[index], count);
   1295 	si->si_flags |= SI_CMAP_CHANGED;
   1296 	splx(s);
   1297 
   1298 	/*
   1299 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1300 	 * must flush immediatley.
   1301 	 */
   1302 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1303 		stic_flush(si);
   1304 
   1305 	return (0);
   1306 }
   1307 
   1308 int
   1309 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1310 {
   1311 #define	cc (&si->si_cursor)
   1312 	u_int v, index, count, icount;
   1313 	struct stic_screen *ss;
   1314 	int s;
   1315 
   1316 	v = p->which;
   1317 	ss = si->si_curscreen;
   1318 
   1319 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1320 		index = p->cmap.index;
   1321 		count = p->cmap.count;
   1322 		if (index >= 2 || (index + count) > 2)
   1323 			return (EINVAL);
   1324 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
   1325 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
   1326 		    !uvm_useracc(p->cmap.blue, count, B_READ))
   1327 			return (EFAULT);
   1328 	}
   1329 
   1330 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1331 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
   1332 			return (EINVAL);
   1333 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
   1334 		if (!uvm_useracc(p->image, icount, B_READ) ||
   1335 		    !uvm_useracc(p->mask, icount, B_READ))
   1336 			return (EFAULT);
   1337 	}
   1338 
   1339 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
   1340 		if (v & WSDISPLAY_CURSOR_DOCUR)
   1341 			cc->cc_hot = p->hot;
   1342 		if (v & WSDISPLAY_CURSOR_DOPOS)
   1343 			stic_set_curpos(si, &p->pos);
   1344 	}
   1345 
   1346 	s = spltty();
   1347 
   1348 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
   1349 		if (p->enable)
   1350 			ss->ss_flags |= SS_CURENB;
   1351 		else
   1352 			ss->ss_flags &= ~SS_CURENB;
   1353 		si->si_flags |= SI_CURENB_CHANGED;
   1354 	}
   1355 
   1356 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
   1357 		copyin(p->cmap.red, &cc->cc_color[index], count);
   1358 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
   1359 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
   1360 		si->si_flags |= SI_CURCMAP_CHANGED;
   1361 	}
   1362 
   1363 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
   1364 		memset(cc->cc_image, 0, sizeof(cc->cc_image));
   1365 		copyin(p->image, cc->cc_image, icount);
   1366 		copyin(p->mask, cc->cc_image + CURSOR_MAX_SIZE, icount);
   1367 		si->si_flags |= SI_CURSHAPE_CHANGED;
   1368 	}
   1369 
   1370 	splx(s);
   1371 
   1372 	/*
   1373 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
   1374 	 * must flush immediatley.
   1375 	 */
   1376 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
   1377 		stic_flush(si);
   1378 
   1379 	return (0);
   1380 #undef cc
   1381 }
   1382 
   1383 int
   1384 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
   1385 {
   1386 
   1387 	/* XXX */
   1388 	return (EPASSTHROUGH);
   1389 }
   1390 
   1391 void
   1392 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
   1393 {
   1394 	int x, y;
   1395 
   1396 	x = curpos->x;
   1397 	y = curpos->y;
   1398 
   1399 	if (y < 0)
   1400 		y = 0;
   1401 	else if (y > 1023)
   1402 		y = 1023;
   1403 	if (x < 0)
   1404 		x = 0;
   1405 	else if (x > 1279)
   1406 		x = 1279;
   1407 
   1408 	si->si_cursor.cc_pos.x = x;
   1409 	si->si_cursor.cc_pos.y = y;
   1410 	stic_set_hwcurpos(si);
   1411 }
   1412 
   1413 void
   1414 stic_set_hwcurpos(struct stic_info *si)
   1415 {
   1416 	volatile u_int32_t *vdac;
   1417 	int x, y, s;
   1418 
   1419 	vdac = si->si_vdac;
   1420 
   1421 	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
   1422 	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
   1423 	x += STIC_MAGIC_X;
   1424 	y += STIC_MAGIC_Y;
   1425 
   1426 	s = spltty();
   1427 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
   1428 	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
   1429 	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
   1430 	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
   1431 	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
   1432 	splx(s);
   1433 }
   1434 
   1435 /*
   1436  * STIC control inteface.  We have a separate device for mapping the board,
   1437  * because access to the DMA engine means that it's possible to circumvent
   1438  * the securelevel mechanism.  Given the way devices work in the BSD kernel,
   1439  * and given the unfortunate design of the mmap() call it's near impossible
   1440  * to protect against this using a shared device (i.e. wsdisplay).
   1441  *
   1442  * This is a gross hack... Hopefully not too many other devices will need
   1443  * it.
   1444  */
   1445 int
   1446 sticopen(dev_t dev, int flag, int mode, struct proc *p)
   1447 {
   1448 	struct stic_info *si;
   1449 	int s;
   1450 
   1451 	if (securelevel > 0)
   1452 		return (EPERM);
   1453 	if (minor(dev) >= STIC_MAXDV)
   1454 		return (ENXIO);
   1455 	if ((si = stic_info[minor(dev)]) == NULL)
   1456 		return (ENXIO);
   1457 
   1458 	s = spltty();
   1459 	if ((si->si_flags & SI_DVOPEN) != 0) {
   1460 		splx(s);
   1461 		return (EBUSY);
   1462 	}
   1463 	si->si_flags |= SI_DVOPEN;
   1464 	splx(s);
   1465 
   1466 	return (0);
   1467 }
   1468 
   1469 int
   1470 sticclose(dev_t dev, int flag, int mode, struct proc *p)
   1471 {
   1472 	struct stic_info *si;
   1473 	int s;
   1474 
   1475 	si = stic_info[minor(dev)];
   1476 	s = spltty();
   1477 	si->si_flags &= ~SI_DVOPEN;
   1478 	splx(s);
   1479 
   1480 	return (0);
   1481 }
   1482 
   1483 paddr_t
   1484 sticmmap(dev_t dev, off_t offset, int prot)
   1485 {
   1486 	struct stic_info *si;
   1487 	struct stic_xmap *sxm;
   1488 	paddr_t pa;
   1489 
   1490 	si = stic_info[minor(dev)];
   1491 	sxm = NULL;
   1492 
   1493 	if (securelevel > 0)
   1494 		return (-1L);
   1495 	if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
   1496 		return (-1L);
   1497 
   1498 	if (offset < 0)
   1499 		return ((paddr_t)-1L);
   1500 
   1501 	if (offset < sizeof(sxm->sxm_stic)) {
   1502 		pa = STIC_KSEG_TO_PHYS(si->si_stic);
   1503 		return (machine_btop(pa + offset));
   1504 	}
   1505 	offset -= sizeof(sxm->sxm_stic);
   1506 
   1507 	if (offset < sizeof(sxm->sxm_poll)) {
   1508 		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
   1509 		return (machine_btop(pa + offset));
   1510 	}
   1511 	offset -= sizeof(sxm->sxm_poll);
   1512 
   1513 	if (offset < si->si_buf_size)
   1514 		return (machine_btop(si->si_buf_phys + offset));
   1515 
   1516 	return ((paddr_t)-1L);
   1517 }
   1518