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