Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.33
      1 /* $NetBSD: xcfb.c,v 1.33 2003/11/13 03:09:29 chs 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.33 2003/11/13 03:09:29 chs 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 __P((struct device *, struct cfdata *, void *));
    100 static void xcfbattach __P((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 __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.allocattr)(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.allocattr)(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 	int error;
    556 
    557 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    558 		return (EINVAL);
    559 
    560 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    561 	if (error)
    562 		return error;
    563 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    564 	if (error)
    565 		return error;
    566 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    567 	return error;
    568 }
    569 
    570 static int
    571 set_cmap(sc, p)
    572 	struct xcfb_softc *sc;
    573 	struct wsdisplay_cmap *p;
    574 {
    575 	struct hwcmap256 cmap;
    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 = copyin(p->red, &cmap.r[index], count);
    583 	if (error)
    584 		return error;
    585 	error = copyin(p->green, &cmap.g[index], count);
    586 	if (error)
    587 		return error;
    588 	error = copyin(p->blue, &cmap.b[index], count);
    589 	if (error)
    590 		return error;
    591 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    592 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    593 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    594 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    595 	return (0);
    596 }
    597 
    598 static int
    599 set_cursor(sc, p)
    600 	struct xcfb_softc *sc;
    601 	struct wsdisplay_cursor *p;
    602 {
    603 #define	cc (&sc->sc_cursor)
    604 	u_int v, index = 0, count = 0, icount = 0;
    605 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    606 	int error;
    607 
    608 	v = p->which;
    609 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    610 		index = p->cmap.index;
    611 		count = p->cmap.count;
    612 
    613 		if (index >= 2 || index + count > 2)
    614 			return (EINVAL);
    615 		error = copyin(p->cmap.red, &r[index], count);
    616 		if (error)
    617 			return error;
    618 		error = copyin(p->cmap.green, &g[index], count);
    619 		if (error)
    620 			return error;
    621 		error = copyin(p->cmap.blue, &b[index], count);
    622 		if (error)
    623 			return error;
    624 	}
    625 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    626 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    627 			return (EINVAL);
    628 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    629 		error = copyin(p->image, image, icount);
    630 		if (error)
    631 			return error;
    632 		error = copyin(p->mask, mask, icount);
    633 		if (error)
    634 			return error;
    635 	}
    636 
    637 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    638 		memcpy(&cc->cc_color[index], &r[index], count);
    639 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    640 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    641 		ims332_load_curcmap(sc);
    642 	}
    643 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    644 		cc->cc_size = p->size;
    645 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    646 		memcpy(cc->cc_image, image, icount);
    647 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    648 		memcpy(cc->cc_mask, mask, icount);
    649 		ims332_load_curshape(sc);
    650 	}
    651 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    652 		cc->cc_hot = p->hot;
    653 		if (p->enable)
    654 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    655 		else
    656 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    657 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    658 	}
    659 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    660 		set_curpos(sc, &p->pos);
    661 		ims332_set_curpos(sc);
    662 	}
    663 
    664 	return (0);
    665 #undef cc
    666 }
    667 
    668 static int
    669 get_cursor(sc, p)
    670 	struct xcfb_softc *sc;
    671 	struct wsdisplay_cursor *p;
    672 {
    673 	return (EPASSTHROUGH); /* XXX */
    674 }
    675 
    676 static void
    677 set_curpos(sc, curpos)
    678 	struct xcfb_softc *sc;
    679 	struct wsdisplay_curpos *curpos;
    680 {
    681 	struct rasops_info *ri = sc->sc_ri;
    682 	int x = curpos->x, y = curpos->y;
    683 
    684 	if (y < 0)
    685 		y = 0;
    686 	else if (y > ri->ri_height)
    687 		y = ri->ri_height;
    688 	if (x < 0)
    689 		x = 0;
    690 	else if (x > ri->ri_width)
    691 		x = ri->ri_width;
    692 	sc->sc_cursor.cc_pos.x = x;
    693 	sc->sc_cursor.cc_pos.y = y;
    694 }
    695 
    696 static void
    697 ims332_loadcmap(cm)
    698 	struct hwcmap256 *cm;
    699 {
    700 	int i;
    701 	u_int32_t rgb;
    702 
    703 	for (i = 0; i < CMAP_SIZE; i++) {
    704 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    705 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    706 	}
    707 }
    708 
    709 static void
    710 ims332_set_curpos(sc)
    711 	struct xcfb_softc *sc;
    712 {
    713 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    714 	u_int32_t pos;
    715 	int s;
    716 
    717 	s = spltty();
    718 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    719 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    720 	splx(s);
    721 }
    722 
    723 static void
    724 ims332_load_curcmap(sc)
    725 	struct xcfb_softc *sc;
    726 {
    727 	u_int8_t *cp = sc->sc_cursor.cc_color;
    728 	u_int32_t rgb;
    729 
    730 	/* cursor background */
    731 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    732 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    733 
    734 	/* cursor foreground */
    735 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    736 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    737 }
    738 
    739 static void
    740 ims332_load_curshape(sc)
    741 	struct xcfb_softc *sc;
    742 {
    743 	u_int i, img, msk, bits;
    744 	u_int8_t u, *ip, *mp;
    745 
    746 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
    747 	mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    748 
    749 	i = 0;
    750 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
    751 	while (i < sc->sc_cursor.cc_size.y * 8) {
    752 		/* pad right half 32 pixel when smaller than 33 */
    753 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
    754 			bits = 0;
    755 		else {
    756 			img = *ip++;
    757 			msk = *mp++;
    758 			img &= msk;	/* cookie off image */
    759 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    760 			bits = shuffle[u];
    761 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    762 			bits = (shuffle[u] << 8) | bits;
    763 		}
    764 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
    765 		i += 1;
    766 	}
    767 	/* pad unoccupied scan lines */
    768 	while (i < CURSOR_MAX_SIZE * 8) {
    769 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    770 		i += 1;
    771 	}
    772 }
    773 
    774 static void
    775 ims332_write_reg(regno, val)
    776 	int regno;
    777 	u_int32_t val;
    778 {
    779 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    780 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
    781 
    782 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
    783 	*(volatile u_int16_t *)low16 = val;
    784 }
    785 
    786 #if 0
    787 static u_int32_t
    788 ims332_read_reg(regno)
    789 	int regno;
    790 {
    791 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    792 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
    793 	u_int v0, v1;
    794 
    795 	v1 = *(volatile u_int16_t *)high8;
    796 	v0 = *(volatile u_int16_t *)low16;
    797 	return (v1 & 0xff00) << 8 | v0;
    798 }
    799 #endif
    800