xref: /netbsd-src/sys/dev/tc/xcfb.c (revision 5e4c038a45edbc7d63b7c2daa76e29f88b64a4e3)
1 /* $NetBSD: xcfb.c,v 1.27 2002/03/17 19:41:03 atatat Exp $ */
2 
3 /*
4  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tohru Nishimura
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.27 2002/03/17 19:41:03 atatat Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52 
53 #include <dev/tc/tcvar.h>
54 #include <dev/tc/ioasicreg.h>
55 #include <dev/ic/ims332reg.h>
56 #include <pmax/pmax/maxine.h>
57 
58 #include <uvm/uvm_extern.h>
59 
60 struct hwcmap256 {
61 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
62 	u_int8_t r[CMAP_SIZE];
63 	u_int8_t g[CMAP_SIZE];
64 	u_int8_t b[CMAP_SIZE];
65 };
66 
67 struct hwcursor64 {
68 	struct wsdisplay_curpos cc_pos;
69 	struct wsdisplay_curpos cc_hot;
70 	struct wsdisplay_curpos cc_size;
71 	struct wsdisplay_curpos cc_magic;	/* not used by PMAG-DV */
72 #define	CURSOR_MAX_SIZE	64
73 	u_int8_t cc_color[6];
74 	u_int64_t cc_image[64 + 64];
75 };
76 
77 #define	XCFB_FB_BASE	(XINE_PHYS_CFB_START + 0x2000000)
78 #define	XCFB_FB_SIZE	0x100000
79 
80 #define	IMS332_HIGH	(IOASIC_SLOT_5_START)
81 #define	IMS332_RLOW	(IOASIC_SLOT_7_START)
82 #define	IMS332_WLOW	(IOASIC_SLOT_7_START + 0x20000)
83 
84 struct xcfb_softc {
85 	struct device sc_dev;
86 	vaddr_t sc_vaddr;
87 	size_t sc_size;
88 	struct rasops_info *sc_ri;
89 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
90 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
91 	int sc_blanked;
92 	/* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
93 	int nscreens;
94 	/* cursor coordinate is located at upper-left corner */
95 	int sc_csr;			/* software copy of IMS332 CSR A */
96 };
97 
98 static int  xcfbmatch __P((struct device *, struct cfdata *, void *));
99 static void xcfbattach __P((struct device *, struct device *, void *));
100 
101 const struct cfattach xcfb_ca = {
102 	sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
103 };
104 
105 static tc_addr_t xcfb_consaddr;
106 static struct rasops_info xcfb_console_ri;
107 static void xcfb_common_init __P((struct rasops_info *));
108 static void xcfbhwinit __P((caddr_t));
109 int xcfb_cnattach __P((void));
110 
111 struct wsscreen_descr xcfb_stdscreen = {
112 	"std", 0, 0,
113 	0, /* textops */
114 	0, 0,
115 	WSSCREEN_REVERSE
116 };
117 
118 static const struct wsscreen_descr *_xcfb_scrlist[] = {
119 	&xcfb_stdscreen,
120 };
121 
122 static const struct wsscreen_list xcfb_screenlist = {
123 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
124 };
125 
126 static int	xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
127 static paddr_t	xcfbmmap __P((void *, off_t, int));
128 
129 static int	xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
130 				       void **, int *, int *, long *));
131 static void	xcfb_free_screen __P((void *, void *));
132 static int	xcfb_show_screen __P((void *, void *, int,
133 				      void (*) (void *, int, int), void *));
134 
135 static const struct wsdisplay_accessops xcfb_accessops = {
136 	xcfbioctl,
137 	xcfbmmap,
138 	xcfb_alloc_screen,
139 	xcfb_free_screen,
140 	xcfb_show_screen,
141 	0 /* load_font */
142 };
143 
144 static int  xcfbintr __P((void *));
145 static void xcfb_screenblank __P((struct xcfb_softc *));
146 static int  set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
147 static int  get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
148 static int  set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
149 static int  get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
150 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
151 static void ims332_loadcmap __P((struct hwcmap256 *));
152 static void ims332_set_curpos __P((struct xcfb_softc *));
153 static void ims332_load_curcmap __P((struct xcfb_softc *));
154 static void ims332_load_curshape __P((struct xcfb_softc *));
155 static void ims332_write_reg __P((int, u_int32_t));
156 #if 0
157 static u_int32_t ims332_read_reg __P((int));
158 #endif
159 
160 extern long ioasic_base;	/* XXX */
161 
162 /*
163  * Compose 2 bit/pixel cursor image.
164  *   M M M M I I I I		M I M I M I M I
165  *	[ before ]		   [ after ]
166  *   3 2 1 0 3 2 1 0		3 3 2 2 1 1 0 0
167  *   7 6 5 4 7 6 5 4		7 7 6 6 5 5 4 4
168  */
169 static const u_int8_t shuffle[256] = {
170 	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
171 	0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
172 	0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
173 	0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
174 	0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
175 	0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
176 	0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
177 	0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
178 	0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
179 	0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
180 	0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
181 	0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
182 	0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
183 	0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
184 	0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
185 	0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
186 	0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
187 	0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
188 	0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
189 	0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
190 	0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
191 	0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
192 	0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
193 	0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
194 	0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
195 	0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
196 	0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
197 	0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
198 	0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
199 	0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
200 	0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
201 	0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
202 };
203 
204 static int
205 xcfbmatch(parent, match, aux)
206 	struct device *parent;
207 	struct cfdata *match;
208 	void *aux;
209 {
210 	struct tc_attach_args *ta = aux;
211 
212 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
213 		return (0);
214 
215 	return (1);
216 }
217 
218 static void
219 xcfbattach(parent, self, aux)
220 	struct device *parent, *self;
221 	void *aux;
222 {
223 	struct xcfb_softc *sc = (struct xcfb_softc *)self;
224 	struct tc_attach_args *ta = aux;
225 	struct rasops_info *ri;
226 	struct wsemuldisplaydev_attach_args waa;
227 	struct hwcmap256 *cm;
228 	const u_int8_t *p;
229 	int console, index;
230 
231 	console = (ta->ta_addr == xcfb_consaddr);
232 	if (console) {
233 		sc->sc_ri = ri = &xcfb_console_ri;
234 		sc->nscreens = 1;
235 	}
236 	else {
237 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
238 			M_DEVBUF, M_NOWAIT);
239 		if (ri == NULL) {
240 			printf(": can't alloc memory\n");
241 			return;
242 		}
243 		memset(ri, 0, sizeof(struct rasops_info));
244 
245 		ri->ri_hw = (void *)ioasic_base;
246 		xcfb_common_init(ri);
247 		sc->sc_ri = ri;
248 	}
249 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
250 
251 	cm = &sc->sc_cmap;
252 	p = rasops_cmap;
253 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
254 		cm->r[index] = p[0];
255 		cm->g[index] = p[1];
256 		cm->b[index] = p[2];
257 	}
258 
259 	sc->sc_vaddr = ta->ta_addr;
260 	sc->sc_blanked = 0;
261 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
262 
263         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
264 
265 	waa.console = console;
266 	waa.scrdata = &xcfb_screenlist;
267 	waa.accessops = &xcfb_accessops;
268 	waa.accesscookie = sc;
269 
270 	config_found(self, &waa, wsemuldisplaydevprint);
271 }
272 
273 static void
274 xcfb_common_init(ri)
275 	struct rasops_info *ri;
276 {
277 	int cookie;
278 
279 	/* initialize colormap and cursor hardware */
280 	xcfbhwinit((caddr_t)ri->ri_hw);
281 
282 	ri->ri_flg = RI_CENTER;
283 	ri->ri_depth = 8;
284 	ri->ri_width = 1024;
285 	ri->ri_height = 768;
286 	ri->ri_stride = 1024;
287 	ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
288 
289 	/* clear the screen */
290 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
291 
292 	wsfont_init();
293 	/* prefer 12 pixel wide font */
294 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
295 	    WSDISPLAY_FONTORDER_L2R);
296 	if (cookie <= 0)
297 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
298 		    WSDISPLAY_FONTORDER_L2R);
299 	if (cookie <= 0) {
300 		printf("xcfb: font table is empty\n");
301 		return;
302 	}
303 
304 	if (wsfont_lock(cookie, &ri->ri_font)) {
305 		printf("xcfb: couldn't lock font\n");
306 		return;
307 	}
308 	ri->ri_wsfcookie = cookie;
309 
310 	rasops_init(ri, 34, 80);
311 
312 	/* XXX shouldn't be global */
313 	xcfb_stdscreen.nrows = ri->ri_rows;
314 	xcfb_stdscreen.ncols = ri->ri_cols;
315 	xcfb_stdscreen.textops = &ri->ri_ops;
316 	xcfb_stdscreen.capabilities = ri->ri_caps;
317 }
318 
319 int
320 xcfb_cnattach()
321 {
322 	struct rasops_info *ri;
323 	long defattr;
324 
325 	ri = &xcfb_console_ri;
326 	ri->ri_hw = (void *)ioasic_base;
327 	xcfb_common_init(ri);
328 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
329 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
330 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
331 	return (0);
332 }
333 
334 static void
335 xcfbhwinit(base)
336 	caddr_t base;
337 {
338 	u_int32_t *csr, i;
339 	const u_int8_t *p;
340 
341 	csr = (u_int32_t *)(base + IOASIC_CSR);
342 	i = *csr;
343 	i &= ~XINE_CSR_VDAC_ENABLE;
344 	*csr = i;
345 	DELAY(50);
346 	i |= XINE_CSR_VDAC_ENABLE;
347 	*csr = i;
348 	DELAY(50);
349 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
350 	ims332_write_reg(IMS332_REG_CSR_A,
351 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
352 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
353 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
354 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
355 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
356 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
357 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
358 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
359 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
360 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
361 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
362 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
363 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
364 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
365 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
366 	ims332_write_reg(IMS332_REG_CSR_A,
367 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
368 
369 	/* build sane colormap */
370 	p = rasops_cmap;
371 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
372 		u_int32_t bgr;
373 
374 		bgr = p[2] << 16 | p[1] << 8 | p[0];
375 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
376 	}
377 
378 	/* clear out cursor image */
379 	for (i = 0; i < 512; i++)
380 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
381 
382 	/*
383 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
384 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
385 	 * image color.  LUT_0 will be never used.
386 	 */
387 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
388 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
389 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
390 }
391 
392 static int
393 xcfbioctl(v, cmd, data, flag, p)
394 	void *v;
395 	u_long cmd;
396 	caddr_t data;
397 	int flag;
398 	struct proc *p;
399 {
400 	struct xcfb_softc *sc = v;
401 	struct rasops_info *ri = sc->sc_ri;
402 	int turnoff, error;
403 
404 	switch (cmd) {
405 	case WSDISPLAYIO_GTYPE:
406 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
407 		return (0);
408 
409 	case WSDISPLAYIO_GINFO:
410 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
411 		wsd_fbip->height = ri->ri_height;
412 		wsd_fbip->width = ri->ri_width;
413 		wsd_fbip->depth = ri->ri_depth;
414 		wsd_fbip->cmsize = CMAP_SIZE;
415 #undef fbt
416 		return (0);
417 
418 	case WSDISPLAYIO_GETCMAP:
419 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
420 
421 	case WSDISPLAYIO_PUTCMAP:
422 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
423 		if (error == 0)
424 			ims332_loadcmap(&sc->sc_cmap);
425 		return (error);
426 
427 	case WSDISPLAYIO_SVIDEO:
428 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
429 		if ((sc->sc_blanked == 0) ^ turnoff) {
430 			sc->sc_blanked = turnoff;
431 			xcfb_screenblank(sc);
432 		}
433 		return (0);
434 
435 	case WSDISPLAYIO_GVIDEO:
436 		*(u_int *)data = sc->sc_blanked ?
437 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
438 		return (0);
439 
440 	case WSDISPLAYIO_GCURPOS:
441 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
442 		return (0);
443 
444 	case WSDISPLAYIO_SCURPOS:
445 		set_curpos(sc, (struct wsdisplay_curpos *)data);
446 		ims332_set_curpos(sc);
447 		return (0);
448 
449 	case WSDISPLAYIO_GCURMAX:
450 		((struct wsdisplay_curpos *)data)->x =
451 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
452 		return (0);
453 
454 	case WSDISPLAYIO_GCURSOR:
455 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
456 
457 	case WSDISPLAYIO_SCURSOR:
458 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
459 	}
460 	return (EPASSTHROUGH);
461 }
462 
463 static paddr_t
464 xcfbmmap(v, offset, prot)
465 	void *v;
466 	off_t offset;
467 	int prot;
468 {
469 
470 	if (offset >= XCFB_FB_SIZE || offset < 0)
471 		return (-1);
472 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
473 }
474 
475 static int
476 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
477 	void *v;
478 	const struct wsscreen_descr *type;
479 	void **cookiep;
480 	int *curxp, *curyp;
481 	long *attrp;
482 {
483 	struct xcfb_softc *sc = v;
484 	struct rasops_info *ri = sc->sc_ri;
485 	long defattr;
486 
487 	if (sc->nscreens > 0)
488 		return (ENOMEM);
489 
490 	*cookiep = ri; 		/* one and only for now */
491 	*curxp = 0;
492 	*curyp = 0;
493 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
494 	*attrp = defattr;
495 	sc->nscreens++;
496 	return (0);
497 }
498 
499 static void
500 xcfb_free_screen(v, cookie)
501 	void *v;
502 	void *cookie;
503 {
504 	struct xcfb_softc *sc = v;
505 
506 	if (sc->sc_ri == &xcfb_console_ri)
507 		panic("xcfb_free_screen: console");
508 
509 	sc->nscreens--;
510 }
511 
512 static int
513 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
514 	void *v;
515 	void *cookie;
516 	int waitok;
517 	void (*cb) __P((void *, int, int));
518 	void *cbarg;
519 {
520 
521 	return (0);
522 }
523 
524 static int
525 xcfbintr(v)
526 	void *v;
527 {
528 	struct xcfb_softc *sc = v;
529 	u_int32_t *intr, i;
530 
531 	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
532 	i = *intr;
533 	i &= ~XINE_INTR_VINT;
534 	*intr = i;
535 	return (1);
536 }
537 
538 static void
539 xcfb_screenblank(sc)
540 	struct xcfb_softc *sc;
541 {
542 	if (sc->sc_blanked)
543 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
544 	else
545 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
546 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
547 }
548 
549 static int
550 get_cmap(sc, p)
551 	struct xcfb_softc *sc;
552 	struct wsdisplay_cmap *p;
553 {
554 	u_int index = p->index, count = p->count;
555 
556 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
557 		return (EINVAL);
558 
559 	if (!uvm_useracc(p->red, count, B_WRITE) ||
560 	    !uvm_useracc(p->green, count, B_WRITE) ||
561 	    !uvm_useracc(p->blue, count, B_WRITE))
562 		return (EFAULT);
563 
564 	copyout(&sc->sc_cmap.r[index], p->red, count);
565 	copyout(&sc->sc_cmap.g[index], p->green, count);
566 	copyout(&sc->sc_cmap.b[index], p->blue, count);
567 
568 	return (0);
569 }
570 
571 static int
572 set_cmap(sc, p)
573 	struct xcfb_softc *sc;
574 	struct wsdisplay_cmap *p;
575 {
576 	u_int index = p->index, count = p->count;
577 
578 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
579 		return (EINVAL);
580 
581 	if (!uvm_useracc(p->red, count, B_READ) ||
582 	    !uvm_useracc(p->green, count, B_READ) ||
583 	    !uvm_useracc(p->blue, count, B_READ))
584 		return (EFAULT);
585 
586 	copyin(p->red, &sc->sc_cmap.r[index], count);
587 	copyin(p->green, &sc->sc_cmap.g[index], count);
588 	copyin(p->blue, &sc->sc_cmap.b[index], count);
589 
590 	return (0);
591 }
592 
593 static int
594 set_cursor(sc, p)
595 	struct xcfb_softc *sc;
596 	struct wsdisplay_cursor *p;
597 {
598 #define	cc (&sc->sc_cursor)
599 	u_int v, index, count;
600 
601 	v = p->which;
602 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
603 		index = p->cmap.index;
604 		count = p->cmap.count;
605 
606 		if (index >= 2 || index + count > 2)
607 			return (EINVAL);
608 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
609 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
610 		    !uvm_useracc(p->cmap.blue, count, B_READ))
611 			return (EFAULT);
612 
613 		copyin(p->cmap.red, &cc->cc_color[index], count);
614 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
615 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
616 		ims332_load_curcmap(sc);
617 	}
618 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
619 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
620 			return (EINVAL);
621 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
622 		if (!uvm_useracc(p->image, count, B_READ) ||
623 		    !uvm_useracc(p->mask, count, B_READ))
624 			return (EFAULT);
625 		cc->cc_size = p->size;
626 		memset(cc->cc_image, 0, sizeof cc->cc_image);
627 		copyin(p->image, cc->cc_image, count);
628 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
629 		ims332_load_curshape(sc);
630 	}
631 	if (v & WSDISPLAY_CURSOR_DOCUR) {
632 		cc->cc_hot = p->hot;
633 		if (p->enable)
634 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
635 		else
636 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
637 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
638 	}
639 	if (v & WSDISPLAY_CURSOR_DOPOS) {
640 		set_curpos(sc, &p->pos);
641 		ims332_set_curpos(sc);
642 	}
643 
644 	return (0);
645 #undef cc
646 }
647 
648 static int
649 get_cursor(sc, p)
650 	struct xcfb_softc *sc;
651 	struct wsdisplay_cursor *p;
652 {
653 	return (EPASSTHROUGH); /* XXX */
654 }
655 
656 static void
657 set_curpos(sc, curpos)
658 	struct xcfb_softc *sc;
659 	struct wsdisplay_curpos *curpos;
660 {
661 	struct rasops_info *ri = sc->sc_ri;
662 	int x = curpos->x, y = curpos->y;
663 
664 	if (y < 0)
665 		y = 0;
666 	else if (y > ri->ri_height)
667 		y = ri->ri_height;
668 	if (x < 0)
669 		x = 0;
670 	else if (x > ri->ri_width)
671 		x = ri->ri_width;
672 	sc->sc_cursor.cc_pos.x = x;
673 	sc->sc_cursor.cc_pos.y = y;
674 }
675 
676 static void
677 ims332_loadcmap(cm)
678 	struct hwcmap256 *cm;
679 {
680 	int i;
681 	u_int32_t rgb;
682 
683 	for (i = 0; i < CMAP_SIZE; i++) {
684 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
685 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
686 	}
687 }
688 
689 static void
690 ims332_set_curpos(sc)
691 	struct xcfb_softc *sc;
692 {
693 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
694 	u_int32_t pos;
695 	int s;
696 
697 	s = spltty();
698 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
699 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
700 	splx(s);
701 }
702 
703 static void
704 ims332_load_curcmap(sc)
705 	struct xcfb_softc *sc;
706 {
707 	u_int8_t *cp = sc->sc_cursor.cc_color;
708 	u_int32_t rgb;
709 
710 	/* cursor background */
711 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
712 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
713 
714 	/* cursor foreground */
715 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
716 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
717 }
718 
719 static void
720 ims332_load_curshape(sc)
721 	struct xcfb_softc *sc;
722 {
723 	unsigned i, img, msk, bits;
724 	u_int8_t u, *ip, *mp;
725 
726 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
727 	mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
728 
729 	i = 0;
730 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
731 	while (i < sc->sc_cursor.cc_size.y * 8) {
732 		/* pad right half 32 pixel when smaller than 33 */
733 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
734 			bits = 0;
735 		else {
736 			img = *ip++;
737 			msk = *mp++;
738 			img &= msk;	/* cookie off image */
739 			u = (msk & 0x0f) << 4 | (img & 0x0f);
740 			bits = shuffle[u];
741 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
742 			bits = (shuffle[u] << 8) | bits;
743 		}
744 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
745 		i += 1;
746 	}
747 	/* pad unoccupied scan lines */
748 	while (i < CURSOR_MAX_SIZE * 8) {
749 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
750 		i += 1;
751 	}
752 }
753 
754 static void
755 ims332_write_reg(regno, val)
756 	int regno;
757 	u_int32_t val;
758 {
759 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
760 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
761 
762 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
763 	*(volatile u_int16_t *)low16 = val;
764 }
765 
766 #if 0
767 static u_int32_t
768 ims332_read_reg(regno)
769 	int regno;
770 {
771 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
772 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
773 	u_int v0, v1;
774 
775 	v1 = *(volatile u_int16_t *)high8;
776 	v0 = *(volatile u_int16_t *)low16;
777 	return (v1 & 0xff00) << 8 | v0;
778 }
779 #endif
780