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