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