1/*	$NetBSD: stic.c,v 1.59 2022/07/20 15:45:28 thorpej 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.59 2022/07/20 15:45:28 thorpej 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
124static int	sticioctl(void *, void *, u_long, void *, int, struct lwp *);
125static int	stic_alloc_screen(void *, const struct wsscreen_descr *,
126				  void **, int *, int *, long *);
127static void	stic_free_screen(void *, void *);
128static int	stic_show_screen(void *, void *, int,
129				 void (*)(void *, int, int), void *);
130
131static void	stic_do_switch(void *);
132static void	stic_setup_backing(struct stic_info *, struct stic_screen *);
133static void	stic_setup_vdac(struct stic_info *);
134static void	stic_clear_screen(struct stic_info *);
135
136static int	stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *);
137static int	stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *);
138static int	stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *);
139static int	stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *);
140static void	stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *);
141static void	stic_set_hwcurpos(struct stic_info *);
142
143static void	stic_cursor(void *, int, int, int);
144static void	stic_copycols(void *, int, int, int, int);
145static void	stic_copyrows(void *, int, int, int);
146static void	stic_erasecols(void *, int, int, int, long);
147static void	stic_eraserows(void *, int, int, long);
148static int	stic_mapchar(void *, int, u_int *);
149static void	stic_putchar(void *, int, int, u_int, long);
150static int	stic_allocattr(void *, int, int, int, long *);
151
152static dev_type_open(sticopen);
153static dev_type_close(sticclose);
154static dev_type_mmap(sticmmap);
155
156const 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. */
172static 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 */
199static 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
234static 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
243static 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
254static struct wsscreen_descr stic_stdscreen = {
255	"std",
256	0, 0,
257	&stic_emulops,
258	0, 0,
259	WSSCREEN_WSCOLORS | WSSCREEN_HILIT
260};
261
262static const struct wsscreen_descr *_stic_scrlist[] = {
263	&stic_stdscreen,
264};
265
266static const struct wsscreen_list stic_screenlist = {
267	sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist
268};
269
270struct	stic_info stic_consinfo;
271static struct	stic_screen stic_consscr;
272static struct	stic_info *stic_info[STIC_MAXDV];
273static int	stic_unit;
274
275void
276stic_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_syncbus();
292	DELAY(1000);
293
294	/* Finish the initialization. */
295	SELECT(vdac, BT459_IREG_COMMAND_1);
296	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
297	REG(vdac, bt_reg) = 0x00c2c2c2; tc_wmb();
298	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
299
300	for (i = 0; i < 7; i++) {
301		REG(vdac, bt_reg) = 0x00000000;
302		tc_wmb();
303	}
304
305	/* Set cursor colormap. */
306	SELECT(vdac, BT459_IREG_CCOLOR_1);
307	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
308	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
309	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
310	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
311	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
312	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
313	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
314	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
315	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
316
317	/* Get a font and set up screen metrics. */
318	wsfont_init();
319
320	cookie = wsfont_find(NULL, 12, 0, 2, WSDISPLAY_FONTORDER_R2L,
321	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
322	if (cookie <= 0)
323		cookie = wsfont_find(NULL, 0, 0, 2, WSDISPLAY_FONTORDER_R2L,
324		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
325	if (cookie <= 0)
326		panic("stic_init: font table is empty");
327
328	if (wsfont_lock(cookie, &si->si_font))
329		panic("stic_init: couldn't lock font");
330
331	si->si_fontw = si->si_font->fontwidth;
332	si->si_fonth = si->si_font->fontheight;
333	si->si_consw = (1280 / si->si_fontw) & ~1;
334	si->si_consh = 1024 / si->si_fonth;
335	stic_stdscreen.ncols = si->si_consw;
336	stic_stdscreen.nrows = si->si_consh;
337
338#ifdef DIAGNOSTIC
339	if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
340		panic("stic_init: unusable font");
341#endif
342
343	stic_setup_vdac(si);
344	stic_clear_screen(si);
345	si->si_dispmode = WSDISPLAYIO_MODE_EMUL;
346}
347
348void
349stic_reset(struct stic_info *si)
350{
351	int modtype, xconfig, yconfig, config;
352	volatile struct stic_regs *sr;
353
354	sr = si->si_stic;
355
356	/*
357	 * Initialize the interface chip registers.
358	 */
359	sr->sr_sticsr = 0x00000030;	/* Get the STIC's attention. */
360	tc_syncbus();
361	DELAY(2000);			/* wait 2ms for STIC to respond. */
362	sr->sr_sticsr = 0x00000000;	/* Hit the STIC's csr again... */
363	tc_wmb();
364	sr->sr_buscsr = 0xffffffff;	/* and bash its bus-access csr. */
365	tc_syncbus();			/* Blam! */
366	DELAY(20000);			/* wait until the stic recovers... */
367
368	modtype = sr->sr_modcl;
369	xconfig = (modtype & 0x800) >> 11;
370	yconfig = (modtype & 0x600) >> 9;
371	config = (yconfig << 1) | xconfig;
372	si->si_stampw = (xconfig ? 5 : 4);
373	si->si_stamph = (1 << yconfig);
374	si->si_stamphm = si->si_stamph - 1;
375#ifdef notyet
376	si->si_option = (char)((modtype >> 12) & 3);
377#endif
378
379	/* First PixelStamp */
380	si->si_stamp[0x000b0] = config;
381	si->si_stamp[0x000b4] = 0x0;
382
383	/* Second PixelStamp */
384	if (yconfig > 0) {
385		si->si_stamp[0x100b0] = config | 8;
386		si->si_stamp[0x100b4] = 0;
387	}
388
389	/*
390	 * Initialize STIC video registers.  Enable error and vertical
391	 * retrace interrupts.  Set the packet done flag so the Xserver will
392	 * not time-out on the first packet submitted.
393	 */
394	sr->sr_vblank = (1024 << 16) | 1063;
395	sr->sr_vsync = (1027 << 16) | 1030;
396	sr->sr_hblank = (255 << 16) | 340;
397	sr->sr_hsync2 = 245;
398	sr->sr_hsync = (261 << 16) | 293;
399	sr->sr_ipdvint =
400	    STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN;
401	sr->sr_sticsr = 8;
402	tc_syncbus();
403}
404
405void
406stic_attach(device_t self, struct stic_info *si, int console)
407{
408	struct wsemuldisplaydev_attach_args waa;
409
410	if (stic_unit < STIC_MAXDV) {
411		stic_info[stic_unit] = si;
412		si->si_unit = stic_unit++;
413	} else
414		si->si_unit = -1;
415
416	callout_init(&si->si_switch_callout, 0);
417
418	/*
419	 * Allocate backing for the console.  We could trawl back through
420	 * msgbuf and fill the backing, but it's not worth the hassle.
421	 * We could also grab backing using pmap_steal_memory() early on,
422	 * but that's a little ugly.
423	 */
424	if (console)
425		stic_setup_backing(si, &stic_consscr);
426
427	waa.console = console;
428	waa.scrdata = &stic_screenlist;
429	waa.accessops = &stic_accessops;
430	waa.accesscookie = si;
431
432	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
433}
434
435void
436stic_cnattach(struct stic_info *si)
437{
438	struct stic_screen *ss;
439	long defattr;
440
441	ss = &stic_consscr;
442	si->si_curscreen = ss;
443	ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
444	ss->ss_si = si;
445
446	si->si_flags |= SI_CURENB_CHANGED;
447	stic_flush(si);
448
449	stic_allocattr(ss, 0, 0, 0, &defattr);
450	stic_eraserows(ss, 0, si->si_consh, 0);
451	wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
452}
453
454static void
455stic_setup_vdac(struct stic_info *si)
456{
457	uint8_t *ip, *mp;
458	int r, c, o, b, i, s;
459
460	s = spltty();
461
462	ip = (uint8_t *)si->si_cursor.cc_image;
463	mp = (uint8_t *)si->si_cursor.cc_mask;
464	memset(ip, 0, sizeof(si->si_cursor.cc_image));
465	memset(mp, 0, sizeof(si->si_cursor.cc_mask));
466
467	for (r = 0; r < si->si_fonth; r++) {
468		for (c = r & 1; c < si->si_fontw; c += 2) {
469			o = c >> 3;
470			b = 1 << (c & 7);
471			ip[o] |= b;
472			mp[o] |= b;
473		}
474
475		ip += 8;
476		mp += 8;
477	}
478
479	si->si_cursor.cc_size.x = 64;
480	si->si_cursor.cc_size.y = si->si_fonth;
481	si->si_cursor.cc_hot.x = 0;
482	si->si_cursor.cc_hot.y = 0;
483
484	si->si_cursor.cc_color[0] = 0xff;
485	si->si_cursor.cc_color[2] = 0xff;
486	si->si_cursor.cc_color[4] = 0xff;
487	si->si_cursor.cc_color[1] = 0x00;
488	si->si_cursor.cc_color[3] = 0x00;
489	si->si_cursor.cc_color[5] = 0x00;
490
491	memset(&si->si_cmap, 0, sizeof(si->si_cmap));
492	for (i = 0; i < 16; i++) {
493		si->si_cmap.r[i] = stic_cmap[i*3 + 0];
494		si->si_cmap.g[i] = stic_cmap[i*3 + 1];
495		si->si_cmap.b[i] = stic_cmap[i*3 + 2];
496	}
497
498	si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
499	    SI_CURCMAP_CHANGED;
500
501	splx(s);
502}
503
504static void
505stic_clear_screen(struct stic_info *si)
506{
507	uint32_t *pb;
508	int i;
509
510	/*
511	 * Do this twice, since the first packet after a reset may be
512	 * silently ignored.
513	 */
514	for (i = 0; i < 2; i++) {
515		pb = (*si->si_pbuf_get)(si);
516
517		pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
518		pb[1] = 0x01ffffff;
519		pb[2] = 0;
520		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
521		pb[4] = (1024 << 2) - 1;
522		pb[5] = 0;
523		pb[6] = 0;
524		pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]);
525
526		(*si->si_pbuf_post)(si, pb);
527	}
528}
529
530static int
531sticioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
532{
533	struct stic_info *si;
534	int s;
535
536	si = v;
537
538	switch (cmd) {
539	case WSDISPLAYIO_GTYPE:
540		*(u_int *)data = si->si_disptype;
541		return (0);
542
543	case WSDISPLAYIO_GINFO:
544#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
545		wsd_fbip->height = 1024;
546		wsd_fbip->width = 1280;
547		wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
548		wsd_fbip->cmsize = CMAP_SIZE;
549#undef fbt
550		return (0);
551
552	case WSDISPLAYIO_GETCMAP:
553		return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
554
555	case WSDISPLAYIO_PUTCMAP:
556		return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
557
558	case WSDISPLAYIO_SVIDEO:
559#if 0 /* XXX later */
560		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
561		if ((si->si_blanked == 0) ^ turnoff)
562			si->si_blanked = turnoff;
563#endif
564		return (0);
565
566	case WSDISPLAYIO_GVIDEO:
567#if 0 /* XXX later */
568		*(u_int *)data = si->si_blanked ?
569		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
570#endif
571		return (0);
572
573	case WSDISPLAYIO_GCURPOS:
574		*(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
575		return (0);
576
577	case WSDISPLAYIO_SCURPOS:
578		stic_set_curpos(si, (struct wsdisplay_curpos *)data);
579		return (0);
580
581	case WSDISPLAYIO_GCURMAX:
582		((struct wsdisplay_curpos *)data)->x =
583		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
584		return (0);
585
586	case WSDISPLAYIO_GCURSOR:
587		return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
588
589	case WSDISPLAYIO_SCURSOR:
590		return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
591
592	case WSDISPLAYIO_SMODE:
593		si->si_dispmode = *(int *)data;
594		if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) {
595			(*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, l);
596			stic_setup_vdac(si);
597			s = spltty();
598			stic_flush(si);
599			splx(s);
600			stic_clear_screen(si);
601			stic_do_switch(si->si_curscreen);
602		}
603		return (0);
604
605	case STICIO_RESET:
606		stic_reset(si);
607		return (0);
608	}
609
610	if (si->si_ioctl != NULL)
611		return ((*si->si_ioctl)(si, cmd, data, flag, l));
612
613	return (EPASSTHROUGH);
614}
615
616static void
617stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
618{
619	int size;
620
621	size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
622	ss->ss_backing = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
623}
624
625static int
626stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
627		  int *curxp, int *curyp, long *attrp)
628{
629	struct stic_info *si;
630	struct stic_screen *ss;
631
632	si = (struct stic_info *)v;
633
634	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
635		ss = &stic_consscr;
636	else {
637		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO);
638	}
639	stic_setup_backing(si, ss);
640
641	ss->ss_si = si;
642	ss->ss_flags = SS_ALLOCED | SS_CURENB;
643
644	*cookiep = ss;
645	*curxp = 0;
646	*curyp = 0;
647
648	stic_allocattr(ss, 0, 0, 0, attrp);
649	return (0);
650}
651
652static void
653stic_free_screen(void *v, void *cookie)
654{
655	struct stic_screen *ss;
656
657	ss = cookie;
658
659#ifdef DIAGNOSTIC
660	if (ss == &stic_consscr)
661		panic("stic_free_screen: console");
662	if (ss == ((struct stic_info *)v)->si_curscreen)
663		panic("stic_free_screen: freeing current screen");
664#endif
665
666	free(ss->ss_backing, M_DEVBUF);
667	free(ss, M_DEVBUF);
668}
669
670static int
671stic_show_screen(void *v, void *cookie, int waitok,
672		 void (*cb)(void *, int, int), void *cbarg)
673{
674	struct stic_info *si;
675
676	si = (struct stic_info *)v;
677	if (si->si_switchcbarg != NULL)
678		return (EAGAIN);
679	si->si_switchcb = cb;
680	si->si_switchcbarg = cbarg;
681
682	if (cb != NULL) {
683		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
684		    cookie);
685		return (EAGAIN);
686	}
687
688	stic_do_switch(cookie);
689	return (0);
690}
691
692static void
693stic_do_switch(void *cookie)
694{
695	struct stic_screen *ss;
696	struct stic_info *si;
697	u_int r, c, nr, nc;
698	uint16_t *p, *sp;
699
700	ss = cookie;
701	si = ss->ss_si;
702
703#ifdef DIAGNOSTIC
704	if (ss->ss_backing == NULL)
705		panic("stic_do_switch: screen not backed");
706#endif
707
708	/* Swap in the new screen, and temporarily disable its backing. */
709	if (si->si_curscreen != NULL)
710		si->si_curscreen->ss_flags ^= SS_ACTIVE;
711	si->si_curscreen = ss;
712	ss->ss_flags |= SS_ACTIVE;
713	sp = ss->ss_backing;
714	ss->ss_backing = NULL;
715
716	/*
717	 * We assume that most of the screen is blank and blast it with
718	 * eraserows(), because eraserows() is cheap.
719	 */
720	nr = si->si_consh;
721	stic_eraserows(ss, 0, nr, 0);
722
723	nc = si->si_consw;
724	p = sp;
725	for (r = 0; r < nr; r++)
726		for (c = 0; c < nc; c += 2, p += 2) {
727			if ((p[0] & 0xfff0) != 0)
728				stic_putchar(ss, r, c, p[0] >> 8,
729				    p[0] & 0x00ff);
730			if ((p[1] & 0xfff0) != 0)
731				stic_putchar(ss, r, c + 1, p[1] >> 8,
732				    p[1] & 0x00ff);
733		}
734
735	/*
736	 * Re-enable the screen's backing, and move the cursor to the
737	 * correct spot.
738	 */
739	ss->ss_backing = sp;
740	si->si_cursor.cc_pos.x = ss->ss_curx;
741	si->si_cursor.cc_pos.y = ss->ss_cury;
742	stic_set_hwcurpos(si);
743	si->si_flags |= SI_CURENB_CHANGED;
744
745	/*
746	 * XXX Since we don't yet receive vblank interrupts from the
747	 * PXG, we must flush immediately.
748	 */
749	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
750		stic_flush(si);
751
752	/* Tell wscons that we're done. */
753	if (si->si_switchcbarg != NULL) {
754		cookie = si->si_switchcbarg;
755		si->si_switchcbarg = NULL;
756		(*si->si_switchcb)(cookie, 0, 0);
757	}
758}
759
760static int
761stic_allocattr(void *cookie, int fg, int bg, int flags, long *attr)
762{
763	long tmp;
764
765	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
766		return (EINVAL);
767
768	if ((flags & WSATTR_WSCOLORS) == 0) {
769		fg = 7;
770		bg = 0;
771	}
772
773	if ((flags & WSATTR_HILIT) != 0)
774		fg += 8;
775
776	tmp = fg | (bg << 4);
777	*attr = tmp | (tmp << 16);
778	return (0);
779}
780
781static void
782stic_erasecols(void *cookie, int row, int col, int num, long attr)
783{
784	struct stic_info *si;
785	struct stic_screen *ss;
786	uint32_t *pb;
787	u_int i, linewidth;
788	uint16_t *p;
789
790	ss = cookie;
791	si = ss->ss_si;
792
793	if (ss->ss_backing != NULL) {
794		p = ss->ss_backing + row * si->si_consw + col;
795		for (i = num; i != 0; i--)
796			*p++ = (uint16_t)attr;
797	}
798	if ((ss->ss_flags & SS_ACTIVE) == 0)
799		return;
800
801	col = (col * si->si_fontw) << 19;
802	num = (num * si->si_fontw) << 19;
803	row = row * si->si_fonth;
804	attr = (attr & 0xf0) >> 4;
805	linewidth = (si->si_fonth << 2) - 1;
806	row = (row << 3) + linewidth;
807
808	pb = (*si->si_pbuf_get)(si);
809
810	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
811	pb[1] = 0x01ffffff;
812	pb[2] = 0;
813	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
814	pb[4] = linewidth;
815	pb[5] = DUPBYTE0(attr);
816	pb[6] = col | row;
817	pb[7] = (col + num) | row;
818
819	(*si->si_pbuf_post)(si, pb);
820}
821
822static void
823stic_eraserows(void *cookie, int row, int num, long attr)
824{
825	struct stic_info *si;
826	struct stic_screen *ss;
827	u_int linewidth, i;
828	uint32_t *pb;
829
830	ss = cookie;
831	si = ss->ss_si;
832
833	if (ss->ss_backing != NULL) {
834		pb = (uint32_t *)(ss->ss_backing + row * si->si_consw);
835		for (i = si->si_consw * num; i > 0; i -= 2)
836			*pb++ = (uint32_t)attr;
837	}
838	if ((ss->ss_flags & SS_ACTIVE) == 0)
839		return;
840
841	row *= si->si_fonth;
842	num *= si->si_fonth;
843	attr = (attr & 0xf0) >> 4;
844	linewidth = (num << 2) - 1;
845	row = (row << 3) + linewidth;
846
847	pb = (*si->si_pbuf_get)(si);
848
849	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
850	pb[1] = 0x01ffffff;
851	pb[2] = 0;
852	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
853	pb[4] = linewidth;
854	pb[5] = DUPBYTE0(attr);
855	pb[6] = row;
856	pb[7] = (1280 << 19) | row;
857
858	(*si->si_pbuf_post)(si, pb);
859}
860
861static void
862stic_copyrows(void *cookie, int src, int dst, int height)
863{
864	struct stic_info *si;
865	struct stic_screen *ss;
866	uint32_t *pb, *pbs;
867	u_int num, inc, adj;
868
869	ss = cookie;
870	si = ss->ss_si;
871
872	if (ss->ss_backing != NULL)
873		bcopy(ss->ss_backing + src * si->si_consw,
874		    ss->ss_backing + dst * si->si_consw,
875		    si->si_consw * sizeof(*ss->ss_backing) * height);
876	if ((ss->ss_flags & SS_ACTIVE) == 0)
877		return;
878
879	/*
880	 * We need to do this in reverse if the destination row is below
881	 * the source.
882	 */
883	if (dst > src) {
884		src += height;
885		dst += height;
886		inc = -8;
887		adj = -1;
888	} else {
889		inc = 8;
890		adj = 0;
891	}
892
893	src = (src * si->si_fonth + adj) << 3;
894	dst = (dst * si->si_fonth + adj) << 3;
895	height *= si->si_fonth;
896
897	while (height > 0) {
898		num = (height < 255 ? height : 255);
899		height -= num;
900
901		pbs = (*si->si_pbuf_get)(si);
902		pb = pbs;
903
904		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
905		pb[1] = (num << 24) | 0xffffff;
906		pb[2] = 0x0;
907		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
908		    STAMP_COPYSPAN_ALIGNED;
909		pb[4] = 1; /* linewidth */
910
911		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
912			pb[5] = 1280 << 3;
913			pb[6] = src;
914			pb[7] = dst;
915		}
916
917	    	(*si->si_pbuf_post)(si, pbs);
918	}
919}
920
921static void
922stic_copycols(void *cookie, int row, int src, int dst, int num)
923{
924	struct stic_info *si;
925	struct stic_screen *ss;
926	u_int height, updword;
927	uint32_t *pb, *pbs;
928
929	ss = cookie;
930	si = ss->ss_si;
931
932	if (ss->ss_backing != NULL)
933		bcopy(ss->ss_backing + row * si->si_consw + src,
934		    ss->ss_backing + row * si->si_consw + dst,
935		    num * sizeof(*ss->ss_backing));
936	if ((ss->ss_flags & SS_ACTIVE) == 0)
937		return;
938
939	/*
940	 * The stamp reads and writes left -> right only, so we need to
941	 * buffer the span if the source and destination regions overlap
942	 * and the source is left of the destination.
943	 */
944	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
945
946	if (src < dst && src + num > dst)
947		updword |= STAMP_HALF_BUFF;
948
949	row = (row * si->si_fonth) << 3;
950	num = (num * si->si_fontw) << 3;
951	src = row | ((src * si->si_fontw) << 19);
952	dst = row | ((dst * si->si_fontw) << 19);
953	height = si->si_fonth;
954
955	pbs = (*si->si_pbuf_get)(si);
956	pb = pbs;
957
958	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
959	pb[1] = (height << 24) | 0xffffff;
960	pb[2] = 0x0;
961	pb[3] = updword;
962	pb[4] = 1; /* linewidth */
963
964	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
965		pb[5] = num;
966		pb[6] = src;
967		pb[7] = dst;
968	}
969
970	(*si->si_pbuf_post)(si, pbs);
971}
972
973static void
974stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
975{
976	struct wsdisplay_font *font;
977	struct stic_screen *ss;
978	struct stic_info *si;
979	u_int i, bgcolor, fgcolor;
980	u_int *pb, v1, v2, xya;
981	u_short *fr;
982
983	ss = cookie;
984	si = ss->ss_si;
985
986	/* It's cheaper to use erasecols() to blit blanks. */
987	if (uc == 0) {
988		stic_erasecols(cookie, r, c, 1, attr);
989		return;
990	}
991
992	if (ss->ss_backing != NULL)
993		ss->ss_backing[r * si->si_consw + c] =
994		    (u_short)((attr & 0xff) | (uc << 8));
995	if ((ss->ss_flags & SS_ACTIVE) == 0)
996		return;
997
998	font = si->si_font;
999	pb = (*si->si_pbuf_get)(si);
1000
1001	/*
1002	 * Create a mask from the glyph.  Squeeze the foreground color
1003	 * through the mask, and then squeeze the background color through
1004	 * the inverted mask.  We may well read outside the glyph when
1005	 * creating the mask, but it's bounded by the hardware so it
1006	 * shouldn't matter a great deal...
1007	 */
1008	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
1009	    STAMP_LW_PERPRIMATIVE;
1010	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
1011	pb[2] = 0x0;
1012	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
1013
1014	r *= font->fontheight;
1015	c *= font->fontwidth;
1016	uc = (uc - font->firstchar) * font->stride * font->fontheight;
1017	fr = (u_short *)((char *)font->data + uc);
1018	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
1019	fgcolor = DUPBYTE0(attr & 0x0f);
1020
1021	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
1022	v1 = (c << 19) | ((r << 3) + i);
1023	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1024	xya = XYMASKADDR(si->si_stampw, si->si_stamphm, c, r, 0, 0);
1025
1026	pb[4] = PACK(fr, 0);
1027	pb[5] = PACK(fr, 2);
1028	pb[6] = PACK(fr, 4);
1029	pb[7] = PACK(fr, 6);
1030	pb[8] = PACK(fr, 8);
1031	pb[9] = PACK(fr, 10);
1032	pb[10] = PACK(fr, 12);
1033	pb[11] = PACK(fr, 14);
1034	pb[12] = xya;
1035	pb[13] = v1;
1036	pb[14] = v2;
1037	pb[15] = i;
1038	pb[16] = fgcolor;
1039
1040	pb[17] = ~pb[4];
1041	pb[18] = ~pb[5];
1042	pb[19] = ~pb[6];
1043	pb[20] = ~pb[7];
1044	pb[21] = ~pb[8];
1045	pb[22] = ~pb[9];
1046	pb[23] = ~pb[10];
1047	pb[24] = ~pb[11];
1048	pb[25] = xya;
1049	pb[26] = v1;
1050	pb[27] = v2;
1051	pb[28] = i;
1052	pb[29] = bgcolor;
1053
1054	/* Two more squeezes for the lower part of the character. */
1055	if (font->fontheight > 16) {
1056		i = ((font->fontheight - 16) << 2) - 1;
1057		r += 16;
1058		v1 = (c << 19) | ((r << 3) + i);
1059		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1060
1061		pb[30] = PACK(fr, 16);
1062		pb[31] = PACK(fr, 18);
1063		pb[32] = PACK(fr, 20);
1064		pb[33] = PACK(fr, 22);
1065		pb[34] = PACK(fr, 24);
1066		pb[35] = PACK(fr, 26);
1067		pb[36] = PACK(fr, 28);
1068		pb[37] = PACK(fr, 30);
1069		pb[38] = xya;
1070		pb[39] = v1;
1071		pb[40] = v2;
1072		pb[41] = i;
1073		pb[42] = fgcolor;
1074
1075		pb[43] = ~pb[30];
1076		pb[44] = ~pb[31];
1077		pb[45] = ~pb[32];
1078		pb[46] = ~pb[33];
1079		pb[47] = ~pb[34];
1080		pb[48] = ~pb[35];
1081		pb[49] = ~pb[36];
1082		pb[50] = ~pb[37];
1083		pb[51] = xya;
1084		pb[52] = v1;
1085		pb[53] = v2;
1086		pb[54] = i;
1087		pb[55] = bgcolor;
1088	}
1089
1090	(*si->si_pbuf_post)(si, pb);
1091}
1092
1093static int
1094stic_mapchar(void *cookie, int c, u_int *cp)
1095{
1096	struct stic_info *si;
1097
1098	si = ((struct stic_screen *)cookie)->ss_si;
1099
1100	if (c < si->si_font->firstchar || c == ' ') {
1101		*cp = 0;
1102		return (0);
1103	}
1104
1105	if (c - si->si_font->firstchar >= si->si_font->numchars) {
1106		*cp = 0;
1107		return (0);
1108	}
1109
1110	*cp = c;
1111	return (5);
1112}
1113
1114static void
1115stic_cursor(void *cookie, int on, int row, int col)
1116{
1117	struct stic_screen *ss;
1118	struct stic_info *si;
1119	int s;
1120
1121	ss = cookie;
1122	si = ss->ss_si;
1123
1124	ss->ss_curx = col * si->si_fontw;
1125	ss->ss_cury = row * si->si_fonth;
1126
1127	s = spltty();
1128
1129	if (on)
1130		ss->ss_flags |= SS_CURENB;
1131	else
1132		ss->ss_flags &= ~SS_CURENB;
1133
1134	if ((ss->ss_flags & SS_ACTIVE) != 0) {
1135		si->si_cursor.cc_pos.x = ss->ss_curx;
1136		si->si_cursor.cc_pos.y = ss->ss_cury;
1137		si->si_flags |= SI_CURENB_CHANGED;
1138		stic_set_hwcurpos(si);
1139
1140		/*
1141		 * XXX Since we don't yet receive vblank interrupts from the
1142		 * PXG, we must flush immediately.
1143		 */
1144		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1145			stic_flush(si);
1146	}
1147
1148	splx(s);
1149}
1150
1151void
1152stic_flush(struct stic_info *si)
1153{
1154	volatile uint32_t *vdac;
1155	int v;
1156
1157	if ((si->si_flags & SI_ALL_CHANGED) == 0)
1158		return;
1159
1160	vdac = si->si_vdac;
1161	v = si->si_flags;
1162	si->si_flags &= ~SI_ALL_CHANGED;
1163
1164	if ((v & SI_CURENB_CHANGED) != 0) {
1165		SELECT(vdac, BT459_IREG_CCR);
1166		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
1167			REG(vdac, bt_reg) = 0x00c0c0c0;
1168		else
1169			REG(vdac, bt_reg) = 0x00000000;
1170		tc_wmb();
1171	}
1172
1173	if ((v & SI_CURCMAP_CHANGED) != 0) {
1174		uint8_t *cp;
1175
1176		cp = si->si_cursor.cc_color;
1177
1178		SELECT(vdac, BT459_IREG_CCOLOR_2);
1179		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
1180		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
1181		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
1182		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
1183		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
1184		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
1185	}
1186
1187	if ((v & SI_CURSHAPE_CHANGED) != 0) {
1188		uint8_t *ip, *mp, img, msk;
1189		uint8_t u;
1190		int bcnt;
1191
1192		ip = (uint8_t *)si->si_cursor.cc_image;
1193		mp = (uint8_t *)si->si_cursor.cc_mask;
1194
1195		bcnt = 0;
1196		SELECT(vdac, BT459_IREG_CRAM_BASE);
1197		/* 64 pixel scan line is consisted with 16 byte cursor ram */
1198		while (bcnt < CURSOR_MAX_SIZE * 16) {
1199			img = *ip++;
1200			msk = *mp++;
1201			img &= msk;	/* cookie off image */
1202			u = (msk & 0x0f) << 4 | (img & 0x0f);
1203			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1204			tc_wmb();
1205			u = (msk & 0xf0) | (img & 0xf0) >> 4;
1206			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1207			tc_wmb();
1208			bcnt += 2;
1209		}
1210	}
1211
1212	if ((v & SI_CMAP_CHANGED) != 0) {
1213		struct stic_hwcmap256 *cm;
1214		int index;
1215
1216		cm = &si->si_cmap;
1217
1218		SELECT(vdac, 0);
1219		SELECT(vdac, 0);
1220		for (index = 0; index < CMAP_SIZE; index++) {
1221			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
1222			tc_wmb();
1223			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
1224			tc_wmb();
1225			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
1226			tc_wmb();
1227		}
1228	}
1229}
1230
1231static int
1232stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1233{
1234	u_int index = p->index, count = p->count;
1235	int error;
1236
1237	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
1238		return (EINVAL);
1239
1240	error = copyout(&si->si_cmap.r[index], p->red, count);
1241	if (error)
1242		return error;
1243	error = copyout(&si->si_cmap.g[index], p->green, count);
1244	if (error)
1245		return error;
1246	error = copyout(&si->si_cmap.b[index], p->blue, count);
1247	return error;
1248}
1249
1250static int
1251stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1252{
1253	struct stic_hwcmap256 cmap;
1254	u_int index, count;
1255	int s, error;
1256
1257	index = p->index;
1258	count = p->count;
1259
1260	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
1261		return (EINVAL);
1262
1263	error = copyin(p->red, &cmap.r[index], count);
1264	if (error)
1265		return error;
1266	error = copyin(p->green, &cmap.g[index], count);
1267	if (error)
1268		return error;
1269	error = copyin(p->blue, &cmap.b[index], count);
1270	if (error)
1271		return error;
1272
1273	s = spltty();
1274	memcpy(&si->si_cmap.r[index], &cmap.r[index], count);
1275	memcpy(&si->si_cmap.g[index], &cmap.g[index], count);
1276	memcpy(&si->si_cmap.b[index], &cmap.b[index], count);
1277	si->si_flags |= SI_CMAP_CHANGED;
1278	splx(s);
1279
1280	/*
1281	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1282	 * must flush immediately.
1283	 */
1284	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1285		stic_flush(si);
1286
1287	return (0);
1288}
1289
1290static int
1291stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1292{
1293#define	cc (&si->si_cursor)
1294	u_int v, index = 0, count = 0, icount = 0;
1295	struct stic_screen *ss;
1296	uint8_t r[2], g[2], b[2], image[512], mask[512];
1297	int s, error;
1298
1299	v = p->which;
1300	ss = si->si_curscreen;
1301	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1302		index = p->cmap.index;
1303		count = p->cmap.count;
1304		if (index >= 2 || count > 2 - index)
1305			return (EINVAL);
1306		error = copyin(p->cmap.red, &r[index], count);
1307		if (error)
1308			return error;
1309		error = copyin(p->cmap.green, &g[index], count);
1310		if (error)
1311			return error;
1312		error = copyin(p->cmap.blue, &b[index], count);
1313		if (error)
1314			return error;
1315	}
1316	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1317		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
1318			return (EINVAL);
1319		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
1320		error = copyin(p->image, image, icount);
1321		if (error)
1322			return error;
1323		error = copyin(p->mask, mask, icount);
1324		if (error)
1325			return error;
1326	}
1327	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
1328		if (v & WSDISPLAY_CURSOR_DOCUR)
1329			cc->cc_hot = p->hot;
1330		if (v & WSDISPLAY_CURSOR_DOPOS)
1331			stic_set_curpos(si, &p->pos);
1332	}
1333
1334	s = spltty();
1335	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
1336		if (p->enable)
1337			ss->ss_flags |= SS_CURENB;
1338		else
1339			ss->ss_flags &= ~SS_CURENB;
1340		si->si_flags |= SI_CURENB_CHANGED;
1341	}
1342	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1343		memcpy(&cc->cc_color[index], &r[index], count);
1344		memcpy(&cc->cc_color[index + 2], &g[index], count);
1345		memcpy(&cc->cc_color[index + 4], &b[index], count);
1346		si->si_flags |= SI_CURCMAP_CHANGED;
1347	}
1348	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1349		memset(cc->cc_image, 0, sizeof cc->cc_image);
1350		memcpy(cc->cc_image, image, icount);
1351		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
1352		memcpy(cc->cc_mask, mask, icount);
1353		si->si_flags |= SI_CURSHAPE_CHANGED;
1354	}
1355	splx(s);
1356
1357	/*
1358	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1359	 * must flush immediately.
1360	 */
1361	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1362		stic_flush(si);
1363
1364	return (0);
1365#undef cc
1366}
1367
1368static int
1369stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1370{
1371
1372	/* XXX */
1373	return (EPASSTHROUGH);
1374}
1375
1376static void
1377stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
1378{
1379	int x, y;
1380
1381	x = curpos->x;
1382	y = curpos->y;
1383
1384	if (y < 0)
1385		y = 0;
1386	else if (y > 1023)
1387		y = 1023;
1388	if (x < 0)
1389		x = 0;
1390	else if (x > 1279)
1391		x = 1279;
1392
1393	si->si_cursor.cc_pos.x = x;
1394	si->si_cursor.cc_pos.y = y;
1395	stic_set_hwcurpos(si);
1396}
1397
1398static void
1399stic_set_hwcurpos(struct stic_info *si)
1400{
1401	volatile uint32_t *vdac;
1402	int x, y, s;
1403
1404	vdac = si->si_vdac;
1405
1406	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
1407	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
1408	x += STIC_MAGIC_X;
1409	y += STIC_MAGIC_Y;
1410
1411	s = spltty();
1412	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
1413	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
1414	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
1415	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
1416	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
1417	splx(s);
1418}
1419
1420/*
1421 * STIC control interface.  We have a separate device for mapping the board,
1422 * because access to the DMA engine means that it's possible to circumvent
1423 * the securelevel mechanism.
1424 */
1425static int
1426sticopen(dev_t dev, int flag, int mode, struct lwp *l)
1427{
1428	struct stic_info *si;
1429	int s, error;
1430
1431	error = kauth_authorize_device_passthru(l->l_cred, dev,
1432	    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, NULL);
1433	if (error)
1434		return (error);
1435	if (minor(dev) >= STIC_MAXDV)
1436		return (ENXIO);
1437	if ((si = stic_info[minor(dev)]) == NULL)
1438		return (ENXIO);
1439
1440	s = spltty();
1441	if ((si->si_flags & SI_DVOPEN) != 0) {
1442		splx(s);
1443		return (EBUSY);
1444	}
1445	si->si_flags |= SI_DVOPEN;
1446	splx(s);
1447
1448	return (0);
1449}
1450
1451static int
1452sticclose(dev_t dev, int flag, int mode, struct lwp *l)
1453{
1454	struct stic_info *si;
1455	int s;
1456
1457	si = stic_info[minor(dev)];
1458	s = spltty();
1459	si->si_flags &= ~SI_DVOPEN;
1460	splx(s);
1461
1462	return (0);
1463}
1464
1465static paddr_t
1466sticmmap(dev_t dev, off_t offset, int prot)
1467{
1468	struct stic_info *si;
1469	struct stic_xmap *sxm;
1470	paddr_t pa;
1471
1472	si = stic_info[minor(dev)];
1473	sxm = NULL;
1474
1475	if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
1476		return (-1L);
1477
1478	if (offset < 0)
1479		return ((paddr_t)-1L);
1480
1481	if (offset < sizeof(sxm->sxm_stic)) {
1482		pa = STIC_KSEG_TO_PHYS(si->si_stic);
1483		return (machine_btop(pa + offset));
1484	}
1485	offset -= sizeof(sxm->sxm_stic);
1486
1487	if (offset < sizeof(sxm->sxm_poll)) {
1488		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
1489		return (machine_btop(pa + offset));
1490	}
1491	offset -= sizeof(sxm->sxm_poll);
1492
1493	if (offset < si->si_buf_size)
1494		return (machine_btop(si->si_buf_phys + offset));
1495
1496	return ((paddr_t)-1L);
1497}
1498