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