Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.43
      1 /* $NetBSD: cfb.c,v 1.43 2003/12/17 03:59:32 ad 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: cfb.c,v 1.43 2003/12/17 03:59:32 ad 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/ic/bt459reg.h>
     55 
     56 #include <uvm/uvm_extern.h>
     57 
     58 #if defined(pmax)
     59 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
     60 #endif
     61 
     62 #if defined(alpha)
     63 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
     64 #endif
     65 
     66 /*
     67  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     68  * obscure register layout such as 2nd and 3rd Bt459 registers are
     69  * adjacent each other in a word, i.e.,
     70  *	struct bt459triplet {
     71  * 		struct {
     72  *			u_int8_t u0;
     73  *			u_int8_t u1;
     74  *			u_int8_t u2;
     75  *			unsigned :8;
     76  *		} bt_lo;
     77  *		...
     78  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
     79  *	struct bt459reg {
     80  *		   u_int32_t	   bt_lo;
     81  *		   u_int32_t	   bt_hi;
     82  *		   u_int32_t	   bt_reg;
     83  *		   u_int32_t	   bt_cmap;
     84  *	};
     85  */
     86 
     87 /* Bt459 hardware registers */
     88 #define	bt_lo	0
     89 #define	bt_hi	1
     90 #define	bt_reg	2
     91 #define	bt_cmap 3
     92 
     93 #define	REG(base, index)	*((u_int32_t *)(base) + (index))
     94 #define	SELECT(vdac, regno) do {			\
     95 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
     96 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
     97 	tc_wmb();					\
     98    } while (0)
     99 
    100 struct hwcmap256 {
    101 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    102 	u_int8_t r[CMAP_SIZE];
    103 	u_int8_t g[CMAP_SIZE];
    104 	u_int8_t b[CMAP_SIZE];
    105 };
    106 
    107 struct hwcursor64 {
    108 	struct wsdisplay_curpos cc_pos;
    109 	struct wsdisplay_curpos cc_hot;
    110 	struct wsdisplay_curpos cc_size;
    111 	struct wsdisplay_curpos cc_magic;
    112 #define	CURSOR_MAX_SIZE	64
    113 	u_int8_t cc_color[6];
    114 	u_int64_t cc_image[CURSOR_MAX_SIZE];
    115 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
    116 };
    117 
    118 struct cfb_softc {
    119 	struct device sc_dev;
    120 	vaddr_t sc_vaddr;
    121 	size_t sc_size;
    122 	struct rasops_info *sc_ri;
    123 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    124 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    125 	int sc_blanked;
    126 	int sc_curenb;			/* cursor sprite enabled */
    127 	int sc_changed;			/* need update of hardware */
    128 #define	WSDISPLAY_CMAP_DOLUT	0x20
    129 	int nscreens;
    130 };
    131 
    132 #define	CX_MAGIC_X	220
    133 #define	CX_MAGIC_Y 	35
    134 
    135 #define	CX_FB_OFFSET	0x000000
    136 #define	CX_FB_SIZE	0x100000
    137 #define	CX_BT459_OFFSET	0x200000
    138 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
    139 
    140 static int  cfbmatch __P((struct device *, struct cfdata *, void *));
    141 static void cfbattach __P((struct device *, struct device *, void *));
    142 
    143 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
    144     cfbmatch, cfbattach, NULL, NULL);
    145 
    146 static void cfb_common_init __P((struct rasops_info *));
    147 static struct rasops_info cfb_console_ri;
    148 static tc_addr_t cfb_consaddr;
    149 
    150 static struct wsscreen_descr cfb_stdscreen = {
    151 	"std", 0, 0,
    152 	0, /* textops */
    153 	0, 0,
    154 	WSSCREEN_REVERSE
    155 };
    156 
    157 static const struct wsscreen_descr *_cfb_scrlist[] = {
    158 	&cfb_stdscreen,
    159 };
    160 
    161 static const struct wsscreen_list cfb_screenlist = {
    162 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    163 };
    164 
    165 static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    166 static paddr_t	cfbmmap __P((void *, off_t, int));
    167 
    168 static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    169 				      void **, int *, int *, long *));
    170 static void	cfb_free_screen __P((void *, void *));
    171 static int	cfb_show_screen __P((void *, void *, int,
    172 				     void (*) (void *, int, int), void *));
    173 
    174 static const struct wsdisplay_accessops cfb_accessops = {
    175 	cfbioctl,
    176 	cfbmmap,
    177 	cfb_alloc_screen,
    178 	cfb_free_screen,
    179 	cfb_show_screen,
    180 	0 /* load_font */
    181 };
    182 
    183 int  cfb_cnattach __P((tc_addr_t));
    184 static int  cfbintr __P((void *));
    185 static void cfbhwinit __P((caddr_t));
    186 static void cfb_cmap_init __P((struct cfb_softc *));
    187 
    188 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    189 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    190 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    191 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    192 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
    193 
    194 /*
    195  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
    196  *   M M M M I I I I		M I M I M I M I
    197  *	[ before ]		   [ after ]
    198  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
    199  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
    200  */
    201 static const u_int8_t shuffle[256] = {
    202 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
    203 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
    204 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
    205 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
    206 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
    207 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
    208 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
    209 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
    210 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
    211 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
    212 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
    213 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
    214 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
    215 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
    216 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
    217 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
    218 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
    219 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
    220 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
    221 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
    222 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
    223 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
    224 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
    225 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
    226 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
    227 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
    228 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
    229 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
    230 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
    231 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
    232 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
    233 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
    234 };
    235 
    236 static int
    237 cfbmatch(parent, match, aux)
    238 	struct device *parent;
    239 	struct cfdata *match;
    240 	void *aux;
    241 {
    242 	struct tc_attach_args *ta = aux;
    243 
    244 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    245 		return (0);
    246 
    247 	return (1);
    248 }
    249 
    250 static void
    251 cfbattach(parent, self, aux)
    252 	struct device *parent, *self;
    253 	void *aux;
    254 {
    255 	struct cfb_softc *sc = (struct cfb_softc *)self;
    256 	struct tc_attach_args *ta = aux;
    257 	struct rasops_info *ri;
    258 	struct wsemuldisplaydev_attach_args waa;
    259 	int console;
    260 
    261 	console = (ta->ta_addr == cfb_consaddr);
    262 	if (console) {
    263 		sc->sc_ri = ri = &cfb_console_ri;
    264 		sc->nscreens = 1;
    265 	}
    266 	else {
    267 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    268 			M_DEVBUF, M_NOWAIT);
    269 		if (ri == NULL) {
    270 			printf(": can't alloc memory\n");
    271 			return;
    272 		}
    273 		memset(ri, 0, sizeof(struct rasops_info));
    274 
    275 		ri->ri_hw = (void *)ta->ta_addr;
    276 		cfb_common_init(ri);
    277 		sc->sc_ri = ri;
    278 	}
    279 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    280 
    281 	cfb_cmap_init(sc);
    282 
    283 	sc->sc_vaddr = ta->ta_addr;
    284 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
    285 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
    286 	sc->sc_blanked = sc->sc_curenb = 0;
    287 
    288 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
    289 
    290 	/* clear any pending interrupts */
    291 	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
    292 
    293 	waa.console = console;
    294 	waa.scrdata = &cfb_screenlist;
    295 	waa.accessops = &cfb_accessops;
    296 	waa.accesscookie = sc;
    297 
    298 	config_found(self, &waa, wsemuldisplaydevprint);
    299 }
    300 
    301 static void
    302 cfb_cmap_init(sc)
    303 	struct cfb_softc *sc;
    304 {
    305 	struct hwcmap256 *cm;
    306 	const u_int8_t *p;
    307 	int index;
    308 
    309 	cm = &sc->sc_cmap;
    310 	p = rasops_cmap;
    311 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    312 		cm->r[index] = p[0];
    313 		cm->g[index] = p[1];
    314 		cm->b[index] = p[2];
    315 	}
    316 }
    317 
    318 static void
    319 cfb_common_init(ri)
    320 	struct rasops_info *ri;
    321 {
    322 	caddr_t base;
    323 	int cookie;
    324 
    325 	base = (caddr_t)ri->ri_hw;
    326 
    327 	/* initialize colormap and cursor hardware */
    328 	cfbhwinit(base);
    329 
    330 	ri->ri_flg = RI_CENTER;
    331 	ri->ri_depth = 8;
    332 	ri->ri_width = 1024;
    333 	ri->ri_height = 864;
    334 	ri->ri_stride = 1024;
    335 	ri->ri_bits = base + CX_FB_OFFSET;
    336 
    337 	/* clear the screen */
    338 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    339 
    340 	wsfont_init();
    341 	/* prefer 12 pixel wide font */
    342 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
    343 	    WSDISPLAY_FONTORDER_L2R);
    344 	if (cookie <= 0)
    345 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
    346 		    WSDISPLAY_FONTORDER_L2R);
    347 	if (cookie <= 0) {
    348 		printf("cfb: font table is empty\n");
    349 		return;
    350 	}
    351 
    352 	if (wsfont_lock(cookie, &ri->ri_font)) {
    353 		printf("cfb: couldn't lock font\n");
    354 		return;
    355 	}
    356 	ri->ri_wsfcookie = cookie;
    357 
    358 	rasops_init(ri, 34, 80);
    359 
    360 	/* XXX shouldn't be global */
    361 	cfb_stdscreen.nrows = ri->ri_rows;
    362 	cfb_stdscreen.ncols = ri->ri_cols;
    363 	cfb_stdscreen.textops = &ri->ri_ops;
    364 	cfb_stdscreen.capabilities = ri->ri_caps;
    365 }
    366 
    367 static int
    368 cfbioctl(v, cmd, data, flag, p)
    369 	void *v;
    370 	u_long cmd;
    371 	caddr_t data;
    372 	int flag;
    373 	struct proc *p;
    374 {
    375 	struct cfb_softc *sc = v;
    376 	struct rasops_info *ri = sc->sc_ri;
    377 	int turnoff, s;
    378 
    379 	switch (cmd) {
    380 	case WSDISPLAYIO_GTYPE:
    381 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
    382 		return (0);
    383 
    384 	case WSDISPLAYIO_GINFO:
    385 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    386 		wsd_fbip->height = ri->ri_height;
    387 		wsd_fbip->width = ri->ri_width;
    388 		wsd_fbip->depth = ri->ri_depth;
    389 		wsd_fbip->cmsize = CMAP_SIZE;
    390 #undef fbt
    391 		return (0);
    392 
    393 	case WSDISPLAYIO_GETCMAP:
    394 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    395 
    396 	case WSDISPLAYIO_PUTCMAP:
    397 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    398 
    399 	case WSDISPLAYIO_SVIDEO:
    400 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    401 		if ((sc->sc_blanked == 0) ^ turnoff) {
    402 			sc->sc_blanked = turnoff;
    403 			/* XXX later XXX */
    404 		}
    405 		return (0);
    406 
    407 	case WSDISPLAYIO_GVIDEO:
    408 		*(u_int *)data = sc->sc_blanked ?
    409 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    410 		return (0);
    411 
    412 	case WSDISPLAYIO_GCURPOS:
    413 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    414 		return (0);
    415 
    416 	case WSDISPLAYIO_SCURPOS:
    417 		s = spltty();
    418 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    419 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    420 		splx(s);
    421 		return (0);
    422 
    423 	case WSDISPLAYIO_GCURMAX:
    424 		((struct wsdisplay_curpos *)data)->x =
    425 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    426 		return (0);
    427 
    428 	case WSDISPLAYIO_GCURSOR:
    429 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    430 
    431 	case WSDISPLAYIO_SCURSOR:
    432 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    433 
    434 	case WSDISPLAYIO_SMODE:
    435 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
    436 			s = spltty();
    437 			cfb_cmap_init(sc);
    438 			sc->sc_curenb = 0;
    439 			sc->sc_blanked = 0;
    440 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
    441 			    WSDISPLAY_CMAP_DOLUT);
    442 			splx(s);
    443 		}
    444 		return (0);
    445 	}
    446 	return EPASSTHROUGH;
    447 }
    448 
    449 paddr_t
    450 cfbmmap(v, offset, prot)
    451 	void *v;
    452 	off_t offset;
    453 	int prot;
    454 {
    455 	struct cfb_softc *sc = v;
    456 
    457 	if (offset >= CX_FB_SIZE || offset < 0)
    458 		return (-1);
    459 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
    460 }
    461 
    462 static int
    463 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    464 	void *v;
    465 	const struct wsscreen_descr *type;
    466 	void **cookiep;
    467 	int *curxp, *curyp;
    468 	long *attrp;
    469 {
    470 	struct cfb_softc *sc = v;
    471 	struct rasops_info *ri = sc->sc_ri;
    472 	long defattr;
    473 
    474 	if (sc->nscreens > 0)
    475 		return (ENOMEM);
    476 
    477 	*cookiep = ri;	 /* one and only for now */
    478 	*curxp = 0;
    479 	*curyp = 0;
    480 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    481 	*attrp = defattr;
    482 	sc->nscreens++;
    483 	return (0);
    484 }
    485 
    486 static void
    487 cfb_free_screen(v, cookie)
    488 	void *v;
    489 	void *cookie;
    490 {
    491 	struct cfb_softc *sc = v;
    492 
    493 	if (sc->sc_ri == &cfb_console_ri)
    494 		panic("cfb_free_screen: console");
    495 
    496 	sc->nscreens--;
    497 }
    498 
    499 static int
    500 cfb_show_screen(v, cookie, waitok, cb, cbarg)
    501 	void *v;
    502 	void *cookie;
    503 	int waitok;
    504 	void (*cb) __P((void *, int, int));
    505 	void *cbarg;
    506 {
    507 
    508 	return (0);
    509 }
    510 
    511 /* EXPORT */ int
    512 cfb_cnattach(addr)
    513 	tc_addr_t addr;
    514 {
    515 	struct rasops_info *ri;
    516 	long defattr;
    517 
    518 	ri = &cfb_console_ri;
    519 	ri->ri_hw = (void *)addr;
    520 	cfb_common_init(ri);
    521 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    522 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
    523 	cfb_consaddr = addr;
    524 	return(0);
    525 }
    526 
    527 static int
    528 cfbintr(arg)
    529 	void *arg;
    530 {
    531 	struct cfb_softc *sc = arg;
    532 	caddr_t base, vdac;
    533 	int v;
    534 
    535 	base = (caddr_t)sc->sc_ri->ri_hw;
    536 	*(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
    537 	if (sc->sc_changed == 0)
    538 		return (1);
    539 
    540 	vdac = base + CX_BT459_OFFSET;
    541 	v = sc->sc_changed;
    542 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    543 		SELECT(vdac, BT459_IREG_CCR);
    544 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
    545 	}
    546 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    547 		int x, y;
    548 
    549 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    550 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    551 
    552 		x += sc->sc_cursor.cc_magic.x;
    553 		y += sc->sc_cursor.cc_magic.y;
    554 
    555 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
    556 		REG(vdac, bt_reg) = x;		tc_wmb();
    557 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
    558 		REG(vdac, bt_reg) = y;		tc_wmb();
    559 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
    560 	}
    561 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    562 		u_int8_t *cp = sc->sc_cursor.cc_color;
    563 
    564 		SELECT(vdac, BT459_IREG_CCOLOR_2);
    565 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
    566 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
    567 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
    568 
    569 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
    570 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
    571 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
    572 	}
    573 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    574 		u_int8_t *ip, *mp, img, msk;
    575 		u_int8_t u;
    576 		int bcnt;
    577 
    578 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    579 		mp = (u_int8_t *)sc->sc_cursor.cc_mask;
    580 
    581 		bcnt = 0;
    582 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
    583 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    584 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    585 			/* pad right half 32 pixel when smaller than 33 */
    586 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    587 				REG(vdac, bt_reg) = 0; tc_wmb();
    588 				REG(vdac, bt_reg) = 0; tc_wmb();
    589 			}
    590 			else {
    591 				img = *ip++;
    592 				msk = *mp++;
    593 				img &= msk;	/* cookie off image */
    594 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    595 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    596 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    597 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    598 			}
    599 			bcnt += 2;
    600 		}
    601 		/* pad unoccupied scan lines */
    602 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    603 			REG(vdac, bt_reg) = 0; tc_wmb();
    604 			REG(vdac, bt_reg) = 0; tc_wmb();
    605 			bcnt += 2;
    606 		}
    607 	}
    608 	if (v & WSDISPLAY_CMAP_DOLUT) {
    609 		struct hwcmap256 *cm = &sc->sc_cmap;
    610 		int index;
    611 
    612 		SELECT(vdac, 0);
    613 		for (index = 0; index < CMAP_SIZE; index++) {
    614 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
    615 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
    616 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
    617 		}
    618 	}
    619 	sc->sc_changed = 0;
    620 	return (1);
    621 }
    622 
    623 static void
    624 cfbhwinit(cfbbase)
    625 	caddr_t cfbbase;
    626 {
    627 	caddr_t vdac = cfbbase + CX_BT459_OFFSET;
    628 	const u_int8_t *p;
    629 	int i;
    630 
    631 	SELECT(vdac, BT459_IREG_COMMAND_0);
    632 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    633 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    634 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    635 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    636 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    637 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    638 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    639 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    640 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    641 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    642 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    643 
    644 	SELECT(vdac, BT459_IREG_CCR);
    645 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    646 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    647 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    648 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    649 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    650 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    651 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    652 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    653 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    654 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    655 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    656 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    657 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    658 
    659 	/* build sane colormap */
    660 	SELECT(vdac, 0);
    661 	p = rasops_cmap;
    662 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    663 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
    664 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
    665 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
    666 	}
    667 
    668 	/* clear out cursor image */
    669 	SELECT(vdac, BT459_IREG_CRAM_BASE);
    670 	for (i = 0; i < 1024; i++)
    671 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    672 
    673 	/*
    674 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    675 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    676 	 * image color.  CCOLOR_1 will be never used.
    677 	 */
    678 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    679 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    680 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    681 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    682 
    683 	REG(vdac, bt_reg) = 0;	tc_wmb();
    684 	REG(vdac, bt_reg) = 0;	tc_wmb();
    685 	REG(vdac, bt_reg) = 0;	tc_wmb();
    686 
    687 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    688 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    689 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    690 }
    691 
    692 static int
    693 get_cmap(sc, p)
    694 	struct cfb_softc *sc;
    695 	struct wsdisplay_cmap *p;
    696 {
    697 	u_int index = p->index, count = p->count;
    698 	int error;
    699 
    700 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    701 		return (EINVAL);
    702 
    703 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
    704 	if (error)
    705 		return error;
    706 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
    707 	if (error)
    708 		return error;
    709 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
    710 	return error;
    711 }
    712 
    713 static int
    714 set_cmap(sc, p)
    715 	struct cfb_softc *sc;
    716 	struct wsdisplay_cmap *p;
    717 {
    718 	struct hwcmap256 cmap;
    719 	u_int index = p->index, count = p->count;
    720 	int error, s;
    721 
    722 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
    723 		return (EINVAL);
    724 
    725 	error = copyin(p->red, &cmap.r[index], count);
    726 	if (error)
    727 		return error;
    728 	error = copyin(p->green, &cmap.g[index], count);
    729 	if (error)
    730 		return error;
    731 	error = copyin(p->blue, &cmap.b[index], count);
    732 	if (error)
    733 		return error;
    734 	s = spltty();
    735 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
    736 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
    737 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
    738 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    739 	splx(s);
    740 	return (0);
    741 }
    742 
    743 static int
    744 set_cursor(sc, p)
    745 	struct cfb_softc *sc;
    746 	struct wsdisplay_cursor *p;
    747 {
    748 #define	cc (&sc->sc_cursor)
    749 	u_int v, index = 0, count = 0, icount = 0;
    750 	uint8_t r[2], g[2], b[2], image[512], mask[512];
    751 	int error, s;
    752 
    753 	v = p->which;
    754 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    755 		index = p->cmap.index;
    756 		count = p->cmap.count;
    757 		if (index >= 2 || (index + count) > 2)
    758 			return (EINVAL);
    759 		error = copyin(p->cmap.red, &r[index], count);
    760 		if (error)
    761 			return error;
    762 		error = copyin(p->cmap.green, &g[index], count);
    763 		if (error)
    764 			return error;
    765 		error = copyin(p->cmap.blue, &b[index], count);
    766 		if (error)
    767 			return error;
    768 	}
    769 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    770 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    771 			return (EINVAL);
    772 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    773 		error = copyin(p->image, image, icount);
    774 		if (error)
    775 			return error;
    776 		error = copyin(p->mask, mask, icount);
    777 		if (error)
    778 			return error;
    779 	}
    780 
    781 	s = spltty();
    782 	if (v & WSDISPLAY_CURSOR_DOCUR)
    783 		sc->sc_curenb = p->enable;
    784 	if (v & WSDISPLAY_CURSOR_DOPOS)
    785 		set_curpos(sc, &p->pos);
    786 	if (v & WSDISPLAY_CURSOR_DOHOT)
    787 		cc->cc_hot = p->hot;
    788 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    789 		memcpy(&cc->cc_color[index], &r[index], count);
    790 		memcpy(&cc->cc_color[index + 2], &g[index], count);
    791 		memcpy(&cc->cc_color[index + 4], &b[index], count);
    792 	}
    793 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    794 		cc->cc_size = p->size;
    795 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    796 		memcpy(cc->cc_image, image, icount);
    797 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
    798 		memcpy(cc->cc_mask, mask, icount);
    799 	}
    800 	sc->sc_changed |= v;
    801 	splx(s);
    802 
    803 	return (0);
    804 #undef cc
    805 }
    806 
    807 static int
    808 get_cursor(sc, p)
    809 	struct cfb_softc *sc;
    810 	struct wsdisplay_cursor *p;
    811 {
    812 	return (EPASSTHROUGH); /* XXX */
    813 }
    814 
    815 static void
    816 set_curpos(sc, curpos)
    817 	struct cfb_softc *sc;
    818 	struct wsdisplay_curpos *curpos;
    819 {
    820 	struct rasops_info *ri = sc->sc_ri;
    821 	int x = curpos->x, y = curpos->y;
    822 
    823 	if (y < 0)
    824 		y = 0;
    825 	else if (y > ri->ri_height)
    826 		y = ri->ri_height;
    827 	if (x < 0)
    828 		x = 0;
    829 	else if (x > ri->ri_width)
    830 		x = ri->ri_width;
    831 	sc->sc_cursor.cc_pos.x = x;
    832 	sc->sc_cursor.cc_pos.y = y;
    833 }
    834