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