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