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