1706f2543Smrg/* 2706f2543Smrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 3706f2543Smrg * 4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5706f2543Smrg * copy of this software and associated documentation files (the "Software"), 6706f2543Smrg * to deal in the Software without restriction, including without limitation 7706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the 9706f2543Smrg * Software is furnished to do so, subject to the following conditions: 10706f2543Smrg * 11706f2543Smrg * The above copyright notice and this permission notice shall be included in 12706f2543Smrg * all copies or substantial portions of the Software. 13706f2543Smrg * 14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE. 21706f2543Smrg * 22706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s) 23706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote 24706f2543Smrg * the sale, use or other dealings in this Software without prior written 25706f2543Smrg * authorization from the copyright holder(s) and author(s). 26706f2543Smrg */ 27706f2543Smrg 28706f2543Smrg#ifdef HAVE_XORG_CONFIG_H 29706f2543Smrg#include <xorg-config.h> 30706f2543Smrg#else 31706f2543Smrg#ifdef HAVE_CONFIG_H 32706f2543Smrg#include <config.h> 33706f2543Smrg#endif 34706f2543Smrg#endif 35706f2543Smrg 36706f2543Smrg#include "xf86Modes.h" 37706f2543Smrg#include "xf86Priv.h" 38706f2543Smrg 39706f2543Smrgextern XF86ConfigPtr xf86configptr; 40706f2543Smrg 41706f2543Smrg/** 42706f2543Smrg * Calculates the horizontal sync rate of a mode. 43706f2543Smrg */ 44706f2543Smrgdouble 45706f2543Smrgxf86ModeHSync(const DisplayModeRec *mode) 46706f2543Smrg{ 47706f2543Smrg double hsync = 0.0; 48706f2543Smrg 49706f2543Smrg if (mode->HSync > 0.0) 50706f2543Smrg hsync = mode->HSync; 51706f2543Smrg else if (mode->HTotal > 0) 52706f2543Smrg hsync = (float)mode->Clock / (float)mode->HTotal; 53706f2543Smrg 54706f2543Smrg return hsync; 55706f2543Smrg} 56706f2543Smrg 57706f2543Smrg/** 58706f2543Smrg * Calculates the vertical refresh rate of a mode. 59706f2543Smrg */ 60706f2543Smrgdouble 61706f2543Smrgxf86ModeVRefresh(const DisplayModeRec *mode) 62706f2543Smrg{ 63706f2543Smrg double refresh = 0.0; 64706f2543Smrg 65706f2543Smrg if (mode->VRefresh > 0.0) 66706f2543Smrg refresh = mode->VRefresh; 67706f2543Smrg else if (mode->HTotal > 0 && mode->VTotal > 0) { 68706f2543Smrg refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; 69706f2543Smrg if (mode->Flags & V_INTERLACE) 70706f2543Smrg refresh *= 2.0; 71706f2543Smrg if (mode->Flags & V_DBLSCAN) 72706f2543Smrg refresh /= 2.0; 73706f2543Smrg if (mode->VScan > 1) 74706f2543Smrg refresh /= (float)(mode->VScan); 75706f2543Smrg } 76706f2543Smrg return refresh; 77706f2543Smrg} 78706f2543Smrg 79706f2543Smrgint 80706f2543Smrgxf86ModeWidth (const DisplayModeRec *mode, Rotation rotation) 81706f2543Smrg{ 82706f2543Smrg switch (rotation & 0xf) { 83706f2543Smrg case RR_Rotate_0: 84706f2543Smrg case RR_Rotate_180: 85706f2543Smrg return mode->HDisplay; 86706f2543Smrg case RR_Rotate_90: 87706f2543Smrg case RR_Rotate_270: 88706f2543Smrg return mode->VDisplay; 89706f2543Smrg default: 90706f2543Smrg return 0; 91706f2543Smrg } 92706f2543Smrg} 93706f2543Smrg 94706f2543Smrgint 95706f2543Smrgxf86ModeHeight (const DisplayModeRec *mode, Rotation rotation) 96706f2543Smrg{ 97706f2543Smrg switch (rotation & 0xf) { 98706f2543Smrg case RR_Rotate_0: 99706f2543Smrg case RR_Rotate_180: 100706f2543Smrg return mode->VDisplay; 101706f2543Smrg case RR_Rotate_90: 102706f2543Smrg case RR_Rotate_270: 103706f2543Smrg return mode->HDisplay; 104706f2543Smrg default: 105706f2543Smrg return 0; 106706f2543Smrg } 107706f2543Smrg} 108706f2543Smrg 109706f2543Smrg/** Calculates the memory bandwidth (in MiB/sec) of a mode. */ 110706f2543Smrgunsigned int 111706f2543Smrgxf86ModeBandwidth(DisplayModePtr mode, int depth) 112706f2543Smrg{ 113706f2543Smrg float a_active, a_total, active_percent, pixels_per_second; 114706f2543Smrg int bytes_per_pixel = bits_to_bytes(depth); 115706f2543Smrg 116706f2543Smrg if (!mode->HTotal || !mode->VTotal || !mode->Clock) 117706f2543Smrg return 0; 118706f2543Smrg 119706f2543Smrg a_active = mode->HDisplay * mode->VDisplay; 120706f2543Smrg a_total = mode->HTotal * mode->VTotal; 121706f2543Smrg active_percent = a_active / a_total; 122706f2543Smrg pixels_per_second = active_percent * mode->Clock * 1000.0; 123706f2543Smrg 124706f2543Smrg return (unsigned int)(pixels_per_second * bytes_per_pixel / (1024 * 1024)); 125706f2543Smrg} 126706f2543Smrg 127706f2543Smrg/** Sets a default mode name of <width>x<height> on a mode. */ 128706f2543Smrgvoid 129706f2543Smrgxf86SetModeDefaultName(DisplayModePtr mode) 130706f2543Smrg{ 131706f2543Smrg Bool interlaced = !!(mode->Flags & V_INTERLACE); 132706f2543Smrg 133706f2543Smrg free(mode->name); 134706f2543Smrg 135706f2543Smrg XNFasprintf(&mode->name, "%dx%d%s", mode->HDisplay, mode->VDisplay, 136706f2543Smrg interlaced ? "i" : ""); 137706f2543Smrg} 138706f2543Smrg 139706f2543Smrg/* 140706f2543Smrg * xf86SetModeCrtc 141706f2543Smrg * 142706f2543Smrg * Initialises the Crtc parameters for a mode. The initialisation includes 143706f2543Smrg * adjustments for interlaced and double scan modes. 144706f2543Smrg */ 145706f2543Smrgvoid 146706f2543Smrgxf86SetModeCrtc(DisplayModePtr p, int adjustFlags) 147706f2543Smrg{ 148706f2543Smrg if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) 149706f2543Smrg return; 150706f2543Smrg 151706f2543Smrg p->CrtcHDisplay = p->HDisplay; 152706f2543Smrg p->CrtcHSyncStart = p->HSyncStart; 153706f2543Smrg p->CrtcHSyncEnd = p->HSyncEnd; 154706f2543Smrg p->CrtcHTotal = p->HTotal; 155706f2543Smrg p->CrtcHSkew = p->HSkew; 156706f2543Smrg p->CrtcVDisplay = p->VDisplay; 157706f2543Smrg p->CrtcVSyncStart = p->VSyncStart; 158706f2543Smrg p->CrtcVSyncEnd = p->VSyncEnd; 159706f2543Smrg p->CrtcVTotal = p->VTotal; 160706f2543Smrg if (p->Flags & V_INTERLACE) { 161706f2543Smrg if (adjustFlags & INTERLACE_HALVE_V) { 162706f2543Smrg p->CrtcVDisplay /= 2; 163706f2543Smrg p->CrtcVSyncStart /= 2; 164706f2543Smrg p->CrtcVSyncEnd /= 2; 165706f2543Smrg p->CrtcVTotal /= 2; 166706f2543Smrg } 167706f2543Smrg /* Force interlaced modes to have an odd VTotal */ 168706f2543Smrg /* maybe we should only do this when INTERLACE_HALVE_V is set? */ 169706f2543Smrg p->CrtcVTotal |= 1; 170706f2543Smrg } 171706f2543Smrg 172706f2543Smrg if (p->Flags & V_DBLSCAN) { 173706f2543Smrg p->CrtcVDisplay *= 2; 174706f2543Smrg p->CrtcVSyncStart *= 2; 175706f2543Smrg p->CrtcVSyncEnd *= 2; 176706f2543Smrg p->CrtcVTotal *= 2; 177706f2543Smrg } 178706f2543Smrg if (p->VScan > 1) { 179706f2543Smrg p->CrtcVDisplay *= p->VScan; 180706f2543Smrg p->CrtcVSyncStart *= p->VScan; 181706f2543Smrg p->CrtcVSyncEnd *= p->VScan; 182706f2543Smrg p->CrtcVTotal *= p->VScan; 183706f2543Smrg } 184706f2543Smrg p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); 185706f2543Smrg p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); 186706f2543Smrg p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); 187706f2543Smrg p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); 188706f2543Smrg 189706f2543Smrg p->CrtcHAdjusted = FALSE; 190706f2543Smrg p->CrtcVAdjusted = FALSE; 191706f2543Smrg} 192706f2543Smrg 193706f2543Smrg/** 194706f2543Smrg * Allocates and returns a copy of pMode, including pointers within pMode. 195706f2543Smrg */ 196706f2543SmrgDisplayModePtr 197706f2543Smrgxf86DuplicateMode(const DisplayModeRec *pMode) 198706f2543Smrg{ 199706f2543Smrg DisplayModePtr pNew; 200706f2543Smrg 201706f2543Smrg pNew = xnfalloc(sizeof(DisplayModeRec)); 202706f2543Smrg *pNew = *pMode; 203706f2543Smrg pNew->next = NULL; 204706f2543Smrg pNew->prev = NULL; 205706f2543Smrg 206706f2543Smrg if (pMode->name == NULL) 207706f2543Smrg xf86SetModeDefaultName(pNew); 208706f2543Smrg else 209706f2543Smrg pNew->name = xnfstrdup(pMode->name); 210706f2543Smrg 211706f2543Smrg return pNew; 212706f2543Smrg} 213706f2543Smrg 214706f2543Smrg/** 215706f2543Smrg * Duplicates every mode in the given list and returns a pointer to the first 216706f2543Smrg * mode. 217706f2543Smrg * 218706f2543Smrg * \param modeList doubly-linked mode list 219706f2543Smrg */ 220706f2543SmrgDisplayModePtr 221706f2543Smrgxf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) 222706f2543Smrg{ 223706f2543Smrg DisplayModePtr first = NULL, last = NULL; 224706f2543Smrg DisplayModePtr mode; 225706f2543Smrg 226706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 227706f2543Smrg DisplayModePtr new; 228706f2543Smrg 229706f2543Smrg new = xf86DuplicateMode(mode); 230706f2543Smrg 231706f2543Smrg /* Insert pNew into modeList */ 232706f2543Smrg if (last) { 233706f2543Smrg last->next = new; 234706f2543Smrg new->prev = last; 235706f2543Smrg } else { 236706f2543Smrg first = new; 237706f2543Smrg new->prev = NULL; 238706f2543Smrg } 239706f2543Smrg new->next = NULL; 240706f2543Smrg last = new; 241706f2543Smrg } 242706f2543Smrg 243706f2543Smrg return first; 244706f2543Smrg} 245706f2543Smrg 246706f2543Smrg/** 247706f2543Smrg * Returns true if the given modes should program to the same timings. 248706f2543Smrg * 249706f2543Smrg * This doesn't use Crtc values, as it might be used on ModeRecs without the 250706f2543Smrg * Crtc values set. So, it's assumed that the other numbers are enough. 251706f2543Smrg */ 252706f2543SmrgBool 253706f2543Smrgxf86ModesEqual(const DisplayModeRec *pMode1, const DisplayModeRec *pMode2) 254706f2543Smrg{ 255706f2543Smrg if (pMode1->Clock == pMode2->Clock && 256706f2543Smrg pMode1->HDisplay == pMode2->HDisplay && 257706f2543Smrg pMode1->HSyncStart == pMode2->HSyncStart && 258706f2543Smrg pMode1->HSyncEnd == pMode2->HSyncEnd && 259706f2543Smrg pMode1->HTotal == pMode2->HTotal && 260706f2543Smrg pMode1->HSkew == pMode2->HSkew && 261706f2543Smrg pMode1->VDisplay == pMode2->VDisplay && 262706f2543Smrg pMode1->VSyncStart == pMode2->VSyncStart && 263706f2543Smrg pMode1->VSyncEnd == pMode2->VSyncEnd && 264706f2543Smrg pMode1->VTotal == pMode2->VTotal && 265706f2543Smrg pMode1->VScan == pMode2->VScan && 266706f2543Smrg pMode1->Flags == pMode2->Flags) 267706f2543Smrg { 268706f2543Smrg return TRUE; 269706f2543Smrg } else { 270706f2543Smrg return FALSE; 271706f2543Smrg } 272706f2543Smrg} 273706f2543Smrg 274706f2543Smrgstatic void 275706f2543Smrgadd(char **p, char *new) 276706f2543Smrg{ 277706f2543Smrg *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); 278706f2543Smrg strcat(*p, " "); 279706f2543Smrg strcat(*p, new); 280706f2543Smrg} 281706f2543Smrg 282706f2543Smrg/** 283706f2543Smrg * Print out a modeline. 284706f2543Smrg */ 285706f2543Smrgvoid 286706f2543Smrgxf86PrintModeline(int scrnIndex,DisplayModePtr mode) 287706f2543Smrg{ 288706f2543Smrg char tmp[256]; 289706f2543Smrg char *flags = xnfcalloc(1, 1); 290706f2543Smrg 291706f2543Smrg if (mode->HSkew) { 292706f2543Smrg snprintf(tmp, 256, "hskew %i", mode->HSkew); 293706f2543Smrg add(&flags, tmp); 294706f2543Smrg } 295706f2543Smrg if (mode->VScan) { 296706f2543Smrg snprintf(tmp, 256, "vscan %i", mode->VScan); 297706f2543Smrg add(&flags, tmp); 298706f2543Smrg } 299706f2543Smrg if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); 300706f2543Smrg if (mode->Flags & V_CSYNC) add(&flags, "composite"); 301706f2543Smrg if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); 302706f2543Smrg if (mode->Flags & V_BCAST) add(&flags, "bcast"); 303706f2543Smrg if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); 304706f2543Smrg if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); 305706f2543Smrg if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); 306706f2543Smrg if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); 307706f2543Smrg if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); 308706f2543Smrg if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); 309706f2543Smrg#if 0 310706f2543Smrg if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); 311706f2543Smrg#endif 312706f2543Smrg xf86DrvMsg(scrnIndex, X_INFO, 313706f2543Smrg "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s " 314706f2543Smrg "(%.01f kHz)\n", 315706f2543Smrg mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay, 316706f2543Smrg mode->HSyncStart, mode->HSyncEnd, mode->HTotal, 317706f2543Smrg mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, 318706f2543Smrg mode->VTotal, flags, xf86ModeHSync(mode)); 319706f2543Smrg free(flags); 320706f2543Smrg} 321706f2543Smrg 322706f2543Smrg/** 323706f2543Smrg * Marks as bad any modes with unsupported flags. 324706f2543Smrg * 325706f2543Smrg * \param modeList doubly-linked list of modes. 326706f2543Smrg * \param flags flags supported by the driver. 327706f2543Smrg * 328706f2543Smrg * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? 329706f2543Smrg */ 330706f2543Smrgvoid 331706f2543Smrgxf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, 332706f2543Smrg int flags) 333706f2543Smrg{ 334706f2543Smrg DisplayModePtr mode; 335706f2543Smrg 336706f2543Smrg if (flags == (V_INTERLACE | V_DBLSCAN)) 337706f2543Smrg return; 338706f2543Smrg 339706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 340706f2543Smrg if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) 341706f2543Smrg mode->status = MODE_NO_INTERLACE; 342706f2543Smrg if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) 343706f2543Smrg mode->status = MODE_NO_DBLESCAN; 344706f2543Smrg } 345706f2543Smrg} 346706f2543Smrg 347706f2543Smrg/** 348706f2543Smrg * Marks as bad any modes extending beyond the given max X, Y, or pitch. 349706f2543Smrg * 350706f2543Smrg * \param modeList doubly-linked list of modes. 351706f2543Smrg */ 352706f2543Smrgvoid 353706f2543Smrgxf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, 354706f2543Smrg int maxX, int maxY, int maxPitch) 355706f2543Smrg{ 356706f2543Smrg DisplayModePtr mode; 357706f2543Smrg 358706f2543Smrg if (maxPitch <= 0) 359706f2543Smrg maxPitch = MAXINT; 360706f2543Smrg if (maxX <= 0) 361706f2543Smrg maxX = MAXINT; 362706f2543Smrg if (maxY <= 0) 363706f2543Smrg maxY = MAXINT; 364706f2543Smrg 365706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 366706f2543Smrg if ((xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 367706f2543Smrg xf86ModeWidth(mode, RR_Rotate_0) > maxX || 368706f2543Smrg xf86ModeHeight(mode, RR_Rotate_0) > maxY) && 369706f2543Smrg (xf86ModeWidth(mode, RR_Rotate_90) > maxPitch || 370706f2543Smrg xf86ModeWidth(mode, RR_Rotate_90) > maxX || 371706f2543Smrg xf86ModeHeight(mode, RR_Rotate_90) > maxY)) { 372706f2543Smrg if (xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 373706f2543Smrg xf86ModeWidth(mode, RR_Rotate_90) > maxPitch) 374706f2543Smrg mode->status = MODE_BAD_WIDTH; 375706f2543Smrg 376706f2543Smrg if (xf86ModeWidth(mode, RR_Rotate_0) > maxX || 377706f2543Smrg xf86ModeWidth(mode, RR_Rotate_90) > maxX) 378706f2543Smrg mode->status = MODE_VIRTUAL_X; 379706f2543Smrg 380706f2543Smrg if (xf86ModeHeight(mode, RR_Rotate_0) > maxY || 381706f2543Smrg xf86ModeHeight(mode, RR_Rotate_90) > maxY) 382706f2543Smrg mode->status = MODE_VIRTUAL_Y; 383706f2543Smrg } 384706f2543Smrg 385706f2543Smrg if (mode->next == modeList) 386706f2543Smrg break; 387706f2543Smrg } 388706f2543Smrg} 389706f2543Smrg 390706f2543Smrg/** 391706f2543Smrg * Marks as bad any modes that aren't supported by the given monitor's 392706f2543Smrg * hsync and vrefresh ranges. 393706f2543Smrg * 394706f2543Smrg * \param modeList doubly-linked list of modes. 395706f2543Smrg */ 396706f2543Smrgvoid 397706f2543Smrgxf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, 398706f2543Smrg MonPtr mon) 399706f2543Smrg{ 400706f2543Smrg DisplayModePtr mode; 401706f2543Smrg 402706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 403706f2543Smrg Bool bad; 404706f2543Smrg int i; 405706f2543Smrg 406706f2543Smrg bad = TRUE; 407706f2543Smrg for (i = 0; i < mon->nHsync; i++) { 408706f2543Smrg if (xf86ModeHSync(mode) >= mon->hsync[i].lo * (1-SYNC_TOLERANCE) && 409706f2543Smrg xf86ModeHSync(mode) <= mon->hsync[i].hi * (1+SYNC_TOLERANCE)) 410706f2543Smrg { 411706f2543Smrg bad = FALSE; 412706f2543Smrg } 413706f2543Smrg } 414706f2543Smrg if (bad) 415706f2543Smrg mode->status = MODE_HSYNC; 416706f2543Smrg 417706f2543Smrg bad = TRUE; 418706f2543Smrg for (i = 0; i < mon->nVrefresh; i++) { 419706f2543Smrg if (xf86ModeVRefresh(mode) >= mon->vrefresh[i].lo * (1-SYNC_TOLERANCE) && 420706f2543Smrg xf86ModeVRefresh(mode) <= mon->vrefresh[i].hi * (1+SYNC_TOLERANCE)) 421706f2543Smrg { 422706f2543Smrg bad = FALSE; 423706f2543Smrg } 424706f2543Smrg } 425706f2543Smrg if (bad) 426706f2543Smrg mode->status = MODE_VSYNC; 427706f2543Smrg 428706f2543Smrg if (mode->next == modeList) 429706f2543Smrg break; 430706f2543Smrg } 431706f2543Smrg} 432706f2543Smrg 433706f2543Smrg/** 434706f2543Smrg * Marks as bad any modes extending beyond outside of the given clock ranges. 435706f2543Smrg * 436706f2543Smrg * \param modeList doubly-linked list of modes. 437706f2543Smrg * \param min pointer to minimums of clock ranges 438706f2543Smrg * \param max pointer to maximums of clock ranges 439706f2543Smrg * \param n_ranges number of ranges. 440706f2543Smrg */ 441706f2543Smrgvoid 442706f2543Smrgxf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, 443706f2543Smrg int *min, int *max, int n_ranges) 444706f2543Smrg{ 445706f2543Smrg DisplayModePtr mode; 446706f2543Smrg int i; 447706f2543Smrg 448706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 449706f2543Smrg Bool good = FALSE; 450706f2543Smrg for (i = 0; i < n_ranges; i++) { 451706f2543Smrg if (mode->Clock >= min[i] * (1-SYNC_TOLERANCE) && 452706f2543Smrg mode->Clock <= max[i] * (1+SYNC_TOLERANCE)) { 453706f2543Smrg good = TRUE; 454706f2543Smrg break; 455706f2543Smrg } 456706f2543Smrg } 457706f2543Smrg if (!good) 458706f2543Smrg mode->status = MODE_CLOCK_RANGE; 459706f2543Smrg } 460706f2543Smrg} 461706f2543Smrg 462706f2543Smrg/** 463706f2543Smrg * If the user has specified a set of mode names to use, mark as bad any modes 464706f2543Smrg * not listed. 465706f2543Smrg * 466706f2543Smrg * The user mode names specified are prefixes to names of modes, so "1024x768" 467706f2543Smrg * will match modes named "1024x768", "1024x768x75", "1024x768-good", but 468706f2543Smrg * "1024x768x75" would only match "1024x768x75" from that list. 469706f2543Smrg * 470706f2543Smrg * MODE_BAD is used as the rejection flag, for lack of a better flag. 471706f2543Smrg * 472706f2543Smrg * \param modeList doubly-linked list of modes. 473706f2543Smrg */ 474706f2543Smrgvoid 475706f2543Smrgxf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) 476706f2543Smrg{ 477706f2543Smrg DisplayModePtr mode; 478706f2543Smrg 479706f2543Smrg if (pScrn->display->modes[0] == NULL) 480706f2543Smrg return; 481706f2543Smrg 482706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 483706f2543Smrg int i; 484706f2543Smrg Bool good = FALSE; 485706f2543Smrg 486706f2543Smrg for (i = 0; pScrn->display->modes[i] != NULL; i++) { 487706f2543Smrg if (strncmp(pScrn->display->modes[i], mode->name, 488706f2543Smrg strlen(pScrn->display->modes[i])) == 0) { 489706f2543Smrg good = TRUE; 490706f2543Smrg break; 491706f2543Smrg } 492706f2543Smrg } 493706f2543Smrg if (!good) 494706f2543Smrg mode->status = MODE_BAD; 495706f2543Smrg } 496706f2543Smrg} 497706f2543Smrg 498706f2543Smrg 499706f2543Smrg/** 500706f2543Smrg * Marks as bad any modes exceeding the given bandwidth. 501706f2543Smrg * 502706f2543Smrg * \param modeList doubly-linked list of modes. 503706f2543Smrg * \param bandwidth bandwidth in MHz. 504706f2543Smrg * \param depth color depth. 505706f2543Smrg */ 506706f2543Smrgvoid 507706f2543Smrgxf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList, 508706f2543Smrg unsigned int bandwidth, int depth) 509706f2543Smrg{ 510706f2543Smrg DisplayModePtr mode; 511706f2543Smrg 512706f2543Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 513706f2543Smrg if (xf86ModeBandwidth(mode, depth) > bandwidth) 514706f2543Smrg mode->status = MODE_BANDWIDTH; 515706f2543Smrg } 516706f2543Smrg} 517706f2543Smrg 518706f2543SmrgBool 519706f2543Smrgxf86ModeIsReduced(const DisplayModeRec *mode) 520706f2543Smrg{ 521706f2543Smrg if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) && 522706f2543Smrg ((mode->HTotal - mode->HDisplay) == 160) && 523706f2543Smrg ((mode->HSyncEnd - mode->HDisplay) == 80) && 524706f2543Smrg ((mode->HSyncEnd - mode->HSyncStart) == 32) && 525706f2543Smrg ((mode->VSyncStart - mode->VDisplay) == 3)) 526706f2543Smrg return TRUE; 527706f2543Smrg return FALSE; 528706f2543Smrg} 529706f2543Smrg 530706f2543Smrg/** 531706f2543Smrg * Marks as bad any reduced-blanking modes. 532706f2543Smrg * 533706f2543Smrg * \param modeList doubly-linked list of modes. 534706f2543Smrg */ 535706f2543Smrgvoid 536706f2543Smrgxf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn, DisplayModePtr modeList) 537706f2543Smrg{ 538706f2543Smrg for (; modeList != NULL; modeList = modeList->next) 539706f2543Smrg if (xf86ModeIsReduced(modeList)) 540706f2543Smrg modeList->status = MODE_NO_REDUCED; 541706f2543Smrg} 542706f2543Smrg 543706f2543Smrg/** 544706f2543Smrg * Frees any modes from the list with a status other than MODE_OK. 545706f2543Smrg * 546706f2543Smrg * \param modeList pointer to a doubly-linked or circular list of modes. 547706f2543Smrg * \param verbose determines whether the reason for mode invalidation is 548706f2543Smrg * printed. 549706f2543Smrg */ 550706f2543Smrgvoid 551706f2543Smrgxf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, 552706f2543Smrg Bool verbose) 553706f2543Smrg{ 554706f2543Smrg DisplayModePtr mode; 555706f2543Smrg 556706f2543Smrg for (mode = *modeList; mode != NULL;) { 557706f2543Smrg DisplayModePtr next = mode->next, first = *modeList; 558706f2543Smrg 559706f2543Smrg if (mode->status != MODE_OK) { 560706f2543Smrg if (verbose) { 561706f2543Smrg char *type = ""; 562706f2543Smrg if (mode->type & M_T_BUILTIN) 563706f2543Smrg type = "built-in "; 564706f2543Smrg else if (mode->type & M_T_DEFAULT) 565706f2543Smrg type = "default "; 566706f2543Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 567706f2543Smrg "Not using %smode \"%s\" (%s)\n", type, mode->name, 568706f2543Smrg xf86ModeStatusToString(mode->status)); 569706f2543Smrg } 570706f2543Smrg xf86DeleteMode(modeList, mode); 571706f2543Smrg } 572706f2543Smrg 573706f2543Smrg if (next == first) 574706f2543Smrg break; 575706f2543Smrg mode = next; 576706f2543Smrg } 577706f2543Smrg} 578706f2543Smrg 579706f2543Smrg/** 580706f2543Smrg * Adds the new mode into the mode list, and returns the new list 581706f2543Smrg * 582706f2543Smrg * \param modes doubly-linked mode list. 583706f2543Smrg */ 584706f2543SmrgDisplayModePtr 585706f2543Smrgxf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) 586706f2543Smrg{ 587706f2543Smrg if (modes == NULL) 588706f2543Smrg return new; 589706f2543Smrg 590706f2543Smrg if (new) { 591706f2543Smrg DisplayModePtr mode = modes; 592706f2543Smrg 593706f2543Smrg while (mode->next) 594706f2543Smrg mode = mode->next; 595706f2543Smrg 596706f2543Smrg mode->next = new; 597706f2543Smrg new->prev = mode; 598706f2543Smrg } 599706f2543Smrg 600706f2543Smrg return modes; 601706f2543Smrg} 602706f2543Smrg 603706f2543Smrg/** 604706f2543Smrg * Build a mode list from a list of config file modes 605706f2543Smrg */ 606706f2543Smrgstatic DisplayModePtr 607706f2543Smrgxf86GetConfigModes (XF86ConfModeLinePtr conf_mode) 608706f2543Smrg{ 609706f2543Smrg DisplayModePtr head = NULL, prev = NULL, mode; 610706f2543Smrg 611706f2543Smrg for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) 612706f2543Smrg { 613706f2543Smrg mode = calloc(1, sizeof(DisplayModeRec)); 614706f2543Smrg if (!mode) 615706f2543Smrg continue; 616706f2543Smrg mode->name = xstrdup(conf_mode->ml_identifier); 617706f2543Smrg if (!mode->name) 618706f2543Smrg { 619706f2543Smrg free(mode); 620706f2543Smrg continue; 621706f2543Smrg } 622706f2543Smrg mode->type = 0; 623706f2543Smrg mode->Clock = conf_mode->ml_clock; 624706f2543Smrg mode->HDisplay = conf_mode->ml_hdisplay; 625706f2543Smrg mode->HSyncStart = conf_mode->ml_hsyncstart; 626706f2543Smrg mode->HSyncEnd = conf_mode->ml_hsyncend; 627706f2543Smrg mode->HTotal = conf_mode->ml_htotal; 628706f2543Smrg mode->VDisplay = conf_mode->ml_vdisplay; 629706f2543Smrg mode->VSyncStart = conf_mode->ml_vsyncstart; 630706f2543Smrg mode->VSyncEnd = conf_mode->ml_vsyncend; 631706f2543Smrg mode->VTotal = conf_mode->ml_vtotal; 632706f2543Smrg mode->Flags = conf_mode->ml_flags; 633706f2543Smrg mode->HSkew = conf_mode->ml_hskew; 634706f2543Smrg mode->VScan = conf_mode->ml_vscan; 635706f2543Smrg 636706f2543Smrg mode->prev = prev; 637706f2543Smrg mode->next = NULL; 638706f2543Smrg if (prev) 639706f2543Smrg prev->next = mode; 640706f2543Smrg else 641706f2543Smrg head = mode; 642706f2543Smrg prev = mode; 643706f2543Smrg } 644706f2543Smrg return head; 645706f2543Smrg} 646706f2543Smrg 647706f2543Smrg/** 648706f2543Smrg * Build a mode list from a monitor configuration 649706f2543Smrg */ 650706f2543SmrgDisplayModePtr 651706f2543Smrgxf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) 652706f2543Smrg{ 653706f2543Smrg DisplayModePtr modes = NULL; 654706f2543Smrg XF86ConfModesLinkPtr modes_link; 655706f2543Smrg 656706f2543Smrg if (!conf_monitor) 657706f2543Smrg return NULL; 658706f2543Smrg 659706f2543Smrg /* 660706f2543Smrg * first we collect the mode lines from the UseModes directive 661706f2543Smrg */ 662706f2543Smrg for (modes_link = conf_monitor->mon_modes_sect_lst; 663706f2543Smrg modes_link; 664706f2543Smrg modes_link = modes_link->list.next) 665706f2543Smrg { 666706f2543Smrg /* If this modes link hasn't been resolved, go look it up now */ 667706f2543Smrg if (!modes_link->ml_modes) 668706f2543Smrg modes_link->ml_modes = xf86findModes (modes_link->ml_modes_str, 669706f2543Smrg xf86configptr->conf_modes_lst); 670706f2543Smrg if (modes_link->ml_modes) 671706f2543Smrg modes = xf86ModesAdd (modes, 672706f2543Smrg xf86GetConfigModes (modes_link->ml_modes->mon_modeline_lst)); 673706f2543Smrg } 674706f2543Smrg 675706f2543Smrg return xf86ModesAdd (modes, 676706f2543Smrg xf86GetConfigModes (conf_monitor->mon_modeline_lst)); 677706f2543Smrg} 678706f2543Smrg 679706f2543Smrg/** 680706f2543Smrg * Build a mode list containing all of the default modes 681706f2543Smrg */ 682706f2543SmrgDisplayModePtr 683706f2543Smrgxf86GetDefaultModes (void) 684706f2543Smrg{ 685706f2543Smrg DisplayModePtr head = NULL, mode; 686706f2543Smrg int i; 687706f2543Smrg 688706f2543Smrg for (i = 0; i < xf86NumDefaultModes; i++) 689706f2543Smrg { 690706f2543Smrg const DisplayModeRec *defMode = &xf86DefaultModes[i]; 691706f2543Smrg 692706f2543Smrg mode = xf86DuplicateMode(defMode); 693706f2543Smrg head = xf86ModesAdd(head, mode); 694706f2543Smrg } 695706f2543Smrg return head; 696706f2543Smrg} 697706f2543Smrg 698706f2543Smrg/* 699706f2543Smrg * Walk a mode list and prune out duplicates. Will preserve the preferred 700706f2543Smrg * mode of an otherwise-duplicate pair. 701706f2543Smrg * 702706f2543Smrg * Probably best to call this on lists that are all of a single class 703706f2543Smrg * (driver, default, user, etc.), otherwise, which mode gets deleted is 704706f2543Smrg * not especially well defined. 705706f2543Smrg * 706706f2543Smrg * Returns the new list. 707706f2543Smrg */ 708706f2543Smrg 709706f2543SmrgDisplayModePtr 710706f2543Smrgxf86PruneDuplicateModes(DisplayModePtr modes) 711706f2543Smrg{ 712706f2543Smrg DisplayModePtr m, n, o; 713706f2543Smrg 714706f2543Smrgtop: 715706f2543Smrg for (m = modes; m; m = m->next) { 716706f2543Smrg for (n = m->next; n; n = o) { 717706f2543Smrg o = n->next; 718706f2543Smrg if (xf86ModesEqual(m, n)) { 719706f2543Smrg if (n->type & M_T_PREFERRED) { 720706f2543Smrg xf86DeleteMode(&modes, m); 721706f2543Smrg goto top; 722706f2543Smrg } 723706f2543Smrg else 724706f2543Smrg xf86DeleteMode(&modes, n); 725706f2543Smrg } 726706f2543Smrg } 727706f2543Smrg } 728706f2543Smrg 729706f2543Smrg return modes; 730706f2543Smrg} 731