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