Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.22
      1 /* $NetBSD: tfb.c,v 1.22 2000/03/14 06:25:21 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: tfb.c,v 1.22 2000/03/14 06:25:21 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/wscons/wsconsio.h>
     50 #include <dev/wscons/wsdisplayvar.h>
     51 
     52 #include <dev/rasops/rasops.h>
     53 #include <dev/wsfont/wsfont.h>
     54 
     55 #include <dev/tc/tcvar.h>
     56 #include <dev/ic/bt463reg.h>
     57 #include <dev/ic/bt431reg.h>
     58 
     59 #include <uvm/uvm_extern.h>
     60 
     61 #if defined(pmax)
     62 #define	machine_btop(x) mips_btop(x)
     63 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
     64 
     65 /*
     66  * struct bt463reg {
     67  * 	u_int8_t	bt_lo;
     68  * 	unsigned : 24;
     69  * 	u_int8_t	bt_hi;
     70  * 	unsigned : 24;
     71  * 	u_int8_t	bt_reg;
     72  * 	unsigned : 24;
     73  * 	u_int8_t	bt_cmap;
     74  * };
     75  *
     76  * N.B. a pair of Bt431s are located adjascently.
     77  * 	struct bt431twin {
     78  *		struct {
     79  *			u_int8_t u0;	for sprite mask
     80  *			u_int8_t u1;	for sprite image
     81  *			unsigned :16;
     82  *		} bt_lo;
     83  *		...
     84  *
     85  * struct bt431reg {
     86  * 	u_int16_t	bt_lo;
     87  * 	unsigned : 16;
     88  * 	u_int16_t	bt_hi;
     89  * 	unsigned : 16;
     90  * 	u_int16_t	bt_ram;
     91  * 	unsigned : 16;
     92  * 	u_int16_t	bt_ctl;
     93  * };
     94  */
     95 
     96 #define	BYTE(base, index)	*((u_int8_t *)(base) + ((index)<<2))
     97 #define	HALF(base, index)	*((u_int16_t *)(base) + ((index)<<1))
     98 
     99 #endif
    100 
    101 #if defined(__alpha__) || defined(alpha)
    102 #define machine_btop(x) alpha_btop(x)
    103 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
    104 
    105 /*
    106  * struct bt463reg {
    107  * 	u_int32_t	bt_lo;
    108  * 	u_int32_t	bt_hi;
    109  * 	u_int32_t	bt_reg;
    110  * 	u_int32_t	bt_cmap;
    111  * };
    112  *
    113  * struct bt431reg {
    114  * 	u_int32_t	bt_lo;
    115  * 	u_int32_t	bt_hi;
    116  * 	u_int32_t	bt_ram;
    117  * 	u_int32_t	bt_ctl;
    118  * };
    119  */
    120 
    121 #define	BYTE(base, index)	*((u_int32_t *)(base) + (index))
    122 #define	HALF(base, index)	*((u_int32_t *)(base) + (index))
    123 
    124 #endif
    125 
    126 /* Bt463 hardware registers */
    127 #define	bt_lo	0
    128 #define	bt_hi	1
    129 #define	bt_reg	2
    130 #define	bt_cmap	3
    131 
    132 /* Bt431 hardware registers */
    133 #define	bt_ram	2
    134 #define	bt_ctl	3
    135 
    136 #define	SELECT463(vdac, regno) do {			\
    137 	BYTE(vdac, bt_lo) = (regno) & 0x00ff;		\
    138 	BYTE(vdac, bt_hi) = ((regno)& 0xff00) >> 8;	\
    139 	tc_wmb();					\
    140    } while (0)
    141 
    142 #define	TWIN(x)	   ((x) | ((x) << 8))
    143 #define	TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
    144 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
    145 
    146 #define	SELECT431(curs, regno) do {	\
    147 	HALF(curs, bt_lo) = TWIN(regno);\
    148 	HALF(curs, bt_hi) = 0;		\
    149 	tc_wmb();			\
    150    } while (0)
    151 
    152 struct fb_devconfig {
    153 	vaddr_t dc_vaddr;		/* memory space virtual base address */
    154 	paddr_t dc_paddr;		/* memory space physical base address */
    155 	vsize_t dc_size;		/* size of slot memory */
    156 	int	dc_wid;			/* width of frame buffer */
    157 	int	dc_ht;			/* height of frame buffer */
    158 	int	dc_depth;		/* depth, bits per pixel */
    159 	int	dc_rowbytes;		/* bytes in a FB scan line */
    160 	vaddr_t dc_videobase;		/* base of flat frame buffer */
    161 	int	    dc_blanked;		/* currently has video disabled */
    162 
    163 	struct rasops_info rinfo;
    164 };
    165 
    166 struct hwcmap256 {
    167 #define	CMAP_SIZE	256	/* R/G/B entries */
    168 	u_int8_t r[CMAP_SIZE];
    169 	u_int8_t g[CMAP_SIZE];
    170 	u_int8_t b[CMAP_SIZE];
    171 };
    172 
    173 struct hwcursor64 {
    174 	struct wsdisplay_curpos cc_pos;
    175 	struct wsdisplay_curpos cc_hot;
    176 	struct wsdisplay_curpos cc_size;
    177 	struct wsdisplay_curpos cc_magic;
    178 #define	CURSOR_MAX_SIZE	64
    179 	u_int8_t cc_color[6];
    180 	u_int64_t cc_image[64 + 64];
    181 };
    182 
    183 struct tfb_softc {
    184 	struct device sc_dev;
    185 	struct fb_devconfig *sc_dc;	/* device configuration */
    186 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
    187 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
    188 	int sc_curenb;			/* cursor sprite enabled */
    189 	int sc_changed;			/* need update of colormap */
    190 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
    191 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
    192 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
    193 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
    194 #define	DATA_ALL_CHANGED	0x0f
    195 	int nscreens;
    196 };
    197 
    198 #define	TX_MAGIC_X	360
    199 #define	TX_MAGIC_Y	36
    200 
    201 #define	TX_BT463_OFFSET	0x040000
    202 #define	TX_BT431_OFFSET	0x040010
    203 #define	TX_CONTROL	0x040030
    204 #define	TX_MAP_REGISTER	0x040030
    205 #define	TX_PIP_OFFSET	0x0800c0
    206 #define	TX_SELECTION	0x100000
    207 #define	TX_8BPP_OFFSET	0x200000
    208 #define	TX_8BPP_SIZE	0x200000
    209 #define	TX_24BPP_OFFSET	0x400000
    210 #define	TX_24BPP_SIZE	0x600000
    211 #define	TX_VIDEO_ENABLE	0xa00000
    212 
    213 #define	TX_CTL_VIDEO_ON	0x80
    214 #define	TX_CTL_INT_ENA	0x40
    215 #define	TX_CTL_INT_PEND	0x20
    216 #define	TX_CTL_SEG_ENA	0x10
    217 #define	TX_CTL_SEG	0x0f
    218 
    219 static int  tfbmatch __P((struct device *, struct cfdata *, void *));
    220 static void tfbattach __P((struct device *, struct device *, void *));
    221 
    222 const struct cfattach tfb_ca = {
    223 	sizeof(struct tfb_softc), tfbmatch, tfbattach,
    224 };
    225 
    226 static void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
    227 static struct fb_devconfig tfb_console_dc;
    228 static tc_addr_t tfb_consaddr;
    229 
    230 static struct wsscreen_descr tfb_stdscreen = {
    231 	"std", 0, 0,
    232 	0, /* textops */
    233 	0, 0,
    234 	WSSCREEN_REVERSE
    235 };
    236 
    237 static const struct wsscreen_descr *_tfb_scrlist[] = {
    238 	&tfb_stdscreen,
    239 };
    240 
    241 static const struct wsscreen_list tfb_screenlist = {
    242 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
    243 };
    244 
    245 static int  tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
    246 static int  tfbmmap __P((void *, off_t, int));
    247 
    248 static int  tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
    249 				      void **, int *, int *, long *));
    250 static void tfb_free_screen __P((void *, void *));
    251 static int tfb_show_screen __P((void *, void *, int,
    252 				void (*) (void *, int, int), void *));
    253 
    254 static const struct wsdisplay_accessops tfb_accessops = {
    255 	tfbioctl,
    256 	tfbmmap,
    257 	tfb_alloc_screen,
    258 	tfb_free_screen,
    259 	tfb_show_screen,
    260 	0 /* load_font */
    261 };
    262 
    263 int  tfb_cnattach __P((tc_addr_t));
    264 static int  tfbintr __P((void *));
    265 static void tfbinit __P((struct fb_devconfig *));
    266 
    267 static int  get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    268 static int  set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
    269 static int  set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    270 static int  get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
    271 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
    272 static void bt431_set_curpos __P((struct tfb_softc *));
    273 
    274 /* bit order reverse */
    275 static const u_int8_t flip[256] = {
    276 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    277 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    278 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    279 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    280 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    281 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    282 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    283 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    284 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    285 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    286 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    287 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    288 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    289 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    290 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    291 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    292 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    293 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    294 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    295 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    296 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    297 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    298 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    299 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    300 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    301 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    302 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    303 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    304 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    305 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    306 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    307 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    308 };
    309 
    310 static int
    311 tfbmatch(parent, match, aux)
    312 	struct device *parent;
    313 	struct cfdata *match;
    314 	void *aux;
    315 {
    316 	struct tc_attach_args *ta = aux;
    317 
    318 	if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
    319 	    && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
    320 		return (0);
    321 
    322 	return (1);
    323 }
    324 
    325 static void
    326 tfb_getdevconfig(dense_addr, dc)
    327 	tc_addr_t dense_addr;
    328 	struct fb_devconfig *dc;
    329 {
    330 	int i, cookie;
    331 
    332 	dc->dc_vaddr = dense_addr;
    333 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
    334 
    335 	dc->dc_wid = 1280;
    336 	dc->dc_ht = 1024;
    337 	dc->dc_depth = 8;
    338 	dc->dc_rowbytes = 1280;
    339 	dc->dc_videobase = dc->dc_vaddr + TX_8BPP_OFFSET;
    340 	dc->dc_blanked = 0;
    341 
    342 	/* initialize colormap and cursor resource */
    343 	tfbinit(dc);
    344 
    345 	/* clear the screen */
    346 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
    347 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
    348 
    349 	dc->rinfo.ri_depth = dc->dc_depth;
    350 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
    351 	dc->rinfo.ri_width = dc->dc_wid;
    352 	dc->rinfo.ri_height = dc->dc_ht;
    353 	dc->rinfo.ri_stride = dc->dc_rowbytes;
    354 	dc->rinfo.ri_hw = NULL;
    355 
    356 	wsfont_init();
    357 	/* prefer 8 pixel wide font */
    358 	if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
    359 		cookie = wsfont_find(NULL, 0, 0, 0);
    360 	if (cookie <= 0) {
    361 		printf("tfb: font table is empty\n");
    362 		return;
    363 	}
    364 
    365 	if (wsfont_lock(cookie, &dc->rinfo.ri_font,
    366 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
    367 		printf("tfb: couldn't lock font\n");
    368 		return;
    369 	}
    370 	dc->rinfo.ri_wsfcookie = cookie;
    371 
    372 	rasops_init(&dc->rinfo, 34, 80);
    373 
    374 	/* XXX shouldn't be global */
    375 	tfb_stdscreen.nrows = dc->rinfo.ri_rows;
    376 	tfb_stdscreen.ncols = dc->rinfo.ri_cols;
    377 	tfb_stdscreen.textops = &dc->rinfo.ri_ops;
    378 	tfb_stdscreen.capabilities = dc->rinfo.ri_caps;
    379 }
    380 
    381 static void
    382 tfbattach(parent, self, aux)
    383 	struct device *parent, *self;
    384 	void *aux;
    385 {
    386 	struct tfb_softc *sc = (struct tfb_softc *)self;
    387 	struct tc_attach_args *ta = aux;
    388 	struct wsemuldisplaydev_attach_args waa;
    389 	struct hwcmap256 *cm;
    390 	int console;
    391 
    392 	console = (ta->ta_addr == tfb_consaddr);
    393 	if (console) {
    394 		sc->sc_dc = &tfb_console_dc;
    395 		sc->nscreens = 1;
    396 	}
    397 	else {
    398 		sc->sc_dc = (struct fb_devconfig *)
    399 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    400 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    401 	}
    402 	printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
    403 
    404 	cm = &sc->sc_cmap;
    405 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
    406 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
    407 
    408 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    409 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    410 
    411 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
    412 
    413 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    414 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    415 
    416 	waa.console = console;
    417 	waa.scrdata = &tfb_screenlist;
    418 	waa.accessops = &tfb_accessops;
    419 	waa.accesscookie = sc;
    420 
    421 	config_found(self, &waa, wsemuldisplaydevprint);
    422 }
    423 
    424 static int
    425 tfbioctl(v, cmd, data, flag, p)
    426 	void *v;
    427 	u_long cmd;
    428 	caddr_t data;
    429 	int flag;
    430 	struct proc *p;
    431 {
    432 	struct tfb_softc *sc = v;
    433 	struct fb_devconfig *dc = sc->sc_dc;
    434 	int turnoff;
    435 
    436 	switch (cmd) {
    437 	case WSDISPLAYIO_GTYPE:
    438 		*(u_int *)data = WSDISPLAY_TYPE_TX;
    439 		return (0);
    440 
    441 	case WSDISPLAYIO_GINFO:
    442 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    443 		wsd_fbip->height = sc->sc_dc->dc_ht;
    444 		wsd_fbip->width = sc->sc_dc->dc_wid;
    445 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    446 		wsd_fbip->cmsize = CMAP_SIZE;
    447 #undef fbt
    448 		return (0);
    449 
    450 	case WSDISPLAYIO_GETCMAP:
    451 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    452 
    453 	case WSDISPLAYIO_PUTCMAP:
    454 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    455 
    456 	case WSDISPLAYIO_SVIDEO:
    457 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    458 		if ((dc->dc_blanked == 0) ^ turnoff) {
    459 			dc->dc_blanked = turnoff;
    460 #if 0	/* XXX later XXX */
    461 	To turn off;
    462 	- clear the MSB of TX control register; &= ~0x80,
    463 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
    464 #endif	/* XXX XXX XXX */
    465 		}
    466 		return (0);
    467 
    468 	case WSDISPLAYIO_GVIDEO:
    469 		*(u_int *)data = dc->dc_blanked ?
    470 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    471 		return (0);
    472 
    473 	case WSDISPLAYIO_GCURPOS:
    474 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    475 		return (0);
    476 
    477 	case WSDISPLAYIO_SCURPOS:
    478 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    479 		bt431_set_curpos(sc);
    480 		return (0);
    481 
    482 	case WSDISPLAYIO_GCURMAX:
    483 		((struct wsdisplay_curpos *)data)->x =
    484 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    485 		return (0);
    486 
    487 	case WSDISPLAYIO_GCURSOR:
    488 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    489 
    490 	case WSDISPLAYIO_SCURSOR:
    491 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    492 	}
    493 	return (ENOTTY);
    494 }
    495 
    496 static int
    497 tfbmmap(v, offset, prot)
    498 	void *v;
    499 	off_t offset;
    500 	int prot;
    501 {
    502 	struct tfb_softc *sc = v;
    503 
    504 	if (offset >= TX_8BPP_SIZE || offset < 0)
    505 		return (-1);
    506 	return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset);
    507 }
    508 
    509 static int
    510 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    511 	void *v;
    512 	const struct wsscreen_descr *type;
    513 	void **cookiep;
    514 	int *curxp, *curyp;
    515 	long *attrp;
    516 {
    517 	struct tfb_softc *sc = v;
    518 	long defattr;
    519 
    520 	if (sc->nscreens > 0)
    521 		return (ENOMEM);
    522 
    523 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
    524 	*curxp = 0;
    525 	*curyp = 0;
    526 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    527 	*attrp = defattr;
    528 	sc->nscreens++;
    529 	return (0);
    530 }
    531 
    532 static void
    533 tfb_free_screen(v, cookie)
    534 	void *v;
    535 	void *cookie;
    536 {
    537 	struct tfb_softc *sc = v;
    538 
    539 	if (sc->sc_dc == &tfb_console_dc)
    540 		panic("tfb_free_screen: console");
    541 
    542 	sc->nscreens--;
    543 }
    544 
    545 static int
    546 tfb_show_screen(v, cookie, waitok, cb, cbarg)
    547 	void *v;
    548 	void *cookie;
    549 	int waitok;
    550 	void (*cb) __P((void *, int, int));
    551 	void *cbarg;
    552 {
    553 
    554 	return (0);
    555 }
    556 
    557 /* EXPORT */ int
    558 tfb_cnattach(addr)
    559 	tc_addr_t addr;
    560 {
    561 	struct fb_devconfig *dcp = &tfb_console_dc;
    562 	long defattr;
    563 
    564 	tfb_getdevconfig(addr, dcp);
    565 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    566 	wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    567 	tfb_consaddr = addr;
    568 	return (0);
    569 }
    570 
    571 static int
    572 tfbintr(arg)
    573 	void *arg;
    574 {
    575 	struct tfb_softc *sc = arg;
    576 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    577 	void *vdac, *curs;
    578 	int v;
    579 
    580 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    581 	if (sc->sc_changed == 0)
    582 		goto done;
    583 
    584 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    585 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    586 	v = sc->sc_changed;
    587 	sc->sc_changed = 0;
    588 	if (v & DATA_ENB_CHANGED) {
    589 		SELECT431(curs, BT431_REG_COMMAND);
    590 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
    591 	}
    592 	if (v & DATA_CURCMAP_CHANGED) {
    593 		u_int8_t *cp = sc->sc_cursor.cc_color;
    594 
    595 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
    596 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    597 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    598 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    599 
    600 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    601 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    602 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    603 
    604 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    605 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    606 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    607 
    608 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    609 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    610 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    611 	}
    612 	if (v & DATA_CURSHAPE_CHANGED) {
    613 		u_int8_t *ip, *mp, img, msk;
    614 		int bcnt;
    615 
    616 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    617 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    618 		bcnt = 0;
    619 		SELECT431(curs, BT431_REG_CRAM_BASE);
    620 
    621 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    622 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    623 			/* pad right half 32 pixel when smaller than 33 */
    624 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    625 				HALF(curs, bt_ram) = 0;
    626 				tc_wmb();
    627 			}
    628 			else {
    629 				img = *ip++;
    630 				msk = *mp++;
    631 				img &= msk;	/* cookie off image */
    632 				HALF(curs, bt_ram)
    633 				    = (flip[img] << 8) | flip[msk];
    634 				tc_wmb();
    635 			}
    636 			bcnt += 2;
    637 		}
    638 		/* pad unoccupied scan lines */
    639 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    640 			HALF(curs, bt_ram) = 0;
    641 			tc_wmb();
    642 			bcnt += 2;
    643 		}
    644 	}
    645 	if (v & DATA_CMAP_CHANGED) {
    646 		struct hwcmap256 *cm = &sc->sc_cmap;
    647 		int index;
    648 
    649 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    650 		for (index = 0; index < CMAP_SIZE; index++) {
    651 			BYTE(vdac, bt_cmap) = cm->r[index];
    652 			BYTE(vdac, bt_cmap) = cm->g[index];
    653 			BYTE(vdac, bt_cmap) = cm->b[index];
    654 		}
    655 	}
    656 done:
    657 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
    658 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    659 	return (1);
    660 }
    661 
    662 static void
    663 tfbinit(dc)
    664 	struct fb_devconfig *dc;
    665 {
    666 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    667 	void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    668 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    669 	int i;
    670 
    671 	SELECT463(vdac, BT463_IREG_COMMAND_0);
    672 	BYTE(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
    673 	BYTE(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
    674 	BYTE(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
    675 	BYTE(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
    676 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
    677 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
    678 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
    679 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
    680 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
    681 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
    682 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
    683 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
    684 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();
    685 
    686 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    687   {
    688 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    689 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    690 	};
    691 
    692 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    693 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    694 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    695 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    696 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    697 	}
    698   }
    699 #endif
    700 
    701 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    702 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    703 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    704 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
    705 	for (i = 1; i < 256; i++) {
    706 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    707 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    708 		BYTE(vdac, bt_cmap) = 0xff;	tc_wmb();
    709 	}
    710 
    711 	/* !? Eeeh !? */
    712 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    713 	for (i = 0; i < 256; i++) {
    714 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    715 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    716 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    717 	}
    718 
    719 	SELECT431(curs, BT431_REG_COMMAND);
    720 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
    721 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
    722 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
    723 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
    724 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
    725 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
    726 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
    727 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    728 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    729 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
    730 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
    731 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
    732 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
    733 
    734 	SELECT431(curs, BT431_REG_CRAM_BASE);
    735 	for (i = 0; i < 512; i++) {
    736 		HALF(curs, bt_ram) = 0;	tc_wmb();
    737 	}
    738 }
    739 
    740 static int
    741 get_cmap(sc, p)
    742 	struct tfb_softc *sc;
    743 	struct wsdisplay_cmap *p;
    744 {
    745 	u_int index = p->index, count = p->count;
    746 
    747 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    748 		return (EINVAL);
    749 
    750 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    751 	    !uvm_useracc(p->green, count, B_WRITE) ||
    752 	    !uvm_useracc(p->blue, count, B_WRITE))
    753 		return (EFAULT);
    754 
    755 	copyout(&sc->sc_cmap.r[index], p->red, count);
    756 	copyout(&sc->sc_cmap.g[index], p->green, count);
    757 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    758 
    759 	return (0);
    760 }
    761 
    762 static int
    763 set_cmap(sc, p)
    764 	struct tfb_softc *sc;
    765 	struct wsdisplay_cmap *p;
    766 {
    767 	u_int index = p->index, count = p->count;
    768 
    769 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    770 		return (EINVAL);
    771 
    772 	if (!uvm_useracc(p->red, count, B_READ) ||
    773 	    !uvm_useracc(p->green, count, B_READ) ||
    774 	    !uvm_useracc(p->blue, count, B_READ))
    775 		return (EFAULT);
    776 
    777 	copyin(p->red, &sc->sc_cmap.r[index], count);
    778 	copyin(p->green, &sc->sc_cmap.g[index], count);
    779 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    780 
    781 	sc->sc_changed |= DATA_CMAP_CHANGED;
    782 
    783 	return (0);
    784 }
    785 
    786 static int
    787 set_cursor(sc, p)
    788 	struct tfb_softc *sc;
    789 	struct wsdisplay_cursor *p;
    790 {
    791 #define	cc (&sc->sc_cursor)
    792 	int v, index, count, icount;
    793 
    794 	v = p->which;
    795 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    796 		index = p->cmap.index;
    797 		count = p->cmap.count;
    798 		if (index >= 2 || (index + count) > 2)
    799 			return (EINVAL);
    800 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    801 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    802 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    803 			return (EFAULT);
    804 	}
    805 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    806 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    807 			return (EINVAL);
    808 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    809 		if (!uvm_useracc(p->image, icount, B_READ) ||
    810 		    !uvm_useracc(p->mask, icount, B_READ))
    811 			return (EFAULT);
    812 	}
    813 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    814 		if (v & WSDISPLAY_CURSOR_DOCUR)
    815 			cc->cc_hot = p->hot;
    816 		if (v & WSDISPLAY_CURSOR_DOPOS)
    817 			set_curpos(sc, &p->pos);
    818 		bt431_set_curpos(sc);
    819 	}
    820 
    821 	sc->sc_changed = 0;
    822 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    823 		sc->sc_curenb = p->enable;
    824 		sc->sc_changed |= DATA_ENB_CHANGED;
    825 	}
    826 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    827 		copyin(p->cmap.red, &cc->cc_color[index], count);
    828 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    829 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    830 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    831 	}
    832 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    833 		cc->cc_size = p->size;
    834 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    835 		copyin(p->image, cc->cc_image, icount);
    836 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    837 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    838 	}
    839 
    840 	return (0);
    841 #undef cc
    842 }
    843 
    844 static int
    845 get_cursor(sc, p)
    846 	struct tfb_softc *sc;
    847 	struct wsdisplay_cursor *p;
    848 {
    849 	return (ENOTTY); /* XXX */
    850 }
    851 
    852 static void
    853 set_curpos(sc, curpos)
    854 	struct tfb_softc *sc;
    855 	struct wsdisplay_curpos *curpos;
    856 {
    857 	struct fb_devconfig *dc = sc->sc_dc;
    858 	int x = curpos->x, y = curpos->y;
    859 
    860 	if (y < 0)
    861 		y = 0;
    862 	else if (y > dc->dc_ht)
    863 		y = dc->dc_ht;
    864 	if (x < 0)
    865 		x = 0;
    866 	else if (x > dc->dc_wid)
    867 		x = dc->dc_wid;
    868 	sc->sc_cursor.cc_pos.x = x;
    869 	sc->sc_cursor.cc_pos.y = y;
    870 }
    871 
    872 static void
    873 bt431_set_curpos(sc)
    874 	struct tfb_softc *sc;
    875 {
    876 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    877 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    878 	u_int16_t twin;
    879 	int x, y, s;
    880 
    881 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    882 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    883 
    884 	x += sc->sc_cursor.cc_magic.x;
    885 	y += sc->sc_cursor.cc_magic.y;
    886 
    887 	s = spltty();
    888 
    889 	SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    890 	HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
    891 	HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
    892 	HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
    893 	HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
    894 
    895 	splx(s);
    896 }
    897