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