Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.29
      1 /* $NetBSD: cfb.c,v 1.29 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: cfb.c,v 1.29 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/ic/bt459reg.h>
     56 
     57 #include <uvm/uvm_extern.h>
     58 
     59 #if defined(pmax)
     60 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
     61 #endif
     62 
     63 #if defined(alpha)
     64 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
     65 #endif
     66 
     67 /*
     68  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
     69  * obscure register layout such as 2nd and 3rd Bt459 registers are
     70  * adjacent each other in a word, i.e.,
     71  *	struct bt459triplet {
     72  * 		struct {
     73  *			u_int8_t u0;
     74  *			u_int8_t u1;
     75  *			u_int8_t u2;
     76  *			unsigned :8;
     77  *		} bt_lo;
     78  *		...
     79  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
     80  *	struct bt459reg {
     81  *		   u_int32_t	   bt_lo;
     82  *		   u_int32_t	   bt_hi;
     83  *		   u_int32_t	   bt_reg;
     84  *		   u_int32_t	   bt_cmap;
     85  *	};
     86  */
     87 
     88 /* Bt459 hardware registers */
     89 #define	bt_lo	0
     90 #define	bt_hi	1
     91 #define	bt_reg	2
     92 #define	bt_cmap 3
     93 
     94 #define	REG(base, index)	*((u_int32_t *)(base) + (index))
     95 #define	SELECT(vdac, regno) do {			\
     96 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
     97 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
     98 	tc_wmb();					\
     99    } while (0)
    100 
    101 struct hwcmap256 {
    102 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    103 	u_int8_t r[CMAP_SIZE];
    104 	u_int8_t g[CMAP_SIZE];
    105 	u_int8_t b[CMAP_SIZE];
    106 };
    107 
    108 struct hwcursor64 {
    109 	struct wsdisplay_curpos cc_pos;
    110 	struct wsdisplay_curpos cc_hot;
    111 	struct wsdisplay_curpos cc_size;
    112 	struct wsdisplay_curpos cc_magic;
    113 #define	CURSOR_MAX_SIZE	64
    114 	u_int8_t cc_color[6];
    115 	u_int64_t cc_image[64 + 64];
    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 const struct cfattach cfb_ca = {
    144 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
    145 };
    146 
    147 static void cfb_common_init __P((struct rasops_info *));
    148 static struct rasops_info cfb_console_ri;
    149 static tc_addr_t cfb_consaddr;
    150 
    151 static struct wsscreen_descr cfb_stdscreen = {
    152 	"std", 0, 0,
    153 	0, /* textops */
    154 	0, 0,
    155 	WSSCREEN_REVERSE
    156 };
    157 
    158 static const struct wsscreen_descr *_cfb_scrlist[] = {
    159 	&cfb_stdscreen,
    160 };
    161 
    162 static const struct wsscreen_list cfb_screenlist = {
    163 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
    164 };
    165 
    166 static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    167 static paddr_t	cfbmmap __P((void *, off_t, int));
    168 
    169 static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    170 				      void **, int *, int *, long *));
    171 static void	cfb_free_screen __P((void *, void *));
    172 static int	cfb_show_screen __P((void *, void *, int,
    173 				     void (*) (void *, int, int), void *));
    174 
    175 static const struct wsdisplay_accessops cfb_accessops = {
    176 	cfbioctl,
    177 	cfbmmap,
    178 	cfb_alloc_screen,
    179 	cfb_free_screen,
    180 	cfb_show_screen,
    181 	0 /* load_font */
    182 };
    183 
    184 int  cfb_cnattach __P((tc_addr_t));
    185 static int  cfbintr __P((void *));
    186 static void cfbhwinit __P((caddr_t));
    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 	struct hwcmap256 *cm;
    260 	const u_int8_t *p;
    261 	int console, index;
    262 
    263 	console = (ta->ta_addr == cfb_consaddr);
    264 	if (console) {
    265 		sc->sc_ri = ri = &cfb_console_ri;
    266 		sc->nscreens = 1;
    267 	}
    268 	else {
    269 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    270 			M_DEVBUF, M_NOWAIT);
    271 		if (ri == NULL) {
    272 			printf(": can't alloc memory\n");
    273 			return;
    274 		}
    275 		memset(ri, 0, sizeof(struct rasops_info));
    276 
    277 		ri->ri_hw = (void *)ta->ta_addr;
    278 		cfb_common_init(ri);
    279 		sc->sc_ri = ri;
    280 	}
    281 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    282 
    283 	cm = &sc->sc_cmap;
    284 	p = rasops_cmap;
    285 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    286 		cm->r[index] = p[0];
    287 		cm->g[index] = p[1];
    288 		cm->b[index] = p[2];
    289 	}
    290 
    291 	sc->sc_vaddr = ta->ta_addr;
    292 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
    293 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
    294 	sc->sc_blanked = sc->sc_curenb = 0;
    295 
    296 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
    297 
    298 	/* clear any pending interrupts */
    299 	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
    300 
    301 	waa.console = console;
    302 	waa.scrdata = &cfb_screenlist;
    303 	waa.accessops = &cfb_accessops;
    304 	waa.accesscookie = sc;
    305 
    306 	config_found(self, &waa, wsemuldisplaydevprint);
    307 }
    308 
    309 static void
    310 cfb_common_init(ri)
    311 	struct rasops_info *ri;
    312 {
    313 	caddr_t base;
    314 	int cookie;
    315 
    316 	base = (caddr_t)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 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
    334 		cookie = wsfont_find(NULL, 0, 0, 0);
    335 	if (cookie <= 0) {
    336 		printf("cfb: font table is empty\n");
    337 		return;
    338 	}
    339 
    340 	if (wsfont_lock(cookie, &ri->ri_font,
    341 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
    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 ENOTTY;
    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.alloc_attr)(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.alloc_attr)(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 || (index + count) > CMAP_SIZE)
    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 || (index + count) > CMAP_SIZE)
    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 (ENOTTY); /* 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