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