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