xf86-video-intel: Branch 'modesetting' - 3 commits - src/i830_display.c src/i830.h src/i830_modes.c src/i830_xf86Modes.c src/i830_xf86Modes.h

Eric Anholt anholt at kemper.freedesktop.org
Wed Jun 28 18:24:06 EEST 2006


 src/i830.h           |    7 
 src/i830_display.c   |   45 +++-
 src/i830_modes.c     |  529 ++++++++++++++++++++++++++++++++-------------------
 src/i830_xf86Modes.c |  188 +++++++++++++++++-
 src/i830_xf86Modes.h |   29 ++
 5 files changed, 596 insertions(+), 202 deletions(-)

New commits:
diff-tree 48f27ac62128251640a9b1ca54f63376676b47eb (from ce5bd108c55d2378db072617c380514a39672603)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Jun 28 15:07:01 2006 +0200

    Replace i830InjectModes with i830DuplicateModes usage.
    
    The remaining functionality of DuplicateModes was OBE, and the name was bad.

diff --git a/src/i830_modes.c b/src/i830_modes.c
index 6b914bc..cb50523 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -587,56 +587,6 @@ i830DuplicateModes(ScrnInfoPtr pScrn, Di
     return first;
 }
 
-/**
- * Duplicates and appends a list of modes to a mode list.
- *
- * Take the doubly-linked list of modes we've probed for the device, and injects
- * it into the doubly-linked modeList.  We don't need to filter, because the
- * eventual call to xf86ValidateModes will do this for us.  I think.
- */
-static int
-i830InjectModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
-		DisplayModePtr addModes)
-{
-    DisplayModePtr  last = *modeList;
-    DisplayModePtr  first = *modeList;
-    DisplayModePtr  addMode;
-    int count = 0;
-
-    for (addMode = addModes; addMode != NULL; addMode = addMode->next) {
-	DisplayModePtr pNew;
-
-	pNew = I830DuplicateMode(addMode);
-#if 0
-	/* If the user didn't specify any modes, mark all modes as M_T_USERDEF
-	 * so that we can cycle through them, etc.  XXX: really need to?
-	 */
-	if (pScrn->display->modes[0] == NULL) {
-	    pNew->type |= M_T_USERDEF;
-	}
-#endif
-
-	/* Insert pNew into modeList */
-	if (last) {
-	    last->next = pNew;
-	    pNew->prev = last;
-	} else {
-	    first = pNew;
-	    pNew->prev = NULL;
-	}
-	pNew->next = NULL;
-	last = pNew;
-
-	count++;
-    }
-    *modeList = first;
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-	       "Injected %d modes detected from the monitor\n", count);
-
-    return count;
-}
-
 static MonPtr
 i830GetDDCMonitor(ScrnInfoPtr pScrn, I2CBusPtr pDDCBus)
 {
@@ -1037,9 +987,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
      * care about enough to make some sort of unioned list.
      */
     if (pI830->pipeMon[1] != NULL) {
-	i830InjectModes(pScrn, &pScrn->modes, pI830->pipeMon[1]->Modes);
+	pScrn->modes = i830DuplicateModes(pScrn, pI830->pipeMon[1]->Modes);
     } else {
-	i830InjectModes(pScrn, &pScrn->modes, pI830->pipeMon[0]->Modes);
+	pScrn->modes = i830DuplicateModes(pScrn, pI830->pipeMon[0]->Modes);
     }
     if (pScrn->modes == NULL) {
 	FatalError("No modes found\n");
diff-tree ce5bd108c55d2378db072617c380514a39672603 (from 367f69f8e7710e53dcd286f1b62506a3276e80f9)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Jun 28 14:21:49 2006 +0200

    Validate and insert user and VESA standard modes for DDC or configured fallback.
    
    This isn't really tested because I lack a good CRT to test against currently.

diff --git a/src/i830_modes.c b/src/i830_modes.c
index 7433344..6b914bc 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -237,10 +237,10 @@ I830GetVESAEstablishedMode(ScrnInfoPtr p
     {
 	if (pMode->HDisplay == est_timings[i].hsize &&
 	    pMode->VDisplay == est_timings[i].vsize &&
-	    fabs(I830ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0)
+	    fabs(i830xf86ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0)
 	{
 	    DisplayModePtr pNew = I830DuplicateMode(pMode);
-	    pNew->VRefresh = I830ModeVRefresh(pMode);
+	    pNew->VRefresh = i830xf86ModeVRefresh(pMode);
 	    return pNew;
 	}
     }
@@ -523,16 +523,80 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char
    return first;
 }
 
+static DisplayModePtr
+i830GetModeListTail(DisplayModePtr pModeList)
+{
+    DisplayModePtr last;
+
+    if (pModeList == NULL)
+	return NULL;
+
+    for (last = pModeList; last->next != NULL; last = last->next)
+	;
+
+    return last;
+}
+
+/**
+ * Appends a list of modes to another mode list, without duplication.
+ */
+static void
+i830AppendModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+		DisplayModePtr addModes)
+{
+    DisplayModePtr first = *modeList;
+    DisplayModePtr last = i830GetModeListTail(first);
+
+    if (first == NULL) {
+	*modeList = addModes;
+    } else {
+	last->next = addModes;
+	addModes->prev = last;
+    }
+}
+
+/**
+ * Duplicates every mode in the given list and returns a pointer to the first
+ * mode.
+ *
+ * \param modeList doubly-linked mode list
+ */
+static DisplayModePtr
+i830DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList)
+{
+    DisplayModePtr first = NULL, last = NULL;
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	DisplayModePtr new;
+
+	new = I830DuplicateMode(mode);
+
+	/* Insert pNew into modeList */
+	if (last) {
+	    last->next = new;
+	    new->prev = last;
+	} else {
+	    first = new;
+	    new->prev = NULL;
+	}
+	new->next = NULL;
+	last = new;
+    }
+
+    return first;
+}
+
 /**
- * Injects a list of probed modes into another mode list.
+ * Duplicates and appends a list of modes to a mode list.
  *
  * Take the doubly-linked list of modes we've probed for the device, and injects
  * it into the doubly-linked modeList.  We don't need to filter, because the
  * eventual call to xf86ValidateModes will do this for us.  I think.
  */
 static int
-I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
-		      DisplayModePtr addModes)
+i830InjectModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+		DisplayModePtr addModes)
 {
     DisplayModePtr  last = *modeList;
     DisplayModePtr  first = *modeList;
@@ -573,25 +637,12 @@ I830InjectProbedModes(ScrnInfoPtr pScrn,
     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;
+    DisplayModePtr userModes;
     int i;
 
     ddc = xf86DoEDID_DDC2(pScrn->scrnIndex, pDDCBus);
@@ -601,7 +652,6 @@ i830GetDDCMonitor(ScrnInfoPtr pScrn, I2C
 
     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++) {
@@ -624,6 +674,22 @@ i830GetDDCMonitor(ScrnInfoPtr pScrn, I2C
 	}
     }
 
+    /* Add in VESA standard and user modelines, and do additional validation
+     * on them beyond what pipe config will do (x/y/pitch, clocks, flags)
+     */
+    userModes = i830DuplicateModes(pScrn, pScrn->monitor->Modes);
+
+    i830xf86ValidateModesSync(pScrn, userModes, mon);
+    if (ddc->features.hsize > 0 && ddc->features.vsize > 0) {
+	i830xf86ValidateModesSize(pScrn, userModes, ddc->features.hsize,
+				  ddc->features.vsize, -1);
+    }
+    i830xf86PruneInvalidModes(pScrn, &userModes, TRUE);
+
+    i830AppendModes(pScrn, &mon->Modes, userModes);
+
+    mon->Last = i830GetModeListTail(mon->Modes);
+
     return mon;
 }
 
@@ -643,6 +709,7 @@ static MonPtr
 i830GetConfiguredMonitor(ScrnInfoPtr pScrn)
 {
     MonPtr mon;
+    DisplayModePtr userModes;
 
     mon = xnfcalloc(1, sizeof(*mon));
     memcpy(mon, pScrn->monitor, sizeof(*mon));
@@ -654,6 +721,17 @@ i830GetConfiguredMonitor(ScrnInfoPtr pSc
     if (pScrn->monitor->model != NULL)
 	mon->model = xnfstrdup(pScrn->monitor->model);
 
+    /* Add in VESA standard and user modelines, and do additional validation
+     * on them beyond what pipe config will do (x/y/pitch, clocks, flags)
+     */
+    userModes = i830DuplicateModes(pScrn, pScrn->monitor->Modes);
+    i830xf86ValidateModesSync(pScrn, userModes, mon);
+    i830xf86PruneInvalidModes(pScrn, &userModes, FALSE);
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "prune 1\n");
+    i830AppendModes(pScrn, &mon->Modes, userModes);
+
+    mon->Last = i830GetModeListTail(mon->Modes);
+
     return mon;
 }
 
@@ -776,8 +854,7 @@ I830ReprobePipeModeList(ScrnInfoPtr pScr
 	    /* The code to choose the best mode per pipe later on will require
 	     * VRefresh to be set.
 	     */
-
-	    pMode->VRefresh = I830ModeVRefresh(pMode);
+	    pMode->VRefresh = i830xf86ModeVRefresh(pMode);
 	    I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
 #ifdef DEBUG_REPROBE
 	    PrintModeline(pScrn->scrnIndex, pMode);
@@ -960,9 +1037,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
      * care about enough to make some sort of unioned list.
      */
     if (pI830->pipeMon[1] != NULL) {
-	I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[1]->Modes);
+	i830InjectModes(pScrn, &pScrn->modes, pI830->pipeMon[1]->Modes);
     } else {
-	I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[0]->Modes);
+	i830InjectModes(pScrn, &pScrn->modes, pI830->pipeMon[0]->Modes);
     }
     if (pScrn->modes == NULL) {
 	FatalError("No modes found\n");
diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c
index 6f620c8..09f6b34 100644
--- a/src/i830_xf86Modes.c
+++ b/src/i830_xf86Modes.c
@@ -44,13 +44,32 @@
  * there but we still want to use.  We need to come up with better API here.
  */
 
+
 /**
- * Calculates the vertical refresh of a mode.
+ * Calculates the horizontal sync rate of a mode.
  *
  * Exact copy of xf86Mode.c's.
  */
 double
-I830ModeVRefresh(DisplayModePtr mode)
+i830xf86ModeHSync(DisplayModePtr mode)
+{
+    double hsync = 0.0;
+    
+    if (mode->HSync > 0.0)
+	    hsync = mode->HSync;
+    else if (mode->HTotal > 0)
+	    hsync = (float)mode->Clock / (float)mode->HTotal;
+
+    return hsync;
+}
+
+/**
+ * Calculates the vertical refresh rate of a mode.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+double
+i830xf86ModeVRefresh(DisplayModePtr mode)
 {
     double refresh = 0.0;
 
@@ -291,6 +310,51 @@ i830xf86ValidateModesSize(ScrnInfoPtr pS
 }
 
 /**
+ * Marks as bad any modes that aren't supported by the given monitor's
+ * hsync and vrefresh ranges.
+ *
+ * \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
+i830xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			  MonPtr mon)
+{
+    DisplayModePtr mode;
+
+    for (mode = modeList; mode != NULL; mode = mode->next) {
+	Bool bad;
+	int i;
+
+	bad = TRUE;
+	for (i = 0; i < mon->nHsync; i++) {
+	    if (i830xf86ModeHSync(mode) >= mon->hsync[i].lo &&
+		i830xf86ModeHSync(mode) <= mon->hsync[i].hi)
+	    {
+		bad = FALSE;
+	    }
+	}
+	if (bad)
+	    mode->status = MODE_HSYNC;
+
+	bad = TRUE;
+	for (i = 0; i < mon->nVrefresh; i++) {
+	    if (i830xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo &&
+		i830xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi)
+	    {
+		bad = FALSE;
+	    }
+	}
+	if (bad)
+	    mode->status = MODE_VSYNC;
+
+	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.
diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h
index 86e5b06..855aa46 100644
--- a/src/i830_xf86Modes.h
+++ b/src/i830_xf86Modes.h
@@ -26,7 +26,10 @@
  */
 
 double
-I830ModeVRefresh(DisplayModePtr mode);
+i830xf86ModeHSync(DisplayModePtr mode);
+
+double
+i830xf86ModeVRefresh(DisplayModePtr mode);
 
 void
 I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags);
@@ -47,6 +50,10 @@ i830xf86ValidateModesSize(ScrnInfoPtr pS
 			  int maxX, int maxY, int maxPitch);
 
 void
+i830xf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList,
+			  MonPtr mon);
+
+void
 i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
 			  Bool verbose);
 
diff-tree 367f69f8e7710e53dcd286f1b62506a3276e80f9 (from 9fbd3d8f4befb75ed6f6bd9a9ffe0175626e8785)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Wed Jun 28 13:10:02 2006 +0200

    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.

diff --git a/src/i830.h b/src/i830.h
index 9bd0227..f1b9774 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 8080c55..24103cb 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -268,11 +268,12 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     /* 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, Displ
 		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, DisplayMo
 	       (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 893ef10..7433344 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 p
 }
 
 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
 
    /* 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
 	    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,
     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,
     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 pScr
     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 pScr
 	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 pSc
 	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 pSc
 	} 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 pSc
 	}
     }
 
-    /* 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 pSc
 	I830xf86DeleteModeFromList(&pScrn->modes, saved_mode);
     }
 
-    if (!first_time) {
-	saved_virtualX = pScrn->virtualX;
-	saved_virtualY = pScrn->virtualY;
-	saved_displayWidth = pScrn->displayWidth;
-    }
-
-    I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
-
-    /* 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.
+    /* Clear any existing modes from pScrn->modes */
+    while (pScrn->modes != NULL)
+	xf86DeleteMode(&pScrn->modes, pScrn->modes);
+
+    /* 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 */);
+    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");
+    }
 
-    /* availModes is of no more use as xf86ValidateModes has duplicated and
-     * saved everything it needs.
+    /* 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 pSc
     } 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 16a8cd8..6f620c8 100644
--- a/src/i830_xf86Modes.c
+++ b/src/i830_xf86Modes.c
@@ -238,6 +238,126 @@ PrintModeline(int scrnIndex,DisplayModeP
     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 ba7d820..86e5b06 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[];



More information about the xorg-commit mailing list