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