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