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