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