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