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