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