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