mga_merge.c revision fe5e51b7
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/mga/mga_merge.c,v 1.4 2003/09/24 02:43:24 dawes Exp $ */ 2 3#ifdef HAVE_CONFIG_H 4#include "config.h" 5#endif 6 7/* All drivers should typically include these */ 8#include "xf86.h" 9#include "xf86_OSproc.h" 10#include "xf86Resources.h" 11 12/* All drivers need this */ 13 14#include "compiler.h" 15 16/* Drivers for PCI hardware need this */ 17#include "xf86PciInfo.h" 18#include "mga.h" 19#include "mga_macros.h" 20#include "mga_reg.h" 21#include "mga_merge.h" 22 23#include "fbdevhw.h" 24 25static int 26StrToRanges(range* r, char* s) { 27 float num=0.0; 28 int rangenum=0; 29 Bool gotdash = FALSE; 30 Bool nextdash = FALSE; 31 char* strnum=NULL; 32 do { 33 switch(*s) { 34 case '0': case '1': case '2': case '3': case '4': case '5': 35 case '6': case '7': case '8': case '9': case '.': 36 if(strnum == NULL) { 37 strnum = s; 38 gotdash = nextdash; 39 nextdash = FALSE; 40 } 41 42 break; 43 case '-': 44 case ' ': case 0: 45 if(strnum == NULL) break; /*is extra seperator */ 46 if(strnum != NULL) sscanf(strnum,"%f",&num); 47 if(gotdash) /*if wasn't singlet: correct. */ 48 r[rangenum-1].hi = num; 49 else { /*first, assume singlet */ 50 r[rangenum].lo = num; 51 r[rangenum].hi = num; 52 rangenum++; 53 } 54 strnum = NULL; 55 if(*s == '-') 56 nextdash = (rangenum != 0); /*ignore dash if before any number.*/ 57 break; 58 default : 59 return 0; 60 } 61 } while(*(s++) != 0); /* run loop for every char including null terminator.*/ 62 63 return rangenum; 64} 65 66 67/* Copys mode i, links the result to dest, and returns it. 68 * Links i and j in Private record. 69 * if dest is NULL, return value is copy of i linked to itself. 70 */ 71static DisplayModePtr 72CopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { 73 DisplayModePtr mode; 74 int dx = 0,dy = 0; 75 /* start with first node */ 76 mode = xalloc(sizeof(DisplayModeRec)); 77 memcpy(mode,i, sizeof(DisplayModeRec)); 78 mode->Private = xalloc(sizeof(MergedDisplayModeRec)); 79 ((MergedDisplayModePtr)mode->Private)->Monitor1 = i; 80 ((MergedDisplayModePtr)mode->Private)->Monitor2 = j; 81 ((MergedDisplayModePtr)mode->Private)->Monitor2Pos = srel; 82 mode->PrivSize = 0; 83 84 switch(srel) { 85 case mgaLeftOf: 86 case mgaRightOf: 87 dx = min(pScrn->virtualX,i->HDisplay + j->HDisplay) - mode->HDisplay; 88 dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; 89 break; 90 case mgaAbove: 91 case mgaBelow: 92 dy = min(pScrn->virtualY,i->VDisplay + j->VDisplay) - mode->VDisplay; 93 dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; 94 break; 95 case mgaClone: 96 dx = min(pScrn->virtualX, max(i->HDisplay,j->HDisplay)) - mode->HDisplay; 97 dy = min(pScrn->virtualY, max(i->VDisplay,j->VDisplay)) - mode->VDisplay; 98 break; 99 } 100 mode->HDisplay += dx; 101 mode->HSyncStart += dx; 102 mode->HSyncEnd += dx; 103 mode->HTotal += dx; 104 mode->VDisplay += dy; 105 mode->VSyncStart += dy; 106 mode->VSyncEnd += dy; 107 mode->VTotal += dy; 108 mode->Clock = 0; /* Shows we're in Merge mode. */ 109 110 mode->next = mode; 111 mode->prev = mode; 112 113 if(dest) { 114 /* Insert node after "dest" */ 115 mode->next = dest->next; 116 dest->next->prev = mode; 117 mode->prev = dest; 118 dest->next = mode; 119 } 120 121 return mode; 122} 123 124static DisplayModePtr 125GetModeFromName(char* str, DisplayModePtr i) 126{ 127 DisplayModePtr c = i; 128 if(!i) return NULL; 129 do { 130 if(strcmp(str,c->name) == 0) return c; 131 c = c->next; 132 } while(c != i); 133 return NULL; 134} 135 136/* takes a config file string of MetaModes and generates a MetaModeList */ 137static DisplayModePtr 138GenerateModeList(ScrnInfoPtr pScrn, char* str, 139 DisplayModePtr i, DisplayModePtr j, MgaScrn2Rel srel) { 140 char* strmode = str; 141 char modename[256]; 142 Bool gotdash = FALSE; 143 MgaScrn2Rel sr; 144 145 DisplayModePtr mode1 = NULL; 146 DisplayModePtr mode2 = NULL; 147 DisplayModePtr result = NULL; 148 do { 149 switch(*str) { 150 case 0: 151 case '-': 152 case ' ': 153 case ',': 154 case ';': 155 if((strmode != str)) {/*we got a mode */ 156 /* read new entry */ 157 strncpy(modename,strmode,str - strmode); 158 modename[str - strmode] = 0; 159 160 if(gotdash) { 161 if(mode1 == NULL) return NULL; 162 mode2 = GetModeFromName(modename,j); 163 if(!mode2) { 164 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 165 "Mode: \"%s\" is not a supported mode for monitor 2\n",modename); 166 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 167 "Skipping metamode \"%s-%s\".\n",mode1->name,modename); 168 mode1 = NULL; 169 } 170 } else { 171 mode1 = GetModeFromName(modename,i); 172 if(!mode1) { 173 char* tmps = str; 174 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 175 "Mode: \"%s\" is not a supported mode for monitor 1\n",modename); 176 /* find if a monitor2 mode follows */ 177 gotdash = FALSE; 178 while(*tmps == ' ' || *tmps == ';') tmps++; 179 if(*tmps == '-' || *tmps == ',') { /* skip the next mode */ 180 tmps++; 181 while(*tmps == ' ' || *tmps == ';') tmps++; /*skip spaces */ 182 while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != ',') tmps++; /*skip modename */ 183 /* for error message */ 184 strncpy(modename,strmode,tmps - strmode); 185 modename[tmps - strmode] = 0; 186 str = tmps-1; 187 } 188 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 189 "Skipping metamode \"%s\".\n",modename); 190 mode1 = NULL; 191 } 192 } 193 gotdash = FALSE; 194 } 195 strmode = str+1; /* number starts on next char */ 196 gotdash |= (*str == '-' || *str == ','); 197 198 if(*str != 0) break; /* if end of string, we wont get a chance to catch a char and run the 199 default case. do it now */ 200 201 default: 202 if(!gotdash && mode1) { /* complete previous pair */ 203 sr = srel; 204 if(!mode2) { 205 mode2 = GetModeFromName(mode1->name,j); 206 sr = mgaClone; 207 } 208 if(!mode2) { 209 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 210 "Mode: \"%s\" is not a supported mode for monitor 2\n",mode1->name); 211 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, 212 "Skipping clone mode \"%s\".\n", mode1->name); 213 mode1 = NULL; 214 } else { 215 result = CopyModeNLink(pScrn,result,mode1,mode2,sr); 216 mode1 = NULL; 217 mode2 = NULL; 218 } 219 } 220 break; 221 222 } 223 } while(*(str++) != 0); 224 return result; 225} 226 227 228/* second CRTC init funcitons. Used to check monitor timings and refreshes. 229 * this function looses lots of maintainability points due to redundancy, 230 * but it still was the cleanest and least-intrusive way I found. */ 231 232Bool 233MGAPreInitMergedFB(ScrnInfoPtr pScrn1, int flags) 234{ 235 ScrnInfoPtr pScrn; 236 MGAPtr pMga; 237 MGAPtr pMga1; 238 MessageType from; 239 int i; 240 char* s; 241 ClockRangePtr clockRanges; 242#ifdef USEMGAHAL 243 ULONG status; 244#endif 245 MgaScrn2Rel Monitor2Pos; 246 247 xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "==== Start of second screen initialization ====\n"); 248 pScrn = xalloc(sizeof(ScrnInfoRec)); 249 memcpy(pScrn,pScrn1,sizeof(ScrnInfoRec)); 250 251 pScrn->driverPrivate = NULL; 252 /* Allocate the MGARec driverPrivate */ 253 if (!MGAGetRec(pScrn)) { 254 return FALSE; 255 } 256 257 pMga = MGAPTR(pScrn); 258#ifdef USEMGAHAL 259 pMga->pMgaModeInfo = NULL; /*will be allocated later if NULL*/ 260#endif 261 pMga1 = MGAPTR(pScrn1); 262 pMga1->pScrn2 = pScrn; 263 264 /* Get the entity, and make sure it is PCI. */ 265 pMga->pEnt = pMga1->pEnt; 266 267 /* Set pMga->device to the relevant Device section */ 268 pMga->device = pMga1->device; 269 270 if (flags & PROBE_DETECT) { 271 MGAProbeDDC(pScrn, pMga->pEnt->index); /*FIXME make shure this probes second monitor */ 272 return TRUE; 273 } 274 275#ifndef XSERVER_LIBPCIACCESS 276 pMga->PciTag = pMga1->PciTag; 277#endif 278 pMga->Primary = pMga1->Primary; 279 280 /* Set pScrn->monitor */ 281 { 282 pScrn->monitor = xalloc(sizeof(MonRec)); 283 /* copy everything we don't care about */ 284 memcpy(pScrn->monitor,pScrn1->monitor,sizeof(MonRec)); 285 pScrn->monitor->DDC = NULL; /*FIXME:have to try this */ 286 if ((s = xf86GetOptValString(pMga1->Options, OPTION_HSYNC2))) { 287 pScrn->monitor->nHsync = StrToRanges(pScrn->monitor->hsync,s); 288 } 289 if ((s = xf86GetOptValString(pMga1->Options, OPTION_VREFRESH2))) { 290 pScrn->monitor->nVrefresh = StrToRanges(pScrn->monitor->vrefresh,s); 291 } 292 293 294 295 } 296 297 pMga->SecondCrtc = TRUE; 298 pMga->HWCursor = FALSE; 299 pScrn->AdjustFrame = MGAAdjustMergeFrames; 300 pScrn1->AdjustFrame = MGAAdjustMergeFrames; 301 302/* if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) FIXME:have to copy result form scrn1 303 if (!xf86SetWeight(pScrn, zeros, zeros)) { 304*/ 305 306 /* We use a programamble clock */ 307 pScrn->progClock = TRUE; 308 309 /* Collect all of the relevant option flags (fill in pScrn->options) */ 310 pScrn->options = pScrn1->options; 311 312/* xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pMga->Options);*/ 313 pMga->Options = pMga1->Options; 314 315 316 /* Set the bits per RGB for 8bpp mode */ 317 if (pScrn->depth == 8) 318 pScrn->rgbBits = 8; 319 320 /* 321 * Set the Chipset and ChipRev, allowing config file entries to 322 * override. 323 */ 324 pScrn->chipset = pScrn1->chipset; 325 pMga->Chipset = pMga1->Chipset; 326 pMga->ChipRev = pMga1->ChipRev; 327 328#ifdef XF86DRI 329 pMga->agpMode = pMga1->agpMode; 330#endif 331 332 pMga->NoAccel = pMga1->NoAccel; 333 pMga->UsePCIRetry = pMga1->UsePCIRetry; 334 pMga->SyncOnGreen = pMga1->SyncOnGreen; 335 pMga->ShowCache = pMga1->ShowCache; 336 pMga->HasSDRAM = pMga1->HasSDRAM; 337 pMga->MemClk = pMga1->MemClk; 338 pMga->Overlay8Plus24 = pMga1->Overlay8Plus24; 339 pMga->colorKey = pMga1->colorKey; 340 pScrn->colorKey = pScrn1->colorKey; 341 pScrn->overlayFlags = pScrn1->overlayFlags; 342 pMga->videoKey = pMga1->videoKey; 343 /* unsupported options */ 344 pMga->HWCursor = FALSE; 345 pMga->ShadowFB = FALSE; 346 pMga->FBDev = FALSE; 347 348 pMga->OverclockMem = pMga1->OverclockMem; 349 pMga->TexturedVideo = pMga1->TexturedVideo; 350 pMga->MergedFB = TRUE; 351 352 pMga->Rotate = 0; 353 354 switch (pMga->Chipset) { 355 case PCI_CHIP_MGA2064: 356 case PCI_CHIP_MGA2164: 357 case PCI_CHIP_MGA2164_AGP: 358 MGA2064SetupFuncs(pScrn); 359 break; 360 case PCI_CHIP_MGA1064: 361 case PCI_CHIP_MGAG100: 362 case PCI_CHIP_MGAG100_PCI: 363 case PCI_CHIP_MGAG200: 364 case PCI_CHIP_MGAG200_PCI: 365 case PCI_CHIP_MGAG200_SE_A_PCI: 366 case PCI_CHIP_MGAG200_SE_B_PCI: 367 case PCI_CHIP_MGAG400: 368 case PCI_CHIP_MGAG550: 369 MGAGSetupFuncs(pScrn); 370 break; 371 } 372 373 pMga->FbAddress = pMga1->FbAddress; 374 pMga->PciInfo = pMga1->PciInfo; 375#ifndef XSERVER_LIBPCIACCESS 376 pMga->IOAddress = pMga1->IOAddress; 377 pMga->ILOADAddress = pMga1->ILOADAddress; 378 pMga->BiosFrom = pMga1->BiosFrom; 379 pMga->BiosAddress = pMga1->BiosAddress; 380#endif 381 382 /* 383 * Read the BIOS data struct 384 */ 385 386 mga_read_and_process_bios( pScrn ); 387 388 /* HW bpp matches reported bpp */ 389 pMga->HwBpp = pMga1->HwBpp; 390 391 /* 392 * Reset card if it isn't primary one 393 */ 394 if ( (!pMga->Primary && !pMga->FBDev) || xf86IsPc98() ) 395 MGASoftReset(pScrn); 396 397 398 pScrn->videoRam = pScrn1->videoRam; 399 pMga->FbMapSize = pMga1->FbMapSize; 400 pMga->SrcOrg = pMga1->SrcOrg; 401 pMga->DstOrg = pMga1->DstOrg; 402 403 /* Set the bpp shift value */ 404 pMga->BppShifts[0] = 0; 405 pMga->BppShifts[1] = 1; 406 pMga->BppShifts[2] = 0; 407 pMga->BppShifts[3] = 2; 408 409 /* 410 * fill MGAdac struct 411 * Warning: currently, it should be after RAM counting 412 */ 413 (*pMga->PreInit)(pScrn); 414 415#if !defined(__powerpc__) 416 417 /* Read and print the Monitor DDC info */ 418/* pScrn->monitor->DDC = MGAdoDDC(pScrn);*/ /*FIXME: have to try this*/ 419#endif /* !__powerpc__ */ 420 421 /* 422 * If the driver can do gamma correction, it should call xf86SetGamma() 423 * here. 424 */ 425 { 426 Gamma zeros = {0.0, 0.0, 0.0}; 427 428 if (!xf86SetGamma(pScrn, zeros)) { 429 return FALSE; 430 } 431 } 432 433 434 /* Set the min pixel clock */ 435 pMga->MinClock = pMga1->MinClock; /* XXX Guess, need to check this */ 436 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Min pixel clock is %d MHz\n", 437 pMga->MinClock / 1000); 438 /* Override on 2nd crtc */ 439 440 if (pMga->ChipRev >= 0x80 || (pMga->Chipset == PCI_CHIP_MGAG550)) { 441 /* G450, G550 */ 442 pMga->MaxClock = 234000; 443 } else { 444 pMga->MaxClock = 135000; 445 } 446 xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "CRTC2: Max pixel clock is %d MHz\n", 447 pMga->MaxClock / 1000); 448 /* 449 * Setup the ClockRanges, which describe what clock ranges are available, 450 * and what sort of modes they can be used for. 451 */ 452 clockRanges = xnfcalloc(sizeof(ClockRange), 1); 453 clockRanges->next = NULL; 454 clockRanges->minClock = pMga->MinClock; 455 clockRanges->maxClock = pMga->MaxClock; 456 clockRanges->clockIndex = -1; /* programmable */ 457 clockRanges->interlaceAllowed = TRUE; 458 clockRanges->doubleScanAllowed = TRUE; 459#ifdef USEMGAHAL 460 MGA_HAL(clockRanges->interlaceAllowed = FALSE); 461 MGA_HAL(clockRanges->doubleScanAllowed = FALSE); 462#endif 463 clockRanges->interlaceAllowed = FALSE; /*no interlace on CRTC2 */ 464 465 clockRanges->ClockMulFactor = 1; 466 clockRanges->ClockDivFactor = 1; 467 /* Only set MemClk if appropriate for the ramdac */ 468 if (pMga->Dac.SetMemClk) { 469 if (pMga->MemClk == 0) { 470 pMga->MemClk = pMga->Dac.MemoryClock; 471 from = pMga->Dac.MemClkFrom; 472 } else 473 from = X_CONFIG; 474 xf86DrvMsg(pScrn->scrnIndex, from, "CRTC2: MCLK used is %.1f MHz\n", 475 pMga->MemClk / 1000.0); 476 } 477 478 /* 479 * xf86ValidateModes will check that the mode HTotal and VTotal values 480 * don't exceed the chipset's limit if pScrn->maxHValue and 481 * pScrn->maxVValue are set. Since our MGAValidMode() already takes 482 * care of this, we don't worry about setting them here. 483 */ 484 { 485 int Pitches1[] = 486 {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0}; 487 int Pitches2[] = 488 {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664, 489 1920, 2048, 0}; 490 int *linePitches = NULL; 491 int minPitch = 256; 492 int maxPitch = 2048; 493 494 switch(pMga->Chipset) { 495 case PCI_CHIP_MGA2064: 496 if (!pMga->NoAccel) { 497 linePitches = xalloc(sizeof(Pitches1)); 498 memcpy(linePitches, Pitches1, sizeof(Pitches1)); 499 minPitch = maxPitch = 0; 500 } 501 break; 502 case PCI_CHIP_MGA2164: 503 case PCI_CHIP_MGA2164_AGP: 504 case PCI_CHIP_MGA1064: 505 if (!pMga->NoAccel) { 506 linePitches = xalloc(sizeof(Pitches2)); 507 memcpy(linePitches, Pitches2, sizeof(Pitches2)); 508 minPitch = maxPitch = 0; 509 } 510 break; 511 case PCI_CHIP_MGAG100: 512 case PCI_CHIP_MGAG100_PCI: 513 maxPitch = 2048; 514 break; 515 case PCI_CHIP_MGAG200: 516 case PCI_CHIP_MGAG200_PCI: 517 case PCI_CHIP_MGAG200_SE_A_PCI: 518 case PCI_CHIP_MGAG200_SE_B_PCI: 519 case PCI_CHIP_MGAG400: 520 case PCI_CHIP_MGAG550: 521 maxPitch = 4096; 522 break; 523 } 524 525 pScrn->modePool=NULL; 526 pScrn->modes = NULL; 527 i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, 528 pScrn->display->modes, clockRanges, 529 linePitches, minPitch, maxPitch, 530 pMga->Roundings[(pScrn->bitsPerPixel >> 3) - 1] * 531 pScrn->bitsPerPixel, 128, 2048, 532 pScrn->display->virtualX, 533 pScrn->display->virtualY, 534 pMga->FbMapSize, 535 LOOKUP_BEST_REFRESH); 536 537 if (linePitches) 538 xfree(linePitches); 539 } 540 541 542 if (i < 1 && pMga->FBDev) { 543 fbdevHWUseBuildinMode(pScrn); 544 pScrn->displayWidth = pScrn->virtualX; /* FIXME: might be wrong */ 545 i = 1; 546 } 547 if (i == -1) { 548 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: Validate Modes Failed\n"); 549 MGAFreeRec(pScrn); 550 return FALSE; 551 } 552 553 /* Prune the modes marked as invalid */ 554 xf86PruneDriverModes(pScrn); 555 556 if (i == 0 || pScrn->modes == NULL) { 557 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "CRTC2: No valid modes found\n"); 558 MGAFreeRec(pScrn); 559 return FALSE; 560 } 561#ifdef USEMGAHAL 562 MGA_HAL( 563 564 pMga->pBoard = pMga1->pBoard; 565 pMga->pClientStruct = pMga1->pClientStruct; 566 pMga->pMgaHwInfo = pMga1->pMgaHwInfo; 567 568 569 MGAFillModeInfoStruct(pScrn,NULL); 570 /* Fields usually handled by MGAFillModeInfoStruct, but are unavailable 571 * because no mode is given 572 */ 573 pMga->pMgaModeInfo->ulDispWidth = pScrn->virtualX; 574 pMga->pMgaModeInfo->ulDispHeight = pScrn->virtualY; 575 576 if((status = MGAValidateMode(pMga->pBoard,pMga->pMgaModeInfo)) != 0) { 577 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 578 "MGAValidateMode from HALlib found the mode to be invalid.\n" 579 "\tError: 0x%lx\n", status); 580 return FALSE; 581 } 582 pScrn->displayWidth = pMga->pMgaModeInfo->ulFBPitch; 583 ); /* MGA_HAL */ 584#endif 585 586 /* 587 * Set the CRTC parameters for all of the modes based on the type 588 * of mode, and the chipset's interlace requirements. 589 * 590 * Calling this is required if the mode->Crtc* values are used by the 591 * driver and if the driver doesn't provide code to set them. They 592 * are not pre-initialised at all. 593 */ 594#ifdef USEMGAHAL 595 MGA_HAL(xf86SetCrtcForModes(pScrn, 0)); 596#endif 597 MGA_NOT_HAL(xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V)); 598 599 /* Set the current mode to the first in the list */ 600 pScrn->currentMode = pScrn->modes; 601 602 /* Print the list of modes being used */ 603 xf86PrintModes(pScrn); 604 605 /* Set display resolution */ 606 xf86SetDpi(pScrn, 0, 0); 607 608 /* 609 * Compute the byte offset into the linear frame buffer where the 610 * frame buffer data should actually begin. According to DDK misc.c 611 * line 1023, if more than 4MB is to be displayed, YDSTORG must be set 612 * appropriately to align memory bank switching, and this requires a 613 * corresponding offset on linear frame buffer access. 614 * This is only needed for WRAM. 615 */ 616 617 pMga->YDstOrg = pMga1->YDstOrg; 618 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "CRTC2: YDstOrg is set to %d\n", 619 pMga->YDstOrg); 620 pMga->FbUsableSize = pMga1->FbUsableSize; 621 pMga->FbCursorOffset = pMga1->FbCursorOffset; 622 623 pMga->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel; 624 pMga->CurrentLayout.depth = pScrn->depth; 625 pMga->CurrentLayout.displayWidth = pScrn->displayWidth; 626 pMga->CurrentLayout.weight.red = pScrn->weight.red; 627 pMga->CurrentLayout.weight.green = pScrn->weight.green; 628 pMga->CurrentLayout.weight.blue = pScrn->weight.blue; 629 pMga->CurrentLayout.Overlay8Plus24 = pMga->Overlay8Plus24; 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