--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XORG_NV/sun-src/xf86-video-ati-6.5.8.0/src/radeon_mergedfb.c Thu Jun 22 17:09:23 2006 -0700
@@ -0,0 +1,2037 @@
+/* $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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * Authors:
+ * Alex Deucher <[email protected]>
+ * 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 <X11/extensions/panoramiXproto.h> /* 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;
+
+ /* This is needed for not generating negative refesh rates in xrandr with the
+ faked DotClock below
+ */
+ if (!(mode->VRefresh))
+ mode->VRefresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
+
+ /* 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;
+ char gotsep = 0;
+ 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 ' ':
+ 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%c%s\")\n", mode1->name, gotsep, modename);
+ mode1 = NULL;
+ gotsep = 0;
+ }
+ } 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 == ';') tmps++;
+ /* skip the next mode */
+ if(*tmps == '-' || *tmps == '+' || *tmps == ',') {
+ tmps++;
+ /* skip spaces */
+ while(*tmps == ' ' || *tmps == ';') tmps++;
+ /* skip modename */
+ while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') 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;
+ gotsep = 0;
+ }
+ }
+ gotdash = FALSE;
+ }
+ strmode = str + 1;
+ gotdash |= (*str == '-' || *str == '+' || *str == ',');
+ if (*str == '-' || *str == '+' || *str == ',')
+ gotsep = *str;
+
+ if(*str != 0) break;
+ /* Fall through otherwise */
+
+ default:
+ if(!gotdash && mode1) {
+ sr = srel;
+ if(gotsep == '+') 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;
+ }
+ gotsep = 0;
+ }
+ 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)));
+#ifdef USE_EXA
+ if (info->useEXA)
+ OUTREG(RADEON_CUR_OFFSET, info->cursor_offset + yorigin * stride);
+#endif /* USE_EXA */
+#ifdef USE_XAA
+ if (!info->useEXA)
+ OUTREG(RADEON_CUR_OFFSET, info->cursor_offset + yorigin * stride);
+#endif /* USE_XAA */
+ /* 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)));
+#ifdef USE_EXA
+ if (info->useEXA)
+ OUTREG(RADEON_CUR2_OFFSET, info->cursor_offset + yorigin * stride);
+#endif /* USE_EXA */
+#ifdef USE_XAA
+ if (!info->useEXA)
+ OUTREG(RADEON_CUR2_OFFSET, info->cursor_offset + yorigin * stride);
+#endif /* USE_XAA */
+}
+
+/* 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;
+ }
+}