xref: /original-bsd/sys/pmax/dev/pm.c (revision 00a25f5a)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)pm.c	8.2 (Berkeley) 06/02/95
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 #include <pm.h>
31 #include <dc.h>
32 #if NPM > 0
33 #if NDC == 0
34 pm needs dc device
35 #else
36 
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/kernel.h>
40 #include <sys/ioctl.h>
41 #include <sys/file.h>
42 #include <sys/errno.h>
43 #include <sys/proc.h>
44 #include <sys/mman.h>
45 
46 #include <vm/vm.h>
47 
48 #include <machine/machConst.h>
49 #include <machine/dc7085cons.h>
50 #include <machine/pmioctl.h>
51 
52 #include <pmax/pmax/kn01.h>
53 #include <pmax/pmax/pmaxtype.h>
54 #include <pmax/pmax/cons.h>
55 
56 #include <pmax/dev/device.h>
57 #include <pmax/dev/pmreg.h>
58 #include <pmax/dev/fbreg.h>
59 
60 /*
61  * These need to be mapped into user space.
62  */
63 struct fbuaccess pmu;
64 struct pmax_fb pmfb;
65 static u_short curReg;		/* copy of PCCRegs.cmdr since it's read only */
66 
67 /*
68  * Forward references.
69  */
70 static void pmScreenInit();
71 static void pmLoadCursor();
72 static void pmRestoreCursorColor();
73 static void pmCursorColor();
74 void pmPosCursor();
75 static void pmInitColorMap();
76 static void pmVDACInit();
77 static void pmLoadColorMap();
78 
79 void pmKbdEvent(), pmMouseEvent(), pmMouseButtons();
80 extern void dcPutc();
81 extern void (*dcDivertXInput)();
82 extern void (*dcMouseEvent)();
83 extern void (*dcMouseButtons)();
84 extern int pmax_boardtype;
85 extern u_short defCursor[32];
86 extern struct consdev cn_tab;
87 
88 int	pmprobe();
89 struct	driver pmdriver = {
90 	"pm", pmprobe, 0, 0,
91 };
92 
93 /*
94  * Test to see if device is present.
95  * Return true if found and initialized ok.
96  */
97 /*ARGSUSED*/
98 pmprobe(cp)
99 	register struct pmax_ctlr *cp;
100 {
101 	register struct pmax_fb *fp = &pmfb;
102 
103 	if (pmax_boardtype != DS_PMAX)
104 		return (0);
105 	if (!fp->initialized && !pminit())
106 		return (0);
107 	if (fp->isMono)
108 		printf("pm0 (monochrome display)\n");
109 	else
110 		printf("pm0 (color display)\n");
111 	return (1);
112 }
113 
114 /*ARGSUSED*/
115 pmopen(dev, flag)
116 	dev_t dev;
117 	int flag;
118 {
119 	register struct pmax_fb *fp = &pmfb;
120 	int s;
121 
122 	if (!fp->initialized)
123 		return (ENXIO);
124 	if (fp->GraphicsOpen)
125 		return (EBUSY);
126 
127 	fp->GraphicsOpen = 1;
128 	if (!fp->isMono)
129 		pmInitColorMap();
130 	/*
131 	 * Set up event queue for later
132 	 */
133 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
134 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
135 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
136 	fp->fbu->scrInfo.qe.tcNext = 0;
137 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
138 	s = spltty();
139 	dcDivertXInput = pmKbdEvent;
140 	dcMouseEvent = pmMouseEvent;
141 	dcMouseButtons = pmMouseButtons;
142 	splx(s);
143 	return (0);
144 }
145 
146 /*ARGSUSED*/
147 pmclose(dev, flag)
148 	dev_t dev;
149 	int flag;
150 {
151 	register struct pmax_fb *fp = &pmfb;
152 	int s;
153 
154 	if (!fp->GraphicsOpen)
155 		return (EBADF);
156 
157 	fp->GraphicsOpen = 0;
158 	if (!fp->isMono)
159 		pmInitColorMap();
160 	s = spltty();
161 	dcDivertXInput = (void (*)())0;
162 	dcMouseEvent = (void (*)())0;
163 	dcMouseButtons = (void (*)())0;
164 	splx(s);
165 	pmScreenInit();
166 	bzero((caddr_t)fp->fr_addr,
167 		(fp->isMono ? 1024 / 8 : 1024) * 864);
168 	pmPosCursor(fp->col * 8, fp->row * 15);
169 	return (0);
170 }
171 
172 /*ARGSUSED*/
173 pmioctl(dev, cmd, data, flag, p)
174 	dev_t dev;
175 	u_long cmd;
176 	caddr_t data;
177 	struct proc *p;
178 {
179 	register PCCRegs *pcc = (PCCRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_PCC);
180 	register struct pmax_fb *fp = &pmfb;
181 	int s;
182 
183 	switch (cmd) {
184 	case QIOCGINFO:
185 		return (fbmmap(fp, dev, data, p));
186 
187 	case QIOCPMSTATE:
188 		/*
189 		 * Set mouse state.
190 		 */
191 		fp->fbu->scrInfo.mouse = *(pmCursor *)data;
192 		pmPosCursor(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y);
193 		break;
194 
195 	case QIOCINIT:
196 		/*
197 		 * Initialize the screen.
198 		 */
199 		pmScreenInit();
200 		break;
201 
202 	case QIOCKPCMD:
203 	    {
204 		pmKpCmd *kpCmdPtr;
205 		unsigned char *cp;
206 
207 		kpCmdPtr = (pmKpCmd *)data;
208 		if (kpCmdPtr->nbytes == 0)
209 			kpCmdPtr->cmd |= 0x80;
210 		if (!fp->GraphicsOpen)
211 			kpCmdPtr->cmd |= 1;
212 		(*fp->KBDPutc)(fp->kbddev, (int)kpCmdPtr->cmd);
213 		cp = &kpCmdPtr->par[0];
214 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
215 			if (kpCmdPtr->nbytes == 1)
216 				*cp |= 0x80;
217 			(*fp->KBDPutc)(fp->kbddev, (int)*cp);
218 		}
219 		break;
220 	    }
221 
222 	case QIOCADDR:
223 		*(PM_Info **)data = &fp->fbu->scrInfo;
224 		break;
225 
226 	case QIOWCURSOR:
227 		pmLoadCursor((unsigned short *)data);
228 		break;
229 
230 	case QIOWCURSORCOLOR:
231 		pmCursorColor((unsigned int *)data);
232 		break;
233 
234 	case QIOSETCMAP:
235 		pmLoadColorMap((ColorMap *)data);
236 		break;
237 
238 	case QIOKERNLOOP:
239 		s = spltty();
240 		dcDivertXInput = pmKbdEvent;
241 		dcMouseEvent = pmMouseEvent;
242 		dcMouseButtons = pmMouseButtons;
243 		splx(s);
244 		break;
245 
246 	case QIOKERNUNLOOP:
247 		s = spltty();
248 		dcDivertXInput = (void (*)())0;
249 		dcMouseEvent = (void (*)())0;
250 		dcMouseButtons = (void (*)())0;
251 		splx(s);
252 		break;
253 
254 	case QIOVIDEOON:
255 		if (!fp->isMono)
256 			pmRestoreCursorColor();
257 		curReg |= PCC_ENPA;
258 		curReg &= ~PCC_FOPB;
259 		pcc->cmdr = curReg;
260 		break;
261 
262 	case QIOVIDEOOFF:
263 		if (!fp->isMono)
264 			pmVDACInit();
265 		curReg |= PCC_FOPB;
266 		curReg &= ~PCC_ENPA;
267 		pcc->cmdr = curReg;
268 		break;
269 
270 	default:
271 		printf("pm0: Unknown ioctl command %x\n", cmd);
272 		return (EINVAL);
273 	}
274 	return (0);
275 }
276 
277 /*
278  * Return the physical page number that corresponds to byte offset 'off'.
279  */
280 /*ARGSUSED*/
281 pmmap(dev, off, prot)
282 	dev_t dev;
283 {
284 	int len;
285 
286 	len = pmax_round_page(((vm_offset_t)&pmu & PGOFSET) + sizeof(pmu));
287 	if (off < len)
288 		return pmax_btop(MACH_CACHED_TO_PHYS(&pmu) + off);
289 	off -= len;
290 	if (off >= pmfb.fr_size)
291 		return (-1);
292 	return pmax_btop(MACH_UNCACHED_TO_PHYS(pmfb.fr_addr) + off);
293 }
294 
295 pmselect(dev, flag, p)
296 	dev_t dev;
297 	int flag;
298 	struct proc *p;
299 {
300 	struct pmax_fb *fp = &pmfb;
301 
302 	switch (flag) {
303 	case FREAD:
304 		if (fp->fbu->scrInfo.qe.eHead != fp->fbu->scrInfo.qe.eTail)
305 			return (1);
306 		selrecord(p, &fp->selp);
307 		break;
308 	}
309 
310 	return (0);
311 }
312 
313 static u_char	bg_RGB[3];	/* background color for the cursor */
314 static u_char	fg_RGB[3];	/* foreground color for the cursor */
315 
316 /*
317  * Test to see if device is present.
318  * Return true if found and initialized ok.
319  */
320 pminit()
321 {
322 	register PCCRegs *pcc = (PCCRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_PCC);
323 	register struct pmax_fb *fp = &pmfb;
324 
325 	fp->isMono = *(volatile u_short *)MACH_PHYS_TO_UNCACHED(KN01_SYS_CSR) &
326 		KN01_CSR_MONO;
327 	fp->fr_addr = (char *)MACH_PHYS_TO_UNCACHED(KN01_PHYS_FBUF_START);
328 	fp->fr_size = fp->isMono ? 0x40000 : 0x100000;
329 	/*
330 	 * Must be in Uncached space since the fbuaccess structure is
331 	 * mapped into the user's address space uncached.
332 	 */
333 	fp->fbu = (struct fbuaccess *)
334 		MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(&pmu));
335 	fp->posCursor = pmPosCursor;
336 	fp->KBDPutc = dcPutc;
337 	fp->kbddev = makedev(DCDEV, DCKBD_PORT);
338 	if (fp->isMono) {
339 		/* check for no frame buffer */
340 		if (badaddr((char *)fp->fr_addr, 4))
341 			return (0);
342 	}
343 
344 	/*
345 	 * Initialize the screen.
346 	 */
347 	pcc->cmdr = PCC_FOPB | PCC_VBHI;
348 
349 	/*
350 	 * Initialize the cursor register.
351 	 */
352 	pcc->cmdr = curReg = PCC_ENPA | PCC_ENPB;
353 
354 	/*
355 	 * Initialize screen info.
356 	 */
357 	fp->fbu->scrInfo.max_row = 56;
358 	fp->fbu->scrInfo.max_col = 80;
359 	fp->fbu->scrInfo.max_x = 1024;
360 	fp->fbu->scrInfo.max_y = 864;
361 	fp->fbu->scrInfo.max_cur_x = 1023;
362 	fp->fbu->scrInfo.max_cur_y = 863;
363 	fp->fbu->scrInfo.version = 11;
364 	fp->fbu->scrInfo.mthreshold = 4;
365 	fp->fbu->scrInfo.mscale = 2;
366 	fp->fbu->scrInfo.min_cur_x = -15;
367 	fp->fbu->scrInfo.min_cur_y = -15;
368 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
369 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
370 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
371 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
372 	fp->fbu->scrInfo.qe.tcNext = 0;
373 
374 	/*
375 	 * Initialize the color map, the screen, and the mouse.
376 	 */
377 	pmInitColorMap();
378 	pmScreenInit();
379 	fbScroll(fp);
380 
381 	fp->initialized = 1;
382 	if (cn_tab.cn_fb == (struct pmax_fb *)0)
383 		cn_tab.cn_fb = fp;
384 	return (1);
385 }
386 
387 /*
388  * ----------------------------------------------------------------------------
389  *
390  * pmScreenInit --
391  *
392  *	Initialize the screen.
393  *
394  * Results:
395  *	None.
396  *
397  * Side effects:
398  *	The screen is initialized.
399  *
400  * ----------------------------------------------------------------------------
401  */
402 static void
403 pmScreenInit()
404 {
405 	register struct pmax_fb *fp = &pmfb;
406 
407 	/*
408 	 * Home the cursor.
409 	 * We want an LSI terminal emulation.  We want the graphics
410 	 * terminal to scroll from the bottom. So start at the bottom.
411 	 */
412 	fp->row = 55;
413 	fp->col = 0;
414 
415 	/*
416 	 * Load the cursor with the default values
417 	 *
418 	 */
419 	pmLoadCursor(defCursor);
420 }
421 
422 /*
423  * ----------------------------------------------------------------------------
424  *
425  * pmLoadCursor --
426  *
427  *	Routine to load the cursor Sprite pattern.
428  *
429  * Results:
430  *	None.
431  *
432  * Side effects:
433  *	The cursor is loaded into the hardware cursor.
434  *
435  * ----------------------------------------------------------------------------
436  */
437 static void
438 pmLoadCursor(cur)
439 	unsigned short *cur;
440 {
441 	register PCCRegs *pcc = (PCCRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_PCC);
442 	register int i;
443 
444 	curReg |= PCC_LODSA;
445 	pcc->cmdr = curReg;
446 	for (i = 0; i < 32; i++) {
447 		pcc->memory = cur[i];
448 		MachEmptyWriteBuffer();
449 	}
450 	curReg &= ~PCC_LODSA;
451 	pcc->cmdr = curReg;
452 }
453 
454 /*
455  * ----------------------------------------------------------------------------
456  *
457  * pmRestoreCursorColor --
458  *
459  *	Routine to restore the color of the cursor.
460  *
461  * Results:
462  *	None.
463  *
464  * Side effects:
465  *	None.
466  *
467  * ----------------------------------------------------------------------------
468  */
469 static void
470 pmRestoreCursorColor()
471 {
472 	register VDACRegs *vdac = (VDACRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_VDAC);
473 	register int i;
474 
475 	vdac->overWA = 0x04;
476 	MachEmptyWriteBuffer();
477 	for (i = 0; i < 3; i++) {
478 		vdac->over = bg_RGB[i];
479 		MachEmptyWriteBuffer();
480 	}
481 
482 	vdac->overWA = 0x08;
483 	MachEmptyWriteBuffer();
484 	vdac->over = 0x00;
485 	MachEmptyWriteBuffer();
486 	vdac->over = 0x00;
487 	MachEmptyWriteBuffer();
488 	vdac->over = 0x7f;
489 	MachEmptyWriteBuffer();
490 
491 	vdac->overWA = 0x0c;
492 	MachEmptyWriteBuffer();
493 	for (i = 0; i < 3; i++) {
494 		vdac->over = fg_RGB[i];
495 		MachEmptyWriteBuffer();
496 	}
497 }
498 
499 /*
500  * ----------------------------------------------------------------------------
501  *
502  * pmCursorColor --
503  *
504  *	Set the color of the cursor.
505  *
506  * Results:
507  *	None.
508  *
509  * Side effects:
510  *	None.
511  *
512  * ----------------------------------------------------------------------------
513  */
514 static void
515 pmCursorColor(color)
516 	unsigned int color[];
517 {
518 	register int i, j;
519 
520 	for (i = 0; i < 3; i++)
521 		bg_RGB[i] = (u_char)(color[i] >> 8);
522 
523 	for (i = 3, j = 0; i < 6; i++, j++)
524 		fg_RGB[j] = (u_char)(color[i] >> 8);
525 
526 	pmRestoreCursorColor();
527 }
528 
529 /*
530  * ----------------------------------------------------------------------------
531  *
532  * pmInitColorMap --
533  *
534  *	Initialize the color map.
535  *
536  * Results:
537  *	None.
538  *
539  * Side effects:
540  *	The colormap is initialized appropriately whether it is color or
541  *	monochrome.
542  *
543  * ----------------------------------------------------------------------------
544  */
545 static void
546 pmInitColorMap()
547 {
548 	register VDACRegs *vdac = (VDACRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_VDAC);
549 	struct pmax_fb *fp = &pmfb;
550 	register int i;
551 
552 	*(volatile char *)MACH_PHYS_TO_UNCACHED(KN01_PHYS_COLMASK_START) = 0xff;
553 	MachEmptyWriteBuffer();
554 
555 	if (fp->isMono) {
556 		vdac->mapWA = 0; MachEmptyWriteBuffer();
557 		for (i = 0; i < 256; i++) {
558 			vdac->map = (i < 128) ? 0x00 : 0xff;
559 			MachEmptyWriteBuffer();
560 			vdac->map = (i < 128) ? 0x00 : 0xff;
561 			MachEmptyWriteBuffer();
562 			vdac->map = (i < 128) ? 0x00 : 0xff;
563 			MachEmptyWriteBuffer();
564 		}
565 	} else {
566 		vdac->mapWA = 0; MachEmptyWriteBuffer();
567 		vdac->map = 0; MachEmptyWriteBuffer();
568 		vdac->map = 0; MachEmptyWriteBuffer();
569 		vdac->map = 0; MachEmptyWriteBuffer();
570 
571 		for (i = 1; i < 256; i++) {
572 			vdac->map = 0xff; MachEmptyWriteBuffer();
573 			vdac->map = 0xff; MachEmptyWriteBuffer();
574 			vdac->map = 0xff; MachEmptyWriteBuffer();
575 		}
576 	}
577 
578 	for (i = 0; i < 3; i++) {
579 		bg_RGB[i] = 0x00;
580 		fg_RGB[i] = 0xff;
581 	}
582 	pmRestoreCursorColor();
583 }
584 
585 /*
586  * ----------------------------------------------------------------------------
587  *
588  * pmVDACInit --
589  *
590  *	Initialize the VDAC.
591  *
592  * Results:
593  *	None.
594  *
595  * Side effects:
596  *	None.
597  *
598  * ----------------------------------------------------------------------------
599  */
600 static void
601 pmVDACInit()
602 {
603 	register VDACRegs *vdac = (VDACRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_VDAC);
604 
605 	/*
606 	 *
607 	 * Initialize the VDAC
608 	 */
609 	vdac->overWA = 0x04; MachEmptyWriteBuffer();
610 	vdac->over = 0x00; MachEmptyWriteBuffer();
611 	vdac->over = 0x00; MachEmptyWriteBuffer();
612 	vdac->over = 0x00; MachEmptyWriteBuffer();
613 	vdac->overWA = 0x08; MachEmptyWriteBuffer();
614 	vdac->over = 0x00; MachEmptyWriteBuffer();
615 	vdac->over = 0x00; MachEmptyWriteBuffer();
616 	vdac->over = 0x7f; MachEmptyWriteBuffer();
617 	vdac->overWA = 0x0c; MachEmptyWriteBuffer();
618 	vdac->over = 0xff; MachEmptyWriteBuffer();
619 	vdac->over = 0xff; MachEmptyWriteBuffer();
620 	vdac->over = 0xff; MachEmptyWriteBuffer();
621 }
622 
623 /*
624  * ----------------------------------------------------------------------------
625  *
626  * pmLoadColorMap --
627  *
628  *	Load the color map.
629  *
630  * Results:
631  *	None.
632  *
633  * Side effects:
634  *	The color map is loaded.
635  *
636  * ----------------------------------------------------------------------------
637  */
638 static void
639 pmLoadColorMap(ptr)
640 	ColorMap *ptr;
641 {
642 	register VDACRegs *vdac = (VDACRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_VDAC);
643 
644 	if (ptr->index > 256)
645 		return;
646 
647 	vdac->mapWA = ptr->index; MachEmptyWriteBuffer();
648 	vdac->map = ptr->Entry.red; MachEmptyWriteBuffer();
649 	vdac->map = ptr->Entry.green; MachEmptyWriteBuffer();
650 	vdac->map = ptr->Entry.blue; MachEmptyWriteBuffer();
651 }
652 
653 /*
654  *----------------------------------------------------------------------
655  *
656  * pmPosCursor --
657  *
658  *	Postion the cursor.
659  *
660  * Results:
661  *	None.
662  *
663  * Side effects:
664  *	None.
665  *
666  *----------------------------------------------------------------------
667  */
668 void
669 pmPosCursor(x, y)
670 	register int x, y;
671 {
672 	register PCCRegs *pcc = (PCCRegs *)MACH_PHYS_TO_UNCACHED(KN01_SYS_PCC);
673 	register struct pmax_fb *fp = &pmfb;
674 
675 	if (y < fp->fbu->scrInfo.min_cur_y || y > fp->fbu->scrInfo.max_cur_y)
676 		y = fp->fbu->scrInfo.max_cur_y;
677 	if (x < fp->fbu->scrInfo.min_cur_x || x > fp->fbu->scrInfo.max_cur_x)
678 		x = fp->fbu->scrInfo.max_cur_x;
679 	fp->fbu->scrInfo.cursor.x = x;		/* keep track of real cursor */
680 	fp->fbu->scrInfo.cursor.y = y;		/* position, indep. of mouse */
681 	pcc->xpos = PCC_X_OFFSET + x;
682 	pcc->ypos = PCC_Y_OFFSET + y;
683 }
684 
685 /*
686  * pm keyboard and mouse input. Just punt to the generic ones in fb.c
687  */
688 void
689 pmKbdEvent(ch)
690 	int ch;
691 {
692 	fbKbdEvent(ch, &pmfb);
693 }
694 
695 void
696 pmMouseEvent(newRepPtr)
697 	MouseReport *newRepPtr;
698 {
699 	fbMouseEvent(newRepPtr, &pmfb);
700 }
701 
702 void
703 pmMouseButtons(newRepPtr)
704 	MouseReport *newRepPtr;
705 {
706 	fbMouseButtons(newRepPtr, &pmfb);
707 }
708 #endif /* NDC */
709 #endif /* NPM */
710