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