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