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