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