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.1 (Berkeley) 03/09/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 699 if (!GraphicsOpen) 700 return (EBADF); 701 702 GraphicsOpen = 0; 703 if (!isMono) 704 InitColorMap(); 705 ScreenInit(); 706 vmUserUnmap(); 707 bzero(fb_addr, (isMono ? 1024 / 8 : 1024) * 864); 708 PosCursor(col * 8, row * 15); 709 return (0); 710 } 711 712 /*ARGSUSED*/ 713 cfbioctl(dev, cmd, data, flag) 714 dev_t dev; 715 caddr_t data; 716 { 717 718 switch (cmd) { 719 case QIOCGINFO: 720 { 721 caddr_t addr; 722 extern caddr_t vmUserMap(); 723 724 /* 725 * Map the all the data the user needs access to into 726 * user space. 727 */ 728 addr = vmUserMap(sizeof(pmu), (unsigned)&pmu); 729 if (addr == (caddr_t)0) 730 goto mapError; 731 *(PM_Info **)data = &((struct pmuaccess *)addr)->scrInfo; 732 pmu.scrInfo.qe.events = ((struct pmuaccess *)addr)->events; 733 pmu.scrInfo.qe.tcs = ((struct pmuaccess *)addr)->tcs; 734 /* 735 * Map the plane mask into the user's address space. 736 */ 737 addr = vmUserMap(4, planemask_addr); 738 if (addr == (caddr_t)0) 739 goto mapError; 740 pmu.scrInfo.planemask = (char *)addr; 741 /* 742 * Map the frame buffer into the user's address space. 743 */ 744 addr = vmUserMap(isMono ? 256*1024 : 1024*1024, fb_addr); 745 if (addr == (caddr_t)0) 746 goto mapError; 747 pmu.scrInfo.bitmap = (char *)addr; 748 break; 749 750 mapError: 751 vmUserUnmap(); 752 printf("Cannot map shared data structures\n"); 753 return (EIO); 754 } 755 756 case QIOCPMSTATE: 757 /* 758 * Set mouse state. 759 */ 760 pmu.scrInfo.mouse = *(pmCursor *)data; 761 PosCursor(pmu.scrInfo.mouse.x, pmu.scrInfo.mouse.y); 762 break; 763 764 case QIOCINIT: 765 /* 766 * Initialize the screen. 767 */ 768 ScreenInit(); 769 break; 770 771 case QIOCKPCMD: 772 { 773 pmKpCmd *kpCmdPtr; 774 unsigned char *cp; 775 776 kpCmdPtr = (pmKpCmd *)data; 777 if (kpCmdPtr->nbytes == 0) 778 kpCmdPtr->cmd |= 0x80; 779 if (!GraphicsOpen) 780 kpCmdPtr->cmd |= 1; 781 dcKBDPutc((int)kpCmdPtr->cmd); 782 cp = &kpCmdPtr->par[0]; 783 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 784 if (kpCmdPtr->nbytes == 1) 785 *cp |= 0x80; 786 dcKBDPutc((int)*cp); 787 } 788 break; 789 } 790 791 case QIOCADDR: 792 *(PM_Info **)data = &pmu.scrInfo; 793 break; 794 795 case QIOWCURSOR: 796 LoadCursor((unsigned short *)data); 797 break; 798 799 case QIOWCURSORCOLOR: 800 CursorColor((unsigned int *)data); 801 break; 802 803 case QIOSETCMAP: 804 LoadColorMap((ColorMap *)data); 805 break; 806 807 case QIOKERNLOOP: 808 dcDivertXInput = cfbKbdEvent; 809 dcMouseEvent = cfbMouseEvent; 810 dcMouseButtons = cfbMouseButtons; 811 break; 812 813 case QIOKERNUNLOOP: 814 dcDivertXInput = (void (*)())0; 815 dcMouseEvent = (void (*)())0; 816 dcMouseButtons = (void (*)())0; 817 break; 818 819 case QIOVIDEOON: 820 EnableVideo(); 821 break; 822 823 case QIOVIDEOOFF: 824 DisableVideo(); 825 break; 826 827 default: 828 printf("cfb0: Unknown ioctl command %x\n", cmd); 829 return (EINVAL); 830 } 831 return (0); 832 } 833 834 cfbselect(dev, flag, p) 835 dev_t dev; 836 int flag; 837 struct proc *p; 838 { 839 840 switch (flag) { 841 case FREAD: 842 if (pmu.scrInfo.qe.eHead != pmu.scrInfo.qe.eTail) 843 return (1); 844 selrecord(p, &cfb_selp); 845 break; 846 } 847 848 return (0); 849 } 850 851 static u_char cursor_RGB[6]; /* cursor color 2 & 3 */ 852 853 /* 854 * The default cursor. 855 */ 856 static unsigned short defCursor[1024] = { 857 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 858 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 859 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 860 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 861 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 862 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 863 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 864 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 865 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 866 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 867 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 868 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 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 }; 890 891 #define CFB_OFFSET_VRAM 0x0 /* from module's base */ 892 /* Replicated at x100000 */ 893 #define CFB_OFFSET_BT459 0x200000 /* Bt459 registers */ 894 #define CFB_OFFSET_IREQ 0x300000 /* Interrupt req. control */ 895 #define CFB_OFFSET_ROM 0x380000 /* Diagnostic ROM */ 896 #define CFB_OFFSET_RESET 0x3c0000 /* Bt459 resets on writes */ 897 898 /* 899 * Generic register access 900 */ 901 void 902 bt459_select_reg(regs, regno) 903 bt459_regmap_t *regs; 904 { 905 regs->addr_lo = regno; 906 regs->addr_hi = regno >> 8; 907 MachEmptyWriteBuffer(); 908 } 909 910 void 911 bt459_write_reg(regs, regno, val) 912 bt459_regmap_t *regs; 913 { 914 regs->addr_lo = regno; 915 regs->addr_hi = regno >> 8; 916 MachEmptyWriteBuffer(); 917 regs->addr_reg = val; 918 MachEmptyWriteBuffer(); 919 } 920 921 unsigned char 922 bt459_read_reg(regs, regno) 923 bt459_regmap_t *regs; 924 { 925 regs->addr_lo = regno; 926 regs->addr_hi = regno >> 8; 927 MachEmptyWriteBuffer(); 928 return regs->addr_reg; 929 } 930 931 #ifdef DEBUG 932 bt459_print_colormap(regs) 933 bt459_regmap_t *regs; 934 { 935 register int i; 936 937 bt459_select_reg(regs, 0); 938 for (i = 0; i < 256; i++) { 939 register unsigned red, green, blue; 940 941 red = regs->addr_cmap; 942 green = regs->addr_cmap; 943 blue = regs->addr_cmap; 944 printf("%x->[x%x x%x x%x]\n", i, red, green, blue); 945 } 946 } 947 #endif 948 949 /* 950 * Test to see if device is present. 951 * Return true if found and initialized ok. 952 */ 953 cfb_init(cp) 954 register struct pmax_ctlr *cp; 955 { 956 bt459_regmap_t *regs; 957 958 /* check for no frame buffer */ 959 if (badaddr(cp->pmax_addr, 4)) 960 return (0); 961 962 fb_addr = (unsigned)cp->pmax_addr + CFB_OFFSET_VRAM; 963 planemask_addr = 0; /* XXX */ 964 regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 965 966 if (bt459_read_reg(regs, BT459_REG_ID) != 0x4a) 967 return (0); 968 969 *(int *)(fb_addr + CFB_OFFSET_RESET) = 0; /* force chip reset */ 970 DELAY(2000); /* ???? check right time on specs! ???? */ 971 972 /* use 4:1 input mux */ 973 bt459_write_reg(regs, BT459_REG_CMD0, 0x40); 974 975 /* no zooming, no panning */ 976 bt459_write_reg(regs, BT459_REG_CMD1, 0x00); 977 978 /* 979 * signature test, X-windows cursor, no overlays, SYNC* PLL, 980 * normal RAM select, 7.5 IRE pedestal, do sync 981 */ 982 bt459_write_reg(regs, BT459_REG_CMD2, 0xc2); 983 984 /* get all pixel bits */ 985 bt459_write_reg(regs, BT459_REG_PRM, 0xff); 986 987 /* no blinking */ 988 bt459_write_reg(regs, BT459_REG_PBM, 0x00); 989 990 /* no overlay */ 991 bt459_write_reg(regs, BT459_REG_ORM, 0x00); 992 993 /* no overlay blink */ 994 bt459_write_reg(regs, BT459_REG_OBM, 0x00); 995 996 /* no interleave, no underlay */ 997 bt459_write_reg(regs, BT459_REG_ILV, 0x00); 998 999 /* normal operation, no signature analysis */ 1000 bt459_write_reg(regs, BT459_REG_TEST, 0x00); 1001 1002 /* 1003 * no blinking, 1bit cross hair, XOR reg&crosshair, 1004 * no crosshair on either plane 0 or 1, 1005 * regular cursor on both planes. 1006 */ 1007 bt459_write_reg(regs, BT459_REG_CCR, 0xc0); 1008 1009 /* home cursor */ 1010 bt459_write_reg(regs, BT459_REG_CXLO, 0x00); 1011 bt459_write_reg(regs, BT459_REG_CXHI, 0x00); 1012 bt459_write_reg(regs, BT459_REG_CYLO, 0x00); 1013 bt459_write_reg(regs, BT459_REG_CYHI, 0x00); 1014 1015 /* no crosshair window */ 1016 bt459_write_reg(regs, BT459_REG_WXLO, 0x00); 1017 bt459_write_reg(regs, BT459_REG_WXHI, 0x00); 1018 bt459_write_reg(regs, BT459_REG_WYLO, 0x00); 1019 bt459_write_reg(regs, BT459_REG_WYHI, 0x00); 1020 bt459_write_reg(regs, BT459_REG_WWLO, 0x00); 1021 bt459_write_reg(regs, BT459_REG_WWHI, 0x00); 1022 bt459_write_reg(regs, BT459_REG_WHLO, 0x00); 1023 bt459_write_reg(regs, BT459_REG_WHHI, 0x00); 1024 1025 /* 1026 * Initialize screen info. 1027 */ 1028 pmu.scrInfo.max_row = MAX_ROW; 1029 pmu.scrInfo.max_col = MAX_COL; 1030 pmu.scrInfo.max_x = 1024; 1031 pmu.scrInfo.max_y = 864; 1032 pmu.scrInfo.max_cur_x = 1023; 1033 pmu.scrInfo.max_cur_y = 863; 1034 pmu.scrInfo.version = 11; 1035 pmu.scrInfo.mthreshold = 4; 1036 pmu.scrInfo.mscale = 2; 1037 pmu.scrInfo.min_cur_x = 0; 1038 pmu.scrInfo.min_cur_y = 0; 1039 pmu.scrInfo.qe.timestamp_ms = TO_MS(time); 1040 pmu.scrInfo.qe.eSize = PM_MAXEVQ; 1041 pmu.scrInfo.qe.eHead = pmu.scrInfo.qe.eTail = 0; 1042 pmu.scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 1043 pmu.scrInfo.qe.tcNext = 0; 1044 1045 /* 1046 * Initialize the color map, the screen, and the mouse. 1047 */ 1048 InitColorMap(); 1049 ScreenInit(); 1050 Scroll(); 1051 1052 initialized = 1; 1053 return (1); 1054 } 1055 1056 /* 1057 * ---------------------------------------------------------------------------- 1058 * 1059 * ScreenInit -- 1060 * 1061 * Initialize the screen. 1062 * 1063 * Results: 1064 * None. 1065 * 1066 * Side effects: 1067 * The screen is initialized. 1068 * 1069 * ---------------------------------------------------------------------------- 1070 */ 1071 static void 1072 ScreenInit() 1073 { 1074 1075 /* 1076 * Home the cursor. 1077 * We want an LSI terminal emulation. We want the graphics 1078 * terminal to scroll from the bottom. So start at the bottom. 1079 */ 1080 row = 55; 1081 col = 0; 1082 1083 /* 1084 * Load the cursor with the default values 1085 * 1086 */ 1087 LoadCursor(defCursor); 1088 } 1089 1090 /* 1091 * ---------------------------------------------------------------------------- 1092 * 1093 * LoadCursor -- 1094 * 1095 * Routine to load the cursor Sprite pattern. 1096 * 1097 * Results: 1098 * None. 1099 * 1100 * Side effects: 1101 * The cursor is loaded into the hardware cursor. 1102 * 1103 * ---------------------------------------------------------------------------- 1104 */ 1105 static void 1106 LoadCursor(cur) 1107 unsigned short *cur; 1108 { 1109 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1110 register int i, j; 1111 1112 /* 1113 * As per specs, must run a check to see if we 1114 * had contention. If so, re-write the cursor. 1115 */ 1116 for (j = 0; j < 2; j++) { 1117 /* loop once to write */ 1118 bt459_select_reg(regs, BT459_REG_CRAM_BASE); 1119 for (i = 0; i < 1024; i++) { 1120 regs->addr_reg = cur[i]; 1121 MachEmptyWriteBuffer(); 1122 } 1123 1124 /* loop to check, if fail write again */ 1125 bt459_select_reg(regs, BT459_REG_CRAM_BASE); 1126 for (i = 0; i < 1024; i++) 1127 if (regs->addr_reg != cur[i]) 1128 break; 1129 if (i == 1024) 1130 break; /* all went well first shot */ 1131 } 1132 } 1133 1134 /* 1135 * ---------------------------------------------------------------------------- 1136 * 1137 * RestoreCursorColor -- 1138 * 1139 * Routine to restore the color of the cursor. 1140 * 1141 * Results: 1142 * None. 1143 * 1144 * Side effects: 1145 * None. 1146 * 1147 * ---------------------------------------------------------------------------- 1148 */ 1149 static void 1150 RestoreCursorColor() 1151 { 1152 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1153 register int i; 1154 1155 bt459_select_reg(regs, BT459_REG_CCOLOR_2); 1156 for (i = 0; i < 6; i++) { 1157 regs->addr_reg = cursor_RGB[i]; 1158 MachEmptyWriteBuffer(); 1159 } 1160 } 1161 1162 /* 1163 * ---------------------------------------------------------------------------- 1164 * 1165 * CursorColor -- 1166 * 1167 * Set the color of the cursor. 1168 * 1169 * Results: 1170 * None. 1171 * 1172 * Side effects: 1173 * None. 1174 * 1175 * ---------------------------------------------------------------------------- 1176 */ 1177 static void 1178 CursorColor(color) 1179 unsigned int color[]; 1180 { 1181 register int i, j; 1182 1183 for (i = 0; i < 6; i++) 1184 cursor_RGB[i] = (u_char)(color[i] >> 8); 1185 1186 RestoreCursorColor(); 1187 } 1188 1189 /* 1190 *---------------------------------------------------------------------- 1191 * 1192 * PosCursor -- 1193 * 1194 * Postion the cursor. 1195 * 1196 * Results: 1197 * None. 1198 * 1199 * Side effects: 1200 * None. 1201 * 1202 *---------------------------------------------------------------------- 1203 */ 1204 static void 1205 PosCursor(x, y) 1206 register int x, y; 1207 { 1208 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1209 1210 if (y < pmu.scrInfo.min_cur_y || y > pmu.scrInfo.max_cur_y) 1211 y = pmu.scrInfo.max_cur_y; 1212 if (x < pmu.scrInfo.min_cur_x || x > pmu.scrInfo.max_cur_x) 1213 x = pmu.scrInfo.max_cur_x; 1214 pmu.scrInfo.cursor.x = x; /* keep track of real cursor */ 1215 pmu.scrInfo.cursor.y = y; /* position, indep. of mouse */ 1216 1217 x += 219; 1218 y += 34; 1219 1220 bt459_select_reg(regs, BT459_REG_CXLO); 1221 regs->addr_reg = x; 1222 MachEmptyWriteBuffer(); 1223 regs->addr_reg = x >> 8; 1224 MachEmptyWriteBuffer(); 1225 regs->addr_reg = y; 1226 MachEmptyWriteBuffer(); 1227 regs->addr_reg = y >> 8; 1228 MachEmptyWriteBuffer(); 1229 } 1230 1231 /* 1232 * ---------------------------------------------------------------------------- 1233 * 1234 * InitColorMap -- 1235 * 1236 * Initialize the color map. 1237 * 1238 * Results: 1239 * None. 1240 * 1241 * Side effects: 1242 * The colormap is initialized appropriately. 1243 * 1244 * ---------------------------------------------------------------------------- 1245 */ 1246 static void 1247 InitColorMap() 1248 { 1249 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1250 register int i; 1251 1252 bt459_select_reg(regs, 0); 1253 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1254 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1255 regs->addr_cmap = 0; MachEmptyWriteBuffer(); 1256 1257 for (i = 1; i < 256; i++) { 1258 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1259 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1260 regs->addr_cmap = 0xff; MachEmptyWriteBuffer(); 1261 } 1262 1263 for (i = 0; i < 3; i++) { 1264 cursor_RGB[i] = 0x00; 1265 cursor_RGB[i + 3] = 0xff; 1266 } 1267 RestoreCursorColor(); 1268 } 1269 1270 /* 1271 * ---------------------------------------------------------------------------- 1272 * 1273 * LoadColorMap -- 1274 * 1275 * Load the color map. 1276 * 1277 * Results: 1278 * None. 1279 * 1280 * Side effects: 1281 * The color map is loaded. 1282 * 1283 * ---------------------------------------------------------------------------- 1284 */ 1285 static void 1286 LoadColorMap(ptr) 1287 ColorMap *ptr; 1288 { 1289 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1290 1291 if (ptr->index > 256) 1292 return; 1293 1294 bt459_select_reg(regs, ptr->index); 1295 1296 regs->addr_cmap = ptr->Entry.red; MachEmptyWriteBuffer(); 1297 regs->addr_cmap = ptr->Entry.green; MachEmptyWriteBuffer(); 1298 regs->addr_cmap = ptr->Entry.blue; MachEmptyWriteBuffer(); 1299 } 1300 1301 /* 1302 * Video on/off state. 1303 */ 1304 struct vstate { 1305 u_char color0[3]; /* saved color map entry zero */ 1306 u_char off; /* TRUE if display is off */ 1307 } vstate; 1308 1309 /* 1310 * ---------------------------------------------------------------------------- 1311 * 1312 * EnableVideo -- 1313 * 1314 * Enable the video display. 1315 * 1316 * Results: 1317 * None. 1318 * 1319 * Side effects: 1320 * The display is enabled. 1321 * 1322 * ---------------------------------------------------------------------------- 1323 */ 1324 static void 1325 EnableVideo() 1326 { 1327 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1328 1329 if (!vstate.off) 1330 return; 1331 1332 /* restore old color map entry zero */ 1333 bt459_select_reg(regs, 0); 1334 regs->addr_cmap = vstate.color0[0]; 1335 MachEmptyWriteBuffer(); 1336 regs->addr_cmap = vstate.color0[1]; 1337 MachEmptyWriteBuffer(); 1338 regs->addr_cmap = vstate.color0[2]; 1339 MachEmptyWriteBuffer(); 1340 1341 /* enable normal display */ 1342 bt459_write_reg(regs, BT459_REG_PRM, 0xff); 1343 bt459_write_reg(regs, BT459_REG_CCR, 0xc0); 1344 1345 vstate.off = 0; 1346 } 1347 1348 /* 1349 * ---------------------------------------------------------------------------- 1350 * 1351 * DisableVideo -- 1352 * 1353 * Disable the video display. 1354 * 1355 * Results: 1356 * None. 1357 * 1358 * Side effects: 1359 * The display is disabled. 1360 * 1361 * ---------------------------------------------------------------------------- 1362 */ 1363 static void 1364 DisableVideo() 1365 { 1366 bt459_regmap_t *regs = (bt459_regmap_t *)(fb_addr + CFB_OFFSET_BT459); 1367 1368 if (vstate.off) 1369 return; 1370 1371 /* save old color map entry zero */ 1372 bt459_select_reg(regs, 0); 1373 vstate.color0[0] = regs->addr_cmap; 1374 vstate.color0[1] = regs->addr_cmap; 1375 vstate.color0[2] = regs->addr_cmap; 1376 1377 /* set color map entry zero to zero */ 1378 bt459_select_reg(regs, 0); 1379 regs->addr_cmap = 0; 1380 MachEmptyWriteBuffer(); 1381 regs->addr_cmap = 0; 1382 MachEmptyWriteBuffer(); 1383 regs->addr_cmap = 0; 1384 MachEmptyWriteBuffer(); 1385 1386 /* disable display */ 1387 bt459_write_reg(regs, BT459_REG_PRM, 0); 1388 bt459_write_reg(regs, BT459_REG_CCR, 0); 1389 1390 vstate.off = 1; 1391 } 1392 #endif 1393