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