Home | History | Annotate | Line # | Download | only in tc
cfb.c revision 1.30
      1 /* $NetBSD: cfb.c,v 1.30 2001/11/13 06:26:09 lukem 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.30 2001/11/13 06:26:09 lukem 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 const struct cfattach cfb_ca = {
    143 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
    144 };
    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 
    187 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    188 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
    189 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    190 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
    191 static void set_curpos __P((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(parent, match, aux)
    237 	struct device *parent;
    238 	struct cfdata *match;
    239 	void *aux;
    240 {
    241 	struct tc_attach_args *ta = aux;
    242 
    243 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    244 		return (0);
    245 
    246 	return (1);
    247 }
    248 
    249 static void
    250 cfbattach(parent, self, aux)
    251 	struct device *parent, *self;
    252 	void *aux;
    253 {
    254 	struct cfb_softc *sc = (struct cfb_softc *)self;
    255 	struct tc_attach_args *ta = aux;
    256 	struct rasops_info *ri;
    257 	struct wsemuldisplaydev_attach_args waa;
    258 	struct hwcmap256 *cm;
    259 	const u_int8_t *p;
    260 	int console, index;
    261 
    262 	console = (ta->ta_addr == cfb_consaddr);
    263 	if (console) {
    264 		sc->sc_ri = ri = &cfb_console_ri;
    265 		sc->nscreens = 1;
    266 	}
    267 	else {
    268 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
    269 			M_DEVBUF, M_NOWAIT);
    270 		if (ri == NULL) {
    271 			printf(": can't alloc memory\n");
    272 			return;
    273 		}
    274 		memset(ri, 0, sizeof(struct rasops_info));
    275 
    276 		ri->ri_hw = (void *)ta->ta_addr;
    277 		cfb_common_init(ri);
    278 		sc->sc_ri = ri;
    279 	}
    280 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
    281 
    282 	cm = &sc->sc_cmap;
    283 	p = rasops_cmap;
    284 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
    285 		cm->r[index] = p[0];
    286 		cm->g[index] = p[1];
    287 		cm->b[index] = p[2];
    288 	}
    289 
    290 	sc->sc_vaddr = ta->ta_addr;
    291 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
    292 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
    293 	sc->sc_blanked = sc->sc_curenb = 0;
    294 
    295 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
    296 
    297 	/* clear any pending interrupts */
    298 	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
    299 
    300 	waa.console = console;
    301 	waa.scrdata = &cfb_screenlist;
    302 	waa.accessops = &cfb_accessops;
    303 	waa.accesscookie = sc;
    304 
    305 	config_found(self, &waa, wsemuldisplaydevprint);
    306 }
    307 
    308 static void
    309 cfb_common_init(ri)
    310 	struct rasops_info *ri;
    311 {
    312 	caddr_t base;
    313 	int cookie;
    314 
    315 	base = (caddr_t)ri->ri_hw;
    316 
    317 	/* initialize colormap and cursor hardware */
    318 	cfbhwinit(base);
    319 
    320 	ri->ri_flg = RI_CENTER;
    321 	ri->ri_depth = 8;
    322 	ri->ri_width = 1024;
    323 	ri->ri_height = 864;
    324 	ri->ri_stride = 1024;
    325 	ri->ri_bits = base + CX_FB_OFFSET;
    326 
    327 	/* clear the screen */
    328 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
    329 
    330 	wsfont_init();
    331 	/* prefer 12 pixel wide font */
    332 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
    333 		cookie = wsfont_find(NULL, 0, 0, 0);
    334 	if (cookie <= 0) {
    335 		printf("cfb: font table is empty\n");
    336 		return;
    337 	}
    338 
    339 	if (wsfont_lock(cookie, &ri->ri_font,
    340 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
    341 		printf("cfb: couldn't lock font\n");
    342 		return;
    343 	}
    344 	ri->ri_wsfcookie = cookie;
    345 
    346 	rasops_init(ri, 34, 80);
    347 
    348 	/* XXX shouldn't be global */
    349 	cfb_stdscreen.nrows = ri->ri_rows;
    350 	cfb_stdscreen.ncols = ri->ri_cols;
    351 	cfb_stdscreen.textops = &ri->ri_ops;
    352 	cfb_stdscreen.capabilities = ri->ri_caps;
    353 }
    354 
    355 static int
    356 cfbioctl(v, cmd, data, flag, p)
    357 	void *v;
    358 	u_long cmd;
    359 	caddr_t data;
    360 	int flag;
    361 	struct proc *p;
    362 {
    363 	struct cfb_softc *sc = v;
    364 	struct rasops_info *ri = sc->sc_ri;
    365 	int turnoff;
    366 
    367 	switch (cmd) {
    368 	case WSDISPLAYIO_GTYPE:
    369 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
    370 		return (0);
    371 
    372 	case WSDISPLAYIO_GINFO:
    373 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    374 		wsd_fbip->height = ri->ri_height;
    375 		wsd_fbip->width = ri->ri_width;
    376 		wsd_fbip->depth = ri->ri_depth;
    377 		wsd_fbip->cmsize = CMAP_SIZE;
    378 #undef fbt
    379 		return (0);
    380 
    381 	case WSDISPLAYIO_GETCMAP:
    382 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    383 
    384 	case WSDISPLAYIO_PUTCMAP:
    385 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    386 
    387 	case WSDISPLAYIO_SVIDEO:
    388 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    389 		if ((sc->sc_blanked == 0) ^ turnoff) {
    390 			sc->sc_blanked = turnoff;
    391 			/* XXX later XXX */
    392 		}
    393 		return (0);
    394 
    395 	case WSDISPLAYIO_GVIDEO:
    396 		*(u_int *)data = sc->sc_blanked ?
    397 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    398 		return (0);
    399 
    400 	case WSDISPLAYIO_GCURPOS:
    401 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    402 		return (0);
    403 
    404 	case WSDISPLAYIO_SCURPOS:
    405 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    406 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
    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 	return ENOTTY;
    421 }
    422 
    423 paddr_t
    424 cfbmmap(v, offset, prot)
    425 	void *v;
    426 	off_t offset;
    427 	int prot;
    428 {
    429 	struct cfb_softc *sc = v;
    430 
    431 	if (offset >= CX_FB_SIZE || offset < 0)
    432 		return (-1);
    433 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
    434 }
    435 
    436 static int
    437 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    438 	void *v;
    439 	const struct wsscreen_descr *type;
    440 	void **cookiep;
    441 	int *curxp, *curyp;
    442 	long *attrp;
    443 {
    444 	struct cfb_softc *sc = v;
    445 	struct rasops_info *ri = sc->sc_ri;
    446 	long defattr;
    447 
    448 	if (sc->nscreens > 0)
    449 		return (ENOMEM);
    450 
    451 	*cookiep = ri;	 /* one and only for now */
    452 	*curxp = 0;
    453 	*curyp = 0;
    454 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
    455 	*attrp = defattr;
    456 	sc->nscreens++;
    457 	return (0);
    458 }
    459 
    460 static void
    461 cfb_free_screen(v, cookie)
    462 	void *v;
    463 	void *cookie;
    464 {
    465 	struct cfb_softc *sc = v;
    466 
    467 	if (sc->sc_ri == &cfb_console_ri)
    468 		panic("cfb_free_screen: console");
    469 
    470 	sc->nscreens--;
    471 }
    472 
    473 static int
    474 cfb_show_screen(v, cookie, waitok, cb, cbarg)
    475 	void *v;
    476 	void *cookie;
    477 	int waitok;
    478 	void (*cb) __P((void *, int, int));
    479 	void *cbarg;
    480 {
    481 
    482 	return (0);
    483 }
    484 
    485 /* EXPORT */ int
    486 cfb_cnattach(addr)
    487 	tc_addr_t addr;
    488 {
    489 	struct rasops_info *ri;
    490 	long defattr;
    491 
    492 	ri = &cfb_console_ri;
    493 	ri->ri_hw = (void *)addr;
    494 	cfb_common_init(ri);
    495 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
    496 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
    497 	cfb_consaddr = addr;
    498 	return(0);
    499 }
    500 
    501 static int
    502 cfbintr(arg)
    503 	void *arg;
    504 {
    505 	struct cfb_softc *sc = arg;
    506 	caddr_t base, vdac;
    507 	int v;
    508 
    509 	base = (caddr_t)sc->sc_ri->ri_hw;
    510 	*(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
    511 	if (sc->sc_changed == 0)
    512 		return (1);
    513 
    514 	vdac = base + CX_BT459_OFFSET;
    515 	v = sc->sc_changed;
    516 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    517 		SELECT(vdac, BT459_IREG_CCR);
    518 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
    519 	}
    520 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
    521 		int x, y;
    522 
    523 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    524 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    525 
    526 		x += sc->sc_cursor.cc_magic.x;
    527 		y += sc->sc_cursor.cc_magic.y;
    528 
    529 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
    530 		REG(vdac, bt_reg) = x;		tc_wmb();
    531 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
    532 		REG(vdac, bt_reg) = y;		tc_wmb();
    533 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
    534 	}
    535 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    536 		u_int8_t *cp = sc->sc_cursor.cc_color;
    537 
    538 		SELECT(vdac, BT459_IREG_CCOLOR_2);
    539 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
    540 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
    541 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
    542 
    543 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
    544 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
    545 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
    546 	}
    547 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    548 		u_int8_t *ip, *mp, img, msk;
    549 		u_int8_t u;
    550 		int bcnt;
    551 
    552 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    553 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    554 
    555 		bcnt = 0;
    556 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
    557 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    558 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    559 			/* pad right half 32 pixel when smaller than 33 */
    560 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    561 				REG(vdac, bt_reg) = 0; tc_wmb();
    562 				REG(vdac, bt_reg) = 0; tc_wmb();
    563 			}
    564 			else {
    565 				img = *ip++;
    566 				msk = *mp++;
    567 				img &= msk;	/* cookie off image */
    568 				u = (msk & 0x0f) << 4 | (img & 0x0f);
    569 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    570 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
    571 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
    572 			}
    573 			bcnt += 2;
    574 		}
    575 		/* pad unoccupied scan lines */
    576 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    577 			REG(vdac, bt_reg) = 0; tc_wmb();
    578 			REG(vdac, bt_reg) = 0; tc_wmb();
    579 			bcnt += 2;
    580 		}
    581 	}
    582 	if (v & WSDISPLAY_CMAP_DOLUT) {
    583 		struct hwcmap256 *cm = &sc->sc_cmap;
    584 		int index;
    585 
    586 		SELECT(vdac, 0);
    587 		for (index = 0; index < CMAP_SIZE; index++) {
    588 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
    589 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
    590 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
    591 		}
    592 	}
    593 	sc->sc_changed = 0;
    594 	return (1);
    595 }
    596 
    597 static void
    598 cfbhwinit(cfbbase)
    599 	caddr_t cfbbase;
    600 {
    601 	caddr_t vdac = cfbbase + CX_BT459_OFFSET;
    602 	const u_int8_t *p;
    603 	int i;
    604 
    605 	SELECT(vdac, BT459_IREG_COMMAND_0);
    606 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
    607 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
    608 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
    609 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
    610 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
    611 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
    612 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
    613 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
    614 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
    615 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
    616 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
    617 
    618 	SELECT(vdac, BT459_IREG_CCR);
    619 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
    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 
    633 	/* build sane colormap */
    634 	SELECT(vdac, 0);
    635 	p = rasops_cmap;
    636 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
    637 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
    638 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
    639 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
    640 	}
    641 
    642 	/* clear out cursor image */
    643 	SELECT(vdac, BT459_IREG_CRAM_BASE);
    644 	for (i = 0; i < 1024; i++)
    645 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
    646 
    647 	/*
    648 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
    649 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
    650 	 * image color.  CCOLOR_1 will be never used.
    651 	 */
    652 	SELECT(vdac, BT459_IREG_CCOLOR_1);
    653 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    654 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    655 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    656 
    657 	REG(vdac, bt_reg) = 0;	tc_wmb();
    658 	REG(vdac, bt_reg) = 0;	tc_wmb();
    659 	REG(vdac, bt_reg) = 0;	tc_wmb();
    660 
    661 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    662 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    663 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
    664 }
    665 
    666 static int
    667 get_cmap(sc, p)
    668 	struct cfb_softc *sc;
    669 	struct wsdisplay_cmap *p;
    670 {
    671 	u_int index = p->index, count = p->count;
    672 
    673 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    674 		return (EINVAL);
    675 
    676 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    677 	    !uvm_useracc(p->green, count, B_WRITE) ||
    678 	    !uvm_useracc(p->blue, count, B_WRITE))
    679 		return (EFAULT);
    680 
    681 	copyout(&sc->sc_cmap.r[index], p->red, count);
    682 	copyout(&sc->sc_cmap.g[index], p->green, count);
    683 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    684 
    685 	return (0);
    686 }
    687 
    688 static int
    689 set_cmap(sc, p)
    690 	struct cfb_softc *sc;
    691 	struct wsdisplay_cmap *p;
    692 {
    693 	u_int index = p->index, count = p->count;
    694 
    695 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    696 		return (EINVAL);
    697 
    698 	if (!uvm_useracc(p->red, count, B_READ) ||
    699 	    !uvm_useracc(p->green, count, B_READ) ||
    700 	    !uvm_useracc(p->blue, count, B_READ))
    701 		return (EFAULT);
    702 
    703 	copyin(p->red, &sc->sc_cmap.r[index], count);
    704 	copyin(p->green, &sc->sc_cmap.g[index], count);
    705 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    706 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
    707 	return (0);
    708 }
    709 
    710 static int
    711 set_cursor(sc, p)
    712 	struct cfb_softc *sc;
    713 	struct wsdisplay_cursor *p;
    714 {
    715 #define	cc (&sc->sc_cursor)
    716 	u_int v, index, count, icount;
    717 
    718 	v = p->which;
    719 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    720 		index = p->cmap.index;
    721 		count = p->cmap.count;
    722 		if (index >= 2 || (index + count) > 2)
    723 			return (EINVAL);
    724 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    725 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    726 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    727 			return (EFAULT);
    728 	}
    729 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    730 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    731 			return (EINVAL);
    732 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    733 		if (!uvm_useracc(p->image, icount, B_READ) ||
    734 		    !uvm_useracc(p->mask, icount, B_READ))
    735 			return (EFAULT);
    736 	}
    737 
    738 	if (v & WSDISPLAY_CURSOR_DOCUR)
    739 		sc->sc_curenb = p->enable;
    740 	if (v & WSDISPLAY_CURSOR_DOPOS)
    741 		set_curpos(sc, &p->pos);
    742 	if (v & WSDISPLAY_CURSOR_DOHOT)
    743 		cc->cc_hot = p->hot;
    744 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    745 		copyin(p->cmap.red, &cc->cc_color[index], count);
    746 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    747 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    748 	}
    749 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    750 		cc->cc_size = p->size;
    751 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    752 		copyin(p->image, cc->cc_image, icount);
    753 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    754 	}
    755 	sc->sc_changed |= v;
    756 
    757 	return (0);
    758 #undef cc
    759 }
    760 
    761 static int
    762 get_cursor(sc, p)
    763 	struct cfb_softc *sc;
    764 	struct wsdisplay_cursor *p;
    765 {
    766 	return (ENOTTY); /* XXX */
    767 }
    768 
    769 static void
    770 set_curpos(sc, curpos)
    771 	struct cfb_softc *sc;
    772 	struct wsdisplay_curpos *curpos;
    773 {
    774 	struct rasops_info *ri = sc->sc_ri;
    775 	int x = curpos->x, y = curpos->y;
    776 
    777 	if (y < 0)
    778 		y = 0;
    779 	else if (y > ri->ri_height)
    780 		y = ri->ri_height;
    781 	if (x < 0)
    782 		x = 0;
    783 	else if (x > ri->ri_width)
    784 		x = ri->ri_width;
    785 	sc->sc_cursor.cc_pos.x = x;
    786 	sc->sc_cursor.cc_pos.y = y;
    787 }
    788