diff options
author | Eric Anholt <eric@anholt.net> | 2006-11-01 12:23:50 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2006-11-01 12:23:50 -0800 |
commit | fb94c1210966f7875e5f034f10ea31c06c502c3a (patch) | |
tree | d7915f0f38b71d76cba50801aa7ed14b4ca3d442 | |
parent | f30d7f912f36b110c3af7dc795e35456593781ab (diff) |
Move mode lists from per-pipe to per-output.
This should let RandR do the right thing in exposing the modes to userland.
As a side effect of getting this working, the SDVO pixel clock range code
was fixed and the mode valid tests for various outputs got extended. Also,
LVDS grew a get_modes for the fixed panel mode.
Note that we now no longer do automatic enabling of outputs at xrandr -s 0,
hotkey, or VT switch. That will be left to generic RandR code later. Also,
generic modes and user-defined modes are once again not validated into the
lists, so this is a regression there.
-rw-r--r-- | src/i830.h | 2 | ||||
-rw-r--r-- | src/i830_crt.c | 41 | ||||
-rw-r--r-- | src/i830_display.c | 25 | ||||
-rw-r--r-- | src/i830_driver.c | 64 | ||||
-rw-r--r-- | src/i830_dvo.c | 5 | ||||
-rw-r--r-- | src/i830_lvds.c | 39 | ||||
-rw-r--r-- | src/i830_modes.c | 766 | ||||
-rw-r--r-- | src/i830_randr.c | 19 | ||||
-rw-r--r-- | src/i830_sdvo.c | 22 | ||||
-rw-r--r-- | src/i830_tv.c | 2 | ||||
-rw-r--r-- | src/i830_xf86Modes.c | 53 | ||||
-rw-r--r-- | src/i830_xf86Modes.h | 6 |
12 files changed, 332 insertions, 712 deletions
@@ -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); |