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. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)cfb.c 7.2 (Berkeley) 03/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 * Mach Operating System 31 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 32 * All Rights Reserved. 33 * 34 * Permission to use, copy, modify and distribute this software and its 35 * documentation is hereby granted, provided that both the copyright 36 * notice and this permission notice appear in all copies of the 37 * software, derivative works or modified versions, and any portions 38 * thereof, and that both notices appear in supporting documentation. 39 * 40 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 41 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 42 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 43 * 44 * Carnegie Mellon requests users of this software to return to 45 * 46 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 47 * School of Computer Science 48 * Carnegie Mellon University 49 * Pittsburgh PA 15213-3890 50 * 51 * any improvements or extensions that they make and grant Carnegie the 52 * rights to redistribute these changes. 53 */ 54 55 #include "cfb.h" 56 #if NCFB > 0 57 58 /* 59 * This is a device driver for the PMAG-BA color frame buffer 60 * on the TURBOchannel. 61 * XXX This is just to get a console working; 62 * it will need changes to work with X11R5. 63 */ 64 65 #include "param.h" 66 #include "time.h" 67 #include "kernel.h" 68 #include "ioctl.h" 69 #include "file.h" 70 #include "errno.h" 71 #include "proc.h" 72 #include "mman.h" 73 #include "vm/vm.h" 74 75 #include "machine/machConst.h" 76 #include "machine/machMon.h" 77 #include "machine/dc7085cons.h" 78 #include "machine/pmioctl.h" 79 80 #include "device.h" 81 #include "cfbreg.h" 82 #include "font.c" 83 84 #define MAX_ROW 56 85 #define MAX_COL 80 86 87 /* 88 * Macro to translate from a time struct to milliseconds. 89 */ 90 #define TO_MS(tv) ((tv.tv_sec * 1000) + (tv.tv_usec / 1000)) 91 92 static int isMono; /* true if B&W frame buffer */ 93 static int initialized; /* true if 'probe' was successful */ 94 static int GraphicsOpen; /* true if the graphics device is open */ 95 static int row, col; /* row and col for console cursor */ 96 static struct selinfo cfb_selp; /* process waiting for select */ 97 static unsigned fb_addr; /* frame buffer kernel virtual address */ 98 static unsigned planemask_addr; /* plane mask kernel virtual address */ 99 100 /* 101 * These need to be mapped into user space. 102 */ 103 static struct pmuaccess { 104 PM_Info scrInfo; 105 pmEvent events[PM_MAXEVQ]; 106 pmTimeCoord tcs[MOTION_BUFFER_SIZE]; 107 } pmu; 108 109 /* 110 * Font mask bits used by Blitc(). 111 */ 112 static unsigned int fontmaskBits[16] = { 113 0x00000000, 114 0x00000001, 115 0x00000100, 116 0x00000101, 117 0x00010000, 118 0x00010001, 119 0x00010100, 120 0x00010101, 121 0x01000000, 122 0x01000001, 123 0x01000100, 124 0x01000101, 125 0x01010000, 126 0x01010001, 127 0x01010100, 128 0x01010101 129 }; 130 131 /* 132 * Forward references. 133 */ 134 static void Scroll(); 135 static void Blitc(); 136 137 static void ScreenInit(); 138 static void LoadCursor(); 139 static void RestoreCursorColor(); 140 static void CursorColor(); 141 static void PosCursor(); 142 static void InitColorMap(); 143 static void LoadColorMap(); 144 static void EnableVideo(); 145 static void DisableVideo(); 146 147 extern void dcKBDPutc(); 148 extern void (*dcDivertXInput)(); 149 extern void (*dcMouseEvent)(); 150 extern void (*dcMouseButtons)(); 151 152 int cfbprobe(); 153 struct driver cfbdriver = { 154 "cfb", cfbprobe, 0, 0, 155 }; 156 157 /* 158 * Test to see if device is present. 159 * Return true if found and initialized ok. 160 */ 161 cfbprobe(cp) 162 register struct pmax_ctlr *cp; 163 { 164 165 if (!initialized) { 166 if (!cfb_init(cp)) 167 return (0); 168 } 169 printf("cfb%d at nexus0 csr 0x%x priority %d\n", 170 cp->pmax_unit, cp->pmax_addr, cp->pmax_pri); 171 return (1); 172 } 173 174 /* 175 *---------------------------------------------------------------------- 176 * 177 * cfbKbdEvent -- 178 * 179 * Process a received character. 180 * 181 * Results: 182 * None. 183 * 184 * Side effects: 185 * Events added to the queue. 186 * 187 *---------------------------------------------------------------------- 188 */ 189 void 190 cfbKbdEvent(ch) 191 int ch; 192 { 193 register pmEvent *eventPtr; 194 int i; 195 196 if (!GraphicsOpen) 197 return; 198 199 /* 200 * See if there is room in the queue. 201 */ 202 i = PM_EVROUND(pmu.scrInfo.qe.eTail + 1); 203 if (i == pmu.scrInfo.qe.eHead) 204 return; 205 206 /* 207 * Add the event to the queue. 208 */ 209 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 210 eventPtr->type = BUTTON_RAW_TYPE; 211 eventPtr->device = KEYBOARD_DEVICE; 212 eventPtr->x = pmu.scrInfo.mouse.x; 213 eventPtr->y = pmu.scrInfo.mouse.y; 214 eventPtr->time = TO_MS(time); 215 eventPtr->key = ch; 216 pmu.scrInfo.qe.eTail = i; 217 selwakeup(&cfb_selp); 218 } 219 220 /* 221 *---------------------------------------------------------------------- 222 * 223 * cfbMouseEvent -- 224 * 225 * Process a mouse event. 226 * 227 * Results: 228 * None. 229 * 230 * Side effects: 231 * An event is added to the event queue. 232 * 233 *---------------------------------------------------------------------- 234 */ 235 void 236 cfbMouseEvent(newRepPtr) 237 register MouseReport *newRepPtr; 238 { 239 unsigned milliSec; 240 int i; 241 pmEvent *eventPtr; 242 243 if (!GraphicsOpen) 244 return; 245 246 milliSec = TO_MS(time); 247 248 /* 249 * Check to see if we have to accelerate the mouse 250 */ 251 if (pmu.scrInfo.mscale >= 0) { 252 if (newRepPtr->dx >= pmu.scrInfo.mthreshold) { 253 newRepPtr->dx += 254 (newRepPtr->dx - pmu.scrInfo.mthreshold) * 255 pmu.scrInfo.mscale; 256 } 257 if (newRepPtr->dy >= pmu.scrInfo.mthreshold) { 258 newRepPtr->dy += 259 (newRepPtr->dy - pmu.scrInfo.mthreshold) * 260 pmu.scrInfo.mscale; 261 } 262 } 263 264 /* 265 * Update mouse position 266 */ 267 if (newRepPtr->state & MOUSE_X_SIGN) { 268 pmu.scrInfo.mouse.x += newRepPtr->dx; 269 if (pmu.scrInfo.mouse.x > pmu.scrInfo.max_cur_x) 270 pmu.scrInfo.mouse.x = pmu.scrInfo.max_cur_x; 271 } else { 272 pmu.scrInfo.mouse.x -= newRepPtr->dx; 273 if (pmu.scrInfo.mouse.x < pmu.scrInfo.min_cur_x) 274 pmu.scrInfo.mouse.x = pmu.scrInfo.min_cur_x; 275 } 276 if (newRepPtr->state & MOUSE_Y_SIGN) { 277 pmu.scrInfo.mouse.y -= newRepPtr->dy; 278 if (pmu.scrInfo.mouse.y < pmu.scrInfo.min_cur_y) 279 pmu.scrInfo.mouse.y = pmu.scrInfo.min_cur_y; 280 } else { 281 pmu.scrInfo.mouse.y += newRepPtr->dy; 282 if (pmu.scrInfo.mouse.y > pmu.scrInfo.max_cur_y) 283 pmu.scrInfo.mouse.y = pmu.scrInfo.max_cur_y; 284 } 285 286 /* 287 * Move the hardware cursor. 288 */ 289 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 290 291 /* 292 * Store the motion event in the motion buffer. 293 */ 294 pmu.tcs[pmu.scrInfo.qe.tcNext].time = milliSec; 295 pmu.tcs[pmu.scrInfo.qe.tcNext].x = pmu.scrInfo.mouse.x; 296 pmu.tcs[pmu.scrInfo.qe.tcNext].y = pmu.scrInfo.mouse.y; 297 if (++pmu.scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE) 298 pmu.scrInfo.qe.tcNext = 0; 299 if (pmu.scrInfo.mouse.y < pmu.scrInfo.mbox.bottom && 300 pmu.scrInfo.mouse.y >= pmu.scrInfo.mbox.top && 301 pmu.scrInfo.mouse.x < pmu.scrInfo.mbox.right && 302 pmu.scrInfo.mouse.x >= pmu.scrInfo.mbox.left) 303 return; 304 305 pmu.scrInfo.mbox.bottom = 0; 306 if (PM_EVROUND(pmu.scrInfo.qe.eTail + 1) == pmu.scrInfo.qe.eHead) 307 return; 308 309 i = PM_EVROUND(pmu.scrInfo.qe.eTail - 1); 310 if ((pmu.scrInfo.qe.eTail != pmu.scrInfo.qe.eHead) && 311 (i != pmu.scrInfo.qe.eHead)) { 312 pmEvent *eventPtr; 313 314 eventPtr = &pmu.events[i]; 315 if (eventPtr->type == MOTION_TYPE) { 316 eventPtr->x = pmu.scrInfo.mouse.x; 317 eventPtr->y = pmu.scrInfo.mouse.y; 318 eventPtr->time = milliSec; 319 eventPtr->device = MOUSE_DEVICE; 320 return; 321 } 322 } 323 /* 324 * Put event into queue and wakeup any waiters. 325 */ 326 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 327 eventPtr->type = MOTION_TYPE; 328 eventPtr->time = milliSec; 329 eventPtr->x = pmu.scrInfo.mouse.x; 330 eventPtr->y = pmu.scrInfo.mouse.y; 331 eventPtr->device = MOUSE_DEVICE; 332 pmu.scrInfo.qe.eTail = PM_EVROUND(pmu.scrInfo.qe.eTail + 1); 333 selwakeup(&cfb_selp); 334 } 335 336 /* 337 *---------------------------------------------------------------------- 338 * 339 * cfbMouseButtons -- 340 * 341 * Process mouse buttons. 342 * 343 * Results: 344 * None. 345 * 346 * Side effects: 347 * None. 348 * 349 *---------------------------------------------------------------------- 350 */ 351 void 352 cfbMouseButtons(newRepPtr) 353 MouseReport *newRepPtr; 354 { 355 static char temp, oldSwitch, newSwitch; 356 int i, j; 357 pmEvent *eventPtr; 358 static MouseReport lastRep; 359 360 if (!GraphicsOpen) 361 return; 362 363 newSwitch = newRepPtr->state & 0x07; 364 oldSwitch = lastRep.state & 0x07; 365 366 temp = oldSwitch ^ newSwitch; 367 if (temp == 0) 368 return; 369 for (j = 1; j < 8; j <<= 1) { 370 if ((j & temp) == 0) 371 continue; 372 373 /* 374 * Check for room in the queue 375 */ 376 i = PM_EVROUND(pmu.scrInfo.qe.eTail+1); 377 if (i == pmu.scrInfo.qe.eHead) 378 return; 379 380 /* 381 * Put event into queue. 382 */ 383 eventPtr = &pmu.events[pmu.scrInfo.qe.eTail]; 384 385 switch (j) { 386 case RIGHT_BUTTON: 387 eventPtr->key = EVENT_RIGHT_BUTTON; 388 break; 389 390 case MIDDLE_BUTTON: 391 eventPtr->key = EVENT_MIDDLE_BUTTON; 392 break; 393 394 case LEFT_BUTTON: 395 eventPtr->key = EVENT_LEFT_BUTTON; 396 } 397 if (newSwitch & j) 398 eventPtr->type = BUTTON_DOWN_TYPE; 399 else 400 eventPtr->type = BUTTON_UP_TYPE; 401 eventPtr->device = MOUSE_DEVICE; 402 403 eventPtr->time = TO_MS(time); 404 eventPtr->x = pmu.scrInfo.mouse.x; 405 eventPtr->y = pmu.scrInfo.mouse.y; 406 } 407 pmu.scrInfo.qe.eTail = i; 408 selwakeup(&cfb_selp); 409 410 lastRep = *newRepPtr; 411 pmu.scrInfo.mswitches = newSwitch; 412 } 413 414 /* 415 *---------------------------------------------------------------------- 416 * 417 * Scroll -- 418 * 419 * Scroll the screen. 420 * 421 * Results: 422 * None. 423 * 424 * Side effects: 425 * None. 426 * 427 *---------------------------------------------------------------------- 428 */ 429 static void 430 Scroll() 431 { 432 register int *dest, *src; 433 register int *end; 434 register int temp0, temp1, temp2, temp3; 435 register int i, scanInc, lineCount; 436 int line; 437 438 /* 439 * If the mouse is on we don't scroll so that the bit map remains sane. 440 */ 441 if (GraphicsOpen) { 442 row = 0; 443 return; 444 } 445 446 /* 447 * The following is an optimization to cause the scrolling 448 * of text to be memory limited. Basically the writebuffer is 449 * 4 words (32 bits ea.) long so to achieve maximum speed we 450 * read and write in multiples of 4 words. We also limit the 451 * size to be MAX_COL characters for more speed. 452 */ 453 if (isMono) { 454 lineCount = 5; 455 line = 1920 * 2; 456 scanInc = 44; 457 } else { 458 lineCount = 40; 459 scanInc = 96; 460 line = 1920 * 8; 461 } 462 src = (int *)(fb_addr + line); 463 dest = (int *)(fb_addr); 464 end = (int *)(fb_addr + (60 * line) - line); 465 do { 466 i = 0; 467 do { 468 temp0 = src[0]; 469 temp1 = src[1]; 470 temp2 = src[2]; 471 temp3 = src[3]; 472 dest[0] = temp0; 473 dest[1] = temp1; 474 dest[2] = temp2; 475 dest[3] = temp3; 476 dest += 4; 477 src += 4; 478 i++; 479 } while (i < lineCount); 480 src += scanInc; 481 dest += scanInc; 482 } while (src < end); 483 484 /* 485 * Now zero out the last two lines 486 */ 487 bzero(fb_addr + (row * line), 3 * line); 488 } 489 490 /* 491 *---------------------------------------------------------------------- 492 * 493 * cfbPutc -- 494 * 495 * Write a character to the console. 496 * 497 * Results: 498 * None. 499 * 500 * Side effects: 501 * None. 502 * 503 *---------------------------------------------------------------------- 504 */ 505 cfbPutc(c) 506 register int c; 507 { 508 int s; 509 510 s = splhigh(); /* in case we do any printf's at interrupt time */ 511 if (initialized) { 512 #ifdef DEBUG 513 /* 514 * If the HELP key is pressed, wait for another 515 * HELP key press to start/stop output. 516 */ 517 if (dcDebugGetc() == LK_HELP) { 518 while (dcDebugGetc() != LK_HELP) 519 ; 520 } 521 #endif 522 Blitc(c); 523 } else { 524 void (*f)() = (void (*)())MACH_MON_PUTCHAR; 525 526 (*f)(c); 527 } 528 splx(s); 529 } 530 531 /* 532 *---------------------------------------------------------------------- 533 * 534 * Blitc -- 535 * 536 * Write a character to the screen. 537 * 538 * Results: 539 * None. 540 * 541 * Side effects: 542 * None. 543 * 544 *---------------------------------------------------------------------- 545 */ 546 static void 547 Blitc(c) 548 register int c; 549 { 550 register char *bRow, *fRow; 551 register int i; 552 register int ote = isMono ? 256 : 1024; /* offset to table entry */ 553 int colMult = isMono ? 1 : 8; 554 555 c &= 0xff; 556 557 switch (c) { 558 case '\t': 559 for (i = 8 - (col & 0x7); i > 0; i--) 560 Blitc(' '); 561 break; 562 563 case '\r': 564 col = 0; 565 break; 566 567 case '\b': 568 col--; 569 if (col < 0) 570 col = 0; 571 break; 572 573 case '\n': 574 if (row + 1 >= MAX_ROW) 575 Scroll(); 576 else 577 row++; 578 col = 0; 579 break; 580 581 case '\007': 582 dcKBDPutc(LK_RING_BELL); 583 break; 584 585 default: 586 /* 587 * 0xA1 to 0xFD are the printable characters added with 8-bit 588 * support. 589 */ 590 if (c < ' ' || c > '~' && c < 0xA1 || c > 0xFD) 591 break; 592 /* 593 * If the next character will wrap around then 594 * increment row counter or scroll screen. 595 */ 596 if (col >= MAX_COL) { 597 col = 0; 598 if (row + 1 >= MAX_ROW) 599 Scroll(); 600 else 601 row++; 602 } 603 bRow = (char *)(fb_addr + 604 (row * 15 & 0x3ff) * ote + col * colMult); 605 i = c - ' '; 606 /* 607 * This is to skip the (32) 8-bit 608 * control chars, as well as DEL 609 * and 0xA0 which aren't printable 610 */ 611 if (c > '~') 612 i -= 34; 613 i *= 15; 614 fRow = (char *)((int)pmFont + i); 615 616 /* inline expansion for speed */ 617 if (isMono) { 618 *bRow = *fRow++; bRow += ote; 619 *bRow = *fRow++; bRow += ote; 620 *bRow = *fRow++; bRow += ote; 621 *bRow = *fRow++; bRow += ote; 622 *bRow = *fRow++; bRow += ote; 623 *bRow = *fRow++; bRow += ote; 624 *bRow = *fRow++; bRow += ote; 625 *bRow = *fRow++; bRow += ote; 626 *bRow = *fRow++; bRow += ote; 627 *bRow = *fRow++; bRow += ote; 628 *bRow = *fRow++; bRow += ote; 629 *bRow = *fRow++; bRow += ote; 630 *bRow = *fRow++; bRow += ote; 631 *bRow = *fRow++; bRow += ote; 632 *bRow = *fRow++; bRow += ote; 633 } else { 634 register int j; 635 register unsigned int *pInt; 636 637 pInt = (unsigned int *)bRow; 638 for (j = 0; j < 15; j++) { 639 /* 640 * fontmaskBits converts a nibble 641 * (4 bytes) to a long word 642 * containing 4 pixels corresponding 643 * to each bit in the nibble. Thus 644 * we write two longwords for each 645 * byte in font. 646 * 647 * Remember the font is 8 bits wide 648 * and 15 bits high. 649 * 650 * We add 256 to the pointer to 651 * point to the pixel on the 652 * next scan line 653 * directly below the current 654 * pixel. 655 */ 656 pInt[0] = fontmaskBits[(*fRow) & 0xf]; 657 pInt[1] = fontmaskBits[((*fRow) >> 4) & 0xf]; 658 fRow++; 659 pInt += 256; 660 } 661 } 662 col++; /* increment column counter */ 663 } 664 if (!GraphicsOpen) 665 PosCursor(col * 8, row * 15); 666 } 667 668 /*ARGSUSED*/ 669 cfbopen(dev, flag) 670 dev_t dev; 671 int flag; 672 { 673 674 if (!initialized) 675 return (ENXIO); 676 if (GraphicsOpen) 677 return (EBUSY); 678 679 GraphicsOpen = 1; 680 if (!isMono) 681 InitColorMap(); 682 /* 683 * Set up event queue for later 684 */ 685 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 686 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 687 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 688 pmu.scrInfo.qe.tcNext = 0; 689 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 690 return (0); 691 } 692 693 /*ARGSUSED*/ 694 cfbclose(dev, flag) 695 dev_t dev; 696 int flag; 697 { 698 int s; 699 700 if (!GraphicsOpen) 701 return (EBADF); 702 703 GraphicsOpen = 0; 704 if (!isMono) 705 InitColorMap(); 706 s = spltty(); 707 dcDivertXInput = (void (*)())0; 708 dcMouseEvent = (void (*)())0; 709 dcMouseButtons = (void (*)())0; 710 splx(s); 711 ScreenInit(); 712 vmUserUnmap(); 713 bzero(fb_addr, (isMono ? 1024 / 8 : 1024) * 864); 714 PosCursor(col * 8, row * 15); 715 return (0); 716 } 717 718 /*ARGSUSED*/ 719 cfbioctl(dev, cmd, data, flag) 720 dev_t dev; 721 caddr_t data; 722 { 723 int s; 724 725 switch (cmd) { 726 case QIOCGINFO: 727 { 728 caddr_t addr; 729 extern caddr_t vmUserMap(); 730 731 /* 732 * Map the all the data the user needs access to into 733 * user space. 734 */ 735 addr = vmUserMap(sizeof(pmu), (unsigned)&pmu); 736 if (addr == (caddr_t)0) 737 goto mapError; 738 *(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo; 739 pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events; 740 pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs; 741 /* 742 * Map the plane mask into the user's address space. 743 */ 744 addr = vmUserMap(4, planemask_addr); 745 if (addr == (caddr_t)0) 746 goto mapError; 747 pmu.scrInfo.planemask = (char *)addr; 748 /* 749 * Map the frame buffer into the user's address space. 750 */ 751 addr = vmUserMap(isMono ? 256*1024 : 1024*1024, fb_addr); 752 if (addr == (caddr_t)0) 753 goto mapError; 754 pmu.scrInfo.bitmap = (char *)addr; 755 break; 756 757 mapError: 758 vmUserUnmap(); 759 printf("Cannot map shared data structures\n"); 760 return (EIO); 761 } 762 763 case QIOCPMSTATE: 764 /* 765 * Set mouse state. 766 */ 767 pmu.scrInfo.mouse = *(pmCursor *)data; 768 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 769 break; 770 771 case QIOCINIT: 772 /* 773 * Initialize the screen. 774 */ 775 ScreenInit(); 776 break; 777 778 case QIOCKPCMD: 779 { 780 pmKpCmd *kpCmdPtr; 781 unsigned char *cp; 782 783 kpCmdPtr = (pmKpCmd *)data; 784 if (kpCmdPtr->nbytes == 0) 785 kpCmdPtr->cmd |= 0x80; 786 if (!GraphicsOpen) 787 kpCmdPtr->cmd |= 1; 788 dcKBDPutc((int)kpCmdPtr->cmd); 789 cp = &kpCmdPtr->par[0]; 790 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 791 if (kpCmdPtr->nbytes == 1) 792 *cp |= 0x80; 793 dcKBDPutc((int)*cp); 794 } 795 break; 796 } 797 798 case QIOCADDR: 799 *(PM_Info **)data = &pmu.scrInfo; 800 break; 801 802 case QIOWCURSOR: 803 LoadCursor((unsigned short *)data); 804 break; 805 806 case QIOWCURSORCOLOR: 807 CursorColor((unsigned int *)data); 808 break; 809 810 case QIOSETCMAP: 811 LoadColorMap((ColorMap *)data); 812 break; 813 814 case QIOKERNLOOP: 815 s = spltty(); 816 dcDivertXInput = cfbKbdEvent; 817 dcMouseEvent = cfbMouseEvent; 818 dcMouseButtons = cfbMouseButtons; 819 splx(s); 820 break; 821 822 case QIOKERNUNLOOP: 823 s = spltty(); 824 dcDivertXInput = (void (*)())0; 825 dcMouseEvent = (void (*)())0; 826 dcMouseButtons = (void (*)())0; 827 splx(s); 828 break; 829 830 case QIOVIDEOON: 831 EnableVideo(); 832 break; 833 834 case QIOVIDEOOFF: 835 DisableVideo(); 836 break; 837 838 default: 839 printf("cfb0: Unknown ioctl command %x\n", cmd); 840 return (EINVAL); 841 } 842 return (0); 843 } 844 845 cfbselect(dev, flag, p) 846 dev_t dev; 847 int flag; 848 struct proc *p; 849 { 850 851 switch (flag) { 852 case FREAD: 853 if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail) 854 return (1); 855 selrecord(p, &cfb_selp); 856 break; 857 } 858 859 return (0); 860 } 861 862 static u_char cursor_RGB[6]; /* cursor color 2 & 3 */ 863 864 /* 865 * The default cursor. 866 */ 867 static unsigned short defCursor[1024] = { 868 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 869 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 870 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 871 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 872 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 873 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 874 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 875 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 876 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 877 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 878 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 879 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 880 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 881 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 882 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 883 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 884 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 885 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 886 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 887 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 888 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 889 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 890 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 891 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 892 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 893 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 894 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 895 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 896 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 897 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 898 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 899 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 900 }; 901 902 #define CFB_OFFSET_VRAM 0x0 /* from module's base */ 903 /* Replicated at x100000 */ 904 #define CFB_OFFSET_BT459 0x200000 /* Bt459 registers */ 905 #define CFB_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 906 #define CFB_OFFSET_ROM 0x380000 /* Diagnostic ROM */ 907 #define CFB_OFFSET_RESET 0x3c0000 /* Bt459 resets on writes */ 908 909 /* 910 * Generic register access 911 */ 912 void 913 bt459_select_reg(regs, regno) 914 bt459_regmap_t *regs; 915 { 916 regs->addr_lo = regno; 917 regs->addr_hi = regno >> 8; 918 MachEmptyWriteBuffer(); 919 } 920 921 void 922 bt459_write_reg(regs, regno, val) 923 bt459_regmap_t *regs; 924 { 925 regs->addr_lo = regno; 926 regs->addr_hi = regno >> 8; 927 MachEmptyWriteBuffer(); 928 regs->addr_reg = val; 929 MachEmptyWriteBuffer(); 930 } 931 932 unsigned char 933 bt459_read_reg(regs, regno) 934 bt459_regmap_t *regs; 935 { 936 regs->addr_lo = regno; 937 regs->addr_hi = regno >> 8; 938 MachEmptyWriteBuffer(); 939 return regs->addr_reg; 940 } 941 942 #ifdef DEBUG 943 bt459_print_colormap(regs) 944 bt459_regmap_t *regs; 945 { 946 register int i; 947 948 bt459_select_reg(regs, 0); 949 for (i = 0; i < 256; i++) { 950 register unsigned red, green, blue; 951 952 red = regs->addr_cmap; 953 green = regs->addr_cmap; 954 blue = regs->addr_cmap; 955 printf("%x->[x%x x%x x%x]\n", i, red, green, blue); 956 } 957 } 958 #endif 959 960 /* 961 * Test to see if device is present. 962 * Return true if found and initialized ok. 963 */ 964 cfb_init(cp) 965 register struct pmax_ctlr *cp; 966 { 967 bt459_regmap_t *regs; 968 969 /* check for no frame buffer */ 970 if (badaddr(cp->pmax_addr, 4)) 971 return (0); 972 973 fb_addr = (unsigned)cp->pmax_addr + CFB_OFFSET_VRAM; 974 planemask_addr = 0; /* XXX */ 975 regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 976 977 if (bt459_read_reg(regs, BT459_REG_ID) != 0x4a) 978 return (0); 979 980 *(int *)(fb_addr + CFB_OFFSET_RESET) = 0; /* force chip reset */ 981 DELAY(2000); /* ???? check right time on specs! ???? */ 982 983 /* use 4:1 input mux */ 984 bt459_write_reg(regs, BT459_REG_CMD0, 0x40); 985 986 /* no zooming, no panning */ 987 bt459_write_reg(regs, BT459_REG_CMD1, 0x00); 988 989 /* 990 * signature test, X-windows cursor, no overlays, SYNC* PLL, 991 * normal RAM select, 7.5 IRE pedestal, do sync 992 */ 993 bt459_write_reg(regs, BT459_REG_CMD2, 0xc2); 994 995 /* get all pixel bits */ 996 bt459_write_reg(regs, BT459_REG_PRM, 0xff); 997 998 /* no blinking */ 999 bt459_write_reg(regs, BT459_REG_PBM, 0x00); 1000 1001 /* no overlay */ 1002 bt459_write_reg(regs, BT459_REG_ORM, 0x00); 1003 1004 /* no overlay blink */ 1005 bt459_write_reg(regs, BT459_REG_OBM, 0x00); 1006 1007 /* no interleave, no underlay */ 1008 bt459_write_reg(regs, BT459_REG_ILV, 0x00); 1009 1010 /* normal operation, no signature analysis */ 1011 bt459_write_reg(regs, BT459_REG_TEST, 0x00); 1012 1013 /* 1014 * no blinking, 1bit cross hair, XOR reg&crosshair, 1015 * no crosshair on either plane 0 or 1, 1016 * regular cursor on both planes. 1017 */ 1018 bt459_write_reg(regs, BT459_REG_CCR, 0xc0); 1019 1020 /* home cursor */ 1021 bt459_write_reg(regs, BT459_REG_CXLO, 0x00); 1022 bt459_write_reg(regs, BT459_REG_CXHI, 0x00); 1023 bt459_write_reg(regs, BT459_REG_CYLO, 0x00); 1024 bt459_write_reg(regs, BT459_REG_CYHI, 0x00); 1025 1026 /* no crosshair window */ 1027 bt459_write_reg(regs, BT459_REG_WXLO, 0x00); 1028 bt459_write_reg(regs, BT459_REG_WXHI, 0x00); 1029 bt459_write_reg(regs, BT459_REG_WYLO, 0x00); 1030 bt459_write_reg(regs, BT459_REG_WYHI, 0x00); 1031 bt459_write_reg(regs, BT459_REG_WWLO, 0x00); 1032 bt459_write_reg(regs, BT459_REG_WWHI, 0x00); 1033 bt459_write_reg(regs, BT459_REG_WHLO, 0x00); 1034 bt459_write_reg(regs, BT459_REG_WHHI, 0x00); 1035 1036 /* 1037 * Initialize screen info. 1038 */ 1039 pmu.scrInfo.max_row = MAX_ROW; 1040 pmu.scrInfo.max_col = MAX_COL; 1041 pmu.scrInfo.max_x = 1024; 1042 pmu.scrInfo.max_y = 864; 1043 pmu.scrInfo.max_cur_x = 1023; 1044 pmu.scrInfo.max_cur_y = 863; 1045 pmu.scrInfo.version = 11; 1046 pmu.scrInfo.mthreshold = 4; 1047 pmu.scrInfo.mscale = 2; 1048 pmu.scrInfo.min_cur_x = 0; 1049 pmu.scrInfo.min_cur_y = 0; 1050 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 1051 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 1052 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 1053 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 1054 pmu.scrInfo.qe.tcNext = 0; 1055 1056 /* 1057 * Initialize the color map, the screen, and the mouse. 1058 */ 1059 InitColorMap(); 1060 ScreenInit(); 1061 Scroll(); 1062 1063 initialized = 1; 1064 return (1); 1065 } 1066 1067 /* 1068 * ---------------------------------------------------------------------------- 1069 * 1070 * ScreenInit -- 1071 * 1072 * Initialize the screen. 1073 * 1074 * Results: 1075 * None. 1076 * 1077 * Side effects: 1078 * The screen is initialized. 1079 * 1080 * ---------------------------------------------------------------------------- 1081 */ 1082 static void 1083 ScreenInit() 1084 { 1085 1086 /* 1087 * Home the cursor. 1088 * We want an LSI terminal emulation. We want the graphics 1089 * terminal to scroll from the bottom. So start at the bottom. 1090 */ 1091 row = 55; 1092 col = 0; 1093 1094 /* 1095 * Load the cursor with the default values 1096 * 1097 */ 1098 LoadCursor(defCursor); 1099 } 1100 1101 /* 1102 * ---------------------------------------------------------------------------- 1103 * 1104 * LoadCursor -- 1105 * 1106 * Routine to load the cursor Sprite pattern. 1107 * 1108 * Results: 1109 * None. 1110 * 1111 * Side effects: 1112 * The cursor is loaded into the hardware cursor. 1113 * 1114 * ---------------------------------------------------------------------------- 1115 */ 1116 static void 1117 LoadCursor(cur) 1118 unsigned short *cur; 1119 { 1120 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1121 register int i, j; 1122 1123 /* 1124 * As per specs, must run a check to see if we 1125 * had contention. If so, re-write the cursor. 1126 */ 1127 for (j = 0; j < 2; j++) { 1128 /* loop once to write */ 1129 bt459_select_reg(regs, BT459_REG_CRAM_BASE); 1130 for (i = 0; i < 1024; i++) { 1131 regs->addr_reg = cur[i]; 1132 MachEmptyWriteBuffer(); 1133 } 1134 1135 /* loop to check, if fail write again */ 1136 bt459_select_reg(regs, BT459_REG_CRAM_BASE); 1137 for (i = 0; i < 1024; i++) 1138 if (regs->addr_reg != cur[i]) 1139 break; 1140 if (i == 1024) 1141 break; /* all went well first shot */ 1142 } 1143 } 1144 1145 /* 1146 * ---------------------------------------------------------------------------- 1147 * 1148 * RestoreCursorColor -- 1149 * 1150 * Routine to restore the color of the cursor. 1151 * 1152 * Results: 1153 * None. 1154 * 1155 * Side effects: 1156 * None. 1157 * 1158 * ---------------------------------------------------------------------------- 1159 */ 1160 static void 1161 RestoreCursorColor() 1162 { 1163 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1164 register int i; 1165 1166 bt459_select_reg(regs, BT459_REG_CCOLOR_2); 1167 for (i = 0; i < 6; i++) { 1168 regs->addr_reg = cursor_RGB[i]; 1169 MachEmptyWriteBuffer(); 1170 } 1171 } 1172 1173 /* 1174 * ---------------------------------------------------------------------------- 1175 * 1176 * CursorColor -- 1177 * 1178 * Set the color of the cursor. 1179 * 1180 * Results: 1181 * None. 1182 * 1183 * Side effects: 1184 * None. 1185 * 1186 * ---------------------------------------------------------------------------- 1187 */ 1188 static void 1189 CursorColor(color) 1190 unsigned int color[]; 1191 { 1192 register int i, j; 1193 1194 for (i = 0; i < 6; i++) 1195 cursor_RGB[i] = (u_char)(color[i] >> 8); 1196 1197 RestoreCursorColor(); 1198 } 1199 1200 /* 1201 *---------------------------------------------------------------------- 1202 * 1203 * PosCursor -- 1204 * 1205 * Postion the cursor. 1206 * 1207 * Results: 1208 * None. 1209 * 1210 * Side effects: 1211 * None. 1212 * 1213 *---------------------------------------------------------------------- 1214 */ 1215 static void 1216 PosCursor(x, y) 1217 register int x, y; 1218 { 1219 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1220 1221 if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y) 1222 y = pmu.scrInfo.max_cur_y; 1223 if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x) 1224 x = pmu.scrInfo.max_cur_x; 1225 pmu.scrInfo.cursor.x = x; /* keep track of real cursor */ 1226 pmu.scrInfo.cursor.y = y; /* position, indep. of mouse */ 1227 1228 x += 219; 1229 y += 34; 1230 1231 bt459_select_reg(regs, BT459_REG_CXLO); 1232 regs->addr_reg = x; 1233 MachEmptyWriteBuffer(); 1234 regs->addr_reg = x >> 8; 1235 MachEmptyWriteBuffer(); 1236 regs->addr_reg = y; 1237 MachEmptyWriteBuffer(); 1238 regs->addr_reg = y >> 8; 1239 MachEmptyWriteBuffer(); 1240 } 1241 1242 /* 1243 * ---------------------------------------------------------------------------- 1244 * 1245 * InitColorMap -- 1246 * 1247 * Initialize the color map. 1248 * 1249 * Results: 1250 * None. 1251 * 1252 * Side effects: 1253 * The colormap is initialized appropriately. 1254 * 1255 * ---------------------------------------------------------------------------- 1256 */ 1257 static void 1258 InitColorMap() 1259 { 1260 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1261 register int i; 1262 1263 bt459_select_reg(regs, 0); 1264 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1265 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1266 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1267 1268 for (i = 1; i < 256; i++) { 1269 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1270 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1271 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1272 } 1273 1274 for (i = 0; i < 3; i++) { 1275 cursor_RGB[i] = 0x00; 1276 cursor_RGB[i + 3] = 0xff; 1277 } 1278 RestoreCursorColor(); 1279 } 1280 1281 /* 1282 * ---------------------------------------------------------------------------- 1283 * 1284 * LoadColorMap -- 1285 * 1286 * Load the color map. 1287 * 1288 * Results: 1289 * None. 1290 * 1291 * Side effects: 1292 * The color map is loaded. 1293 * 1294 * ---------------------------------------------------------------------------- 1295 */ 1296 static void 1297 LoadColorMap(ptr) 1298 ColorMap *ptr; 1299 { 1300 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1301 1302 if (ptr->index > 256) 1303 return; 1304 1305 bt459_select_reg(regs, ptr->index); 1306 1307 regs->addr_cmap = ptr->Entry.red; MachEmptyWriteBuffer(); 1308 regs->addr_cmap = ptr->Entry.green; MachEmptyWriteBuffer(); 1309 regs->addr_cmap = ptr->Entry.blue; MachEmptyWriteBuffer(); 1310 } 1311 1312 /* 1313 * Video on/off state. 1314 */ 1315 struct vstate { 1316 u_char color0[3]; /* saved color map entry zero */ 1317 u_char off; /* TRUE if display is off */ 1318 } vstate; 1319 1320 /* 1321 * ---------------------------------------------------------------------------- 1322 * 1323 * EnableVideo -- 1324 * 1325 * Enable the video display. 1326 * 1327 * Results: 1328 * None. 1329 * 1330 * Side effects: 1331 * The display is enabled. 1332 * 1333 * ---------------------------------------------------------------------------- 1334 */ 1335 static void 1336 EnableVideo() 1337 { 1338 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1339 1340 if (!vstate.off) 1341 return; 1342 1343 /* restore old color map entry zero */ 1344 bt459_select_reg(regs, 0); 1345 regs->addr_cmap = vstate.color0[0]; 1346 MachEmptyWriteBuffer(); 1347 regs->addr_cmap = vstate.color0[1]; 1348 MachEmptyWriteBuffer(); 1349 regs->addr_cmap = vstate.color0[2]; 1350 MachEmptyWriteBuffer(); 1351 1352 /* enable normal display */ 1353 bt459_write_reg(regs, BT459_REG_PRM, 0xff); 1354 bt459_write_reg(regs, BT459_REG_CCR, 0xc0); 1355 1356 vstate.off = 0; 1357 } 1358 1359 /* 1360 * ---------------------------------------------------------------------------- 1361 * 1362 * DisableVideo -- 1363 * 1364 * Disable the video display. 1365 * 1366 * Results: 1367 * None. 1368 * 1369 * Side effects: 1370 * The display is disabled. 1371 * 1372 * ---------------------------------------------------------------------------- 1373 */ 1374 static void 1375 DisableVideo() 1376 { 1377 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1378 1379 if (vstate.off) 1380 return; 1381 1382 /* save old color map entry zero */ 1383 bt459_select_reg(regs, 0); 1384 vstate.color0[0] = regs->addr_cmap; 1385 vstate.color0[1] = regs->addr_cmap; 1386 vstate.color0[2] = regs->addr_cmap; 1387 1388 /* set color map entry zero to zero */ 1389 bt459_select_reg(regs, 0); 1390 regs->addr_cmap = 0; 1391 MachEmptyWriteBuffer(); 1392 regs->addr_cmap = 0; 1393 MachEmptyWriteBuffer(); 1394 regs->addr_cmap = 0; 1395 MachEmptyWriteBuffer(); 1396 1397 /* disable display */ 1398 bt459_write_reg(regs, BT459_REG_PRM, 0); 1399 bt459_write_reg(regs, BT459_REG_CCR, 0); 1400 1401 vstate.off = 1; 1402 } 1403 #endif 1404