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