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