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