xref: /original-bsd/sys/pmax/dev/cfb.c (revision 3952dc01)
1 /*-
2  * Copyright (c) 1992 The 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  *	@(#)cfb.c	7.1 (Berkeley) 03/09/92
11  */
12 
13 /*
14  *  devGraphics.c --
15  *
16  *     	This file contains machine-dependent routines for the graphics device.
17  *
18  *	Copyright (C) 1989 Digital Equipment Corporation.
19  *	Permission to use, copy, modify, and distribute this software and
20  *	its documentation for any purpose and without fee is hereby granted,
21  *	provided that the above copyright notice appears in all copies.
22  *	Digital Equipment Corporation makes no representations about the
23  *	suitability of this software for any purpose.  It is provided "as is"
24  *	without express or implied warranty.
25  *
26  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
27  *	v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
28  */
29 /*
30  * Mach Operating System
31  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
32  * All Rights Reserved.
33  *
34  * Permission to use, copy, modify and distribute this software and its
35  * documentation is hereby granted, provided that both the copyright
36  * notice and this permission notice appear in all copies of the
37  * software, derivative works or modified versions, and any portions
38  * thereof, and that both notices appear in supporting documentation.
39  *
40  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
41  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
42  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43  *
44  * Carnegie Mellon requests users of this software to return to
45  *
46  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
47  *  School of Computer Science
48  *  Carnegie Mellon University
49  *  Pittsburgh PA 15213-3890
50  *
51  * any improvements or extensions that they make and grant Carnegie the
52  * rights to redistribute these changes.
53  */
54 
55 #include "cfb.h"
56 #if NCFB > 0
57 
58 /*
59  * This is a device driver for the PMAG-BA color frame buffer
60  * on the TURBOchannel.
61  * XXX This is just to get a console working;
62  *	it will need changes to work with X11R5.
63  */
64 
65 #include "param.h"
66 #include "time.h"
67 #include "kernel.h"
68 #include "ioctl.h"
69 #include "file.h"
70 #include "errno.h"
71 #include "proc.h"
72 #include "mman.h"
73 #include "vm/vm.h"
74 
75 #include "machine/machConst.h"
76 #include "machine/machMon.h"
77 #include "machine/dc7085cons.h"
78 #include "machine/pmioctl.h"
79 
80 #include "device.h"
81 #include "cfbreg.h"
82 #include "font.c"
83 
84 #define MAX_ROW	56
85 #define MAX_COL	80
86 
87 /*
88  * Macro to translate from a time struct to milliseconds.
89  */
90 #define TO_MS(tv) ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))
91 
92 static int	isMono;		/* true if B&W frame buffer */
93 static int	initialized;	/* true if 'probe' was successful */
94 static int	GraphicsOpen;	/* true if the graphics device is open */
95 static int	row, col;	/* row and col for console cursor */
96 static struct	selinfo cfb_selp;	/* process waiting for select */
97 static unsigned	fb_addr;	/* frame buffer kernel virtual address */
98 static unsigned	planemask_addr;	/* plane mask kernel virtual address */
99 
100 /*
101  * These need to be mapped into user space.
102  */
103 static struct pmuaccess {
104 	PM_Info		scrInfo;
105 	pmEvent		events[PM_MAXEVQ];
106 	pmTimeCoord	tcs[MOTION_BUFFER_SIZE];
107 } pmu;
108 
109 /*
110  * Font mask bits used by Blitc().
111  */
112 static unsigned int fontmaskBits[16] = {
113 	0x00000000,
114 	0x00000001,
115 	0x00000100,
116 	0x00000101,
117 	0x00010000,
118 	0x00010001,
119 	0x00010100,
120 	0x00010101,
121 	0x01000000,
122 	0x01000001,
123 	0x01000100,
124 	0x01000101,
125 	0x01010000,
126 	0x01010001,
127 	0x01010100,
128 	0x01010101
129 };
130 
131 /*
132  * Forward references.
133  */
134 static void Scroll();
135 static void Blitc();
136 
137 static void ScreenInit();
138 static void LoadCursor();
139 static void RestoreCursorColor();
140 static void CursorColor();
141 static void PosCursor();
142 static void InitColorMap();
143 static void LoadColorMap();
144 static void EnableVideo();
145 static void DisableVideo();
146 
147 extern void dcKBDPutc();
148 extern void (*dcDivertXInput)();
149 extern void (*dcMouseEvent)();
150 extern void (*dcMouseButtons)();
151 
152 int	cfbprobe();
153 struct	driver cfbdriver = {
154 	"cfb", cfbprobe, 0, 0,
155 };
156 
157 /*
158  * Test to see if device is present.
159  * Return true if found and initialized ok.
160  */
161 cfbprobe(cp)
162 	register struct pmax_ctlr *cp;
163 {
164 
165 	if (!initialized) {
166 		if (!cfb_init(cp))
167 			return (0);
168 	}
169 	printf("cfb%d at nexus0 csr 0x%x priority %d\n",
170 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
171 	return (1);
172 }
173 
174 /*
175  *----------------------------------------------------------------------
176  *
177  * cfbKbdEvent --
178  *
179  *	Process a received character.
180  *
181  * Results:
182  *	None.
183  *
184  * Side effects:
185  *	Events added to the queue.
186  *
187  *----------------------------------------------------------------------
188  */
189 void
190 cfbKbdEvent(ch)
191 	int ch;
192 {
193 	register pmEvent *eventPtr;
194 	int i;
195 
196 	if (!GraphicsOpen)
197 		return;
198 
199 	/*
200 	 * See if there is room in the queue.
201 	 */
202 	i = PM_EVROUND(pmu.scrInfo.qe.eTail + 1);
203 	if (i == pmu.scrInfo.qe.eHead)
204 		return;
205 
206 	/*
207 	 * Add the event to the queue.
208 	 */
209 	eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
210 	eventPtr->type = BUTTON_RAW_TYPE;
211 	eventPtr->device = KEYBOARD_DEVICE;
212 	eventPtr->x = pmu.scrInfo.mouse.x;
213 	eventPtr->y = pmu.scrInfo.mouse.y;
214 	eventPtr->time = TO_MS(time);
215 	eventPtr->key = ch;
216 	pmu.scrInfo.qe.eTail = i;
217 	selwakeup(&cfb_selp);
218 }
219 
220 /*
221  *----------------------------------------------------------------------
222  *
223  * cfbMouseEvent --
224  *
225  *	Process a mouse event.
226  *
227  * Results:
228  *	None.
229  *
230  * Side effects:
231  *	An event is added to the event queue.
232  *
233  *----------------------------------------------------------------------
234  */
235 void
236 cfbMouseEvent(newRepPtr)
237 	register MouseReport *newRepPtr;
238 {
239 	unsigned milliSec;
240 	int i;
241 	pmEvent *eventPtr;
242 
243 	if (!GraphicsOpen)
244 		return;
245 
246 	milliSec = TO_MS(time);
247 
248 	/*
249 	 * Check to see if we have to accelerate the mouse
250 	 */
251 	if (pmu.scrInfo.mscale >= 0) {
252 		if (newRepPtr->dx >= pmu.scrInfo.mthreshold) {
253 			newRepPtr->dx +=
254 				(newRepPtr->dx - pmu.scrInfo.mthreshold) *
255 				pmu.scrInfo.mscale;
256 		}
257 		if (newRepPtr->dy >= pmu.scrInfo.mthreshold) {
258 			newRepPtr->dy +=
259 				(newRepPtr->dy - pmu.scrInfo.mthreshold) *
260 				pmu.scrInfo.mscale;
261 		}
262 	}
263 
264 	/*
265 	 * Update mouse position
266 	 */
267 	if (newRepPtr->state & MOUSE_X_SIGN) {
268 		pmu.scrInfo.mouse.x += newRepPtr->dx;
269 		if (pmu.scrInfo.mouse.x > pmu.scrInfo.max_cur_x)
270 			pmu.scrInfo.mouse.x = pmu.scrInfo.max_cur_x;
271 	} else {
272 		pmu.scrInfo.mouse.x -= newRepPtr->dx;
273 		if (pmu.scrInfo.mouse.x < pmu.scrInfo.min_cur_x)
274 			pmu.scrInfo.mouse.x = pmu.scrInfo.min_cur_x;
275 	}
276 	if (newRepPtr->state & MOUSE_Y_SIGN) {
277 		pmu.scrInfo.mouse.y -= newRepPtr->dy;
278 		if (pmu.scrInfo.mouse.y < pmu.scrInfo.min_cur_y)
279 			pmu.scrInfo.mouse.y = pmu.scrInfo.min_cur_y;
280 	} else {
281 		pmu.scrInfo.mouse.y += newRepPtr->dy;
282 		if (pmu.scrInfo.mouse.y > pmu.scrInfo.max_cur_y)
283 			pmu.scrInfo.mouse.y = pmu.scrInfo.max_cur_y;
284 	}
285 
286 	/*
287 	 * Move the hardware cursor.
288 	 */
289 	PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y);
290 
291 	/*
292 	 * Store the motion event in the motion buffer.
293 	 */
294 	pmu.tcs[pmu.scrInfo.qe.tcNext].time = milliSec;
295 	pmu.tcs[pmu.scrInfo.qe.tcNext].x = pmu.scrInfo.mouse.x;
296 	pmu.tcs[pmu.scrInfo.qe.tcNext].y = pmu.scrInfo.mouse.y;
297 	if (++pmu.scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE)
298 		pmu.scrInfo.qe.tcNext = 0;
299 	if (pmu.scrInfo.mouse.y < pmu.scrInfo.mbox.bottom &&
300 	    pmu.scrInfo.mouse.y >=  pmu.scrInfo.mbox.top &&
301 	    pmu.scrInfo.mouse.x < pmu.scrInfo.mbox.right &&
302 	    pmu.scrInfo.mouse.x >=  pmu.scrInfo.mbox.left)
303 		return;
304 
305 	pmu.scrInfo.mbox.bottom = 0;
306 	if (PM_EVROUND(pmu.scrInfo.qe.eTail + 1) == pmu.scrInfo.qe.eHead)
307 		return;
308 
309 	i = PM_EVROUND(pmu.scrInfo.qe.eTail - 1);
310 	if ((pmu.scrInfo.qe.eTail != pmu.scrInfo.qe.eHead) &&
311 	    (i != pmu.scrInfo.qe.eHead)) {
312 		pmEvent *eventPtr;
313 
314 		eventPtr = &pmu.events[i];
315 		if (eventPtr->type == MOTION_TYPE) {
316 			eventPtr->x = pmu.scrInfo.mouse.x;
317 			eventPtr->y = pmu.scrInfo.mouse.y;
318 			eventPtr->time = milliSec;
319 			eventPtr->device = MOUSE_DEVICE;
320 			return;
321 		}
322 	}
323 	/*
324 	 * Put event into queue and wakeup any waiters.
325 	 */
326 	eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
327 	eventPtr->type = MOTION_TYPE;
328 	eventPtr->time = milliSec;
329 	eventPtr->x = pmu.scrInfo.mouse.x;
330 	eventPtr->y = pmu.scrInfo.mouse.y;
331 	eventPtr->device = MOUSE_DEVICE;
332 	pmu.scrInfo.qe.eTail = PM_EVROUND(pmu.scrInfo.qe.eTail + 1);
333 	selwakeup(&cfb_selp);
334 }
335 
336 /*
337  *----------------------------------------------------------------------
338  *
339  * cfbMouseButtons --
340  *
341  *	Process mouse buttons.
342  *
343  * Results:
344  *	None.
345  *
346  * Side effects:
347  *	None.
348  *
349  *----------------------------------------------------------------------
350  */
351 void
352 cfbMouseButtons(newRepPtr)
353 	MouseReport *newRepPtr;
354 {
355 	static char temp, oldSwitch, newSwitch;
356 	int i, j;
357 	pmEvent *eventPtr;
358 	static MouseReport lastRep;
359 
360 	if (!GraphicsOpen)
361 		return;
362 
363 	newSwitch = newRepPtr->state & 0x07;
364 	oldSwitch = lastRep.state & 0x07;
365 
366 	temp = oldSwitch ^ newSwitch;
367 	if (temp == 0)
368 		return;
369 	for (j = 1; j < 8; j <<= 1) {
370 		if ((j & temp) == 0)
371 			continue;
372 
373 		/*
374 		 * Check for room in the queue
375 		 */
376 		i = PM_EVROUND(pmu.scrInfo.qe.eTail+1);
377 		if (i == pmu.scrInfo.qe.eHead)
378 			return;
379 
380 		/*
381 		 * Put event into queue.
382 		 */
383 		eventPtr = &pmu.events[pmu.scrInfo.qe.eTail];
384 
385 		switch (j) {
386 		case RIGHT_BUTTON:
387 			eventPtr->key = EVENT_RIGHT_BUTTON;
388 			break;
389 
390 		case MIDDLE_BUTTON:
391 			eventPtr->key = EVENT_MIDDLE_BUTTON;
392 			break;
393 
394 		case LEFT_BUTTON:
395 			eventPtr->key = EVENT_LEFT_BUTTON;
396 		}
397 		if (newSwitch & j)
398 			eventPtr->type = BUTTON_DOWN_TYPE;
399 		else
400 			eventPtr->type = BUTTON_UP_TYPE;
401 		eventPtr->device = MOUSE_DEVICE;
402 
403 		eventPtr->time = TO_MS(time);
404 		eventPtr->x = pmu.scrInfo.mouse.x;
405 		eventPtr->y = pmu.scrInfo.mouse.y;
406 	}
407 	pmu.scrInfo.qe.eTail = i;
408 	selwakeup(&cfb_selp);
409 
410 	lastRep = *newRepPtr;
411 	pmu.scrInfo.mswitches = newSwitch;
412 }
413 
414 /*
415  *----------------------------------------------------------------------
416  *
417  * Scroll --
418  *
419  *	Scroll the screen.
420  *
421  * Results:
422  *	None.
423  *
424  * Side effects:
425  *	None.
426  *
427  *----------------------------------------------------------------------
428  */
429 static void
430 Scroll()
431 {
432 	register int *dest, *src;
433 	register int *end;
434 	register int temp0, temp1, temp2, temp3;
435 	register int i, scanInc, lineCount;
436 	int line;
437 
438 	/*
439 	 * If the mouse is on we don't scroll so that the bit map remains sane.
440 	 */
441 	if (GraphicsOpen) {
442 		row = 0;
443 		return;
444 	}
445 
446 	/*
447 	 *  The following is an optimization to cause the scrolling
448 	 *  of text to be memory limited.  Basically the writebuffer is
449 	 *  4 words (32 bits ea.) long so to achieve maximum speed we
450 	 *  read and write in multiples of 4 words. We also limit the
451 	 *  size to be MAX_COL characters for more speed.
452 	 */
453 	if (isMono) {
454 		lineCount = 5;
455 		line = 1920 * 2;
456 		scanInc = 44;
457 	} else {
458 		lineCount = 40;
459 		scanInc = 96;
460 		line = 1920 * 8;
461 	}
462 	src = (int *)(fb_addr + line);
463 	dest = (int *)(fb_addr);
464 	end = (int *)(fb_addr + (60 * line) - line);
465 	do {
466 		i = 0;
467 		do {
468 			temp0 = src[0];
469 			temp1 = src[1];
470 			temp2 = src[2];
471 			temp3 = src[3];
472 			dest[0] = temp0;
473 			dest[1] = temp1;
474 			dest[2] = temp2;
475 			dest[3] = temp3;
476 			dest += 4;
477 			src += 4;
478 			i++;
479 		} while (i < lineCount);
480 		src += scanInc;
481 		dest += scanInc;
482 	} while (src < end);
483 
484 	/*
485 	 * Now zero out the last two lines
486 	 */
487 	bzero(fb_addr + (row * line), 3 * line);
488 }
489 
490 /*
491  *----------------------------------------------------------------------
492  *
493  * cfbPutc --
494  *
495  *	Write a character to the console.
496  *
497  * Results:
498  *	None.
499  *
500  * Side effects:
501  *	None.
502  *
503  *----------------------------------------------------------------------
504  */
505 cfbPutc(c)
506 	register int c;
507 {
508 	int s;
509 
510 	s = splhigh();	/* in case we do any printf's at interrupt time */
511 	if (initialized) {
512 #ifdef DEBUG
513 		/*
514 		 * If the HELP key is pressed, wait for another
515 		 * HELP key press to start/stop output.
516 		 */
517 		if (dcDebugGetc() == LK_HELP) {
518 			while (dcDebugGetc() != LK_HELP)
519 				;
520 		}
521 #endif
522 		Blitc(c);
523 	} else {
524 		void (*f)() = (void (*)())MACH_MON_PUTCHAR;
525 
526 		(*f)(c);
527 	}
528 	splx(s);
529 }
530 
531 /*
532  *----------------------------------------------------------------------
533  *
534  * Blitc --
535  *
536  *	Write a character to the screen.
537  *
538  * Results:
539  *	None.
540  *
541  * Side effects:
542  *	None.
543  *
544  *----------------------------------------------------------------------
545  */
546 static void
547 Blitc(c)
548 	register int c;
549 {
550 	register char *bRow, *fRow;
551 	register int i;
552 	register int ote = isMono ? 256 : 1024; /* offset to table entry */
553 	int colMult = isMono ? 1 : 8;
554 
555 	c &= 0xff;
556 
557 	switch (c) {
558 	case '\t':
559 		for (i = 8 - (col & 0x7); i > 0; i--)
560 			Blitc(' ');
561 		break;
562 
563 	case '\r':
564 		col = 0;
565 		break;
566 
567 	case '\b':
568 		col--;
569 		if (col < 0)
570 			col = 0;
571 		break;
572 
573 	case '\n':
574 		if (row + 1 >= MAX_ROW)
575 			Scroll();
576 		else
577 			row++;
578 		col = 0;
579 		break;
580 
581 	case '\007':
582 		dcKBDPutc(LK_RING_BELL);
583 		break;
584 
585 	default:
586 		/*
587 		 * 0xA1 to 0xFD are the printable characters added with 8-bit
588 		 * support.
589 		 */
590 		if (c < ' ' || c > '~' && c < 0xA1 || c > 0xFD)
591 			break;
592 		/*
593 		 * If the next character will wrap around then
594 		 * increment row counter or scroll screen.
595 		 */
596 		if (col >= MAX_COL) {
597 			col = 0;
598 			if (row + 1 >= MAX_ROW)
599 				Scroll();
600 			else
601 				row++;
602 		}
603 		bRow = (char *)(fb_addr +
604 			(row * 15 & 0x3ff) * ote + col * colMult);
605 		i = c - ' ';
606 		/*
607 		 * This is to skip the (32) 8-bit
608 		 * control chars, as well as DEL
609 		 * and 0xA0 which aren't printable
610 		 */
611 		if (c > '~')
612 			i -= 34;
613 		i *= 15;
614 		fRow = (char *)((int)pmFont + i);
615 
616 		/* inline expansion for speed */
617 		if (isMono) {
618 			*bRow = *fRow++; bRow += ote;
619 			*bRow = *fRow++; bRow += ote;
620 			*bRow = *fRow++; bRow += ote;
621 			*bRow = *fRow++; bRow += ote;
622 			*bRow = *fRow++; bRow += ote;
623 			*bRow = *fRow++; bRow += ote;
624 			*bRow = *fRow++; bRow += ote;
625 			*bRow = *fRow++; bRow += ote;
626 			*bRow = *fRow++; bRow += ote;
627 			*bRow = *fRow++; bRow += ote;
628 			*bRow = *fRow++; bRow += ote;
629 			*bRow = *fRow++; bRow += ote;
630 			*bRow = *fRow++; bRow += ote;
631 			*bRow = *fRow++; bRow += ote;
632 			*bRow = *fRow++; bRow += ote;
633 		} else {
634 			register int j;
635 			register unsigned int *pInt;
636 
637 			pInt = (unsigned int *)bRow;
638 			for (j = 0; j < 15; j++) {
639 				/*
640 				 * fontmaskBits converts a nibble
641 				 * (4 bytes) to a long word
642 				 * containing 4 pixels corresponding
643 				 * to each bit in the nibble.  Thus
644 				 * we write two longwords for each
645 				 * byte in font.
646 				 *
647 				 * Remember the font is 8 bits wide
648 				 * and 15 bits high.
649 				 *
650 				 * We add 256 to the pointer to
651 				 * point to the pixel on the
652 				 * next scan line
653 				 * directly below the current
654 				 * pixel.
655 				 */
656 				pInt[0] = fontmaskBits[(*fRow) & 0xf];
657 				pInt[1] = fontmaskBits[((*fRow) >> 4) & 0xf];
658 				fRow++;
659 				pInt += 256;
660 			}
661 		}
662 		col++; /* increment column counter */
663 	}
664 	if (!GraphicsOpen)
665 		PosCursor(col * 8, row * 15);
666 }
667 
668 /*ARGSUSED*/
669 cfbopen(dev, flag)
670 	dev_t dev;
671 	int flag;
672 {
673 
674 	if (!initialized)
675 		return (ENXIO);
676 	if (GraphicsOpen)
677 		return (EBUSY);
678 
679 	GraphicsOpen = 1;
680 	if (!isMono)
681 		InitColorMap();
682 	/*
683 	 * Set up event queue for later
684 	 */
685 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
686 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
687 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
688 	pmu.scrInfo.qe.tcNext = 0;
689 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
690 	return (0);
691 }
692 
693 /*ARGSUSED*/
694 cfbclose(dev, flag)
695 	dev_t dev;
696 	int flag;
697 {
698 
699 	if (!GraphicsOpen)
700 		return (EBADF);
701 
702 	GraphicsOpen = 0;
703 	if (!isMono)
704 		InitColorMap();
705 	ScreenInit();
706 	vmUserUnmap();
707 	bzero(fb_addr, (isMono ? 1024 / 8 : 1024) * 864);
708 	PosCursor(col * 8, row * 15);
709 	return (0);
710 }
711 
712 /*ARGSUSED*/
713 cfbioctl(dev, cmd, data, flag)
714 	dev_t dev;
715 	caddr_t data;
716 {
717 
718 	switch (cmd) {
719 	case QIOCGINFO:
720 	    {
721 		caddr_t addr;
722 		extern caddr_t vmUserMap();
723 
724 		/*
725 		 * Map the all the data the user needs access to into
726 		 * user space.
727 		 */
728 		addr = vmUserMap(sizeof(pmu), (unsigned)&pmu);
729 		if (addr == (caddr_t)0)
730 			goto mapError;
731 		*(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo;
732 		pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events;
733 		pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs;
734 		/*
735 		 * Map the plane mask into the user's address space.
736 		 */
737 		addr = vmUserMap(4, planemask_addr);
738 		if (addr == (caddr_t)0)
739 			goto mapError;
740 		pmu.scrInfo.planemask = (char *)addr;
741 		/*
742 		 * Map the frame buffer into the user's address space.
743 		 */
744 		addr = vmUserMap(isMono ? 256*1024 : 1024*1024, fb_addr);
745 		if (addr == (caddr_t)0)
746 			goto mapError;
747 		pmu.scrInfo.bitmap = (char *)addr;
748 		break;
749 
750 	mapError:
751 		vmUserUnmap();
752 		printf("Cannot map shared data structures\n");
753 		return (EIO);
754 	    }
755 
756 	case QIOCPMSTATE:
757 		/*
758 		 * Set mouse state.
759 		 */
760 		pmu.scrInfo.mouse = *(pmCursor *)data;
761 		PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y);
762 		break;
763 
764 	case QIOCINIT:
765 		/*
766 		 * Initialize the screen.
767 		 */
768 		ScreenInit();
769 		break;
770 
771 	case QIOCKPCMD:
772 	    {
773 		pmKpCmd *kpCmdPtr;
774 		unsigned char *cp;
775 
776 		kpCmdPtr = (pmKpCmd *)data;
777 		if (kpCmdPtr->nbytes == 0)
778 			kpCmdPtr->cmd |= 0x80;
779 		if (!GraphicsOpen)
780 			kpCmdPtr->cmd |= 1;
781 		dcKBDPutc((int)kpCmdPtr->cmd);
782 		cp = &kpCmdPtr->par[0];
783 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
784 			if (kpCmdPtr->nbytes == 1)
785 				*cp |= 0x80;
786 			dcKBDPutc((int)*cp);
787 		}
788 		break;
789 	    }
790 
791 	case QIOCADDR:
792 		*(PM_Info **)data = &pmu.scrInfo;
793 		break;
794 
795 	case QIOWCURSOR:
796 		LoadCursor((unsigned short *)data);
797 		break;
798 
799 	case QIOWCURSORCOLOR:
800 		CursorColor((unsigned int *)data);
801 		break;
802 
803 	case QIOSETCMAP:
804 		LoadColorMap((ColorMap *)data);
805 		break;
806 
807 	case QIOKERNLOOP:
808 		dcDivertXInput = cfbKbdEvent;
809 		dcMouseEvent = cfbMouseEvent;
810 		dcMouseButtons = cfbMouseButtons;
811 		break;
812 
813 	case QIOKERNUNLOOP:
814 		dcDivertXInput = (void (*)())0;
815 		dcMouseEvent = (void (*)())0;
816 		dcMouseButtons = (void (*)())0;
817 		break;
818 
819 	case QIOVIDEOON:
820 		EnableVideo();
821 		break;
822 
823 	case QIOVIDEOOFF:
824 		DisableVideo();
825 		break;
826 
827 	default:
828 		printf("cfb0: Unknown ioctl command %x\n", cmd);
829 		return (EINVAL);
830 	}
831 	return (0);
832 }
833 
834 cfbselect(dev, flag, p)
835 	dev_t dev;
836 	int flag;
837 	struct proc *p;
838 {
839 
840 	switch (flag) {
841 	case FREAD:
842 		if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail)
843 			return (1);
844 		selrecord(p, &cfb_selp);
845 		break;
846 	}
847 
848 	return (0);
849 }
850 
851 static u_char	cursor_RGB[6];	/* cursor color 2 & 3 */
852 
853 /*
854  * The default cursor.
855  */
856 static unsigned short defCursor[1024] = {
857 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
858 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
859 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
860 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
861 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
862 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
863 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
864 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
865 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
866 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
867 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
868 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
869 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
870 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
871 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
872 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
873 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
874 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
875 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
876 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
877 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
878 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
879 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
880 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
881 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
882 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
883 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
884 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
885 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
886 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
887 	0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
888 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
889 };
890 
891 #define	CFB_OFFSET_VRAM		0x0		/* from module's base */
892 						/* Replicated at x100000 */
893 #define CFB_OFFSET_BT459	0x200000	/* Bt459 registers */
894 #define CFB_OFFSET_IREQ		0x300000	/* Interrupt req. control */
895 #define CFB_OFFSET_ROM		0x380000	/* Diagnostic ROM */
896 #define CFB_OFFSET_RESET	0x3c0000	/* Bt459 resets on writes */
897 
898 /*
899  * Generic register access
900  */
901 void
902 bt459_select_reg(regs, regno)
903 	bt459_regmap_t *regs;
904 {
905 	regs->addr_lo = regno;
906 	regs->addr_hi = regno >> 8;
907 	MachEmptyWriteBuffer();
908 }
909 
910 void
911 bt459_write_reg(regs, regno, val)
912 	bt459_regmap_t *regs;
913 {
914 	regs->addr_lo = regno;
915 	regs->addr_hi = regno >> 8;
916 	MachEmptyWriteBuffer();
917 	regs->addr_reg = val;
918 	MachEmptyWriteBuffer();
919 }
920 
921 unsigned char
922 bt459_read_reg(regs, regno)
923 	bt459_regmap_t *regs;
924 {
925 	regs->addr_lo = regno;
926 	regs->addr_hi = regno >> 8;
927 	MachEmptyWriteBuffer();
928 	return regs->addr_reg;
929 }
930 
931 #ifdef DEBUG
932 bt459_print_colormap(regs)
933 	bt459_regmap_t *regs;
934 {
935 	register int i;
936 
937 	bt459_select_reg(regs, 0);
938 	for (i = 0; i < 256; i++) {
939 		register unsigned red, green, blue;
940 
941 		red = regs->addr_cmap;
942 		green = regs->addr_cmap;
943 		blue = regs->addr_cmap;
944 		printf("%x->[x%x x%x x%x]\n", i, red, green, blue);
945 	}
946 }
947 #endif
948 
949 /*
950  * Test to see if device is present.
951  * Return true if found and initialized ok.
952  */
953 cfb_init(cp)
954 	register struct pmax_ctlr *cp;
955 {
956 	bt459_regmap_t *regs;
957 
958 	/* check for no frame buffer */
959 	if (badaddr(cp->pmax_addr, 4))
960 		return (0);
961 
962 	fb_addr = (unsigned)cp->pmax_addr + CFB_OFFSET_VRAM;
963 	planemask_addr = 0; /* XXX */
964 	regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
965 
966 	if (bt459_read_reg(regs, BT459_REG_ID) != 0x4a)
967 		return (0);
968 
969 	*(int *)(fb_addr + CFB_OFFSET_RESET) = 0;	/* force chip reset */
970 	DELAY(2000);	/* ???? check right time on specs! ???? */
971 
972 	/* use 4:1 input mux */
973 	bt459_write_reg(regs, BT459_REG_CMD0, 0x40);
974 
975 	/* no zooming, no panning */
976 	bt459_write_reg(regs, BT459_REG_CMD1, 0x00);
977 
978 	/*
979 	 * signature test, X-windows cursor, no overlays, SYNC* PLL,
980 	 * normal RAM select, 7.5 IRE pedestal, do sync
981 	 */
982 	bt459_write_reg(regs, BT459_REG_CMD2, 0xc2);
983 
984 	/* get all pixel bits */
985 	bt459_write_reg(regs, BT459_REG_PRM, 0xff);
986 
987 	/* no blinking */
988 	bt459_write_reg(regs, BT459_REG_PBM, 0x00);
989 
990 	/* no overlay */
991 	bt459_write_reg(regs, BT459_REG_ORM, 0x00);
992 
993 	/* no overlay blink */
994 	bt459_write_reg(regs, BT459_REG_OBM, 0x00);
995 
996 	/* no interleave, no underlay */
997 	bt459_write_reg(regs, BT459_REG_ILV, 0x00);
998 
999 	/* normal operation, no signature analysis */
1000 	bt459_write_reg(regs, BT459_REG_TEST, 0x00);
1001 
1002 	/*
1003 	 * no blinking, 1bit cross hair, XOR reg&crosshair,
1004 	 * no crosshair on either plane 0 or 1,
1005 	 * regular cursor on both planes.
1006 	 */
1007 	bt459_write_reg(regs, BT459_REG_CCR, 0xc0);
1008 
1009 	/* home cursor */
1010 	bt459_write_reg(regs, BT459_REG_CXLO, 0x00);
1011 	bt459_write_reg(regs, BT459_REG_CXHI, 0x00);
1012 	bt459_write_reg(regs, BT459_REG_CYLO, 0x00);
1013 	bt459_write_reg(regs, BT459_REG_CYHI, 0x00);
1014 
1015 	/* no crosshair window */
1016 	bt459_write_reg(regs, BT459_REG_WXLO, 0x00);
1017 	bt459_write_reg(regs, BT459_REG_WXHI, 0x00);
1018 	bt459_write_reg(regs, BT459_REG_WYLO, 0x00);
1019 	bt459_write_reg(regs, BT459_REG_WYHI, 0x00);
1020 	bt459_write_reg(regs, BT459_REG_WWLO, 0x00);
1021 	bt459_write_reg(regs, BT459_REG_WWHI, 0x00);
1022 	bt459_write_reg(regs, BT459_REG_WHLO, 0x00);
1023 	bt459_write_reg(regs, BT459_REG_WHHI, 0x00);
1024 
1025 	/*
1026 	 * Initialize screen info.
1027 	 */
1028 	pmu.scrInfo.max_row = MAX_ROW;
1029 	pmu.scrInfo.max_col = MAX_COL;
1030 	pmu.scrInfo.max_x = 1024;
1031 	pmu.scrInfo.max_y = 864;
1032 	pmu.scrInfo.max_cur_x = 1023;
1033 	pmu.scrInfo.max_cur_y = 863;
1034 	pmu.scrInfo.version = 11;
1035 	pmu.scrInfo.mthreshold = 4;
1036 	pmu.scrInfo.mscale = 2;
1037 	pmu.scrInfo.min_cur_x = 0;
1038 	pmu.scrInfo.min_cur_y = 0;
1039 	pmu.scrInfo.qe.timestamp_ms = TO_MS(time);
1040 	pmu.scrInfo.qe.eSize = PM_MAXEVQ;
1041 	pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0;
1042 	pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
1043 	pmu.scrInfo.qe.tcNext = 0;
1044 
1045 	/*
1046 	 * Initialize the color map, the screen, and the mouse.
1047 	 */
1048 	InitColorMap();
1049 	ScreenInit();
1050 	Scroll();
1051 
1052 	initialized = 1;
1053 	return (1);
1054 }
1055 
1056 /*
1057  * ----------------------------------------------------------------------------
1058  *
1059  * ScreenInit --
1060  *
1061  *	Initialize the screen.
1062  *
1063  * Results:
1064  *	None.
1065  *
1066  * Side effects:
1067  *	The screen is initialized.
1068  *
1069  * ----------------------------------------------------------------------------
1070  */
1071 static void
1072 ScreenInit()
1073 {
1074 
1075 	/*
1076 	 * Home the cursor.
1077 	 * We want an LSI terminal emulation. We want the graphics
1078 	 * terminal to scroll from the bottom. So start at the bottom.
1079 	 */
1080 	row = 55;
1081 	col = 0;
1082 
1083 	/*
1084 	 * Load the cursor with the default values
1085 	 *
1086 	 */
1087 	LoadCursor(defCursor);
1088 }
1089 
1090 /*
1091  * ----------------------------------------------------------------------------
1092  *
1093  * LoadCursor --
1094  *
1095  *	Routine to load the cursor Sprite pattern.
1096  *
1097  * Results:
1098  *	None.
1099  *
1100  * Side effects:
1101  *	The cursor is loaded into the hardware cursor.
1102  *
1103  * ----------------------------------------------------------------------------
1104  */
1105 static void
1106 LoadCursor(cur)
1107 	unsigned short *cur;
1108 {
1109 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1110 	register int i, j;
1111 
1112 	/*
1113 	 * As per specs, must run a check to see if we
1114 	 * had contention. If so, re-write the cursor.
1115 	 */
1116 	for (j = 0; j < 2; j++) {
1117 		/* loop once to write */
1118 		bt459_select_reg(regs, BT459_REG_CRAM_BASE);
1119 		for (i = 0; i < 1024; i++) {
1120 			regs->addr_reg = cur[i];
1121 			MachEmptyWriteBuffer();
1122 		}
1123 
1124 		/* loop to check, if fail write again */
1125 		bt459_select_reg(regs, BT459_REG_CRAM_BASE);
1126 		for (i = 0; i < 1024; i++)
1127 			if (regs->addr_reg != cur[i])
1128 				break;
1129 		if (i == 1024)
1130 			break;	/* all went well first shot */
1131 	}
1132 }
1133 
1134 /*
1135  * ----------------------------------------------------------------------------
1136  *
1137  * RestoreCursorColor --
1138  *
1139  *	Routine to restore the color of the cursor.
1140  *
1141  * Results:
1142  *	None.
1143  *
1144  * Side effects:
1145  *	None.
1146  *
1147  * ----------------------------------------------------------------------------
1148  */
1149 static void
1150 RestoreCursorColor()
1151 {
1152 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1153 	register int i;
1154 
1155 	bt459_select_reg(regs, BT459_REG_CCOLOR_2);
1156 	for (i = 0; i < 6; i++) {
1157 		regs->addr_reg = cursor_RGB[i];
1158 		MachEmptyWriteBuffer();
1159 	}
1160 }
1161 
1162 /*
1163  * ----------------------------------------------------------------------------
1164  *
1165  * CursorColor --
1166  *
1167  *	Set the color of the cursor.
1168  *
1169  * Results:
1170  *	None.
1171  *
1172  * Side effects:
1173  *	None.
1174  *
1175  * ----------------------------------------------------------------------------
1176  */
1177 static void
1178 CursorColor(color)
1179 	unsigned int color[];
1180 {
1181 	register int i, j;
1182 
1183 	for (i = 0; i < 6; i++)
1184 		cursor_RGB[i] = (u_char)(color[i] >> 8);
1185 
1186 	RestoreCursorColor();
1187 }
1188 
1189 /*
1190  *----------------------------------------------------------------------
1191  *
1192  * PosCursor --
1193  *
1194  *	Postion the cursor.
1195  *
1196  * Results:
1197  *	None.
1198  *
1199  * Side effects:
1200  *	None.
1201  *
1202  *----------------------------------------------------------------------
1203  */
1204 static void
1205 PosCursor(x, y)
1206 	register int x, y;
1207 {
1208 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1209 
1210 	if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y)
1211 		y = pmu.scrInfo.max_cur_y;
1212 	if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x)
1213 		x = pmu.scrInfo.max_cur_x;
1214 	pmu.scrInfo.cursor.x = x;		/* keep track of real cursor */
1215 	pmu.scrInfo.cursor.y = y;		/* position, indep. of mouse */
1216 
1217 	x += 219;
1218 	y += 34;
1219 
1220 	bt459_select_reg(regs, BT459_REG_CXLO);
1221 	regs->addr_reg = x;
1222 	MachEmptyWriteBuffer();
1223 	regs->addr_reg = x >> 8;
1224 	MachEmptyWriteBuffer();
1225 	regs->addr_reg = y;
1226 	MachEmptyWriteBuffer();
1227 	regs->addr_reg = y >> 8;
1228 	MachEmptyWriteBuffer();
1229 }
1230 
1231 /*
1232  * ----------------------------------------------------------------------------
1233  *
1234  * InitColorMap --
1235  *
1236  *	Initialize the color map.
1237  *
1238  * Results:
1239  *	None.
1240  *
1241  * Side effects:
1242  *	The colormap is initialized appropriately.
1243  *
1244  * ----------------------------------------------------------------------------
1245  */
1246 static void
1247 InitColorMap()
1248 {
1249 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1250 	register int i;
1251 
1252 	bt459_select_reg(regs, 0);
1253 	regs->addr_cmap = 0; MachEmptyWriteBuffer();
1254 	regs->addr_cmap = 0; MachEmptyWriteBuffer();
1255 	regs->addr_cmap = 0; MachEmptyWriteBuffer();
1256 
1257 	for (i = 1; i < 256; i++) {
1258 		regs->addr_cmap = 0xff; MachEmptyWriteBuffer();
1259 		regs->addr_cmap = 0xff; MachEmptyWriteBuffer();
1260 		regs->addr_cmap = 0xff; MachEmptyWriteBuffer();
1261 	}
1262 
1263 	for (i = 0; i < 3; i++) {
1264 		cursor_RGB[i] = 0x00;
1265 		cursor_RGB[i + 3] = 0xff;
1266 	}
1267 	RestoreCursorColor();
1268 }
1269 
1270 /*
1271  * ----------------------------------------------------------------------------
1272  *
1273  * LoadColorMap --
1274  *
1275  *	Load the color map.
1276  *
1277  * Results:
1278  *	None.
1279  *
1280  * Side effects:
1281  *	The color map is loaded.
1282  *
1283  * ----------------------------------------------------------------------------
1284  */
1285 static void
1286 LoadColorMap(ptr)
1287 	ColorMap *ptr;
1288 {
1289 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1290 
1291 	if (ptr->index > 256)
1292 		return;
1293 
1294 	bt459_select_reg(regs, ptr->index);
1295 
1296 	regs->addr_cmap = ptr->Entry.red; MachEmptyWriteBuffer();
1297 	regs->addr_cmap = ptr->Entry.green; MachEmptyWriteBuffer();
1298 	regs->addr_cmap = ptr->Entry.blue; MachEmptyWriteBuffer();
1299 }
1300 
1301 /*
1302  * Video on/off state.
1303  */
1304 struct vstate {
1305 	u_char	color0[3];	/* saved color map entry zero */
1306 	u_char	off;		/* TRUE if display is off */
1307 } vstate;
1308 
1309 /*
1310  * ----------------------------------------------------------------------------
1311  *
1312  * EnableVideo --
1313  *
1314  *	Enable the video display.
1315  *
1316  * Results:
1317  *	None.
1318  *
1319  * Side effects:
1320  *	The display is enabled.
1321  *
1322  * ----------------------------------------------------------------------------
1323  */
1324 static void
1325 EnableVideo()
1326 {
1327 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1328 
1329 	if (!vstate.off)
1330 		return;
1331 
1332 	/* restore old color map entry zero */
1333 	bt459_select_reg(regs, 0);
1334 	regs->addr_cmap = vstate.color0[0];
1335 	MachEmptyWriteBuffer();
1336 	regs->addr_cmap = vstate.color0[1];
1337 	MachEmptyWriteBuffer();
1338 	regs->addr_cmap = vstate.color0[2];
1339 	MachEmptyWriteBuffer();
1340 
1341 	/* enable normal display */
1342 	bt459_write_reg(regs, BT459_REG_PRM, 0xff);
1343 	bt459_write_reg(regs, BT459_REG_CCR, 0xc0);
1344 
1345 	vstate.off = 0;
1346 }
1347 
1348 /*
1349  * ----------------------------------------------------------------------------
1350  *
1351  * DisableVideo --
1352  *
1353  *	Disable the video display.
1354  *
1355  * Results:
1356  *	None.
1357  *
1358  * Side effects:
1359  *	The display is disabled.
1360  *
1361  * ----------------------------------------------------------------------------
1362  */
1363 static void
1364 DisableVideo()
1365 {
1366 	bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459);
1367 
1368 	if (vstate.off)
1369 		return;
1370 
1371 	/* save old color map entry zero */
1372 	bt459_select_reg(regs, 0);
1373 	vstate.color0[0] = regs->addr_cmap;
1374 	vstate.color0[1] = regs->addr_cmap;
1375 	vstate.color0[2] = regs->addr_cmap;
1376 
1377 	/* set color map entry zero to zero */
1378 	bt459_select_reg(regs, 0);
1379 	regs->addr_cmap = 0;
1380 	MachEmptyWriteBuffer();
1381 	regs->addr_cmap = 0;
1382 	MachEmptyWriteBuffer();
1383 	regs->addr_cmap = 0;
1384 	MachEmptyWriteBuffer();
1385 
1386 	/* disable display */
1387 	bt459_write_reg(regs, BT459_REG_PRM, 0);
1388 	bt459_write_reg(regs, BT459_REG_CCR, 0);
1389 
1390 	vstate.off = 1;
1391 }
1392 #endif
1393