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