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