1 /* 2 * Copyright (c) 1992 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. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)pm.c 7.3 (Berkeley) 03/07/92 11 * 12 * devGraphics.c -- 13 * 14 * This file contains machine-dependent routines for the graphics device. 15 * 16 * Copyright (C) 1989 Digital Equipment Corporation. 17 * Permission to use, copy, modify, and distribute this software and 18 * its documentation for any purpose and without fee is hereby granted, 19 * provided that the above copyright notice appears in all copies. 20 * Digital Equipment Corporation makes no representations about the 21 * suitability of this software for any purpose. It is provided "as is" 22 * without express or implied warranty. 23 * 24 * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c, 25 * v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)"; 26 */ 27 28 #include "pm.h" 29 #if NPM > 0 30 31 #include "param.h" 32 #include "time.h" 33 #include "kernel.h" 34 #include "ioctl.h" 35 #include "file.h" 36 #include "errno.h" 37 #include "proc.h" 38 #include "mman.h" 39 #include "vm/vm.h" 40 41 #include "machine/machConst.h" 42 #include "machine/machMon.h" 43 #include "machine/dc7085cons.h" 44 #include "machine/pmioctl.h" 45 46 #include "device.h" 47 #include "pmreg.h" 48 #include "font.c" 49 50 #define MAX_ROW 56 51 #define MAX_COL 80 52 53 /* 54 * Macro to translate from a time struct to milliseconds. 55 */ 56 #define TO_MS(tv) ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)) 57 58 static u_short curReg; /* copy of PCCRegs.cmdr since it's read only */ 59 static int isMono; /* true if B&W frame buffer */ 60 static int initialized; /* true if 'probe' was successful */ 61 static int GraphicsOpen; /* true if the graphics device is open */ 62 static int row, col; /* row and col for console cursor */ 63 static struct selinfo pm_selp;/* process waiting for select */ 64 65 /* 66 * These need to be mapped into user space. 67 */ 68 static struct pmuaccess { 69 PM_Info scrInfo; 70 pmEvent events[PM_MAXEVQ]; 71 pmTimeCoord tcs[MOTION_BUFFER_SIZE]; 72 } pmu; 73 74 /* 75 * Font mask bits used by Blitc(). 76 */ 77 static unsigned int fontmaskBits[16] = { 78 0x00000000, 79 0x00000001, 80 0x00000100, 81 0x00000101, 82 0x00010000, 83 0x00010001, 84 0x00010100, 85 0x00010101, 86 0x01000000, 87 0x01000001, 88 0x01000100, 89 0x01000101, 90 0x01010000, 91 0x01010001, 92 0x01010100, 93 0x01010101 94 }; 95 96 /* 97 * Forward references. 98 */ 99 static void Scroll(); 100 static void Blitc(); 101 102 static void ScreenInit(); 103 static void LoadCursor(); 104 static void RestoreCursorColor(); 105 static void CursorColor(); 106 static void PosCursor(); 107 static void InitColorMap(); 108 static void VDACInit(); 109 static void LoadColorMap(); 110 static void EnableVideo(); 111 static void DisableVideo(); 112 113 extern void dcKBDPutc(); 114 extern void (*dcDivertXInput)(); 115 extern void (*dcMouseEvent)(); 116 extern void (*dcMouseButtons)(); 117 118 int pmprobe(); 119 struct driver pmdriver = { 120 "pm", pmprobe, 0, 0, 121 }; 122 123 /* 124 * Test to see if device is present. 125 * Return true if found and initialized ok. 126 */ 127 /*ARGSUSED*/ 128 pmprobe(cp) 129 register struct pmax_ctlr *cp; 130 { 131 132 if (!initialized && !pminit()) 133 return (0); 134 if (isMono) 135 printf("pm0 (monochrome display)\n"); 136 else 137 printf("pm0 (color display)\n"); 138 return (1); 139 } 140 141 /* 142 *---------------------------------------------------------------------- 143 * 144 * pmKbdEvent -- 145 * 146 * Process a received character. 147 * 148 * Results: 149 * None. 150 * 151 * Side effects: 152 * Events added to the queue. 153 * 154 *---------------------------------------------------------------------- 155 */ 156 void 157 pmKbdEvent(ch) 158 int ch; 159 { 160 register pmEvent *eventPtr; 161 int i; 162 163 if (!GraphicsOpen) 164 return; 165 166 /* 167 * See if there is room in the queue. 168 */ 169 i = PM_EVROUND(pmu.scrInfo.qe.eTail + 1); 170 if (i == pmu.scrInfo.qe.eHead) 171 return; 172 173 /* 174 * Add the event to the queue. 175 */ 176 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 177 eventPtr->type = BUTTON_RAW_TYPE; 178 eventPtr->device = KEYBOARD_DEVICE; 179 eventPtr->x = pmu.scrInfo.mouse.x; 180 eventPtr->y = pmu.scrInfo.mouse.y; 181 eventPtr->time = TO_MS(time); 182 eventPtr->key = ch; 183 pmu.scrInfo.qe.eTail = i; 184 selwakeup(&pm_selp); 185 } 186 187 /* 188 *---------------------------------------------------------------------- 189 * 190 * pmMouseEvent -- 191 * 192 * Process a mouse event. 193 * 194 * Results: 195 * None. 196 * 197 * Side effects: 198 * An event is added to the event queue. 199 * 200 *---------------------------------------------------------------------- 201 */ 202 void 203 pmMouseEvent(newRepPtr) 204 register MouseReport *newRepPtr; 205 { 206 unsigned milliSec; 207 int i; 208 pmEvent *eventPtr; 209 210 if (!GraphicsOpen) 211 return; 212 213 milliSec = TO_MS(time); 214 215 /* 216 * Check to see if we have to accelerate the mouse 217 */ 218 if (pmu.scrInfo.mscale >= 0) { 219 if (newRepPtr->dx >= pmu.scrInfo.mthreshold) { 220 newRepPtr->dx += 221 (newRepPtr->dx - pmu.scrInfo.mthreshold) * 222 pmu.scrInfo.mscale; 223 } 224 if (newRepPtr->dy >= pmu.scrInfo.mthreshold) { 225 newRepPtr->dy += 226 (newRepPtr->dy - pmu.scrInfo.mthreshold) * 227 pmu.scrInfo.mscale; 228 } 229 } 230 231 /* 232 * Update mouse position 233 */ 234 if (newRepPtr->state & MOUSE_X_SIGN) { 235 pmu.scrInfo.mouse.x += newRepPtr->dx; 236 if (pmu.scrInfo.mouse.x > pmu.scrInfo.max_cur_x) 237 pmu.scrInfo.mouse.x = pmu.scrInfo.max_cur_x; 238 } else { 239 pmu.scrInfo.mouse.x -= newRepPtr->dx; 240 if (pmu.scrInfo.mouse.x < pmu.scrInfo.min_cur_x) 241 pmu.scrInfo.mouse.x = pmu.scrInfo.min_cur_x; 242 } 243 if (newRepPtr->state & MOUSE_Y_SIGN) { 244 pmu.scrInfo.mouse.y -= newRepPtr->dy; 245 if (pmu.scrInfo.mouse.y < pmu.scrInfo.min_cur_y) 246 pmu.scrInfo.mouse.y = pmu.scrInfo.min_cur_y; 247 } else { 248 pmu.scrInfo.mouse.y += newRepPtr->dy; 249 if (pmu.scrInfo.mouse.y > pmu.scrInfo.max_cur_y) 250 pmu.scrInfo.mouse.y = pmu.scrInfo.max_cur_y; 251 } 252 253 /* 254 * Move the hardware cursor. 255 */ 256 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 257 258 /* 259 * Store the motion event in the motion buffer. 260 */ 261 pmu.tcs[pmu.scrInfo.qe.tcNext].time = milliSec; 262 pmu.tcs[pmu.scrInfo.qe.tcNext].x = pmu.scrInfo.mouse.x; 263 pmu.tcs[pmu.scrInfo.qe.tcNext].y = pmu.scrInfo.mouse.y; 264 if (++pmu.scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE) 265 pmu.scrInfo.qe.tcNext = 0; 266 if (pmu.scrInfo.mouse.y < pmu.scrInfo.mbox.bottom && 267 pmu.scrInfo.mouse.y >= pmu.scrInfo.mbox.top && 268 pmu.scrInfo.mouse.x < pmu.scrInfo.mbox.right && 269 pmu.scrInfo.mouse.x >= pmu.scrInfo.mbox.left) 270 return; 271 272 pmu.scrInfo.mbox.bottom = 0; 273 if (PM_EVROUND(pmu.scrInfo.qe.eTail + 1) == pmu.scrInfo.qe.eHead) 274 return; 275 276 i = PM_EVROUND(pmu.scrInfo.qe.eTail - 1); 277 if ((pmu.scrInfo.qe.eTail != pmu.scrInfo.qe.eHead) && 278 (i != pmu.scrInfo.qe.eHead)) { 279 pmEvent *eventPtr; 280 281 eventPtr = &pmu.events[i]; 282 if (eventPtr->type == MOTION_TYPE) { 283 eventPtr->x = pmu.scrInfo.mouse.x; 284 eventPtr->y = pmu.scrInfo.mouse.y; 285 eventPtr->time = milliSec; 286 eventPtr->device = MOUSE_DEVICE; 287 return; 288 } 289 } 290 /* 291 * Put event into queue and wakeup any waiters. 292 */ 293 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 294 eventPtr->type = MOTION_TYPE; 295 eventPtr->time = milliSec; 296 eventPtr->x = pmu.scrInfo.mouse.x; 297 eventPtr->y = pmu.scrInfo.mouse.y; 298 eventPtr->device = MOUSE_DEVICE; 299 pmu.scrInfo.qe.eTail = PM_EVROUND(pmu.scrInfo.qe.eTail + 1); 300 selwakeup(&pm_selp); 301 } 302 303 /* 304 *---------------------------------------------------------------------- 305 * 306 * pmMouseButtons -- 307 * 308 * Process mouse buttons. 309 * 310 * Results: 311 * None. 312 * 313 * Side effects: 314 * None. 315 * 316 *---------------------------------------------------------------------- 317 */ 318 void 319 pmMouseButtons(newRepPtr) 320 MouseReport *newRepPtr; 321 { 322 static char temp, oldSwitch, newSwitch; 323 int i, j; 324 pmEvent *eventPtr; 325 static MouseReport lastRep; 326 327 if (!GraphicsOpen) 328 return; 329 330 newSwitch = newRepPtr->state & 0x07; 331 oldSwitch = lastRep.state & 0x07; 332 333 temp = oldSwitch ^ newSwitch; 334 if (temp == 0) 335 return; 336 for (j = 1; j < 8; j <<= 1) { 337 if ((j & temp) == 0) 338 continue; 339 340 /* 341 * Check for room in the queue 342 */ 343 i = PM_EVROUND(pmu.scrInfo.qe.eTail+1); 344 if (i == pmu.scrInfo.qe.eHead) 345 return; 346 347 /* 348 * Put event into queue. 349 */ 350 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 351 352 switch (j) { 353 case RIGHT_BUTTON: 354 eventPtr->key = EVENT_RIGHT_BUTTON; 355 break; 356 357 case MIDDLE_BUTTON: 358 eventPtr->key = EVENT_MIDDLE_BUTTON; 359 break; 360 361 case LEFT_BUTTON: 362 eventPtr->key = EVENT_LEFT_BUTTON; 363 } 364 if (newSwitch & j) 365 eventPtr->type = BUTTON_DOWN_TYPE; 366 else 367 eventPtr->type = BUTTON_UP_TYPE; 368 eventPtr->device = MOUSE_DEVICE; 369 370 eventPtr->time = TO_MS(time); 371 eventPtr->x = pmu.scrInfo.mouse.x; 372 eventPtr->y = pmu.scrInfo.mouse.y; 373 } 374 pmu.scrInfo.qe.eTail = i; 375 selwakeup(&pm_selp); 376 377 lastRep = *newRepPtr; 378 pmu.scrInfo.mswitches = newSwitch; 379 } 380 381 /* 382 *---------------------------------------------------------------------- 383 * 384 * Scroll -- 385 * 386 * Scroll the screen. 387 * 388 * Results: 389 * None. 390 * 391 * Side effects: 392 * None. 393 * 394 *---------------------------------------------------------------------- 395 */ 396 static void 397 Scroll() 398 { 399 register int *dest, *src; 400 register int *end; 401 register int temp0, temp1, temp2, temp3; 402 register int i, scanInc, lineCount; 403 int line; 404 405 /* 406 * If the mouse is on we don't scroll so that the bit map remains sane. 407 */ 408 if (GraphicsOpen) { 409 row = 0; 410 return; 411 } 412 413 /* 414 * The following is an optimization to cause the scrolling 415 * of text to be memory limited. Basically the writebuffer is 416 * 4 words (32 bits ea.) long so to achieve maximum speed we 417 * read and write in multiples of 4 words. We also limit the 418 * size to be MAX_COL characters for more speed. 419 */ 420 if (isMono) { 421 lineCount = 5; 422 line = 1920 * 2; 423 scanInc = 44; 424 } else { 425 lineCount = 40; 426 scanInc = 96; 427 line = 1920 * 8; 428 } 429 src = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR + line); 430 dest = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR); 431 end = (int *)(MACH_UNCACHED_FRAME_BUFFER_ADDR + (60 * line) - line); 432 do { 433 i = 0; 434 do { 435 temp0 = src[0]; 436 temp1 = src[1]; 437 temp2 = src[2]; 438 temp3 = src[3]; 439 dest[0] = temp0; 440 dest[1] = temp1; 441 dest[2] = temp2; 442 dest[3] = temp3; 443 dest += 4; 444 src += 4; 445 i++; 446 } while (i < lineCount); 447 src += scanInc; 448 dest += scanInc; 449 } while (src < end); 450 451 /* 452 * Now zero out the last two lines 453 */ 454 bzero(MACH_UNCACHED_FRAME_BUFFER_ADDR + (row * line), 3 * line); 455 } 456 457 /* 458 *---------------------------------------------------------------------- 459 * 460 * pmPutc -- 461 * 462 * Write a character to the console. 463 * 464 * Results: 465 * None. 466 * 467 * Side effects: 468 * None. 469 * 470 *---------------------------------------------------------------------- 471 */ 472 pmPutc(c) 473 register int c; 474 { 475 int s; 476 477 s = splhigh(); /* in case we do any printf's at interrupt time */ 478 if (initialized) { 479 #ifdef DEBUG 480 /* 481 * If the HELP key is pressed, wait for another 482 * HELP key press to start/stop output. 483 */ 484 if (dcDebugGetc() == LK_HELP) { 485 while (dcDebugGetc() != LK_HELP) 486 ; 487 } 488 #endif 489 Blitc(c); 490 } else { 491 void (*f)() = (void (*)())MACH_MON_PUTCHAR; 492 493 (*f)(c); 494 } 495 splx(s); 496 } 497 498 /* 499 *---------------------------------------------------------------------- 500 * 501 * Blitc -- 502 * 503 * Write a character to the screen. 504 * 505 * Results: 506 * None. 507 * 508 * Side effects: 509 * None. 510 * 511 *---------------------------------------------------------------------- 512 */ 513 static void 514 Blitc(c) 515 register int c; 516 { 517 register char *bRow, *fRow; 518 register int i; 519 register int ote = isMono ? 256 : 1024; /* offset to table entry */ 520 int colMult = isMono ? 1 : 8; 521 522 c &= 0xff; 523 524 switch (c) { 525 case '\t': 526 for (i = 8 - (col & 0x7); i > 0; i--) 527 Blitc(' '); 528 break; 529 530 case '\r': 531 col = 0; 532 break; 533 534 case '\b': 535 col--; 536 if (col < 0) 537 col = 0; 538 break; 539 540 case '\n': 541 if (row + 1 >= MAX_ROW) 542 Scroll(); 543 else 544 row++; 545 col = 0; 546 break; 547 548 case '\007': 549 dcKBDPutc(LK_RING_BELL); 550 break; 551 552 default: 553 /* 554 * 0xA1 to 0xFD are the printable characters added with 8-bit 555 * support. 556 */ 557 if (c < ' ' || c > '~' && c < 0xA1 || c > 0xFD) 558 break; 559 /* 560 * If the next character will wrap around then 561 * increment row counter or scroll screen. 562 */ 563 if (col >= MAX_COL) { 564 col = 0; 565 if (row + 1 >= MAX_ROW) 566 Scroll(); 567 else 568 row++; 569 } 570 bRow = (char *)(MACH_UNCACHED_FRAME_BUFFER_ADDR + 571 (row * 15 & 0x3ff) * ote + col * colMult); 572 i = c - ' '; 573 /* 574 * This is to skip the (32) 8-bit 575 * control chars, as well as DEL 576 * and 0xA0 which aren't printable 577 */ 578 if (c > '~') 579 i -= 34; 580 i *= 15; 581 fRow = (char *)((int)pmFont + i); 582 583 /* inline expansion for speed */ 584 if (isMono) { 585 *bRow = *fRow++; bRow += ote; 586 *bRow = *fRow++; bRow += ote; 587 *bRow = *fRow++; bRow += ote; 588 *bRow = *fRow++; bRow += ote; 589 *bRow = *fRow++; bRow += ote; 590 *bRow = *fRow++; bRow += ote; 591 *bRow = *fRow++; bRow += ote; 592 *bRow = *fRow++; bRow += ote; 593 *bRow = *fRow++; bRow += ote; 594 *bRow = *fRow++; bRow += ote; 595 *bRow = *fRow++; bRow += ote; 596 *bRow = *fRow++; bRow += ote; 597 *bRow = *fRow++; bRow += ote; 598 *bRow = *fRow++; bRow += ote; 599 *bRow = *fRow++; bRow += ote; 600 } else { 601 register int j; 602 register unsigned int *pInt; 603 604 pInt = (unsigned int *)bRow; 605 for (j = 0; j < 15; j++) { 606 /* 607 * fontmaskBits converts a nibble 608 * (4 bytes) to a long word 609 * containing 4 pixels corresponding 610 * to each bit in the nibble. Thus 611 * we write two longwords for each 612 * byte in font. 613 * 614 * Remember the font is 8 bits wide 615 * and 15 bits high. 616 * 617 * We add 256 to the pointer to 618 * point to the pixel on the 619 * next scan line 620 * directly below the current 621 * pixel. 622 */ 623 pInt[0] = fontmaskBits[(*fRow) & 0xf]; 624 pInt[1] = fontmaskBits[((*fRow) >> 4) & 0xf]; 625 fRow++; 626 pInt += 256; 627 } 628 } 629 col++; /* increment column counter */ 630 } 631 if (!GraphicsOpen) 632 PosCursor(col * 8, row * 15); 633 } 634 635 /*ARGSUSED*/ 636 pmopen(dev, flag) 637 dev_t dev; 638 int flag; 639 { 640 641 if (!initialized) 642 return (ENXIO); 643 if (GraphicsOpen) 644 return (EBUSY); 645 646 GraphicsOpen = 1; 647 if (!isMono) 648 InitColorMap(); 649 /* 650 * Set up event queue for later 651 */ 652 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 653 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 654 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 655 pmu.scrInfo.qe.tcNext = 0; 656 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 657 return (0); 658 } 659 660 /*ARGSUSED*/ 661 pmclose(dev, flag) 662 dev_t dev; 663 int flag; 664 { 665 666 if (!GraphicsOpen) 667 return (EBADF); 668 669 GraphicsOpen = 0; 670 if (!isMono) 671 InitColorMap(); 672 ScreenInit(); 673 vmUserUnmap(); 674 bzero((caddr_t)MACH_UNCACHED_FRAME_BUFFER_ADDR, 675 (isMono ? 1024 / 8 : 1024) * 864); 676 PosCursor(col * 8, row * 15); 677 return (0); 678 } 679 680 /*ARGSUSED*/ 681 pmioctl(dev, cmd, data, flag) 682 dev_t dev; 683 caddr_t data; 684 { 685 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 686 687 switch (cmd) { 688 case QIOCGINFO: 689 { 690 caddr_t addr; 691 extern caddr_t vmUserMap(); 692 693 /* 694 * Map the all the data the user needs access to into 695 * user space. 696 */ 697 addr = vmUserMap(sizeof(pmu), (unsigned)&pmu); 698 if (addr == (caddr_t)0) 699 goto mapError; 700 *(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo; 701 pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events; 702 pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs; 703 /* 704 * Map the plane mask into the user's address space. 705 */ 706 addr = vmUserMap(4, (unsigned)MACH_PLANE_MASK_ADDR); 707 if (addr == (caddr_t)0) 708 goto mapError; 709 pmu.scrInfo.planemask = (char *)addr; 710 /* 711 * Map the frame buffer into the user's address space. 712 */ 713 addr = vmUserMap(isMono ? 256*1024 : 1024*1024, 714 (unsigned)MACH_UNCACHED_FRAME_BUFFER_ADDR); 715 if (addr == (caddr_t)0) 716 goto mapError; 717 pmu.scrInfo.bitmap = (char *)addr; 718 break; 719 720 mapError: 721 vmUserUnmap(); 722 printf("Cannot map shared data structures\n"); 723 return (EIO); 724 } 725 726 case QIOCPMSTATE: 727 /* 728 * Set mouse state. 729 */ 730 pmu.scrInfo.mouse = *(pmCursor *)data; 731 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 732 break; 733 734 case QIOCINIT: 735 /* 736 * Initialize the screen. 737 */ 738 ScreenInit(); 739 break; 740 741 case QIOCKPCMD: 742 { 743 pmKpCmd *kpCmdPtr; 744 unsigned char *cp; 745 746 kpCmdPtr = (pmKpCmd *)data; 747 if (kpCmdPtr->nbytes == 0) 748 kpCmdPtr->cmd |= 0x80; 749 if (!GraphicsOpen) 750 kpCmdPtr->cmd |= 1; 751 dcKBDPutc((int)kpCmdPtr->cmd); 752 cp = &kpCmdPtr->par[0]; 753 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 754 if (kpCmdPtr->nbytes == 1) 755 *cp |= 0x80; 756 dcKBDPutc((int)*cp); 757 } 758 break; 759 } 760 761 case QIOCADDR: 762 *(PM_Info **)data = &pmu.scrInfo; 763 break; 764 765 case QIOWCURSOR: 766 LoadCursor((unsigned short *)data); 767 break; 768 769 case QIOWCURSORCOLOR: 770 CursorColor((unsigned int *)data); 771 break; 772 773 case QIOSETCMAP: 774 LoadColorMap((ColorMap *)data); 775 break; 776 777 case QIOKERNLOOP: 778 dcDivertXInput = pmKbdEvent; 779 dcMouseEvent = pmMouseEvent; 780 dcMouseButtons = pmMouseButtons; 781 break; 782 783 case QIOKERNUNLOOP: 784 dcDivertXInput = (void (*)())0; 785 dcMouseEvent = (void (*)())0; 786 dcMouseButtons = (void (*)())0; 787 break; 788 789 case QIOVIDEOON: 790 if (!isMono) 791 RestoreCursorColor(); 792 curReg |= PCC_ENPA; 793 curReg &= ~PCC_FOPB; 794 pcc->cmdr = curReg; 795 break; 796 797 case QIOVIDEOOFF: 798 if (!isMono) 799 VDACInit(); 800 curReg |= PCC_FOPB; 801 curReg &= ~PCC_ENPA; 802 pcc->cmdr = curReg; 803 break; 804 805 default: 806 printf("pm0: Unknown ioctl command %x\n", cmd); 807 return (EINVAL); 808 } 809 return (0); 810 } 811 812 pmselect(dev, flag, p) 813 dev_t dev; 814 int flag; 815 struct proc *p; 816 { 817 818 switch (flag) { 819 case FREAD: 820 if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail) 821 return (1); 822 selrecord(p, &pm_selp); 823 break; 824 } 825 826 return (0); 827 } 828 829 static u_char bg_RGB[3]; /* background color for the cursor */ 830 static u_char fg_RGB[3]; /* foreground color for the cursor */ 831 832 /* 833 * The default cursor. 834 */ 835 unsigned short defCursor[32] = { 836 /* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 837 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 838 /* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 839 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF 840 841 }; 842 843 /* 844 * Test to see if device is present. 845 * Return true if found and initialized ok. 846 */ 847 pminit() 848 { 849 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 850 851 isMono = *(u_short *)MACH_SYS_CSR_ADDR & MACH_CSR_MONO; 852 if (isMono) { 853 /* check for no frame buffer */ 854 if (badaddr((char *)MACH_UNCACHED_FRAME_BUFFER_ADDR, 4)) 855 return (0); 856 } 857 858 /* 859 * Initialize the screen. 860 */ 861 pcc->cmdr = PCC_FOPB | PCC_VBHI; 862 863 /* 864 * Initialize the cursor register. 865 */ 866 pcc->cmdr = curReg = PCC_ENPA | PCC_ENPB; 867 868 /* 869 * Initialize screen info. 870 */ 871 pmu.scrInfo.max_row = 56; 872 pmu.scrInfo.max_col = 80; 873 pmu.scrInfo.max_x = 1024; 874 pmu.scrInfo.max_y = 864; 875 pmu.scrInfo.max_cur_x = 1023; 876 pmu.scrInfo.max_cur_y = 863; 877 pmu.scrInfo.version = 11; 878 pmu.scrInfo.mthreshold = 4; 879 pmu.scrInfo.mscale = 2; 880 pmu.scrInfo.min_cur_x = -15; 881 pmu.scrInfo.min_cur_y = -15; 882 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 883 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 884 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 885 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 886 pmu.scrInfo.qe.tcNext = 0; 887 888 /* 889 * Initialize the color map, the screen, and the mouse. 890 */ 891 InitColorMap(); 892 ScreenInit(); 893 Scroll(); 894 895 initialized = 1; 896 return (1); 897 } 898 899 /* 900 * ---------------------------------------------------------------------------- 901 * 902 * ScreenInit -- 903 * 904 * Initialize the screen. 905 * 906 * Results: 907 * None. 908 * 909 * Side effects: 910 * The screen is initialized. 911 * 912 * ---------------------------------------------------------------------------- 913 */ 914 static void 915 ScreenInit() 916 { 917 918 /* 919 * Home the cursor. 920 * We want an LSI terminal emulation. We want the graphics 921 * terminal to scroll from the bottom. So start at the bottom. 922 */ 923 row = 55; 924 col = 0; 925 926 /* 927 * Load the cursor with the default values 928 * 929 */ 930 LoadCursor(defCursor); 931 } 932 933 /* 934 * ---------------------------------------------------------------------------- 935 * 936 * LoadCursor -- 937 * 938 * Routine to load the cursor Sprite pattern. 939 * 940 * Results: 941 * None. 942 * 943 * Side effects: 944 * The cursor is loaded into the hardware cursor. 945 * 946 * ---------------------------------------------------------------------------- 947 */ 948 static void 949 LoadCursor(cur) 950 unsigned short *cur; 951 { 952 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 953 register int i; 954 955 curReg |= PCC_LODSA; 956 pcc->cmdr = curReg; 957 for (i = 0; i < 32; i++) { 958 pcc->memory = cur[i]; 959 MachEmptyWriteBuffer(); 960 } 961 curReg &= ~PCC_LODSA; 962 pcc->cmdr = curReg; 963 } 964 965 /* 966 * ---------------------------------------------------------------------------- 967 * 968 * RestoreCursorColor -- 969 * 970 * Routine to restore the color of the cursor. 971 * 972 * Results: 973 * None. 974 * 975 * Side effects: 976 * None. 977 * 978 * ---------------------------------------------------------------------------- 979 */ 980 static void 981 RestoreCursorColor() 982 { 983 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 984 register int i; 985 986 vdac->overWA = 0x04; 987 MachEmptyWriteBuffer(); 988 for (i = 0; i < 3; i++) { 989 vdac->over = bg_RGB[i]; 990 MachEmptyWriteBuffer(); 991 } 992 993 vdac->overWA = 0x08; 994 MachEmptyWriteBuffer(); 995 vdac->over = 0x00; 996 MachEmptyWriteBuffer(); 997 vdac->over = 0x00; 998 MachEmptyWriteBuffer(); 999 vdac->over = 0x7f; 1000 MachEmptyWriteBuffer(); 1001 1002 vdac->overWA = 0x0c; 1003 MachEmptyWriteBuffer(); 1004 for (i = 0; i < 3; i++) { 1005 vdac->over = fg_RGB[i]; 1006 MachEmptyWriteBuffer(); 1007 } 1008 } 1009 1010 /* 1011 * ---------------------------------------------------------------------------- 1012 * 1013 * CursorColor -- 1014 * 1015 * Set the color of the cursor. 1016 * 1017 * Results: 1018 * None. 1019 * 1020 * Side effects: 1021 * None. 1022 * 1023 * ---------------------------------------------------------------------------- 1024 */ 1025 static void 1026 CursorColor(color) 1027 unsigned int color[]; 1028 { 1029 register int i, j; 1030 1031 for (i = 0; i < 3; i++) 1032 bg_RGB[i] = (u_char)(color[i] >> 8); 1033 1034 for (i = 3, j = 0; i < 6; i++, j++) 1035 fg_RGB[j] = (u_char)(color[i] >> 8); 1036 1037 RestoreCursorColor(); 1038 } 1039 1040 /* 1041 * ---------------------------------------------------------------------------- 1042 * 1043 * InitColorMap -- 1044 * 1045 * Initialize the color map. 1046 * 1047 * Results: 1048 * None. 1049 * 1050 * Side effects: 1051 * The colormap is initialized appropriately whether it is color or 1052 * monochrome. 1053 * 1054 * ---------------------------------------------------------------------------- 1055 */ 1056 static void 1057 InitColorMap() 1058 { 1059 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1060 register int i; 1061 1062 *(char *)MACH_PLANE_MASK_ADDR = 0xff; 1063 MachEmptyWriteBuffer(); 1064 1065 if (isMono) { 1066 vdac->mapWA = 0; MachEmptyWriteBuffer(); 1067 for (i = 0; i < 256; i++) { 1068 vdac->map = (i < 128) ? 0x00 : 0xff; 1069 MachEmptyWriteBuffer(); 1070 vdac->map = (i < 128) ? 0x00 : 0xff; 1071 MachEmptyWriteBuffer(); 1072 vdac->map = (i < 128) ? 0x00 : 0xff; 1073 MachEmptyWriteBuffer(); 1074 } 1075 } else { 1076 vdac->mapWA = 0; MachEmptyWriteBuffer(); 1077 vdac->map = 0; MachEmptyWriteBuffer(); 1078 vdac->map = 0; MachEmptyWriteBuffer(); 1079 vdac->map = 0; MachEmptyWriteBuffer(); 1080 1081 for (i = 1; i < 256; i++) { 1082 vdac->map = 0xff; MachEmptyWriteBuffer(); 1083 vdac->map = 0xff; MachEmptyWriteBuffer(); 1084 vdac->map = 0xff; MachEmptyWriteBuffer(); 1085 } 1086 } 1087 1088 for (i = 0; i < 3; i++) { 1089 bg_RGB[i] = 0x00; 1090 fg_RGB[i] = 0xff; 1091 } 1092 RestoreCursorColor(); 1093 } 1094 1095 /* 1096 * ---------------------------------------------------------------------------- 1097 * 1098 * VDACInit -- 1099 * 1100 * Initialize the VDAC. 1101 * 1102 * Results: 1103 * None. 1104 * 1105 * Side effects: 1106 * None. 1107 * 1108 * ---------------------------------------------------------------------------- 1109 */ 1110 static void 1111 VDACInit() 1112 { 1113 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1114 1115 /* 1116 * 1117 * Initialize the VDAC 1118 */ 1119 vdac->overWA = 0x04; MachEmptyWriteBuffer(); 1120 vdac->over = 0x00; MachEmptyWriteBuffer(); 1121 vdac->over = 0x00; MachEmptyWriteBuffer(); 1122 vdac->over = 0x00; MachEmptyWriteBuffer(); 1123 vdac->overWA = 0x08; MachEmptyWriteBuffer(); 1124 vdac->over = 0x00; MachEmptyWriteBuffer(); 1125 vdac->over = 0x00; MachEmptyWriteBuffer(); 1126 vdac->over = 0x7f; MachEmptyWriteBuffer(); 1127 vdac->overWA = 0x0c; MachEmptyWriteBuffer(); 1128 vdac->over = 0xff; MachEmptyWriteBuffer(); 1129 vdac->over = 0xff; MachEmptyWriteBuffer(); 1130 vdac->over = 0xff; MachEmptyWriteBuffer(); 1131 } 1132 1133 /* 1134 * ---------------------------------------------------------------------------- 1135 * 1136 * LoadColorMap -- 1137 * 1138 * Load the color map. 1139 * 1140 * Results: 1141 * None. 1142 * 1143 * Side effects: 1144 * The color map is loaded. 1145 * 1146 * ---------------------------------------------------------------------------- 1147 */ 1148 static void 1149 LoadColorMap(ptr) 1150 ColorMap *ptr; 1151 { 1152 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1153 1154 if (ptr->index > 256) 1155 return; 1156 1157 vdac->mapWA = ptr->index; MachEmptyWriteBuffer(); 1158 vdac->map = ptr->Entry.red; MachEmptyWriteBuffer(); 1159 vdac->map = ptr->Entry.green; MachEmptyWriteBuffer(); 1160 vdac->map = ptr->Entry.blue; MachEmptyWriteBuffer(); 1161 } 1162 1163 /* 1164 *---------------------------------------------------------------------- 1165 * 1166 * PosCursor -- 1167 * 1168 * Postion the cursor. 1169 * 1170 * Results: 1171 * None. 1172 * 1173 * Side effects: 1174 * None. 1175 * 1176 *---------------------------------------------------------------------- 1177 */ 1178 static void 1179 PosCursor(x, y) 1180 register int x, y; 1181 { 1182 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 1183 1184 if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y) 1185 y = pmu.scrInfo.max_cur_y; 1186 if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x) 1187 x = pmu.scrInfo.max_cur_x; 1188 pmu.scrInfo.cursor.x = x; /* keep track of real cursor */ 1189 pmu.scrInfo.cursor.y = y; /* position, indep. of mouse */ 1190 pcc->xpos = PCC_X_OFFSET + x; 1191 pcc->ypos = PCC_Y_OFFSET + y; 1192 } 1193 #endif 1194