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