mga_merge.c revision 6f68ce78
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 seperator */ 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/* Copys 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 wont 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 funcitons. 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 shure 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_MGAG400: 361 case PCI_CHIP_MGAG550: 362 MGAGSetupFuncs(pScrn); 363 break; 364 } 365 366 pMga->FbAddress = pMga1->FbAddress; 367 pMga->PciInfo = pMga1->PciInfo; 368#ifndef XSERVER_LIBPCIACCESS 369 pMga->IOAddress = pMga1->IOAddress; 370 pMga->ILOADAddress = pMga1->ILOADAddress; 371 pMga->BiosFrom = pMga1->BiosFrom; 372 pMga->BiosAddress = pMga1->BiosAddress; 373#endif 374 375 /* 376 * Read the BIOS data struct 377 */ 378 379 mga_read_and_process_bios( pScrn ); 380 381 /* HW bpp matches reported bpp */ 382 pMga->HwBpp = pMga1->HwBpp; 383 384 /* 385 * Reset card if it isn't primary one 386 */ 387 if ( (!pMga->Primary && !pMga->FBDev) ) 388 MGASoftReset(pScrn); 389 390 391 pScrn->videoRam = pScrn1->videoRam; 392 pMga->FbMapSize = pMga1->FbMapSize; 393 pMga->SrcOrg = pMga1->SrcOrg; 394 pMga->DstOrg = pMga1->DstOrg; 395 396 /* Set the bpp shift value */ 397 pMga->BppShifts[0] = 0; 398 pMga->BppShifts[1] = 1; 399 pMga->BppShifts[2] = 0; 400 pMga->BppShifts[3] = 2; 401 402 /* 403 * fill MGAdac struct 404 * Warning: currently, it should be after RAM counting 405 */ 406 (*pMga->PreInit)(pScrn); 407 408#if !defined(__powerpc__) 409 410 /* Read and print the Monitor DDC info */ 411/* pScrn->monitor->DDC = MGAdoDDC(pScrn);*/ /*FIXME: have to try this*/ 412#endif /* !__powerpc__ */ 413 414 /* 415 * If the driver can do gamma correction, it should call xf86SetGamma() 416 * here. 417 */ 418 { 419 Gamma zeros = {0.0, 0.0, 0.0}; 420 421 if (!xf86SetGamma(pScrn, zeros)) { 422 return FALSE; 423 } 424 } 425 426 427 /* Set the min pixel clock */ 428 pMga->MinClock = pMga1->MinClock; /* XXX Guess, need to check this */ 429 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Min pixel clock is %d MHz\n", 430 pMga->MinClock / 1000); 431 /* Override on 2nd crtc */ 432 433 if (pMga->ChipRev >= 0x80 || (pMga->Chipset == PCI_CHIP_MGAG550)) { 434 /* G450, G550 */ 435 pMga->MaxClock = 234000; 436 } else { 437 pMga->MaxClock = 135000; 438 } 439 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Max pixel clock is %d MHz\n", 440 pMga->MaxClock / 1000); 441 /* 442 * Setup the ClockRanges, which describe what clock ranges are available, 443 * and what sort of modes they can be used for. 444 */ 445 clockRanges = xnfcalloc(sizeof(ClockRange), 1); 446 clockRanges->next = NULL; 447 clockRanges->minClock = pMga->MinClock; 448 clockRanges->maxClock = pMga->MaxClock; 449 clockRanges->clockIndex = -1; /* programmable */ 450 clockRanges->interlaceAllowed = TRUE; 451 clockRanges->doubleScanAllowed = TRUE; 452 clockRanges->interlaceAllowed = FALSE; /*no interlace on CRTC2 */ 453 454 clockRanges->ClockMulFactor = 1; 455 clockRanges->ClockDivFactor = 1; 456 /* Only set MemClk if appropriate for the ramdac */ 457 if (pMga->Dac.SetMemClk) { 458 if (pMga->MemClk == 0) { 459 pMga->MemClk = pMga->Dac.MemoryClock; 460 from = pMga->Dac.MemClkFrom; 461 } else 462 from = X_CONFIG; 463 xf86DrvMsg(pScrn->scrnIndex, from, "CRTC2: MCLK used is %.1f MHz\n", 464 pMga->MemClk / 1000.0); 465 } 466 467 /* 468 * xf86ValidateModes will check that the mode HTotal and VTotal values 469 * don't exceed the chipset's limit if pScrn->maxHValue and 470 * pScrn->maxVValue are set. Since our MGAValidMode() already takes 471 * care of this, we don't worry about setting them here. 472 */ 473 { 474 int Pitches1[] = 475 {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0}; 476 int Pitches2[] = 477 {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664, 478 1920, 2048, 0}; 479 int *linePitches = NULL; 480 int minPitch = 256; 481 int maxPitch = 2048; 482 483 switch(pMga->Chipset) { 484 case PCI_CHIP_MGA2064: 485 if (!pMga->NoAccel) { 486 linePitches = malloc(sizeof(Pitches1)); 487 memcpy(linePitches, Pitches1, sizeof(Pitches1)); 488 minPitch = maxPitch = 0; 489 } 490 break; 491 case PCI_CHIP_MGA2164: 492 case PCI_CHIP_MGA2164_AGP: 493 case PCI_CHIP_MGA1064: 494 if (!pMga->NoAccel) { 495 linePitches = malloc(sizeof(Pitches2)); 496 memcpy(linePitches, Pitches2, sizeof(Pitches2)); 497 minPitch = maxPitch = 0; 498 } 499 break; 500 case PCI_CHIP_MGAG100: 501 case PCI_CHIP_MGAG100_PCI: 502 maxPitch = 2048; 503 break; 504 case PCI_CHIP_MGAG200: 505 case PCI_CHIP_MGAG200_PCI: 506 case PCI_CHIP_MGAG200_SE_A_PCI: 507 case PCI_CHIP_MGAG200_SE_B_PCI: 508 case PCI_CHIP_MGAG200_WINBOND_PCI: 509 case PCI_CHIP_MGAG200_EW3_PCI: 510 case PCI_CHIP_MGAG200_EV_PCI: 511 case PCI_CHIP_MGAG200_EH_PCI: 512 case PCI_CHIP_MGAG200_ER_PCI: 513 case PCI_CHIP_MGAG400: 514 case PCI_CHIP_MGAG550: 515 maxPitch = 4096; 516 break; 517 } 518 519 pScrn->modePool=NULL; 520 pScrn->modes = NULL; 521 i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 522 pScrn->display->modes, clockRanges, 523 linePitches, minPitch, maxPitch, 524 pMga->Roundings[(pScrn->bitsPerPixel >> 3) - 1] * 525 pScrn->bitsPerPixel, 128, 2048, 526 pScrn->display->virtualX, 527 pScrn->display->virtualY, 528 pMga->FbMapSize, 529 LOOKUP_BEST_REFRESH); 530 531 free(linePitches); 532 } 533 534 535 if (i < 1 && pMga->FBDev) { 536 fbdevHWUseBuildinMode(pScrn); 537 pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */ 538 i = 1; 539 } 540 if (i == -1) { 541 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: Validate Modes Failed\n"); 542 MGAFreeRec(pScrn); 543 return FALSE; 544 } 545 546 /* Prune the modes marked as invalid */ 547 xf86PruneDriverModes(pScrn); 548 549 if (i == 0 || pScrn->modes == NULL) { 550 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: No valid modes found\n"); 551 MGAFreeRec(pScrn); 552 return FALSE; 553 } 554 555 /* 556 * Set the CRTC parameters for all of the modes based on the type 557 * of mode, and the chipset's interlace requirements. 558 * 559 * Calling this is required if the mode->Crtc* values are used by the 560 * driver and if the driver doesn't provide code to set them. They 561 * are not pre-initialised at all. 562 */ 563 MGA_NOT_HAL(xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V)); 564 565 /* Set the current mode to the first in the list */ 566 pScrn->currentMode = pScrn->modes; 567 568 /* Print the list of modes being used */ 569 xf86PrintModes(pScrn); 570 571 /* Set display resolution */ 572 xf86SetDpi(pScrn, 0, 0); 573 574 /* 575 * Compute the byte offset into the linear frame buffer where the 576 * frame buffer data should actually begin. According to DDK misc.c 577 * line 1023, if more than 4MB is to be displayed, YDSTORG must be set 578 * appropriately to align memory bank switching, and this requires a 579 * corresponding offset on linear frame buffer access. 580 * This is only needed for WRAM. 581 */ 582 583 pMga->YDstOrg = pMga1->YDstOrg; 584 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "CRTC2: YDstOrg is set to %d\n", 585 pMga->YDstOrg); 586 pMga->FbUsableSize = pMga1->FbUsableSize; 587 pMga->FbCursorOffset = pMga1->FbCursorOffset; 588 589 pMga->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; 590 pMga->CurrentLayout.depth = pScrn->depth; 591 pMga->CurrentLayout.displayWidth = pScrn->displayWidth; 592 pMga->CurrentLayout.weight.red = pScrn->weight.red; 593 pMga->CurrentLayout.weight.green = pScrn->weight.green; 594 pMga->CurrentLayout.weight.blue = pScrn->weight.blue; 595 pMga->CurrentLayout.mode = pScrn->currentMode; 596 597 598 Monitor2Pos = mgaRightOf; 599 if ((s = xf86GetOptValString(pMga1->Options, OPTION_MONITOR2POS))) { 600 switch(s[0]) { 601 case 'L': case 'l': case 'G': case 'g': 602 Monitor2Pos = mgaLeftOf; 603 break; 604 case 'R': case 'r': case 'D': case 'd': 605 Monitor2Pos = mgaRightOf; 606 break; 607 608 case 'A': case 'a': case 'H': case 'h': 609 Monitor2Pos = mgaAbove; 610 break; 611 612 case 'B': case 'b': 613 Monitor2Pos = mgaBelow; 614 break; 615 616 case 'C': case 'c': 617 Monitor2Pos = mgaClone; 618 break; 619 default: 620 Monitor2Pos = mgaRightOf; 621 break; 622 } 623 } 624 625 /* Fool xf86 into thinking we have huge modes */ 626 /* Keep the original values somewhere */ 627 pMga1->M1modes = pScrn1->modes; 628 pMga1->M1currentMode = pScrn1->currentMode; 629 /* make a copy of the mode list, so we can modify it. */ 630 if ((s = xf86GetOptValString(pMga1->Options, OPTION_METAMODES))) { 631 pScrn1->modes = GenerateModeList(pScrn,s,pMga1->M1modes,pScrn->modes,Monitor2Pos); /*FIXME: free this list*/ 632 if(!pScrn1->modes) { 633 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Parse Error reading MetaModes, or No modes left.\n"); 634 return FALSE; 635 } 636 637 pScrn1->modes = pScrn1->modes->next; 638 pScrn1->currentMode = pScrn1->modes; 639 } else { 640 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "MetaModes option missing.\n"); 641 return FALSE; 642 } 643 xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== End of second screen initialization ====\n"); 644 return TRUE; 645} 646 647void 648MGADisplayPowerManagementSetMerged(ScrnInfoPtr pScrn, int PowerManagementMode, 649 int flags) 650{ 651 MGADisplayPowerManagementSet(pScrn,PowerManagementMode,flags); 652 MGADisplayPowerManagementSetCrtc2(pScrn,PowerManagementMode,flags); 653} 654 655typedef struct _region { 656 int x0,x1,y0,y1; 657 } region; 658 659static Bool 660InRegion(int x, int y, region r) { 661 return (r.x0 <= x) && (x < r.x1) && (r.y0 <= y) && (y < r.y1); 662} 663 664 665#define BOUND(test,low,hi) { \ 666 if(test < low) test = low; \ 667 if(test > hi) test = hi; } 668#define REBOUND(low,hi,test) { \ 669 if(test < low) { \ 670 hi += test-low; \ 671 low = test; } \ 672 if(test > hi) { \ 673 low += test-hi; \ 674 hi = test; } } 675 void 676MGAMergePointerMoved(SCRN_ARG_TYPE arg, int x, int y) 677{ 678 SCRN_INFO_PTR(arg); 679 MGAPtr pMga = MGAPTR(pScrn); 680 ScrnInfoPtr pScr2 = pMga->pScrn2; 681 682 region out,in1,in2,f2,f1; 683 684 int deltax,deltay; 685 686 /* for ease. */ 687 f1.x0 = pMga->M1frameX0; 688 f1.x1 = pMga->M1frameX1+1; 689 f1.y0 = pMga->M1frameY0; 690 f1.y1 = pMga->M1frameY1+1; 691 f2.x0 = pScr2->frameX0; 692 f2.x1 = pScr2->frameX1+1; 693 f2.y0 = pScr2->frameY0; 694 f2.y1 = pScr2->frameY1+1; 695 696 697 /*specify outer clipping region. crossing this causes all frames to move*/ 698 out.x0 = pScrn->frameX0; 699 out.x1 = pScrn->frameX1+1; 700 out.y0 = pScrn->frameY0; 701 out.y1 = pScrn->frameY1+1; 702 703 /* 704 * specify inner sliding window. beeing outsize both frames, and inside 705 * the outer cliping window, causes corresponding frame to slide 706 */ 707 in1 = out; 708 in2 = out; 709 switch(((MergedDisplayModePtr)pScrn->currentMode->Private)->Monitor2Pos) { 710 case mgaLeftOf : 711 in1.x0 = f1.x0; 712 in2.x1 = f2.x1; 713 break; 714 case mgaRightOf : 715 in1.x1 = f1.x1; 716 in2.x0 = f2.x0; 717 break; 718 case mgaBelow : 719 in1.y1 = f1.y1; 720 in2.y0 = f2.y0; 721 break; 722 case mgaAbove : 723 in1.y0 = f1.y0; 724 in2.y1 = f2.y1; 725 break; 726 case mgaClone : 727 break; 728 } 729 730 731 deltay = 0; 732 deltax = 0; 733 734 if(InRegion(x,y,out)) { 735 if( InRegion(x,y, in1) && !InRegion(x,y, f1) ) { 736 REBOUND(f1.x0,f1.x1,x); 737 REBOUND(f1.y0,f1.y1,y); 738 deltax = 1; /*force frame update */ 739 } 740 if( InRegion(x,y, in2) && !InRegion(x,y, f2) ) { 741 REBOUND(f2.x0,f2.x1,x); 742 REBOUND(f2.y0,f2.y1,y); 743 deltax = 1; /*force frame update */ 744 } 745 } 746 else { /*outside outer clipping region*/ 747 if ( out.x0 > x) { 748 deltax = x - out.x0; 749 } 750 if ( out.x1 < x) { 751 deltax = x - out.x1; 752 } 753 f1.x0 += deltax; 754 f1.x1 += deltax; 755 f2.x0 += deltax; 756 f2.x1 += deltax; 757 pScrn->frameX0 += deltax; 758 pScrn->frameX1 += deltax; 759 760 761 if ( out.y0 > y) { 762 deltay = y - out.y0; 763 } 764 if ( out.y1 < y) { 765 deltay = y - out.y1; 766 } 767 f1.y0 += deltay; 768 f1.y1 += deltay; 769 f2.y0 += deltay; 770 f2.y1 += deltay; 771 pScrn->frameY0 += deltay; 772 pScrn->frameY1 += deltay; 773 } 774 775 776 if (deltax != 0 || deltay != 0) { 777 /* back to reality. */ 778 pMga->M1frameX0 = f1.x0; 779 pMga->M1frameY0 = f1.y0; 780 pScr2->frameX0 = f2.x0; 781 pScr2->frameY0 = f2.y0; 782 783 /*Adjust Granularity */ 784 MGAAdjustGranularity(pScrn,&pMga->M1frameX0,&pMga->M1frameY0); 785 MGAAdjustGranularity(pScrn,&pScr2->frameX0,&pScr2->frameY0); 786 MGAAdjustGranularity(pScrn,&pScrn->frameX0,&pScrn->frameY0); 787 788 pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn)->Monitor1->HDisplay -1; 789 pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn)->Monitor1->VDisplay -1; 790 pScr2->frameX1 = pScr2->frameX0 + MDMPTR(pScrn)->Monitor2->HDisplay -1; 791 pScr2->frameY1 = pScr2->frameY0 + MDMPTR(pScrn)->Monitor2->VDisplay -1; 792 pScrn->frameX1 = pScrn->frameX0 + pScrn->currentMode->HDisplay -1; 793 pScrn->frameY1 = pScrn->frameY0 + pScrn->currentMode->VDisplay -1; 794 795 MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); 796 MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScr2->frameX0, pScr2->frameY0)); 797 } 798 799/* if(pMga->PointerMoved) 800 (*pMga->PointerMoved)(scrnIndex, x, y); FIXME: do I need to call old func?*/ 801 802} 803 804 805void 806MGAAdjustMergeFrames(ADJUST_FRAME_ARGS_DECL) { 807 SCRN_INFO_PTR(arg); 808 ScrnInfoPtr pScrn1 = pScrn; 809 MGAPtr pMga = MGAPTR(pScrn1); 810 ScrnInfoPtr pScrn2 = pMga->pScrn2; 811 int VTotal = pScrn1->currentMode->VDisplay; 812 int HTotal = pScrn1->currentMode->HDisplay; 813 int VMax = VTotal; 814 int HMax = HTotal; 815 816 BOUND(x,0,pScrn1->virtualX-HTotal); 817 BOUND(y,0,pScrn1->virtualY-VTotal); 818 switch(MDMPTR(pScrn1)->Monitor2Pos) { 819 case mgaLeftOf: 820 pScrn2->frameX0 = x; 821 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 822 pMga->M1frameX0 = x+MDMPTR(pScrn1)->Monitor2->HDisplay; 823 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 824 break; 825 case mgaRightOf: 826 pMga->M1frameX0 = x; 827 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 828 pScrn2->frameX0 = x+MDMPTR(pScrn1)->Monitor1->HDisplay; 829 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 830 break; 831 case mgaAbove: 832 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 833 pScrn2->frameY0 = y; 834 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 835 pMga->M1frameY0 = y+MDMPTR(pScrn1)->Monitor2->VDisplay; 836 break; 837 case mgaBelow: 838 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 839 pMga->M1frameY0 = y; 840 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 841 pScrn2->frameY0 = y+MDMPTR(pScrn1)->Monitor1->VDisplay; 842 break; 843 case mgaClone: 844 BOUND(pMga->M1frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor1->HDisplay); 845 BOUND(pMga->M1frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor1->VDisplay); 846 BOUND(pScrn2->frameX0,x,x + HMax - MDMPTR(pScrn1)->Monitor2->HDisplay); 847 BOUND(pScrn2->frameY0,y,y + VMax - MDMPTR(pScrn1)->Monitor2->VDisplay); 848 break; 849 } 850 /* sanity checks. Make shure were not out of bounds */ 851 BOUND(pMga->M1frameX0,0,pScrn1->virtualX -MDMPTR(pScrn1)->Monitor1->HDisplay); 852 BOUND(pMga->M1frameY0,0,pScrn1->virtualY -MDMPTR(pScrn1)->Monitor1->VDisplay); 853 BOUND(pScrn2->frameX0,0,pScrn2->virtualX -MDMPTR(pScrn1)->Monitor2->HDisplay); 854 BOUND(pScrn2->frameY0,0,pScrn2->virtualY -MDMPTR(pScrn1)->Monitor2->VDisplay); 855 856 pScrn1->frameX0 = x; 857 pScrn1->frameY0 = y; 858 859 /* check granularity */ 860 MGAAdjustGranularity(pScrn1,&pMga->M1frameX0,&pMga->M1frameY0); 861 MGAAdjustGranularity(pScrn1,&pScrn2->frameX0,&pScrn2->frameY0); 862 MGAAdjustGranularity(pScrn1,&pScrn1->frameX0,&pScrn1->frameY0); 863 864 /* complete shitty redundant info */ 865 pMga->M1frameX1 = pMga->M1frameX0 + MDMPTR(pScrn1)->Monitor1->HDisplay -1; 866 pMga->M1frameY1 = pMga->M1frameY0 + MDMPTR(pScrn1)->Monitor1->VDisplay -1; 867 pScrn2->frameX1 = pScrn2->frameX0 + MDMPTR(pScrn1)->Monitor2->HDisplay -1; 868 pScrn2->frameY1 = pScrn2->frameY0 + MDMPTR(pScrn1)->Monitor2->VDisplay -1; 869 pScrn1->frameX1 = pScrn1->frameX0 + pScrn1->currentMode->HDisplay -1; 870 pScrn1->frameY1 = pScrn1->frameY0 + pScrn1->currentMode->VDisplay -1; 871 872 MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pMga->M1frameX0, pMga->M1frameY0)); 873 MGAAdjustFrameCrtc2(ADJUST_FRAME_ARGS(pScrn, pScrn2->frameX0, pScrn2->frameY0)); 874 return; 875} 876 877Bool 878MGACloseScreenMerged(ScreenPtr pScreen) { 879 ScrnInfoPtr pScrn1 = xf86ScreenToScrn(pScreen); 880 MGAPtr pMga = MGAPTR(pScrn1); 881 ScrnInfoPtr pScrn2 = pMga->pScrn2; 882 883 if(pScrn2) { 884 free(pScrn2->monitor); 885 pScrn2->monitor = NULL; 886 887 free(pScrn2); 888 pMga->pScrn2 = NULL; 889 } 890 891 if(pScrn1->modes) { 892 pScrn1->currentMode = pScrn1->modes; 893 do { 894 DisplayModePtr p = pScrn1->currentMode->next; 895 free(pScrn1->currentMode->Private); 896 free(pScrn1->currentMode); 897 pScrn1->currentMode = p; 898 }while( pScrn1->currentMode != pScrn1->modes); 899 } 900 901 pScrn1->currentMode = pMga->M1currentMode; 902 pScrn1->modes = pMga->M1modes; 903 904 return TRUE; 905} 906 907Bool 908MGASaveScreenMerged(ScreenPtr pScreen, int mode) 909{ 910 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 911 MGAPtr pMga = MGAPTR(pScrn); 912 BOOL on = xf86IsUnblank(mode); 913 CARD8 reg; 914 915 if (on) { 916/* SetTimdeSinceLastInputEvent();*/ 917 918 /* power on Dac1 */ 919 reg = inMGAdac(MGA1064_MISC_CTL); 920 reg |= MGA1064_MISC_CTL_DAC_EN; 921 outMGAdac(MGA1064_MISC_CTL, reg); 922 923 /* power on Dac2 */ 924 reg = inMGAdac(MGA1064_PWR_CTL); 925 reg |= MGA1064_PWR_CTL_DAC2_EN; 926 outMGAdac(MGA1064_PWR_CTL, reg); 927 } else { 928 /* power off Dac1 */ 929 reg = inMGAdac(MGA1064_MISC_CTL); 930 reg &= ~MGA1064_MISC_CTL_DAC_EN; 931 outMGAdac(MGA1064_MISC_CTL, reg); 932 933 /* power off Dac2 */ 934 reg = inMGAdac(MGA1064_PWR_CTL); 935 reg &= ~MGA1064_PWR_CTL_DAC2_EN; 936 outMGAdac(MGA1064_PWR_CTL, reg); 937 } 938 939 return TRUE; 940} 941 942 943