Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.2
      1 /* $NetBSD: xcfb.c,v 1.2 1998/10/30 00:53:12 nisimura Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1996, 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.2 1998/10/30 00:53:12 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 #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 struct xcfb_softc {
     95 	struct device sc_dev;
     96 	struct fb_devconfig *sc_dc;	/* device configuration */
     97 	struct hwcmap sc_cmap;		/* software copy of colormap */
     98 	struct hwcursor sc_cursor;	/* software copy of cursor */
     99 	/* no sc_change field because PMAG-DV does not emit interrupt */
    100 	/* XXX XXX real-ly !?  See MACH code XXX XXX */
    101 	int nscreens;
    102 };
    103 
    104 int  xcfbmatch __P((struct device *, struct cfdata *, void *));
    105 void xcfbattach __P((struct device *, struct device *, void *));
    106 
    107 struct cfattach xcfb_ca = {
    108 	sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
    109 };
    110 
    111 void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    112 struct fb_devconfig xcfb_console_dc;
    113 tc_addr_t xcfb_consaddr;
    114 
    115 struct wsdisplay_emulops xcfb_emulops = {
    116 	rcons_cursor,
    117 	rcons_mapchar,
    118 	rcons_putchar,
    119 	rcons_copycols,
    120 	rcons_erasecols,
    121 	rcons_copyrows,
    122 	rcons_eraserows,
    123 	rcons_alloc_attr
    124 };
    125 
    126 struct wsscreen_descr xcfb_stdscreen = {
    127 	"std",
    128 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
    129 	&xcfb_emulops,
    130 	0, 0,
    131 	0
    132 };
    133 
    134 const struct wsscreen_descr *_xcfb_scrlist[] = {
    135 	&xcfb_stdscreen,
    136 };
    137 
    138 struct wsscreen_list xcfb_screenlist = {
    139 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
    140 };
    141 
    142 int	xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    143 int	xcfbmmap __P((void *, off_t, int));
    144 
    145 int	xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    146 				      void **, int *, int *, long *));
    147 void	xcfb_free_screen __P((void *, void *));
    148 void	xcfb_show_screen __P((void *, void *));
    149 int	xcfb_load_font __P((void *, void *, int, int, int, void *));
    150 
    151 struct wsdisplay_accessops xcfb_accessops = {
    152 	xcfbioctl,
    153 	xcfbmmap,
    154 	xcfb_alloc_screen,
    155 	xcfb_free_screen,
    156 	xcfb_show_screen,
    157 	xcfb_load_font
    158 };
    159 
    160 int  xcfb_cnattach __P((tc_addr_t));
    161 void xcfbinit __P((struct fb_devconfig *));
    162 void xcfb_blank __P((struct xcfb_softc *));
    163 void xcfb_unblank __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 #define	XCFB_FB_OFFSET	0x2000000	/* from module's base */
    179 #define	XCFB_FB_SIZE	0x100000	/* frame buffer size */
    180 
    181 #define	IMS332_ADDRESS	0xbc140000
    182 #define	IMS332_RPTR	0xbc1c0000
    183 #define	IMS332_WPTR	0xbc1e0000
    184 
    185 int
    186 xcfbmatch(parent, match, aux)
    187 	struct device *parent;
    188 	struct cfdata *match;
    189 	void *aux;
    190 {
    191 	struct tc_attach_args *ta = aux;
    192 
    193 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
    194 		return (0);
    195 
    196 	return (1);
    197 }
    198 
    199 void
    200 xcfb_getdevconfig(dense_addr, dc)
    201 	tc_addr_t dense_addr;
    202 	struct fb_devconfig *dc;
    203 {
    204 	struct raster *rap;
    205 	struct rcons *rcp;
    206 	int i;
    207 
    208 	dc->dc_vaddr = dense_addr;
    209 	dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET);
    210 
    211 	dc->dc_wid = 1024;
    212 	dc->dc_ht = 768;
    213 	dc->dc_depth = 8;
    214 	dc->dc_rowbytes = 1024;
    215 	dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET;
    216 	dc->dc_blanked = 0;
    217 
    218 	/* initialize colormap and cursor resource */
    219 	xcfbinit(dc);
    220 
    221 	/* clear the screen */
    222 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    223 		*(u_int32_t *)(dc->dc_videobase + i) = 0;
    224 
    225 	/* initialize the raster */
    226 	rap = &dc->dc_raster;
    227 	rap->width = dc->dc_wid;
    228 	rap->height = dc->dc_ht;
    229 	rap->depth = dc->dc_depth;
    230 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
    231 	rap->pixels = (u_int32_t *)dc->dc_videobase;
    232 
    233 	/* initialize the raster console blitter */
    234 	rcp = &dc->dc_rcons;
    235 	rcp->rc_sp = rap;
    236 	rcp->rc_crow = rcp->rc_ccol = -1;
    237 	rcp->rc_crowp = &rcp->rc_crow;
    238 	rcp->rc_ccolp = &rcp->rc_ccol;
    239 	rcons_init(rcp, 34, 80);
    240 
    241 	xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
    242 	xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
    243 }
    244 
    245 void
    246 xcfbattach(parent, self, aux)
    247 	struct device *parent, *self;
    248 	void *aux;
    249 {
    250 	struct xcfb_softc *sc = (struct xcfb_softc *)self;
    251 	struct tc_attach_args *ta = aux;
    252 	struct wsemuldisplaydev_attach_args waa;
    253 	struct hwcmap *cm;
    254 	int console, i;
    255 
    256 	console = (ta->ta_addr == xcfb_consaddr);
    257 	if (console) {
    258 		sc->sc_dc = &xcfb_console_dc;
    259 		sc->nscreens = 1;
    260 	}
    261 	else {
    262 		sc->sc_dc = (struct fb_devconfig *)
    263 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    264 		xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    265 	}
    266 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
    267 	    sc->sc_dc->dc_depth);
    268 
    269 	cm = &sc->sc_cmap;
    270 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
    271 	for (i = 1; i < CMAP_SIZE; i++) {
    272 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
    273 	}
    274 
    275 	/* PMAG-DV emits no interrupt */
    276 
    277 	waa.console = console;
    278 	waa.scrdata = &xcfb_screenlist;
    279 	waa.accessops = &xcfb_accessops;
    280 	waa.accesscookie = sc;
    281 
    282 	config_found(self, &waa, wsemuldisplaydevprint);
    283 }
    284 
    285 int
    286 xcfbioctl(v, cmd, data, flag, p)
    287 	void *v;
    288 	u_long cmd;
    289 	caddr_t data;
    290 	int flag;
    291 	struct proc *p;
    292 {
    293 	struct xcfb_softc *sc = v;
    294 	struct fb_devconfig *dc = sc->sc_dc;
    295 	int error;
    296 
    297 	switch (cmd) {
    298 	case WSDISPLAYIO_GTYPE:
    299 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    300 		return (0);
    301 
    302 	case WSDISPLAYIO_GINFO:
    303 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    304 		wsd_fbip->height = sc->sc_dc->dc_ht;
    305 		wsd_fbip->width = sc->sc_dc->dc_wid;
    306 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    307 		wsd_fbip->cmsize = CMAP_SIZE;
    308 #undef fbt
    309 		return (0);
    310 
    311 	case WSDISPLAYIO_GETCMAP:
    312 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    313 
    314 	case WSDISPLAYIO_PUTCMAP:
    315 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    316 		if (error == 0)
    317 			ims332_loadcmap(&sc->sc_cmap);
    318 		return (error);
    319 
    320 	case WSDISPLAYIO_SVIDEO:
    321 		if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
    322 			xcfb_blank(sc);
    323 		else
    324 			xcfb_unblank(sc);
    325 		return (0);
    326 
    327 	case WSDISPLAYIO_GVIDEO:
    328 		*(u_int *)data = dc->dc_blanked ?
    329 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    330 		return (0);
    331 
    332 	case WSDISPLAYIO_GCURPOS:
    333 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    334 		return (0);
    335 
    336 	case WSDISPLAYIO_SCURPOS:
    337 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    338 		ims332_set_curpos(sc);
    339 		return (0);
    340 
    341 	case WSDISPLAYIO_GCURMAX:
    342 		((struct wsdisplay_curpos *)data)->x =
    343 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    344 		return (0);
    345 
    346 	case WSDISPLAYIO_GCURSOR:
    347 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    348 
    349 	case WSDISPLAYIO_SCURSOR:
    350 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    351 	}
    352 	return ENOTTY;
    353 }
    354 
    355 int
    356 xcfbmmap(v, offset, prot)
    357 	void *v;
    358 	off_t offset;
    359 	int prot;
    360 {
    361 	struct xcfb_softc *sc = v;
    362 
    363 	if (offset > XCFB_FB_SIZE)
    364 		return -1;
    365 	return mips_btop(sc->sc_dc->dc_paddr + offset);
    366 }
    367 
    368 int
    369 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    370 	void *v;
    371 	const struct wsscreen_descr *type;
    372 	void **cookiep;
    373 	int *curxp, *curyp;
    374 	long *attrp;
    375 {
    376 	struct xcfb_softc *sc = v;
    377 	long defattr;
    378 
    379 	if (sc->nscreens > 0)
    380 		return (ENOMEM);
    381 
    382 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
    383 	*curxp = 0;
    384 	*curyp = 0;
    385 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
    386 	*attrp = defattr;
    387 	sc->nscreens++;
    388 	return (0);
    389 }
    390 
    391 void
    392 xcfb_free_screen(v, cookie)
    393 	void *v;
    394 	void *cookie;
    395 {
    396 	struct xcfb_softc *sc = v;
    397 
    398 	if (sc->sc_dc == &xcfb_console_dc)
    399 		panic("xcfb_free_screen: console");
    400 
    401 	sc->nscreens--;
    402 }
    403 
    404 void
    405 xcfb_show_screen(v, cookie)
    406 	void *v;
    407 	void *cookie;
    408 {
    409 }
    410 
    411 int
    412 xcfb_load_font(v, cookie, first, num, stride, data)
    413 	void *v;
    414 	void *cookie;
    415 	int first, num, stride;
    416 	void *data;
    417 {
    418 	return (EINVAL);
    419 }
    420 
    421 int
    422 xcfb_cnattach(addr)
    423         tc_addr_t addr;
    424 {
    425         struct fb_devconfig *dcp = &xcfb_console_dc;
    426         long defattr;
    427 
    428         xcfb_getdevconfig(addr, dcp);
    429 
    430         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
    431 
    432         wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
    433                            0, 0, defattr);
    434         xcfb_consaddr = addr;
    435         return(0);
    436 }
    437 
    438 void
    439 xcfbinit(dc)
    440 	struct fb_devconfig *dc;
    441 {
    442 	u_int32_t csr;
    443 	int i;
    444 
    445 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    446 	for (i = 1; i < CMAP_SIZE; i++)
    447 		ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
    448 
    449 	csr = IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE
    450 		| IMS332_CSR_A_VTG_ENABLE | IMS332_CSR_A_DISABLE_CURSOR;
    451 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    452 
    453 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    454 }
    455 
    456 void
    457 xcfb_blank(sc)
    458 	struct xcfb_softc *sc;
    459 {
    460 	struct fb_devconfig *dc = sc->sc_dc;
    461 
    462 	if (dc->dc_blanked)
    463 		return;
    464 	dc->dc_blanked = 1;
    465 
    466 	/* blank screen */
    467 	ims332_write_reg(IMS332_REG_LUT_BASE, 0);
    468 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0);
    469 #if 0
    470 	/* turnoff hardware cursor */
    471 	csr = ims332_read_reg(IMS332_REG_CSR_A);
    472 	csr |= IMS332_CSR_A_DISABLE_CURSOR;
    473 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    474 #endif	/* pratically unnecessary */
    475 }
    476 
    477 void
    478 xcfb_unblank(sc)
    479 	struct xcfb_softc *sc;
    480 {
    481 	struct fb_devconfig *dc = sc->sc_dc;
    482 
    483 	if (!dc->dc_blanked)
    484 		return;
    485 	dc->dc_blanked = 0;
    486 
    487 	/* restore current colormap */
    488 	ims332_loadcmap(&sc->sc_cmap);
    489 #if 0
    490 	/* turnon hardware cursor */
    491 	csr = ims332_read_reg(IMS332_REG_CSR_A);
    492 	csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    493 	ims332_write_reg(IMS332_REG_CSR_A, csr);
    494 #endif	/* pratically unnecessary */
    495 }
    496 
    497 static int
    498 get_cmap(sc, p)
    499 	struct xcfb_softc *sc;
    500 	struct wsdisplay_cmap *p;
    501 {
    502 	u_int index = p->index, count = p->count;
    503 
    504 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    505 		return (EINVAL);
    506 
    507 	if (!useracc(p->red, count, B_WRITE) ||
    508 	    !useracc(p->green, count, B_WRITE) ||
    509 	    !useracc(p->blue, count, B_WRITE))
    510 		return (EFAULT);
    511 
    512 	copyout(&sc->sc_cmap.r[index], p->red, count);
    513 	copyout(&sc->sc_cmap.g[index], p->green, count);
    514 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    515 
    516 	return (0);
    517 }
    518 
    519 static int
    520 set_cmap(sc, p)
    521 	struct xcfb_softc *sc;
    522 	struct wsdisplay_cmap *p;
    523 {
    524 	u_int index = p->index, count = p->count;
    525 
    526 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    527 		return (EINVAL);
    528 
    529 	if (!useracc(p->red, count, B_READ) ||
    530 	    !useracc(p->green, count, B_READ) ||
    531 	    !useracc(p->blue, count, B_READ))
    532 		return (EFAULT);
    533 
    534 	copyin(p->red, &sc->sc_cmap.r[index], count);
    535 	copyin(p->green, &sc->sc_cmap.g[index], count);
    536 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    537 
    538 	return (0);
    539 }
    540 
    541 static int
    542 set_cursor(sc, p)
    543 	struct xcfb_softc *sc;
    544 	struct wsdisplay_cursor *p;
    545 {
    546 #define	cc (&sc->sc_cursor)
    547 	int v, index, count;
    548 	u_int32_t csr;
    549 
    550 	v = p->which;
    551 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    552 		index = p->cmap.index;
    553 		count = p->cmap.count;
    554 
    555 		if (index >= 2 || index + count > 2)
    556 			return (EINVAL);
    557 		if (!useracc(p->cmap.red, count, B_READ) ||
    558 		    !useracc(p->cmap.green, count, B_READ) ||
    559 		    !useracc(p->cmap.blue, count, B_READ))
    560 			return (EFAULT);
    561 
    562 		copyin(p->cmap.red, &cc->cc_color[index], count);
    563 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    564 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    565 
    566 		ims332_load_curcmap(sc);
    567 	}
    568 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    569 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    570 			return (EINVAL);
    571 		count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
    572 		if (!useracc(p->image, count, B_READ) ||
    573 		    !useracc(p->mask, count, B_READ))
    574 			return (EFAULT);
    575 		cc->cc_size = p->size;
    576 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    577 		copyin(p->image, cc->cc_image, count);
    578 		copyin(p->mask, &cc->cc_image[CURSOR_MAX_SIZE], count);
    579 
    580 		ims332_load_curshape(sc);
    581 	}
    582 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    583 		cc->cc_hot = p->hot;
    584 		csr = ims332_read_reg(IMS332_REG_CSR_A);
    585 		if (p->enable)
    586 			csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
    587 		else
    588 			csr |= IMS332_CSR_A_DISABLE_CURSOR;
    589 		ims332_write_reg(IMS332_REG_CSR_A, csr);
    590 	}
    591 	if (v & WSDISPLAY_CURSOR_DOPOS) {
    592 		set_curpos(sc, &p->pos);
    593 		ims332_set_curpos(sc);
    594 	}
    595 
    596 	return (0);
    597 #undef cc
    598 }
    599 
    600 static int
    601 get_cursor(sc, p)
    602 	struct xcfb_softc *sc;
    603 	struct wsdisplay_cursor *p;
    604 {
    605 	return (ENOTTY); /* XXX */
    606 }
    607 
    608 static void
    609 set_curpos(sc, curpos)
    610 	struct xcfb_softc *sc;
    611 	struct wsdisplay_curpos *curpos;
    612 {
    613 	struct fb_devconfig *dc = sc->sc_dc;
    614 	int x = curpos->x, y = curpos->y;
    615 
    616 	if (y < 0)
    617 		y = 0;
    618 	else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
    619 		y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
    620 	if (x < 0)
    621 		x = 0;
    622 	else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
    623 		x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
    624 	sc->sc_cursor.cc_pos.x = x;
    625 	sc->sc_cursor.cc_pos.y = y;
    626 }
    627 
    628 void
    629 ims332_loadcmap(cm)
    630 	struct hwcmap *cm;
    631 {
    632 	int i;
    633 	u_int32_t rgb;
    634 
    635 	for (i = 0; i < CMAP_SIZE; i++) {
    636 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
    637 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
    638 	}
    639 }
    640 
    641 void
    642 ims332_set_curpos(sc)
    643 	struct xcfb_softc *sc;
    644 {
    645 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
    646 	u_int32_t pos;
    647 
    648 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
    649 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
    650 }
    651 
    652 void
    653 ims332_load_curcmap(sc)
    654 	struct xcfb_softc *sc;
    655 {
    656 	u_int8_t *cp = sc->sc_cursor.cc_color;
    657 	u_int32_t rgb;
    658 
    659 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
    660 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, rgb);
    661 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
    662 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
    663 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
    664 }
    665 
    666 void
    667 ims332_load_curshape(sc)
    668 	struct xcfb_softc *sc;
    669 {
    670 	int i;
    671 	u_int16_t *word;
    672 
    673 	word = (u_int16_t *)sc->sc_cursor.cc_image;
    674 	for (i = 0; i < sizeof(sc->sc_cursor.cc_image)/sizeof(u_int16_t); i++)
    675 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, *word++);
    676 }
    677 
    678 u_int32_t
    679 ims332_read_reg(regno)
    680 	int regno;
    681 {
    682 	caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
    683 	caddr_t rptr = (caddr_t)IMS332_RPTR + (regno << 4);
    684 	u_int v0, v1;
    685 
    686 	v1 = *(volatile u_int32_t *)imsreg;
    687 	v0 = *(volatile u_int16_t *)rptr;
    688 	return (v1 & 0xff00) << 8 | v0;
    689 }
    690 
    691 void
    692 ims332_write_reg(regno, val)
    693 	int regno;
    694 	u_int32_t val;
    695 {
    696 	caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
    697 	caddr_t wptr = (caddr_t)IMS332_WPTR + (regno << 4);
    698 
    699 	*(volatile u_int32_t *)imsreg = (val & 0xff0000) >> 8;
    700 	*(volatile u_int16_t *)wptr = val;
    701 }
    702