xref: /netbsd-src/sys/dev/tc/stic.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /*	$NetBSD: stic.c,v 1.12 2001/11/13 06:26:10 lukem 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.12 2001/11/13 06:26:10 lukem 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);
637 	memset(ss->ss_backing, 0, size);
638 }
639 
640 int
641 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
642 		  int *curxp, int *curyp, long *attrp)
643 {
644 	struct stic_info *si;
645 	struct stic_screen *ss;
646 
647 	si = (struct stic_info *)v;
648 
649 	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
650 		ss = &stic_consscr;
651 	else {
652 		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK);
653 		memset(ss, 0, sizeof(*ss));
654 	}
655 	stic_setup_backing(si, ss);
656 
657 	ss->ss_si = si;
658 	ss->ss_flags = SS_ALLOCED | SS_CURENB;
659 
660 	*cookiep = ss;
661 	*curxp = 0;
662 	*curyp = 0;
663 
664 	stic_alloc_attr(ss, 0, 0, 0, attrp);
665 	return (0);
666 }
667 
668 void
669 stic_free_screen(void *v, void *cookie)
670 {
671 	struct stic_screen *ss;
672 
673 	ss = cookie;
674 
675 #ifdef DIAGNOSTIC
676 	if (ss == &stic_consscr)
677 		panic("stic_free_screen: console");
678 	if (ss == ((struct stic_info *)v)->si_curscreen)
679 		panic("stic_free_screen: freeing current screen");
680 #endif
681 
682 	free(ss->ss_backing, M_DEVBUF);
683 	free(ss, M_DEVBUF);
684 }
685 
686 int
687 stic_show_screen(void *v, void *cookie, int waitok,
688 		 void (*cb)(void *, int, int), void *cbarg)
689 {
690 	struct stic_info *si;
691 
692 	si = (struct stic_info *)v;
693 	if (si->si_switchcbarg != NULL)
694 		return (EAGAIN);
695 	si->si_switchcb = cb;
696 	si->si_switchcbarg = cbarg;
697 
698 	if (cb != NULL) {
699 		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
700 		    cookie);
701 		return (EAGAIN);
702 	}
703 
704 	stic_do_switch(cookie);
705 	return (0);
706 }
707 
708 void
709 stic_do_switch(void *cookie)
710 {
711 	struct stic_screen *ss;
712 	struct stic_info *si;
713 	u_int r, c, nr, nc;
714 	u_int16_t *p, *sp;
715 
716 	ss = cookie;
717 	si = ss->ss_si;
718 
719 #ifdef DIAGNOSTIC
720 	if (ss->ss_backing == NULL)
721 		panic("stic_do_switch: screen not backed");
722 #endif
723 
724 	/* Swap in the new screen, and temporarily disable its backing. */
725 	if (si->si_curscreen != NULL)
726 		si->si_curscreen->ss_flags ^= SS_ACTIVE;
727 	si->si_curscreen = ss;
728 	ss->ss_flags |= SS_ACTIVE;
729 	sp = ss->ss_backing;
730 	ss->ss_backing = NULL;
731 
732 	/*
733 	 * We assume that most of the screen is blank and blast it with
734 	 * eraserows(), because eraserows() is cheap.
735 	 */
736 	nr = si->si_consh;
737 	stic_eraserows(ss, 0, nr, 0);
738 
739 	nc = si->si_consw;
740 	p = sp;
741 	for (r = 0; r < nr; r++)
742 		for (c = 0; c < nc; c += 2, p += 2) {
743 			if ((p[0] & 0xfff0) != 0)
744 				stic_putchar(ss, r, c, p[0] >> 8,
745 				    p[0] & 0x00ff);
746 			if ((p[1] & 0xfff0) != 0)
747 				stic_putchar(ss, r, c + 1, p[1] >> 8,
748 				    p[1] & 0x00ff);
749 		}
750 
751 	/*
752 	 * Re-enable the screen's backing, and move the cursor to the
753 	 * correct spot.
754 	 */
755 	ss->ss_backing = sp;
756 	si->si_cursor.cc_pos.x = ss->ss_curx;
757 	si->si_cursor.cc_pos.y = ss->ss_cury;
758 	stic_set_hwcurpos(si);
759 	si->si_flags |= SI_CURENB_CHANGED;
760 
761 	/*
762 	 * XXX Since we don't yet receive vblank interrupts from the
763 	 * PXG, we must flush immediatley.
764 	 */
765 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
766 		stic_flush(si);
767 
768 	/* Tell wscons that we're done. */
769 	if (si->si_switchcbarg != NULL) {
770 		cookie = si->si_switchcbarg;
771 		si->si_switchcbarg = NULL;
772 		(*si->si_switchcb)(cookie, 0, 0);
773 	}
774 }
775 
776 int
777 stic_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
778 {
779 	long tmp;
780 
781 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
782 		return (EINVAL);
783 
784 	if ((flags & WSATTR_WSCOLORS) == 0) {
785 		fg = 7;
786 		bg = 0;
787 	}
788 
789 	if ((flags & WSATTR_HILIT) != 0)
790 		fg += 8;
791 
792 	tmp = fg | (bg << 4);
793 	*attr = tmp | (tmp << 16);
794 	return (0);
795 }
796 
797 void
798 stic_erasecols(void *cookie, int row, int col, int num, long attr)
799 {
800 	struct stic_info *si;
801 	struct stic_screen *ss;
802 	u_int32_t *pb;
803 	u_int i, linewidth;
804 	u_int16_t *p;
805 
806 	ss = cookie;
807 	si = ss->ss_si;
808 
809 	if (ss->ss_backing != NULL) {
810 		p = ss->ss_backing + row * si->si_consw + col;
811 		for (i = num; i != 0; i--)
812 			*p++ = (u_int16_t)attr;
813 	}
814 	if ((ss->ss_flags & SS_ACTIVE) == 0)
815 		return;
816 
817 	col = (col * si->si_fontw) << 19;
818 	num = (num * si->si_fontw) << 19;
819 	row = row * si->si_fonth;
820 	attr = (attr & 0xf0) >> 4;
821 	linewidth = (si->si_fonth << 2) - 1;
822 	row = (row << 3) + linewidth;
823 
824 	pb = (*si->si_pbuf_get)(si);
825 
826 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
827 	pb[1] = 0x01ffffff;
828 	pb[2] = 0;
829 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
830 	pb[4] = linewidth;
831 	pb[5] = DUPBYTE0(attr);
832 	pb[6] = col | row;
833 	pb[7] = (col + num) | row;
834 
835 	(*si->si_pbuf_post)(si, pb);
836 }
837 
838 void
839 stic_eraserows(void *cookie, int row, int num, long attr)
840 {
841 	struct stic_info *si;
842 	struct stic_screen *ss;
843 	u_int linewidth, i;
844 	u_int32_t *pb;
845 
846 	ss = cookie;
847 	si = ss->ss_si;
848 
849 	if (ss->ss_backing != NULL) {
850 		pb = (u_int32_t *)(ss->ss_backing + row * si->si_consw);
851 		for (i = si->si_consw * num; i > 0; i -= 2)
852 			*pb++ = (u_int32_t)attr;
853 	}
854 	if ((ss->ss_flags & SS_ACTIVE) == 0)
855 		return;
856 
857 	row *= si->si_fonth;
858 	num *= si->si_fonth;
859 	attr = (attr & 0xf0) >> 4;
860 	linewidth = (num << 2) - 1;
861 	row = (row << 3) + linewidth;
862 
863 	pb = (*si->si_pbuf_get)(si);
864 
865 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
866 	pb[1] = 0x01ffffff;
867 	pb[2] = 0;
868 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
869 	pb[4] = linewidth;
870 	pb[5] = DUPBYTE0(attr);
871 	pb[6] = row;
872 	pb[7] = (1280 << 19) | row;
873 
874 	(*si->si_pbuf_post)(si, pb);
875 }
876 
877 void
878 stic_copyrows(void *cookie, int src, int dst, int height)
879 {
880 	struct stic_info *si;
881 	struct stic_screen *ss;
882 	u_int32_t *pb, *pbs;
883 	u_int num, inc, adj;
884 
885 	ss = cookie;
886 	si = ss->ss_si;
887 
888 	if (ss->ss_backing != NULL)
889 		bcopy(ss->ss_backing + src * si->si_consw,
890 		    ss->ss_backing + dst * si->si_consw,
891 		    si->si_consw * sizeof(*ss->ss_backing) * height);
892 	if ((ss->ss_flags & SS_ACTIVE) == 0)
893 		return;
894 
895 	/*
896 	 * We need to do this in reverse if the destination row is below
897 	 * the source.
898 	 */
899 	if (dst > src) {
900 		src += height;
901 		dst += height;
902 		inc = -8;
903 		adj = -1;
904 	} else {
905 		inc = 8;
906 		adj = 0;
907 	}
908 
909 	src = (src * si->si_fonth + adj) << 3;
910 	dst = (dst * si->si_fonth + adj) << 3;
911 	height *= si->si_fonth;
912 
913 	while (height > 0) {
914 		num = (height < 255 ? height : 255);
915 		height -= num;
916 
917 		pbs = (*si->si_pbuf_get)(si);
918 		pb = pbs;
919 
920 		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
921 		pb[1] = (num << 24) | 0xffffff;
922 		pb[2] = 0x0;
923 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
924 		    STAMP_COPYSPAN_ALIGNED;
925 		pb[4] = 1; /* linewidth */
926 
927 		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
928 			pb[5] = 1280 << 3;
929 			pb[6] = src;
930 			pb[7] = dst;
931 		}
932 
933 	    	(*si->si_pbuf_post)(si, pbs);
934 	}
935 }
936 
937 void
938 stic_copycols(void *cookie, int row, int src, int dst, int num)
939 {
940 	struct stic_info *si;
941 	struct stic_screen *ss;
942 	u_int height, updword;
943 	u_int32_t *pb, *pbs;
944 
945 	ss = cookie;
946 	si = ss->ss_si;
947 
948 	if (ss->ss_backing != NULL)
949 		bcopy(ss->ss_backing + row * si->si_consw + src,
950 		    ss->ss_backing + row * si->si_consw + dst,
951 		    num * sizeof(*ss->ss_backing));
952 	if ((ss->ss_flags & SS_ACTIVE) == 0)
953 		return;
954 
955 	/*
956 	 * The stamp reads and writes left -> right only, so we need to
957 	 * buffer the span if the source and destination regions overlap
958 	 * and the source is left of the destination.
959 	 */
960 	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
961 
962 	if (src < dst && src + num > dst)
963 		updword |= STAMP_HALF_BUFF;
964 
965 	row = (row * si->si_fonth) << 3;
966 	num = (num * si->si_fontw) << 3;
967 	src = row | ((src * si->si_fontw) << 19);
968 	dst = row | ((dst * si->si_fontw) << 19);
969 	height = si->si_fonth;
970 
971 	pbs = (*si->si_pbuf_get)(si);
972 	pb = pbs;
973 
974 	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
975 	pb[1] = (height << 24) | 0xffffff;
976 	pb[2] = 0x0;
977 	pb[3] = updword;
978 	pb[4] = 1; /* linewidth */
979 
980 	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
981 		pb[5] = num;
982 		pb[6] = src;
983 		pb[7] = dst;
984 	}
985 
986 	(*si->si_pbuf_post)(si, pbs);
987 }
988 
989 void
990 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
991 {
992 	struct wsdisplay_font *font;
993 	struct stic_screen *ss;
994 	struct stic_info *si;
995 	u_int i, bgcolor, fgcolor;
996 	u_int *pb, v1, v2, xya;
997 	u_short *fr;
998 
999 	ss = cookie;
1000 	si = ss->ss_si;
1001 
1002 	/* It's cheaper to use erasecols() to blit blanks. */
1003 	if (uc == 0) {
1004 		stic_erasecols(cookie, r, c, 1, attr);
1005 		return;
1006 	}
1007 
1008 	if (ss->ss_backing != NULL)
1009 		ss->ss_backing[r * si->si_consw + c] =
1010 		    (u_short)((attr & 0xff) | (uc << 8));
1011 	if ((ss->ss_flags & SS_ACTIVE) == 0)
1012 		return;
1013 
1014 	font = si->si_font;
1015 	pb = (*si->si_pbuf_get)(si);
1016 
1017 	/*
1018 	 * Create a mask from the glyph.  Squeeze the foreground color
1019 	 * through the mask, and then squeeze the background color through
1020 	 * the inverted mask.  We may well read outside the glyph when
1021 	 * creating the mask, but it's bounded by the hardware so it
1022 	 * shouldn't matter a great deal...
1023 	 */
1024 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
1025 	    STAMP_LW_PERPRIMATIVE;
1026 	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
1027 	pb[2] = 0x0;
1028 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
1029 
1030 	r *= font->fontheight;
1031 	c *= font->fontwidth;
1032 	uc = (uc - font->firstchar) * font->stride * font->fontheight;
1033 	fr = (u_short *)((caddr_t)font->data + uc);
1034 	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
1035 	fgcolor = DUPBYTE0(attr & 0x0f);
1036 
1037 	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
1038 	v1 = (c << 19) | ((r << 3) + i);
1039 	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1040 	xya = XYMASKADDR(si->si_stampw, si->si_stamph, c, r, 0, 0);
1041 
1042 	pb[4] = PACK(fr, 0);
1043 	pb[5] = PACK(fr, 2);
1044 	pb[6] = PACK(fr, 4);
1045 	pb[7] = PACK(fr, 6);
1046 	pb[8] = PACK(fr, 8);
1047 	pb[9] = PACK(fr, 10);
1048 	pb[10] = PACK(fr, 12);
1049 	pb[11] = PACK(fr, 14);
1050 	pb[12] = xya;
1051 	pb[13] = v1;
1052 	pb[14] = v2;
1053 	pb[15] = i;
1054 	pb[16] = fgcolor;
1055 
1056 	pb[17] = ~pb[4];
1057 	pb[18] = ~pb[5];
1058 	pb[19] = ~pb[6];
1059 	pb[20] = ~pb[7];
1060 	pb[21] = ~pb[8];
1061 	pb[22] = ~pb[9];
1062 	pb[23] = ~pb[10];
1063 	pb[24] = ~pb[11];
1064 	pb[25] = xya;
1065 	pb[26] = v1;
1066 	pb[27] = v2;
1067 	pb[28] = i;
1068 	pb[29] = bgcolor;
1069 
1070 	/* Two more squeezes for the lower part of the character. */
1071 	if (font->fontheight > 16) {
1072 		i = ((font->fontheight - 16) << 2) - 1;
1073 		r += 16;
1074 		v1 = (c << 19) | ((r << 3) + i);
1075 		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1076 
1077 		pb[30] = PACK(fr, 16);
1078 		pb[31] = PACK(fr, 18);
1079 		pb[32] = PACK(fr, 20);
1080 		pb[33] = PACK(fr, 22);
1081 		pb[34] = PACK(fr, 24);
1082 		pb[35] = PACK(fr, 26);
1083 		pb[36] = PACK(fr, 28);
1084 		pb[37] = PACK(fr, 30);
1085 		pb[38] = xya;
1086 		pb[39] = v1;
1087 		pb[40] = v2;
1088 		pb[41] = i;
1089 		pb[42] = fgcolor;
1090 
1091 		pb[43] = ~pb[30];
1092 		pb[44] = ~pb[31];
1093 		pb[45] = ~pb[32];
1094 		pb[46] = ~pb[33];
1095 		pb[47] = ~pb[34];
1096 		pb[48] = ~pb[35];
1097 		pb[49] = ~pb[36];
1098 		pb[50] = ~pb[37];
1099 		pb[51] = xya;
1100 		pb[52] = v1;
1101 		pb[53] = v2;
1102 		pb[54] = i;
1103 		pb[55] = bgcolor;
1104 	}
1105 
1106 	(*si->si_pbuf_post)(si, pb);
1107 }
1108 
1109 int
1110 stic_mapchar(void *cookie, int c, u_int *cp)
1111 {
1112 	struct stic_info *si;
1113 
1114 	si = ((struct stic_screen *)cookie)->ss_si;
1115 
1116 	if (c < si->si_font->firstchar || c == ' ') {
1117 		*cp = 0;
1118 		return (0);
1119 	}
1120 
1121 	if (c - si->si_font->firstchar >= si->si_font->numchars) {
1122 		*cp = 0;
1123 		return (0);
1124 	}
1125 
1126 	*cp = c;
1127 	return (5);
1128 }
1129 
1130 void
1131 stic_cursor(void *cookie, int on, int row, int col)
1132 {
1133 	struct stic_screen *ss;
1134 	struct stic_info *si;
1135 	int s;
1136 
1137 	ss = cookie;
1138 	si = ss->ss_si;
1139 
1140 	ss->ss_curx = col * si->si_fontw;
1141 	ss->ss_cury = row * si->si_fonth;
1142 
1143 	s = spltty();
1144 
1145 	if (on)
1146 		ss->ss_flags |= SS_CURENB;
1147 	else
1148 		ss->ss_flags &= ~SS_CURENB;
1149 
1150 	if ((ss->ss_flags & SS_ACTIVE) != 0) {
1151 		si->si_cursor.cc_pos.x = ss->ss_curx;
1152 		si->si_cursor.cc_pos.y = ss->ss_cury;
1153 		si->si_flags |= SI_CURENB_CHANGED;
1154 		stic_set_hwcurpos(si);
1155 
1156 		/*
1157 		 * XXX Since we don't yet receive vblank interrupts from the
1158 		 * PXG, we must flush immediatley.
1159 		 */
1160 		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1161 			stic_flush(si);
1162 	}
1163 
1164 	splx(s);
1165 }
1166 
1167 void
1168 stic_flush(struct stic_info *si)
1169 {
1170 	volatile u_int32_t *vdac;
1171 	int v;
1172 
1173 	if ((si->si_flags & SI_ALL_CHANGED) == 0)
1174 		return;
1175 
1176 	vdac = si->si_vdac;
1177 	v = si->si_flags;
1178 	si->si_flags &= ~SI_ALL_CHANGED;
1179 
1180 	if ((v & SI_CURENB_CHANGED) != 0) {
1181 		SELECT(vdac, BT459_IREG_CCR);
1182 		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
1183 			REG(vdac, bt_reg) = 0x00c0c0c0;
1184 		else
1185 			REG(vdac, bt_reg) = 0x00000000;
1186 		tc_wmb();
1187 	}
1188 
1189 	if ((v & SI_CURCMAP_CHANGED) != 0) {
1190 		u_int8_t *cp;
1191 
1192 		cp = si->si_cursor.cc_color;
1193 
1194 		SELECT(vdac, BT459_IREG_CCOLOR_2);
1195 		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
1196 		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
1197 		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
1198 		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
1199 		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
1200 		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
1201 	}
1202 
1203 	if ((v & SI_CURSHAPE_CHANGED) != 0) {
1204 		u_int8_t *ip, *mp, img, msk;
1205 		u_int8_t u;
1206 		int bcnt;
1207 
1208 		ip = (u_int8_t *)si->si_cursor.cc_image;
1209 		mp = (u_int8_t *)(si->si_cursor.cc_image + CURSOR_MAX_SIZE);
1210 
1211 		bcnt = 0;
1212 		SELECT(vdac, BT459_IREG_CRAM_BASE);
1213 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
1214 		while (bcnt < CURSOR_MAX_SIZE * 16) {
1215 			img = *ip++;
1216 			msk = *mp++;
1217 			img &= msk;	/* cookie off image */
1218 			u = (msk & 0x0f) << 4 | (img & 0x0f);
1219 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1220 			tc_wmb();
1221 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
1222 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1223 			tc_wmb();
1224 			bcnt += 2;
1225 		}
1226 	}
1227 
1228 	if ((v & SI_CMAP_CHANGED) != 0) {
1229 		struct stic_hwcmap256 *cm;
1230 		int index;
1231 
1232 		cm = &si->si_cmap;
1233 
1234 		SELECT(vdac, 0);
1235 		SELECT(vdac, 0);
1236 		for (index = 0; index < CMAP_SIZE; index++) {
1237 			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
1238 			tc_wmb();
1239 			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
1240 			tc_wmb();
1241 			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
1242 			tc_wmb();
1243 		}
1244 	}
1245 }
1246 
1247 int
1248 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1249 {
1250 	u_int index, count;
1251 
1252 	index = p->index;
1253 	count = p->count;
1254 
1255 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
1256 		return (EINVAL);
1257 
1258 	if (!uvm_useracc(p->red, count, B_WRITE) ||
1259 	    !uvm_useracc(p->green, count, B_WRITE) ||
1260 	    !uvm_useracc(p->blue, count, B_WRITE))
1261 		return (EFAULT);
1262 
1263 	copyout(&si->si_cmap.r[index], p->red, count);
1264 	copyout(&si->si_cmap.g[index], p->green, count);
1265 	copyout(&si->si_cmap.b[index], p->blue, count);
1266 	return (0);
1267 }
1268 
1269 int
1270 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1271 {
1272 	u_int index, count;
1273 	int s;
1274 
1275 	index = p->index;
1276 	count = p->count;
1277 
1278 	if ((index + count) > CMAP_SIZE)
1279 		return (EINVAL);
1280 
1281 	if (!uvm_useracc(p->red, count, B_READ) ||
1282 	    !uvm_useracc(p->green, count, B_READ) ||
1283 	    !uvm_useracc(p->blue, count, B_READ))
1284 		return (EFAULT);
1285 
1286 	s = spltty();
1287 	copyin(p->red, &si->si_cmap.r[index], count);
1288 	copyin(p->green, &si->si_cmap.g[index], count);
1289 	copyin(p->blue, &si->si_cmap.b[index], count);
1290 	si->si_flags |= SI_CMAP_CHANGED;
1291 	splx(s);
1292 
1293 	/*
1294 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1295 	 * must flush immediatley.
1296 	 */
1297 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1298 		stic_flush(si);
1299 
1300 	return (0);
1301 }
1302 
1303 int
1304 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1305 {
1306 #define	cc (&si->si_cursor)
1307 	u_int v, index, count, icount;
1308 	struct stic_screen *ss;
1309 	int s;
1310 
1311 	v = p->which;
1312 	ss = si->si_curscreen;
1313 
1314 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1315 		index = p->cmap.index;
1316 		count = p->cmap.count;
1317 		if (index >= 2 || (index + count) > 2)
1318 			return (EINVAL);
1319 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
1320 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
1321 		    !uvm_useracc(p->cmap.blue, count, B_READ))
1322 			return (EFAULT);
1323 	}
1324 
1325 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1326 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
1327 			return (EINVAL);
1328 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
1329 		if (!uvm_useracc(p->image, icount, B_READ) ||
1330 		    !uvm_useracc(p->mask, icount, B_READ))
1331 			return (EFAULT);
1332 	}
1333 
1334 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
1335 		if (v & WSDISPLAY_CURSOR_DOCUR)
1336 			cc->cc_hot = p->hot;
1337 		if (v & WSDISPLAY_CURSOR_DOPOS)
1338 			stic_set_curpos(si, &p->pos);
1339 	}
1340 
1341 	s = spltty();
1342 
1343 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
1344 		if (p->enable)
1345 			ss->ss_flags |= SS_CURENB;
1346 		else
1347 			ss->ss_flags &= ~SS_CURENB;
1348 		si->si_flags |= SI_CURENB_CHANGED;
1349 	}
1350 
1351 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1352 		copyin(p->cmap.red, &cc->cc_color[index], count);
1353 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
1354 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
1355 		si->si_flags |= SI_CURCMAP_CHANGED;
1356 	}
1357 
1358 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1359 		memset(cc->cc_image, 0, sizeof(cc->cc_image));
1360 		copyin(p->image, cc->cc_image, icount);
1361 		copyin(p->mask, cc->cc_image + CURSOR_MAX_SIZE, icount);
1362 		si->si_flags |= SI_CURSHAPE_CHANGED;
1363 	}
1364 
1365 	splx(s);
1366 
1367 	/*
1368 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1369 	 * must flush immediatley.
1370 	 */
1371 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1372 		stic_flush(si);
1373 
1374 	return (0);
1375 #undef cc
1376 }
1377 
1378 int
1379 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1380 {
1381 
1382 	/* XXX */
1383 	return (ENOTTY);
1384 }
1385 
1386 void
1387 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
1388 {
1389 	int x, y;
1390 
1391 	x = curpos->x;
1392 	y = curpos->y;
1393 
1394 	if (y < 0)
1395 		y = 0;
1396 	else if (y > 1023)
1397 		y = 1023;
1398 	if (x < 0)
1399 		x = 0;
1400 	else if (x > 1279)
1401 		x = 1279;
1402 
1403 	si->si_cursor.cc_pos.x = x;
1404 	si->si_cursor.cc_pos.y = y;
1405 	stic_set_hwcurpos(si);
1406 }
1407 
1408 void
1409 stic_set_hwcurpos(struct stic_info *si)
1410 {
1411 	volatile u_int32_t *vdac;
1412 	int x, y, s;
1413 
1414 	vdac = si->si_vdac;
1415 
1416 	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
1417 	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
1418 	x += STIC_MAGIC_X;
1419 	y += STIC_MAGIC_Y;
1420 
1421 	s = spltty();
1422 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
1423 	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
1424 	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
1425 	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
1426 	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
1427 	splx(s);
1428 }
1429 
1430 /*
1431  * STIC control inteface.  We have a seperate device for mapping the board,
1432  * because access to the DMA engine means that it's possible to circumvent
1433  * the securelevel mechanism.  Given the way devices work in the BSD kernel,
1434  * and given the unfortunate design of the mmap() call it's near impossible
1435  * to protect against this using a shared device (i.e. wsdisplay).
1436  *
1437  * This is a gross hack... Hopefully not too many other devices will need
1438  * it.
1439  */
1440 int
1441 sticopen(dev_t dev, int flag, int mode, struct proc *p)
1442 {
1443 	struct stic_info *si;
1444 	int s;
1445 
1446 	if (securelevel > 0)
1447 		return (EPERM);
1448 	if (minor(dev) >= STIC_MAXDV)
1449 		return (ENXIO);
1450 	if ((si = stic_info[minor(dev)]) == NULL)
1451 		return (ENXIO);
1452 
1453 	s = spltty();
1454 	if ((si->si_flags & SI_DVOPEN) != 0) {
1455 		splx(s);
1456 		return (EBUSY);
1457 	}
1458 	si->si_flags |= SI_DVOPEN;
1459 	splx(s);
1460 
1461 	return (0);
1462 }
1463 
1464 int
1465 sticclose(dev_t dev, int flag, int mode, struct proc *p)
1466 {
1467 	struct stic_info *si;
1468 	int s;
1469 
1470 	si = stic_info[minor(dev)];
1471 	s = spltty();
1472 	si->si_flags &= ~SI_DVOPEN;
1473 	splx(s);
1474 
1475 	return (0);
1476 }
1477 
1478 paddr_t
1479 sticmmap(dev_t dev, off_t offset, int prot)
1480 {
1481 	struct stic_info *si;
1482 	struct stic_xmap *sxm;
1483 	paddr_t pa;
1484 
1485 	si = stic_info[minor(dev)];
1486 	sxm = NULL;
1487 
1488 	if (securelevel > 0)
1489 		return (-1L);
1490 	if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
1491 		return (-1L);
1492 
1493 	if (offset < 0)
1494 		return ((paddr_t)-1L);
1495 
1496 	if (offset < sizeof(sxm->sxm_stic)) {
1497 		pa = STIC_KSEG_TO_PHYS(si->si_stic);
1498 		return (machine_btop(pa + offset));
1499 	}
1500 	offset -= sizeof(sxm->sxm_stic);
1501 
1502 	if (offset < sizeof(sxm->sxm_poll)) {
1503 		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
1504 		return (machine_btop(pa + offset));
1505 	}
1506 	offset -= sizeof(sxm->sxm_poll);
1507 
1508 	if (offset < si->si_buf_size)
1509 		return (machine_btop(si->si_buf_phys + offset));
1510 
1511 	return ((paddr_t)-1L);
1512 }
1513