1#ifdef HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5/* All drivers should typically include these */ 6#include "xf86.h" 7#include "xf86_OSproc.h" 8 9/* All drivers need this */ 10 11#include "compiler.h" 12 13#include "mga.h" 14#include "mga_macros.h" 15#include "mga_reg.h" 16#include "mga_merge.h" 17 18#include "fbdevhw.h" 19 20static int 21StrToRanges(range* r, const char* s) { 22 float num=0.0; 23 int rangenum=0; 24 Bool gotdash = FALSE; 25 Bool nextdash = FALSE; 26 const char* strnum=NULL; 27 do { 28 switch(*s) { 29 case '0': case '1': case '2': case '3': case '4': case '5': 30 case '6': case '7': case '8': case '9': case '.': 31 if(strnum == NULL) { 32 strnum = s; 33 gotdash = nextdash; 34 nextdash = FALSE; 35 } 36 37 break; 38 case '-': 39 case ' ': case 0: 40 if(strnum == NULL) break; /*is extra separator */ 41 if(strnum != NULL) sscanf(strnum,"%f",&num); 42 if(gotdash) /*if wasn't singlet: correct. */ 43 r[rangenum-1].hi = num; 44 else { /*first, assume singlet */ 45 r[rangenum].lo = num; 46 r[rangenum].hi = num; 47 rangenum++; 48 } 49 strnum = NULL; 50 if(*s == '-') 51 nextdash = (rangenum != 0); /*ignore dash if before any number.*/ 52 break; 53 default : 54 return 0; 55 } 56 } while(*(s++) != 0); /* run loop for every char including null terminator.*/ 57 58 return rangenum; 59} 60 61 62/* Copies mode i, links the result to dest, and returns it. 63 * Links i and j in Private record. 64 * if dest is NULL, return value is copy of i linked to itself. 65 */ 66static DisplayModePtr 67CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { 68 DisplayModePtr mode; 69 int dx = 0,dy = 0; 70 /* start with first node */ 71 mode = malloc(sizeof(DisplayModeRec)); 72 memcpy(mode,i, sizeof(DisplayModeRec)); 73 mode->Private = malloc(sizeof(MergedDisplayModeRec)); 74 ((MergedDisplayModePtr)mode->Private)->Monitor1 = i; 75 ((MergedDisplayModePtr)mode->Private)->Monitor2 = j; 76 ((MergedDisplayModePtr)mode->Private)->Monitor2Pos = srel; 77 mode->PrivSize = 0; 78 79 switch(srel) { 80 case mgaLeftOf: 81 case mgaRightOf: 82 dx = min(pScrn->virtualX,i->HDisplay + j->HDisplay) - mode->HDisplay; 83 dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; 84 break; 85 case mgaAbove: 86 case mgaBelow: 87 dy = min(pScrn->virtualY,i->VDisplay + j->VDisplay) - mode->VDisplay; 88 dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; 89 break; 90 case mgaClone: 91 dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; 92 dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; 93 break; 94 } 95 mode->HDisplay += dx; 96 mode->HSyncStart += dx; 97 mode->HSyncEnd += dx; 98 mode->HTotal += dx; 99 mode->VDisplay += dy; 100 mode->VSyncStart += dy; 101 mode->VSyncEnd += dy; 102 mode->VTotal += dy; 103 mode->Clock = 0; /* Shows we're in Merge mode. */ 104 105 mode->next = mode; 106 mode->prev = mode; 107 108 if(dest) { 109 /* Insert node after "dest" */ 110 mode->next = dest->next; 111 dest->next->prev = mode; 112 mode->prev = dest; 113 dest->next = mode; 114 } 115 116 return mode; 117} 118 119static DisplayModePtr 120GetModeFromName(const char* str, DisplayModePtr i) 121{ 122 DisplayModePtr c = i; 123 if(!i) return NULL; 124 do { 125 if(strcmp(str,c->name) == 0) return c; 126 c = c->next; 127 } while(c != i); 128 return NULL; 129} 130 131/* takes a config file string of MetaModes and generates a MetaModeList */ 132static DisplayModePtr 133GenerateModeList(ScrnInfoPtr pScrn, const char* str, 134 DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { 135 const char* strmode = str; 136 char modename[256]; 137 Bool gotdash = FALSE; 138 MgaScrn2Rel sr; 139 140 DisplayModePtr mode1 = NULL; 141 DisplayModePtr mode2 = NULL; 142 DisplayModePtr result = NULL; 143 do { 144 switch(*str) { 145 case 0: 146 case '-': 147 case ' ': 148 case ',': 149 case ';': 150 if((strmode != str)) {/*we got a mode */ 151 /* read new entry */ 152 strncpy(modename,strmode,str - strmode); 153 modename[str - strmode] = 0; 154 155 if(gotdash) { 156 if(mode1 == NULL) return NULL; 157 mode2 = GetModeFromName(modename,j); 158 if(!mode2) { 159 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 160 "Mode: \"%s\" is not a supported mode for monitor 2\n",modename); 161 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 162 "Skipping metamode \"%s-%s\".\n",mode1->name,modename); 163 mode1 = NULL; 164 } 165 } else { 166 mode1 = GetModeFromName(modename,i); 167 if(!mode1) { 168 const char* tmps = str; 169 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 170 "Mode: \"%s\" is not a supported mode for monitor 1\n",modename); 171 /* find if a monitor2 mode follows */ 172 gotdash = FALSE; 173 while(*tmps == ' ' || *tmps == ';') tmps++; 174 if(*tmps == '-' || *tmps == ',') { /* skip the next mode */ 175 tmps++; 176 while(*tmps == ' ' || *tmps == ';') tmps++; /*skip spaces */ 177 while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != ',') tmps++; /*skip modename */ 178 /* for error message */ 179 strncpy(modename,strmode,tmps - strmode); 180 modename[tmps - strmode] = 0; 181 str = tmps-1; 182 } 183 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 184 "Skipping metamode \"%s\".\n",modename); 185 mode1 = NULL; 186 } 187 } 188 gotdash = FALSE; 189 } 190 strmode = str+1; /* number starts on next char */ 191 gotdash |= (*str == '-' || *str == ','); 192 193 if(*str != 0) break; /* if end of string, we won't get a chance to catch a char and run the 194 default case. do it now */ 195 196 default: 197 if(!gotdash && mode1) { /* complete previous pair */ 198 sr = srel; 199 if(!mode2) { 200 mode2 = GetModeFromName(mode1->name,j); 201 sr = mgaClone; 202 } 203 if(!mode2) { 204 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 205 "Mode: \"%s\" is not a supported mode for monitor 2\n",mode1->name); 206 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 207 "Skipping clone mode \"%s\".\n", mode1->name); 208 mode1 = NULL; 209 } else { 210 result = CopyModeNLink(pScrn,result,mode1,mode2,sr); 211 mode1 = NULL; 212 mode2 = NULL; 213 } 214 } 215 break; 216 217 } 218 } while(*(str++) != 0); 219 return result; 220} 221 222 223/* second CRTC init functions. Used to check monitor timings and refreshes. 224 * this function looses lots of maintainability points due to redundancy, 225 * but it still was the cleanest and least-intrusive way I found. */ 226 227Bool 228MGAPreInitMergedFB(ScrnInfoPtr pScrn1, int flags) 229{ 230 ScrnInfoPtr pScrn; 231 MGAPtr pMga; 232 MGAPtr pMga1; 233 MessageType from; 234 int i; 235 const char* s; 236 ClockRangePtr clockRanges; 237 MgaScrn2Rel Monitor2Pos; 238 239 xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== Start of second screen initialization ====\n"); 240 pScrn = malloc(sizeof(ScrnInfoRec)); 241 memcpy(pScrn,pScrn1,sizeof(ScrnInfoRec)); 242 243 pScrn->driverPrivate = NULL; 244 /* Allocate the MGARec driverPrivate */ 245 if (!MGAGetRec(pScrn)) { 246 return FALSE; 247 } 248 249 pMga = MGAPTR(pScrn); 250 pMga1 = MGAPTR(pScrn1); 251 pMga1->pScrn2 = pScrn; 252 253 /* Get the entity, and make sure it is PCI. */ 254 pMga->pEnt = pMga1->pEnt; 255 256 /* Set pMga->device to the relevant Device section */ 257 pMga->device = pMga1->device; 258 259 if (flags & PROBE_DETECT) { 260 MGAProbeDDC(pScrn, pMga->pEnt->index); /*FIXME make sure this probes second monitor */ 261 return TRUE; 262 } 263 264#ifndef XSERVER_LIBPCIACCESS 265 pMga->PciTag = pMga1->PciTag; 266#endif 267 pMga->Primary = pMga1->Primary; 268 269 /* Set pScrn->monitor */ 270 { 271 pScrn->monitor = malloc(sizeof(MonRec)); 272 /* copy everything we don't care about */ 273 memcpy(pScrn->monitor,pScrn1->monitor,sizeof(MonRec)); 274 pScrn->monitor->DDC = NULL; /*FIXME:have to try this */ 275 if ((s = xf86GetOptValString(pMga1->Options, OPTION_HSYNC2))) { 276 pScrn->monitor->nHsync = StrToRanges(pScrn->monitor->hsync,s); 277 } 278 if ((s = xf86GetOptValString(pMga1->Options, OPTION_VREFRESH2))) { 279 pScrn->monitor->nVrefresh = StrToRanges(pScrn->monitor->vrefresh,s); 280 } 281 282 283 284 } 285 286 pMga->SecondCrtc = TRUE; 287 pMga->HWCursor = FALSE; 288 pScrn->AdjustFrame = MGAAdjustMergeFrames; 289 pScrn1->AdjustFrame = MGAAdjustMergeFrames; 290 291/* if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) FIXME:have to copy result form scrn1 292 if (!xf86SetWeight(pScrn, zeros, zeros)) { 293*/ 294 295 /* We use a programamble clock */ 296 pScrn->progClock = TRUE; 297 298 /* Collect all of the relevant option flags (fill in pScrn->options) */ 299 pScrn->options = pScrn1->options; 300 301/* xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pMga->Options);*/ 302 pMga->Options = pMga1->Options; 303 304 305 /* Set the bits per RGB for 8bpp mode */ 306 if (pScrn->depth == 8) 307 pScrn->rgbBits = 8; 308 309 /* 310 * Set the Chipset and ChipRev, allowing config file entries to 311 * override. 312 */ 313 pScrn->chipset = pScrn1->chipset; 314 pMga->Chipset = pMga1->Chipset; 315 pMga->ChipRev = pMga1->ChipRev; 316 317#ifdef MGADRI 318 pMga->agpMode = pMga1->agpMode; 319#endif 320 321 pMga->NoAccel = pMga1->NoAccel; 322 pMga->UsePCIRetry = pMga1->UsePCIRetry; 323 pMga->SyncOnGreen = pMga1->SyncOnGreen; 324 pMga->ShowCache = pMga1->ShowCache; 325 pMga->HasSDRAM = pMga1->HasSDRAM; 326 pMga->MemClk = pMga1->MemClk; 327 pMga->colorKey = pMga1->colorKey; 328 pScrn->colorKey = pScrn1->colorKey; 329 pScrn->overlayFlags = pScrn1->overlayFlags; 330 pMga->videoKey = pMga1->videoKey; 331 /* unsupported options */ 332 pMga->HWCursor = FALSE; 333 pMga->ShadowFB = FALSE; 334 pMga->FBDev = FALSE; 335 336 pMga->OverclockMem = pMga1->OverclockMem; 337 pMga->TexturedVideo = pMga1->TexturedVideo; 338 pMga->MergedFB = TRUE; 339 340 pMga->Rotate = 0; 341 342 switch (pMga->Chipset) { 343 case PCI_CHIP_MGA2064: 344 case PCI_CHIP_MGA2164: 345 case PCI_CHIP_MGA2164_AGP: 346 MGA2064SetupFuncs(pScrn); 347 break; 348 case PCI_CHIP_MGA1064: 349 case PCI_CHIP_MGAG100: 350 case PCI_CHIP_MGAG100_PCI: 351 case PCI_CHIP_MGAG200: 352 case PCI_CHIP_MGAG200_PCI: 353 case PCI_CHIP_MGAG200_SE_A_PCI: 354 case PCI_CHIP_MGAG200_SE_B_PCI: 355 case PCI_CHIP_MGAG200_WINBOND_PCI: 356 case PCI_CHIP_MGAG200_EW3_PCI: 357 case PCI_CHIP_MGAG200_EV_PCI: 358 case PCI_CHIP_MGAG200_EH_PCI: 359 case PCI_CHIP_MGAG200_ER_PCI: 360 case PCI_CHIP_MGAG200_EH3_PCI: 361 case PCI_CHIP_MGAG400: 362 case PCI_CHIP_MGAG550: 363 MGAGSetupFuncs(pScrn); 364 break; 365 } 366 367 pMga->FbAddress = pMga1->FbAddress; 368 pMga->PciInfo = pMga1->PciInfo; 369#ifndef XSERVER_LIBPCIACCESS 370 pMga->IOAddress = pMga1->IOAddress; 371 pMga->ILOADAddress = pMga1->ILOADAddress; 372 pMga->BiosFrom = pMga1->BiosFrom; 373 pMga->BiosAddress = pMga1->BiosAddress; 374#endif 375 376 /* 377 * Read the BIOS data struct 378 */ 379 380 mga_read_and_process_bios( pScrn ); 381 382 /* HW bpp matches reported bpp */ 383 pMga->HwBpp = pMga1->HwBpp; 384 385 /* 386 * Reset card if it isn't primary one 387 */ 388 if ( (!pMga->Primary && !pMga->FBDev) ) 389 MGASoftReset(pScrn); 390 391 392 pScrn->videoRam = pScrn1->videoRam; 393 pMga->FbMapSize = pMga1->FbMapSize; 394 pMga->SrcOrg = pMga1->SrcOrg; 395 pMga->DstOrg = pMga1->DstOrg; 396 397 /* Set the bpp shift value */ 398 pMga->BppShifts[0] = 0; 399 pMga->BppShifts[1] = 1; 400 pMga->BppShifts[2] = 0; 401 pMga->BppShifts[3] = 2; 402 403 /* 404 * fill MGAdac struct 405 * Warning: currently, it should be after RAM counting 406 */ 407 (*pMga->PreInit)(pScrn); 408 409#if !defined(__powerpc__) 410 411 /* Read and print the Monitor DDC info */ 412/* pScrn->monitor->DDC = MGAdoDDC(pScrn);*/ /*FIXME: have to try this*/ 413#endif /* !__powerpc__ */ 414 415 /* 416 * If the driver can do gamma correction, it should call xf86SetGamma() 417 * here. 418 */ 419 { 420 Gamma zeros = {0.0, 0.0, 0.0}; 421 422 if (!xf86SetGamma(pScrn, zeros)) { 423 return FALSE; 424 } 425 } 426 427 428 /* Set the min pixel clock */ 429 pMga->MinClock = pMga1->MinClock; /* XXX Guess, need to check this */ 430 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Min pixel clock is %d MHz\n", 431 pMga->MinClock / 1000); 432 /* Override on 2nd crtc */ 433 434 if (pMga->ChipRev >= 0x80 || (pMga->Chipset == PCI_CHIP_MGAG550)) { 435 /* G450, G550 */ 436 pMga->MaxClock = 234000; 437 } else { 438 pMga->MaxClock = 135000; 439 } 440 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Max pixel clock is %d MHz\n", 441 pMga->MaxClock / 1000); 442 /* 443 * Setup the ClockRanges, which describe what clock ranges are available, 444 * and what sort of modes they can be used for. 445 */ 446 clockRanges = xnfcalloc(sizeof(ClockRange), 1); 447 clockRanges->next = NULL; 448 clockRanges->minClock = pMga->MinClock; 449 clockRanges->maxClock = pMga->MaxClock; 450 clockRanges->clockIndex = -1; /* programmable */ 451 clockRanges->interlaceAllowed = TRUE; 452 clockRanges->doubleScanAllowed = TRUE; 453 clockRanges->interlaceAllowed = FALSE; /*no interlace on CRTC2 */ 454 455 clockRanges->ClockMulFactor = 1; 456 clockRanges->ClockDivFactor = 1; 457 /* Only set MemClk if appropriate for the ramdac */ 458 if (pMga->Dac.SetMemClk) { 459 if (pMga->MemClk == 0) { 460 pMga->MemClk = pMga->Dac.MemoryClock; 461 from = pMga->Dac.MemClkFrom; 462 } else 463 from = X_CONFIG; 464 xf86DrvMsg(pScrn->scrnIndex, from, "CRTC2: MCLK used is %.1f MHz\n", 465 pMga->MemClk / 1000.0); 466 } 467 468 /* 469 * xf86ValidateModes will check that the mode HTotal and VTotal values 470 * don't exceed the chipset's limit if pScrn->maxHValue and 471 * pScrn->maxVValue are set. Since our MGAValidMode() already takes 472 * care of this, we don't worry about setting them here. 473 */ 474 { 475 int Pitches1[] = 476 {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0}; 477 int Pitches2[] = 478 {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664, 479 1920, 2048, 0}; 480 int *linePitches = NULL; 481 int minPitch = 256; 482 int maxPitch = 2048; 483 484 switch(pMga->Chipset) { 485 case PCI_CHIP_MGA2064: 486 if (!pMga->NoAccel) { 487 linePitches = malloc(sizeof(Pitches1)); 488 memcpy(linePitches, Pitches1, sizeof(Pitches1)); 489 minPitch = maxPitch = 0; 490 } 491 break; 492 case PCI_CHIP_MGA2164: 493 case PCI_CHIP_MGA2164_AGP: 494 case PCI_CHIP_MGA1064: 495 if (!pMga->NoAccel) { 496 linePitches = malloc(sizeof(Pitches2)); 497 memcpy(linePitches, Pitches2, sizeof(Pitches2)); 498 minPitch = maxPitch = 0; 499 } 500 break; 501 case PCI_CHIP_MGAG100: 502 case PCI_CHIP_MGAG100_PCI: 503 maxPitch = 2048; 504 break; 505 case PCI_CHIP_MGAG200: 506 case PCI_CHIP_MGAG200_PCI: 507 case PCI_CHIP_MGAG200_SE_A_PCI: 508 case PCI_CHIP_MGAG200_SE_B_PCI: 509 case PCI_CHIP_MGAG200_WINBOND_PCI: 510 case PCI_CHIP_MGAG200_EW3_PCI: 511 case PCI_CHIP_MGAG200_EV_PCI: 512 case PCI_CHIP_MGAG200_EH_PCI: 513 case PCI_CHIP_MGAG200_ER_PCI: 514 case PCI_CHIP_MGAG200_EH3_PCI: 515 case PCI_CHIP_MGAG400: 516 case PCI_CHIP_MGAG550: 517 maxPitch = 4096; 518 break; 519 } 520 521 pScrn->modePool=NULL; 522 pScrn->modes = NULL; 523 i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 524 pScrn->display->modes, clockRanges, 525 linePitches, minPitch, maxPitch, 526 pMga->Roundings[(pScrn->bitsPerPixel >> 3) - 1] * 527 pScrn->bitsPerPixel, 128, 2048, 528 pScrn->display->virtualX, 529 pScrn->display->virtualY, 530 pMga->FbMapSize, 531 LOOKUP_BEST_REFRESH); 532 533 free(linePitches); 534 } 535 536 537 if (i < 1 && pMga->FBDev) { 538 fbdevHWUseBuildinMode(pScrn); 539 pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */ 540 i = 1; 541 } 542 if (i == -1) { 543 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: Validate Modes Failed\n"); 544 MGAFreeRec(pScrn); 545 return FALSE; 546 } 547 548 /* Prune the modes marked as invalid */ 549 xf86PruneDriverModes(pScrn); 550 551 if (i == 0 || pScrn->modes == NULL) { 552 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: No valid modes found\n"); 553 MGAFreeRec(pScrn); 554 return FALSE; 555 } 556 557 /* 558 * Set the CRTC parameters for all of the modes based on the type 559 * of mode, and the chipset's interlace requirements. 560 * 561 * Calling this is required if the mode->Crtc* values are used by the 562 * driver and if the driver doesn't provide code to set them. They 563 * are not pre-initialised at all. 564 */ 565 MGA_NOT_HAL(xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V)); 566 567 /* Set the current mode to the first in the list */ 568 pScrn->currentMode = pScrn->modes; 569 570 /* Print the list of modes being used */ 571 xf86PrintModes(pScrn); 572 573 /* Set display resolution */ 574 xf86SetDpi(pScrn, 0, 0); 575 576 /* 577 * Compute the byte offset into the linear frame buffer where the 578 * frame buffer data should actually begin. According to DDK misc.c 579 * line 1023, if more than 4MB is to be displayed, YDSTORG must be set 580 * appropriately to align memory bank switching, and this requires a 581 * corresponding offset on linear frame buffer access. 582 * This is only needed for WRAM. 583 */ 584 585 pMga->YDstOrg = pMga1->YDstOrg; 586 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "CRTC2: YDstOrg is set to %d\n", 587 pMga->YDstOrg); 588 pMga->FbUsableSize = pMga1->FbUsableSize; 589 pMga->FbCursorOffset = pMga1->FbCursorOffset; 590 591 pMga->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; 592 pMga->CurrentLayout.depth = pScrn->depth; 593 pMga->CurrentLayout.displayWidth = pScrn->displayWidth; 594 pMga->CurrentLayout.weight.red = pScrn->weight.red; 595 pMga->CurrentLayout.weight.green = pScrn->weight.green; 596 pMga->CurrentLayout.weight.blue = pScrn->weight.blue; 597 pMga->CurrentLayout.mode = pScrn->currentMode; 598 599 600 Monitor2Pos = mgaRightOf; 601 if ((s = xf86GetOptValString(pMga1->Options, OPTION_MONITOR2POS))) { 602 switch(s[0]) { 603 case 'L': case 'l': case 'G': case 'g': 604 Monitor2Pos = mgaLeftOf; 605 break; 606 case 'R': case 'r': case 'D': case 'd': 607 Monitor2Pos = mgaRightOf; 608 break; 609 610 case 'A': case 'a': case 'H': case 'h': 611 Monitor2Pos = mgaAbove; 612 break; 613 614 case 'B': case 'b': 615 Monitor2Pos = mgaBelow; 616 break; 617 618 case 'C': case 'c': 619 Monitor2Pos = mgaClone; 620 break; 621 default: 622 Monitor2Pos = mgaRightOf; 623 break; 624 } 625 } 626 627 /* Fool xf86 into thinking we have huge modes */ 628 /* Keep the original values somewhere */ 629 pMga1->M1modes = pScrn1->modes; 630 pMga1->M1currentMode = pScrn1->currentMode; 631 /* make a copy of the mode list, so we can modify it. */ 632 if ((s = xf86GetOptValString(pMga1->Options, OPTION_METAMODES))) { 633 pScrn1->modes = GenerateModeList(pScrn,s,pMga1->M1modes,pScrn->modes,Monitor2Pos); /*FIXME: free this list*/ 634 if(!pScrn1->modes) { 635 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Parse Error reading MetaModes, or No modes left.\n"); 636 return FALSE; 637 } 638 639 pScrn1->modes = pScrn1->modes->next; 640 pScrn1->currentMode = pScrn1->modes; 641 } else { 642 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MetaModes option missing.\n"); 643 return FALSE; 644 } 645 xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== End of second screen initialization ====\n"); 646 return TRUE; 647} 648 649void 650MGADisplayPowerManagementSetMerged(ScrnInfoPtr pScrn, int PowerManagementMode, 651 int flags) 652{ 653 MGADisplayPowerManagementSet(pScrn,PowerManagementMode,flags); 654 MGADisplayPowerManagementSetCrtc2(pScrn,PowerManagementMode,flags); 655} 656 657typedef struct _region { 658 int x0,x1,y0,y1; 659 } region; 660 661static Bool 662InRegion(int x, int y, region r) { 663 return (r.x0 <= x) && (x < r.x1) && (r.y0 <= y) && (y < r.y1); 664} 665 666 667#define BOUND(test,low,hi) { \ 668 if(test < low) test = low; \ 669 if(test > hi) test = hi; } 670#define REBOUND(low,hi,test) { \ 671 if(test < low) { \ 672 hi += test-low; \ 673 low = test; } \ 674 if(test > hi) { \ 675 low += test-hi; \ 676 hi = test; } } 677 void 678MGAMergePointerMoved(SCRN_ARG_TYPE arg, int x, int y) 679{ 680 SCRN_INFO_PTR(arg); 681 MGAPtr pMga = MGAPTR(pScrn); 682 ScrnInfoPtr pScr2 = pMga->pScrn2; 683 684 region out,in1,in2,f2,f1; 685 686 int deltax,deltay; 687 688 /* for ease. */ 689 f1.x0 = pMga->M1frameX0; 690 f1.x1 = pMga->M1frameX1+1; 691 f1.y0 = pMga->M1frameY0; 692 f1.y1 = pMga->M1frameY1+1; 693 f2.x0 = pScr2->frameX0; 694 f2.x1 = pScr2->frameX1+1; 695 f2.y0 = pScr2->frameY0; 696 f2.y1 = pScr2->frameY1+1; 697 698 699 /*specify outer clipping region. crossing this causes all frames to move*/ 700 out.x0 = pScrn->frameX0; 701 out.x1 = pScrn->frameX1+1; 702 out.y0 = pScrn->frameY0; 703 out.y1 = pScrn->frameY1+1; 704 705 /* 706 * specify inner sliding window. being outsize both frames, and inside 707 * the outer clipping window, causes corresponding frame to slide 708 */ 709 in1 = out; 710 in2 = out; 711 switch(((MergedDisplayModePtr)pScrn->currentMode->Private)->Monitor2Pos) { 712 case mgaLeftOf : 713 in1.x0 = f1.x0; 714 in2.x1 = f2.x1; 715 break; 716 case mgaRightOf : 717 in1.x1 = f1.x1; 718 in2.x0 = f2.x0; 719 break; 720 case mgaBelow : 721 in1.y1 = f1.y1; 722 in2.y0 = f2.y0; 723 break; 724 case mgaAbove : 725 in1.y0 = f1.y0; 726 in2.y1 = f2.y1; 727 break; 728 case mgaClone : 729 break; 730 } 731 732 733 deltay = 0; 734 deltax = 0; 735 736 if(InRegion(x,y,out)) { 737 if( InRegion(x,y, in1) && !InRegion(x,y, f1) ) { 738 REBOUND(f1.x0,f1.x1,x); 739 REBOUND(f1.y0,f1.y1,y); 740 deltax = 1; /*force frame update */ 741 } 742 if( InRegion(x,y, in2) && !InRegion(x,y, f2) ) { 743 REBOUND(f2.x0,f2.x1,x); 744 REBOUND(f2.y0,f2.y1,y); 745 deltax = 1; /*force frame update */ 746 } 747 } 748 else { /*outside outer clipping region*/ 749 if ( out.x0 > x) { 750 deltax = x - out.x0; 751 } 752 if ( out.x1 < x) { 753 deltax = x - out.x1; 754 } 755 f1.x0 += deltax; 756 f1.x1 += deltax; 757 f2.x0 += deltax; 758 f2.x1 += deltax; 759 pScrn->frameX0 += deltax; 760 pScrn->frameX1 += deltax; 761 762 763 if ( out.y0 > y) { 764 deltay = y - out.y0; 765 } 766 if ( out.y1 < y) { 767 deltay = y - out.y1; 768 } 769 f1.y0 += deltay; 770 f1.y1 += deltay; 771 f2.y0 += deltay; 772 f2.y1 += deltay; 773 pScrn->frameY0 += deltay; 774 pScrn->frameY1 += deltay; 775 } 776 777 778 if (deltax != 0 || deltay != 0) { 779 /* back to reality. */ 780 pMga->M1frameX0 = f1.x0; 781 pMga->M1frameY0 = f1.y0; 782 pScr2->frameX0 = f2.x0; 783 pScr2->frameY0 = f2.y0; 784 785 /*Adjust Granularity */ 786 MGAAdjustGranularity(pScrn,&pMga->M1frameX0,&pMga->M1frameY0); 787 MGAAdjustGranularity(pScrn,&pScr2->frameX0,&pScr2->frameY0); 788 MGAAdjustGranularity(pScrn,&pScrn->frameX0,&pScrn->frameY0); 789 790 pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn)->Monitor1->HDisplay -1; 791 pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn)->Monitor1->VDisplay -1; 792 pScr2->frameX1 = pScr2->frameX0 + MDMPTR(pScrn)->Monitor2->HDisplay -1; 793 pScr2->frameY1 = pScr2->frameY0 + MDMPTR(pScrn)->Monitor2->VDisplay -1; 794 pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay -1; 795 pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay -1; 796 797 MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); 798 MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScr2->frameX0, pScr2->frameY0)); 799 } 800 801/* if(pMga->PointerMoved) 802 (*pMga->PointerMoved)(scrnIndex, x, y); FIXME: do I need to call old func?*/ 803 804} 805 806 807void 808MGAAdjustMergeFrames(ADJUST_FRAME_ARGS_DECL) { 809 SCRN_INFO_PTR(arg); 810 ScrnInfoPtr pScrn1 = pScrn; 811 MGAPtr pMga = MGAPTR(pScrn1); 812 ScrnInfoPtr pScrn2 = pMga->pScrn2; 813 int VTotal = pScrn1->currentMode->VDisplay; 814 int HTotal = pScrn1->currentMode->HDisplay; 815 int VMax = VTotal; 816 int HMax = HTotal; 817 818 BOUND(x,0,pScrn1->virtualX-HTotal); 819 BOUND(y,0,pScrn1->virtualY-VTotal); 820 switch(MDMPTR(pScrn1)->Monitor2Pos) { 821 case mgaLeftOf: 822 pScrn2->frameX0 = x; 823 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 824 pMga->M1frameX0 = x+MDMPTR(pScrn1)->Monitor2->HDisplay; 825 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 826 break; 827 case mgaRightOf: 828 pMga->M1frameX0 = x; 829 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 830 pScrn2->frameX0 = x+MDMPTR(pScrn1)->Monitor1->HDisplay; 831 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 832 break; 833 case mgaAbove: 834 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 835 pScrn2->frameY0 = y; 836 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 837 pMga->M1frameY0 = y+MDMPTR(pScrn1)->Monitor2->VDisplay; 838 break; 839 case mgaBelow: 840 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 841 pMga->M1frameY0 = y; 842 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 843 pScrn2->frameY0 = y+MDMPTR(pScrn1)->Monitor1->VDisplay; 844 break; 845 case mgaClone: 846 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 847 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 848 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 849 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 850 break; 851 } 852 /* sanity checks. Make sure were not out of bounds */ 853 BOUND(pMga->M1frameX0,0,pScrn1->virtualX -MDMPTR(pScrn1)->Monitor1->HDisplay); 854 BOUND(pMga->M1frameY0,0,pScrn1->virtualY -MDMPTR(pScrn1)->Monitor1->VDisplay); 855 BOUND(pScrn2->frameX0,0,pScrn2->virtualX -MDMPTR(pScrn1)->Monitor2->HDisplay); 856 BOUND(pScrn2->frameY0,0,pScrn2->virtualY -MDMPTR(pScrn1)->Monitor2->VDisplay); 857 858 pScrn1->frameX0 = x; 859 pScrn1->frameY0 = y; 860 861 /* check granularity */ 862 MGAAdjustGranularity(pScrn1,&pMga->M1frameX0,&pMga->M1frameY0); 863 MGAAdjustGranularity(pScrn1,&pScrn2->frameX0,&pScrn2->frameY0); 864 MGAAdjustGranularity(pScrn1,&pScrn1->frameX0,&pScrn1->frameY0); 865 866 /* complete shitty redundant info */ 867 pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn1)->Monitor1->HDisplay -1; 868 pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn1)->Monitor1->VDisplay -1; 869 pScrn2->frameX1 = pScrn2->frameX0 + MDMPTR(pScrn1)->Monitor2->HDisplay -1; 870 pScrn2->frameY1 = pScrn2->frameY0 + MDMPTR(pScrn1)->Monitor2->VDisplay -1; 871 pScrn1->frameX1 = pScrn1->frameX0 + pScrn1->currentMode->HDisplay -1; 872 pScrn1->frameY1 = pScrn1->frameY0 + pScrn1->currentMode->VDisplay -1; 873 874 MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); 875 MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScrn2->frameX0, pScrn2->frameY0)); 876 return; 877} 878 879Bool 880MGACloseScreenMerged(ScreenPtr pScreen) { 881 ScrnInfoPtr pScrn1 = xf86ScreenToScrn(pScreen); 882 MGAPtr pMga = MGAPTR(pScrn1); 883 ScrnInfoPtr pScrn2 = pMga->pScrn2; 884 885 if(pScrn2) { 886 free(pScrn2->monitor); 887 pScrn2->monitor = NULL; 888 889 free(pScrn2); 890 pMga->pScrn2 = NULL; 891 } 892 893 if(pScrn1->modes) { 894 pScrn1->currentMode = pScrn1->modes; 895 do { 896 DisplayModePtr p = pScrn1->currentMode->next; 897 free(pScrn1->currentMode->Private); 898 free(pScrn1->currentMode); 899 pScrn1->currentMode = p; 900 }while( pScrn1->currentMode != pScrn1->modes); 901 } 902 903 pScrn1->currentMode = pMga->M1currentMode; 904 pScrn1->modes = pMga->M1modes; 905 906 return TRUE; 907} 908 909Bool 910MGASaveScreenMerged(ScreenPtr pScreen, int mode) 911{ 912 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 913 MGAPtr pMga = MGAPTR(pScrn); 914 BOOL on = xf86IsUnblank(mode); 915 CARD8 reg; 916 917 if (on) { 918/* SetTimdeSinceLastInputEvent();*/ 919 920 /* power on Dac1 */ 921 reg = inMGAdac(MGA1064_MISC_CTL); 922 reg |= MGA1064_MISC_CTL_DAC_EN; 923 outMGAdac(MGA1064_MISC_CTL, reg); 924 925 /* power on Dac2 */ 926 reg = inMGAdac(MGA1064_PWR_CTL); 927 reg |= MGA1064_PWR_CTL_DAC2_EN; 928 outMGAdac(MGA1064_PWR_CTL, reg); 929 } else { 930 /* power off Dac1 */ 931 reg = inMGAdac(MGA1064_MISC_CTL); 932 reg &= ~MGA1064_MISC_CTL_DAC_EN; 933 outMGAdac(MGA1064_MISC_CTL, reg); 934 935 /* power off Dac2 */ 936 reg = inMGAdac(MGA1064_PWR_CTL); 937 reg &= ~MGA1064_PWR_CTL_DAC2_EN; 938 outMGAdac(MGA1064_PWR_CTL, reg); 939 } 940 941 return TRUE; 942} 943 944 945