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