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