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