/* $XFree86$ */ /* * Copyright 2003 Alex Deucher. * * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation on the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL ALEX DEUCHER, OR ANY OTHER * CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * Authors: * Alex Deucher * Based, in large part, on the sis driver by Thomas Winischhofer. */ #include "xf86.h" #include "xf86Priv.h" #include "xf86Resources.h" #include "xf86_OSproc.h" #include "extnsionst.h" /* required */ #include /* required */ #include "dixstruct.h" #include "vbe.h" #include "radeon.h" #include "radeon_reg.h" #include "radeon_macros.h" #include "radeon_mergedfb.h" /* psuedo xinerama support */ static unsigned char RADEONXineramaReqCode = 0; int RADEONXineramaPixWidth = 0; int RADEONXineramaPixHeight = 0; int RADEONXineramaNumScreens = 0; RADEONXineramaData *RADEONXineramadataPtr = NULL; static int RADEONXineramaGeneration; Bool RADEONnoPanoramiXExtension = TRUE; int RADEONProcXineramaQueryVersion(ClientPtr client); int RADEONProcXineramaGetState(ClientPtr client); int RADEONProcXineramaGetScreenCount(ClientPtr client); int RADEONProcXineramaGetScreenSize(ClientPtr client); int RADEONProcXineramaIsActive(ClientPtr client); int RADEONProcXineramaQueryScreens(ClientPtr client); int RADEONSProcXineramaDispatch(ClientPtr client); static void RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y); /* mergedfb functions */ /* Helper function for CRT2 monitor vrefresh/hsync options * (Taken from mga, sis drivers) */ int RADEONStrToRanges(range *r, char *s, int max) { float num = 0.0; int rangenum = 0; Bool gotdash = FALSE; Bool nextdash = FALSE; char* strnum = NULL; do { switch(*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': if(strnum == NULL) { strnum = s; gotdash = nextdash; nextdash = FALSE; } break; case '-': case ' ': case 0: if(strnum == NULL) break; sscanf(strnum, "%f", &num); strnum = NULL; if(gotdash) r[rangenum - 1].hi = num; else { r[rangenum].lo = num; r[rangenum].hi = num; rangenum++; } if(*s == '-') nextdash = (rangenum != 0); else if(rangenum >= max) return rangenum; break; default : return 0; } } while(*(s++) != 0); return rangenum; } /* Copy and link two modes (i, j) for merged-fb mode * (Taken from mga, sis drivers) * Copys mode i, merges j to copy of i, links the result to dest, and returns it. * Links i and j in Private record. * If dest is NULL, return value is copy of i linked to itself. * For mergedfb auto-config, we only check the dimension * against virtualX/Y, if they were user-provided. */ static DisplayModePtr RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, DisplayModePtr i, DisplayModePtr j, RADEONScrn2Rel srel) { DisplayModePtr mode; int dx = 0,dy = 0; RADEONInfoPtr info = RADEONPTR(pScrn); if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest; memcpy(mode, i, sizeof(DisplayModeRec)); if(!((mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec))))) { xfree(mode); return dest; } ((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i; ((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j; ((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel; mode->PrivSize = 0; switch(srel) { case radeonLeftOf: case radeonRightOf: if(!(pScrn->display->virtualX)) { dx = i->HDisplay + j->HDisplay; } else { dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay); } dx -= mode->HDisplay; if(!(pScrn->display->virtualY)) { dy = max(i->VDisplay, j->VDisplay); } else { dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); } dy -= mode->VDisplay; break; case radeonAbove: case radeonBelow: if(!(pScrn->display->virtualY)) { dy = i->VDisplay + j->VDisplay; } else { dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay); } dy -= mode->VDisplay; if(!(pScrn->display->virtualX)) { dx = max(i->HDisplay, j->HDisplay); } else { dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); } dx -= mode->HDisplay; break; case radeonClone: if(!(pScrn->display->virtualX)) { dx = max(i->HDisplay, j->HDisplay); } else { dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); } dx -= mode->HDisplay; if(!(pScrn->display->virtualY)) { dy = max(i->VDisplay, j->VDisplay); } else { dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); } dy -= mode->VDisplay; break; } mode->HDisplay += dx; mode->HSyncStart += dx; mode->HSyncEnd += dx; mode->HTotal += dx; mode->VDisplay += dy; mode->VSyncStart += dy; mode->VSyncEnd += dy; mode->VTotal += dy; /* Provide a sophisticated fake DotClock in order to trick the vidmode * extension to allow selecting among a number of modes whose merged result * looks identical but consists of different modes for CRT1 and CRT2 */ mode->Clock = (((i->Clock >> 3) + i->HTotal) << 16) | ((j->Clock >> 2) + j->HTotal); mode->Clock ^= ((i->VTotal << 19) | (j->VTotal << 3)); if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > (pScrn->videoRam * 1024)) || (mode->HDisplay > 8191) || (mode->VDisplay > 8191) ) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n", mode->name, mode->HDisplay, mode->VDisplay); xfree(mode->Private); xfree(mode); return dest; } if(srel != radeonClone) { info->AtLeastOneNonClone = TRUE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d%s\n", i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay, mode->HDisplay, mode->VDisplay, (srel == radeonClone) ? " (Clone)" : ""); mode->next = mode; mode->prev = mode; if(dest) { mode->next = dest->next; /* Insert node after "dest" */ dest->next->prev = mode; mode->prev = dest; dest->next = mode; } return mode; } /* Helper function to find a mode from a given name * (Taken from mga, sis drivers) */ static DisplayModePtr RADEONGetModeFromName(char* str, DisplayModePtr i) { DisplayModePtr c = i; if(!i) return NULL; do { if(strcmp(str, c->name) == 0) return c; c = c->next; } while(c != i); return NULL; } static DisplayModePtr RADEONFindWidestTallestMode(DisplayModePtr i, Bool tallest) { DisplayModePtr c = i, d = NULL; int max = 0; if(!i) return NULL; do { if(tallest) { if(c->VDisplay > max) { max = c->VDisplay; d = c; } } else { if(c->HDisplay > max) { max = c->HDisplay; d = c; } } c = c->next; } while(c != i); return d; } static void RADEONFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest, DisplayModePtr *a, DisplayModePtr *b) { DisplayModePtr c = i, d; int max = 0; Bool foundone; (*a) = (*b) = NULL; if(!i || !j) return; do { d = j; foundone = FALSE; do { if( (c->HDisplay == d->HDisplay) && (c->VDisplay == d->VDisplay) ) { foundone = TRUE; break; } d = d->next; } while(d != j); if(foundone) { if(tallest) { if(c->VDisplay > max) { max = c->VDisplay; (*a) = c; (*b) = d; } } else { if(c->HDisplay > max) { max = c->HDisplay; (*a) = c; (*b) = d; } } } c = c->next; } while(c != i); } static DisplayModePtr RADEONGenerateModeListFromLargestModes(ScrnInfoPtr pScrn, DisplayModePtr i, DisplayModePtr j, RADEONScrn2Rel srel) { RADEONInfoPtr info = RADEONPTR(pScrn); DisplayModePtr mode1 = NULL; DisplayModePtr mode2 = NULL; DisplayModePtr mode3 = NULL; DisplayModePtr mode4 = NULL; DisplayModePtr result = NULL; int p = 0; int count = 0; info->AtLeastOneNonClone = FALSE; /* Now build a default list of MetaModes. * - Non-clone: If the user enabled NonRectangular, we use the * largest mode for each CRT1 and CRT2. If not, we use the largest * common mode for CRT1 and CRT2 (if available). Additionally, and * regardless if the above, we produce a clone mode consisting of * the largest common mode (if available) in order to use DGA. * - Clone: If the (global) CRT2Position is Clone, we use the * largest common mode if available, otherwise the first two modes * in each list. */ switch(srel) { case radeonLeftOf: case radeonRightOf: mode1 = RADEONFindWidestTallestMode(i, FALSE); mode2 = RADEONFindWidestTallestMode(j, FALSE); RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4); break; case radeonAbove: case radeonBelow: mode1 = RADEONFindWidestTallestMode(i, TRUE); mode2 = RADEONFindWidestTallestMode(j, TRUE); RADEONFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4); break; case radeonClone: RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4); if(mode3 && mode4) { mode1 = mode3; mode2 = mode4; } else { mode1 = i; mode2 = j; } } if(srel != radeonClone) { if(mode3 && mode4 && !info->NonRect) { mode1 = mode3; mode2 = mode2; } } if(mode1 && mode2) { result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel); } if(srel != radeonClone) { if(mode3 && mode4) { result = RADEONCopyModeNLink(pScrn, result, mode3, mode4, radeonClone); } } return result; } /* Generate the merged-fb mode modelist * (Taken from mga, sis drivers) */ static DisplayModePtr RADEONGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str, DisplayModePtr i, DisplayModePtr j, RADEONScrn2Rel srel) { char* strmode = str; char modename[256]; Bool gotdash = FALSE, gotplus = FALSE; RADEONScrn2Rel sr; DisplayModePtr mode1 = NULL; DisplayModePtr mode2 = NULL; DisplayModePtr result = NULL; int myslen; RADEONInfoPtr info = RADEONPTR(pScrn); info->AtLeastOneNonClone = FALSE; do { switch(*str) { case 0: case '-': case '+': case ' ': if(strmode != str) { myslen = str - strmode; if(myslen > 255) myslen = 255; strncpy(modename, strmode, myslen); modename[myslen] = 0; if(gotdash) { if(mode1 == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Error parsing MetaModes parameter\n"); return NULL; } mode2 = RADEONGetModeFromName(modename, j); if(!mode2) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode \"%s\" is not a supported mode for CRT2\n", modename); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "\t(Skipping metamode \"%s%s%s\")\n", mode1->name, gotplus ? "+" : "-", modename); mode1 = NULL; gotplus = FALSE; } } else { mode1 = RADEONGetModeFromName(modename, i); if(!mode1) { char* tmps = str; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode \"%s\" is not a supported mode for CRT1\n", modename); while(*tmps == ' ') tmps++; /* skip the next mode */ if((*tmps == '-') || (*tmps == '+')) { tmps++; /* skip spaces */ while(*tmps == ' ') tmps++; /* skip modename */ while((*tmps != ' ') && (*tmps != '-') && (*tmps != '+') && (*tmps != 0)) tmps++; myslen = tmps - strmode; if(myslen > 255) myslen = 255; strncpy(modename,strmode,myslen); modename[myslen] = 0; str = tmps-1; } xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "\t(Skipping metamode \"%s\")\n", modename); mode1 = NULL; gotplus = FALSE; } } gotdash = FALSE; } strmode = str + 1; gotdash |= ((*str == '-') || (*str == '+')); gotplus |= (*str == '+'); if(*str != 0) break; /* Fall through otherwise */ default: if(!gotdash && mode1) { sr = srel; if(gotplus) sr = radeonClone; if(!mode2) { mode2 = RADEONGetModeFromName(mode1->name, j); sr = radeonClone; } if(!mode2) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "\t(Skipping metamode \"%s\")\n", modename); mode1 = NULL; } else { result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr); mode1 = NULL; mode2 = NULL; } gotplus = FALSE; } break; } } while(*(str++) != 0); return result; } DisplayModePtr RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, DisplayModePtr i, DisplayModePtr j, RADEONScrn2Rel srel) { RADEONInfoPtr info = RADEONPTR(pScrn); if(str != NULL) { return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel)); } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No MetaModes given, linking %s modes by default\n", (srel == radeonClone) ? "largest common" : (info->NonRect ? (((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest" : "tallest") : (((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest common" : "tallest common")) ); return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel)); } } void RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); DisplayModePtr mode, bmode; int maxh, maxv; static const char *str = "MergedFB: Virtual %s %d\n"; static const char *errstr = "Virtual %s to small for given CRT2Position offset\n"; mode = bmode = pScrn->modes; maxh = maxv = 0; do { if(mode->HDisplay > maxh) maxh = mode->HDisplay; if(mode->VDisplay > maxv) maxv = mode->VDisplay; mode = mode->next; } while(mode != bmode); maxh += info->CRT1XOffs + info->CRT2XOffs; maxv += info->CRT1YOffs + info->CRT2YOffs; if(!(pScrn->display->virtualX)) { if(maxh > 8191) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Virtual width with CRT2Position offset beyond hardware specs\n"); info->CRT1XOffs = info->CRT2XOffs = 0; maxh -= (info->CRT1XOffs + info->CRT2XOffs); } pScrn->virtualX = maxh; pScrn->displayWidth = maxh; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh); } else { if(maxh < pScrn->display->virtualX) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width"); info->CRT1XOffs = info->CRT2XOffs = 0; } } if(!(pScrn->display->virtualY)) { pScrn->virtualY = maxv; xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv); } else { if(maxv < pScrn->display->virtualY) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height"); info->CRT1YOffs = info->CRT2YOffs = 0; } } } /* Pseudo-Xinerama extension for MergedFB mode */ void RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1) { RADEONInfoPtr info = RADEONPTR(pScrn1); ScrnInfoPtr pScrn2 = NULL; int crt1scrnnum = 0, crt2scrnnum = 1; int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0; int realvirtX, realvirtY; DisplayModePtr currentMode, firstMode; Bool infochanged = FALSE; Bool usenonrect = info->NonRect; const char *rectxine = "\t... setting up rectangular Xinerama layout\n"; info->MBXNR1XMAX = info->MBXNR1YMAX = info->MBXNR2XMAX = info->MBXNR2YMAX = 65536; info->HaveNonRect = info->HaveOffsRegions = FALSE; if(!info->MergedFB) return; if(RADEONnoPanoramiXExtension) return; if(!RADEONXineramadataPtr) return; if(info->CRT2IsScrn0) { crt1scrnnum = 1; crt2scrnnum = 0; } pScrn2 = info->CRT2pScrn; /* Attention: Usage of RandR may lead into virtual X and Y values * actually smaller than our MetaModes! To avoid this, we calculate * the maxCRT fields here (and not somewhere else, like in CopyNLink) */ /* "Real" virtual: Virtual without the Offset */ realvirtX = pScrn1->virtualX - info->CRT1XOffs - info->CRT2XOffs; realvirtY = pScrn1->virtualY - info->CRT1YOffs - info->CRT2YOffs; if((info->RADEONXineramaVX != pScrn1->virtualX) || (info->RADEONXineramaVY != pScrn1->virtualY)) { if(!(pScrn1->modes)) { xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, "Internal error: RADEONUpdateXineramaScreenInfo(): pScrn->modes is NULL\n"); return; } info->maxCRT1_X1 = info->maxCRT1_X2 = 0; info->maxCRT1_Y1 = info->maxCRT1_Y2 = 0; info->maxCRT2_X1 = info->maxCRT2_X2 = 0; info->maxCRT2_Y1 = info->maxCRT2_Y2 = 0; info->maxClone_X1 = info->maxClone_X2 = 0; info->maxClone_Y1 = info->maxClone_Y2 = 0; currentMode = firstMode = pScrn1->modes; do { DisplayModePtr p = currentMode->next; DisplayModePtr i = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT1; DisplayModePtr j = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2; RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2Position; if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) && (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) && (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) { if(srel != radeonClone) { if(info->maxCRT1_X1 == i->HDisplay) { if(info->maxCRT1_X2 < j->HDisplay) { info->maxCRT1_X2 = j->HDisplay; /* Widest CRT2 mode displayed with widest CRT1 mode */ } } else if(info->maxCRT1_X1 < i->HDisplay) { info->maxCRT1_X1 = i->HDisplay; /* Widest CRT1 mode */ info->maxCRT1_X2 = j->HDisplay; } if(info->maxCRT2_X2 == j->HDisplay) { if(info->maxCRT2_X1 < i->HDisplay) { info->maxCRT2_X1 = i->HDisplay; /* Widest CRT1 mode displayed with widest CRT2 mode */ } } else if(info->maxCRT2_X2 < j->HDisplay) { info->maxCRT2_X2 = j->HDisplay; /* Widest CRT2 mode */ info->maxCRT2_X1 = i->HDisplay; } if(info->maxCRT1_Y1 == i->VDisplay) { /* Same as above, but tallest instead of widest */ if(info->maxCRT1_Y2 < j->VDisplay) { info->maxCRT1_Y2 = j->VDisplay; } } else if(info->maxCRT1_Y1 < i->VDisplay) { info->maxCRT1_Y1 = i->VDisplay; info->maxCRT1_Y2 = j->VDisplay; } if(info->maxCRT2_Y2 == j->VDisplay) { if(info->maxCRT2_Y1 < i->VDisplay) { info->maxCRT2_Y1 = i->VDisplay; } } else if(info->maxCRT2_Y2 < j->VDisplay) { info->maxCRT2_Y2 = j->VDisplay; info->maxCRT2_Y1 = i->VDisplay; } } else { if(info->maxClone_X1 < i->HDisplay) { info->maxClone_X1 = i->HDisplay; } if(info->maxClone_X2 < j->HDisplay) { info->maxClone_X2 = j->HDisplay; } if(info->maxClone_Y1 < i->VDisplay) { info->maxClone_Y1 = i->VDisplay; } if(info->maxClone_Y2 < j->VDisplay) { info->maxClone_Y2 = j->VDisplay; } } } currentMode = p; } while((currentMode) && (currentMode != firstMode)); info->RADEONXineramaVX = pScrn1->virtualX; info->RADEONXineramaVY = pScrn1->virtualY; infochanged = TRUE; } if((usenonrect) && (info->CRT2Position != radeonClone) && info->maxCRT1_X1) { switch(info->CRT2Position) { case radeonLeftOf: case radeonRightOf: if((info->maxCRT1_Y1 != realvirtY) && (info->maxCRT2_Y2 != realvirtY)) { usenonrect = FALSE; } break; case radeonAbove: case radeonBelow: if((info->maxCRT1_X1 != realvirtX) && (info->maxCRT2_X2 != realvirtX)) { usenonrect = FALSE; } break; case radeonClone: break; } if(infochanged && !usenonrect) { xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Virtual screen size does not match maximum display modes...\n"); xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); } } else if(infochanged && usenonrect) { usenonrect = FALSE; xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Only clone modes available for this virtual screen size...\n"); xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); } if(info->maxCRT1_X1) { /* Means we have at least one non-clone mode */ switch(info->CRT2Position) { case radeonLeftOf: x1 = min(info->maxCRT1_X2, pScrn1->virtualX - info->maxCRT1_X1); if(x1 < 0) x1 = 0; y1 = info->CRT1YOffs; w1 = pScrn1->virtualX - x1; h1 = realvirtY; if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) { h1 = info->MBXNR1YMAX = info->maxCRT1_Y1; info->NonRectDead.x0 = x1; info->NonRectDead.x1 = x1 + w1 - 1; info->NonRectDead.y0 = y1 + h1; info->NonRectDead.y1 = pScrn1->virtualY - 1; info->HaveNonRect = TRUE; } x2 = 0; y2 = info->CRT2YOffs; w2 = max(info->maxCRT2_X2, pScrn1->virtualX - info->maxCRT2_X1); if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX; h2 = realvirtY; if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) { h2 = info->MBXNR2YMAX = info->maxCRT2_Y2; info->NonRectDead.x0 = x2; info->NonRectDead.x1 = x2 + w2 - 1; info->NonRectDead.y0 = y2 + h2; info->NonRectDead.y1 = pScrn1->virtualY - 1; info->HaveNonRect = TRUE; } break; case radeonRightOf: x1 = 0; y1 = info->CRT1YOffs; w1 = max(info->maxCRT1_X1, pScrn1->virtualX - info->maxCRT1_X2); if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX; h1 = realvirtY; if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) { h1 = info->MBXNR1YMAX = info->maxCRT1_Y1; info->NonRectDead.x0 = x1; info->NonRectDead.x1 = x1 + w1 - 1; info->NonRectDead.y0 = y1 + h1; info->NonRectDead.y1 = pScrn1->virtualY - 1; info->HaveNonRect = TRUE; } x2 = min(info->maxCRT2_X1, pScrn1->virtualX - info->maxCRT2_X2); if(x2 < 0) x2 = 0; y2 = info->CRT2YOffs; w2 = pScrn1->virtualX - x2; h2 = realvirtY; if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) { h2 = info->MBXNR2YMAX = info->maxCRT2_Y2; info->NonRectDead.x0 = x2; info->NonRectDead.x1 = x2 + w2 - 1; info->NonRectDead.y0 = y2 + h2; info->NonRectDead.y1 = pScrn1->virtualY - 1; info->HaveNonRect = TRUE; } break; case radeonAbove: x1 = info->CRT1XOffs; y1 = min(info->maxCRT1_Y2, pScrn1->virtualY - info->maxCRT1_Y1); if(y1 < 0) y1 = 0; w1 = realvirtX; h1 = pScrn1->virtualY - y1; if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) { w1 = info->MBXNR1XMAX = info->maxCRT1_X1; info->NonRectDead.x0 = x1 + w1; info->NonRectDead.x1 = pScrn1->virtualX - 1; info->NonRectDead.y0 = y1; info->NonRectDead.y1 = y1 + h1 - 1; info->HaveNonRect = TRUE; } x2 = info->CRT2XOffs; y2 = 0; w2 = realvirtX; h2 = max(info->maxCRT2_Y2, pScrn1->virtualY - info->maxCRT2_Y1); if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY; if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) { w2 = info->MBXNR2XMAX = info->maxCRT2_X2; info->NonRectDead.x0 = x2 + w2; info->NonRectDead.x1 = pScrn1->virtualX - 1; info->NonRectDead.y0 = y2; info->NonRectDead.y1 = y2 + h2 - 1; info->HaveNonRect = TRUE; } break; case radeonBelow: x1 = info->CRT1XOffs; y1 = 0; w1 = realvirtX; h1 = max(info->maxCRT1_Y1, pScrn1->virtualY - info->maxCRT1_Y2); if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY; if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) { w1 = info->MBXNR1XMAX = info->maxCRT1_X1; info->NonRectDead.x0 = x1 + w1; info->NonRectDead.x1 = pScrn1->virtualX - 1; info->NonRectDead.y0 = y1; info->NonRectDead.y1 = y1 + h1 - 1; info->HaveNonRect = TRUE; } x2 = info->CRT2XOffs; y2 = min(info->maxCRT2_Y1, pScrn1->virtualY - info->maxCRT2_Y2); if(y2 < 0) y2 = 0; w2 = realvirtX; h2 = pScrn1->virtualY - y2; if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) { w2 = info->MBXNR2XMAX = info->maxCRT2_X2; info->NonRectDead.x0 = x2 + w2; info->NonRectDead.x1 = pScrn1->virtualX - 1; info->NonRectDead.y0 = y2; info->NonRectDead.y1 = y2 + h2 - 1; info->HaveNonRect = TRUE; } default: break; } switch(info->CRT2Position) { case radeonLeftOf: case radeonRightOf: if(info->CRT1YOffs) { info->OffDead1.x0 = x1; info->OffDead1.x1 = x1 + w1 - 1; info->OffDead1.y0 = 0; info->OffDead1.y1 = y1 - 1; info->OffDead2.x0 = x2; info->OffDead2.x1 = x2 + w2 - 1; info->OffDead2.y0 = y2 + h2; info->OffDead2.y1 = pScrn1->virtualY - 1; info->HaveOffsRegions = TRUE; } else if(info->CRT2YOffs) { info->OffDead1.x0 = x2; info->OffDead1.x1 = x2 + w2 - 1; info->OffDead1.y0 = 0; info->OffDead1.y1 = y2 - 1; info->OffDead2.x0 = x1; info->OffDead2.x1 = x1 + w1 - 1; info->OffDead2.y0 = y1 + h1; info->OffDead2.y1 = pScrn1->virtualY - 1; info->HaveOffsRegions = TRUE; } break; case radeonAbove: case radeonBelow: if(info->CRT1XOffs) { info->OffDead1.x0 = x2 + w2; info->OffDead1.x1 = pScrn1->virtualX - 1; info->OffDead1.y0 = y2; info->OffDead1.y1 = y2 + h2 - 1; info->OffDead2.x0 = 0; info->OffDead2.x1 = x1 - 1; info->OffDead2.y0 = y1; info->OffDead2.y1 = y1 + h1 - 1; info->HaveOffsRegions = TRUE; } else if(info->CRT2XOffs) { info->OffDead1.x0 = x1 + w1; info->OffDead1.x1 = pScrn1->virtualX - 1; info->OffDead1.y0 = y1; info->OffDead1.y1 = y1 + h1 - 1; info->OffDead2.x0 = 0; info->OffDead2.x1 = x2 - 1; info->OffDead2.y0 = y2; info->OffDead2.y1 = y2 + h2 - 1; info->HaveOffsRegions = TRUE; } default: break; } } else { /* Only clone-modes left */ x1 = x2 = 0; y1 = y2 = 0; w1 = w2 = max(info->maxClone_X1, info->maxClone_X2); h1 = h2 = max(info->maxClone_Y1, info->maxClone_Y2); } RADEONXineramadataPtr[crt1scrnnum].x = x1; RADEONXineramadataPtr[crt1scrnnum].y = y1; RADEONXineramadataPtr[crt1scrnnum].width = w1; RADEONXineramadataPtr[crt1scrnnum].height = h1; RADEONXineramadataPtr[crt2scrnnum].x = x2; RADEONXineramadataPtr[crt2scrnnum].y = y2; RADEONXineramadataPtr[crt2scrnnum].width = w2; RADEONXineramadataPtr[crt2scrnnum].height = h2; if(infochanged) { xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n", crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1); xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n", crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1); if(info->HaveNonRect) { xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n", info->NonRectDead.x0, info->NonRectDead.y0, info->NonRectDead.x1, info->NonRectDead.y1); } if(info->HaveOffsRegions) { xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", info->OffDead1.x0, info->OffDead1.y0, info->OffDead1.x1, info->OffDead1.y1); xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", info->OffDead2.x0, info->OffDead2.y0, info->OffDead2.x1, info->OffDead2.y1); } if(info->HaveNonRect || info->HaveOffsRegions) { xf86DrvMsg(pScrn1->scrnIndex, X_INFO, "Mouse restriction for inaccessible areas is %s\n", info->MouseRestrictions ? "enabled" : "disabled"); } } } /* Proc */ int RADEONProcXineramaQueryVersion(ClientPtr client) { xPanoramiXQueryVersionReply rep; register int n; REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.majorVersion = RADEON_XINERAMA_MAJOR_VERSION; rep.minorVersion = RADEON_XINERAMA_MINOR_VERSION; if(client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swaps(&rep.majorVersion, n); swaps(&rep.minorVersion, n); } WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); return (client->noClientException); } int RADEONProcXineramaGetState(ClientPtr client) { REQUEST(xPanoramiXGetStateReq); WindowPtr pWin; xPanoramiXGetStateReply rep; register int n; REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); pWin = LookupWindow(stuff->window, client); if(!pWin) return BadWindow; rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.state = !RADEONnoPanoramiXExtension; if(client->swapped) { swaps (&rep.sequenceNumber, n); swapl (&rep.length, n); swaps (&rep.state, n); } WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); return client->noClientException; } int RADEONProcXineramaGetScreenCount(ClientPtr client) { REQUEST(xPanoramiXGetScreenCountReq); WindowPtr pWin; xPanoramiXGetScreenCountReply rep; register int n; REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); pWin = LookupWindow(stuff->window, client); if(!pWin) return BadWindow; rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.ScreenCount = RADEONXineramaNumScreens; if(client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swaps(&rep.ScreenCount, n); } WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); return client->noClientException; } int RADEONProcXineramaGetScreenSize(ClientPtr client) { REQUEST(xPanoramiXGetScreenSizeReq); WindowPtr pWin; xPanoramiXGetScreenSizeReply rep; register int n; REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); pWin = LookupWindow (stuff->window, client); if(!pWin) return BadWindow; rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.width = RADEONXineramadataPtr[stuff->screen].width; rep.height = RADEONXineramadataPtr[stuff->screen].height; if(client->swapped) { swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swaps(&rep.width, n); swaps(&rep.height, n); } WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); return client->noClientException; } int RADEONProcXineramaIsActive(ClientPtr client) { xXineramaIsActiveReply rep; REQUEST_SIZE_MATCH(xXineramaIsActiveReq); rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.state = !RADEONnoPanoramiXExtension; if(client->swapped) { register int n; swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swapl(&rep.state, n); } WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); return client->noClientException; } int RADEONProcXineramaQueryScreens(ClientPtr client) { xXineramaQueryScreensReply rep; REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); rep.type = X_Reply; rep.sequenceNumber = client->sequence; rep.number = (RADEONnoPanoramiXExtension) ? 0 : RADEONXineramaNumScreens; rep.length = rep.number * sz_XineramaScreenInfo >> 2; if(client->swapped) { register int n; swaps(&rep.sequenceNumber, n); swapl(&rep.length, n); swapl(&rep.number, n); } WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); if(!RADEONnoPanoramiXExtension) { xXineramaScreenInfo scratch; int i; for(i = 0; i < RADEONXineramaNumScreens; i++) { scratch.x_org = RADEONXineramadataPtr[i].x; scratch.y_org = RADEONXineramadataPtr[i].y; scratch.width = RADEONXineramadataPtr[i].width; scratch.height = RADEONXineramadataPtr[i].height; if(client->swapped) { register int n; swaps(&scratch.x_org, n); swaps(&scratch.y_org, n); swaps(&scratch.width, n); swaps(&scratch.height, n); } WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch); } } return client->noClientException; } static int RADEONProcXineramaDispatch(ClientPtr client) { REQUEST(xReq); switch (stuff->data) { case X_PanoramiXQueryVersion: return RADEONProcXineramaQueryVersion(client); case X_PanoramiXGetState: return RADEONProcXineramaGetState(client); case X_PanoramiXGetScreenCount: return RADEONProcXineramaGetScreenCount(client); case X_PanoramiXGetScreenSize: return RADEONProcXineramaGetScreenSize(client); case X_XineramaIsActive: return RADEONProcXineramaIsActive(client); case X_XineramaQueryScreens: return RADEONProcXineramaQueryScreens(client); } return BadRequest; } /* SProc */ static int RADEONSProcXineramaQueryVersion (ClientPtr client) { REQUEST(xPanoramiXQueryVersionReq); register int n; swaps(&stuff->length,n); REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); return RADEONProcXineramaQueryVersion(client); } static int RADEONSProcXineramaGetState(ClientPtr client) { REQUEST(xPanoramiXGetStateReq); register int n; swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); return RADEONProcXineramaGetState(client); } static int RADEONSProcXineramaGetScreenCount(ClientPtr client) { REQUEST(xPanoramiXGetScreenCountReq); register int n; swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); return RADEONProcXineramaGetScreenCount(client); } static int RADEONSProcXineramaGetScreenSize(ClientPtr client) { REQUEST(xPanoramiXGetScreenSizeReq); register int n; swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); return RADEONProcXineramaGetScreenSize(client); } static int RADEONSProcXineramaIsActive(ClientPtr client) { REQUEST(xXineramaIsActiveReq); register int n; swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xXineramaIsActiveReq); return RADEONProcXineramaIsActive(client); } static int RADEONSProcXineramaQueryScreens(ClientPtr client) { REQUEST(xXineramaQueryScreensReq); register int n; swaps (&stuff->length, n); REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); return RADEONProcXineramaQueryScreens(client); } int RADEONSProcXineramaDispatch(ClientPtr client) { REQUEST(xReq); switch (stuff->data) { case X_PanoramiXQueryVersion: return RADEONSProcXineramaQueryVersion(client); case X_PanoramiXGetState: return RADEONSProcXineramaGetState(client); case X_PanoramiXGetScreenCount: return RADEONSProcXineramaGetScreenCount(client); case X_PanoramiXGetScreenSize: return RADEONSProcXineramaGetScreenSize(client); case X_XineramaIsActive: return RADEONSProcXineramaIsActive(client); case X_XineramaQueryScreens: return RADEONSProcXineramaQueryScreens(client); } return BadRequest; } static void RADEONXineramaResetProc(ExtensionEntry* extEntry) { if(RADEONXineramadataPtr) { Xfree(RADEONXineramadataPtr); RADEONXineramadataPtr = NULL; } } void RADEONXineramaExtensionInit(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); Bool success = FALSE; if(!(RADEONXineramadataPtr)) { if(!info->MergedFB) { RADEONnoPanoramiXExtension = TRUE; info->MouseRestrictions = FALSE; return; } #ifdef PANORAMIX if(!noPanoramiXExtension) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xinerama active, not initializing Radeon Pseudo-Xinerama\n"); RADEONnoPanoramiXExtension = TRUE; info->MouseRestrictions = FALSE; return; } #endif if(RADEONnoPanoramiXExtension) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Radeon Pseudo-Xinerama disabled\n"); info->MouseRestrictions = FALSE; return; } if(info->CRT2Position == radeonClone) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Running MergedFB in Clone mode, Radeon Pseudo-Xinerama disabled\n"); RADEONnoPanoramiXExtension = TRUE; info->MouseRestrictions = FALSE; return; } if(!(info->AtLeastOneNonClone)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Only Clone modes defined, Radeon Pseudo-Xinerama disabled\n"); RADEONnoPanoramiXExtension = TRUE; info->MouseRestrictions = FALSE; return; } RADEONXineramaNumScreens = 2; while(RADEONXineramaGeneration != serverGeneration) { info->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, RADEONProcXineramaDispatch, RADEONSProcXineramaDispatch, RADEONXineramaResetProc, StandardMinorOpcode); if(!info->XineramaExtEntry) break; RADEONXineramaReqCode = (unsigned char)info->XineramaExtEntry->base; if(!(RADEONXineramadataPtr = (RADEONXineramaData *) xcalloc(RADEONXineramaNumScreens, sizeof(RADEONXineramaData)))) break; RADEONXineramaGeneration = serverGeneration; success = TRUE; } if(!success) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize Radeon Pseudo-Xinerama extension\n"); RADEONnoPanoramiXExtension = TRUE; info->MouseRestrictions = FALSE; return; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initialized Radeon Pseudo-Xinerama extension\n"); info->RADEONXineramaVX = 0; info->RADEONXineramaVY = 0; } RADEONUpdateXineramaScreenInfo(pScrn); } /* End of PseudoXinerama */ static Bool InRegion(int x, int y, region r) { return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); } void RADEONMergePointerMoved(int scrnIndex, int x, int y) { ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn1); ScrnInfoPtr pScrn2 = info->CRT2pScrn; region out, in1, in2, f2, f1; int deltax, deltay; int temp1, temp2; int old1x0, old1y0, old2x0, old2y0; int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0; int HVirt = pScrn1->virtualX; int VVirt = pScrn1->virtualY; int sigstate; Bool doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE; RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; if(info->DGAactive) { return; /* DGA: There is no cursor and no panning while DGA is active. */ /* If it were, we would need to do: */ /* HVirt = info->CurrentLayout.displayWidth; VVirt = info->CurrentLayout.displayHeight; BOUND(x, info->CurrentLayout.DGAViewportX, HVirt); BOUND(y, info->CurrentLayout.DGAViewportY, VVirt); */ } else { CRT1XOffs = info->CRT1XOffs; CRT1YOffs = info->CRT1YOffs; CRT2XOffs = info->CRT2XOffs; CRT2YOffs = info->CRT2YOffs; HaveNonRect = info->HaveNonRect; HaveOffsRegions = info->HaveOffsRegions; } /* Check if the pointer is inside our dead areas */ if((info->MouseRestrictions) && (srel != radeonClone) && !RADEONnoPanoramiXExtension) { if(HaveNonRect) { if(InRegion(x, y, info->NonRectDead)) { switch(srel) { case radeonLeftOf: case radeonRightOf: y = info->NonRectDead.y0 - 1; doit = TRUE; break; case radeonAbove: case radeonBelow: x = info->NonRectDead.x0 - 1; doit = TRUE; default: break; } } } if(HaveOffsRegions) { if(InRegion(x, y, info->OffDead1)) { switch(srel) { case radeonLeftOf: case radeonRightOf: y = info->OffDead1.y1; doit = TRUE; break; case radeonAbove: case radeonBelow: x = info->OffDead1.x1; doit = TRUE; default: break; } } else if(InRegion(x, y, info->OffDead2)) { switch(srel) { case radeonLeftOf: case radeonRightOf: y = info->OffDead2.y0 - 1; doit = TRUE; break; case radeonAbove: case radeonBelow: x = info->OffDead2.x0 - 1; doit = TRUE; default: break; } } } if(doit) { UpdateCurrentTime(); sigstate = xf86BlockSIGIO(); miPointerAbsoluteCursor(x, y, currentTime.milliseconds); xf86UnblockSIGIO(sigstate); return; } } f1.x0 = old1x0 = info->CRT1frameX0; f1.x1 = info->CRT1frameX1; f1.y0 = old1y0 = info->CRT1frameY0; f1.y1 = info->CRT1frameY1; f2.x0 = old2x0 = pScrn2->frameX0; f2.x1 = pScrn2->frameX1; f2.y0 = old2y0 = pScrn2->frameY0; f2.y1 = pScrn2->frameY1; /* Define the outer region. Crossing this causes all frames to move */ out.x0 = pScrn1->frameX0; out.x1 = pScrn1->frameX1; out.y0 = pScrn1->frameY0; out.y1 = pScrn1->frameY1; /* * Define the inner sliding window. Being outsize both frames but * inside the outer clipping window will slide corresponding frame */ in1 = out; in2 = out; switch(srel) { case radeonLeftOf: in1.x0 = f1.x0; in2.x1 = f2.x1; break; case radeonRightOf: in1.x1 = f1.x1; in2.x0 = f2.x0; break; case radeonBelow: in1.y1 = f1.y1; in2.y0 = f2.y0; break; case radeonAbove: in1.y0 = f1.y0; in2.y1 = f2.y1; break; case radeonClone: break; } deltay = 0; deltax = 0; if(InRegion(x, y, out)) { /* inside outer region */ /* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n", x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { REBOUND(f1.x0, f1.x1, x); REBOUND(f1.y0, f1.y1, y); deltax = 1; /* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n", x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ } if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { REBOUND(f2.x0, f2.x1, x); REBOUND(f2.y0, f2.y1, y); deltax = 1; } } else { /* outside outer region */ /* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n", x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n", out.x0, out.x1, out.y0, out.y1); */ if(out.x0 > x) { deltax = x - out.x0; } if(out.x1 < x) { deltax = x - out.x1; } if(deltax) { pScrn1->frameX0 += deltax; pScrn1->frameX1 += deltax; f1.x0 += deltax; f1.x1 += deltax; f2.x0 += deltax; f2.x1 += deltax; } if(out.y0 > y) { deltay = y - out.y0; } if(out.y1 < y) { deltay = y - out.y1; } if(deltay) { pScrn1->frameY0 += deltay; pScrn1->frameY1 += deltay; f1.y0 += deltay; f1.y1 += deltay; f2.y0 += deltay; f2.y1 += deltay; } switch(srel) { case radeonLeftOf: if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } break; case radeonRightOf: if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } break; case radeonBelow: if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } break; case radeonAbove: if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } break; case radeonClone: break; } } if(deltax || deltay) { info->CRT1frameX0 = f1.x0; info->CRT1frameY0 = f1.y0; pScrn2->frameX0 = f2.x0; pScrn2->frameY0 = f2.y0; switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { case radeonLeftOf: case radeonRightOf: if(info->CRT1YOffs || info->CRT2YOffs || HaveNonRect) { if(info->CRT1frameY0 != old1y0) { if(info->CRT1frameY0 < info->CRT1YOffs) info->CRT1frameY0 = info->CRT1YOffs; temp1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay; /*temp2 = pScrn1->virtualY - info->CRT2YOffs;*/ temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + info->MBXNR1YMAX)); if(temp1 > temp2) info->CRT1frameY0 -= (temp1 - temp2); } if(pScrn2->frameY0 != old2y0) { if(pScrn2->frameY0 < info->CRT2YOffs) pScrn2->frameY0 = info->CRT2YOffs; temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay; /*temp2 = pScrn1->virtualY - info->CRT1YOffs;*/ temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + info->MBXNR2YMAX)); if(temp1 > temp2) pScrn2->frameY0 -= (temp1 - temp2); } } break; case radeonBelow: case radeonAbove: if(info->CRT1XOffs || info->CRT2XOffs || HaveNonRect) { if(info->CRT1frameX0 != old1x0) { if(info->CRT1frameX0 < info->CRT1XOffs) info->CRT1frameX0 = info->CRT1XOffs; temp1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay; /*temp2 = pScrn1->virtualX - info->CRT2XOffs;*/ temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + info->MBXNR1XMAX)); if(temp1 > temp2) info->CRT1frameX0 -= (temp1 - temp2); } if(pScrn2->frameX0 != old2x0) { if(pScrn2->frameX0 < info->CRT2XOffs) pScrn2->frameX0 = info->CRT2XOffs; temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay; /*temp2 = pScrn1->virtualX - info->CRT1XOffs;*/ temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + info->MBXNR2XMAX)); if(temp1 > temp2) pScrn2->frameX0 -= (temp1 - temp2); } } break; case radeonClone: break; } info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; #if 0 pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; #endif RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); } } static void RADEONAdjustFrameMergedHelper(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn1); ScrnInfoPtr pScrn2 = info->CRT2pScrn; int VTotal = info->CurrentLayout.mode->VDisplay; int HTotal = info->CurrentLayout.mode->HDisplay; int VMax = VTotal; int HMax = HTotal; int HVirt = pScrn1->virtualX; int VVirt = pScrn1->virtualY; int x1 = x, x2 = x; int y1 = y, y2 = y; int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0; int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536; if(info->DGAactive) { HVirt = info->CurrentLayout.displayWidth; VVirt = info->CurrentLayout.displayHeight; } else { CRT1XOffs = info->CRT1XOffs; CRT1YOffs = info->CRT1YOffs; CRT2XOffs = info->CRT2XOffs; CRT2YOffs = info->CRT2YOffs; MBXNR1XMAX = info->MBXNR1XMAX; MBXNR1YMAX = info->MBXNR1YMAX; MBXNR2XMAX = info->MBXNR2XMAX; MBXNR2YMAX = info->MBXNR2YMAX; } BOUND(x, 0, pScrn1->virtualX - HTotal); BOUND(y, 0, pScrn1->virtualY - VTotal); if(SDMPTR(pScrn1)->CRT2Position != radeonClone) { #if 0 BOUND(x1, info->CRT1XOffs, pScrn1->virtualX - HTotal - info->CRT2XOffs); BOUND(y1, info->CRT1YOffs, pScrn1->virtualY - VTotal - info->CRT2YOffs); BOUND(x2, info->CRT2XOffs, pScrn1->virtualX - HTotal - info->CRT1XOffs); BOUND(y2, info->CRT2YOffs, pScrn1->virtualY - VTotal - info->CRT1YOffs); #endif BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs); BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs); BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs); BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs); } switch(SDMPTR(pScrn1)->CRT2Position) { case radeonLeftOf: pScrn2->frameX0 = x2; /*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/ BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay); info->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay; /*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/ BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay); break; case radeonRightOf: info->CRT1frameX0 = x1; /*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/ BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay); pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay; /*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/ BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay); break; case radeonAbove: /*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/ BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay); pScrn2->frameY0 = y2; /*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/ BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay); info->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay; break; case radeonBelow: /*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/ BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay); info->CRT1frameY0 = y1; /*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/ BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay); pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay; break; case radeonClone: BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); break; } BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay); BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay); BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay); BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay); pScrn1->frameX0 = x; pScrn1->frameY0 = y; info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; if(SDMPTR(pScrn1)->CRT2Position != radeonClone) { pScrn1->frameX1 += CRT1XOffs + CRT2XOffs; pScrn1->frameY1 += CRT1YOffs + CRT2YOffs; } /* RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); */ } void RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn1); ScrnInfoPtr pScrn2 = info->CRT2pScrn; RADEONAdjustFrameMergedHelper(scrnIndex, x, y, flags); RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); } void RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel) { RADEONInfoPtr info = RADEONPTR(pScrn1); MessageType from = X_DEFAULT; xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC); xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC); int ddcWidthmm = 0, ddcHeightmm = 0; const char *dsstr = "MergedFB: Display dimensions: (%d, %d) mm\n"; /* This sets the DPI for MergedFB mode. The problem is that * this can never be exact, because the output devices may * have different dimensions. This function tries to compromise * through a few assumptions, and it just calculates an average DPI * value for both monitors. */ /* Given DisplaySize should regard BOTH monitors */ pScrn1->widthmm = pScrn1->monitor->widthmm; pScrn1->heightmm = pScrn1->monitor->heightmm; /* Get DDC display size; if only either CRT1 or CRT2 provided these, * assume equal dimensions for both, otherwise add dimensions */ if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) && (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) { ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10; ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10; switch(srel) { case radeonLeftOf: case radeonRightOf: ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10; break; case radeonAbove: case radeonBelow: ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10; default: break; } } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) { ddcWidthmm = DDC1->features.hsize * 10; ddcHeightmm = DDC1->features.vsize * 10; switch(srel) { case radeonLeftOf: case radeonRightOf: ddcWidthmm *= 2; break; case radeonAbove: case radeonBelow: ddcHeightmm *= 2; default: break; } } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) { ddcWidthmm = DDC2->features.hsize * 10; ddcHeightmm = DDC2->features.vsize * 10; switch(srel) { case radeonLeftOf: case radeonRightOf: ddcWidthmm *= 2; break; case radeonAbove: case radeonBelow: ddcHeightmm *= 2; default: break; } } if(monitorResolution > 0) { /* Set command line given values (overrules given options) */ pScrn1->xDpi = monitorResolution; pScrn1->yDpi = monitorResolution; from = X_CMDLINE; } else if(info->MergedFBXDPI) { /* Set option-wise given values (overrule DisplaySize) */ pScrn1->xDpi = info->MergedFBXDPI; pScrn1->yDpi = info->MergedFBYDPI; from = X_CONFIG; } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) { /* Set values calculated from given DisplaySize */ from = X_CONFIG; if(pScrn1->widthmm > 0) { pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); } if(pScrn1->heightmm > 0) { pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); } xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm); } else if(ddcWidthmm && ddcHeightmm) { /* Set values from DDC-provided display size */ from = X_PROBED; xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm ); pScrn1->widthmm = ddcWidthmm; pScrn1->heightmm = ddcHeightmm; if(pScrn1->widthmm > 0) { pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); } if(pScrn1->heightmm > 0) { pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); } } else { pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI; } /* Sanity check */ if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0) pScrn1->yDpi = pScrn1->xDpi; if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0) pScrn1->xDpi = pScrn1->yDpi; pScrn2->xDpi = pScrn1->xDpi; pScrn2->yDpi = pScrn1->yDpi; xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n", pScrn1->xDpi, pScrn1->yDpi); } /* radeon cursor helpers */ static void RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y) { RADEONInfoPtr info = RADEONPTR(pScrn1); unsigned char *RADEONMMIO = info->MMIO; RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; ScrnInfoPtr pScrn2 = info->CRT2pScrn; if (srel == radeonClone) { /* show cursor 2 */ OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, ~RADEON_CRTC2_CUR_EN); /* show cursor 1 */ OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, ~RADEON_CRTC_CUR_EN); } else { if (((x >= pScrn1->frameX0) && (x <= pScrn1->frameX1)) && ((y >= pScrn1->frameY0) && (y <= pScrn1->frameY1))) { /* hide cursor 2 */ OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); /* show cursor 1 */ OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, ~RADEON_CRTC_CUR_EN); } if (((x >= pScrn2->frameX0) && (x <= pScrn2->frameX1)) && ((y >= pScrn2->frameY0) && (y <= pScrn2->frameY1))) { /* hide cursor 1 */ OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); /* show cursor 2 */ OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, ~RADEON_CRTC2_CUR_EN); } } } void RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; xf86CursorInfoPtr cursor = info->cursor; int xorigin = 0; int yorigin = 0; int stride = 256; ScrnInfoPtr pScrn2 = info->CRT2pScrn; DisplayModePtr mode1 = CDMPTR->CRT1; DisplayModePtr mode2 = CDMPTR->CRT2; int x1, y1, x2, y2; int total_y1 = pScrn->frameY1 - pScrn->frameY0; int total_y2 = pScrn2->frameY1 - pScrn2->frameY0; if (x < 0) xorigin = -x+1; if (y < 0) yorigin = -y+1; /* if (y > total_y) y = total_y; */ if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; x += pScrn->frameX0; y += pScrn->frameY0; x1 = x - info->CRT1frameX0; y1 = y - info->CRT1frameY0; x2 = x - pScrn2->frameX0; y2 = y - pScrn2->frameY0; if (y1 > total_y1) y1 = total_y1; if (y2 > total_y2) y2 = total_y2; if(mode1->Flags & V_INTERLACE) y1 /= 2; else if(mode1->Flags & V_DBLSCAN) y1 *= 2; if(mode2->Flags & V_INTERLACE) y2 /= 2; else if(mode2->Flags & V_DBLSCAN) y2 *= 2; if (x < 0) x = 0; if (y < 0) y = 0; RADEONChooseCursorCRTC(pScrn, x, y); /* cursor1 */ OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK | (xorigin << 16) | yorigin)); OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK | ((xorigin ? 0 : x1) << 16) | (yorigin ? 0 : y1))); OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride); /* cursor2 */ OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK | (xorigin << 16) | yorigin)); OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK | ((xorigin ? 0 : x2) << 16) | (yorigin ? 0 : y2))); OUTREG(RADEON_CUR2_OFFSET, info->cursor_start + yorigin * stride); } /* radeon Xv helpers */ /* choose the crtc for the overlay for mergedfb based on the location of the output window and the orientation of the crtcs */ void RADEONChooseOverlayCRTC( ScrnInfoPtr pScrn, BoxPtr dstBox ) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; if (srel == radeonLeftOf) { if (dstBox->x1 >= info->CRT2pScrn->frameX1) info->OverlayOnCRTC2 = FALSE; else info->OverlayOnCRTC2 = TRUE; } if (srel == radeonRightOf) { if (dstBox->x2 <= info->CRT2pScrn->frameX0) info->OverlayOnCRTC2 = FALSE; else info->OverlayOnCRTC2 = TRUE; } if (srel == radeonAbove) { if (dstBox->y1 >= info->CRT2pScrn->frameY1) info->OverlayOnCRTC2 = FALSE; else info->OverlayOnCRTC2 = TRUE; } if (srel == radeonBelow) { if (dstBox->y2 <= info->CRT2pScrn->frameY0) info->OverlayOnCRTC2 = FALSE; else info->OverlayOnCRTC2 = TRUE; } }