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