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