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