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