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