xref: /original-bsd/sys/pmax/dev/pm.c (revision 135ce860)
1 /*
2  * Copyright (c) 1992 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.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)pm.c	7.5 (Berkeley) 06/02/92
11  *
12  *  devGraphics.c --
13  *
14  *     	This file contains machine-dependent routines for the graphics device.
15  *
16  *	Copyright (C) 1989 Digital Equipment Corporation.
17  *	Permission to use, copy, modify, and distribute this software and
18  *	its documentation for any purpose and without fee is hereby granted,
19  *	provided that the above copyright notice appears in all copies.
20  *	Digital Equipment Corporation makes no representations about the
21  *	suitability of this software for any purpose.  It is provided "as is"
22  *	without express or implied warranty.
23  *
24  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
25  *	v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
26  */
27 
28 #include "pm.h"
29 #if NPM > 0
30 
31 #include "param.h"
32 #include "time.h"
33 #include "kernel.h"
34 #include "ioctl.h"
35 #include "file.h"
36 #include "errno.h"
37 #include "proc.h"
38 #include "mman.h"
39 #include "vm/vm.h"
40 
41 #include "machine/machConst.h"
42 #include "machine/machMon.h"
43 #include "machine/dc7085cons.h"
44 #include "machine/pmioctl.h"
45 
46 #include "device.h"
47 #include "pmreg.h"
48 #include "font.c"
49 
50 #define MAX_ROW	56
51 #define MAX_COL	80
52 
53 /*
54  * Macro to translate from a time struct to milliseconds.
55  */
56 #define TO_MS(tv) ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))
57 
58 static u_short	curReg;		/* copy of PCCRegs.cmdr since it's read only */
59 static int	isMono;		/* true if B&W frame buffer */
60 static int	initialized;	/* true if 'probe' was successful */
61 static int	GraphicsOpen;	/* true if the graphics device is open */
62 static int	row, col;	/* row and col for console cursor */
63 static struct	selinfo pm_selp;/* process waiting for select */
64 
65 /*
66  * These need to be mapped into user space.
67  */
68 static struct pmuaccess {
69 	PM_Info		scrInfo;
70 	pmEvent		events[PM_MAXEVQ];
71 	pmTimeCoord	tcs[MOTION_BUFFER_SIZE];
72 } pmu;
73 
74 /*
75  * Font mask bits used by Blitc().
76  */
77 static unsigned int fontmaskBits[16] = {
78 	0x00000000,
79 	0x00000001,
80 	0x00000100,
81 	0x00000101,
82 	0x00010000,
83 	0x00010001,
84 	0x00010100,
85 	0x00010101,
86 	0x01000000,
87 	0x01000001,
88 	0x01000100,
89 	0x01000101,
90 	0x01010000,
91 	0x01010001,
92 	0x01010100,
93 	0x01010101
94 };
95 
96 /*
97  * Forward references.
98  */
99 static void Scroll();
100 static void Blitc();
101 
102 static void ScreenInit();
103 static void LoadCursor();
104 static void RestoreCursorColor();
105 static void CursorColor();
106 static void PosCursor();
107 static void InitColorMap();
108 static void VDACInit();
109 static void LoadColorMap();
110 static void EnableVideo();
111 static void DisableVideo();
112 
113 extern void dcKBDPutc();
114 extern void (*dcDivertXInput)();
115 extern void (*dcMouseEvent)();
116 extern void (*dcMouseButtons)();
117 
118 int	pmprobe();
119 struct	driver pmdriver = {
120 	"pm", pmprobe, 0, 0,
121 };
122 
123 /*
124  * Test to see if device is present.
125  * Return true if found and initialized ok.
126  */
127 /*ARGSUSED*/
128 pmprobe(cp)
129 	register struct pmax_ctlr *cp;
130 {
131 
132 	if (!initialized && !pminit())
133 		return (0);
134 	if (isMono)
135 		printf("pm0 (monochrome display)\n");
136 	else
137 		printf("pm0 (color display)\n");
138 	return (1);
139 }
140 
141 /*
142  *----------------------------------------------------------------------
143  *
144  * pmKbdEvent --
145  *
146  *	Process a received character.
147  *
148  * Results:
149  *	None.
150  *
151  * Side effects:
152  *	Events added to the queue.
153  *
154  *----------------------------------------------------------------------
155  */
156 void
157 pmKbdEvent(ch)
158 	int ch;
159 {
160 	register pmEvent *eventPtr;
161 	int i;
162 
163 	if (!GraphicsOpen)
164 		return;
165 
166 	/*
167 	 * See if there is room in the queue.
168 	 */
169 	i = PM_EVROUND(pmu.scrInfo.qe.eTail + 1);
170 	if (i == pmu.scrInfo.qe.eHead)
171 		return;
172 
173 	/*
174 	 * Add the event to the queue.
175 	 */
176 	eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
177 	eventPtr->type = BUTTON_RAW_TYPE;
178 	eventPtr->device = KEYBOARD_DEVICE;
179 	eventPtr->x = pmu.scrInfo.mouse.x;
180 	eventPtr->y = pmu.scrInfo.mouse.y;
181 	eventPtr->time = TO_MS(time);
182 	eventPtr->key = ch;
183 	pmu.scrInfo.qe.eTail = i;
184 	selwakeup(&pm_selp);
185 }
186 
187 /*
188  *----------------------------------------------------------------------
189  *
190  * pmMouseEvent --
191  *
192  *	Process a mouse event.
193  *
194  * Results:
195  *	None.
196  *
197  * Side effects:
198  *	An event is added to the event queue.
199  *
200  *----------------------------------------------------------------------
201  */
202 void
203 pmMouseEvent(newRepPtr)
204 	register MouseReport *newRepPtr;
205 {
206 	unsigned milliSec;
207 	int i;
208 	pmEvent *eventPtr;
209 
210 	if (!GraphicsOpen)
211 		return;
212 
213 	milliSec = TO_MS(time);
214 
215 	/*
216 	 * Check to see if we have to accelerate the mouse
217 	 */
218 	if (pmu.scrInfo.mscale >= 0) {
219 		if (newRepPtr->dx >= pmu.scrInfo.mthreshold) {
220 			newRepPtr->dx +=
221 				(newRepPtr->dx - pmu.scrInfo.mthreshold) *
222 				pmu.scrInfo.mscale;
223 		}
224 		if (newRepPtr->dy >= pmu.scrInfo.mthreshold) {
225 			newRepPtr->dy +=
226 				(newRepPtr->dy - pmu.scrInfo.mthreshold) *
227 				pmu.scrInfo.mscale;
228 		}
229 	}
230 
231 	/*
232 	 * Update mouse position
233 	 */
234 	if (newRepPtr->state & MOUSE_X_SIGN) {
235 		pmu.scrInfo.mouse.x += newRepPtr->dx;
236 		if (pmu.scrInfo.mouse.x > pmu.scrInfo.max_cur_x)
237 			pmu.scrInfo.mouse.x = pmu.scrInfo.max_cur_x;
238 	} else {
239 		pmu.scrInfo.mouse.x -= newRepPtr->dx;
240 		if (pmu.scrInfo.mouse.x < pmu.scrInfo.min_cur_x)
241 			pmu.scrInfo.mouse.x = pmu.scrInfo.min_cur_x;
242 	}
243 	if (newRepPtr->state & MOUSE_Y_SIGN) {
244 		pmu.scrInfo.mouse.y -= newRepPtr->dy;
245 		if (pmu.scrInfo.mouse.y < pmu.scrInfo.min_cur_y)
246 			pmu.scrInfo.mouse.y = pmu.scrInfo.min_cur_y;
247 	} else {
248 		pmu.scrInfo.mouse.y += newRepPtr->dy;
249 		if (pmu.scrInfo.mouse.y > pmu.scrInfo.max_cur_y)
250 			pmu.scrInfo.mouse.y = pmu.scrInfo.max_cur_y;
251 	}
252 
253 	/*
254 	 * Move the hardware cursor.
255 	 */
256 	PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y);
257 
258 	/*
259 	 * Store the motion event in the motion buffer.
260 	 */
261 	pmu.tcs[pmu.scrInfo.qe.tcNext].time = milliSec;
262 	pmu.tcs[pmu.scrInfo.qe.tcNext].x = pmu.scrInfo.mouse.x;
263 	pmu.tcs[pmu.scrInfo.qe.tcNext].y = pmu.scrInfo.mouse.y;
264 	if (++pmu.scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE)
265 		pmu.scrInfo.qe.tcNext = 0;
266 	if (pmu.scrInfo.mouse.y < pmu.scrInfo.mbox.bottom &&
267 	    pmu.scrInfo.mouse.y >=  pmu.scrInfo.mbox.top &&
268 	    pmu.scrInfo.mouse.x < pmu.scrInfo.mbox.right &&
269 	    pmu.scrInfo.mouse.x >=  pmu.scrInfo.mbox.left)
270 		return;
271 
272 	pmu.scrInfo.mbox.bottom = 0;
273 	if (PM_EVROUND(pmu.scrInfo.qe.eTail + 1) == pmu.scrInfo.qe.eHead)
274 		return;
275 
276 	i = PM_EVROUND(pmu.scrInfo.qe.eTail - 1);
277 	if ((pmu.scrInfo.qe.eTail != pmu.scrInfo.qe.eHead) &&
278 	    (i != pmu.scrInfo.qe.eHead)) {
279 		pmEvent *eventPtr;
280 
281 		eventPtr = &pmu.events[i];
282 		if (eventPtr->type == MOTION_TYPE) {
283 			eventPtr->x = pmu.scrInfo.mouse.x;
284 			eventPtr->y = pmu.scrInfo.mouse.y;
285 			eventPtr->time = milliSec;
286 			eventPtr->device = MOUSE_DEVICE;
287 			return;
288 		}
289 	}
290 	/*
291 	 * Put event into queue and wakeup any waiters.
292 	 */
293 	eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
294 	eventPtr->type = MOTION_TYPE;
295 	eventPtr->time = milliSec;
296 	eventPtr->x = pmu.scrInfo.mouse.x;
297 	eventPtr->y = pmu.scrInfo.mouse.y;
298 	eventPtr->device = MOUSE_DEVICE;
299 	pmu.scrInfo.qe.eTail = PM_EVROUND(pmu.scrInfo.qe.eTail + 1);
300 	selwakeup(&pm_selp);
301 }
302 
303 /*
304  *----------------------------------------------------------------------
305  *
306  * pmMouseButtons --
307  *
308  *	Process mouse buttons.
309  *
310  * Results:
311  *	None.
312  *
313  * Side effects:
314  *	None.
315  *
316  *----------------------------------------------------------------------
317  */
318 void
319 pmMouseButtons(newRepPtr)
320 	MouseReport *newRepPtr;
321 {
322 	static char temp, oldSwitch, newSwitch;
323 	int i, j;
324 	pmEvent *eventPtr;
325 	static MouseReport lastRep;
326 
327 	if (!GraphicsOpen)
328 		return;
329 
330 	newSwitch = newRepPtr->state & 0x07;
331 	oldSwitch = lastRep.state & 0x07;
332 
333 	temp = oldSwitch ^ newSwitch;
334 	if (temp == 0)
335 		return;
336 	for (j = 1; j < 8; j <<= 1) {
337 		if ((j & temp) == 0)
338 			continue;
339 
340 		/*
341 		 * Check for room in the queue
342 		 */
343 		i = PM_EVROUND(pmu.scrInfo.qe.eTail+1);
344 		if (i == pmu.scrInfo.qe.eHead)
345 			return;
346 
347 		/*
348 		 * Put event into queue.
349 		 */
350 		eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
351 
352 		switch (j) {
353 		case RIGHT_BUTTON:
354 			eventPtr->key = EVENT_RIGHT_BUTTON;
355 			break;
356 
357 		case MIDDLE_BUTTON:
358 			eventPtr->key = EVENT_MIDDLE_BUTTON;
359 			break;
360 
361 		case LEFT_BUTTON:
362 			eventPtr->key = EVENT_LEFT_BUTTON;
363 		}
364 		if (newSwitch & j)
365 			eventPtr->type = BUTTON_DOWN_TYPE;
366 		else
367 			eventPtr->type = BUTTON_UP_TYPE;
368 		eventPtr->device = MOUSE_DEVICE;
369 
370 		eventPtr->time = TO_MS(time);
371 		eventPtr->x = pmu.scrInfo.mouse.x;
372 		eventPtr->y = pmu.scrInfo.mouse.y;
373 	}
374 	pmu.scrInfo.qe.eTail = i;
375 	selwakeup(&pm_selp);
376 
377 	lastRep = *newRepPtr;
378 	pmu.scrInfo.mswitches = newSwitch;
379 }
380 
381 /*
382  *----------------------------------------------------------------------
383  *
384  * Scroll --
385  *
386  *	Scroll the screen.
387  *
388  * Results:
389  *	None.
390  *
391  * Side effects:
392  *	None.
393  *
394  *----------------------------------------------------------------------
395  */
396 static void
397 Scroll()
398 {
399 	register int *dest, *src;
400 	register int *end;
401 	register int temp0, temp1, temp2, temp3;
402 	register int i, scanInc, lineCount;
403 	int line;
404 
405 	/*
406 	 * If the mouse is on we don't scroll so that the bit map remains sane.
407 	 */
408 	if (GraphicsOpen) {
409 		row = 0;
410 		return;
411 	}
412 
413 	/*
414 	 *  The following is an optimization to cause the scrolling
415 	 *  of text to be memory limited.  Basically the writebuffer is
416 	 *  4 words (32 bits ea.) long so to achieve maximum speed we
417 	 *  read and write in multiples of 4 words. We also limit the
418 	 *  size to be MAX_COL characters for more speed.
419 	 */
420 	if (isMono) {
421 		lineCount = 5;
422 		line = 1920 * 2;
423 		scanInc = 44;
424 	} else {
425 		lineCount = 40;
426 		scanInc = 96;
427 		line = 1920 * 8;
428 	}
429 	src = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR + line);
430 	dest = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR);
431 	end = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR + (60 * line) - line);
432 	do {
433 		i = 0;
434 		do {
435 			temp0 = src[0];
436 			temp1 = src[1];
437 			temp2 = src[2];
438 			temp3 = src[3];
439 			dest[0] = temp0;
440 			dest[1] = temp1;
441 			dest[2] = temp2;
442 			dest[3] = temp3;
443 			dest += 4;
444 			src += 4;
445 			i++;
446 		} while (i < lineCount);
447 		src += scanInc;
448 		dest += scanInc;
449 	} while (src < end);
450 
451 	/*
452 	 * Now zero out the last two lines
453 	 */
454 	bzero(MACH_UNCACHED_FRAME_BUFFER_ADDR + (row * line), 3 * line);
455 }
456 
457 /*
458  *----------------------------------------------------------------------
459  *
460  * pmPutc --
461  *
462  *	Write a character to the console.
463  *
464  * Results:
465  *	None.
466  *
467  * Side effects:
468  *	None.
469  *
470  *----------------------------------------------------------------------
471  */
472 pmPutc(c)
473 	register int c;
474 {
475 	int s;
476 
477 	s = splhigh();	/* in case we do any printf's at interrupt time */
478 	if (initialized) {
479 #ifdef DEBUG
480 		/*
481 		 * If the HELP key is pressed, wait for another
482 		 * HELP key press to start/stop output.
483 		 */
484 		if (dcDebugGetc() == LK_HELP) {
485 			while (dcDebugGetc() != LK_HELP)
486 				;
487 		}
488 #endif
489 		Blitc(c);
490 	} else {
491 		void (*f)() = (void (*)())MACH_MON_PUTCHAR;
492 
493 		(*f)(c);
494 	}
495 	splx(s);
496 }
497 
498 /*
499  *----------------------------------------------------------------------
500  *
501  * Blitc --
502  *
503  *	Write a character to the screen.
504  *
505  * Results:
506  *	None.
507  *
508  * Side effects:
509  *	None.
510  *
511  *----------------------------------------------------------------------
512  */
513 static void
514 Blitc(c)
515 	register int c;
516 {
517 	register char *bRow, *fRow;
518 	register int i;
519 	register int ote = isMono ? 256 : 1024; /* offset to table entry */
520 	int colMult = isMono ? 1 : 8;
521 
522 	c &= 0xff;
523 
524 	switch (c) {
525 	case '\t':
526 		for (i = 8 - (col & 0x7); i > 0; i--)
527 			Blitc(' ');
528 		break;
529 
530 	case '\r':
531 		col = 0;
532 		break;
533 
534 	case '\b':
535 		col--;
536 		if (col < 0)
537 			col = 0;
538 		break;
539 
540 	case '\n':
541 		if (row + 1 >= MAX_ROW)
542 			Scroll();
543 		else
544 			row++;
545 		col = 0;
546 		break;
547 
548 	case '\007':
549 		dcKBDPutc(LK_RING_BELL);
550 		break;
551 
552 	default:
553 		/*
554 		 * 0xA1 to 0xFD are the printable characters added with 8-bit
555 		 * support.
556 		 */
557 		if (c < ' ' || c > '~' && c < 0xA1 || c > 0xFD)
558 			break;
559 		/*
560 		 * If the next character will wrap around then
561 		 * increment row counter or scroll screen.
562 		 */
563 		if (col >= MAX_COL) {
564 			col = 0;
565 			if (row + 1 >= MAX_ROW)
566 				Scroll();
567 			else
568 				row++;
569 		}
570 		bRow = (char *)(MACH_UNCACHED_FRAME_BUFFER_ADDR +
571 			(row * 15 & 0x3ff) * ote + col * colMult);
572 		i = c - ' ';
573 		/*
574 		 * This is to skip the (32) 8-bit
575 		 * control chars, as well as DEL
576 		 * and 0xA0 which aren't printable
577 		 */
578 		if (c > '~')
579 			i -= 34;
580 		i *= 15;
581 		fRow = (char *)((int)pmFont + i);
582 
583 		/* inline expansion for speed */
584 		if (isMono) {
585 			*bRow = *fRow++; bRow += ote;
586 			*bRow = *fRow++; bRow += ote;
587 			*bRow = *fRow++; bRow += ote;
588 			*bRow = *fRow++; bRow += ote;
589 			*bRow = *fRow++; bRow += ote;
590 			*bRow = *fRow++; bRow += ote;
591 			*bRow = *fRow++; bRow += ote;
592 			*bRow = *fRow++; bRow += ote;
593 			*bRow = *fRow++; bRow += ote;
594 			*bRow = *fRow++; bRow += ote;
595 			*bRow = *fRow++; bRow += ote;
596 			*bRow = *fRow++; bRow += ote;
597 			*bRow = *fRow++; bRow += ote;
598 			*bRow = *fRow++; bRow += ote;
599 			*bRow = *fRow++; bRow += ote;
600 		} else {
601 			register int j;
602 			register unsigned int *pInt;
603 
604 			pInt = (unsigned int *)bRow;
605 			for (j = 0; j < 15; j++) {
606 				/*
607 				 * fontmaskBits converts a nibble
608 				 * (4 bytes) to a long word
609 				 * containing 4 pixels corresponding
610 				 * to each bit in the nibble.  Thus
611 				 * we write two longwords for each
612 				 * byte in font.
613 				 *
614 				 * Remember the font is 8 bits wide
615 				 * and 15 bits high.
616 				 *
617 				 * We add 256 to the pointer to
618 				 * point to the pixel on the
619 				 * next scan line
620 				 * directly below the current
621 				 * pixel.
622 				 */
623 				pInt[0] = fontmaskBits[(*fRow) & 0xf];
624 				pInt[1] = fontmaskBits[((*fRow) >> 4) & 0xf];
625 				fRow++;
626 				pInt += 256;
627 			}
628 		}
629 		col++; /* increment column counter */
630 	}
631 	if (!GraphicsOpen)
632 		PosCursor(col * 8, row * 15);
633 }
634 
635 /*ARGSUSED*/
636 pmopen(dev, flag)
637 	dev_t dev;
638 	int flag;
639 {
640 	int s;
641 
642 	if (!initialized)
643 		return (ENXIO);
644 	if (GraphicsOpen)
645 		return (EBUSY);
646 
647 	GraphicsOpen = 1;
648 	if (!isMono)
649 		InitColorMap();
650 	/*
651 	 * Set up event queue for later
652 	 */
653 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
654 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
655 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
656 	pmu.scrInfo.qe.tcNext = 0;
657 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
658 	s = spltty();
659 	dcDivertXInput = pmKbdEvent;
660 	dcMouseEvent = pmMouseEvent;
661 	dcMouseButtons = pmMouseButtons;
662 	splx(s);
663 	return (0);
664 }
665 
666 /*ARGSUSED*/
667 pmclose(dev, flag)
668 	dev_t dev;
669 	int flag;
670 {
671 	int s;
672 
673 	if (!GraphicsOpen)
674 		return (EBADF);
675 
676 	GraphicsOpen = 0;
677 	if (!isMono)
678 		InitColorMap();
679 	s = spltty();
680 	dcDivertXInput = (void (*)())0;
681 	dcMouseEvent = (void (*)())0;
682 	dcMouseButtons = (void (*)())0;
683 	splx(s);
684 	ScreenInit();
685 	vmUserUnmap();
686 	bzero((caddr_t)MACH_UNCACHED_FRAME_BUFFER_ADDR,
687 		(isMono ? 1024 / 8 : 1024) * 864);
688 	PosCursor(col * 8, row * 15);
689 	return (0);
690 }
691 
692 /*ARGSUSED*/
693 pmioctl(dev, cmd, data, flag)
694 	dev_t dev;
695 	caddr_t data;
696 {
697 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
698 	int s;
699 
700 	switch (cmd) {
701 	case QIOCGINFO:
702 	    {
703 		caddr_t addr;
704 		extern caddr_t vmUserMap();
705 
706 		/*
707 		 * Map the all the data the user needs access to into
708 		 * user space.
709 		 */
710 		addr = vmUserMap(sizeof(pmu), (unsigned)&pmu);
711 		if (addr == (caddr_t)0)
712 			goto mapError;
713 		*(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo;
714 		pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events;
715 		pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs;
716 		/*
717 		 * Map the plane mask into the user's address space.
718 		 */
719 		addr = vmUserMap(4, (unsigned)MACH_PLANE_MASK_ADDR);
720 		if (addr == (caddr_t)0)
721 			goto mapError;
722 		pmu.scrInfo.planemask = (char *)addr;
723 		/*
724 		 * Map the frame buffer into the user's address space.
725 		 */
726 		addr = vmUserMap(isMono ? 256*1024 : 1024*1024,
727 			(unsigned)MACH_UNCACHED_FRAME_BUFFER_ADDR);
728 		if (addr == (caddr_t)0)
729 			goto mapError;
730 		pmu.scrInfo.bitmap = (char *)addr;
731 		break;
732 
733 	mapError:
734 		vmUserUnmap();
735 		printf("Cannot map shared data structures\n");
736 		return (EIO);
737 	    }
738 
739 	case QIOCPMSTATE:
740 		/*
741 		 * Set mouse state.
742 		 */
743 		pmu.scrInfo.mouse = *(pmCursor *)data;
744 		PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y);
745 		break;
746 
747 	case QIOCINIT:
748 		/*
749 		 * Initialize the screen.
750 		 */
751 		ScreenInit();
752 		break;
753 
754 	case QIOCKPCMD:
755 	    {
756 		pmKpCmd *kpCmdPtr;
757 		unsigned char *cp;
758 
759 		kpCmdPtr = (pmKpCmd *)data;
760 		if (kpCmdPtr->nbytes == 0)
761 			kpCmdPtr->cmd |= 0x80;
762 		if (!GraphicsOpen)
763 			kpCmdPtr->cmd |= 1;
764 		dcKBDPutc((int)kpCmdPtr->cmd);
765 		cp = &kpCmdPtr->par[0];
766 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
767 			if (kpCmdPtr->nbytes == 1)
768 				*cp |= 0x80;
769 			dcKBDPutc((int)*cp);
770 		}
771 		break;
772 	    }
773 
774 	case QIOCADDR:
775 		*(PM_Info **)data = &pmu.scrInfo;
776 		break;
777 
778 	case QIOWCURSOR:
779 		LoadCursor((unsigned short *)data);
780 		break;
781 
782 	case QIOWCURSORCOLOR:
783 		CursorColor((unsigned int *)data);
784 		break;
785 
786 	case QIOSETCMAP:
787 		LoadColorMap((ColorMap *)data);
788 		break;
789 
790 	case QIOKERNLOOP:
791 		s = spltty();
792 		dcDivertXInput = pmKbdEvent;
793 		dcMouseEvent = pmMouseEvent;
794 		dcMouseButtons = pmMouseButtons;
795 		splx(s);
796 		break;
797 
798 	case QIOKERNUNLOOP:
799 		s = spltty();
800 		dcDivertXInput = (void (*)())0;
801 		dcMouseEvent = (void (*)())0;
802 		dcMouseButtons = (void (*)())0;
803 		splx(s);
804 		break;
805 
806 	case QIOVIDEOON:
807 		if (!isMono)
808 			RestoreCursorColor();
809 		curReg |= PCC_ENPA;
810 		curReg &= ~PCC_FOPB;
811 		pcc->cmdr = curReg;
812 		break;
813 
814 	case QIOVIDEOOFF:
815 		if (!isMono)
816 			VDACInit();
817 		curReg |= PCC_FOPB;
818 		curReg &= ~PCC_ENPA;
819 		pcc->cmdr = curReg;
820 		break;
821 
822 	default:
823 		printf("pm0: Unknown ioctl command %x\n", cmd);
824 		return (EINVAL);
825 	}
826 	return (0);
827 }
828 
829 pmselect(dev, flag, p)
830 	dev_t dev;
831 	int flag;
832 	struct proc *p;
833 {
834 
835 	switch (flag) {
836 	case FREAD:
837 		if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail)
838 			return (1);
839 		selrecord(p, &pm_selp);
840 		break;
841 	}
842 
843 	return (0);
844 }
845 
846 static u_char	bg_RGB[3];	/* background color for the cursor */
847 static u_char	fg_RGB[3];	/* foreground color for the cursor */
848 
849 /*
850  * The default cursor.
851  */
852 unsigned short defCursor[32] = {
853 /* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
854 	      0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
855 /* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
856               0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
857 
858 };
859 
860 /*
861  * Test to see if device is present.
862  * Return true if found and initialized ok.
863  */
864 pminit()
865 {
866 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
867 
868 	isMono = *(u_short *)MACH_SYS_CSR_ADDR & MACH_CSR_MONO;
869 	if (isMono) {
870 		/* check for no frame buffer */
871 		if (badaddr((char *)MACH_UNCACHED_FRAME_BUFFER_ADDR, 4))
872 			return (0);
873 	}
874 
875 	/*
876 	 * Initialize the screen.
877 	 */
878 	pcc->cmdr = PCC_FOPB | PCC_VBHI;
879 
880 	/*
881 	 * Initialize the cursor register.
882 	 */
883 	pcc->cmdr = curReg = PCC_ENPA | PCC_ENPB;
884 
885 	/*
886 	 * Initialize screen info.
887 	 */
888 	pmu.scrInfo.max_row = 56;
889 	pmu.scrInfo.max_col = 80;
890 	pmu.scrInfo.max_x = 1024;
891 	pmu.scrInfo.max_y = 864;
892 	pmu.scrInfo.max_cur_x = 1023;
893 	pmu.scrInfo.max_cur_y = 863;
894 	pmu.scrInfo.version = 11;
895 	pmu.scrInfo.mthreshold = 4;
896 	pmu.scrInfo.mscale = 2;
897 	pmu.scrInfo.min_cur_x = -15;
898 	pmu.scrInfo.min_cur_y = -15;
899 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
900 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
901 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
902 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
903 	pmu.scrInfo.qe.tcNext = 0;
904 
905 	/*
906 	 * Initialize the color map, the screen, and the mouse.
907 	 */
908 	InitColorMap();
909 	ScreenInit();
910 	Scroll();
911 
912 	initialized = 1;
913 	return (1);
914 }
915 
916 /*
917  * ----------------------------------------------------------------------------
918  *
919  * ScreenInit --
920  *
921  *	Initialize the screen.
922  *
923  * Results:
924  *	None.
925  *
926  * Side effects:
927  *	The screen is initialized.
928  *
929  * ----------------------------------------------------------------------------
930  */
931 static void
932 ScreenInit()
933 {
934 
935 	/*
936 	 * Home the cursor.
937 	 * We want an LSI terminal emulation.  We want the graphics
938 	 * terminal to scroll from the bottom. So start at the bottom.
939 	 */
940 	row = 55;
941 	col = 0;
942 
943 	/*
944 	 * Load the cursor with the default values
945 	 *
946 	 */
947 	LoadCursor(defCursor);
948 }
949 
950 /*
951  * ----------------------------------------------------------------------------
952  *
953  * LoadCursor --
954  *
955  *	Routine to load the cursor Sprite pattern.
956  *
957  * Results:
958  *	None.
959  *
960  * Side effects:
961  *	The cursor is loaded into the hardware cursor.
962  *
963  * ----------------------------------------------------------------------------
964  */
965 static void
966 LoadCursor(cur)
967 	unsigned short *cur;
968 {
969 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
970 	register int i;
971 
972 	curReg |= PCC_LODSA;
973 	pcc->cmdr = curReg;
974 	for (i = 0; i < 32; i++) {
975 		pcc->memory = cur[i];
976 		MachEmptyWriteBuffer();
977 	}
978 	curReg &= ~PCC_LODSA;
979 	pcc->cmdr = curReg;
980 }
981 
982 /*
983  * ----------------------------------------------------------------------------
984  *
985  * RestoreCursorColor --
986  *
987  *	Routine to restore the color of the cursor.
988  *
989  * Results:
990  *	None.
991  *
992  * Side effects:
993  *	None.
994  *
995  * ----------------------------------------------------------------------------
996  */
997 static void
998 RestoreCursorColor()
999 {
1000 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1001 	register int i;
1002 
1003 	vdac->overWA = 0x04;
1004 	MachEmptyWriteBuffer();
1005 	for (i = 0; i < 3; i++) {
1006 		vdac->over = bg_RGB[i];
1007 		MachEmptyWriteBuffer();
1008 	}
1009 
1010 	vdac->overWA = 0x08;
1011 	MachEmptyWriteBuffer();
1012 	vdac->over = 0x00;
1013 	MachEmptyWriteBuffer();
1014 	vdac->over = 0x00;
1015 	MachEmptyWriteBuffer();
1016 	vdac->over = 0x7f;
1017 	MachEmptyWriteBuffer();
1018 
1019 	vdac->overWA = 0x0c;
1020 	MachEmptyWriteBuffer();
1021 	for (i = 0; i < 3; i++) {
1022 		vdac->over = fg_RGB[i];
1023 		MachEmptyWriteBuffer();
1024 	}
1025 }
1026 
1027 /*
1028  * ----------------------------------------------------------------------------
1029  *
1030  * CursorColor --
1031  *
1032  *	Set the color of the cursor.
1033  *
1034  * Results:
1035  *	None.
1036  *
1037  * Side effects:
1038  *	None.
1039  *
1040  * ----------------------------------------------------------------------------
1041  */
1042 static void
1043 CursorColor(color)
1044 	unsigned int color[];
1045 {
1046 	register int i, j;
1047 
1048 	for (i = 0; i < 3; i++)
1049 		bg_RGB[i] = (u_char)(color[i] >> 8);
1050 
1051 	for (i = 3, j = 0; i < 6; i++, j++)
1052 		fg_RGB[j] = (u_char)(color[i] >> 8);
1053 
1054 	RestoreCursorColor();
1055 }
1056 
1057 /*
1058  * ----------------------------------------------------------------------------
1059  *
1060  * InitColorMap --
1061  *
1062  *	Initialize the color map.
1063  *
1064  * Results:
1065  *	None.
1066  *
1067  * Side effects:
1068  *	The colormap is initialized appropriately whether it is color or
1069  *	monochrome.
1070  *
1071  * ----------------------------------------------------------------------------
1072  */
1073 static void
1074 InitColorMap()
1075 {
1076 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1077 	register int i;
1078 
1079 	*(char *)MACH_PLANE_MASK_ADDR = 0xff;
1080 	MachEmptyWriteBuffer();
1081 
1082 	if (isMono) {
1083 		vdac->mapWA = 0; MachEmptyWriteBuffer();
1084 		for (i = 0; i < 256; i++) {
1085 			vdac->map = (i < 128) ? 0x00 : 0xff;
1086 			MachEmptyWriteBuffer();
1087 			vdac->map = (i < 128) ? 0x00 : 0xff;
1088 			MachEmptyWriteBuffer();
1089 			vdac->map = (i < 128) ? 0x00 : 0xff;
1090 			MachEmptyWriteBuffer();
1091 		}
1092 	} else {
1093 		vdac->mapWA = 0; MachEmptyWriteBuffer();
1094 		vdac->map = 0; MachEmptyWriteBuffer();
1095 		vdac->map = 0; MachEmptyWriteBuffer();
1096 		vdac->map = 0; MachEmptyWriteBuffer();
1097 
1098 		for (i = 1; i < 256; i++) {
1099 			vdac->map = 0xff; MachEmptyWriteBuffer();
1100 			vdac->map = 0xff; MachEmptyWriteBuffer();
1101 			vdac->map = 0xff; MachEmptyWriteBuffer();
1102 		}
1103 	}
1104 
1105 	for (i = 0; i < 3; i++) {
1106 		bg_RGB[i] = 0x00;
1107 		fg_RGB[i] = 0xff;
1108 	}
1109 	RestoreCursorColor();
1110 }
1111 
1112 /*
1113  * ----------------------------------------------------------------------------
1114  *
1115  * VDACInit --
1116  *
1117  *	Initialize the VDAC.
1118  *
1119  * Results:
1120  *	None.
1121  *
1122  * Side effects:
1123  *	None.
1124  *
1125  * ----------------------------------------------------------------------------
1126  */
1127 static void
1128 VDACInit()
1129 {
1130 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1131 
1132 	/*
1133 	 *
1134 	 * Initialize the VDAC
1135 	 */
1136 	vdac->overWA = 0x04; MachEmptyWriteBuffer();
1137 	vdac->over = 0x00; MachEmptyWriteBuffer();
1138 	vdac->over = 0x00; MachEmptyWriteBuffer();
1139 	vdac->over = 0x00; MachEmptyWriteBuffer();
1140 	vdac->overWA = 0x08; MachEmptyWriteBuffer();
1141 	vdac->over = 0x00; MachEmptyWriteBuffer();
1142 	vdac->over = 0x00; MachEmptyWriteBuffer();
1143 	vdac->over = 0x7f; MachEmptyWriteBuffer();
1144 	vdac->overWA = 0x0c; MachEmptyWriteBuffer();
1145 	vdac->over = 0xff; MachEmptyWriteBuffer();
1146 	vdac->over = 0xff; MachEmptyWriteBuffer();
1147 	vdac->over = 0xff; MachEmptyWriteBuffer();
1148 }
1149 
1150 /*
1151  * ----------------------------------------------------------------------------
1152  *
1153  * LoadColorMap --
1154  *
1155  *	Load the color map.
1156  *
1157  * Results:
1158  *	None.
1159  *
1160  * Side effects:
1161  *	The color map is loaded.
1162  *
1163  * ----------------------------------------------------------------------------
1164  */
1165 static void
1166 LoadColorMap(ptr)
1167 	ColorMap *ptr;
1168 {
1169 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1170 
1171 	if (ptr->index > 256)
1172 		return;
1173 
1174 	vdac->mapWA = ptr->index; MachEmptyWriteBuffer();
1175 	vdac->map = ptr->Entry.red; MachEmptyWriteBuffer();
1176 	vdac->map = ptr->Entry.green; MachEmptyWriteBuffer();
1177 	vdac->map = ptr->Entry.blue; MachEmptyWriteBuffer();
1178 }
1179 
1180 /*
1181  *----------------------------------------------------------------------
1182  *
1183  * PosCursor --
1184  *
1185  *	Postion the cursor.
1186  *
1187  * Results:
1188  *	None.
1189  *
1190  * Side effects:
1191  *	None.
1192  *
1193  *----------------------------------------------------------------------
1194  */
1195 static void
1196 PosCursor(x, y)
1197 	register int x, y;
1198 {
1199 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
1200 
1201 	if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y)
1202 		y = pmu.scrInfo.max_cur_y;
1203 	if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x)
1204 		x = pmu.scrInfo.max_cur_x;
1205 	pmu.scrInfo.cursor.x = x;		/* keep track of real cursor */
1206 	pmu.scrInfo.cursor.y = y;		/* position, indep. of mouse */
1207 	pcc->xpos = PCC_X_OFFSET + x;
1208 	pcc->ypos = PCC_Y_OFFSET + y;
1209 }
1210 #endif
1211