xref: /original-bsd/sys/pmax/dev/mfb.c (revision e49f9654)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)mfb.c	8.2 (Berkeley) 06/02/95
11  */
12 
13 /*
14  * Mach Operating System
15  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
16  * All Rights Reserved.
17  *
18  * Permission to use, copy, modify and distribute this software and its
19  * documentation is hereby granted, provided that both the copyright
20  * notice and this permission notice appear in all copies of the
21  * software, derivative works or modified versions, and any portions
22  * thereof, and that both notices appear in supporting documentation.
23  *
24  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
25  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27  *
28  * Carnegie Mellon requests users of this software to return to
29  *
30  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31  *  School of Computer Science
32  *  Carnegie Mellon University
33  *  Pittsburgh PA 15213-3890
34  *
35  * any improvements or extensions that they make and grant Carnegie the
36  * rights to redistribute these changes.
37  */
38 /*
39  *  devGraphics.c --
40  *
41  *     	This file contains machine-dependent routines for the graphics device.
42  *
43  *	Copyright (C) 1989 Digital Equipment Corporation.
44  *	Permission to use, copy, modify, and distribute this software and
45  *	its documentation for any purpose and without fee is hereby granted,
46  *	provided that the above copyright notice appears in all copies.
47  *	Digital Equipment Corporation makes no representations about the
48  *	suitability of this software for any purpose.  It is provided "as is"
49  *	without express or implied warranty.
50  *
51  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
52  *	v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
53  */
54 
55 #include <mfb.h>
56 #if NMFB > 0
57 #include <sys/param.h>
58 #include <sys/time.h>
59 #include <sys/kernel.h>
60 #include <sys/ioctl.h>
61 #include <sys/file.h>
62 #include <sys/errno.h>
63 #include <sys/proc.h>
64 #include <sys/mman.h>
65 
66 #include <vm/vm.h>
67 
68 #include <machine/machConst.h>
69 #include <machine/pmioctl.h>
70 
71 #include <pmax/pmax/cons.h>
72 #include <pmax/pmax/pmaxtype.h>
73 
74 #include <pmax/dev/device.h>
75 #include <pmax/dev/mfbreg.h>
76 #include <pmax/dev/fbreg.h>
77 
78 #include <dc.h>
79 #include <dtop.h>
80 #include <scc.h>
81 
82 /*
83  * These need to be mapped into user space.
84  */
85 struct fbuaccess mfbu;
86 struct pmax_fb mfbfb;
87 
88 /*
89  * Forward references.
90  */
91 static void mfbScreenInit();
92 static void mfbLoadCursor();
93 static void mfbRestoreCursorColor();
94 static void mfbCursorColor();
95 void mfbPosCursor();
96 static void mfbInitColorMap();
97 static void mfbLoadColorMap();
98 static void mfbConfigMouse(), mfbDeconfigMouse();
99 static void bt455_video_on(), bt455_video_off(), bt431_select_reg();
100 static void bt431_write_reg(), bt431_init();
101 static u_char bt431_read_reg();
102 
103 void mfbKbdEvent(), mfbMouseEvent(), mfbMouseButtons();
104 #if NDC > 0
105 extern void (*dcDivertXInput)();
106 extern void (*dcMouseEvent)();
107 extern void (*dcMouseButtons)();
108 #endif
109 #if NSCC > 0
110 extern void (*sccDivertXInput)();
111 extern void (*sccMouseEvent)();
112 extern void (*sccMouseButtons)();
113 #endif
114 #if NDTOP > 0
115 extern void (*dtopDivertXInput)();
116 extern void (*dtopMouseEvent)();
117 extern void (*dtopMouseButtons)();
118 #endif
119 extern int pmax_boardtype;
120 extern u_short defCursor[32];
121 extern struct consdev cn_tab;
122 
123 int	mfbprobe();
124 struct	driver mfbdriver = {
125 	"mfb", mfbprobe, 0, 0,
126 };
127 
128 #define	MFB_OFFSET_VRAM		0x200000	/* from module's base */
129 #define MFB_OFFSET_BT431	0x180000	/* Bt431 registers */
130 #define MFB_OFFSET_BT455	0x100000	/* Bt455 registers */
131 #define MFB_OFFSET_IREQ		0x080000	/* Interrupt req. control */
132 #define MFB_OFFSET_ROM		0x0		/* Diagnostic ROM */
133 #define MFB_FB_SIZE		0x200000	/* frame buffer size */
134 
135 /*
136  * Test to see if device is present.
137  * Return true if found and initialized ok.
138  */
139 /*ARGSUSED*/
140 mfbprobe(cp)
141 	register struct pmax_ctlr *cp;
142 {
143 	register struct pmax_fb *fp = &mfbfb;
144 
145 	if (!fp->initialized && !mfbinit(cp->pmax_addr))
146 		return (0);
147 	printf("mfb0 (mono display)\n");
148 	return (1);
149 }
150 
151 /*ARGSUSED*/
152 mfbopen(dev, flag)
153 	dev_t dev;
154 	int flag;
155 {
156 	register struct pmax_fb *fp = &mfbfb;
157 	int s;
158 
159 	if (!fp->initialized)
160 		return (ENXIO);
161 	if (fp->GraphicsOpen)
162 		return (EBUSY);
163 
164 	fp->GraphicsOpen = 1;
165 	mfbInitColorMap(1);
166 	/*
167 	 * Set up event queue for later
168 	 */
169 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
170 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
171 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
172 	fp->fbu->scrInfo.qe.tcNext = 0;
173 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
174 	mfbConfigMouse();
175 	return (0);
176 }
177 
178 /*ARGSUSED*/
179 mfbclose(dev, flag)
180 	dev_t dev;
181 	int flag;
182 {
183 	register struct pmax_fb *fp = &mfbfb;
184 	int s;
185 
186 	if (!fp->GraphicsOpen)
187 		return (EBADF);
188 
189 	fp->GraphicsOpen = 0;
190 	mfbInitColorMap(0);
191 	mfbDeconfigMouse();
192 	mfbScreenInit();
193 	bzero((caddr_t)fp->fr_addr, 2048 * 1024);
194 	mfbPosCursor(fp->col * 8, fp->row * 15);
195 	return (0);
196 }
197 
198 /*ARGSUSED*/
199 mfbioctl(dev, cmd, data, flag, p)
200 	dev_t dev;
201 	u_long cmd;
202 	caddr_t data;
203 	struct proc *p;
204 {
205 	register struct pmax_fb *fp = &mfbfb;
206 	int s;
207 
208 	switch (cmd) {
209 	case QIOCGINFO:
210 		return (fbmmap(fp, dev, data, p));
211 
212 	case QIOCPMSTATE:
213 		/*
214 		 * Set mouse state.
215 		 */
216 		fp->fbu->scrInfo.mouse = *(pmCursor *)data;
217 		mfbPosCursor(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y);
218 		break;
219 
220 	case QIOCINIT:
221 		/*
222 		 * Initialize the screen.
223 		 */
224 		mfbScreenInit();
225 		break;
226 
227 	case QIOCKPCMD:
228 	    {
229 		pmKpCmd *kpCmdPtr;
230 		unsigned char *cp;
231 
232 		kpCmdPtr = (pmKpCmd *)data;
233 		if (kpCmdPtr->nbytes == 0)
234 			kpCmdPtr->cmd |= 0x80;
235 		if (!fp->GraphicsOpen)
236 			kpCmdPtr->cmd |= 1;
237 		(*fp->KBDPutc)(fp->kbddev, (int)kpCmdPtr->cmd);
238 		cp = &kpCmdPtr->par[0];
239 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
240 			if (kpCmdPtr->nbytes == 1)
241 				*cp |= 0x80;
242 			(*fp->KBDPutc)(fp->kbddev, (int)*cp);
243 		}
244 		break;
245 	    }
246 
247 	case QIOCADDR:
248 		*(PM_Info **)data = &fp->fbu->scrInfo;
249 		break;
250 
251 	case QIOWCURSOR:
252 		mfbLoadCursor((unsigned short *)data);
253 		break;
254 
255 	case QIOWCURSORCOLOR:
256 		mfbCursorColor((unsigned int *)data);
257 		break;
258 
259 	case QIOSETCMAP:
260 #ifdef notdef
261 		mfbLoadColorMap((ColorMap *)data);
262 #endif
263 		break;
264 
265 	case QIOKERNLOOP:
266 		mfbConfigMouse();
267 		break;
268 
269 	case QIOKERNUNLOOP:
270 		mfbDeconfigMouse();
271 		break;
272 
273 	case QIOVIDEOON:
274 		bt455_video_on();
275 		break;
276 
277 	case QIOVIDEOOFF:
278 		bt455_video_off();
279 		break;
280 
281 	default:
282 		printf("mfb0: Unknown ioctl command %x\n", cmd);
283 		return (EINVAL);
284 	}
285 	return (0);
286 }
287 
288 /*
289  * Return the physical page number that corresponds to byte offset 'off'.
290  */
291 /*ARGSUSED*/
292 mfbmap(dev, off, prot)
293 	dev_t dev;
294 {
295 	int len;
296 
297 	len = pmax_round_page(((vm_offset_t)&mfbu & PGOFSET) + sizeof(mfbu));
298 	if (off < len)
299 		return pmax_btop(MACH_CACHED_TO_PHYS(&mfbu) + off);
300 	off -= len;
301 	if (off >= mfbfb.fr_size)
302 		return (-1);
303 	return pmax_btop(MACH_UNCACHED_TO_PHYS(mfbfb.fr_addr) + off);
304 }
305 
306 mfbselect(dev, flag, p)
307 	dev_t dev;
308 	int flag;
309 	struct proc *p;
310 {
311 	struct pmax_fb *fp = &mfbfb;
312 
313 	switch (flag) {
314 	case FREAD:
315 		if (fp->fbu->scrInfo.qe.eHead != fp->fbu->scrInfo.qe.eTail)
316 			return (1);
317 		selrecord(p, &fp->selp);
318 		break;
319 	}
320 
321 	return (0);
322 }
323 
324 static u_char	cursor_RGB[6];	/* cursor color 2 & 3 */
325 
326 /*
327  * There are actually 2 Bt431 cursor sprite chips that each generate 1 bit
328  * of each cursor pixel for a 2bit 64x64 cursor sprite. The corresponding
329  * registers for these two chips live in adjacent bytes of the shorts that
330  * are defined in bt431_regmap_t.
331  */
332 static void
333 mfbLoadCursor(cursor)
334 	u_short *cursor;
335 {
336 	register int i, j, k, pos;
337 	register u_short ap, bp, out;
338 	register bt431_regmap_t *regs;
339 
340 	regs = (bt431_regmap_t *)(mfbfb.fr_chipaddr +
341 		 MFB_OFFSET_BT431);
342 	/*
343 	 * Fill in the cursor sprite using the A and B planes, as provided
344 	 * for the pmax.
345 	 * XXX This will have to change when the X server knows that this
346 	 * is not a pmax display. (ie. Not the Xcfbpmax server.)
347 	 */
348 	pos = 0;
349 	bt431_select_reg(regs, BT431_REG_CRAM_BASE);
350 	for (k = 0; k < 16; k++) {
351 		ap = *cursor;
352 		bp = *(cursor + 16);
353 		j = 0;
354 		while (j < 2) {
355 			out = 0;
356 			for (i = 0; i < 8; i++) {
357 				out = (out << 1) | ((bp & 0x1) << 8) |
358 					(ap & 0x1);
359 				ap >>= 1;
360 				bp >>= 1;
361 			}
362 			BT431_WRITE_CMAP_AUTOI(regs, out);
363 			pos++;
364 			j++;
365 		}
366 		while (j < 8) {
367 			BT431_WRITE_CMAP_AUTOI(regs, 0);
368 			pos++;
369 			j++;
370 		}
371 		cursor++;
372 	}
373 	while (pos < 512) {
374 		BT431_WRITE_CMAP_AUTOI(regs, 0);
375 		pos++;
376 	}
377 }
378 
379 /*
380  * Initialization
381  */
382 int
383 mfbinit(cp)
384 	char *cp;
385 {
386 	register struct pmax_fb *fp = &mfbfb;
387 
388 	/* check for no frame buffer */
389 	if (badaddr(cp, 4))
390 		return (0);
391 
392 	fp->isMono = 0;
393 	fp->fr_addr = cp + MFB_OFFSET_VRAM;
394 	fp->fr_chipaddr = cp;
395 	fp->fr_size = MFB_FB_SIZE;
396 	/*
397 	 * Must be in Uncached space since the fbuaccess structure is
398 	 * mapped into the user's address space uncached.
399 	 */
400 	fp->fbu = (struct fbuaccess *)
401 		MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(&mfbu));
402 	fp->posCursor = mfbPosCursor;
403 	if (tb_kbdmouseconfig(fp))
404 		return (0);
405 
406 	/*
407 	 * Initialize the screen.
408 	 */
409 	bt431_init(fp->fr_chipaddr + MFB_OFFSET_BT431);
410 
411 	/*
412 	 * Initialize screen info.
413 	 */
414 	fp->fbu->scrInfo.max_row = 67;
415 	fp->fbu->scrInfo.max_col = 80;
416 	fp->fbu->scrInfo.max_x = 1280;
417 	fp->fbu->scrInfo.max_y = 1024;
418 	fp->fbu->scrInfo.max_cur_x = 1279;
419 	fp->fbu->scrInfo.max_cur_y = 1023;
420 	fp->fbu->scrInfo.version = 11;
421 	fp->fbu->scrInfo.mthreshold = 4;
422 	fp->fbu->scrInfo.mscale = 2;
423 	fp->fbu->scrInfo.min_cur_x = 0;
424 	fp->fbu->scrInfo.min_cur_y = 0;
425 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
426 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
427 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
428 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
429 	fp->fbu->scrInfo.qe.tcNext = 0;
430 
431 	/*
432 	 * Initialize the color map, the screen, and the mouse.
433 	 */
434 	mfbInitColorMap(0);
435 	mfbScreenInit();
436 	fbScroll(fp);
437 
438 	fp->initialized = 1;
439 	if (cn_tab.cn_fb == (struct pmax_fb *)0)
440 		cn_tab.cn_fb = fp;
441 	return (1);
442 }
443 
444 /*
445  * ----------------------------------------------------------------------------
446  *
447  * mfbScreenInit --
448  *
449  *	Initialize the screen.
450  *
451  * Results:
452  *	None.
453  *
454  * Side effects:
455  *	The screen is initialized.
456  *
457  * ----------------------------------------------------------------------------
458  */
459 static void
460 mfbScreenInit()
461 {
462 	register struct pmax_fb *fp = &mfbfb;
463 
464 	/*
465 	 * Home the cursor.
466 	 * We want an LSI terminal emulation.  We want the graphics
467 	 * terminal to scroll from the bottom. So start at the bottom.
468 	 */
469 	fp->row = 66;
470 	fp->col = 0;
471 
472 	/*
473 	 * Load the cursor with the default values
474 	 *
475 	 */
476 	mfbLoadCursor(defCursor);
477 }
478 
479 /*
480  * ----------------------------------------------------------------------------
481  *
482  * RestoreCursorColor --
483  *
484  *	Routine to restore the color of the cursor.
485  *
486  * Results:
487  *	None.
488  *
489  * Side effects:
490  *	None.
491  *
492  * ----------------------------------------------------------------------------
493  */
494 static void
495 mfbRestoreCursorColor()
496 {
497 	bt455_regmap_t *regs = (bt455_regmap_t *)(mfbfb.fr_chipaddr +
498 		MFB_OFFSET_BT455);
499 	ColorMap cm;
500 	u_char fg;
501 
502 	if (cursor_RGB[0] || cursor_RGB[1] || cursor_RGB[2])
503 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0xffff;
504 	else
505 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0;
506 	cm.index = 8;
507 	mfbLoadColorMap(&cm);
508 	cm.index = 9;
509 	mfbLoadColorMap(&cm);
510 
511 	if (cursor_RGB[3] || cursor_RGB[4] || cursor_RGB[5])
512 		fg = 0xf;
513 	else
514 		fg = 0;
515 	regs->addr_ovly = fg;
516 	MachEmptyWriteBuffer();
517 	regs->addr_ovly = fg;
518 	MachEmptyWriteBuffer();
519 	regs->addr_ovly = fg;
520 	MachEmptyWriteBuffer();
521 }
522 
523 /*
524  * ----------------------------------------------------------------------------
525  *
526  * CursorColor --
527  *
528  *	Set the color of the cursor.
529  *
530  * Results:
531  *	None.
532  *
533  * Side effects:
534  *	None.
535  *
536  * ----------------------------------------------------------------------------
537  */
538 static void
539 mfbCursorColor(color)
540 	unsigned int color[];
541 {
542 	register int i, j;
543 
544 	for (i = 0; i < 6; i++)
545 		cursor_RGB[i] = (u_char)(color[i] >> 8);
546 
547 	mfbRestoreCursorColor();
548 }
549 
550 /*
551  *----------------------------------------------------------------------
552  *
553  * PosCursor --
554  *
555  *	Postion the cursor.
556  *
557  * Results:
558  *	None.
559  *
560  * Side effects:
561  *	None.
562  *
563  *----------------------------------------------------------------------
564  */
565 void
566 mfbPosCursor(x, y)
567 	register int x, y;
568 {
569 	bt431_regmap_t *regs = (bt431_regmap_t *)(mfbfb.fr_chipaddr +
570 		 MFB_OFFSET_BT431);
571 	register struct pmax_fb *fp = &mfbfb;
572 
573 	if (y < fp->fbu->scrInfo.min_cur_y || y > fp->fbu->scrInfo.max_cur_y)
574 		y = fp->fbu->scrInfo.max_cur_y;
575 	if (x < fp->fbu->scrInfo.min_cur_x || x > fp->fbu->scrInfo.max_cur_x)
576 		x = fp->fbu->scrInfo.max_cur_x;
577 	fp->fbu->scrInfo.cursor.x = x;		/* keep track of real cursor */
578 	fp->fbu->scrInfo.cursor.y = y;		/* position, indep. of mouse */
579 
580 #define lo(v)	((v)&0xff)
581 #define hi(v)	(((v)&0xf00)>>8)
582 
583 	/*
584 	 * Cx = x + D + H - P
585 	 *  P = 37 if 1:1, 52 if 4:1, 57 if 5:1
586 	 *  D = pixel skew between outdata and external data
587 	 *  H = pixels between HSYNCH falling and active video
588 	 *
589 	 * Cy = y + V - 32
590 	 *  V = scanlines between HSYNCH falling, two or more
591 	 *	clocks after VSYNCH falling, and active video
592 	 */
593 
594 	bt431_write_reg(regs, BT431_REG_CXLO, lo(x + 360));
595 	BT431_WRITE_REG_AUTOI(regs, hi(x + 360));
596 	BT431_WRITE_REG_AUTOI(regs, lo(y + 36));
597 	BT431_WRITE_REG_AUTOI(regs, hi(y + 36));
598 }
599 
600 /*
601  * ----------------------------------------------------------------------------
602  *
603  * InitColorMap --
604  *
605  *	Initialize the color map.
606  *
607  * Results:
608  *	None.
609  *
610  * Side effects:
611  *	The colormap is initialized appropriately.
612  *
613  * ----------------------------------------------------------------------------
614  */
615 static void
616 mfbInitColorMap(blackpix)
617 	int blackpix;
618 {
619 	ColorMap cm;
620 	register int i;
621 
622 	cm.index = 0;
623 	if (blackpix)
624 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0xffff;
625 	else
626 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0;
627 	mfbLoadColorMap(&cm);
628 	if (blackpix)
629 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0;
630 	else
631 		cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0xffff;
632 	for (i = 1; i < 16; i++) {
633 		cm.index = i;
634 		mfbLoadColorMap(&cm);
635 	}
636 
637 	for (i = 0; i < 3; i++) {
638 		cursor_RGB[i] = 0;
639 		cursor_RGB[i + 3] = 0xff;
640 	}
641 	mfbRestoreCursorColor();
642 }
643 
644 /*
645  * ----------------------------------------------------------------------------
646  *
647  * LoadColorMap --
648  *
649  *	Load the color map.
650  *
651  * Results:
652  *	None.
653  *
654  * Side effects:
655  *	The color map is loaded.
656  *
657  * ----------------------------------------------------------------------------
658  */
659 static void
660 mfbLoadColorMap(ptr)
661 	ColorMap *ptr;
662 {
663 	bt455_regmap_t *regs = (bt455_regmap_t *)(mfbfb.fr_chipaddr +
664 		 MFB_OFFSET_BT455);
665 
666 	if (ptr->index > 15)
667 		return;
668 
669 	BT455_SELECT_ENTRY(regs, ptr->index);
670 	regs->addr_cmap_data = ptr->Entry.red >> 12;
671 	MachEmptyWriteBuffer();
672 	regs->addr_cmap_data = ptr->Entry.green >> 12;
673 	MachEmptyWriteBuffer();
674 	regs->addr_cmap_data = ptr->Entry.blue >> 12;
675 	MachEmptyWriteBuffer();
676 }
677 
678 /*
679  * Video on/off state.
680  */
681 static struct vstate {
682 	u_char	color0[6];	/* saved color map entry zero */
683 	u_char	off;		/* TRUE if display is off */
684 	u_char	cursor[6];	/* saved cursor color */
685 } vstate;
686 
687 /*
688  * ----------------------------------------------------------------------------
689  *
690  * bt455_video_on
691  *
692  *	Enable the video display.
693  *
694  * Results:
695  *	None.
696  *
697  * Side effects:
698  *	The display is enabled.
699  *
700  * ----------------------------------------------------------------------------
701  */
702 static void
703 bt455_video_on()
704 {
705 	register int i;
706 	bt455_regmap_t *regs = (bt455_regmap_t *)(mfbfb.fr_chipaddr +
707 		 MFB_OFFSET_BT455);
708 
709 	if (!vstate.off)
710 		return;
711 
712 	/* restore old color map entry zero */
713 	BT455_SELECT_ENTRY(regs, 0);
714 	for (i = 0; i < 6; i++) {
715 		regs->addr_cmap_data = vstate.color0[i];
716 		MachEmptyWriteBuffer();
717 		cursor_RGB[i] = vstate.cursor[i];
718 	}
719 	mfbRestoreCursorColor();
720 	vstate.off = 0;
721 }
722 
723 /*
724  * ----------------------------------------------------------------------------
725  *
726  * bt455_video_off
727  *
728  *	Disable the video display.
729  *
730  * Results:
731  *	None.
732  *
733  * Side effects:
734  *	The display is disabled.
735  *
736  * ----------------------------------------------------------------------------
737  */
738 static void
739 bt455_video_off()
740 {
741 	register int i;
742 	bt455_regmap_t *regs = (bt455_regmap_t *)(mfbfb.fr_chipaddr +
743 		 MFB_OFFSET_BT455);
744 	ColorMap cm;
745 
746 	if (vstate.off)
747 		return;
748 
749 	/* save old color map entry zero */
750 	BT455_SELECT_ENTRY(regs, 0);
751 	for (i = 0; i < 6; i++) {
752 		vstate.color0[i] = regs->addr_cmap_data;
753 		vstate.cursor[i] = cursor_RGB[i];
754 		cursor_RGB[i] = 0;
755 	}
756 
757 	/* set color map entry zero to zero */
758 	cm.index = 0;
759 	cm.Entry.red = cm.Entry.green = cm.Entry.blue = 0;
760 	mfbLoadColorMap(&cm);
761 	cm.index = 1;
762 	mfbLoadColorMap(&cm);
763 
764 	mfbRestoreCursorColor();
765 	vstate.off = 1;
766 }
767 
768 /*
769  * mfb keyboard and mouse input. Just punt to the generic ones in fb.c
770  */
771 void
772 mfbKbdEvent(ch)
773 	int ch;
774 {
775 	fbKbdEvent(ch, &mfbfb);
776 }
777 
778 void
779 mfbMouseEvent(newRepPtr)
780 	MouseReport *newRepPtr;
781 {
782 	fbMouseEvent(newRepPtr, &mfbfb);
783 }
784 
785 void
786 mfbMouseButtons(newRepPtr)
787 	MouseReport *newRepPtr;
788 {
789 	fbMouseButtons(newRepPtr, &mfbfb);
790 }
791 
792 /*
793  * Configure the mouse and keyboard based on machine type
794  */
795 static void
796 mfbConfigMouse()
797 {
798 	int s;
799 
800 	s = spltty();
801 	switch (pmax_boardtype) {
802 #if NDC > 0
803 	case DS_3MAX:
804 		dcDivertXInput = mfbKbdEvent;
805 		dcMouseEvent = mfbMouseEvent;
806 		dcMouseButtons = mfbMouseButtons;
807 		break;
808 #endif
809 #if NSCC > 1
810 	case DS_3MIN:
811 		sccDivertXInput = mfbKbdEvent;
812 		sccMouseEvent = mfbMouseEvent;
813 		sccMouseButtons = mfbMouseButtons;
814 		break;
815 #endif
816 #if NDTOP > 0
817 	case DS_MAXINE:
818 		dtopDivertXInput = mfbKbdEvent;
819 		dtopMouseEvent = mfbMouseEvent;
820 		dtopMouseButtons = mfbMouseButtons;
821 		break;
822 #endif
823 	default:
824 		printf("Can't configure mouse/keyboard\n");
825 	};
826 	splx(s);
827 }
828 
829 /*
830  * and deconfigure them
831  */
832 static void
833 mfbDeconfigMouse()
834 {
835 	int s;
836 
837 	s = spltty();
838 	switch (pmax_boardtype) {
839 #if NDC > 0
840 	case DS_3MAX:
841 		dcDivertXInput = (void (*)())0;
842 		dcMouseEvent = (void (*)())0;
843 		dcMouseButtons = (void (*)())0;
844 		break;
845 #endif
846 #if NSCC > 1
847 	case DS_3MIN:
848 		sccDivertXInput = (void (*)())0;
849 		sccMouseEvent = (void (*)())0;
850 		sccMouseButtons = (void (*)())0;
851 		break;
852 #endif
853 #if NDTOP > 0
854 	case DS_MAXINE:
855 		dtopDivertXInput = (void (*)())0;
856 		dtopMouseEvent = (void (*)())0;
857 		dtopMouseButtons = (void (*)())0;
858 		break;
859 #endif
860 	default:
861 		printf("Can't deconfigure mouse/keyboard\n");
862 	};
863 }
864 
865 /*
866  * Generic register access
867  */
868 static void
869 bt431_select_reg(regs, regno)
870 	bt431_regmap_t *regs;
871 {
872 	regs->addr_lo = SET_VALUE(regno & 0xff);
873 	regs->addr_hi = SET_VALUE((regno >> 8) & 0xff);
874 	MachEmptyWriteBuffer();
875 }
876 
877 static void
878 bt431_write_reg(regs, regno, val)
879 	bt431_regmap_t *regs;
880 {
881 	bt431_select_reg(regs, regno);
882 	regs->addr_reg = SET_VALUE(val);
883 	MachEmptyWriteBuffer();
884 }
885 
886 static u_char
887 bt431_read_reg(regs, regno)
888 	bt431_regmap_t *regs;
889 {
890 	bt431_select_reg(regs, regno);
891 	return (GET_VALUE(regs->addr_reg));
892 }
893 
894 static void
895 bt431_init(regs)
896 	bt431_regmap_t *regs;
897 {
898 	register int i;
899 
900 	/* use 4:1 input mux */
901 	bt431_write_reg(regs, BT431_REG_CMD,
902 			 BT431_CMD_CURS_ENABLE|BT431_CMD_OR_CURSORS|
903 			 BT431_CMD_4_1_MUX|BT431_CMD_THICK_1);
904 
905 	/* home cursor */
906 	BT431_WRITE_REG_AUTOI(regs, 0x00);
907 	BT431_WRITE_REG_AUTOI(regs, 0x00);
908 	BT431_WRITE_REG_AUTOI(regs, 0x00);
909 	BT431_WRITE_REG_AUTOI(regs, 0x00);
910 
911 	/* no crosshair window */
912 	BT431_WRITE_REG_AUTOI(regs, 0x00);
913 	BT431_WRITE_REG_AUTOI(regs, 0x00);
914 	BT431_WRITE_REG_AUTOI(regs, 0x00);
915 	BT431_WRITE_REG_AUTOI(regs, 0x00);
916 	BT431_WRITE_REG_AUTOI(regs, 0x00);
917 	BT431_WRITE_REG_AUTOI(regs, 0x00);
918 	BT431_WRITE_REG_AUTOI(regs, 0x00);
919 	BT431_WRITE_REG_AUTOI(regs, 0x00);
920 }
921 #endif /* NMFB */
922