summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/i830.h2
-rw-r--r--src/i830_crt.c41
-rw-r--r--src/i830_display.c25
-rw-r--r--src/i830_driver.c64
-rw-r--r--src/i830_dvo.c5
-rw-r--r--src/i830_lvds.c39
-rw-r--r--src/i830_modes.c766
-rw-r--r--src/i830_randr.c19
-rw-r--r--src/i830_sdvo.c22
-rw-r--r--src/i830_tv.c2
-rw-r--r--src/i830_xf86Modes.c53
-rw-r--r--src/i830_xf86Modes.h6
12 files changed, 332 insertions, 712 deletions
diff --git a/src/i830.h b/src/i830.h
index 5915a178..a4dc4ba1 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -485,7 +485,6 @@ typedef struct _I830Rec {
int availablePipes;
/* [0] is display plane A, [1] is display plane B. */
int planeEnabled[MAX_DISPLAY_PIPES];
- MonPtr pipeMon[MAX_DISPLAY_PIPES];
DisplayModeRec pipeCurMode[MAX_DISPLAY_PIPES];
/* Driver phase/state information */
@@ -694,6 +693,7 @@ DisplayModePtr i830GetGTF(int h_pixels, int v_lines, float freq,
/* i830_modes.c */
int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time);
+void i830_reprobe_output_modes(ScrnInfoPtr pScrn);
DisplayModePtr i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output);
/* i830_randr.c */
diff --git a/src/i830_crt.c b/src/i830_crt.c
index bd0099ac..407ebe3d 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -31,7 +31,7 @@
#include "xf86.h"
#include "i830.h"
-
+#include "i830_xf86Modes.h"
static void
i830_crt_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
@@ -80,6 +80,12 @@ static int
i830_crt_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
+ if (pMode->Flags & V_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ if (pMode->Clock > 400000 || pMode->Clock < 25000)
+ return MODE_CLOCK_RANGE;
+
return MODE_OK;
}
@@ -273,6 +279,37 @@ i830_crt_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
return OUTPUT_STATUS_UNKNOWN;
}
+static DisplayModePtr
+i830_crt_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
+{
+ DisplayModePtr modes;
+ MonRec fixed_mon;
+
+ modes = i830_ddc_get_modes(pScrn, output);
+ if (modes != NULL)
+ return modes;
+
+ if (output->detect(pScrn, output) == OUTPUT_STATUS_DISCONNECTED)
+ return NULL;
+
+ /* We've got a potentially-connected monitor that we can't DDC. Return a
+ * fixed set of VESA plus user modes for a presumed multisync monitor with
+ * some reasonable limits.
+ */
+ fixed_mon.nHsync = 1;
+ fixed_mon.hsync[0].lo = 31.0;
+ fixed_mon.hsync[0].hi = 100.0;
+ fixed_mon.nVrefresh = 1;
+ fixed_mon.vrefresh[0].lo = 50.0;
+ fixed_mon.vrefresh[0].hi = 70.0;
+
+ modes = i830xf86DuplicateModes(pScrn, pScrn->monitor->Modes);
+ i830xf86ValidateModesSync(pScrn, modes, &fixed_mon);
+ i830xf86PruneInvalidModes(pScrn, &modes, TRUE);
+
+ return modes;
+}
+
void
i830_crt_init(ScrnInfoPtr pScrn)
{
@@ -286,7 +323,7 @@ i830_crt_init(ScrnInfoPtr pScrn)
pI830->output[pI830->num_outputs].pre_set_mode = i830_crt_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_crt_post_set_mode;
pI830->output[pI830->num_outputs].detect = i830_crt_detect;
- pI830->output[pI830->num_outputs].get_modes = i830_ddc_get_modes;
+ pI830->output[pI830->num_outputs].get_modes = i830_crt_get_modes;
/* Set up the DDC bus. */
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,
diff --git a/src/i830_display.c b/src/i830_display.c
index 3151fd10..b3019f80 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -260,8 +260,8 @@ i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y)
}
/**
- * In the current world order, there is a list of per-pipe modes, which may or
- * may not include the mode that was asked to be set by XFree86's mode
+ * In the current world order, there are lists of modes per output, which may
+ * or may not include the mode that was asked to be set by XFree86's mode
* selection. Find the closest one, in the following preference order:
*
* - Equality
@@ -272,21 +272,32 @@ static DisplayModePtr
i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode)
{
I830Ptr pI830 = I830PTR(pScrn);
- DisplayModePtr pBest = NULL, pScan;
+ DisplayModePtr pBest = NULL, pScan = NULL;
+ int i;
+
+ /* Assume that there's only one output connected to the given CRTC. */
+ for (i = 0; i < pI830->num_outputs; i++) {
+ if (pI830->output[i].pipe == pipe &&
+ !pI830->output[i].disabled &&
+ pI830->output[i].probed_modes != NULL)
+ {
+ pScan = pI830->output[i].probed_modes;
+ }
+ }
/* If the pipe doesn't have any detected modes, just let the system try to
* spam the desired mode in.
*/
- if (pI830->pipeMon[pipe] == NULL) {
+ if (pScan == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"No pipe mode list for pipe %d,"
"continuing with desired mode\n", pipe);
return pMode;
}
- assert(pScan->VRefresh != 0.0);
- for (pScan = pI830->pipeMon[pipe]->Modes; pScan != NULL;
- pScan = pScan->next) {
+ for (; pScan != NULL; pScan = pScan->next) {
+ assert(pScan->VRefresh != 0.0);
+
/* If there's an exact match, we're done. */
if (I830ModesEqual(pScan, pMode)) {
pBest = pMode;
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 2c7eca73..7c151747 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -788,55 +788,6 @@ I830PreInitDDC(ScrnInfoPtr pScrn)
}
static void
-I830DetectMonitors(ScrnInfoPtr pScrn)
-{
- I830Ptr pI830 = I830PTR(pScrn);
- int i;
-
- if (!pI830->ddc2)
- return;
-
- for (i=0; i<pI830->num_outputs; i++) {
- switch (pI830->output[i].type) {
- case I830_OUTPUT_ANALOG:
- case I830_OUTPUT_LVDS:
- /* for an analog/LVDS output, just do DDC */
- pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
- pI830->output[i].pDDCBus);
-
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC %s %d, %08lX\n",
- i830_output_type_names[pI830->output[i].type], i,
- pI830->output[i].pDDCBus->DriverPrivate.uval);
- xf86PrintEDID(pI830->output[i].MonInfo);
- break;
- case I830_OUTPUT_DVO:
- /* check for DDC */
- pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
- pI830->output[i].pDDCBus);
-
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC DVO %d, %08lX\n", i,
- pI830->output[i].pDDCBus->DriverPrivate.uval);
- xf86PrintEDID(pI830->output[i].MonInfo);
- break;
- case I830_OUTPUT_SDVO:
- pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
- pI830->output[i].pDDCBus);
-
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08lX\n", i,
- pI830->output[i].pDDCBus->DriverPrivate.uval);
- xf86PrintEDID(pI830->output[i].MonInfo);
- break;
- case I830_OUTPUT_UNUSED:
- break;
- default:
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Unknown or unhandled output device at %d\n", i);
- break;
- }
- }
-}
-
-static void
PreInitCleanup(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
@@ -1333,21 +1284,6 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
I830PreInitDDC(pScrn);
- I830DetectMonitors(pScrn);
-
- /* Walk from the end so we'll happen to hit SDVO first, if we found some. An
- * SDVO device is probably a DFP, and so probably pickier than (say) a CRT
- * that we might find early in the list. This hackery will go away when we
- * start doing independent per-head mode selection.
- */
- for (i = pI830->num_outputs - 1; i >= 0; i--) {
- if (pI830->output[i].MonInfo) {
- pScrn->monitor->DDC = pI830->output[i].MonInfo;
- xf86SetDDCproperties(pScrn, pI830->output[i].MonInfo);
- break;
- }
- }
-
pI830->MonType1 = PIPE_NONE;
pI830->MonType2 = PIPE_NONE;
pI830->specifiedMonitor = FALSE;
diff --git a/src/i830_dvo.c b/src/i830_dvo.c
index c788e4f4..31fb76ba 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -96,6 +96,11 @@ static int
i830_dvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr pMode)
{
+ if (pMode->Flags & V_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ /* XXX: Validate clock range */
+
if (output->i2c_drv->vid_rec->ModeValid(output->i2c_drv->dev_priv, pMode))
return MODE_OK;
else
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 4b899033..7b9fe634 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -189,6 +189,39 @@ i830_lvds_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
return OUTPUT_STATUS_CONNECTED;
}
+/**
+ * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
+ */
+static DisplayModePtr
+i830_lvds_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ DisplayModePtr modes, new;
+ char stmp[32];
+
+ modes = i830_ddc_get_modes(pScrn, output);
+ if (modes != NULL)
+ return modes;
+
+ new = xnfcalloc(1, sizeof (DisplayModeRec));
+ sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes);
+ new->name = xnfalloc(strlen(stmp) + 1);
+ strcpy(new->name, stmp);
+ new->HDisplay = pI830->PanelXRes;
+ new->VDisplay = pI830->PanelYRes;
+ new->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff;
+ new->HSyncEnd = new->HSyncStart + pI830->panel_fixed_hsyncwidth;
+ new->HTotal = new->HSyncEnd + 1;
+ new->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff;
+ new->VSyncEnd = new->VSyncStart + pI830->panel_fixed_vsyncwidth;
+ new->VTotal = new->VSyncEnd + 1;
+ new->Clock = pI830->panel_fixed_clock;
+
+ new->type = M_T_PREFERRED;
+
+ return new;
+}
+
void
i830_lvds_init(ScrnInfoPtr pScrn)
{
@@ -235,11 +268,7 @@ i830_lvds_init(ScrnInfoPtr pScrn)
pI830->output[pI830->num_outputs].pre_set_mode = i830_lvds_pre_set_mode;
pI830->output[pI830->num_outputs].post_set_mode = i830_lvds_post_set_mode;
pI830->output[pI830->num_outputs].detect = i830_lvds_detect;
- /* This will usually return NULL on laptop panels, which is no good.
- * We need to construct a mode from the fixed panel info, and return a copy
- * of that when DDC is unavailable.
- */
- pI830->output[pI830->num_outputs].get_modes = i830_ddc_get_modes;
+ pI830->output[pI830->num_outputs].get_modes = i830_lvds_get_modes;
/* Set up the LVDS DDC channel. Most panels won't support it, but it can
* be useful if available.
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 1ba1defb..d6866ad8 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -162,27 +162,6 @@ I830PrintModes(ScrnInfoPtr scrp)
} while (p != NULL && p != scrp->modes);
}
-/**
- * Allocates and returns a copy of pMode, including pointers within pMode.
- */
-static DisplayModePtr
-I830DuplicateMode(DisplayModePtr pMode)
-{
- DisplayModePtr pNew;
-
- pNew = xnfalloc(sizeof(DisplayModeRec));
- *pNew = *pMode;
- pNew->next = NULL;
- pNew->prev = NULL;
- if (pNew->name == NULL) {
- i830xf86SetModeDefaultName(pMode);
- } else {
- pNew->name = xnfstrdup(pMode->name);
- }
-
- return pNew;
-}
-
/* This function will sort all modes according to their resolution.
* Highest resolution first.
*/
@@ -244,7 +223,7 @@ I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i)
pMode->VDisplay == est_timings[i].vsize &&
fabs(i830xf86ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0)
{
- DisplayModePtr pNew = I830DuplicateMode(pMode);
+ DisplayModePtr pNew = i830xf86DuplicateMode(pMode);
i830xf86SetModeDefaultName(pNew);
pNew->VRefresh = i830xf86ModeVRefresh(pMode);
return pNew;
@@ -391,141 +370,6 @@ i830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc)
return first;
}
-/**
- * This function returns a default mode for flat panels using the timing
- * information provided by the BIOS.
- */
-static DisplayModePtr
-i830FPNativeMode(ScrnInfoPtr pScrn)
-{
- I830Ptr pI830 = I830PTR(pScrn);
- DisplayModePtr new;
- char stmp[32];
-
- if (pI830->PanelXRes == 0 || pI830->PanelYRes == 0)
- return NULL;
-
- /* Add native panel size */
- new = xnfcalloc(1, sizeof (DisplayModeRec));
- sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes);
- new->name = xnfalloc(strlen(stmp) + 1);
- strcpy(new->name, stmp);
- new->HDisplay = pI830->PanelXRes;
- new->VDisplay = pI830->PanelYRes;
- new->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff;
- new->HSyncEnd = new->HSyncStart + pI830->panel_fixed_hsyncwidth;
- new->HTotal = new->HSyncEnd + 1;
- new->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff;
- new->VSyncEnd = new->VSyncStart + pI830->panel_fixed_vsyncwidth;
- new->VTotal = new->VSyncEnd + 1;
- new->Clock = pI830->panel_fixed_clock;
-
- new->type = M_T_PREFERRED;
-
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "No valid mode specified, force to native mode\n");
-
- return new;
-}
-
-/**
- * FP automatic modelist creation routine for using panel fitting.
- *
- * Constructs modes for any resolution less than the panel size specified by the
- * user, with the user flag set, plus standard VESA mode sizes without the user
- * flag set (for randr).
- *
- * Modes will be faked to use GTF parameters, even though at the time of being
- * programmed into the LVDS they'll end up being forced to the panel's fixed
- * mode.
- *
- * \return doubly-linked list of modes.
- */
-static DisplayModePtr
-i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName)
-{
- I830Ptr pI830 = I830PTR(pScrn);
- DisplayModePtr last = NULL;
- DisplayModePtr new = NULL;
- DisplayModePtr first = NULL;
- DisplayModePtr p, tmp;
- int count = 0;
- int i, width, height;
-
- /* We have a flat panel connected to the primary display, and we
- * don't have any DDC info.
- */
- for (i = 0; ppModeName[i] != NULL; i++) {
-
- if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2)
- continue;
-
- /* Note: We allow all non-standard modes as long as they do not
- * exceed the native resolution of the panel. Since these modes
- * need the internal RMX unit in the video chips (and there is
- * only one per card), this will only apply to the primary head.
- */
- if (width < 320 || width > pI830->PanelXRes ||
- height < 200 || height > pI830->PanelYRes) {
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode %s is out of range.\n",
- ppModeName[i]);
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Valid modes must be between 320x200-%dx%d\n",
- pI830->PanelXRes, pI830->PanelYRes);
- continue;
- }
-
- new = i830GetGTF(width, height, 60.0, FALSE, FALSE);
- new->type |= M_T_DEFAULT;
-
- new->next = NULL;
- new->prev = last;
-
- if (last)
- last->next = new;
- last = new;
- if (!first)
- first = new;
-
- count++;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Valid mode using panel fitting: %s\n", new->name);
- }
-
- /* If the user hasn't specified modes, add the native mode */
- if (!count) {
- new = i830FPNativeMode(pScrn);
- if (new) {
- I830xf86SortModes(new, &first, &last);
- count = 1;
- }
- }
-
- /* add in all default vesa modes smaller than panel size, used for randr */
- for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
- if ((p->HDisplay <= pI830->PanelXRes) && (p->VDisplay <= pI830->PanelYRes)) {
- tmp = first;
- while (tmp) {
- if ((p->HDisplay == tmp->HDisplay) && (p->VDisplay == tmp->VDisplay)) break;
- tmp = tmp->next;
- }
- if (!tmp) {
- new = i830GetGTF(p->HDisplay, p->VDisplay, 60.0, FALSE, FALSE);
- new->type |= M_T_DEFAULT;
-
- I830xf86SortModes(new, &first, &last);
-
- count++;
- }
- }
- }
-
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Total number of valid FP mode(s) found: %d\n", count);
-
- return first;
-}
-
static DisplayModePtr
i830GetModeListTail(DisplayModePtr pModeList)
{
@@ -562,330 +406,6 @@ i830AppendModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
}
/**
- * 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;
-}
-
-static MonPtr
-i830GetDDCMonitor(ScrnInfoPtr pScrn, I2CBusPtr pDDCBus)
-{
- xf86MonPtr ddc;
- MonPtr mon;
- DisplayModePtr userModes;
- int i;
-
- ddc = xf86DoEDID_DDC2(pScrn->scrnIndex, pDDCBus);
-
- if (ddc == NULL)
- return NULL;
-
- mon = xnfcalloc(1, sizeof(*mon));
- mon->Modes = i830GetDDCModes(pScrn, ddc);
- 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;
- }
- }
-
- /* 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, TRUE);
-
- i830AppendModes(pScrn, &mon->Modes, userModes);
-
- mon->Last = i830GetModeListTail(mon->Modes);
-
- return mon;
-}
-
-static MonPtr
-i830GetLVDSMonitor(ScrnInfoPtr pScrn)
-{
- MonPtr mon;
- DisplayModePtr mode;
-
- mon = xnfcalloc(1, sizeof(*mon));
- mon->Modes = i830GetLVDSModes(pScrn, pScrn->display->modes);
- mon->Last = i830GetModeListTail(mon->Modes);
- /*
- * Find the preferred mode, use the display resolution to compute
- * the effective monitor size
- */
- for (mode = mon->Modes; mode; mode = mode->next)
- if (mode->type & M_T_PREFERRED)
- break;
- if (!mode)
- mode = mon->Modes;
- if (mode)
- {
-#define MMPERINCH 25.4
- mon->widthmm = (double) mode->HDisplay / pScrn->xDpi * MMPERINCH;
- mon->heightmm = (double) mode->VDisplay / pScrn->yDpi * MMPERINCH;
- }
-
- 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);
-
- /* Use VESA standard and user modelines, and do additional validation
- * on them beyond what pipe config will do (x/y/pitch, clocks, flags)
- */
- mon->Modes = i830DuplicateModes(pScrn, pScrn->monitor->Modes);
- i830xf86ValidateModesSync(pScrn, mon->Modes, mon);
- i830xf86PruneInvalidModes(pScrn, &mon->Modes, TRUE);
- mon->Last = i830GetModeListTail(mon->Modes);
-
- return mon;
-}
-
-static MonPtr
-i830GetDefaultMonitor(ScrnInfoPtr pScrn)
-{
- MonPtr mon;
-
- mon = xnfcalloc(1, sizeof(*mon));
-
- mon->id = xnfstrdup("Unknown Id");
- mon->vendor = xnfstrdup("Unknown Vendor");
- mon->model = xnfstrdup("Unknown Model");
-
- mon->nHsync = 1;
- mon->hsync[0].lo = 31.0;
- mon->hsync[0].hi = 100.0;
- mon->nVrefresh = 1;
- mon->vrefresh[0].lo = 50.0;
- mon->vrefresh[0].hi = 70.0;
- mon->widthmm = 400;
- mon->heightmm = 300;
- /* Use VESA standard and user modelines, and do additional validation
- * on them beyond what pipe config will do (x/y/pitch, clocks, flags)
- */
- mon->Modes = i830DuplicateModes(pScrn, pScrn->monitor->Modes);
- i830xf86ValidateModesSync(pScrn, mon->Modes, mon);
- i830xf86PruneInvalidModes(pScrn, &mon->Modes, TRUE);
- mon->Last = i830GetModeListTail(mon->Modes);
-
- 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.
- *
- * We do not support multiple outputs per pipe (since the cases for that are
- * sufficiently rare we can't imagine the complexity being worth it), so
- * the pipe is a sufficient specifier.
- */
-static void
-I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe)
-{
- I830Ptr pI830 = I830PTR(pScrn);
- int output_index = -1;
- int i;
- int outputs;
- DisplayModePtr pMode;
- MonPtr old_mon = pI830->pipeMon[pipe];
-
- if (pipe == 0)
- outputs = pI830->operatingDevices & 0xff;
- else
- outputs = (pI830->operatingDevices >> 8) & 0xff;
-
- for (i = 0; i < pI830->num_outputs; i++) {
- switch (pI830->output[i].type) {
- case I830_OUTPUT_ANALOG:
- if (outputs & PIPE_CRT) {
- output_index = i;
- }
- break;
- case I830_OUTPUT_LVDS:
- if (outputs & PIPE_LFP) {
- output_index = i;
- }
- break;
- case I830_OUTPUT_DVO:
- if (outputs & PIPE_DFP) {
- output_index = i;
- }
- break;
- case I830_OUTPUT_SDVO:
- if (outputs & PIPE_DFP) {
- output_index = i;
- }
- break;
- }
- }
- /* XXX: If there's no output associated with the pipe, bail for now. */
- if (output_index == -1)
- return;
-
- if (outputs & PIPE_LFP) {
- pI830->pipeMon[pipe] = i830GetLVDSMonitor(pScrn);
- } else if (pI830->output[output_index].pDDCBus != NULL) {
- 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) {
- enum detect_status detect;
-
- detect = pI830->output[output_index].detect(pScrn,
- &pI830->output[output_index]);
-
- switch (pI830->output[output_index].type) {
- case I830_OUTPUT_SDVO:
- if (detect == OUTPUT_STATUS_CONNECTED)
- pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
- break;
- case I830_OUTPUT_ANALOG:
- if (detect == OUTPUT_STATUS_CONNECTED) {
-/* if (pipe == pI830->pipe)
- pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
- else */
- pI830->pipeMon[pipe] = i830GetDefaultMonitor(pScrn);
- }
- break;
- default:
- pI830->pipeMon[pipe] = i830GetConfiguredMonitor(pScrn);
- break;
- }
- }
-
-#ifdef DEBUG_REPROBE
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing probed modes for pipe %d\n",
- pipe);
-#endif
- 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);
-
- /* silently prune modes down to ones matching the user's configuration.
- */
- i830xf86ValidateModesUserConfig(pScrn, pI830->pipeMon[pipe]->Modes);
- i830xf86PruneInvalidModes(pScrn, &pI830->pipeMon[pipe]->Modes, FALSE);
-
- 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 = i830xf86ModeVRefresh(pMode);
- I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
-#ifdef DEBUG_REPROBE
- 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);
-}
-
-/**
* This function removes a mode from a list of modes. It should probably be
* moved to xf86Mode.c.
*
@@ -918,28 +438,18 @@ I830xf86DeleteModeFromList(DisplayModePtr *modeList, DisplayModePtr mode)
mode->next->prev = mode->prev;
}
}
-
-/**
- * Probes for video modes on attached otuputs, and assembles a list to insert
- * into pScrn.
- *
- * \param first_time indicates that the memory layout has already been set up,
- * so displayWidth, virtualX, and virtualY shouldn't be touched.
- *
- * A SetMode must follow this call in order for operatingDevices to match the
- * hardware's state, in case we detect a new output device.
- */
-int
-I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
+
+void
+i830_reprobe_output_modes(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
- int pipe, i;
- DisplayModePtr saved_mode, last;
- Bool pipes_reconfigured = FALSE;
- int originalVirtualX, originalVirtualY;
+ Bool properties_set = FALSE;
+ int i;
/* Re-probe the list of modes for each output. */
for (i = 0; i < pI830->num_outputs; i++) {
+ DisplayModePtr mode;
+
while (pI830->output[i].probed_modes != NULL) {
xf86DeleteMode(&pI830->output[i].probed_modes,
pI830->output[i].probed_modes);
@@ -947,103 +457,66 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
pI830->output[i].probed_modes =
pI830->output[i].get_modes(pScrn, &pI830->output[i]);
- }
-
- for (pipe = 0; pipe < pI830->availablePipes; pipe++) {
- I830ReprobePipeModeList(pScrn, pipe);
- }
- /* If we've got a spare pipe, try to detect if a new CRT has been plugged
- * in.
- */
- if ((pI830->operatingDevices & (PIPE_CRT | (PIPE_CRT << 8))) == 0) {
- if ((pI830->operatingDevices & 0xff) == PIPE_NONE) {
- pI830->operatingDevices |= PIPE_CRT;
- I830ReprobePipeModeList(pScrn, 0);
- if (pI830->pipeMon[0] == NULL) {
- /* No new output found. */
- pI830->operatingDevices &= ~PIPE_CRT;
- } else {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Enabled new CRT on pipe A\n");
- pipes_reconfigured = TRUE;
- /* Clear the current mode, so we reprogram the pipe for sure. */
- memset(&pI830->pipeCurMode[0], 0, sizeof(pI830->pipeCurMode[0]));
- }
- } else if (((pI830->operatingDevices >> 8) & 0xff) == PIPE_NONE) {
- pI830->operatingDevices |= PIPE_CRT << 8;
- I830ReprobePipeModeList(pScrn, 1);
- if (pI830->pipeMon[1] == NULL) {
- /* No new output found. */
- pI830->operatingDevices &= ~(PIPE_CRT << 8);
- } else {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Enabled new CRT on pipe B\n");
- pipes_reconfigured = TRUE;
- /* Clear the current mode, so we reprogram the pipe for sure. */
- memset(&pI830->pipeCurMode[1], 0, sizeof(pI830->pipeCurMode[1]));
- }
- }
- }
-
- 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 (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.
+ /* Set the DDC properties to whatever first output has DDC information.
*/
- for (pipe = 0; pipe < pI830->availablePipes; 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;
- }
+ if (pI830->output[i].MonInfo != NULL && !properties_set) {
+ xf86SetDDCproperties(pScrn, pI830->output[i].MonInfo);
+ properties_set = TRUE;
}
- /* let the user specify a bigger virtual size if they like */
- if (pScrn->display->virtualX > maxX)
- maxX = pScrn->display->virtualX;
- if (pScrn->display->virtualY > maxY)
- maxY = pScrn->display->virtualY;
- pScrn->virtualX = maxX;
- pScrn->virtualY = maxY;
- pScrn->displayWidth = (maxX + 63) & ~63;
- }
-
- I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
- /* Disable modes that are larger than the virtual size we decided on
- * initially.
- */
- if (!first_time) {
- for (pipe = 0; pipe < pI830->availablePipes; pipe++) {
- MonPtr mon = pI830->pipeMon[pipe];
- DisplayModePtr mode;
+ if (pI830->output[i].probed_modes != NULL) {
+ /* silently prune modes down to ones matching the user's
+ * configuration.
+ */
+ i830xf86ValidateModesUserConfig(pScrn,
+ pI830->output[i].probed_modes);
+ i830xf86PruneInvalidModes(pScrn, &pI830->output[i].probed_modes,
+ FALSE);
+ }
- if (mon == NULL)
- continue;
+#ifdef DEBUG_REPROBE
+ if (pI830->output[i].probed_modes != NULL) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Printing probed modes for output %s\n",
+ i830_output_type_names[pI830->output[i].type]);
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "No remaining probed modes for output %s\n",
+ i830_output_type_names[pI830->output[i].type]);
+ }
+#endif
+ for (mode = pI830->output[i].probed_modes; mode != NULL;
+ mode = mode->next)
+ {
+ /* The code to choose the best mode per pipe later on will require
+ * VRefresh to be set.
+ */
+ mode->VRefresh = i830xf86ModeVRefresh(mode);
+ I830xf86SetModeCrtc(mode, INTERLACE_HALVE_V);
- 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;
- }
+#ifdef DEBUG_REPROBE
+ PrintModeline(pScrn->scrnIndex, mode);
+#endif
}
}
+}
+
+/**
+ * Constructs pScrn->modes from the output mode lists.
+ *
+ * Currently it only takes one output's mode list and stuffs it into the
+ * XFree86 DDX mode list while trimming it for root window size.
+ *
+ * This should be obsoleted by RandR 1.2 hopefully.
+ */
+static void
+i830_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ DisplayModePtr saved_mode, last;
+ int originalVirtualX, originalVirtualY;
+ int i;
/* Remove the current mode from the modelist if we're re-validating, so we
* can find a new mode to map ourselves to afterwards.
@@ -1057,30 +530,34 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
while (pScrn->modes != NULL)
xf86DeleteMode(&pScrn->modes, pScrn->modes);
- /* Set pScrn->modes to the mode list for the an arbitrary head.
+ /* Set pScrn->modes to the mode list for an arbitrary output.
* pScrn->modes should only be used for XF86VidMode now, which we don't
* care about enough to make some sort of unioned list.
*/
- if (pI830->pipeMon[1] != NULL) {
- pScrn->modes = i830DuplicateModes(pScrn, pI830->pipeMon[1]->Modes);
- } else {
- pScrn->modes = i830DuplicateModes(pScrn, pI830->pipeMon[0]->Modes);
- }
- if (pScrn->modes == NULL) {
- FatalError("No modes found\n");
+ for (i = 0; i < pI830->num_outputs; i++) {
+ if (pI830->output[i].probed_modes != NULL) {
+ pScrn->modes =
+ i830xf86DuplicateModes(pScrn, pI830->output[i].probed_modes);
+ break;
+ }
}
- /* 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.
+ I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY);
+
+ /* Disable modes in the XFree86 DDX list that are larger than the current
+ * virtual size.
*/
i830xf86ValidateModesSize(pScrn, pScrn->modes,
originalVirtualX, originalVirtualY,
pScrn->displayWidth);
- /* Strip out anything bad that we threw out for virtualX. */
+ /* Strip out anything that we threw out for virtualX/Y. */
i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE);
+ if (pScrn->modes == NULL) {
+ FatalError("No modes left for XFree86 DDX\n");
+ }
+
/* For some reason, pScrn->modes is circular, unlike the other mode lists.
* How great is that?
*/
@@ -1088,25 +565,70 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
last->next = pScrn->modes;
pScrn->modes->prev = last;
-#if DEBUG_REPROBE
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Modes post revalidate\n");
- do {
- DisplayModePtr pMode;
-
- for (pMode = pScrn->modes; ; pMode = pMode->next) {
- PrintModeline(pScrn->scrnIndex, pMode);
- if (pMode->next == pScrn->modes)
- break;
- }
- } while (0);
-#endif
-
/* 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.
*/
pI830->savedCurrentMode = saved_mode;
+}
+
+/**
+ * Takes the output mode lists and decides the default root window size
+ * and framebuffer pitch.
+ */
+static void
+i830_set_default_screen_size(ScrnInfoPtr pScrn)
+{
+ I830Ptr pI830 = I830PTR(pScrn);
+ int maxX = -1, maxY = -1;
+ int i;
+
+ /* Set up a virtual size that will cover any clone mode we'd want to
+ * set for the currently-connected outputs.
+ */
+ for (i = 0; i < pI830->num_outputs; i++) {
+ DisplayModePtr mode;
+
+ for (mode = pI830->output[i].probed_modes; mode != NULL;
+ mode = mode->next)
+ {
+ if (mode->HDisplay > maxX)
+ maxX = mode->HDisplay;
+ if (mode->VDisplay > maxY)
+ maxY = mode->VDisplay;
+ }
+ }
+ /* let the user specify a bigger virtual size if they like */
+ if (pScrn->display->virtualX > maxX)
+ maxX = pScrn->display->virtualX;
+ if (pScrn->display->virtualY > maxY)
+ maxY = pScrn->display->virtualY;
+ pScrn->virtualX = maxX;
+ pScrn->virtualY = maxY;
+ pScrn->displayWidth = (maxX + 63) & ~63;
+}
+
+/**
+ * Probes for video modes on attached otuputs, and assembles a list to insert
+ * into pScrn.
+ *
+ * \param first_time indicates that the memory layout has already been set up,
+ * so displayWidth, virtualX, and virtualY shouldn't be touched.
+ *
+ * A SetMode must follow this call in order for operatingDevices to match the
+ * hardware's state, in case we detect a new output device.
+ */
+int
+I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time)
+{
+ i830_reprobe_output_modes(pScrn);
+
+ if (first_time) {
+ i830_set_default_screen_size(pScrn);
+ }
+
+ i830_set_xf86_modes_from_outputs(pScrn);
return 1; /* XXX */
}
@@ -1118,14 +640,32 @@ DisplayModePtr
i830_ddc_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
xf86MonPtr ddc_mon;
- DisplayModePtr ddc_modes;
+ DisplayModePtr ddc_modes, mode;
ddc_mon = xf86DoEDID_DDC2(pScrn->scrnIndex, output->pDDCBus);
if (ddc_mon == NULL)
return NULL;
+ if (output->MonInfo != NULL)
+ xfree(output->MonInfo);
+ output->MonInfo = ddc_mon;
+
+ /* Debug info for now, at least */
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID for output %s\n",
+ i830_output_type_names[output->type]);
+ xf86PrintEDID(output->MonInfo);
+
ddc_modes = i830GetDDCModes(pScrn, ddc_mon);
+ /* Strip out any modes that can't be supported on this output. */
+ for (mode = ddc_modes; mode != NULL; mode = mode->next) {
+ int status = output->mode_valid(pScrn, output, mode);
+
+ if (status != MODE_OK)
+ mode->status = status;
+ }
+ i830xf86PruneInvalidModes(pScrn, &ddc_modes, TRUE);
+
xfree(ddc_mon);
return ddc_modes;
diff --git a/src/i830_randr.c b/src/i830_randr.c
index f8064b91..69063a8b 100644
--- a/src/i830_randr.c
+++ b/src/i830_randr.c
@@ -630,8 +630,6 @@ I830RandRSetInfo12 (ScreenPtr pScreen)
randrp->virtualX, randrp->virtualY);
for (i = 0; i < pI830->num_outputs; i++)
{
- MonPtr mon;
-
output = &pI830->output[i];
/*
* Valid crtcs
@@ -701,6 +699,11 @@ I830RandRSetInfo12 (ScreenPtr pScreen)
RROutputSetCrtc (randrp->outputs[i], crtc);
+ /* We should pull info out of EDID to get the output physical
+ * size when available.
+ */
+ RROutputSetPhysicalSize(randrp->outputs[i], 0, 0);
+
RROutputSetPossibleOptions (randrp->outputs[i], possibleOptions);
RROutputSetCurrentOptions (randrp->outputs[i], currentOptions);
nmode = 0;
@@ -709,11 +712,6 @@ I830RandRSetInfo12 (ScreenPtr pScreen)
modes = pI830->output[i].probed_modes;
- if (pI830->output[i].pipe >= 0)
- mon = pI830->pipeMon[pipe];
- else
- mon = NULL;
-
for (mode = modes; mode; mode = mode->next)
nmode++;
@@ -723,11 +721,6 @@ I830RandRSetInfo12 (ScreenPtr pScreen)
return FALSE;
nmode = 0;
- /* We should pull info out of EDID to get the output physical
- * size when available.
- */
- RROutputSetPhysicalSize(randrp->outputs[i], 0, 0);
-
for (p = 1; p >= 0; p--) {
for (mode = modes; mode; mode = mode->next) {
if ((p != 0) == ((mode->type & M_T_PREFERRED) != 0)) {
@@ -806,7 +799,7 @@ I830RandRGetInfo12 (ScreenPtr pScreen, Rotation *rotations)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- I830ValidateXF86ModeList(pScrn, FALSE);
+ i830_reprobe_output_modes(pScrn);
return I830RandRSetInfo12 (pScreen);
}
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index b6a3d676..eda28579 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -66,8 +66,8 @@ struct i830_sdvo_priv {
*/
struct i830_sdvo_caps caps;
- /** Pixel clock limitations reported by the SDVO device */
- CARD16 pixel_clock_min, pixel_clock_max;
+ /** Pixel clock limitations reported by the SDVO device, in kHz */
+ int pixel_clock_min, pixel_clock_max;
/** State for save/restore */
/** @{ */
@@ -323,9 +323,12 @@ i830_sdvo_set_active_outputs(I830OutputPtr output,
return (status == SDVO_CMD_STATUS_SUCCESS);
}
+/**
+ * Returns the pixel clock range limits of the current target input in kHz.
+ */
static Bool
-i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, CARD16 *clock_min,
- CARD16 *clock_max)
+i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, int *clock_min,
+ int *clock_max)
{
struct i830_sdvo_pixel_clock_range clocks;
CARD8 status;
@@ -337,8 +340,9 @@ i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, CARD16 *clock_min,
if (status != SDVO_CMD_STATUS_SUCCESS)
return FALSE;
- *clock_min = clocks.min;
- *clock_max = clocks.max;
+ /* Convert the values from units of 10 kHz to kHz. */
+ *clock_min = clocks.min * 10;
+ *clock_max = clocks.max * 10;
return TRUE;
}
@@ -735,6 +739,9 @@ i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
{
struct i830_sdvo_priv *dev_priv = output->dev_priv;
+ if (pMode->Flags & V_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
if (dev_priv->pixel_clock_min > pMode->Clock)
return MODE_CLOCK_HIGH;
@@ -1035,10 +1042,13 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"SDVO device VID/DID: %02X:%02X.%02X, "
+ "clock range %.1fMHz - %.1fMHz, "
"input 1: %c, input 2: %c, "
"output 1: %c, output 2: %c\n",
dev_priv->caps.vendor_id, dev_priv->caps.device_id,
dev_priv->caps.device_rev_id,
+ dev_priv->pixel_clock_min / 1000.0,
+ dev_priv->pixel_clock_max / 1000.0,
(dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
(dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
dev_priv->caps.output_flags.tmds0 ? 'Y' : 'N',
diff --git a/src/i830_tv.c b/src/i830_tv.c
index 47c0d03b..c597db53 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -423,7 +423,7 @@ i830_tv_detect(ScrnInfoPtr pScrn, I830OutputPtr output)
* This should probably return a set of fixed modes, unless we can figure out
* how to probe modes off of TV connections.
*/
-DisplayModePtr
+static DisplayModePtr
i830_tv_get_modes(ScrnInfoPtr pScrn, I830OutputPtr output)
{
return NULL;
diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c
index 8c34053c..8e8a94c5 100644
--- a/src/i830_xf86Modes.c
+++ b/src/i830_xf86Modes.c
@@ -195,6 +195,59 @@ I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
}
/**
+ * Allocates and returns a copy of pMode, including pointers within pMode.
+ */
+DisplayModePtr
+i830xf86DuplicateMode(DisplayModePtr pMode)
+{
+ DisplayModePtr pNew;
+
+ pNew = xnfalloc(sizeof(DisplayModeRec));
+ *pNew = *pMode;
+ pNew->next = NULL;
+ pNew->prev = NULL;
+ if (pNew->name == NULL) {
+ i830xf86SetModeDefaultName(pMode);
+ } else {
+ pNew->name = xnfstrdup(pMode->name);
+ }
+
+ return pNew;
+}
+
+/**
+ * Duplicates every mode in the given list and returns a pointer to the first
+ * mode.
+ *
+ * \param modeList doubly-linked mode list
+ */
+DisplayModePtr
+i830xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList)
+{
+ DisplayModePtr first = NULL, last = NULL;
+ DisplayModePtr mode;
+
+ for (mode = modeList; mode != NULL; mode = mode->next) {
+ DisplayModePtr new;
+
+ new = i830xf86DuplicateMode(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;
+}
+
+/**
* Returns true if the given modes should program to the same timings.
*
* This doesn't use Crtc values, as it might be used on ModeRecs without the
diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h
index 0cba8874..5a26c0e4 100644
--- a/src/i830_xf86Modes.h
+++ b/src/i830_xf86Modes.h
@@ -31,6 +31,12 @@ i830xf86ModeHSync(DisplayModePtr mode);
double
i830xf86ModeVRefresh(DisplayModePtr mode);
+DisplayModePtr
+i830xf86DuplicateMode(DisplayModePtr pMode);
+
+DisplayModePtr
+i830xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList);
+
void
i830xf86SetModeDefaultName(DisplayModePtr mode);