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