xref: /original-bsd/sys/pmax/dev/pm.c (revision 753853ba)
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.4 (Berkeley) 03/15/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 
641 	if (!initialized)
642 		return (ENXIO);
643 	if (GraphicsOpen)
644 		return (EBUSY);
645 
646 	GraphicsOpen = 1;
647 	if (!isMono)
648 		InitColorMap();
649 	/*
650 	 * Set up event queue for later
651 	 */
652 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
653 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
654 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
655 	pmu.scrInfo.qe.tcNext = 0;
656 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
657 	return (0);
658 }
659 
660 /*ARGSUSED*/
661 pmclose(dev, flag)
662 	dev_t dev;
663 	int flag;
664 {
665 	int s;
666 
667 	if (!GraphicsOpen)
668 		return (EBADF);
669 
670 	GraphicsOpen = 0;
671 	if (!isMono)
672 		InitColorMap();
673 	s = spltty();
674 	dcDivertXInput = (void (*)())0;
675 	dcMouseEvent = (void (*)())0;
676 	dcMouseButtons = (void (*)())0;
677 	splx(s);
678 	ScreenInit();
679 	vmUserUnmap();
680 	bzero((caddr_t)MACH_UNCACHED_FRAME_BUFFER_ADDR,
681 		(isMono ? 1024 / 8 : 1024) * 864);
682 	PosCursor(col * 8, row * 15);
683 	return (0);
684 }
685 
686 /*ARGSUSED*/
687 pmioctl(dev, cmd, data, flag)
688 	dev_t dev;
689 	caddr_t data;
690 {
691 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
692 	int s;
693 
694 	switch (cmd) {
695 	case QIOCGINFO:
696 	    {
697 		caddr_t addr;
698 		extern caddr_t vmUserMap();
699 
700 		/*
701 		 * Map the all the data the user needs access to into
702 		 * user space.
703 		 */
704 		addr = vmUserMap(sizeof(pmu), (unsigned)&pmu);
705 		if (addr == (caddr_t)0)
706 			goto mapError;
707 		*(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo;
708 		pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events;
709 		pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs;
710 		/*
711 		 * Map the plane mask into the user's address space.
712 		 */
713 		addr = vmUserMap(4, (unsigned)MACH_PLANE_MASK_ADDR);
714 		if (addr == (caddr_t)0)
715 			goto mapError;
716 		pmu.scrInfo.planemask = (char *)addr;
717 		/*
718 		 * Map the frame buffer into the user's address space.
719 		 */
720 		addr = vmUserMap(isMono ? 256*1024 : 1024*1024,
721 			(unsigned)MACH_UNCACHED_FRAME_BUFFER_ADDR);
722 		if (addr == (caddr_t)0)
723 			goto mapError;
724 		pmu.scrInfo.bitmap = (char *)addr;
725 		break;
726 
727 	mapError:
728 		vmUserUnmap();
729 		printf("Cannot map shared data structures\n");
730 		return (EIO);
731 	    }
732 
733 	case QIOCPMSTATE:
734 		/*
735 		 * Set mouse state.
736 		 */
737 		pmu.scrInfo.mouse = *(pmCursor *)data;
738 		PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y);
739 		break;
740 
741 	case QIOCINIT:
742 		/*
743 		 * Initialize the screen.
744 		 */
745 		ScreenInit();
746 		break;
747 
748 	case QIOCKPCMD:
749 	    {
750 		pmKpCmd *kpCmdPtr;
751 		unsigned char *cp;
752 
753 		kpCmdPtr = (pmKpCmd *)data;
754 		if (kpCmdPtr->nbytes == 0)
755 			kpCmdPtr->cmd |= 0x80;
756 		if (!GraphicsOpen)
757 			kpCmdPtr->cmd |= 1;
758 		dcKBDPutc((int)kpCmdPtr->cmd);
759 		cp = &kpCmdPtr->par[0];
760 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
761 			if (kpCmdPtr->nbytes == 1)
762 				*cp |= 0x80;
763 			dcKBDPutc((int)*cp);
764 		}
765 		break;
766 	    }
767 
768 	case QIOCADDR:
769 		*(PM_Info **)data = &pmu.scrInfo;
770 		break;
771 
772 	case QIOWCURSOR:
773 		LoadCursor((unsigned short *)data);
774 		break;
775 
776 	case QIOWCURSORCOLOR:
777 		CursorColor((unsigned int *)data);
778 		break;
779 
780 	case QIOSETCMAP:
781 		LoadColorMap((ColorMap *)data);
782 		break;
783 
784 	case QIOKERNLOOP:
785 		s = spltty();
786 		dcDivertXInput = pmKbdEvent;
787 		dcMouseEvent = pmMouseEvent;
788 		dcMouseButtons = pmMouseButtons;
789 		splx(s);
790 		break;
791 
792 	case QIOKERNUNLOOP:
793 		s = spltty();
794 		dcDivertXInput = (void (*)())0;
795 		dcMouseEvent = (void (*)())0;
796 		dcMouseButtons = (void (*)())0;
797 		splx(s);
798 		break;
799 
800 	case QIOVIDEOON:
801 		if (!isMono)
802 			RestoreCursorColor();
803 		curReg |= PCC_ENPA;
804 		curReg &= ~PCC_FOPB;
805 		pcc->cmdr = curReg;
806 		break;
807 
808 	case QIOVIDEOOFF:
809 		if (!isMono)
810 			VDACInit();
811 		curReg |= PCC_FOPB;
812 		curReg &= ~PCC_ENPA;
813 		pcc->cmdr = curReg;
814 		break;
815 
816 	default:
817 		printf("pm0: Unknown ioctl command %x\n", cmd);
818 		return (EINVAL);
819 	}
820 	return (0);
821 }
822 
823 pmselect(dev, flag, p)
824 	dev_t dev;
825 	int flag;
826 	struct proc *p;
827 {
828 
829 	switch (flag) {
830 	case FREAD:
831 		if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail)
832 			return (1);
833 		selrecord(p, &pm_selp);
834 		break;
835 	}
836 
837 	return (0);
838 }
839 
840 static u_char	bg_RGB[3];	/* background color for the cursor */
841 static u_char	fg_RGB[3];	/* foreground color for the cursor */
842 
843 /*
844  * The default cursor.
845  */
846 unsigned short defCursor[32] = {
847 /* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
848 	      0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
849 /* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
850               0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
851 
852 };
853 
854 /*
855  * Test to see if device is present.
856  * Return true if found and initialized ok.
857  */
858 pminit()
859 {
860 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
861 
862 	isMono = *(u_short *)MACH_SYS_CSR_ADDR & MACH_CSR_MONO;
863 	if (isMono) {
864 		/* check for no frame buffer */
865 		if (badaddr((char *)MACH_UNCACHED_FRAME_BUFFER_ADDR, 4))
866 			return (0);
867 	}
868 
869 	/*
870 	 * Initialize the screen.
871 	 */
872 	pcc->cmdr = PCC_FOPB | PCC_VBHI;
873 
874 	/*
875 	 * Initialize the cursor register.
876 	 */
877 	pcc->cmdr = curReg = PCC_ENPA | PCC_ENPB;
878 
879 	/*
880 	 * Initialize screen info.
881 	 */
882 	pmu.scrInfo.max_row = 56;
883 	pmu.scrInfo.max_col = 80;
884 	pmu.scrInfo.max_x = 1024;
885 	pmu.scrInfo.max_y = 864;
886 	pmu.scrInfo.max_cur_x = 1023;
887 	pmu.scrInfo.max_cur_y = 863;
888 	pmu.scrInfo.version = 11;
889 	pmu.scrInfo.mthreshold = 4;
890 	pmu.scrInfo.mscale = 2;
891 	pmu.scrInfo.min_cur_x = -15;
892 	pmu.scrInfo.min_cur_y = -15;
893 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
894 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
895 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
896 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
897 	pmu.scrInfo.qe.tcNext = 0;
898 
899 	/*
900 	 * Initialize the color map, the screen, and the mouse.
901 	 */
902 	InitColorMap();
903 	ScreenInit();
904 	Scroll();
905 
906 	initialized = 1;
907 	return (1);
908 }
909 
910 /*
911  * ----------------------------------------------------------------------------
912  *
913  * ScreenInit --
914  *
915  *	Initialize the screen.
916  *
917  * Results:
918  *	None.
919  *
920  * Side effects:
921  *	The screen is initialized.
922  *
923  * ----------------------------------------------------------------------------
924  */
925 static void
926 ScreenInit()
927 {
928 
929 	/*
930 	 * Home the cursor.
931 	 * We want an LSI terminal emulation.  We want the graphics
932 	 * terminal to scroll from the bottom. So start at the bottom.
933 	 */
934 	row = 55;
935 	col = 0;
936 
937 	/*
938 	 * Load the cursor with the default values
939 	 *
940 	 */
941 	LoadCursor(defCursor);
942 }
943 
944 /*
945  * ----------------------------------------------------------------------------
946  *
947  * LoadCursor --
948  *
949  *	Routine to load the cursor Sprite pattern.
950  *
951  * Results:
952  *	None.
953  *
954  * Side effects:
955  *	The cursor is loaded into the hardware cursor.
956  *
957  * ----------------------------------------------------------------------------
958  */
959 static void
960 LoadCursor(cur)
961 	unsigned short *cur;
962 {
963 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
964 	register int i;
965 
966 	curReg |= PCC_LODSA;
967 	pcc->cmdr = curReg;
968 	for (i = 0; i < 32; i++) {
969 		pcc->memory = cur[i];
970 		MachEmptyWriteBuffer();
971 	}
972 	curReg &= ~PCC_LODSA;
973 	pcc->cmdr = curReg;
974 }
975 
976 /*
977  * ----------------------------------------------------------------------------
978  *
979  * RestoreCursorColor --
980  *
981  *	Routine to restore the color of the cursor.
982  *
983  * Results:
984  *	None.
985  *
986  * Side effects:
987  *	None.
988  *
989  * ----------------------------------------------------------------------------
990  */
991 static void
992 RestoreCursorColor()
993 {
994 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
995 	register int i;
996 
997 	vdac->overWA = 0x04;
998 	MachEmptyWriteBuffer();
999 	for (i = 0; i < 3; i++) {
1000 		vdac->over = bg_RGB[i];
1001 		MachEmptyWriteBuffer();
1002 	}
1003 
1004 	vdac->overWA = 0x08;
1005 	MachEmptyWriteBuffer();
1006 	vdac->over = 0x00;
1007 	MachEmptyWriteBuffer();
1008 	vdac->over = 0x00;
1009 	MachEmptyWriteBuffer();
1010 	vdac->over = 0x7f;
1011 	MachEmptyWriteBuffer();
1012 
1013 	vdac->overWA = 0x0c;
1014 	MachEmptyWriteBuffer();
1015 	for (i = 0; i < 3; i++) {
1016 		vdac->over = fg_RGB[i];
1017 		MachEmptyWriteBuffer();
1018 	}
1019 }
1020 
1021 /*
1022  * ----------------------------------------------------------------------------
1023  *
1024  * CursorColor --
1025  *
1026  *	Set the color of the cursor.
1027  *
1028  * Results:
1029  *	None.
1030  *
1031  * Side effects:
1032  *	None.
1033  *
1034  * ----------------------------------------------------------------------------
1035  */
1036 static void
1037 CursorColor(color)
1038 	unsigned int color[];
1039 {
1040 	register int i, j;
1041 
1042 	for (i = 0; i < 3; i++)
1043 		bg_RGB[i] = (u_char)(color[i] >> 8);
1044 
1045 	for (i = 3, j = 0; i < 6; i++, j++)
1046 		fg_RGB[j] = (u_char)(color[i] >> 8);
1047 
1048 	RestoreCursorColor();
1049 }
1050 
1051 /*
1052  * ----------------------------------------------------------------------------
1053  *
1054  * InitColorMap --
1055  *
1056  *	Initialize the color map.
1057  *
1058  * Results:
1059  *	None.
1060  *
1061  * Side effects:
1062  *	The colormap is initialized appropriately whether it is color or
1063  *	monochrome.
1064  *
1065  * ----------------------------------------------------------------------------
1066  */
1067 static void
1068 InitColorMap()
1069 {
1070 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1071 	register int i;
1072 
1073 	*(char *)MACH_PLANE_MASK_ADDR = 0xff;
1074 	MachEmptyWriteBuffer();
1075 
1076 	if (isMono) {
1077 		vdac->mapWA = 0; MachEmptyWriteBuffer();
1078 		for (i = 0; i < 256; i++) {
1079 			vdac->map = (i < 128) ? 0x00 : 0xff;
1080 			MachEmptyWriteBuffer();
1081 			vdac->map = (i < 128) ? 0x00 : 0xff;
1082 			MachEmptyWriteBuffer();
1083 			vdac->map = (i < 128) ? 0x00 : 0xff;
1084 			MachEmptyWriteBuffer();
1085 		}
1086 	} else {
1087 		vdac->mapWA = 0; MachEmptyWriteBuffer();
1088 		vdac->map = 0; MachEmptyWriteBuffer();
1089 		vdac->map = 0; MachEmptyWriteBuffer();
1090 		vdac->map = 0; MachEmptyWriteBuffer();
1091 
1092 		for (i = 1; i < 256; i++) {
1093 			vdac->map = 0xff; MachEmptyWriteBuffer();
1094 			vdac->map = 0xff; MachEmptyWriteBuffer();
1095 			vdac->map = 0xff; MachEmptyWriteBuffer();
1096 		}
1097 	}
1098 
1099 	for (i = 0; i < 3; i++) {
1100 		bg_RGB[i] = 0x00;
1101 		fg_RGB[i] = 0xff;
1102 	}
1103 	RestoreCursorColor();
1104 }
1105 
1106 /*
1107  * ----------------------------------------------------------------------------
1108  *
1109  * VDACInit --
1110  *
1111  *	Initialize the VDAC.
1112  *
1113  * Results:
1114  *	None.
1115  *
1116  * Side effects:
1117  *	None.
1118  *
1119  * ----------------------------------------------------------------------------
1120  */
1121 static void
1122 VDACInit()
1123 {
1124 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1125 
1126 	/*
1127 	 *
1128 	 * Initialize the VDAC
1129 	 */
1130 	vdac->overWA = 0x04; MachEmptyWriteBuffer();
1131 	vdac->over = 0x00; MachEmptyWriteBuffer();
1132 	vdac->over = 0x00; MachEmptyWriteBuffer();
1133 	vdac->over = 0x00; MachEmptyWriteBuffer();
1134 	vdac->overWA = 0x08; MachEmptyWriteBuffer();
1135 	vdac->over = 0x00; MachEmptyWriteBuffer();
1136 	vdac->over = 0x00; MachEmptyWriteBuffer();
1137 	vdac->over = 0x7f; MachEmptyWriteBuffer();
1138 	vdac->overWA = 0x0c; MachEmptyWriteBuffer();
1139 	vdac->over = 0xff; MachEmptyWriteBuffer();
1140 	vdac->over = 0xff; MachEmptyWriteBuffer();
1141 	vdac->over = 0xff; MachEmptyWriteBuffer();
1142 }
1143 
1144 /*
1145  * ----------------------------------------------------------------------------
1146  *
1147  * LoadColorMap --
1148  *
1149  *	Load the color map.
1150  *
1151  * Results:
1152  *	None.
1153  *
1154  * Side effects:
1155  *	The color map is loaded.
1156  *
1157  * ----------------------------------------------------------------------------
1158  */
1159 static void
1160 LoadColorMap(ptr)
1161 	ColorMap *ptr;
1162 {
1163 	register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR;
1164 
1165 	if (ptr->index > 256)
1166 		return;
1167 
1168 	vdac->mapWA = ptr->index; MachEmptyWriteBuffer();
1169 	vdac->map = ptr->Entry.red; MachEmptyWriteBuffer();
1170 	vdac->map = ptr->Entry.green; MachEmptyWriteBuffer();
1171 	vdac->map = ptr->Entry.blue; MachEmptyWriteBuffer();
1172 }
1173 
1174 /*
1175  *----------------------------------------------------------------------
1176  *
1177  * PosCursor --
1178  *
1179  *	Postion the cursor.
1180  *
1181  * Results:
1182  *	None.
1183  *
1184  * Side effects:
1185  *	None.
1186  *
1187  *----------------------------------------------------------------------
1188  */
1189 static void
1190 PosCursor(x, y)
1191 	register int x, y;
1192 {
1193 	register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR;
1194 
1195 	if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y)
1196 		y = pmu.scrInfo.max_cur_y;
1197 	if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x)
1198 		x = pmu.scrInfo.max_cur_x;
1199 	pmu.scrInfo.cursor.x = x;		/* keep track of real cursor */
1200 	pmu.scrInfo.cursor.y = y;		/* position, indep. of mouse */
1201 	pcc->xpos = PCC_X_OFFSET + x;
1202 	pcc->ypos = PCC_Y_OFFSET + y;
1203 }
1204 #endif
1205