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