xref: /netbsd-src/sys/dev/tc/tfb.c (revision 93f9db1b75d415b78f73ed629beeb86235153473)
1 /* $NetBSD: tfb.c,v 1.3 1998/11/09 03:58:06 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.3 1998/11/09 03:58:06 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 /* it's really painful to manipulate 'twined' registers... */
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 #endif
92 
93 #if defined(__alpha__) || defined(alpha)
94 #define machine_btop(x) alpha_btop(x)
95 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
96 
97 struct bt463reg {
98 	u_int32_t	bt_lo;
99 	u_int32_t	bt_hi;
100 	u_int32_t	bt_reg;
101 	u_int32_t	bt_cmap;
102 };
103 
104 /*
105  * N.B. a paif of Bt431s are located adjascently.
106  * 	struct bt431twin {
107  *		struct {
108  *			u_int8_t u0;	for sprite image
109  *			u_int8_t u1;	for sprite mask
110  *			unsigned :16;
111  *		} bt_lo;
112  *		...
113  */
114 struct bt431reg {
115 	u_int32_t	bt_lo;
116 	u_int32_t	bt_hi;
117 	u_int32_t	bt_ram;
118 	u_int32_t	bt_ctl;
119 };
120 #endif
121 
122 /* XXX XXX XXX */
123 
124 struct fb_devconfig {
125 	vaddr_t dc_vaddr;		/* memory space virtual base address */
126 	paddr_t dc_paddr;		/* memory space physical base address */
127 	vsize_t dc_size;		/* size of slot memory */
128 	int	dc_wid;			/* width of frame buffer */
129 	int	dc_ht;			/* height of frame buffer */
130 	int	dc_depth;		/* depth, bits per pixel */
131 	int	dc_rowbytes;		/* bytes in a FB scan line */
132 	vaddr_t dc_videobase;		/* base of flat frame buffer */
133 	struct raster	dc_raster;	/* raster description */
134 	struct rcons	dc_rcons;	/* raster blitter control info */
135 	int	    dc_blanked;		/* currently has video disabled */
136 };
137 
138 struct hwcmap {
139 #define	CMAP_SIZE	256	/* R/G/B entries */
140 	u_int8_t r[CMAP_SIZE];
141 	u_int8_t g[CMAP_SIZE];
142 	u_int8_t b[CMAP_SIZE];
143 };
144 
145 struct hwcursor {
146 	struct wsdisplay_curpos cc_pos;
147 	struct wsdisplay_curpos cc_hot;
148 	struct wsdisplay_curpos cc_size;
149 #define	CURSOR_MAX_SIZE	64
150 	u_int8_t cc_color[6];
151 	u_int64_t cc_image[64 + 64];
152 };
153 
154 struct tfb_softc {
155 	struct device sc_dev;
156 	struct fb_devconfig *sc_dc;	/* device configuration */
157 	struct hwcmap sc_cmap;		/* software copy of colormap */
158 	struct hwcursor sc_cursor;	/* software copy of cursor */
159 	int sc_curenb;			/* cursor sprite enabled */
160 	int sc_changed;			/* need update of colormap */
161 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
162 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
163 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
164 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
165 #define	DATA_ALL_CHANGED	0x0f
166 	int nscreens;
167 	short magic_x, magic_y;		/* TX cursor location offset */
168 #define	TX_MAGIC_X	220
169 #define	TX_MAGIC_Y	35
170 };
171 
172 #define	TX_BT463_OFFSET	0x040000
173 #define	TX_BT431_OFFSET	0x040010
174 #define	TX_CONTROL	0x040030
175 #define	TX_MAP_REGISTER	0x040030
176 #define	TX_PIP_OFFSET	0x0800c0
177 #define	TX_SELECTION	0x100000
178 #define	TX_8FB_OFFSET	0x200000
179 #define	TX_8FB_SIZE	0x100000
180 #define	TX_24FB_OFFSET	0x400000
181 #define	TX_24FB_SIZE	0x400000
182 #define	TX_VIDEO_ENABLE	0xa00000
183 
184 #define TX_CTL_VIDEO_ON	0x80
185 #define TX_CTL_INT_ENA	0x40
186 #define TX_CTL_INT_PEND	0x20
187 #define TX_CTL_SEG_ENA	0x10
188 #define TX_CTL_SEG	0x0f
189 
190 int  tfbmatch __P((struct device *, struct cfdata *, void *));
191 void tfbattach __P((struct device *, struct device *, void *));
192 
193 struct cfattach tfb_ca = {
194 	sizeof(struct tfb_softc), tfbmatch, tfbattach,
195 };
196 
197 void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
198 struct fb_devconfig tfb_console_dc;
199 tc_addr_t tfb_consaddr;
200 
201 struct wsdisplay_emulops tfb_emulops = {
202 	rcons_cursor,			/* could use hardware cursor; punt */
203 	rcons_mapchar,
204 	rcons_putchar,
205 	rcons_copycols,
206 	rcons_erasecols,
207 	rcons_copyrows,
208 	rcons_eraserows,
209 	rcons_alloc_attr
210 };
211 
212 struct wsscreen_descr tfb_stdscreen = {
213 	"std", 0, 0,
214 	&tfb_emulops,
215 	0, 0,
216 	0
217 };
218 
219 const struct wsscreen_descr *_tfb_scrlist[] = {
220 	&tfb_stdscreen,
221 };
222 
223 struct wsscreen_list tfb_screenlist = {
224 	sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
225 };
226 
227 int	tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
228 int	tfbmmap __P((void *, off_t, int));
229 
230 int	tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
231 				      void **, int *, int *, long *));
232 void	tfb_free_screen __P((void *, void *));
233 void	tfb_show_screen __P((void *, void *));
234 int	tfb_load_font __P((void *, void *, int, int, int, void *));
235 
236 struct wsdisplay_accessops tfb_accessops = {
237 	tfbioctl,
238 	tfbmmap,
239 	tfb_alloc_screen,
240 	tfb_free_screen,
241 	tfb_show_screen,
242 	tfb_load_font
243 };
244 
245 int  tfb_cnattach __P((tc_addr_t));
246 int  tfbintr __P((void *));
247 void tfbinit __P((struct fb_devconfig *));
248 
249 static int  get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
250 static int  set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
251 static int  set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
252 static int  get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
253 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
254 static void bt431_set_curpos __P((struct tfb_softc *));
255 
256 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
257 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
258 
259 /* XXX XXX XXX */
260 #define	BT431_SELECT(curs, regno) do {	\
261 	u_int16_t twin;			\
262 	curs->bt_lo = TWIN_LO(regno);	\
263 	curs->bt_hi = TWIN_HI(regno);	\
264 	tc_wmb();			\
265    } while (0)
266 
267 #define	BT463_SELECT(vdac, regno) do {		\
268 	vdac->bt_lo = (regno) & 0x00ff;		\
269 	vdac->bt_hi = ((regno)& 0xff00) >> 8;	\
270 	tc_wmb();				\
271    } while (0)
272 /* XXX XXX XXX */
273 
274 /* bit order reverse */
275 const static 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 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 void
326 tfb_getdevconfig(dense_addr, dc)
327 	tc_addr_t dense_addr;
328 	struct fb_devconfig *dc;
329 {
330 	struct raster *rap;
331 	struct rcons *rcp;
332 	int i;
333 
334 	dc->dc_vaddr = dense_addr;
335 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
336 
337 	dc->dc_wid = 1280;
338 	dc->dc_ht = 1024;
339 	dc->dc_depth = 8;
340 	dc->dc_rowbytes = 1280;
341 	dc->dc_videobase = dc->dc_vaddr + TX_8FB_OFFSET;
342 	dc->dc_blanked = 0;
343 
344 	/* initialize colormap and cursor resource */
345 	tfbinit(dc);
346 
347 	/* clear the screen */
348 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
349 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
350 
351 	/* initialize the raster */
352 	rap = &dc->dc_raster;
353 	rap->width = dc->dc_wid;
354 	rap->height = dc->dc_ht;
355 	rap->depth = dc->dc_depth;
356 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
357 	rap->pixels = (u_int32_t *)dc->dc_videobase;
358 
359 	/* initialize the raster console blitter */
360 	rcp = &dc->dc_rcons;
361 	rcp->rc_sp = rap;
362 	rcp->rc_crow = rcp->rc_ccol = -1;
363 	rcp->rc_crowp = &rcp->rc_crow;
364 	rcp->rc_ccolp = &rcp->rc_ccol;
365 	rcons_init(rcp, 34, 80);
366 
367 	tfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
368 	tfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
369 }
370 
371 void
372 tfbattach(parent, self, aux)
373 	struct device *parent, *self;
374 	void *aux;
375 {
376 	struct tfb_softc *sc = (struct tfb_softc *)self;
377 	struct tc_attach_args *ta = aux;
378 	struct wsemuldisplaydev_attach_args waa;
379 	struct hwcmap *cm;
380 	int console, i;
381 
382 	console = (ta->ta_addr == tfb_consaddr);
383 	if (console) {
384 		sc->sc_dc = &tfb_console_dc;
385 		sc->nscreens = 1;
386 	}
387 	else {
388 		sc->sc_dc = (struct fb_devconfig *)
389 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
390 		tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
391 	}
392 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
393 	    sc->sc_dc->dc_depth);
394 
395 	cm = &sc->sc_cmap;
396 	cm->r[0] = cm->g[0] = cm->b[0] = 0;
397 	for (i = 1; i < CMAP_SIZE; i++) {
398 		cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
399 	}
400 	sc->magic_x = TX_MAGIC_X; sc->magic_y = TX_MAGIC_Y;
401 
402         tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
403 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
404 	*(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
405 
406 	waa.console = console;
407 	waa.scrdata = &tfb_screenlist;
408 	waa.accessops = &tfb_accessops;
409 	waa.accesscookie = sc;
410 
411 	config_found(self, &waa, wsemuldisplaydevprint);
412 }
413 
414 int
415 tfbioctl(v, cmd, data, flag, p)
416 	void *v;
417 	u_long cmd;
418 	caddr_t data;
419 	int flag;
420 	struct proc *p;
421 {
422 	struct tfb_softc *sc = v;
423 	struct fb_devconfig *dc = sc->sc_dc;
424 	int turnoff;
425 
426 	switch (cmd) {
427 	case WSDISPLAYIO_GTYPE:
428 		*(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
429 		return (0);
430 
431 	case WSDISPLAYIO_GINFO:
432 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
433 		wsd_fbip->height = sc->sc_dc->dc_ht;
434 		wsd_fbip->width = sc->sc_dc->dc_wid;
435 		wsd_fbip->depth = sc->sc_dc->dc_depth;
436 		wsd_fbip->cmsize = CMAP_SIZE;
437 #undef fbt
438 		return (0);
439 
440 	case WSDISPLAYIO_GETCMAP:
441 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
442 
443 	case WSDISPLAYIO_PUTCMAP:
444 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
445 
446 	case WSDISPLAYIO_SVIDEO:
447 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
448 		if ((dc->dc_blanked == 0) ^ turnoff) {
449 			dc->dc_blanked = turnoff;
450 			/* XXX later XXX */
451 		}
452 		return (0);
453 
454 	case WSDISPLAYIO_GVIDEO:
455 		*(u_int *)data = dc->dc_blanked ?
456 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
457 		return (0);
458 
459 	case WSDISPLAYIO_GCURPOS:
460 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
461 		return (0);
462 
463 	case WSDISPLAYIO_SCURPOS:
464 		set_curpos(sc, (struct wsdisplay_curpos *)data);
465 		bt431_set_curpos(sc);
466 		return (0);
467 
468 	case WSDISPLAYIO_GCURMAX:
469 		((struct wsdisplay_curpos *)data)->x =
470 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
471 		return (0);
472 
473 	case WSDISPLAYIO_GCURSOR:
474 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
475 
476 	case WSDISPLAYIO_SCURSOR:
477 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
478 	}
479 	return ENOTTY;
480 }
481 
482 int
483 tfbmmap(v, offset, prot)
484 	void *v;
485 	off_t offset;
486 	int prot;
487 {
488 	struct tfb_softc *sc = v;
489 
490 	if (offset > TX_8FB_SIZE) /* XXX */
491 		return (-1);
492 	return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
493 }
494 
495 int
496 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
497 	void *v;
498 	const struct wsscreen_descr *type;
499 	void **cookiep;
500 	int *curxp, *curyp;
501 	long *attrp;
502 {
503 	struct tfb_softc *sc = v;
504 	long defattr;
505 
506 	if (sc->nscreens > 0)
507 		return (ENOMEM);
508 
509 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
510 	*curxp = 0;
511 	*curyp = 0;
512 	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
513 	*attrp = defattr;
514 	sc->nscreens++;
515 	return (0);
516 }
517 
518 void
519 tfb_free_screen(v, cookie)
520 	void *v;
521 	void *cookie;
522 {
523 	struct tfb_softc *sc = v;
524 
525 	if (sc->sc_dc == &tfb_console_dc)
526 		panic("tfb_free_screen: console");
527 
528 	sc->nscreens--;
529 }
530 
531 void
532 tfb_show_screen(v, cookie)
533 	void *v;
534 	void *cookie;
535 {
536 }
537 
538 int
539 tfb_load_font(v, cookie, first, num, stride, data)
540 	void *v;
541 	void *cookie;
542 	int first, num, stride;
543 	void *data;
544 {
545 	return (EINVAL);
546 }
547 
548 int
549 tfb_cnattach(addr)
550         tc_addr_t addr;
551 {
552         struct fb_devconfig *dcp = &tfb_console_dc;
553         long defattr;
554 
555         tfb_getdevconfig(addr, dcp);
556 
557         rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
558 
559         wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
560                            0, 0, defattr);
561         tfb_consaddr = addr;
562         return(0);
563 }
564 
565 int
566 tfbintr(arg)
567 	void *arg;
568 {
569 	struct tfb_softc *sc = arg;
570 	caddr_t tfbbase;
571 	struct bt463reg *vdac;
572 	struct bt431reg *curs;
573 	int v;
574 
575 	if (sc->sc_changed == 0)
576 		return (1);
577 
578 	tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
579 	vdac = (void *)(tfbbase + TX_BT463_OFFSET);
580 	curs = (void *)(tfbbase + TX_BT431_OFFSET);
581 	*(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
582 	v = sc->sc_changed;
583 	sc->sc_changed = 0;
584 	if (v & DATA_ENB_CHANGED) {
585 		BT431_SELECT(curs, BT431_REG_COMMAND);
586 		curs->bt_ctl = (sc->sc_curenb) ? 0x4444 : 0x0404;
587 	}
588 	if (v & DATA_CURCMAP_CHANGED) {
589 		u_int8_t *cp = sc->sc_cursor.cc_color;
590 
591 		BT463_SELECT(vdac, BT463_IREG_CURSOR_COLOR_0);
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 		vdac->bt_reg = cp[0]; tc_wmb();
597 		vdac->bt_reg = cp[2]; tc_wmb();
598 		vdac->bt_reg = cp[4]; tc_wmb();
599 
600 		vdac->bt_reg = cp[1]; tc_wmb();
601 		vdac->bt_reg = cp[3]; tc_wmb();
602 		vdac->bt_reg = cp[5]; tc_wmb();
603 
604 		vdac->bt_reg = cp[1]; tc_wmb();
605 		vdac->bt_reg = cp[3]; tc_wmb();
606 		vdac->bt_reg = cp[5]; tc_wmb();
607 	}
608 	if (v & DATA_CURSHAPE_CHANGED) {
609 		u_int8_t *ip, *mp, img, msk;
610 		int bcnt;
611 
612 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
613 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
614 
615 		bcnt = 0;
616 		BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
617 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
618 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
619 			/* pad right half 32 pixel when smaller than 33 */
620 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
621 				curs->bt_ram = 0;
622 				tc_wmb();
623 			}
624 			else {
625 				img = *ip++;
626 				msk = *mp++;
627 				img &= msk;	/* cookie off image */
628 				curs->bt_ram = (flip[msk] << 8) | flip[img];
629 				tc_wmb();
630 			}
631 			bcnt += 2;
632 		}
633 		/* pad unoccupied scan lines */
634 		while (bcnt < CURSOR_MAX_SIZE * 16) {
635 			curs->bt_ram = 0;
636 			tc_wmb();
637 			bcnt += 2;
638 		}
639 	}
640 	if (v & DATA_CMAP_CHANGED) {
641 		struct hwcmap *cm = &sc->sc_cmap;
642 		int index;
643 
644 		BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
645 		for (index = 0; index < CMAP_SIZE; index++) {
646 			vdac->bt_cmap = cm->r[index];
647 			vdac->bt_cmap = cm->g[index];
648 			vdac->bt_cmap = cm->b[index];
649 		}
650 	}
651 	*(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
652 	return (1);
653 }
654 
655 void
656 tfbinit(dc)
657 	struct fb_devconfig *dc;
658 {
659 	caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
660 	struct bt463reg *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
661 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
662 	int i;
663 
664 	BT463_SELECT(vdac, BT463_IREG_COMMAND_0);
665 	vdac->bt_reg = 0x40;	tc_wmb();
666 	vdac->bt_reg = 0x46;	tc_wmb();
667 	vdac->bt_reg = 0xc0;	tc_wmb();
668 	vdac->bt_reg = 0;	tc_wmb();	/* !? 204 !? */
669 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  0:7  */
670 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane  8:15 */
671 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 16:23 */
672 	vdac->bt_reg = 0xff;	tc_wmb();	/* plane 24:27 */
673 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  0:7  */
674 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink  8:15 */
675 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 16:23 */
676 	vdac->bt_reg = 0x00;	tc_wmb();	/* blink 24:27 */
677 	vdac->bt_reg = 0x00;	tc_wmb();
678 
679 	BT463_SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
680 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
681 		vdac->bt_reg = /* ??? */ 0;
682 		vdac->bt_reg = /* ??? */ 0;
683 		vdac->bt_reg = /* ??? */ 0;
684 	}
685 
686 	BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
687 	vdac->bt_cmap = 0;	tc_wmb();
688 	vdac->bt_cmap = 0;	tc_wmb();
689 	vdac->bt_cmap = 0;	tc_wmb();
690 	for (i = 1; i < BT463_NCMAP_ENTRIES; i++) {
691 		vdac->bt_cmap = 0xff;	tc_wmb();
692 		vdac->bt_cmap = 0xff;	tc_wmb();
693 		vdac->bt_cmap = 0xff;	tc_wmb();
694 	}
695 
696 	BT431_SELECT(curs, BT431_REG_COMMAND);
697 	curs->bt_ctl = 0x0404;	tc_wmb();
698 	curs->bt_ctl = 0;	tc_wmb();
699 	curs->bt_ctl = 0;	tc_wmb();
700 	curs->bt_ctl = 0;	tc_wmb();
701 	curs->bt_ctl = 0;	tc_wmb();
702 	curs->bt_ctl = 0;	tc_wmb();
703 	curs->bt_ctl = 0;	tc_wmb();
704 	curs->bt_ctl = 0;	tc_wmb();
705 	curs->bt_ctl = 0;	tc_wmb();
706 	curs->bt_ctl = 0;	tc_wmb();
707 	curs->bt_ctl = 0;	tc_wmb();
708 	curs->bt_ctl = 0;	tc_wmb();
709 	curs->bt_ctl = 0;	tc_wmb();
710 }
711 
712 static int
713 get_cmap(sc, p)
714 	struct tfb_softc *sc;
715 	struct wsdisplay_cmap *p;
716 {
717 	u_int index = p->index, count = p->count;
718 
719 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
720 		return (EINVAL);
721 
722 	if (!useracc(p->red, count, B_WRITE) ||
723 	    !useracc(p->green, count, B_WRITE) ||
724 	    !useracc(p->blue, count, B_WRITE))
725 		return (EFAULT);
726 
727 	copyout(&sc->sc_cmap.r[index], p->red, count);
728 	copyout(&sc->sc_cmap.g[index], p->green, count);
729 	copyout(&sc->sc_cmap.b[index], p->blue, count);
730 
731 	return (0);
732 }
733 
734 static int
735 set_cmap(sc, p)
736 	struct tfb_softc *sc;
737 	struct wsdisplay_cmap *p;
738 {
739 	u_int index = p->index, count = p->count;
740 
741 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
742 		return (EINVAL);
743 
744 	if (!useracc(p->red, count, B_READ) ||
745 	    !useracc(p->green, count, B_READ) ||
746 	    !useracc(p->blue, count, B_READ))
747 		return (EFAULT);
748 
749 	copyin(p->red, &sc->sc_cmap.r[index], count);
750 	copyin(p->green, &sc->sc_cmap.g[index], count);
751 	copyin(p->blue, &sc->sc_cmap.b[index], count);
752 
753 	sc->sc_changed |= DATA_CMAP_CHANGED;
754 
755 	return (0);
756 }
757 
758 static int
759 set_cursor(sc, p)
760 	struct tfb_softc *sc;
761 	struct wsdisplay_cursor *p;
762 {
763 #define	cc (&sc->sc_cursor)
764 	int v, index, count;
765 
766 	v = p->which;
767 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
768 		index = p->cmap.index;
769 		count = p->cmap.count;
770 		if (index >= 2 || (index + count) > 2)
771 			return (EINVAL);
772 		if (!useracc(p->cmap.red, count, B_READ) ||
773 		    !useracc(p->cmap.green, count, B_READ) ||
774 		    !useracc(p->cmap.blue, count, B_READ))
775 			return (EFAULT);
776 	}
777 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
778 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
779 			return (EINVAL);
780 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
781 		if (!useracc(p->image, count, B_READ) ||
782 		    !useracc(p->mask, count, B_READ))
783 			return (EFAULT);
784 	}
785 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
786 		if (v & WSDISPLAY_CURSOR_DOCUR)
787 			cc->cc_hot = p->hot;
788 		if (v & WSDISPLAY_CURSOR_DOPOS)
789 			set_curpos(sc, &p->pos);
790 		bt431_set_curpos(sc);
791 	}
792 
793 	sc->sc_changed = 0;
794 	if (v & WSDISPLAY_CURSOR_DOCUR) {
795 		sc->sc_curenb = p->enable;
796 		sc->sc_changed |= DATA_ENB_CHANGED;
797 	}
798 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
799 		count = p->cmap.count;
800 		copyin(p->cmap.red, &cc->cc_color[index], count);
801 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
802 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
803 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
804 	}
805 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
806 		cc->cc_size = p->size;
807 		memset(cc->cc_image, 0, sizeof cc->cc_image);
808 		copyin(p->image, cc->cc_image, count);
809 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
810 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
811 	}
812 
813 	return (0);
814 #undef cc
815 }
816 
817 static int
818 get_cursor(sc, p)
819 	struct tfb_softc *sc;
820 	struct wsdisplay_cursor *p;
821 {
822 	return (ENOTTY); /* XXX */
823 }
824 
825 static void
826 set_curpos(sc, curpos)
827 	struct tfb_softc *sc;
828 	struct wsdisplay_curpos *curpos;
829 {
830 	struct fb_devconfig *dc = sc->sc_dc;
831 	int x = curpos->x, y = curpos->y;
832 
833 	if (y < 0)
834 		y = 0;
835 	else if (y > dc->dc_ht)
836 		y = dc->dc_ht;
837 	if (x < 0)
838 		x = 0;
839 	else if (x > dc->dc_wid)
840 		x = dc->dc_wid;
841 	sc->sc_cursor.cc_pos.x = x;
842 	sc->sc_cursor.cc_pos.y = y;
843 }
844 
845 static void
846 bt431_set_curpos(sc)
847 	struct tfb_softc *sc;
848 {
849 	caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
850 	struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
851 	u_int16_t twin;
852 	int x, y, s;
853 
854 	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
855 	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
856 	x += sc->magic_x; y += sc->magic_y; /* magic offset of TX coordinate */
857 
858 	s = spltty();
859 
860 	BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
861 	curs->bt_ctl = TWIN_LO(x);	tc_wmb();
862 	curs->bt_ctl = TWIN_HI(x);	tc_wmb();
863 	curs->bt_ctl = TWIN_LO(y);	tc_wmb();
864 	curs->bt_ctl = TWIN_HI(y);	tc_wmb();
865 
866 	splx(s);
867 }
868