summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <anholt@FreeBSD.org>2006-06-28 13:10:02 +0200
committerEric Anholt <anholt@FreeBSD.org>2006-06-28 13:10:02 +0200
commit367f69f8e7710e53dcd286f1b62506a3276e80f9 (patch)
tree770e165708f0ba56cc9d8a0d205cb13538ea23bc
parent9fbd3d8f4befb75ed6f6bd9a9ffe0175626e8785 (diff)
Replace xf86ValidateModes usage with a set of custom validators and pruning.
This moves us to maintaining MonPtrs per pipe instead of using the EDID structure "xf86MonPtr", which is closer to what we want to be looking at when doing validation. The new validation isn't enough yet -- particularly, we aren't importing and validating the custom modelines to the pipes when applicable, but this will be easier than (for example) trying to make flat panel modes pass xf86ValidateModes through various gross hacks. Hotplug turn-on/off also happens at SwitchMode time now, instead of at randr probe time.
-rw-r--r--src/i830.h7
-rw-r--r--src/i830_display.c45
-rw-r--r--src/i830_modes.c430
-rw-r--r--src/i830_xf86Modes.c120
-rw-r--r--src/i830_xf86Modes.h20
5 files changed, 459 insertions, 163 deletions
diff --git a/src/i830.h b/src/i830.h
index 9bd02275..f1b97745 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -227,6 +227,10 @@ typedef struct _I830Rec {
int fixedPipe;
DisplayModePtr currentMode;
+ /* Mode saved during randr reprobe, which will need to be freed at the point
+ * of the next SwitchMode, when we lose this last reference to it.
+ */
+ DisplayModePtr savedCurrentMode;
Bool Clone;
int CloneRefresh;
@@ -401,8 +405,7 @@ typedef struct _I830Rec {
int availablePipes;
/* [0] is display plane A, [1] is display plane B. */
int planeEnabled[MAX_DISPLAY_PIPES];
- xf86MonPtr pipeMon[MAX_DISPLAY_PIPES];
- DisplayModePtr pipeModes[MAX_DISPLAY_PIPES];
+ MonPtr pipeMon[MAX_DISPLAY_PIPES];
DisplayModeRec pipeCurMode[MAX_DISPLAY_PIPES];
/* Driver phase/state information */
diff --git a/src/i830_display.c b/src/i830_display.c
index 8080c55c..24103cb7 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -268,11 +268,12 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
/* If we've got a list of modes probed for the device, find the best match
* in there to the requested mode.
*/
- if (pI830->pipeModes[pipe] != NULL) {
+ if (pI830->pipeMon[pipe] != NULL) {
DisplayModePtr pBest = NULL, pScan;
assert(pScan->VRefresh != 0.0);
- for (pScan = pI830->pipeModes[pipe]; pScan != NULL; pScan = pScan->next)
+ for (pScan = pI830->pipeMon[pipe]->Modes; pScan != NULL;
+ pScan = pScan->next)
{
/* Reject if it's larger than the desired mode. */
if (pScan->HDisplay > pMode->HDisplay ||
@@ -284,9 +285,20 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
pBest = pScan;
continue;
}
- /* Find if it's closer than the current best option */
- if ((pScan->HDisplay >= pBest->HDisplay &&
- pScan->HDisplay >= pBest->HDisplay) ||
+ /* Find if it's closer to the right size than the current best
+ * option.
+ */
+ if (pScan->HDisplay >= pBest->HDisplay &&
+ pScan->VDisplay >= pBest->VDisplay)
+ {
+ pBest = pScan;
+ continue;
+ }
+ /* Find if it's still closer to the right refresh than the current
+ * best resolution.
+ */
+ if (pScan->HDisplay == pBest->HDisplay &&
+ pScan->VDisplay == pBest->VDisplay &&
(fabs(pScan->VRefresh - pMode->VRefresh) <
fabs(pBest->VRefresh - pMode->VRefresh)))
{
@@ -801,6 +813,29 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
(int)(pMode->HDisplay * pMode->VDisplay *
pMode->VRefresh / 1000000));
+ if (pI830->savedCurrentMode) {
+ /* We're done with the currentMode that the last randr probe had left
+ * behind, so free it.
+ */
+ xfree(pI830->savedCurrentMode->name);
+ xfree(pI830->savedCurrentMode);
+
+ /* If we might have enabled/disabled some pipes, we need to reset
+ * cloning mode support.
+ */
+ if ((pI830->operatingDevices & 0x00ff) &&
+ (pI830->operatingDevices & 0xff00))
+ {
+ pI830->Clone = TRUE;
+ } else {
+ pI830->Clone = FALSE;
+ }
+
+ /* If HW cursor currently showing, reset cursor state */
+ if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn)
+ pI830->CursorInfoRec->ShowCursor(pScrn);
+ }
+
i830DisableUnusedFunctions(pScrn);
planeA = INREG(DSPACNTR);
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 893ef101..74333441 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -47,6 +47,7 @@
#include "xf86.h"
#include "i830.h"
+#include "i830_display.h"
#include "i830_xf86Modes.h"
#include <randrstr.h>
@@ -247,7 +248,7 @@ I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i)
}
static DisplayModePtr
-I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc)
+i830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc)
{
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
@@ -487,9 +488,11 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName)
/* If the user hasn't specified modes, add the native mode */
if (!count) {
- first = last = i830FPNativeMode(pScrn);
- if (first)
+ new = i830FPNativeMode(pScrn);
+ if (first) {
+ I830xf86SortModes(new, &first, &last);
count = 1;
+ }
}
/* add in all default vesa modes smaller than panel size, used for randr */
@@ -507,14 +510,7 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName)
else
new->type |= M_T_DEFAULT;
- new->next = NULL;
- new->prev = last;
-
- if (last)
- last->next = new;
- last = new;
- if (!first)
- first = new;
+ I830xf86SortModes(new, &first, &last);
count++;
}
@@ -546,9 +542,6 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
for (addMode = addModes; addMode != NULL; addMode = addMode->next) {
DisplayModePtr pNew;
- /* XXX: Do we need to check if modeList already contains the same mode?
- */
-
pNew = I830DuplicateMode(addMode);
#if 0
/* If the user didn't specify any modes, mark all modes as M_T_USERDEF
@@ -580,6 +573,102 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
return count;
}
+static DisplayModePtr
+i830GetModeListTail(DisplayModePtr pModeList)
+{
+ DisplayModePtr last;
+
+ if (pModeList == NULL)
+ return NULL;
+
+ for (last = pModeList; last->next != NULL; last = last->next)
+ ;
+
+ return last;
+}
+
+static MonPtr
+i830GetDDCMonitor(ScrnInfoPtr pScrn, I2CBusPtr pDDCBus)
+{
+ xf86MonPtr ddc;
+ MonPtr mon;
+ int i;
+
+ ddc = xf86DoEDID_DDC2(pScrn->scrnIndex, pDDCBus);
+
+ if (ddc == NULL)
+ return NULL;
+
+ mon = xnfcalloc(1, sizeof(*mon));
+ mon->Modes = i830GetDDCModes(pScrn, ddc);
+ mon->Last = i830GetModeListTail(mon->Modes);
+ mon->DDC = ddc;
+
+ for (i = 0; i < DET_TIMINGS; i++) {
+ struct detailed_monitor_section *det_mon = &ddc->det_mon[i];
+
+ switch (ddc->det_mon[i].type) {
+ case DS_RANGES:
+ mon->hsync[mon->nHsync].lo = det_mon->section.ranges.min_h;
+ mon->hsync[mon->nHsync].hi = det_mon->section.ranges.max_h;
+ mon->nHsync++;
+ mon->vrefresh[mon->nVrefresh].lo = det_mon->section.ranges.min_v;
+ mon->vrefresh[mon->nVrefresh].hi = det_mon->section.ranges.max_v;
+ mon->nVrefresh++;
+ break;
+ default:
+ /* We probably don't care about trying to contruct ranges around
+ * modes specified by DDC.
+ */
+ break;
+ }
+ }
+
+ return mon;
+}
+
+static MonPtr
+i830GetLVDSMonitor(ScrnInfoPtr pScrn)
+{
+ MonPtr mon;
+
+ mon = xnfcalloc(1, sizeof(*mon));
+ mon->Modes = i830GetLVDSModes(pScrn, pScrn->display->modes);
+ mon->Last = i830GetModeListTail(mon->Modes);
+
+ return mon;
+}
+
+static MonPtr
+i830GetConfiguredMonitor(ScrnInfoPtr pScrn)
+{
+ MonPtr mon;
+
+ mon = xnfcalloc(1, sizeof(*mon));
+ memcpy(mon, pScrn->monitor, sizeof(*mon));
+
+ if (pScrn->monitor->id != NULL)
+ mon->id = xnfstrdup(pScrn->monitor->id);
+ if (pScrn->monitor->vendor != NULL)
+ mon->vendor = xnfstrdup(pScrn->monitor->vendor);
+ if (pScrn->monitor->model != NULL)
+ mon->model = xnfstrdup(pScrn->monitor->model);
+
+ return mon;
+}
+
+static void
+i830FreeMonitor(ScrnInfoPtr pScrn, MonPtr mon)
+{
+ while (mon->Modes != NULL)
+ xf86DeleteMode(&mon->Modes, mon->Modes);
+ xfree(mon->id);
+ xfree(mon->vendor);
+ xfree(mon->model);
+ xfree(mon->DDC);
+ xfree(mon);
+}
+
/**
* Performs probing of modes available on the output connected to the given
* pipe.
@@ -596,11 +685,7 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe)
int i;
int outputs;
DisplayModePtr pMode;
- Bool had_modes;
-
- had_modes = (pI830->pipeModes[pipe] != NULL);
- while (pI830->pipeModes[pipe] != NULL)
- xf86DeleteMode(&pI830->pipeModes[pipe], pI830->pipeModes[pipe]);
+ MonPtr old_mon = pI830->pipeMon[pipe];
if (pipe == 0)
outputs = pI830->operatingDevices & 0xff;
@@ -631,45 +716,87 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe)
return;
if (outputs & PIPE_LFP) {
- pI830->pipeMon[pipe] = NULL; /* XXX */
- pI830->pipeModes[pipe] = i830GetLVDSModes(pScrn,
- pScrn->display->modes);
+ pI830->pipeMon[pipe] = i830GetLVDSMonitor(pScrn);
} else if (pI830->output[output_index].pDDCBus != NULL) {
- /* XXX: Free the mon */
- pI830->pipeMon[pipe] = xf86DoEDID_DDC2(pScrn->scrnIndex,
- pI830->output[output_index].pDDCBus);
- pI830->pipeModes[pipe] = I830GetDDCModes(pScrn,
- pI830->pipeMon[pipe]);
-
- for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next)
- {
- I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
- }
- if (had_modes && pI830->pipeModes[pipe] == NULL) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Failed to DDC pipe %d, disabling output\n", pipe);
- if (pipe == 0)
- pI830->operatingDevices &= ~0x00ff;
- else
- pI830->operatingDevices &= ~0xff00;
+ pI830->pipeMon[pipe] =
+ i830GetDDCMonitor(pScrn, pI830->output[output_index].pDDCBus);
+ }
+ /* If DDC didn't work (or the flat panel equivalent), then see if we can
+ * detect if a monitor is at least plugged in. If we can't tell that one
+ * is plugged in, then assume that it is.
+ */
+ if (pI830->pipeMon[pipe] == NULL) {
+ switch (pI830->output[output_index].type) {
+ case I830_OUTPUT_SDVO:
+ if (I830DetectSDVODisplays(pScrn, output_index))
+ pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
+ break;
+ case I830_OUTPUT_ANALOG:
+ /* Do a disruptive detect if necessary, since we want to be sure we
+ * know if a monitor is attached, and this detect process should be
+ * infrequent.
+ */
+ if (i830DetectCRT(pScrn, TRUE))
+ pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
+ break;
+ default:
+ pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
+ break;
}
- } else {
- ErrorF("don't know how to get modes for this device.\n");
}
- /* Set the vertical refresh, which is used by the choose-best-mode-per-pipe
- * code later on.
- */
#ifdef DEBUG_REPROBE
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing probed modes for pipe %d\n",
pipe);
#endif
- for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next) {
- pMode->VRefresh = I830ModeVRefresh(pMode);
+ if (pI830->pipeMon[pipe] != NULL) {
+ int minclock, maxclock;
+
+ switch (pI830->output[output_index].type) {
+ case I830_OUTPUT_SDVO:
+ minclock = 25000;
+ maxclock = 165000;
+ case I830_OUTPUT_LVDS:
+ case I830_OUTPUT_ANALOG:
+ default:
+ minclock = 25000;
+ maxclock = 400000;
+ }
+
+ i830xf86ValidateModesFlags(pScrn, pI830->pipeMon[pipe]->Modes,
+ V_INTERLACE);
+ i830xf86ValidateModesClocks(pScrn, pI830->pipeMon[pipe]->Modes,
+ &minclock, &maxclock, 1);
+
+ i830xf86PruneInvalidModes(pScrn, &pI830->pipeMon[pipe]->Modes, TRUE);
+
+ for (pMode = pI830->pipeMon[pipe]->Modes; pMode != NULL;
+ pMode = pMode->next)
+ {
+ /* The code to choose the best mode per pipe later on will require
+ * VRefresh to be set.
+ */
+
+ pMode->VRefresh = I830ModeVRefresh(pMode);
+ I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
#ifdef DEBUG_REPROBE
- PrintModeline(pScrn->scrnIndex, pMode);
+ PrintModeline(pScrn->scrnIndex, pMode);
#endif
+ }
+ }
+
+ if (old_mon != NULL && pI830->pipeMon[pipe] == NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Failed to probe output on pipe %d, disabling output at next "
+ "mode switch\n", pipe);
+ if (pipe == 0)
+ pI830->operatingDevices &= ~0x00ff;
+ else
+ pI830->operatingDevices &= ~0xff00;
}
+
+ if (old_mon != NULL)
+ i830FreeMonitor(pScrn, old_mon);
}
/**
@@ -720,10 +847,8 @@ int
I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
{
I830Ptr pI830 = I830PTR(pScrn);
- ClockRangePtr clockRanges;
- int n, pipe;
- DisplayModePtr saved_mode, availModes = NULL;
- int saved_virtualX = 0, saved_virtualY = 0, saved_displayWidth = 0;
+ int pipe;
+ DisplayModePtr saved_mode, last;
Bool pipes_reconfigured = FALSE;
int originalVirtualX, originalVirtualY;
@@ -738,7 +863,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
if ((pI830->operatingDevices & 0xff) == PIPE_NONE) {
pI830->operatingDevices |= PIPE_CRT;
I830ReprobePipeModeList(pScrn, 0);
- if (pI830->pipeModes[0] == NULL) {
+ if (pI830->pipeMon[0] == NULL) {
/* No new output found. */
pI830->operatingDevices &= ~PIPE_CRT;
} else {
@@ -751,7 +876,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
} else if (((pI830->operatingDevices >> 8) & 0xff) == PIPE_NONE) {
pI830->operatingDevices |= PIPE_CRT << 8;
I830ReprobePipeModeList(pScrn, 1);
- if (pI830->pipeModes[1] == NULL) {
+ if (pI830->pipeMon[1] == NULL) {
/* No new output found. */
pI830->operatingDevices &= ~(PIPE_CRT << 8);
} else {
@@ -764,30 +889,59 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
}
}
- /* Start by injecting the XFree86 default modes and user-configured
- * modelines. XXX: This actually isn't of use if we've got any DDC, as DDC
- * currently has higher priority than the validated modelist. We need to
- * deal with that.
- */
- I830InjectProbedModes(pScrn, &availModes, pScrn->monitor->Modes);
- if (pI830->pipeModes[0] != NULL) {
- I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[0]);
+ if ((pI830->pipeMon[0] == NULL || pI830->pipeMon[0]->Modes == NULL) &&
+ (pI830->pipeMon[1] == NULL || pI830->pipeMon[1]->Modes == NULL))
+ {
+ FatalError("No modes found on either pipe\n");
}
- if (pI830->pipeModes[1] != NULL) {
- I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[1]);
+
+ if (first_time) {
+ int maxX = -1, maxY = -1;
+
+ /* Set up a virtual size that will cover any clone mode we'd want to set
+ * for either of the two pipes.
+ */
+ for (pipe = 0; pipe < MAX_DISPLAY_PIPES; pipe++) {
+ MonPtr mon = pI830->pipeMon[pipe];
+ DisplayModePtr mode;
+
+ if (mon == NULL)
+ continue;
+
+ for (mode = mon->Modes; mode != NULL; mode = mode->next) {
+ if (mode->HDisplay > maxX)
+ maxX = mode->HDisplay;
+ if (mode->VDisplay > maxY)
+ maxY = mode->VDisplay;
+ }
+ }
+ pScrn->virtualX = maxX;
+ pScrn->virtualY = maxY;
+ pScrn->displayWidth = (maxX + 63) & ~63;
}
- /*
- * Set up the ClockRanges, which describe what clock ranges are available,
- * and what sort of modes they can be used for.
+ I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
+
+ /* Disable modes that are larger than the virtual size we decided on
+ * initially.
*/
- clockRanges = xnfcalloc(sizeof(ClockRange), 1);
- clockRanges->next = NULL;
- clockRanges->minClock = 25000;
- clockRanges->maxClock = pI830->MaxClock;
- clockRanges->clockIndex = -1; /* programmable */
- clockRanges->interlaceAllowed = TRUE; /* XXX check this */
- clockRanges->doubleScanAllowed = FALSE; /* XXX check this */
+ if (!first_time) {
+ for (pipe = 0; pipe < MAX_DISPLAY_PIPES; pipe++) {
+ MonPtr mon = pI830->pipeMon[pipe];
+ DisplayModePtr mode;
+
+ if (mon == NULL)
+ continue;
+
+ for (mode = mon->Modes; mode != NULL; mode = mode->next)
+ {
+ if (mode->HDisplay > originalVirtualX)
+ mode->status = MODE_VIRTUAL_X;
+ if (mode->VDisplay > originalVirtualY)
+ mode->status = MODE_VIRTUAL_Y;
+ }
+ }
+ }
/* Remove the current mode from the modelist if we're re-validating, so we
* can find a new mode to map ourselves to afterwards.
@@ -797,53 +951,54 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
I830xf86DeleteModeFromList(&pScrn->modes, saved_mode);
}
- if (!first_time) {
- saved_virtualX = pScrn->virtualX;
- saved_virtualY = pScrn->virtualY;
- saved_displayWidth = pScrn->displayWidth;
- }
-
- I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
+ /* Clear any existing modes from pScrn->modes */
+ while (pScrn->modes != NULL)
+ xf86DeleteMode(&pScrn->modes, pScrn->modes);
- /* Take the pScrn->monitor->Modes we've accumulated and validate them into
- * pScrn->modes.
- * XXX: Should set up a scrp->monitor->DDC covering the union of the
- * capabilities of our pipes.
+ /* Set pScrn->modes to the mode list for the an arbitrary head.
+ * pScrn->modes should only be used for XF86VidMode now, which we don't
+ * care about enough to make some sort of unioned list.
*/
- n = xf86ValidateModes(pScrn,
- availModes, /* availModes */
- pScrn->display->modes, /* modeNames */
- clockRanges, /* clockRanges */
- !first_time ? &pScrn->displayWidth : NULL, /* linePitches */
- 320, /* minPitch */
- MAX_DISPLAY_PITCH, /* maxPitch */
- 64 * pScrn->bitsPerPixel, /* pitchInc */
- 200, /* minHeight */
- MAX_DISPLAY_HEIGHT, /* maxHeight */
- originalVirtualX, /* virtualX maximum */
- originalVirtualY, /* virtualY maximum */
- pI830->FbMapSize, /* apertureSize */
- LOOKUP_BEST_REFRESH /* strategy */);
-
- /* availModes is of no more use as xf86ValidateModes has duplicated and
- * saved everything it needs.
+ if (pI830->pipeMon[1] != NULL) {
+ I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[1]->Modes);
+ } else {
+ I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[0]->Modes);
+ }
+ if (pScrn->modes == NULL) {
+ FatalError("No modes found\n");
+ }
+
+ /* Don't let pScrn->modes have modes larger than the max root window size.
+ * We don't really care about the monitors having it, particularly since we
+ * eventually want randr to be able to move to those sizes.
*/
- while (availModes != NULL)
- xf86DeleteMode(&availModes, availModes);
+ i830xf86ValidateModesSize(pScrn, pScrn->modes,
+ originalVirtualX, originalVirtualY,
+ pScrn->displayWidth);
- if (!first_time) {
- /* Restore things that may have been damaged by xf86ValidateModes. */
- pScrn->virtualX = saved_virtualX;
- pScrn->virtualY = saved_virtualY;
- pScrn->displayWidth = saved_displayWidth;
- }
+ /* Strip out anything bad that we threw out for virtualX. */
+ i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE);
- /* Need to do xf86CrtcForModes so any user-configured modes are valid for
- * non-LVDS.
+ /* For some reason, pScrn->modes is circular, unlike the other mode lists.
+ * How great is that?
*/
- xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
+ last = i830GetModeListTail(pScrn->modes);
+ last->next = pScrn->modes;
+ pScrn->modes->prev = last;
- xf86PruneDriverModes(pScrn);
+#if 0
+ /* XXX: do I need this any more? Maybe XF86VidMode uses it?
+ * Set up the ClockRanges, which describe what clock ranges are available,
+ * and what sort of modes they can be used for.
+ */
+ clockRanges = xnfcalloc(sizeof(ClockRange), 1);
+ clockRanges->next = NULL;
+ clockRanges->minClock = 25000;
+ clockRanges->maxClock = pI830->MaxClock;
+ clockRanges->clockIndex = -1; /* programmable */
+ clockRanges->interlaceAllowed = TRUE; /* XXX check this */
+ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */
+#endif
#if DEBUG_REPROBE
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Modes post revalidate\n");
@@ -858,49 +1013,12 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
} while (0);
#endif
- /* Try to find the closest equivalent of the previous mode pointer to switch
- * to.
- */
- if (saved_mode != NULL) {
- DisplayModePtr pBestMode = NULL, pMode;
-
- /* XXX: Is finding a matching x/y res enough? probably not. */
- for (pMode = pScrn->modes; ; pMode = pMode->next) {
- if (pMode->HDisplay == saved_mode->HDisplay &&
- pMode->VDisplay == saved_mode->VDisplay)
- {
- ErrorF("found matching mode %p\n", pMode);
- pBestMode = pMode;
- }
- if (pMode->next == pScrn->modes)
- break;
- }
-
- if (pBestMode != NULL)
- xf86SwitchMode(pScrn->pScreen, pBestMode);
- else
- FatalError("No suitable modes after re-probe\n");
-
- xfree(saved_mode->name);
- xfree(saved_mode);
- }
-
- /* If we've enabled/disabled some pipes, we need to reset cloning mode
- * support.
+ /* Save a pointer to the previous current mode. We can't reset
+ * pScrn->currentmode, because we rely on xf86SwitchMode's shortcut not
+ * happening so we can hot-enable devices at SwitchMode. We'll notice this
+ * case at SwitchMode and free the saved mode.
*/
- if (pipes_reconfigured) {
- if ((pI830->operatingDevices & 0x00ff) &&
- (pI830->operatingDevices & 0xff00))
- {
- pI830->Clone = TRUE;
- } else {
- pI830->Clone = FALSE;
- }
-
- /* If HW cursor currently showing, reset cursor state */
- if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn)
- pI830->CursorInfoRec->ShowCursor(pScrn);
- }
+ pI830->savedCurrentMode = saved_mode;
- return n;
+ return 1; /* XXX */
}
diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c
index 16a8cd83..6f620c81 100644
--- a/src/i830_xf86Modes.c
+++ b/src/i830_xf86Modes.c
@@ -238,6 +238,126 @@ PrintModeline(int scrnIndex,DisplayModePtr mode)
xfree(flags);
}
+/**
+ * Marks as bad any modes with unsupported flags.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ * \param flags flags supported by the driver.
+ *
+ * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough?
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int flags)
+{
+ DisplayModePtr mode;
+
+ for (mode = modeList; mode != NULL; mode = mode->next) {
+ if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE))
+ mode->status = MODE_NO_INTERLACE;
+ if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN))
+ mode->status = MODE_NO_DBLESCAN;
+ }
+}
+
+/**
+ * Marks as bad any modes extending beyond the given max X, Y, or pitch.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+i830xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int maxX, int maxY, int maxPitch)
+{
+ DisplayModePtr mode;
+
+ for (mode = modeList; mode != NULL; mode = mode->next) {
+ if (maxPitch > 0 && mode->HDisplay > maxPitch)
+ mode->status = MODE_BAD_WIDTH;
+
+ if (maxX > 0 && mode->HDisplay > maxX)
+ mode->status = MODE_VIRTUAL_X;
+
+ if (maxY > 0 && mode->VDisplay > maxY)
+ mode->status = MODE_VIRTUAL_Y;
+
+ if (mode->next == modeList)
+ break;
+ }
+}
+
+/**
+ * Marks as bad any modes extending beyond outside of the given clock ranges.
+ *
+ * \param modeList doubly-linked or circular list of modes.
+ * \param min pointer to minimums of clock ranges
+ * \param max pointer to maximums of clock ranges
+ * \param n_ranges number of ranges.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+i830xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int *min, int *max, int n_ranges)
+{
+ DisplayModePtr mode;
+ int i;
+
+ for (mode = modeList; mode != NULL; mode = mode->next) {
+ Bool good = FALSE;
+ for (i = 0; i < n_ranges; i++) {
+ if (mode->Clock >= min[i] && mode->Clock <= max[i]) {
+ good = TRUE;
+ break;
+ }
+ }
+ if (!good)
+ mode->status = MODE_CLOCK_RANGE;
+ }
+}
+
+/**
+ * Frees any modes from the list with a status other than MODE_OK.
+ *
+ * \param modeList pointer to a doubly-linked or circular list of modes.
+ * \param verbose determines whether the reason for mode invalidation is
+ * printed.
+ *
+ * This is not in xf86Modes.c, but would be part of the proposed new API.
+ */
+void
+i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+ Bool verbose)
+{
+ DisplayModePtr mode;
+
+ for (mode = *modeList; mode != NULL;) {
+ DisplayModePtr next = mode->next;
+
+ if (mode->status != MODE_OK) {
+ if (verbose) {
+ char *type = "";
+ if (mode->type & M_T_BUILTIN)
+ type = "built-in ";
+ else if (mode->type & M_T_DEFAULT)
+ type = "default ";
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Not using %smode \"%s\" (%s)\n", type, mode->name,
+ xf86ModeStatusToString(mode->status));
+ }
+ xf86DeleteMode(modeList, mode);
+ }
+
+ if (next == *modeList)
+ break;
+ mode = next;
+ }
+}
+
#define MODEPREFIX(name) NULL, NULL, name, MODE_OK, M_T_DEFAULT
#define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h
index ba7d8209..86e5b060 100644
--- a/src/i830_xf86Modes.h
+++ b/src/i830_xf86Modes.h
@@ -35,6 +35,26 @@ Bool
I830ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2);
void
+i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int flags);
+
+void
+i830xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int *min, int *max, int n_ranges);
+
+void
+i830xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int maxX, int maxY, int maxPitch);
+
+void
+i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+ Bool verbose);
+
+void
+i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+ int flags);
+
+void
PrintModeline(int scrnIndex,DisplayModePtr mode);
extern DisplayModeRec I830xf86DefaultModes[];