Home | History | Annotate | Line # | Download | only in tc
xcfb.c revision 1.25
      1 /* $NetBSD: xcfb.c,v 1.25 2001/11/13 06:26:10 lukem 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>
     34 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.25 2001/11/13 06:26:10 lukem Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/kernel.h>
     39 #include <sys/device.h>
     40 #include <sys/malloc.h>
     41 #include <sys/buf.h>
     42 #include <sys/ioctl.h>
     43 
     44 #include <machine/bus.h>
     45 #include <machine/intr.h>
     46 
     47 #include <dev/wscons/wsconsio.h>
     48 #include <dev/wscons/wsdisplayvar.h>
     49 
     50 #include <dev/rasops/rasops.h>
     51 #include <dev/wsfont/wsfont.h>
     52 
     53 #include <dev/tc/tcvar.h>
     54 #include <dev/tc/ioasicreg.h>
     55 #include <dev/ic/ims332reg.h>
     56 #include <pmax/pmax/maxine.h>
     57 
     58 #include <uvm/uvm_extern.h>
     59 
     60 struct hwcmap256 {
     61 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
     62 	u_int8_t r[CMAP_SIZE];
     63 	u_int8_t g[CMAP_SIZE];
     64 	u_int8_t b[CMAP_SIZE];
     65 };
     66 
     67 struct hwcursor64 {
     68 	struct wsdisplay_curpos cc_pos;
     69 	struct wsdisplay_curpos cc_hot;
     70 	struct wsdisplay_curpos cc_size;
     71 	struct wsdisplay_curpos cc_magic;	/* not used by PMAG-DV */
     72 #define	CURSOR_MAX_SIZE	64
     73 	u_int8_t cc_color[6];
     74 	u_int64_t cc_image[64 + 64];
     75 };
     76 
     77 #define	XCFB_FB_BASE	(XINE_PHYS_CFB_START + 0x2000000)
     78 #define	XCFB_FB_SIZE	0x100000
     79 
     80 #define	IMS332_HIGH	(IOASIC_SLOT_5_START)
     81 #define	IMS332_RLOW	(IOASIC_SLOT_7_START)
     82 #define	IMS332_WLOW	(IOASIC_SLOT_7_START + 0x20000)
     83 
     84 struct xcfb_softc {
     85 	struct device sc_dev;
     86 	vaddr_t sc_vaddr;
     87 	size_t sc_size;
     88 	struct rasops_info *sc_ri;
     89 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
     90 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
     91 	int sc_blanked;
     92 	/* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
     93 	int nscreens;
     94 	/* cursor coordinate is located at upper-left corner */
     95 	int sc_csr;			/* software copy of IMS332 CSR A */
     96 };
     97 
     98 static int  xcfbmatch __P((struct device *, struct cfdata *, void *));
     99 static void xcfbattach __P((struct device *, struct device *, void *));
    100 
    101 const struct cfattach xcfb_ca = {
    102 	sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
    103 };
    104 
    105 static tc_addr_t xcfb_consaddr;
    106 static struct rasops_info xcfb_console_ri;
    107 static void xcfb_common_init __P((struct rasops_info *));
    108 static void xcfbhwinit __P((caddr_t));
    109 int xcfb_cnattach __P((void));
    110 
    111 struct wsscreen_descr xcfb_stdscreen = {
    112 	"std", 0, 0,
    113 	0, /* textops */
    114 	0, 0,
    115 	WSSCREEN_REVERSE
    116 };
    117 
    118 static const struct wsscreen_descr *_xcfb_scrlist[] = {
    119 	&xcfb_stdscreen,
    120 };
    121 
    122 static const struct wsscreen_list xcfb_screenlist = {
    123 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
    124 };
    125 
    126 static int	xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    127 static paddr_t	xcfbmmap __P((void *, off_t, int));
    128 
    129 static int	xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    130 				       void **, int *, int *, long *));
    131 static void	xcfb_free_screen __P((void *, void *));
    132 static int	xcfb_show_screen __P((void *, void *, int,
    133 				      void (*) (void *, int, int), void *));
    134 
    135 static const struct wsdisplay_accessops xcfb_accessops = {
    136 	xcfbioctl,
    137 	xcfbmmap,
    138 	xcfb_alloc_screen,
    139 	xcfb_free_screen,
    140 	xcfb_show_screen,
    141 	0 /* load_font */
    142 };
    143 
    144 static int  xcfbintr __P((void *));
    145 static void xcfb_screenblank __P((struct xcfb_softc *));
    146 static int  set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    147 static int  get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
    148 static int  set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    149 static int  get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
    150 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
    151 static void ims332_loadcmap __P((struct hwcmap256 *));
    152 static void ims332_set_curpos __P((struct xcfb_softc *));
    153 static void ims332_load_curcmap __P((struct xcfb_softc *));
    154 static void ims332_load_curshape __P((struct xcfb_softc *));
    155 static void ims332_write_reg __P((int, u_int32_t));
    156 #if 0
    157 static u_int32_t ims332_read_reg __P((int));
    158 #endif
    159 
    160 extern long ioasic_base;	/* XXX */
    161 
    162 /*
    163  * Compose 2 bit/pixel cursor image.
    164  *   M M M M I I I I		M I M I M I M I
    165  *	[ before ]		   [ after ]
    166  *   3 2 1 0 3 2 1 0		3 3 2 2 1 1 0 0
    167  *   7 6 5 4 7 6 5 4		7 7 6 6 5 5 4 4
    168  */
    169 static const u_int8_t shuffle[256] = {
    170 	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
    171 	0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
    172 	0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
    173 	0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
    174 	0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
    175 	0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
    176 	0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
    177 	0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
    178 	0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
    179 	0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
    180 	0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
    181 	0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
    182 	0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
    183 	0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
    184 	0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
    185 	0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
    186 	0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
    187 	0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
    188 	0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
    189 	0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
    190 	0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
    191 	0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
    192 	0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
    193 	0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
    194 	0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
    195 	0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
    196 	0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
    197 	0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
    198 	0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
    199 	0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
    200 	0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
    201 	0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
    202 };
    203 
    204 static int
    205 xcfbmatch(parent, match, aux)
    206 	struct device *parent;
    207 	struct cfdata *match;
    208 	void *aux;
    209 {
    210 	struct tc_attach_args *ta = aux;
    211 
    212 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
    213 		return (0);
    214 
    215 	return (1);
    216 }
    217 
    218 static void
    219 xcfbattach(parent, self, aux)
    220 	struct device *parent, *self;
    221 	void *aux;
    222 {
    223 	struct xcfb_softc *sc = (struct xcfb_softc *)self;
    224 	struct tc_attach_args *ta = aux;
    225 	struct rasops_info *ri;
    226 	struct wsemuldisplaydev_attach_args waa;
    227 	struct hwcmap256 *cm;
    228 	const u_int8_t *p;
    229 	int console, index;
    230 
    231 	console = (ta->ta_addr == xcfb_consaddr);
    232 	if (console) {
    233 		sc->sc_ri = ri = &xcfb_console_ri;
    234 		sc->nscreens = 1;
    235 	}
    236 	else {
    237 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    238 			M_DEVBUF, M_NOWAIT);
    239 		if (ri == NULL) {
    240 			printf(": can't alloc memory\n");
    241 			return;
    242 		}
    243 		memset(ri, 0, sizeof(struct rasops_info));
    244 
    245 		ri->ri_hw = (void *)ioasic_base;
    246 		xcfb_common_init(ri);
    247 		sc->sc_ri = ri;
    248 	}
    249 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    250 
    251 	cm = &sc->sc_cmap;
    252 	p = rasops_cmap;
    253 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    254 		cm->r[index] = p[0];
    255 		cm->g[index] = p[1];
    256 		cm->b[index] = p[2];
    257 	}
    258 
    259 	sc->sc_vaddr = ta->ta_addr;
    260 	sc->sc_blanked = 0;
    261 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
    262 
    263         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
    264 
    265 	waa.console = console;
    266 	waa.scrdata = &xcfb_screenlist;
    267 	waa.accessops = &xcfb_accessops;
    268 	waa.accesscookie = sc;
    269 
    270 	config_found(self, &waa, wsemuldisplaydevprint);
    271 }
    272 
    273 static void
    274 xcfb_common_init(ri)
    275 	struct rasops_info *ri;
    276 {
    277 	int cookie;
    278 
    279 	/* initialize colormap and cursor hardware */
    280 	xcfbhwinit((caddr_t)ri->ri_hw);
    281 
    282 	ri->ri_flg = RI_CENTER;
    283 	ri->ri_depth = 8;
    284 	ri->ri_width = 1024;
    285 	ri->ri_height = 768;
    286 	ri->ri_stride = 1024;
    287 	ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
    288 
    289 	/* clear the screen */
    290 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    291 
    292 	wsfont_init();
    293 	/* prefer 12 pixel wide font */
    294 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
    295 		cookie = wsfont_find(NULL, 0, 0, 0);
    296 	if (cookie <= 0) {
    297 		printf("xcfb: font table is empty\n");
    298 		return;
    299 	}
    300 
    301 	if (wsfont_lock(cookie, &ri->ri_font,
    302 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
    303 		printf("xcfb: couldn't lock font\n");
    304 		return;
    305 	}
    306 	ri->ri_wsfcookie = cookie;
    307 
    308 	rasops_init(ri, 34, 80);
    309 
    310 	/* XXX shouldn't be global */
    311 	xcfb_stdscreen.nrows = ri->ri_rows;
    312 	xcfb_stdscreen.ncols = ri->ri_cols;
    313 	xcfb_stdscreen.textops = &ri->ri_ops;
    314 	xcfb_stdscreen.capabilities = ri->ri_caps;
    315 }
    316 
    317 int
    318 xcfb_cnattach()
    319 {
    320 	struct rasops_info *ri;
    321 	long defattr;
    322 
    323 	ri = &xcfb_console_ri;
    324 	ri->ri_hw = (void *)ioasic_base;
    325 	xcfb_common_init(ri);
    326 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
    327 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
    328 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
    329 	return (0);
    330 }
    331 
    332 static void
    333 xcfbhwinit(base)
    334 	caddr_t base;
    335 {
    336 	u_int32_t *csr, i;
    337 	const u_int8_t *p;
    338 
    339 	csr = (u_int32_t *)(base + IOASIC_CSR);
    340 	i = *csr;
    341 	i &= ~XINE_CSR_VDAC_ENABLE;
    342 	*csr = i;
    343 	DELAY(50);
    344 	i |= XINE_CSR_VDAC_ENABLE;
    345 	*csr = i;
    346 	DELAY(50);
    347 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
    348 	ims332_write_reg(IMS332_REG_CSR_A,
    349 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
    350 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
    351 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
    352 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
    353 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
    354 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
    355 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
    356 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
    357 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
    358 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
    359 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
    360 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
    361 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
    362 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
    363 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
    364 	ims332_write_reg(IMS332_REG_CSR_A,
    365 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
    366 
    367 	/* build sane colormap */
    368 	p = rasops_cmap;
    369 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    370 		u_int32_t bgr;
    371 
    372 		bgr = p[2] << 16 | p[1] << 8 | p[0];
    373 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
    374 	}
    375 
    376 	/* clear out cursor image */
    377 	for (i = 0; i < 512; i++)
    378 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
    379 
    380 	/*
    381 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    382 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
    383 	 * image color.  LUT_0 will be never used.
    384 	 */
    385 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
    386 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
    387 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
    388 }
    389 
    390 static int
    391 xcfbioctl(v, cmd, data, flag, p)
    392 	void *v;
    393 	u_long cmd;
    394 	caddr_t data;
    395 	int flag;
    396 	struct proc *p;
    397 {
    398 	struct xcfb_softc *sc = v;
    399 	struct rasops_info *ri = sc->sc_ri;
    400 	int turnoff, error;
    401 
    402 	switch (cmd) {
    403 	case WSDISPLAYIO_GTYPE:
    404 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
    405 		return (0);
    406 
    407 	case WSDISPLAYIO_GINFO:
    408 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    409 		wsd_fbip->height = ri->ri_height;
    410 		wsd_fbip->width = ri->ri_width;
    411 		wsd_fbip->depth = ri->ri_depth;
    412 		wsd_fbip->cmsize = CMAP_SIZE;
    413 #undef fbt
    414 		return (0);
    415 
    416 	case WSDISPLAYIO_GETCMAP:
    417 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    418 
    419 	case WSDISPLAYIO_PUTCMAP:
    420 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
    421 		if (error == 0)
    422 			ims332_loadcmap(&sc->sc_cmap);
    423 		return (error);
    424 
    425 	case WSDISPLAYIO_SVIDEO:
    426 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    427 		if ((sc->sc_blanked == 0) ^ turnoff) {
    428 			sc->sc_blanked = turnoff;
    429 			xcfb_screenblank(sc);
    430 		}
    431 		return (0);
    432 
    433 	case WSDISPLAYIO_GVIDEO:
    434 		*(u_int *)data = sc->sc_blanked ?
    435 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    436 		return (0);
    437 
    438 	case WSDISPLAYIO_GCURPOS:
    439 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    440 		return (0);
    441 
    442 	case WSDISPLAYIO_SCURPOS:
    443 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    444 		ims332_set_curpos(sc);
    445 		return (0);
    446 
    447 	case WSDISPLAYIO_GCURMAX:
    448 		((struct wsdisplay_curpos *)data)->x =
    449 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    450 		return (0);
    451 
    452 	case WSDISPLAYIO_GCURSOR:
    453 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    454 
    455 	case WSDISPLAYIO_SCURSOR:
    456 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    457 	}
    458 	return (ENOTTY);
    459 }
    460 
    461 static paddr_t
    462 xcfbmmap(v, offset, prot)
    463 	void *v;
    464 	off_t offset;
    465 	int prot;
    466 {
    467 
    468 	if (offset >= XCFB_FB_SIZE || offset < 0)
    469 		return (-1);
    470 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
    471 }
    472 
    473 static int
    474 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    475 	void *v;
    476 	const struct wsscreen_descr *type;
    477 	void **cookiep;
    478 	int *curxp, *curyp;
    479 	long *attrp;
    480 {
    481 	struct xcfb_softc *sc = v;
    482 	struct rasops_info *ri = sc->sc_ri;
    483 	long defattr;
    484 
    485 	if (sc->nscreens > 0)
    486 		return (ENOMEM);
    487 
    488 	*cookiep = ri; 		/* one and only for now */
    489 	*curxp = 0;
    490 	*curyp = 0;
    491 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
    492 	*attrp = defattr;
    493 	sc->nscreens++;
    494 	return (0);
    495 }
    496 
    497 static void
    498 xcfb_free_screen(v, cookie)
    499 	void *v;
    500 	void *cookie;
    501 {
    502 	struct xcfb_softc *sc = v;
    503 
    504 	if (sc->sc_ri == &xcfb_console_ri)
    505 		panic("xcfb_free_screen: console");
    506 
    507 	sc->nscreens--;
    508 }
    509 
    510 static int
    511 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
    512 	void *v;
    513 	void *cookie;
    514 	int waitok;
    515 	void (*cb) __P((void *, int, int));
    516 	void *cbarg;
    517 {
    518 
    519 	return (0);
    520 }
    521 
    522 static int
    523 xcfbintr(v)
    524 	void *v;
    525 {
    526 	struct xcfb_softc *sc = v;
    527 	u_int32_t *intr, i;
    528 
    529 	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
    530 	i = *intr;
    531 	i &= ~XINE_INTR_VINT;
    532 	*intr = i;
    533 	return (1);
    534 }
    535 
    536 static void
    537 xcfb_screenblank(sc)
    538 	struct xcfb_softc *sc;
    539 {
    540 	if (sc->sc_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 	u_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 rasops_info *ri = sc->sc_ri;
    660 	int x = curpos->x, y = curpos->y;
    661 
    662 	if (y < 0)
    663 		y = 0;
    664 	else if (y > ri->ri_height)
    665 		y = ri->ri_height;
    666 	if (x < 0)
    667 		x = 0;
    668 	else if (x > ri->ri_width)
    669 		x = ri->ri_width;
    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 halfword 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