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