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