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