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