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