Home | History | Annotate | Line # | Download | only in tc
tfb.c revision 1.24.4.1
      1 /* $NetBSD: tfb.c,v 1.24.4.1 2000/06/30 16:27:52 simonb 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.24.4.1 2000/06/30 16:27:52 simonb 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 paddr_t	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_flg = RI_CENTER;
    350 	dc->rinfo.ri_depth = dc->dc_depth;
    351 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
    352 	dc->rinfo.ri_width = dc->dc_wid;
    353 	dc->rinfo.ri_height = dc->dc_ht;
    354 	dc->rinfo.ri_stride = dc->dc_rowbytes;
    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 	int console;
    390 
    391 	console = (ta->ta_addr == tfb_consaddr);
    392 	if (console) {
    393 		sc->sc_dc = &tfb_console_dc;
    394 		sc->nscreens = 1;
    395 	}
    396 	else {
    397 		sc->sc_dc = (struct fb_devconfig *)
    398 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
    399 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
    400 	}
    401 	printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
    402 
    403 	memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
    404 
    405 	sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
    406 	sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
    407 
    408 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
    409 
    410 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
    411 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
    412 
    413 	waa.console = console;
    414 	waa.scrdata = &tfb_screenlist;
    415 	waa.accessops = &tfb_accessops;
    416 	waa.accesscookie = sc;
    417 
    418 	config_found(self, &waa, wsemuldisplaydevprint);
    419 }
    420 
    421 static int
    422 tfbioctl(v, cmd, data, flag, p)
    423 	void *v;
    424 	u_long cmd;
    425 	caddr_t data;
    426 	int flag;
    427 	struct proc *p;
    428 {
    429 	struct tfb_softc *sc = v;
    430 	struct fb_devconfig *dc = sc->sc_dc;
    431 	int turnoff;
    432 
    433 	switch (cmd) {
    434 	case WSDISPLAYIO_GTYPE:
    435 		*(u_int *)data = WSDISPLAY_TYPE_TX;
    436 		return (0);
    437 
    438 	case WSDISPLAYIO_GINFO:
    439 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
    440 		wsd_fbip->height = sc->sc_dc->dc_ht;
    441 		wsd_fbip->width = sc->sc_dc->dc_wid;
    442 		wsd_fbip->depth = sc->sc_dc->dc_depth;
    443 		wsd_fbip->cmsize = CMAP_SIZE;
    444 #undef fbt
    445 		return (0);
    446 
    447 	case WSDISPLAYIO_GETCMAP:
    448 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
    449 
    450 	case WSDISPLAYIO_PUTCMAP:
    451 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
    452 
    453 	case WSDISPLAYIO_SVIDEO:
    454 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
    455 		if ((dc->dc_blanked == 0) ^ turnoff) {
    456 			dc->dc_blanked = turnoff;
    457 #if 0	/* XXX later XXX */
    458 	To turn off;
    459 	- clear the MSB of TX control register; &= ~0x80,
    460 	- assign Bt431 register #0 with value 0x4 to hide sprite cursor.
    461 #endif	/* XXX XXX XXX */
    462 		}
    463 		return (0);
    464 
    465 	case WSDISPLAYIO_GVIDEO:
    466 		*(u_int *)data = dc->dc_blanked ?
    467 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
    468 		return (0);
    469 
    470 	case WSDISPLAYIO_GCURPOS:
    471 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
    472 		return (0);
    473 
    474 	case WSDISPLAYIO_SCURPOS:
    475 		set_curpos(sc, (struct wsdisplay_curpos *)data);
    476 		bt431_set_curpos(sc);
    477 		return (0);
    478 
    479 	case WSDISPLAYIO_GCURMAX:
    480 		((struct wsdisplay_curpos *)data)->x =
    481 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
    482 		return (0);
    483 
    484 	case WSDISPLAYIO_GCURSOR:
    485 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
    486 
    487 	case WSDISPLAYIO_SCURSOR:
    488 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
    489 	}
    490 	return (ENOTTY);
    491 }
    492 
    493 static paddr_t
    494 tfbmmap(v, offset, prot)
    495 	void *v;
    496 	off_t offset;
    497 	int prot;
    498 {
    499 	struct tfb_softc *sc = v;
    500 
    501 	if (offset >= TX_8BPP_SIZE || offset < 0)
    502 		return (-1);
    503 	return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset);
    504 }
    505 
    506 static int
    507 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
    508 	void *v;
    509 	const struct wsscreen_descr *type;
    510 	void **cookiep;
    511 	int *curxp, *curyp;
    512 	long *attrp;
    513 {
    514 	struct tfb_softc *sc = v;
    515 	long defattr;
    516 
    517 	if (sc->nscreens > 0)
    518 		return (ENOMEM);
    519 
    520 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
    521 	*curxp = 0;
    522 	*curyp = 0;
    523 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
    524 	*attrp = defattr;
    525 	sc->nscreens++;
    526 	return (0);
    527 }
    528 
    529 static void
    530 tfb_free_screen(v, cookie)
    531 	void *v;
    532 	void *cookie;
    533 {
    534 	struct tfb_softc *sc = v;
    535 
    536 	if (sc->sc_dc == &tfb_console_dc)
    537 		panic("tfb_free_screen: console");
    538 
    539 	sc->nscreens--;
    540 }
    541 
    542 static int
    543 tfb_show_screen(v, cookie, waitok, cb, cbarg)
    544 	void *v;
    545 	void *cookie;
    546 	int waitok;
    547 	void (*cb) __P((void *, int, int));
    548 	void *cbarg;
    549 {
    550 
    551 	return (0);
    552 }
    553 
    554 /* EXPORT */ int
    555 tfb_cnattach(addr)
    556 	tc_addr_t addr;
    557 {
    558 	struct fb_devconfig *dcp = &tfb_console_dc;
    559 	long defattr;
    560 
    561 	tfb_getdevconfig(addr, dcp);
    562 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
    563 	wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
    564 	tfb_consaddr = addr;
    565 	return (0);
    566 }
    567 
    568 static int
    569 tfbintr(arg)
    570 	void *arg;
    571 {
    572 	struct tfb_softc *sc = arg;
    573 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    574 	void *vdac, *curs;
    575 	int v;
    576 
    577 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
    578 	if (sc->sc_changed == 0)
    579 		goto done;
    580 
    581 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    582 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
    583 	v = sc->sc_changed;
    584 	sc->sc_changed = 0;
    585 	if (v & DATA_ENB_CHANGED) {
    586 		SELECT431(curs, BT431_REG_COMMAND);
    587 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
    588 	}
    589 	if (v & DATA_CURCMAP_CHANGED) {
    590 		u_int8_t *cp = sc->sc_cursor.cc_color;
    591 
    592 		SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
    593 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    594 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    595 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    596 
    597 		BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
    598 		BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
    599 		BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
    600 
    601 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    602 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    603 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    604 
    605 		BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
    606 		BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
    607 		BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
    608 	}
    609 	if (v & DATA_CURSHAPE_CHANGED) {
    610 		u_int8_t *ip, *mp, img, msk;
    611 		int bcnt;
    612 
    613 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
    614 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
    615 		bcnt = 0;
    616 		SELECT431(curs, BT431_REG_CRAM_BASE);
    617 
    618 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
    619 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
    620 			/* pad right half 32 pixel when smaller than 33 */
    621 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
    622 				HALF(curs, bt_ram) = 0;
    623 				tc_wmb();
    624 			}
    625 			else {
    626 				img = *ip++;
    627 				msk = *mp++;
    628 				img &= msk;	/* cookie off image */
    629 				HALF(curs, bt_ram)
    630 				    = (flip[img] << 8) | flip[msk];
    631 				tc_wmb();
    632 			}
    633 			bcnt += 2;
    634 		}
    635 		/* pad unoccupied scan lines */
    636 		while (bcnt < CURSOR_MAX_SIZE * 16) {
    637 			HALF(curs, bt_ram) = 0;
    638 			tc_wmb();
    639 			bcnt += 2;
    640 		}
    641 	}
    642 	if (v & DATA_CMAP_CHANGED) {
    643 		struct hwcmap256 *cm = &sc->sc_cmap;
    644 		int index;
    645 
    646 		SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    647 		for (index = 0; index < CMAP_SIZE; index++) {
    648 			BYTE(vdac, bt_cmap) = cm->r[index];
    649 			BYTE(vdac, bt_cmap) = cm->g[index];
    650 			BYTE(vdac, bt_cmap) = cm->b[index];
    651 		}
    652 	}
    653 done:
    654 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;	/* !? Eeeh !? */
    655 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
    656 	return (1);
    657 }
    658 
    659 static void
    660 tfbinit(dc)
    661 	struct fb_devconfig *dc;
    662 {
    663 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
    664 	void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
    665 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    666 	int i;
    667 
    668 	SELECT463(vdac, BT463_IREG_COMMAND_0);
    669 	BYTE(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
    670 	BYTE(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
    671 	BYTE(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
    672 	BYTE(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
    673 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
    674 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
    675 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
    676 	BYTE(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
    677 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
    678 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
    679 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
    680 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
    681 	BYTE(vdac, bt_reg) = 0x00;	tc_wmb();
    682 
    683 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
    684   {
    685 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
    686 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    687 	};
    688 
    689 	SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
    690 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
    691 		BYTE(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
    692 		BYTE(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
    693 		BYTE(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
    694 	}
    695   }
    696 #endif
    697 
    698 	SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
    699 	for (i = 0; i < 256; i++) {
    700 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
    701 		tc_wmb();
    702 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
    703 		tc_wmb();
    704 		BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
    705 		tc_wmb();
    706 	}
    707 
    708 	/* !? Eeeh !? */
    709 	SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
    710 	for (i = 0; i < 256; i++) {
    711 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    712 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    713 		BYTE(vdac, bt_cmap) = i;	tc_wmb();
    714 	}
    715 
    716 	SELECT431(curs, BT431_REG_COMMAND);
    717 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
    718 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
    719 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
    720 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
    721 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
    722 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
    723 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
    724 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    725 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
    726 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
    727 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
    728 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
    729 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
    730 
    731 	SELECT431(curs, BT431_REG_CRAM_BASE);
    732 	for (i = 0; i < 512; i++) {
    733 		HALF(curs, bt_ram) = 0;	tc_wmb();
    734 	}
    735 }
    736 
    737 static int
    738 get_cmap(sc, p)
    739 	struct tfb_softc *sc;
    740 	struct wsdisplay_cmap *p;
    741 {
    742 	u_int index = p->index, count = p->count;
    743 
    744 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    745 		return (EINVAL);
    746 
    747 	if (!uvm_useracc(p->red, count, B_WRITE) ||
    748 	    !uvm_useracc(p->green, count, B_WRITE) ||
    749 	    !uvm_useracc(p->blue, count, B_WRITE))
    750 		return (EFAULT);
    751 
    752 	copyout(&sc->sc_cmap.r[index], p->red, count);
    753 	copyout(&sc->sc_cmap.g[index], p->green, count);
    754 	copyout(&sc->sc_cmap.b[index], p->blue, count);
    755 
    756 	return (0);
    757 }
    758 
    759 static int
    760 set_cmap(sc, p)
    761 	struct tfb_softc *sc;
    762 	struct wsdisplay_cmap *p;
    763 {
    764 	u_int index = p->index, count = p->count;
    765 
    766 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
    767 		return (EINVAL);
    768 
    769 	if (!uvm_useracc(p->red, count, B_READ) ||
    770 	    !uvm_useracc(p->green, count, B_READ) ||
    771 	    !uvm_useracc(p->blue, count, B_READ))
    772 		return (EFAULT);
    773 
    774 	copyin(p->red, &sc->sc_cmap.r[index], count);
    775 	copyin(p->green, &sc->sc_cmap.g[index], count);
    776 	copyin(p->blue, &sc->sc_cmap.b[index], count);
    777 
    778 	sc->sc_changed |= DATA_CMAP_CHANGED;
    779 
    780 	return (0);
    781 }
    782 
    783 static int
    784 set_cursor(sc, p)
    785 	struct tfb_softc *sc;
    786 	struct wsdisplay_cursor *p;
    787 {
    788 #define	cc (&sc->sc_cursor)
    789 	int v, index, count, icount;
    790 
    791 	v = p->which;
    792 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    793 		index = p->cmap.index;
    794 		count = p->cmap.count;
    795 		if (index >= 2 || (index + count) > 2)
    796 			return (EINVAL);
    797 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
    798 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
    799 		    !uvm_useracc(p->cmap.blue, count, B_READ))
    800 			return (EFAULT);
    801 	}
    802 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    803 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
    804 			return (EINVAL);
    805 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
    806 		if (!uvm_useracc(p->image, icount, B_READ) ||
    807 		    !uvm_useracc(p->mask, icount, B_READ))
    808 			return (EFAULT);
    809 	}
    810 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
    811 		if (v & WSDISPLAY_CURSOR_DOCUR)
    812 			cc->cc_hot = p->hot;
    813 		if (v & WSDISPLAY_CURSOR_DOPOS)
    814 			set_curpos(sc, &p->pos);
    815 		bt431_set_curpos(sc);
    816 	}
    817 
    818 	sc->sc_changed = 0;
    819 	if (v & WSDISPLAY_CURSOR_DOCUR) {
    820 		sc->sc_curenb = p->enable;
    821 		sc->sc_changed |= DATA_ENB_CHANGED;
    822 	}
    823 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
    824 		copyin(p->cmap.red, &cc->cc_color[index], count);
    825 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
    826 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
    827 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
    828 	}
    829 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
    830 		cc->cc_size = p->size;
    831 		memset(cc->cc_image, 0, sizeof cc->cc_image);
    832 		copyin(p->image, cc->cc_image, icount);
    833 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
    834 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
    835 	}
    836 
    837 	return (0);
    838 #undef cc
    839 }
    840 
    841 static int
    842 get_cursor(sc, p)
    843 	struct tfb_softc *sc;
    844 	struct wsdisplay_cursor *p;
    845 {
    846 	return (ENOTTY); /* XXX */
    847 }
    848 
    849 static void
    850 set_curpos(sc, curpos)
    851 	struct tfb_softc *sc;
    852 	struct wsdisplay_curpos *curpos;
    853 {
    854 	struct fb_devconfig *dc = sc->sc_dc;
    855 	int x = curpos->x, y = curpos->y;
    856 
    857 	if (y < 0)
    858 		y = 0;
    859 	else if (y > dc->dc_ht)
    860 		y = dc->dc_ht;
    861 	if (x < 0)
    862 		x = 0;
    863 	else if (x > dc->dc_wid)
    864 		x = dc->dc_wid;
    865 	sc->sc_cursor.cc_pos.x = x;
    866 	sc->sc_cursor.cc_pos.y = y;
    867 }
    868 
    869 static void
    870 bt431_set_curpos(sc)
    871 	struct tfb_softc *sc;
    872 {
    873 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
    874 	void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
    875 	u_int16_t twin;
    876 	int x, y, s;
    877 
    878 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
    879 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
    880 
    881 	x += sc->sc_cursor.cc_magic.x;
    882 	y += sc->sc_cursor.cc_magic.y;
    883 
    884 	s = spltty();
    885 
    886 	SELECT431(curs, BT431_REG_CURSOR_X_LOW);
    887 	HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
    888 	HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
    889 	HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
    890 	HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
    891 
    892 	splx(s);
    893 }
    894