diff --git a/src/i830.h b/src/i830.h index 9bd02275..f1b97745 100644 --- a/src/i830.h +++ b/src/i830.h @@ -227,6 +227,10 @@ typedef struct _I830Rec { int fixedPipe; DisplayModePtr currentMode; + /* Mode saved during randr reprobe, which will need to be freed at the point + * of the next SwitchMode, when we lose this last reference to it. + */ + DisplayModePtr savedCurrentMode; Bool Clone; int CloneRefresh; @@ -401,8 +405,7 @@ typedef struct _I830Rec { int availablePipes; /* [0] is display plane A, [1] is display plane B. */ int planeEnabled[MAX_DISPLAY_PIPES]; - xf86MonPtr pipeMon[MAX_DISPLAY_PIPES]; - DisplayModePtr pipeModes[MAX_DISPLAY_PIPES]; + MonPtr pipeMon[MAX_DISPLAY_PIPES]; DisplayModeRec pipeCurMode[MAX_DISPLAY_PIPES]; /* Driver phase/state information */ diff --git a/src/i830_display.c b/src/i830_display.c index 8080c55c..24103cb7 100644 --- a/src/i830_display.c +++ b/src/i830_display.c @@ -268,11 +268,12 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) /* If we've got a list of modes probed for the device, find the best match * in there to the requested mode. */ - if (pI830->pipeModes[pipe] != NULL) { + if (pI830->pipeMon[pipe] != NULL) { DisplayModePtr pBest = NULL, pScan; assert(pScan->VRefresh != 0.0); - for (pScan = pI830->pipeModes[pipe]; pScan != NULL; pScan = pScan->next) + for (pScan = pI830->pipeMon[pipe]->Modes; pScan != NULL; + pScan = pScan->next) { /* Reject if it's larger than the desired mode. */ if (pScan->HDisplay > pMode->HDisplay || @@ -284,9 +285,20 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe) pBest = pScan; continue; } - /* Find if it's closer than the current best option */ - if ((pScan->HDisplay >= pBest->HDisplay && - pScan->HDisplay >= pBest->HDisplay) || + /* Find if it's closer to the right size than the current best + * option. + */ + if (pScan->HDisplay >= pBest->HDisplay && + pScan->VDisplay >= pBest->VDisplay) + { + pBest = pScan; + continue; + } + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (pScan->HDisplay == pBest->HDisplay && + pScan->VDisplay == pBest->VDisplay && (fabs(pScan->VRefresh - pMode->VRefresh) < fabs(pBest->VRefresh - pMode->VRefresh))) { @@ -801,6 +813,29 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode) (int)(pMode->HDisplay * pMode->VDisplay * pMode->VRefresh / 1000000)); + if (pI830->savedCurrentMode) { + /* We're done with the currentMode that the last randr probe had left + * behind, so free it. + */ + xfree(pI830->savedCurrentMode->name); + xfree(pI830->savedCurrentMode); + + /* If we might have enabled/disabled some pipes, we need to reset + * cloning mode support. + */ + if ((pI830->operatingDevices & 0x00ff) && + (pI830->operatingDevices & 0xff00)) + { + pI830->Clone = TRUE; + } else { + pI830->Clone = FALSE; + } + + /* If HW cursor currently showing, reset cursor state */ + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) + pI830->CursorInfoRec->ShowCursor(pScrn); + } + i830DisableUnusedFunctions(pScrn); planeA = INREG(DSPACNTR); diff --git a/src/i830_modes.c b/src/i830_modes.c index 893ef101..74333441 100644 --- a/src/i830_modes.c +++ b/src/i830_modes.c @@ -47,6 +47,7 @@ #include "xf86.h" #include "i830.h" +#include "i830_display.h" #include "i830_xf86Modes.h" #include @@ -247,7 +248,7 @@ I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i) } static DisplayModePtr -I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) +i830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) { DisplayModePtr last = NULL; DisplayModePtr new = NULL; @@ -487,9 +488,11 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName) /* If the user hasn't specified modes, add the native mode */ if (!count) { - first = last = i830FPNativeMode(pScrn); - if (first) + new = i830FPNativeMode(pScrn); + if (first) { + I830xf86SortModes(new, &first, &last); count = 1; + } } /* add in all default vesa modes smaller than panel size, used for randr */ @@ -507,14 +510,7 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName) else new->type |= M_T_DEFAULT; - new->next = NULL; - new->prev = last; - - if (last) - last->next = new; - last = new; - if (!first) - first = new; + I830xf86SortModes(new, &first, &last); count++; } @@ -546,9 +542,6 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, for (addMode = addModes; addMode != NULL; addMode = addMode->next) { DisplayModePtr pNew; - /* XXX: Do we need to check if modeList already contains the same mode? - */ - pNew = I830DuplicateMode(addMode); #if 0 /* If the user didn't specify any modes, mark all modes as M_T_USERDEF @@ -580,6 +573,102 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, return count; } +static DisplayModePtr +i830GetModeListTail(DisplayModePtr pModeList) +{ + DisplayModePtr last; + + if (pModeList == NULL) + return NULL; + + for (last = pModeList; last->next != NULL; last = last->next) + ; + + return last; +} + +static MonPtr +i830GetDDCMonitor(ScrnInfoPtr pScrn, I2CBusPtr pDDCBus) +{ + xf86MonPtr ddc; + MonPtr mon; + int i; + + ddc = xf86DoEDID_DDC2(pScrn->scrnIndex, pDDCBus); + + if (ddc == NULL) + return NULL; + + mon = xnfcalloc(1, sizeof(*mon)); + mon->Modes = i830GetDDCModes(pScrn, ddc); + mon->Last = i830GetModeListTail(mon->Modes); + mon->DDC = ddc; + + for (i = 0; i < DET_TIMINGS; i++) { + struct detailed_monitor_section *det_mon = &ddc->det_mon[i]; + + switch (ddc->det_mon[i].type) { + case DS_RANGES: + mon->hsync[mon->nHsync].lo = det_mon->section.ranges.min_h; + mon->hsync[mon->nHsync].hi = det_mon->section.ranges.max_h; + mon->nHsync++; + mon->vrefresh[mon->nVrefresh].lo = det_mon->section.ranges.min_v; + mon->vrefresh[mon->nVrefresh].hi = det_mon->section.ranges.max_v; + mon->nVrefresh++; + break; + default: + /* We probably don't care about trying to contruct ranges around + * modes specified by DDC. + */ + break; + } + } + + return mon; +} + +static MonPtr +i830GetLVDSMonitor(ScrnInfoPtr pScrn) +{ + MonPtr mon; + + mon = xnfcalloc(1, sizeof(*mon)); + mon->Modes = i830GetLVDSModes(pScrn, pScrn->display->modes); + mon->Last = i830GetModeListTail(mon->Modes); + + return mon; +} + +static MonPtr +i830GetConfiguredMonitor(ScrnInfoPtr pScrn) +{ + MonPtr mon; + + mon = xnfcalloc(1, sizeof(*mon)); + memcpy(mon, pScrn->monitor, sizeof(*mon)); + + if (pScrn->monitor->id != NULL) + mon->id = xnfstrdup(pScrn->monitor->id); + if (pScrn->monitor->vendor != NULL) + mon->vendor = xnfstrdup(pScrn->monitor->vendor); + if (pScrn->monitor->model != NULL) + mon->model = xnfstrdup(pScrn->monitor->model); + + return mon; +} + +static void +i830FreeMonitor(ScrnInfoPtr pScrn, MonPtr mon) +{ + while (mon->Modes != NULL) + xf86DeleteMode(&mon->Modes, mon->Modes); + xfree(mon->id); + xfree(mon->vendor); + xfree(mon->model); + xfree(mon->DDC); + xfree(mon); +} + /** * Performs probing of modes available on the output connected to the given * pipe. @@ -596,11 +685,7 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe) int i; int outputs; DisplayModePtr pMode; - Bool had_modes; - - had_modes = (pI830->pipeModes[pipe] != NULL); - while (pI830->pipeModes[pipe] != NULL) - xf86DeleteMode(&pI830->pipeModes[pipe], pI830->pipeModes[pipe]); + MonPtr old_mon = pI830->pipeMon[pipe]; if (pipe == 0) outputs = pI830->operatingDevices & 0xff; @@ -631,45 +716,87 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe) return; if (outputs & PIPE_LFP) { - pI830->pipeMon[pipe] = NULL; /* XXX */ - pI830->pipeModes[pipe] = i830GetLVDSModes(pScrn, - pScrn->display->modes); + pI830->pipeMon[pipe] = i830GetLVDSMonitor(pScrn); } else if (pI830->output[output_index].pDDCBus != NULL) { - /* XXX: Free the mon */ - pI830->pipeMon[pipe] = xf86DoEDID_DDC2(pScrn->scrnIndex, - pI830->output[output_index].pDDCBus); - pI830->pipeModes[pipe] = I830GetDDCModes(pScrn, - pI830->pipeMon[pipe]); - - for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next) - { - I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V); + 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; } - 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; - } - } else { - ErrorF("don't know how to get modes for this device.\n"); } - /* Set the vertical refresh, which is used by the choose-best-mode-per-pipe - * code later on. - */ #ifdef DEBUG_REPROBE xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing probed modes for pipe %d\n", pipe); #endif - for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next) { - pMode->VRefresh = I830ModeVRefresh(pMode); + if (pI830->pipeMon[pipe] != NULL) { + int minclock, maxclock; + + switch (pI830->output[output_index].type) { + case I830_OUTPUT_SDVO: + minclock = 25000; + maxclock = 165000; + case I830_OUTPUT_LVDS: + case I830_OUTPUT_ANALOG: + default: + minclock = 25000; + maxclock = 400000; + } + + i830xf86ValidateModesFlags(pScrn, pI830->pipeMon[pipe]->Modes, + V_INTERLACE); + i830xf86ValidateModesClocks(pScrn, pI830->pipeMon[pipe]->Modes, + &minclock, &maxclock, 1); + + i830xf86PruneInvalidModes(pScrn, &pI830->pipeMon[pipe]->Modes, TRUE); + + for (pMode = pI830->pipeMon[pipe]->Modes; pMode != NULL; + pMode = pMode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + + pMode->VRefresh = I830ModeVRefresh(pMode); + I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V); #ifdef DEBUG_REPROBE - PrintModeline(pScrn->scrnIndex, pMode); + PrintModeline(pScrn->scrnIndex, pMode); #endif + } } + + if (old_mon != NULL && pI830->pipeMon[pipe] == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Failed to probe output on pipe %d, disabling output at next " + "mode switch\n", pipe); + if (pipe == 0) + pI830->operatingDevices &= ~0x00ff; + else + pI830->operatingDevices &= ~0xff00; + } + + if (old_mon != NULL) + i830FreeMonitor(pScrn, old_mon); } /** @@ -720,10 +847,8 @@ int I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) { I830Ptr pI830 = I830PTR(pScrn); - ClockRangePtr clockRanges; - int n, pipe; - DisplayModePtr saved_mode, availModes = NULL; - int saved_virtualX = 0, saved_virtualY = 0, saved_displayWidth = 0; + int pipe; + DisplayModePtr saved_mode, last; Bool pipes_reconfigured = FALSE; int originalVirtualX, originalVirtualY; @@ -738,7 +863,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) if ((pI830->operatingDevices & 0xff) == PIPE_NONE) { pI830->operatingDevices |= PIPE_CRT; I830ReprobePipeModeList(pScrn, 0); - if (pI830->pipeModes[0] == NULL) { + if (pI830->pipeMon[0] == NULL) { /* No new output found. */ pI830->operatingDevices &= ~PIPE_CRT; } else { @@ -751,7 +876,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) } else if (((pI830->operatingDevices >> 8) & 0xff) == PIPE_NONE) { pI830->operatingDevices |= PIPE_CRT << 8; I830ReprobePipeModeList(pScrn, 1); - if (pI830->pipeModes[1] == NULL) { + if (pI830->pipeMon[1] == NULL) { /* No new output found. */ pI830->operatingDevices &= ~(PIPE_CRT << 8); } else { @@ -764,20 +889,105 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) } } - /* Start by injecting the XFree86 default modes and user-configured - * modelines. XXX: This actually isn't of use if we've got any DDC, as DDC - * currently has higher priority than the validated modelist. We need to - * deal with that. - */ - I830InjectProbedModes(pScrn, &availModes, pScrn->monitor->Modes); - if (pI830->pipeModes[0] != NULL) { - I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[0]); - } - if (pI830->pipeModes[1] != NULL) { - I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[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. + */ + 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; + } + + I830GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); + + /* Disable modes that are larger than the virtual size we decided on + * initially. + */ + 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. + */ + saved_mode = pI830->currentMode; + if (saved_mode != NULL) { + I830xf86DeleteModeFromList(&pScrn->modes, saved_mode); + } + + /* 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. + */ + if (pI830->pipeMon[1] != NULL) { + I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[1]->Modes); + } else { + I830InjectProbedModes(pScrn, &pScrn->modes, pI830->pipeMon[0]->Modes); + } + if (pScrn->modes == NULL) { + FatalError("No modes found\n"); + } + + /* Don't let pScrn->modes have modes larger than the max root window size. + * We don't really care about the monitors having it, particularly since we + * eventually want randr to be able to move to those sizes. + */ + i830xf86ValidateModesSize(pScrn, pScrn->modes, + originalVirtualX, originalVirtualY, + pScrn->displayWidth); + + /* Strip out anything bad that we threw out for virtualX. */ + i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); + + /* For some reason, pScrn->modes is circular, unlike the other mode lists. + * How great is that? + */ + last = i830GetModeListTail(pScrn->modes); + last->next = pScrn->modes; + pScrn->modes->prev = last; + +#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. */ @@ -788,62 +998,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) clockRanges->clockIndex = -1; /* programmable */ clockRanges->interlaceAllowed = TRUE; /* XXX check this */ clockRanges->doubleScanAllowed = FALSE; /* XXX check this */ - - /* Remove the current mode from the modelist if we're re-validating, so we - * can find a new mode to map ourselves to afterwards. - */ - saved_mode = pI830->currentMode; - if (saved_mode != NULL) { - 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. - */ - n = xf86ValidateModes(pScrn, - availModes, /* availModes */ - pScrn->display->modes, /* modeNames */ - clockRanges, /* clockRanges */ - !first_time ? &pScrn->displayWidth : NULL, /* linePitches */ - 320, /* minPitch */ - MAX_DISPLAY_PITCH, /* maxPitch */ - 64 * pScrn->bitsPerPixel, /* pitchInc */ - 200, /* minHeight */ - MAX_DISPLAY_HEIGHT, /* maxHeight */ - originalVirtualX, /* virtualX maximum */ - originalVirtualY, /* virtualY maximum */ - pI830->FbMapSize, /* apertureSize */ - LOOKUP_BEST_REFRESH /* strategy */); - - /* availModes is of no more use as xf86ValidateModes has duplicated and - * saved everything it needs. - */ - while (availModes != NULL) - xf86DeleteMode(&availModes, availModes); - - if (!first_time) { - /* Restore things that may have been damaged by xf86ValidateModes. */ - pScrn->virtualX = saved_virtualX; - pScrn->virtualY = saved_virtualY; - pScrn->displayWidth = saved_displayWidth; - } - - /* Need to do xf86CrtcForModes so any user-configured modes are valid for - * non-LVDS. - */ - xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); - - xf86PruneDriverModes(pScrn); +#endif #if DEBUG_REPROBE xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Modes post revalidate\n"); @@ -858,49 +1013,12 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) } while (0); #endif - /* Try to find the closest equivalent of the previous mode pointer to switch - * to. + /* 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 (saved_mode != NULL) { - DisplayModePtr pBestMode = NULL, pMode; + pI830->savedCurrentMode = saved_mode; - /* 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. - */ - 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); - } - - return n; + return 1; /* XXX */ } diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c index 16a8cd83..6f620c81 100644 --- a/src/i830_xf86Modes.c +++ b/src/i830_xf86Modes.c @@ -238,6 +238,126 @@ PrintModeline(int scrnIndex,DisplayModePtr mode) xfree(flags); } +/** + * Marks as bad any modes with unsupported flags. + * + * \param modeList doubly-linked or circular list of modes. + * \param flags flags supported by the driver. + * + * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +void +i830xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int flags) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) + mode->status = MODE_NO_INTERLACE; + if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) + mode->status = MODE_NO_DBLESCAN; + } +} + +/** + * Marks as bad any modes extending beyond the given max X, Y, or pitch. + * + * \param modeList doubly-linked or circular list of modes. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +void +i830xf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int maxX, int maxY, int maxPitch) +{ + DisplayModePtr mode; + + for (mode = modeList; mode != NULL; mode = mode->next) { + if (maxPitch > 0 && mode->HDisplay > maxPitch) + mode->status = MODE_BAD_WIDTH; + + if (maxX > 0 && mode->HDisplay > maxX) + mode->status = MODE_VIRTUAL_X; + + if (maxY > 0 && mode->VDisplay > maxY) + mode->status = MODE_VIRTUAL_Y; + + if (mode->next == modeList) + break; + } +} + +/** + * Marks as bad any modes extending beyond outside of the given clock ranges. + * + * \param modeList doubly-linked or circular list of modes. + * \param min pointer to minimums of clock ranges + * \param max pointer to maximums of clock ranges + * \param n_ranges number of ranges. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +void +i830xf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, + int *min, int *max, int n_ranges) +{ + DisplayModePtr mode; + int i; + + for (mode = modeList; mode != NULL; mode = mode->next) { + Bool good = FALSE; + for (i = 0; i < n_ranges; i++) { + if (mode->Clock >= min[i] && mode->Clock <= max[i]) { + good = TRUE; + break; + } + } + if (!good) + mode->status = MODE_CLOCK_RANGE; + } +} + +/** + * Frees any modes from the list with a status other than MODE_OK. + * + * \param modeList pointer to a doubly-linked or circular list of modes. + * \param verbose determines whether the reason for mode invalidation is + * printed. + * + * This is not in xf86Modes.c, but would be part of the proposed new API. + */ +void +i830xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + Bool verbose) +{ + DisplayModePtr mode; + + for (mode = *modeList; mode != NULL;) { + DisplayModePtr next = mode->next; + + if (mode->status != MODE_OK) { + if (verbose) { + char *type = ""; + if (mode->type & M_T_BUILTIN) + type = "built-in "; + else if (mode->type & M_T_DEFAULT) + type = "default "; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not using %smode \"%s\" (%s)\n", type, mode->name, + xf86ModeStatusToString(mode->status)); + } + xf86DeleteMode(modeList, mode); + } + + if (next == *modeList) + break; + mode = next; + } +} + #define MODEPREFIX(name) NULL, NULL, name, MODE_OK, M_T_DEFAULT #define MODESUFFIX 0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h index ba7d8209..86e5b060 100644 --- a/src/i830_xf86Modes.h +++ b/src/i830_xf86Modes.h @@ -34,6 +34,26 @@ I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags); 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);