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