Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.41
      1 /* $NetBSD: xcfb.c,v 1.41 2006/03/31 17:39:33 thorpej 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.41 2006/03/31 17:39:33 thorpej 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 lwp *);
    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(struct device *parent, struct cfdata *match, void *aux)
    207 {
    208 	struct tc_attach_args *ta = aux;
    209 
    210 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
    211 		return (0);
    212 
    213 	return (1);
    214 }
    215 
    216 static void
    217 xcfbattach(struct device *parent, struct device *self, void *aux)
    218 {
    219 	struct xcfb_softc *sc = device_private(self);
    220 	struct tc_attach_args *ta = aux;
    221 	struct rasops_info *ri;
    222 	struct wsemuldisplaydev_attach_args waa;
    223 	int console;
    224 
    225 	console = (ta->ta_addr == xcfb_consaddr);
    226 	if (console) {
    227 		sc->sc_ri = ri = &xcfb_console_ri;
    228 		sc->nscreens = 1;
    229 	}
    230 	else {
    231 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    232 			M_DEVBUF, M_NOWAIT);
    233 		if (ri == NULL) {
    234 			printf(": can't alloc memory\n");
    235 			return;
    236 		}
    237 		memset(ri, 0, sizeof(struct rasops_info));
    238 
    239 		ri->ri_hw = (void *)ioasic_base;
    240 		xcfb_common_init(ri);
    241 		sc->sc_ri = ri;
    242 	}
    243 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    244 
    245 	xcfb_cmap_init(sc);
    246 
    247 	sc->sc_vaddr = ta->ta_addr;
    248 	sc->sc_blanked = 0;
    249 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
    250 
    251         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
    252 
    253 	waa.console = console;
    254 	waa.scrdata = &xcfb_screenlist;
    255 	waa.accessops = &xcfb_accessops;
    256 	waa.accesscookie = sc;
    257 
    258 	config_found(self, &waa, wsemuldisplaydevprint);
    259 }
    260 
    261 static void
    262 xcfb_cmap_init(struct xcfb_softc *sc)
    263 {
    264 	struct hwcmap256 *cm;
    265 	const u_int8_t *p;
    266 	int index;
    267 
    268 	cm = &sc->sc_cmap;
    269 	p = rasops_cmap;
    270 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    271 		cm->r[index] = p[0];
    272 		cm->g[index] = p[1];
    273 		cm->b[index] = p[2];
    274 	}
    275 }
    276 
    277 static void
    278 xcfb_common_init(struct rasops_info *ri)
    279 {
    280 	int cookie;
    281 
    282 	/* initialize colormap and cursor hardware */
    283 	xcfbhwinit((caddr_t)ri->ri_hw);
    284 
    285 	ri->ri_flg = RI_CENTER;
    286 	ri->ri_depth = 8;
    287 	ri->ri_width = 1024;
    288 	ri->ri_height = 768;
    289 	ri->ri_stride = 1024;
    290 	ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
    291 
    292 	/* clear the screen */
    293 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    294 
    295 	wsfont_init();
    296 	/* prefer 12 pixel wide font */
    297 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    298 	    WSDISPLAY_FONTORDER_L2R);
    299 	if (cookie <= 0)
    300 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    301 		    WSDISPLAY_FONTORDER_L2R);
    302 	if (cookie <= 0) {
    303 		printf("xcfb: font table is empty\n");
    304 		return;
    305 	}
    306 
    307 	if (wsfont_lock(cookie, &ri->ri_font)) {
    308 		printf("xcfb: couldn't lock font\n");
    309 		return;
    310 	}
    311 	ri->ri_wsfcookie = cookie;
    312 
    313 	rasops_init(ri, 34, 80);
    314 
    315 	/* XXX shouldn't be global */
    316 	xcfb_stdscreen.nrows = ri->ri_rows;
    317 	xcfb_stdscreen.ncols = ri->ri_cols;
    318 	xcfb_stdscreen.textops = &ri->ri_ops;
    319 	xcfb_stdscreen.capabilities = ri->ri_caps;
    320 }
    321 
    322 int
    323 xcfb_cnattach(void)
    324 {
    325 	struct rasops_info *ri;
    326 	long defattr;
    327 
    328 	ri = &xcfb_console_ri;
    329 	ri->ri_hw = (void *)ioasic_base;
    330 	xcfb_common_init(ri);
    331 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    332 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
    333 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
    334 	return (0);
    335 }
    336 
    337 static void
    338 xcfbhwinit(caddr_t base)
    339 {
    340 	volatile u_int32_t *csr;
    341 	u_int32_t i;
    342 	const u_int8_t *p;
    343 
    344 	csr = (volatile u_int32_t *)(base + IOASIC_CSR);
    345 	i = *csr;
    346 	i &= ~XINE_CSR_VDAC_ENABLE;
    347 	*csr = i;
    348 	DELAY(50);
    349 	i |= XINE_CSR_VDAC_ENABLE;
    350 	*csr = i;
    351 	DELAY(50);
    352 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
    353 	ims332_write_reg(IMS332_REG_CSR_A,
    354 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
    355 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
    356 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
    357 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
    358 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
    359 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
    360 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
    361 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
    362 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
    363 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
    364 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
    365 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
    366 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
    367 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
    368 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    369 	ims332_write_reg(IMS332_REG_CSR_A,
    370 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
    371 
    372 	/* build sane colormap */
    373 	p = rasops_cmap;
    374 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    375 		u_int32_t bgr;
    376 
    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 
    395 static int
    396 xcfbioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l)
    397 {
    398 	struct xcfb_softc *sc = v;
    399 	struct rasops_info *ri = sc->sc_ri;
    400 	int turnoff, error;
    401 
    402 	switch (cmd) {
    403 	case WSDISPLAYIO_GTYPE:
    404 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    405 		return (0);
    406 
    407 	case WSDISPLAYIO_GINFO:
    408 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    409 		wsd_fbip->height = ri->ri_height;
    410 		wsd_fbip->width = ri->ri_width;
    411 		wsd_fbip->depth = ri->ri_depth;
    412 		wsd_fbip->cmsize = CMAP_SIZE;
    413 #undef fbt
    414 		return (0);
    415 
    416 	case WSDISPLAYIO_GETCMAP:
    417 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    418 
    419 	case WSDISPLAYIO_PUTCMAP:
    420 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    421 		if (error == 0)
    422 			ims332_loadcmap(&sc->sc_cmap);
    423 		return (error);
    424 
    425 	case WSDISPLAYIO_SVIDEO:
    426 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    427 		if (sc->sc_blanked != turnoff) {
    428 			sc->sc_blanked = turnoff;
    429 			xcfb_screenblank(sc);
    430 		}
    431 		return (0);
    432 
    433 	case WSDISPLAYIO_GVIDEO:
    434 		*(u_int *)data = sc->sc_blanked ?
    435 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    436 		return (0);
    437 
    438 	case WSDISPLAYIO_GCURPOS:
    439 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    440 		return (0);
    441 
    442 	case WSDISPLAYIO_SCURPOS:
    443 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    444 		ims332_set_curpos(sc);
    445 		return (0);
    446 
    447 	case WSDISPLAYIO_GCURMAX:
    448 		((struct wsdisplay_curpos *)data)->x =
    449 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    450 		return (0);
    451 
    452 	case WSDISPLAYIO_GCURSOR:
    453 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    454 
    455 	case WSDISPLAYIO_SCURSOR:
    456 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    457 
    458 	case WSDISPLAYIO_SMODE:
    459 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    460 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    461 			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    462 			xcfb_cmap_init(sc);
    463 			ims332_loadcmap(&sc->sc_cmap);
    464 			sc->sc_blanked = 0;
    465 			xcfb_screenblank(sc);
    466 		}
    467 		return (0);
    468 	}
    469 	return (EPASSTHROUGH);
    470 }
    471 
    472 static paddr_t
    473 xcfbmmap(void *v, off_t offset, int prot)
    474 {
    475 
    476 	if (offset >= XCFB_FB_SIZE || offset < 0)
    477 		return (-1);
    478 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
    479 }
    480 
    481 static int
    482 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    483     int *curxp, int *curyp, long *attrp)
    484 {
    485 	struct xcfb_softc *sc = v;
    486 	struct rasops_info *ri = sc->sc_ri;
    487 	long defattr;
    488 
    489 	if (sc->nscreens > 0)
    490 		return (ENOMEM);
    491 
    492 	*cookiep = ri; 		/* one and only for now */
    493 	*curxp = 0;
    494 	*curyp = 0;
    495 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    496 	*attrp = defattr;
    497 	sc->nscreens++;
    498 	return (0);
    499 }
    500 
    501 static void
    502 xcfb_free_screen(void *v, 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(void *v, void *cookie, int waitok,
    514     void (*cb)(void *, int, int), void *cbarg)
    515 {
    516 
    517 	return (0);
    518 }
    519 
    520 static int
    521 xcfbintr(void *v)
    522 {
    523 	struct xcfb_softc *sc = v;
    524 	u_int32_t *intr, i;
    525 
    526 	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
    527 	i = *intr;
    528 	i &= ~XINE_INTR_VINT;
    529 	*intr = i;
    530 	return (1);
    531 }
    532 
    533 static void
    534 xcfb_screenblank(struct xcfb_softc *sc)
    535 {
    536 	if (sc->sc_blanked)
    537 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
    538 	else
    539 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
    540 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    541 }
    542 
    543 static int
    544 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
    545 {
    546 	u_int index = p->index, count = p->count;
    547 	int error;
    548 
    549 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    550 		return (EINVAL);
    551 
    552 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    553 	if (error)
    554 		return error;
    555 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    556 	if (error)
    557 		return error;
    558 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    559 	return error;
    560 }
    561 
    562 static int
    563 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
    564 {
    565 	struct hwcmap256 cmap;
    566 	u_int index = p->index, count = p->count;
    567 	int error;
    568 
    569 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    570 		return (EINVAL);
    571 
    572 	error = copyin(p->red, &cmap.r[index], count);
    573 	if (error)
    574 		return error;
    575 	error = copyin(p->green, &cmap.g[index], count);
    576 	if (error)
    577 		return error;
    578 	error = copyin(p->blue, &cmap.b[index], count);
    579 	if (error)
    580 		return error;
    581 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    582 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    583 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    584 	return (0);
    585 }
    586 
    587 static int
    588 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
    589 {
    590 #define	cc (&sc->sc_cursor)
    591 	u_int v, index = 0, count = 0, icount = 0;
    592 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    593 	int error;
    594 
    595 	v = p->which;
    596 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    597 		index = p->cmap.index;
    598 		count = p->cmap.count;
    599 
    600 		if (index >= 2 || index + count > 2)
    601 			return (EINVAL);
    602 		error = copyin(p->cmap.red, &r[index], count);
    603 		if (error)
    604 			return error;
    605 		error = copyin(p->cmap.green, &g[index], count);
    606 		if (error)
    607 			return error;
    608 		error = copyin(p->cmap.blue, &b[index], count);
    609 		if (error)
    610 			return error;
    611 	}
    612 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    613 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    614 			return (EINVAL);
    615 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    616 		error = copyin(p->image, image, icount);
    617 		if (error)
    618 			return error;
    619 		error = copyin(p->mask, mask, icount);
    620 		if (error)
    621 			return error;
    622 	}
    623 
    624 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    625 		memcpy(&cc->cc_color[index], &r[index], count);
    626 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    627 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    628 		ims332_load_curcmap(sc);
    629 	}
    630 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    631 		cc->cc_size = p->size;
    632 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    633 		memcpy(cc->cc_image, image, icount);
    634 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    635 		memcpy(cc->cc_mask, mask, icount);
    636 		ims332_load_curshape(sc);
    637 	}
    638 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    639 		cc->cc_hot = p->hot;
    640 		if (p->enable)
    641 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    642 		else
    643 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
    644 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
    645 	}
    646 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    647 		set_curpos(sc, &p->pos);
    648 		ims332_set_curpos(sc);
    649 	}
    650 
    651 	return (0);
    652 #undef cc
    653 }
    654 
    655 static int
    656 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
    657 {
    658 	return (EPASSTHROUGH); /* XXX */
    659 }
    660 
    661 static void
    662 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
    663 {
    664 	struct rasops_info *ri = sc->sc_ri;
    665 	int x = curpos->x, y = curpos->y;
    666 
    667 	if (y < 0)
    668 		y = 0;
    669 	else if (y > ri->ri_height)
    670 		y = ri->ri_height;
    671 	if (x < 0)
    672 		x = 0;
    673 	else if (x > ri->ri_width)
    674 		x = ri->ri_width;
    675 	sc->sc_cursor.cc_pos.x = x;
    676 	sc->sc_cursor.cc_pos.y = y;
    677 }
    678 
    679 static void
    680 ims332_loadcmap(struct hwcmap256 *cm)
    681 {
    682 	int i;
    683 	u_int32_t rgb;
    684 
    685 	for (i = 0; i < CMAP_SIZE; i++) {
    686 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    687 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    688 	}
    689 }
    690 
    691 static void
    692 ims332_set_curpos(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 
    704 static void
    705 ims332_load_curcmap(struct xcfb_softc *sc)
    706 {
    707 	u_int8_t *cp = sc->sc_cursor.cc_color;
    708 	u_int32_t rgb;
    709 
    710 	/* cursor background */
    711 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    712 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    713 
    714 	/* cursor foreground */
    715 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    716 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    717 }
    718 
    719 static void
    720 ims332_load_curshape(struct xcfb_softc *sc)
    721 {
    722 	u_int i, img, msk, bits;
    723 	u_int8_t u, *ip, *mp;
    724 
    725 	ip = (u_int8_t *)sc->sc_cursor.cc_image;
    726 	mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    727 
    728 	i = 0;
    729 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
    730 	while (i < sc->sc_cursor.cc_size.y * 8) {
    731 		/* pad right half 32 pixel when smaller than 33 */
    732 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
    733 			bits = 0;
    734 		else {
    735 			img = *ip++;
    736 			msk = *mp++;
    737 			img &= msk;	/* cookie off image */
    738 			u = (msk & 0x0f) << 4 | (img & 0x0f);
    739 			bits = shuffle[u];
    740 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
    741 			bits = (shuffle[u] << 8) | bits;
    742 		}
    743 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
    744 		i += 1;
    745 	}
    746 	/* pad unoccupied scan lines */
    747 	while (i < CURSOR_MAX_SIZE * 8) {
    748 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    749 		i += 1;
    750 	}
    751 }
    752 
    753 static void
    754 ims332_write_reg(int regno, u_int32_t val)
    755 {
    756 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    757 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
    758 
    759 	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
    760 	*(volatile u_int16_t *)low16 = val;
    761 }
    762 
    763 #if 0
    764 static u_int32_t
    765 ims332_read_reg(int regno)
    766 {
    767 	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
    768 	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
    769 	u_int v0, v1;
    770 
    771 	v1 = *(volatile u_int16_t *)high8;
    772 	v0 = *(volatile u_int16_t *)low16;
    773 	return (v1 & 0xff00) << 8 | v0;
    774 }
    775 #endif
    776