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.5 (Berkeley) 06/02/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 int s; 641 642 if (!initialized) 643 return (ENXIO); 644 if (GraphicsOpen) 645 return (EBUSY); 646 647 GraphicsOpen = 1; 648 if (!isMono) 649 InitColorMap(); 650 /* 651 * Set up event queue for later 652 */ 653 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 654 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 655 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 656 pmu.scrInfo.qe.tcNext = 0; 657 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 658 s = spltty(); 659 dcDivertXInput = pmKbdEvent; 660 dcMouseEvent = pmMouseEvent; 661 dcMouseButtons = pmMouseButtons; 662 splx(s); 663 return (0); 664 } 665 666 /*ARGSUSED*/ 667 pmclose(dev, flag) 668 dev_t dev; 669 int flag; 670 { 671 int s; 672 673 if (!GraphicsOpen) 674 return (EBADF); 675 676 GraphicsOpen = 0; 677 if (!isMono) 678 InitColorMap(); 679 s = spltty(); 680 dcDivertXInput = (void (*)())0; 681 dcMouseEvent = (void (*)())0; 682 dcMouseButtons = (void (*)())0; 683 splx(s); 684 ScreenInit(); 685 vmUserUnmap(); 686 bzero((caddr_t)MACH_UNCACHED_FRAME_BUFFER_ADDR, 687 (isMono ? 1024 / 8 : 1024) * 864); 688 PosCursor(col * 8, row * 15); 689 return (0); 690 } 691 692 /*ARGSUSED*/ 693 pmioctl(dev, cmd, data, flag) 694 dev_t dev; 695 caddr_t data; 696 { 697 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 698 int s; 699 700 switch (cmd) { 701 case QIOCGINFO: 702 { 703 caddr_t addr; 704 extern caddr_t vmUserMap(); 705 706 /* 707 * Map the all the data the user needs access to into 708 * user space. 709 */ 710 addr = vmUserMap(sizeof(pmu), (unsigned)&pmu); 711 if (addr == (caddr_t)0) 712 goto mapError; 713 *(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo; 714 pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events; 715 pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs; 716 /* 717 * Map the plane mask into the user's address space. 718 */ 719 addr = vmUserMap(4, (unsigned)MACH_PLANE_MASK_ADDR); 720 if (addr == (caddr_t)0) 721 goto mapError; 722 pmu.scrInfo.planemask = (char *)addr; 723 /* 724 * Map the frame buffer into the user's address space. 725 */ 726 addr = vmUserMap(isMono ? 256*1024 : 1024*1024, 727 (unsigned)MACH_UNCACHED_FRAME_BUFFER_ADDR); 728 if (addr == (caddr_t)0) 729 goto mapError; 730 pmu.scrInfo.bitmap = (char *)addr; 731 break; 732 733 mapError: 734 vmUserUnmap(); 735 printf("Cannot map shared data structures\n"); 736 return (EIO); 737 } 738 739 case QIOCPMSTATE: 740 /* 741 * Set mouse state. 742 */ 743 pmu.scrInfo.mouse = *(pmCursor *)data; 744 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 745 break; 746 747 case QIOCINIT: 748 /* 749 * Initialize the screen. 750 */ 751 ScreenInit(); 752 break; 753 754 case QIOCKPCMD: 755 { 756 pmKpCmd *kpCmdPtr; 757 unsigned char *cp; 758 759 kpCmdPtr = (pmKpCmd *)data; 760 if (kpCmdPtr->nbytes == 0) 761 kpCmdPtr->cmd |= 0x80; 762 if (!GraphicsOpen) 763 kpCmdPtr->cmd |= 1; 764 dcKBDPutc((int)kpCmdPtr->cmd); 765 cp = &kpCmdPtr->par[0]; 766 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 767 if (kpCmdPtr->nbytes == 1) 768 *cp |= 0x80; 769 dcKBDPutc((int)*cp); 770 } 771 break; 772 } 773 774 case QIOCADDR: 775 *(PM_Info **)data = &pmu.scrInfo; 776 break; 777 778 case QIOWCURSOR: 779 LoadCursor((unsigned short *)data); 780 break; 781 782 case QIOWCURSORCOLOR: 783 CursorColor((unsigned int *)data); 784 break; 785 786 case QIOSETCMAP: 787 LoadColorMap((ColorMap *)data); 788 break; 789 790 case QIOKERNLOOP: 791 s = spltty(); 792 dcDivertXInput = pmKbdEvent; 793 dcMouseEvent = pmMouseEvent; 794 dcMouseButtons = pmMouseButtons; 795 splx(s); 796 break; 797 798 case QIOKERNUNLOOP: 799 s = spltty(); 800 dcDivertXInput = (void (*)())0; 801 dcMouseEvent = (void (*)())0; 802 dcMouseButtons = (void (*)())0; 803 splx(s); 804 break; 805 806 case QIOVIDEOON: 807 if (!isMono) 808 RestoreCursorColor(); 809 curReg |= PCC_ENPA; 810 curReg &= ~PCC_FOPB; 811 pcc->cmdr = curReg; 812 break; 813 814 case QIOVIDEOOFF: 815 if (!isMono) 816 VDACInit(); 817 curReg |= PCC_FOPB; 818 curReg &= ~PCC_ENPA; 819 pcc->cmdr = curReg; 820 break; 821 822 default: 823 printf("pm0: Unknown ioctl command %x\n", cmd); 824 return (EINVAL); 825 } 826 return (0); 827 } 828 829 pmselect(dev, flag, p) 830 dev_t dev; 831 int flag; 832 struct proc *p; 833 { 834 835 switch (flag) { 836 case FREAD: 837 if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail) 838 return (1); 839 selrecord(p, &pm_selp); 840 break; 841 } 842 843 return (0); 844 } 845 846 static u_char bg_RGB[3]; /* background color for the cursor */ 847 static u_char fg_RGB[3]; /* foreground color for the cursor */ 848 849 /* 850 * The default cursor. 851 */ 852 unsigned short defCursor[32] = { 853 /* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 854 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 855 /* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 856 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF 857 858 }; 859 860 /* 861 * Test to see if device is present. 862 * Return true if found and initialized ok. 863 */ 864 pminit() 865 { 866 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 867 868 isMono = *(u_short *)MACH_SYS_CSR_ADDR & MACH_CSR_MONO; 869 if (isMono) { 870 /* check for no frame buffer */ 871 if (badaddr((char *)MACH_UNCACHED_FRAME_BUFFER_ADDR, 4)) 872 return (0); 873 } 874 875 /* 876 * Initialize the screen. 877 */ 878 pcc->cmdr = PCC_FOPB | PCC_VBHI; 879 880 /* 881 * Initialize the cursor register. 882 */ 883 pcc->cmdr = curReg = PCC_ENPA | PCC_ENPB; 884 885 /* 886 * Initialize screen info. 887 */ 888 pmu.scrInfo.max_row = 56; 889 pmu.scrInfo.max_col = 80; 890 pmu.scrInfo.max_x = 1024; 891 pmu.scrInfo.max_y = 864; 892 pmu.scrInfo.max_cur_x = 1023; 893 pmu.scrInfo.max_cur_y = 863; 894 pmu.scrInfo.version = 11; 895 pmu.scrInfo.mthreshold = 4; 896 pmu.scrInfo.mscale = 2; 897 pmu.scrInfo.min_cur_x = -15; 898 pmu.scrInfo.min_cur_y = -15; 899 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 900 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 901 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 902 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 903 pmu.scrInfo.qe.tcNext = 0; 904 905 /* 906 * Initialize the color map, the screen, and the mouse. 907 */ 908 InitColorMap(); 909 ScreenInit(); 910 Scroll(); 911 912 initialized = 1; 913 return (1); 914 } 915 916 /* 917 * ---------------------------------------------------------------------------- 918 * 919 * ScreenInit -- 920 * 921 * Initialize the screen. 922 * 923 * Results: 924 * None. 925 * 926 * Side effects: 927 * The screen is initialized. 928 * 929 * ---------------------------------------------------------------------------- 930 */ 931 static void 932 ScreenInit() 933 { 934 935 /* 936 * Home the cursor. 937 * We want an LSI terminal emulation. We want the graphics 938 * terminal to scroll from the bottom. So start at the bottom. 939 */ 940 row = 55; 941 col = 0; 942 943 /* 944 * Load the cursor with the default values 945 * 946 */ 947 LoadCursor(defCursor); 948 } 949 950 /* 951 * ---------------------------------------------------------------------------- 952 * 953 * LoadCursor -- 954 * 955 * Routine to load the cursor Sprite pattern. 956 * 957 * Results: 958 * None. 959 * 960 * Side effects: 961 * The cursor is loaded into the hardware cursor. 962 * 963 * ---------------------------------------------------------------------------- 964 */ 965 static void 966 LoadCursor(cur) 967 unsigned short *cur; 968 { 969 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 970 register int i; 971 972 curReg |= PCC_LODSA; 973 pcc->cmdr = curReg; 974 for (i = 0; i < 32; i++) { 975 pcc->memory = cur[i]; 976 MachEmptyWriteBuffer(); 977 } 978 curReg &= ~PCC_LODSA; 979 pcc->cmdr = curReg; 980 } 981 982 /* 983 * ---------------------------------------------------------------------------- 984 * 985 * RestoreCursorColor -- 986 * 987 * Routine to restore the color of the cursor. 988 * 989 * Results: 990 * None. 991 * 992 * Side effects: 993 * None. 994 * 995 * ---------------------------------------------------------------------------- 996 */ 997 static void 998 RestoreCursorColor() 999 { 1000 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1001 register int i; 1002 1003 vdac->overWA = 0x04; 1004 MachEmptyWriteBuffer(); 1005 for (i = 0; i < 3; i++) { 1006 vdac->over = bg_RGB[i]; 1007 MachEmptyWriteBuffer(); 1008 } 1009 1010 vdac->overWA = 0x08; 1011 MachEmptyWriteBuffer(); 1012 vdac->over = 0x00; 1013 MachEmptyWriteBuffer(); 1014 vdac->over = 0x00; 1015 MachEmptyWriteBuffer(); 1016 vdac->over = 0x7f; 1017 MachEmptyWriteBuffer(); 1018 1019 vdac->overWA = 0x0c; 1020 MachEmptyWriteBuffer(); 1021 for (i = 0; i < 3; i++) { 1022 vdac->over = fg_RGB[i]; 1023 MachEmptyWriteBuffer(); 1024 } 1025 } 1026 1027 /* 1028 * ---------------------------------------------------------------------------- 1029 * 1030 * CursorColor -- 1031 * 1032 * Set the color of the cursor. 1033 * 1034 * Results: 1035 * None. 1036 * 1037 * Side effects: 1038 * None. 1039 * 1040 * ---------------------------------------------------------------------------- 1041 */ 1042 static void 1043 CursorColor(color) 1044 unsigned int color[]; 1045 { 1046 register int i, j; 1047 1048 for (i = 0; i < 3; i++) 1049 bg_RGB[i] = (u_char)(color[i] >> 8); 1050 1051 for (i = 3, j = 0; i < 6; i++, j++) 1052 fg_RGB[j] = (u_char)(color[i] >> 8); 1053 1054 RestoreCursorColor(); 1055 } 1056 1057 /* 1058 * ---------------------------------------------------------------------------- 1059 * 1060 * InitColorMap -- 1061 * 1062 * Initialize the color map. 1063 * 1064 * Results: 1065 * None. 1066 * 1067 * Side effects: 1068 * The colormap is initialized appropriately whether it is color or 1069 * monochrome. 1070 * 1071 * ---------------------------------------------------------------------------- 1072 */ 1073 static void 1074 InitColorMap() 1075 { 1076 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1077 register int i; 1078 1079 *(char *)MACH_PLANE_MASK_ADDR = 0xff; 1080 MachEmptyWriteBuffer(); 1081 1082 if (isMono) { 1083 vdac->mapWA = 0; MachEmptyWriteBuffer(); 1084 for (i = 0; i < 256; i++) { 1085 vdac->map = (i < 128) ? 0x00 : 0xff; 1086 MachEmptyWriteBuffer(); 1087 vdac->map = (i < 128) ? 0x00 : 0xff; 1088 MachEmptyWriteBuffer(); 1089 vdac->map = (i < 128) ? 0x00 : 0xff; 1090 MachEmptyWriteBuffer(); 1091 } 1092 } else { 1093 vdac->mapWA = 0; MachEmptyWriteBuffer(); 1094 vdac->map = 0; MachEmptyWriteBuffer(); 1095 vdac->map = 0; MachEmptyWriteBuffer(); 1096 vdac->map = 0; MachEmptyWriteBuffer(); 1097 1098 for (i = 1; i < 256; i++) { 1099 vdac->map = 0xff; MachEmptyWriteBuffer(); 1100 vdac->map = 0xff; MachEmptyWriteBuffer(); 1101 vdac->map = 0xff; MachEmptyWriteBuffer(); 1102 } 1103 } 1104 1105 for (i = 0; i < 3; i++) { 1106 bg_RGB[i] = 0x00; 1107 fg_RGB[i] = 0xff; 1108 } 1109 RestoreCursorColor(); 1110 } 1111 1112 /* 1113 * ---------------------------------------------------------------------------- 1114 * 1115 * VDACInit -- 1116 * 1117 * Initialize the VDAC. 1118 * 1119 * Results: 1120 * None. 1121 * 1122 * Side effects: 1123 * None. 1124 * 1125 * ---------------------------------------------------------------------------- 1126 */ 1127 static void 1128 VDACInit() 1129 { 1130 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1131 1132 /* 1133 * 1134 * Initialize the VDAC 1135 */ 1136 vdac->overWA = 0x04; MachEmptyWriteBuffer(); 1137 vdac->over = 0x00; MachEmptyWriteBuffer(); 1138 vdac->over = 0x00; MachEmptyWriteBuffer(); 1139 vdac->over = 0x00; MachEmptyWriteBuffer(); 1140 vdac->overWA = 0x08; MachEmptyWriteBuffer(); 1141 vdac->over = 0x00; MachEmptyWriteBuffer(); 1142 vdac->over = 0x00; MachEmptyWriteBuffer(); 1143 vdac->over = 0x7f; MachEmptyWriteBuffer(); 1144 vdac->overWA = 0x0c; MachEmptyWriteBuffer(); 1145 vdac->over = 0xff; MachEmptyWriteBuffer(); 1146 vdac->over = 0xff; MachEmptyWriteBuffer(); 1147 vdac->over = 0xff; MachEmptyWriteBuffer(); 1148 } 1149 1150 /* 1151 * ---------------------------------------------------------------------------- 1152 * 1153 * LoadColorMap -- 1154 * 1155 * Load the color map. 1156 * 1157 * Results: 1158 * None. 1159 * 1160 * Side effects: 1161 * The color map is loaded. 1162 * 1163 * ---------------------------------------------------------------------------- 1164 */ 1165 static void 1166 LoadColorMap(ptr) 1167 ColorMap *ptr; 1168 { 1169 register VDACRegs *vdac = (VDACRegs *)MACH_COLOR_MAP_ADDR; 1170 1171 if (ptr->index > 256) 1172 return; 1173 1174 vdac->mapWA = ptr->index; MachEmptyWriteBuffer(); 1175 vdac->map = ptr->Entry.red; MachEmptyWriteBuffer(); 1176 vdac->map = ptr->Entry.green; MachEmptyWriteBuffer(); 1177 vdac->map = ptr->Entry.blue; MachEmptyWriteBuffer(); 1178 } 1179 1180 /* 1181 *---------------------------------------------------------------------- 1182 * 1183 * PosCursor -- 1184 * 1185 * Postion the cursor. 1186 * 1187 * Results: 1188 * None. 1189 * 1190 * Side effects: 1191 * None. 1192 * 1193 *---------------------------------------------------------------------- 1194 */ 1195 static void 1196 PosCursor(x, y) 1197 register int x, y; 1198 { 1199 register PCCRegs *pcc = (PCCRegs *)MACH_CURSOR_REG_ADDR; 1200 1201 if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y) 1202 y = pmu.scrInfo.max_cur_y; 1203 if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x) 1204 x = pmu.scrInfo.max_cur_x; 1205 pmu.scrInfo.cursor.x = x; /* keep track of real cursor */ 1206 pmu.scrInfo.cursor.y = y; /* position, indep. of mouse */ 1207 pcc->xpos = PCC_X_OFFSET + x; 1208 pcc->ypos = PCC_Y_OFFSET + y; 1209 } 1210 #endif 1211