xref: /netbsd-src/sys/dev/tc/xcfb.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /* $NetBSD: xcfb.c,v 1.25 2001/11/13 06:26:10 lukem 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.25 2001/11/13 06:26:10 lukem 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 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
295 		cookie = wsfont_find(NULL, 0, 0, 0);
296 	if (cookie <= 0) {
297 		printf("xcfb: font table is empty\n");
298 		return;
299 	}
300 
301 	if (wsfont_lock(cookie, &ri->ri_font,
302 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
303 		printf("xcfb: couldn't lock font\n");
304 		return;
305 	}
306 	ri->ri_wsfcookie = cookie;
307 
308 	rasops_init(ri, 34, 80);
309 
310 	/* XXX shouldn't be global */
311 	xcfb_stdscreen.nrows = ri->ri_rows;
312 	xcfb_stdscreen.ncols = ri->ri_cols;
313 	xcfb_stdscreen.textops = &ri->ri_ops;
314 	xcfb_stdscreen.capabilities = ri->ri_caps;
315 }
316 
317 int
318 xcfb_cnattach()
319 {
320 	struct rasops_info *ri;
321 	long defattr;
322 
323 	ri = &xcfb_console_ri;
324 	ri->ri_hw = (void *)ioasic_base;
325 	xcfb_common_init(ri);
326 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
327 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
328 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
329 	return (0);
330 }
331 
332 static void
333 xcfbhwinit(base)
334 	caddr_t base;
335 {
336 	u_int32_t *csr, i;
337 	const u_int8_t *p;
338 
339 	csr = (u_int32_t *)(base + IOASIC_CSR);
340 	i = *csr;
341 	i &= ~XINE_CSR_VDAC_ENABLE;
342 	*csr = i;
343 	DELAY(50);
344 	i |= XINE_CSR_VDAC_ENABLE;
345 	*csr = i;
346 	DELAY(50);
347 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
348 	ims332_write_reg(IMS332_REG_CSR_A,
349 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
350 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
351 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
352 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
353 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
354 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
355 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
356 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
357 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
358 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
359 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
360 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
361 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
362 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
363 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
364 	ims332_write_reg(IMS332_REG_CSR_A,
365 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
366 
367 	/* build sane colormap */
368 	p = rasops_cmap;
369 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
370 		u_int32_t bgr;
371 
372 		bgr = p[2] << 16 | p[1] << 8 | p[0];
373 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
374 	}
375 
376 	/* clear out cursor image */
377 	for (i = 0; i < 512; i++)
378 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
379 
380 	/*
381 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
382 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
383 	 * image color.  LUT_0 will be never used.
384 	 */
385 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
386 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
387 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
388 }
389 
390 static int
391 xcfbioctl(v, cmd, data, flag, p)
392 	void *v;
393 	u_long cmd;
394 	caddr_t data;
395 	int flag;
396 	struct proc *p;
397 {
398 	struct xcfb_softc *sc = v;
399 	struct rasops_info *ri = sc->sc_ri;
400 	int turnoff, error;
401 
402 	switch (cmd) {
403 	case WSDISPLAYIO_GTYPE:
404 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
405 		return (0);
406 
407 	case WSDISPLAYIO_GINFO:
408 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
409 		wsd_fbip->height = ri->ri_height;
410 		wsd_fbip->width = ri->ri_width;
411 		wsd_fbip->depth = ri->ri_depth;
412 		wsd_fbip->cmsize = CMAP_SIZE;
413 #undef fbt
414 		return (0);
415 
416 	case WSDISPLAYIO_GETCMAP:
417 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
418 
419 	case WSDISPLAYIO_PUTCMAP:
420 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
421 		if (error == 0)
422 			ims332_loadcmap(&sc->sc_cmap);
423 		return (error);
424 
425 	case WSDISPLAYIO_SVIDEO:
426 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
427 		if ((sc->sc_blanked == 0) ^ turnoff) {
428 			sc->sc_blanked = turnoff;
429 			xcfb_screenblank(sc);
430 		}
431 		return (0);
432 
433 	case WSDISPLAYIO_GVIDEO:
434 		*(u_int *)data = sc->sc_blanked ?
435 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
436 		return (0);
437 
438 	case WSDISPLAYIO_GCURPOS:
439 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
440 		return (0);
441 
442 	case WSDISPLAYIO_SCURPOS:
443 		set_curpos(sc, (struct wsdisplay_curpos *)data);
444 		ims332_set_curpos(sc);
445 		return (0);
446 
447 	case WSDISPLAYIO_GCURMAX:
448 		((struct wsdisplay_curpos *)data)->x =
449 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
450 		return (0);
451 
452 	case WSDISPLAYIO_GCURSOR:
453 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
454 
455 	case WSDISPLAYIO_SCURSOR:
456 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
457 	}
458 	return (ENOTTY);
459 }
460 
461 static paddr_t
462 xcfbmmap(v, offset, prot)
463 	void *v;
464 	off_t offset;
465 	int prot;
466 {
467 
468 	if (offset >= XCFB_FB_SIZE || offset < 0)
469 		return (-1);
470 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
471 }
472 
473 static int
474 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
475 	void *v;
476 	const struct wsscreen_descr *type;
477 	void **cookiep;
478 	int *curxp, *curyp;
479 	long *attrp;
480 {
481 	struct xcfb_softc *sc = v;
482 	struct rasops_info *ri = sc->sc_ri;
483 	long defattr;
484 
485 	if (sc->nscreens > 0)
486 		return (ENOMEM);
487 
488 	*cookiep = ri; 		/* one and only for now */
489 	*curxp = 0;
490 	*curyp = 0;
491 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
492 	*attrp = defattr;
493 	sc->nscreens++;
494 	return (0);
495 }
496 
497 static void
498 xcfb_free_screen(v, cookie)
499 	void *v;
500 	void *cookie;
501 {
502 	struct xcfb_softc *sc = v;
503 
504 	if (sc->sc_ri == &xcfb_console_ri)
505 		panic("xcfb_free_screen: console");
506 
507 	sc->nscreens--;
508 }
509 
510 static int
511 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
512 	void *v;
513 	void *cookie;
514 	int waitok;
515 	void (*cb) __P((void *, int, int));
516 	void *cbarg;
517 {
518 
519 	return (0);
520 }
521 
522 static int
523 xcfbintr(v)
524 	void *v;
525 {
526 	struct xcfb_softc *sc = v;
527 	u_int32_t *intr, i;
528 
529 	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
530 	i = *intr;
531 	i &= ~XINE_INTR_VINT;
532 	*intr = i;
533 	return (1);
534 }
535 
536 static void
537 xcfb_screenblank(sc)
538 	struct xcfb_softc *sc;
539 {
540 	if (sc->sc_blanked)
541 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
542 	else
543 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
544 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
545 }
546 
547 static int
548 get_cmap(sc, p)
549 	struct xcfb_softc *sc;
550 	struct wsdisplay_cmap *p;
551 {
552 	u_int index = p->index, count = p->count;
553 
554 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
555 		return (EINVAL);
556 
557 	if (!uvm_useracc(p->red, count, B_WRITE) ||
558 	    !uvm_useracc(p->green, count, B_WRITE) ||
559 	    !uvm_useracc(p->blue, count, B_WRITE))
560 		return (EFAULT);
561 
562 	copyout(&sc->sc_cmap.r[index], p->red, count);
563 	copyout(&sc->sc_cmap.g[index], p->green, count);
564 	copyout(&sc->sc_cmap.b[index], p->blue, count);
565 
566 	return (0);
567 }
568 
569 static int
570 set_cmap(sc, p)
571 	struct xcfb_softc *sc;
572 	struct wsdisplay_cmap *p;
573 {
574 	u_int index = p->index, count = p->count;
575 
576 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
577 		return (EINVAL);
578 
579 	if (!uvm_useracc(p->red, count, B_READ) ||
580 	    !uvm_useracc(p->green, count, B_READ) ||
581 	    !uvm_useracc(p->blue, count, B_READ))
582 		return (EFAULT);
583 
584 	copyin(p->red, &sc->sc_cmap.r[index], count);
585 	copyin(p->green, &sc->sc_cmap.g[index], count);
586 	copyin(p->blue, &sc->sc_cmap.b[index], count);
587 
588 	return (0);
589 }
590 
591 static int
592 set_cursor(sc, p)
593 	struct xcfb_softc *sc;
594 	struct wsdisplay_cursor *p;
595 {
596 #define	cc (&sc->sc_cursor)
597 	u_int v, index, count;
598 
599 	v = p->which;
600 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
601 		index = p->cmap.index;
602 		count = p->cmap.count;
603 
604 		if (index >= 2 || index + count > 2)
605 			return (EINVAL);
606 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
607 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
608 		    !uvm_useracc(p->cmap.blue, count, B_READ))
609 			return (EFAULT);
610 
611 		copyin(p->cmap.red, &cc->cc_color[index], count);
612 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
613 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
614 		ims332_load_curcmap(sc);
615 	}
616 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
617 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
618 			return (EINVAL);
619 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
620 		if (!uvm_useracc(p->image, count, B_READ) ||
621 		    !uvm_useracc(p->mask, count, B_READ))
622 			return (EFAULT);
623 		cc->cc_size = p->size;
624 		memset(cc->cc_image, 0, sizeof cc->cc_image);
625 		copyin(p->image, cc->cc_image, count);
626 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
627 		ims332_load_curshape(sc);
628 	}
629 	if (v & WSDISPLAY_CURSOR_DOCUR) {
630 		cc->cc_hot = p->hot;
631 		if (p->enable)
632 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
633 		else
634 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
635 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
636 	}
637 	if (v & WSDISPLAY_CURSOR_DOPOS) {
638 		set_curpos(sc, &p->pos);
639 		ims332_set_curpos(sc);
640 	}
641 
642 	return (0);
643 #undef cc
644 }
645 
646 static int
647 get_cursor(sc, p)
648 	struct xcfb_softc *sc;
649 	struct wsdisplay_cursor *p;
650 {
651 	return (ENOTTY); /* XXX */
652 }
653 
654 static void
655 set_curpos(sc, curpos)
656 	struct xcfb_softc *sc;
657 	struct wsdisplay_curpos *curpos;
658 {
659 	struct rasops_info *ri = sc->sc_ri;
660 	int x = curpos->x, y = curpos->y;
661 
662 	if (y < 0)
663 		y = 0;
664 	else if (y > ri->ri_height)
665 		y = ri->ri_height;
666 	if (x < 0)
667 		x = 0;
668 	else if (x > ri->ri_width)
669 		x = ri->ri_width;
670 	sc->sc_cursor.cc_pos.x = x;
671 	sc->sc_cursor.cc_pos.y = y;
672 }
673 
674 static void
675 ims332_loadcmap(cm)
676 	struct hwcmap256 *cm;
677 {
678 	int i;
679 	u_int32_t rgb;
680 
681 	for (i = 0; i < CMAP_SIZE; i++) {
682 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
683 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
684 	}
685 }
686 
687 static void
688 ims332_set_curpos(sc)
689 	struct xcfb_softc *sc;
690 {
691 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
692 	u_int32_t pos;
693 	int s;
694 
695 	s = spltty();
696 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
697 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
698 	splx(s);
699 }
700 
701 static void
702 ims332_load_curcmap(sc)
703 	struct xcfb_softc *sc;
704 {
705 	u_int8_t *cp = sc->sc_cursor.cc_color;
706 	u_int32_t rgb;
707 
708 	/* cursor background */
709 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
710 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
711 
712 	/* cursor foreground */
713 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
714 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
715 }
716 
717 static void
718 ims332_load_curshape(sc)
719 	struct xcfb_softc *sc;
720 {
721 	unsigned i, img, msk, bits;
722 	u_int8_t u, *ip, *mp;
723 
724 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
725 	mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
726 
727 	i = 0;
728 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
729 	while (i < sc->sc_cursor.cc_size.y * 8) {
730 		/* pad right half 32 pixel when smaller than 33 */
731 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
732 			bits = 0;
733 		else {
734 			img = *ip++;
735 			msk = *mp++;
736 			img &= msk;	/* cookie off image */
737 			u = (msk & 0x0f) << 4 | (img & 0x0f);
738 			bits = shuffle[u];
739 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
740 			bits = (shuffle[u] << 8) | bits;
741 		}
742 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
743 		i += 1;
744 	}
745 	/* pad unoccupied scan lines */
746 	while (i < CURSOR_MAX_SIZE * 8) {
747 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
748 		i += 1;
749 	}
750 }
751 
752 static void
753 ims332_write_reg(regno, val)
754 	int regno;
755 	u_int32_t val;
756 {
757 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
758 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
759 
760 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
761 	*(volatile u_int16_t *)low16 = val;
762 }
763 
764 #if 0
765 static u_int32_t
766 ims332_read_reg(regno)
767 	int regno;
768 {
769 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
770 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
771 	u_int v0, v1;
772 
773 	v1 = *(volatile u_int16_t *)high8;
774 	v0 = *(volatile u_int16_t *)low16;
775 	return (v1 & 0xff00) << 8 | v0;
776 }
777 #endif
778