Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.35
      1 /* $NetBSD: xcfb.c,v 1.35 2003/12/17 03:59:33 ad 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.35 2003/12/17 03:59:33 ad 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 void xcfb_cmap_init __P((struct xcfb_softc *));
    147 static int  set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    148 static int  get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    149 static int  set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    150 static int  get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    151 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
    152 static void ims332_loadcmap __P((struct hwcmap256 *));
    153 static void ims332_set_curpos __P((struct xcfb_softc *));
    154 static void ims332_load_curcmap __P((struct xcfb_softc *));
    155 static void ims332_load_curshape __P((struct xcfb_softc *));
    156 static void ims332_write_reg __P((int, u_int32_t));
    157 #if 0
    158 static u_int32_t ims332_read_reg __P((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 	u_int32_t *csr, i;
    349 	const u_int8_t *p;
    350 
    351 	csr = (u_int32_t *)(base + IOASIC_CSR);
    352 	i = *csr;
    353 	i &= ~XINE_CSR_VDAC_ENABLE;
    354 	*csr = i;
    355 	DELAY(50);
    356 	i |= XINE_CSR_VDAC_ENABLE;
    357 	*csr = i;
    358 	DELAY(50);
    359 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
    360 	ims332_write_reg(IMS332_REG_CSR_A,
    361 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
    362 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
    363 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
    364 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
    365 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
    366 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
    367 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
    368 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
    369 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
    370 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
    371 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
    372 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
    373 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
    374 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
    375 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    376 	ims332_write_reg(IMS332_REG_CSR_A,
    377 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
    378 
    379 	/* build sane colormap */
    380 	p = rasops_cmap;
    381 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    382 		u_int32_t bgr;
    383 
    384 		bgr = p[2] << 16 | p[1] << 8 | p[0];
    385 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
    386 	}
    387 
    388 	/* clear out cursor image */
    389 	for (i = 0; i < 512; i++)
    390 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    391 
    392 	/*
    393 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    394 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
    395 	 * image color.  LUT_0 will be never used.
    396 	 */
    397 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
    398 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
    399 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
    400 }
    401 
    402 static int
    403 xcfbioctl(v, cmd, data, flag, p)
    404 	void *v;
    405 	u_long cmd;
    406 	caddr_t data;
    407 	int flag;
    408 	struct proc *p;
    409 {
    410 	struct xcfb_softc *sc = v;
    411 	struct rasops_info *ri = sc->sc_ri;
    412 	int turnoff, error;
    413 
    414 	switch (cmd) {
    415 	case WSDISPLAYIO_GTYPE:
    416 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    417 		return (0);
    418 
    419 	case WSDISPLAYIO_GINFO:
    420 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    421 		wsd_fbip->height = ri->ri_height;
    422 		wsd_fbip->width = ri->ri_width;
    423 		wsd_fbip->depth = ri->ri_depth;
    424 		wsd_fbip->cmsize = CMAP_SIZE;
    425 #undef fbt
    426 		return (0);
    427 
    428 	case WSDISPLAYIO_GETCMAP:
    429 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    430 
    431 	case WSDISPLAYIO_PUTCMAP:
    432 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    433 		if (error == 0)
    434 			ims332_loadcmap(&sc->sc_cmap);
    435 		return (error);
    436 
    437 	case WSDISPLAYIO_SVIDEO:
    438 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    439 		if ((sc->sc_blanked == 0) ^ turnoff) {
    440 			sc->sc_blanked = turnoff;
    441 			xcfb_screenblank(sc);
    442 		}
    443 		return (0);
    444 
    445 	case WSDISPLAYIO_GVIDEO:
    446 		*(u_int *)data = sc->sc_blanked ?
    447 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    448 		return (0);
    449 
    450 	case WSDISPLAYIO_GCURPOS:
    451 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    452 		return (0);
    453 
    454 	case WSDISPLAYIO_SCURPOS:
    455 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    456 		ims332_set_curpos(sc);
    457 		return (0);
    458 
    459 	case WSDISPLAYIO_GCURMAX:
    460 		((struct wsdisplay_curpos *)data)->x =
    461 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    462 		return (0);
    463 
    464 	case WSDISPLAYIO_GCURSOR:
    465 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    466 
    467 	case WSDISPLAYIO_SCURSOR:
    468 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    469 
    470 	case WSDISPLAYIO_SMODE:
    471 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    472 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    473 			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    474 			xcfb_cmap_init(sc);
    475 			ims332_loadcmap(&sc->sc_cmap);
    476 			sc->sc_blanked = 0;
    477 			xcfb_screenblank(sc);
    478 		}
    479 		return (0);
    480 	}
    481 	return (EPASSTHROUGH);
    482 }
    483 
    484 static paddr_t
    485 xcfbmmap(v, offset, prot)
    486 	void *v;
    487 	off_t offset;
    488 	int prot;
    489 {
    490 
    491 	if (offset >= XCFB_FB_SIZE || offset < 0)
    492 		return (-1);
    493 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
    494 }
    495 
    496 static int
    497 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    498 	void *v;
    499 	const struct wsscreen_descr *type;
    500 	void **cookiep;
    501 	int *curxp, *curyp;
    502 	long *attrp;
    503 {
    504 	struct xcfb_softc *sc = v;
    505 	struct rasops_info *ri = sc->sc_ri;
    506 	long defattr;
    507 
    508 	if (sc->nscreens > 0)
    509 		return (ENOMEM);
    510 
    511 	*cookiep = ri; 		/* one and only for now */
    512 	*curxp = 0;
    513 	*curyp = 0;
    514 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    515 	*attrp = defattr;
    516 	sc->nscreens++;
    517 	return (0);
    518 }
    519 
    520 static void
    521 xcfb_free_screen(v, cookie)
    522 	void *v;
    523 	void *cookie;
    524 {
    525 	struct xcfb_softc *sc = v;
    526 
    527 	if (sc->sc_ri == &xcfb_console_ri)
    528 		panic("xcfb_free_screen: console");
    529 
    530 	sc->nscreens--;
    531 }
    532 
    533 static int
    534 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
    535 	void *v;
    536 	void *cookie;
    537 	int waitok;
    538 	void (*cb) __P((void *, int, int));
    539 	void *cbarg;
    540 {
    541 
    542 	return (0);
    543 }
    544 
    545 static int
    546 xcfbintr(v)
    547 	void *v;
    548 {
    549 	struct xcfb_softc *sc = v;
    550 	u_int32_t *intr, i;
    551 
    552 	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
    553 	i = *intr;
    554 	i &= ~XINE_INTR_VINT;
    555 	*intr = i;
    556 	return (1);
    557 }
    558 
    559 static void
    560 xcfb_screenblank(sc)
    561 	struct xcfb_softc *sc;
    562 {
    563 	if (sc->sc_blanked)
    564 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
    565 	else
    566 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
    567 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    568 }
    569 
    570 static int
    571 get_cmap(sc, p)
    572 	struct xcfb_softc *sc;
    573 	struct wsdisplay_cmap *p;
    574 {
    575 	u_int index = p->index, count = p->count;
    576 	int error;
    577 
    578 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    579 		return (EINVAL);
    580 
    581 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    582 	if (error)
    583 		return error;
    584 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    585 	if (error)
    586 		return error;
    587 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    588 	return error;
    589 }
    590 
    591 static int
    592 set_cmap(sc, p)
    593 	struct xcfb_softc *sc;
    594 	struct wsdisplay_cmap *p;
    595 {
    596 	struct hwcmap256 cmap;
    597 	u_int index = p->index, count = p->count;
    598 	int error;
    599 
    600 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    601 		return (EINVAL);
    602 
    603 	error = copyin(p->red, &cmap.r[index], count);
    604 	if (error)
    605 		return error;
    606 	error = copyin(p->green, &cmap.g[index], count);
    607 	if (error)
    608 		return error;
    609 	error = copyin(p->blue, &cmap.b[index], count);
    610 	if (error)
    611 		return error;
    612 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    613 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    614 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    615 	return (0);
    616 }
    617 
    618 static int
    619 set_cursor(sc, p)
    620 	struct xcfb_softc *sc;
    621 	struct wsdisplay_cursor *p;
    622 {
    623 #define	cc (&sc->sc_cursor)
    624 	u_int v, index = 0, count = 0, icount = 0;
    625 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    626 	int error;
    627 
    628 	v = p->which;
    629 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    630 		index = p->cmap.index;
    631 		count = p->cmap.count;
    632 
    633 		if (index >= 2 || index + count > 2)
    634 			return (EINVAL);
    635 		error = copyin(p->cmap.red, &r[index], count);
    636 		if (error)
    637 			return error;
    638 		error = copyin(p->cmap.green, &g[index], count);
    639 		if (error)
    640 			return error;
    641 		error = copyin(p->cmap.blue, &b[index], count);
    642 		if (error)
    643 			return error;
    644 	}
    645 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    646 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    647 			return (EINVAL);
    648 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    649 		error = copyin(p->image, image, icount);
    650 		if (error)
    651 			return error;
    652 		error = copyin(p->mask, mask, icount);
    653 		if (error)
    654 			return error;
    655 	}
    656 
    657 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    658 		memcpy(&cc->cc_color[index], &r[index], count);
    659 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    660 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    661 		ims332_load_curcmap(sc);
    662 	}
    663 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    664 		cc->cc_size = p->size;
    665 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    666 		memcpy(cc->cc_image, image, icount);
    667 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    668 		memcpy(cc->cc_mask, mask, icount);
    669 		ims332_load_curshape(sc);
    670 	}
    671 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    672 		cc->cc_hot = p->hot;
    673 		if (p->enable)
    674 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    675 		else
    676 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    677 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    678 	}
    679 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    680 		set_curpos(sc, &p->pos);
    681 		ims332_set_curpos(sc);
    682 	}
    683 
    684 	return (0);
    685 #undef cc
    686 }
    687 
    688 static int
    689 get_cursor(sc, p)
    690 	struct xcfb_softc *sc;
    691 	struct wsdisplay_cursor *p;
    692 {
    693 	return (EPASSTHROUGH); /* XXX */
    694 }
    695 
    696 static void
    697 set_curpos(sc, curpos)
    698 	struct xcfb_softc *sc;
    699 	struct wsdisplay_curpos *curpos;
    700 {
    701 	struct rasops_info *ri = sc->sc_ri;
    702 	int x = curpos->x, y = curpos->y;
    703 
    704 	if (y < 0)
    705 		y = 0;
    706 	else if (y > ri->ri_height)
    707 		y = ri->ri_height;
    708 	if (x < 0)
    709 		x = 0;
    710 	else if (x > ri->ri_width)
    711 		x = ri->ri_width;
    712 	sc->sc_cursor.cc_pos.x = x;
    713 	sc->sc_cursor.cc_pos.y = y;
    714 }
    715 
    716 static void
    717 ims332_loadcmap(cm)
    718 	struct hwcmap256 *cm;
    719 {
    720 	int i;
    721 	u_int32_t rgb;
    722 
    723 	for (i = 0; i < CMAP_SIZE; i++) {
    724 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    725 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    726 	}
    727 }
    728 
    729 static void
    730 ims332_set_curpos(sc)
    731 	struct xcfb_softc *sc;
    732 {
    733 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    734 	u_int32_t pos;
    735 	int s;
    736 
    737 	s = spltty();
    738 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    739 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    740 	splx(s);
    741 }
    742 
    743 static void
    744 ims332_load_curcmap(sc)
    745 	struct xcfb_softc *sc;
    746 {
    747 	u_int8_t *cp = sc->sc_cursor.cc_color;
    748 	u_int32_t rgb;
    749 
    750 	/* cursor background */
    751 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    752 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    753 
    754 	/* cursor foreground */
    755 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    756 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    757 }
    758 
    759 static void
    760 ims332_load_curshape(sc)
    761 	struct xcfb_softc *sc;
    762 {
    763 	u_int i, img, msk, bits;
    764 	u_int8_t u, *ip, *mp;
    765 
    766 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
    767 	mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    768 
    769 	i = 0;
    770 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
    771 	while (i < sc->sc_cursor.cc_size.y * 8) {
    772 		/* pad right half 32 pixel when smaller than 33 */
    773 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
    774 			bits = 0;
    775 		else {
    776 			img = *ip++;
    777 			msk = *mp++;
    778 			img &= msk;	/* cookie off image */
    779 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    780 			bits = shuffle[u];
    781 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    782 			bits = (shuffle[u] << 8) | bits;
    783 		}
    784 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
    785 		i += 1;
    786 	}
    787 	/* pad unoccupied scan lines */
    788 	while (i < CURSOR_MAX_SIZE * 8) {
    789 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    790 		i += 1;
    791 	}
    792 }
    793 
    794 static void
    795 ims332_write_reg(regno, val)
    796 	int regno;
    797 	u_int32_t val;
    798 {
    799 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    800 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
    801 
    802 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
    803 	*(volatile u_int16_t *)low16 = val;
    804 }
    805 
    806 #if 0
    807 static u_int32_t
    808 ims332_read_reg(regno)
    809 	int regno;
    810 {
    811 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    812 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
    813 	u_int v0, v1;
    814 
    815 	v1 = *(volatile u_int16_t *)high8;
    816 	v0 = *(volatile u_int16_t *)low16;
    817 	return (v1 & 0xff00) << 8 | v0;
    818 }
    819 #endif
    820