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