105b261ecSmrg/* 205b261ecSmrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 305b261ecSmrg * 405b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a 505b261ecSmrg * copy of this software and associated documentation files (the "Software"), 605b261ecSmrg * to deal in the Software without restriction, including without limitation 705b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 805b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the 905b261ecSmrg * Software is furnished to do so, subject to the following conditions: 1005b261ecSmrg * 1105b261ecSmrg * The above copyright notice and this permission notice shall be included in 1205b261ecSmrg * all copies or substantial portions of the Software. 1305b261ecSmrg * 1405b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1505b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1605b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1705b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1805b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1905b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2005b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg * 2205b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s) 2305b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote 2405b261ecSmrg * the sale, use or other dealings in this Software without prior written 2505b261ecSmrg * authorization from the copyright holder(s) and author(s). 2605b261ecSmrg */ 2705b261ecSmrg 2805b261ecSmrg#ifdef HAVE_XORG_CONFIG_H 2905b261ecSmrg#include <xorg-config.h> 3005b261ecSmrg#endif 3105b261ecSmrg 32ed6184dfSmrg#include <libxcvt/libxcvt.h> 3305b261ecSmrg#include "xf86Modes.h" 3405b261ecSmrg#include "xf86Priv.h" 3505b261ecSmrg 3605b261ecSmrgextern XF86ConfigPtr xf86configptr; 3705b261ecSmrg 3805b261ecSmrg/** 3905b261ecSmrg * Calculates the horizontal sync rate of a mode. 4005b261ecSmrg */ 416747b715Smrgdouble 4235c4bbdfSmrgxf86ModeHSync(const DisplayModeRec * mode) 4305b261ecSmrg{ 4405b261ecSmrg double hsync = 0.0; 4535c4bbdfSmrg 4605b261ecSmrg if (mode->HSync > 0.0) 4735c4bbdfSmrg hsync = mode->HSync; 4805b261ecSmrg else if (mode->HTotal > 0) 4935c4bbdfSmrg hsync = (float) mode->Clock / (float) mode->HTotal; 5005b261ecSmrg 5105b261ecSmrg return hsync; 5205b261ecSmrg} 5305b261ecSmrg 5405b261ecSmrg/** 5505b261ecSmrg * Calculates the vertical refresh rate of a mode. 5605b261ecSmrg */ 576747b715Smrgdouble 5835c4bbdfSmrgxf86ModeVRefresh(const DisplayModeRec * mode) 5905b261ecSmrg{ 6005b261ecSmrg double refresh = 0.0; 6105b261ecSmrg 6205b261ecSmrg if (mode->VRefresh > 0.0) 6335c4bbdfSmrg refresh = mode->VRefresh; 6405b261ecSmrg else if (mode->HTotal > 0 && mode->VTotal > 0) { 6535c4bbdfSmrg refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; 6635c4bbdfSmrg if (mode->Flags & V_INTERLACE) 6735c4bbdfSmrg refresh *= 2.0; 6835c4bbdfSmrg if (mode->Flags & V_DBLSCAN) 6935c4bbdfSmrg refresh /= 2.0; 7035c4bbdfSmrg if (mode->VScan > 1) 7135c4bbdfSmrg refresh /= (float) (mode->VScan); 7205b261ecSmrg } 7305b261ecSmrg return refresh; 7405b261ecSmrg} 7505b261ecSmrg 766747b715Smrgint 7735c4bbdfSmrgxf86ModeWidth(const DisplayModeRec * mode, Rotation rotation) 7805b261ecSmrg{ 7905b261ecSmrg switch (rotation & 0xf) { 8005b261ecSmrg case RR_Rotate_0: 8105b261ecSmrg case RR_Rotate_180: 8235c4bbdfSmrg return mode->HDisplay; 8305b261ecSmrg case RR_Rotate_90: 8405b261ecSmrg case RR_Rotate_270: 8535c4bbdfSmrg return mode->VDisplay; 8605b261ecSmrg default: 8735c4bbdfSmrg return 0; 8805b261ecSmrg } 8905b261ecSmrg} 9005b261ecSmrg 916747b715Smrgint 9235c4bbdfSmrgxf86ModeHeight(const DisplayModeRec * mode, Rotation rotation) 9305b261ecSmrg{ 9405b261ecSmrg switch (rotation & 0xf) { 9505b261ecSmrg case RR_Rotate_0: 9605b261ecSmrg case RR_Rotate_180: 9735c4bbdfSmrg return mode->VDisplay; 9805b261ecSmrg case RR_Rotate_90: 9905b261ecSmrg case RR_Rotate_270: 10035c4bbdfSmrg return mode->HDisplay; 10105b261ecSmrg default: 10235c4bbdfSmrg return 0; 10305b261ecSmrg } 10405b261ecSmrg} 10505b261ecSmrg 1064642e01fSmrg/** Calculates the memory bandwidth (in MiB/sec) of a mode. */ 1076747b715Smrgunsigned int 1084642e01fSmrgxf86ModeBandwidth(DisplayModePtr mode, int depth) 1094642e01fSmrg{ 1104642e01fSmrg float a_active, a_total, active_percent, pixels_per_second; 1116747b715Smrg int bytes_per_pixel = bits_to_bytes(depth); 1124642e01fSmrg 1134642e01fSmrg if (!mode->HTotal || !mode->VTotal || !mode->Clock) 11435c4bbdfSmrg return 0; 1154642e01fSmrg 1164642e01fSmrg a_active = mode->HDisplay * mode->VDisplay; 1174642e01fSmrg a_total = mode->HTotal * mode->VTotal; 1184642e01fSmrg active_percent = a_active / a_total; 1194642e01fSmrg pixels_per_second = active_percent * mode->Clock * 1000.0; 1204642e01fSmrg 12135c4bbdfSmrg return (unsigned int) (pixels_per_second * bytes_per_pixel / (1024 * 1024)); 1224642e01fSmrg} 1234642e01fSmrg 12405b261ecSmrg/** Sets a default mode name of <width>x<height> on a mode. */ 1256747b715Smrgvoid 12605b261ecSmrgxf86SetModeDefaultName(DisplayModePtr mode) 12705b261ecSmrg{ 12835c4bbdfSmrg Bool interlaced = ! !(mode->Flags & V_INTERLACE); 12935c4bbdfSmrg char *tmp; 13005b261ecSmrg 13135c4bbdfSmrg free((void *) mode->name); 1326747b715Smrg 13335c4bbdfSmrg XNFasprintf(&tmp, "%dx%d%s", mode->HDisplay, mode->VDisplay, 13435c4bbdfSmrg interlaced ? "i" : ""); 13535c4bbdfSmrg mode->name = tmp; 13605b261ecSmrg} 13705b261ecSmrg 13805b261ecSmrg/* 13905b261ecSmrg * xf86SetModeCrtc 14005b261ecSmrg * 14105b261ecSmrg * Initialises the Crtc parameters for a mode. The initialisation includes 14205b261ecSmrg * adjustments for interlaced and double scan modes. 14305b261ecSmrg */ 1446747b715Smrgvoid 14505b261ecSmrgxf86SetModeCrtc(DisplayModePtr p, int adjustFlags) 14605b261ecSmrg{ 14705b261ecSmrg if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) 14835c4bbdfSmrg return; 14935c4bbdfSmrg 15035c4bbdfSmrg p->CrtcHDisplay = p->HDisplay; 15135c4bbdfSmrg p->CrtcHSyncStart = p->HSyncStart; 15235c4bbdfSmrg p->CrtcHSyncEnd = p->HSyncEnd; 15335c4bbdfSmrg p->CrtcHTotal = p->HTotal; 15435c4bbdfSmrg p->CrtcHSkew = p->HSkew; 15535c4bbdfSmrg p->CrtcVDisplay = p->VDisplay; 15635c4bbdfSmrg p->CrtcVSyncStart = p->VSyncStart; 15735c4bbdfSmrg p->CrtcVSyncEnd = p->VSyncEnd; 15835c4bbdfSmrg p->CrtcVTotal = p->VTotal; 15905b261ecSmrg if (p->Flags & V_INTERLACE) { 16035c4bbdfSmrg if (adjustFlags & INTERLACE_HALVE_V) { 16135c4bbdfSmrg p->CrtcVDisplay /= 2; 16235c4bbdfSmrg p->CrtcVSyncStart /= 2; 16335c4bbdfSmrg p->CrtcVSyncEnd /= 2; 16435c4bbdfSmrg p->CrtcVTotal /= 2; 16535c4bbdfSmrg } 16635c4bbdfSmrg /* Force interlaced modes to have an odd VTotal */ 16735c4bbdfSmrg /* maybe we should only do this when INTERLACE_HALVE_V is set? */ 16835c4bbdfSmrg p->CrtcVTotal |= 1; 16905b261ecSmrg } 17005b261ecSmrg 17105b261ecSmrg if (p->Flags & V_DBLSCAN) { 17235c4bbdfSmrg p->CrtcVDisplay *= 2; 17335c4bbdfSmrg p->CrtcVSyncStart *= 2; 17435c4bbdfSmrg p->CrtcVSyncEnd *= 2; 17535c4bbdfSmrg p->CrtcVTotal *= 2; 17605b261ecSmrg } 17705b261ecSmrg if (p->VScan > 1) { 17835c4bbdfSmrg p->CrtcVDisplay *= p->VScan; 17935c4bbdfSmrg p->CrtcVSyncStart *= p->VScan; 18035c4bbdfSmrg p->CrtcVSyncEnd *= p->VScan; 18135c4bbdfSmrg p->CrtcVTotal *= p->VScan; 18205b261ecSmrg } 18305b261ecSmrg p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); 18405b261ecSmrg p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); 18505b261ecSmrg p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); 18605b261ecSmrg p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); 18705b261ecSmrg 18805b261ecSmrg p->CrtcHAdjusted = FALSE; 18905b261ecSmrg p->CrtcVAdjusted = FALSE; 19005b261ecSmrg} 19105b261ecSmrg 19235c4bbdfSmrg/** 19335c4bbdfSmrg * Fills in a copy of mode, removing all stale pointer references. 19435c4bbdfSmrg * xf86ModesEqual will return true when comparing with original mode. 19535c4bbdfSmrg */ 19635c4bbdfSmrgvoid 19735c4bbdfSmrgxf86SaveModeContents(DisplayModePtr intern, const DisplayModeRec *mode) 19835c4bbdfSmrg{ 19935c4bbdfSmrg *intern = *mode; 20035c4bbdfSmrg intern->prev = intern->next = NULL; 20135c4bbdfSmrg intern->name = NULL; 20235c4bbdfSmrg intern->PrivSize = 0; 20335c4bbdfSmrg intern->PrivFlags = 0; 20435c4bbdfSmrg intern->Private = NULL; 20535c4bbdfSmrg} 20635c4bbdfSmrg 20705b261ecSmrg/** 20805b261ecSmrg * Allocates and returns a copy of pMode, including pointers within pMode. 20905b261ecSmrg */ 2106747b715SmrgDisplayModePtr 21135c4bbdfSmrgxf86DuplicateMode(const DisplayModeRec * pMode) 21205b261ecSmrg{ 21305b261ecSmrg DisplayModePtr pNew; 21405b261ecSmrg 21505b261ecSmrg pNew = xnfalloc(sizeof(DisplayModeRec)); 21605b261ecSmrg *pNew = *pMode; 21705b261ecSmrg pNew->next = NULL; 21805b261ecSmrg pNew->prev = NULL; 2194642e01fSmrg 2204642e01fSmrg if (pMode->name == NULL) 22135c4bbdfSmrg xf86SetModeDefaultName(pNew); 2224642e01fSmrg else 22335c4bbdfSmrg pNew->name = xnfstrdup(pMode->name); 22405b261ecSmrg 22505b261ecSmrg return pNew; 22605b261ecSmrg} 22705b261ecSmrg 22805b261ecSmrg/** 22905b261ecSmrg * Duplicates every mode in the given list and returns a pointer to the first 23005b261ecSmrg * mode. 23105b261ecSmrg * 23205b261ecSmrg * \param modeList doubly-linked mode list 23305b261ecSmrg */ 2346747b715SmrgDisplayModePtr 23505b261ecSmrgxf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList) 23605b261ecSmrg{ 23705b261ecSmrg DisplayModePtr first = NULL, last = NULL; 23805b261ecSmrg DisplayModePtr mode; 23905b261ecSmrg 24005b261ecSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 24135c4bbdfSmrg DisplayModePtr new; 24235c4bbdfSmrg 24335c4bbdfSmrg new = xf86DuplicateMode(mode); 24435c4bbdfSmrg 24535c4bbdfSmrg /* Insert pNew into modeList */ 24635c4bbdfSmrg if (last) { 24735c4bbdfSmrg last->next = new; 24835c4bbdfSmrg new->prev = last; 24935c4bbdfSmrg } 25035c4bbdfSmrg else { 25135c4bbdfSmrg first = new; 25235c4bbdfSmrg new->prev = NULL; 25335c4bbdfSmrg } 25435c4bbdfSmrg new->next = NULL; 25535c4bbdfSmrg last = new; 25605b261ecSmrg } 25705b261ecSmrg 25805b261ecSmrg return first; 25905b261ecSmrg} 26005b261ecSmrg 26105b261ecSmrg/** 26205b261ecSmrg * Returns true if the given modes should program to the same timings. 26305b261ecSmrg * 26405b261ecSmrg * This doesn't use Crtc values, as it might be used on ModeRecs without the 26505b261ecSmrg * Crtc values set. So, it's assumed that the other numbers are enough. 26605b261ecSmrg */ 2676747b715SmrgBool 26835c4bbdfSmrgxf86ModesEqual(const DisplayModeRec * pMode1, const DisplayModeRec * pMode2) 26905b261ecSmrg{ 27035c4bbdfSmrg if (pMode1->Clock == pMode2->Clock && 27135c4bbdfSmrg pMode1->HDisplay == pMode2->HDisplay && 27235c4bbdfSmrg pMode1->HSyncStart == pMode2->HSyncStart && 27335c4bbdfSmrg pMode1->HSyncEnd == pMode2->HSyncEnd && 27435c4bbdfSmrg pMode1->HTotal == pMode2->HTotal && 27535c4bbdfSmrg pMode1->HSkew == pMode2->HSkew && 27635c4bbdfSmrg pMode1->VDisplay == pMode2->VDisplay && 27735c4bbdfSmrg pMode1->VSyncStart == pMode2->VSyncStart && 27835c4bbdfSmrg pMode1->VSyncEnd == pMode2->VSyncEnd && 27935c4bbdfSmrg pMode1->VTotal == pMode2->VTotal && 28035c4bbdfSmrg pMode1->VScan == pMode2->VScan && pMode1->Flags == pMode2->Flags) { 28135c4bbdfSmrg return TRUE; 28235c4bbdfSmrg } 28335c4bbdfSmrg else { 28435c4bbdfSmrg return FALSE; 28535c4bbdfSmrg } 28605b261ecSmrg} 28705b261ecSmrg 28805b261ecSmrgstatic void 28935c4bbdfSmrgadd(char **p, const char *new) 29005b261ecSmrg{ 29105b261ecSmrg *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2); 29205b261ecSmrg strcat(*p, " "); 29305b261ecSmrg strcat(*p, new); 29405b261ecSmrg} 29505b261ecSmrg 29605b261ecSmrg/** 29705b261ecSmrg * Print out a modeline. 29835c4bbdfSmrg * 29935c4bbdfSmrg * The mode type bits are informational except for the capitalized U 30035c4bbdfSmrg * and P bits which give sort order priority. Letter map: 30135c4bbdfSmrg * 30235c4bbdfSmrg * USERPREF, U, user preferred is set from the xorg.conf Monitor 30335c4bbdfSmrg * Option "PreferredMode" or from the Screen Display Modes statement. 30435c4bbdfSmrg * This unique modeline is moved to the head of the list after sorting. 30535c4bbdfSmrg * 30635c4bbdfSmrg * DRIVER, e, is set by the video driver, EDID or flat panel native. 30735c4bbdfSmrg * 30835c4bbdfSmrg * USERDEF, z, a configured zoom mode Ctrl+Alt+Keypad-{Plus,Minus}. 30935c4bbdfSmrg * 31035c4bbdfSmrg * DEFAULT, d, a compiled-in default. 31135c4bbdfSmrg * 31235c4bbdfSmrg * PREFERRED, P, driver preferred is set by the video device driver, 31335c4bbdfSmrg * e.g. the EDID detailed timing modeline. This is a true sort 31435c4bbdfSmrg * priority and multiple P modes form a sorted sublist at the list 31535c4bbdfSmrg * head. 31635c4bbdfSmrg * 31735c4bbdfSmrg * BUILTIN, b, a hardware fixed CRTC mode. 31835c4bbdfSmrg * 31935c4bbdfSmrg * See modes/xf86Crtc.c: xf86ProbeOutputModes(). 32005b261ecSmrg */ 3216747b715Smrgvoid 32235c4bbdfSmrgxf86PrintModeline(int scrnIndex, DisplayModePtr mode) 32305b261ecSmrg{ 32405b261ecSmrg char tmp[256]; 32505b261ecSmrg char *flags = xnfcalloc(1, 1); 32605b261ecSmrg 32735c4bbdfSmrg#define TBITS 6 32835c4bbdfSmrg const char tchar[TBITS + 1] = "UezdPb"; 32935c4bbdfSmrg 33035c4bbdfSmrg int tbit[TBITS] = { 33135c4bbdfSmrg M_T_USERPREF, M_T_DRIVER, M_T_USERDEF, 33235c4bbdfSmrg M_T_DEFAULT, M_T_PREFERRED, M_T_BUILTIN 33335c4bbdfSmrg }; 33435c4bbdfSmrg char type[TBITS + 2]; /* +1 for leading space */ 33535c4bbdfSmrg 33635c4bbdfSmrg#undef TBITS 33735c4bbdfSmrg int tlen = 0; 33835c4bbdfSmrg 33935c4bbdfSmrg if (mode->type) { 34035c4bbdfSmrg int i; 34135c4bbdfSmrg 34235c4bbdfSmrg type[tlen++] = ' '; 34335c4bbdfSmrg for (i = 0; tchar[i]; i++) 34435c4bbdfSmrg if (mode->type & tbit[i]) 34535c4bbdfSmrg type[tlen++] = tchar[i]; 34635c4bbdfSmrg } 34735c4bbdfSmrg type[tlen] = '\0'; 34835c4bbdfSmrg 34935c4bbdfSmrg if (mode->HSkew) { 35035c4bbdfSmrg snprintf(tmp, 256, "hskew %i", mode->HSkew); 35135c4bbdfSmrg add(&flags, tmp); 35205b261ecSmrg } 35335c4bbdfSmrg if (mode->VScan) { 35435c4bbdfSmrg snprintf(tmp, 256, "vscan %i", mode->VScan); 35535c4bbdfSmrg add(&flags, tmp); 35605b261ecSmrg } 35735c4bbdfSmrg if (mode->Flags & V_INTERLACE) 35835c4bbdfSmrg add(&flags, "interlace"); 35935c4bbdfSmrg if (mode->Flags & V_CSYNC) 36035c4bbdfSmrg add(&flags, "composite"); 36135c4bbdfSmrg if (mode->Flags & V_DBLSCAN) 36235c4bbdfSmrg add(&flags, "doublescan"); 36335c4bbdfSmrg if (mode->Flags & V_BCAST) 36435c4bbdfSmrg add(&flags, "bcast"); 36535c4bbdfSmrg if (mode->Flags & V_PHSYNC) 36635c4bbdfSmrg add(&flags, "+hsync"); 36735c4bbdfSmrg if (mode->Flags & V_NHSYNC) 36835c4bbdfSmrg add(&flags, "-hsync"); 36935c4bbdfSmrg if (mode->Flags & V_PVSYNC) 37035c4bbdfSmrg add(&flags, "+vsync"); 37135c4bbdfSmrg if (mode->Flags & V_NVSYNC) 37235c4bbdfSmrg add(&flags, "-vsync"); 37335c4bbdfSmrg if (mode->Flags & V_PCSYNC) 37435c4bbdfSmrg add(&flags, "+csync"); 37535c4bbdfSmrg if (mode->Flags & V_NCSYNC) 37635c4bbdfSmrg add(&flags, "-csync"); 37705b261ecSmrg#if 0 37835c4bbdfSmrg if (mode->Flags & V_CLKDIV2) 37935c4bbdfSmrg add(&flags, "vclk/2"); 38005b261ecSmrg#endif 38105b261ecSmrg xf86DrvMsg(scrnIndex, X_INFO, 38235c4bbdfSmrg "Modeline \"%s\"x%.01f %6.2f %i %i %i %i %i %i %i %i%s" 38335c4bbdfSmrg " (%.01f kHz%s)\n", 38435c4bbdfSmrg mode->name, mode->VRefresh, mode->Clock / 1000., 38535c4bbdfSmrg mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, 38635c4bbdfSmrg mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal, 38735c4bbdfSmrg flags, xf86ModeHSync(mode), type); 3886747b715Smrg free(flags); 38905b261ecSmrg} 39005b261ecSmrg 39105b261ecSmrg/** 39205b261ecSmrg * Marks as bad any modes with unsupported flags. 39305b261ecSmrg * 3944642e01fSmrg * \param modeList doubly-linked list of modes. 39505b261ecSmrg * \param flags flags supported by the driver. 39605b261ecSmrg * 39705b261ecSmrg * \bug only V_INTERLACE and V_DBLSCAN are supported. Is that enough? 39805b261ecSmrg */ 3996747b715Smrgvoid 40035c4bbdfSmrgxf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList, int flags) 40105b261ecSmrg{ 40205b261ecSmrg DisplayModePtr mode; 40305b261ecSmrg 4046747b715Smrg if (flags == (V_INTERLACE | V_DBLSCAN)) 40535c4bbdfSmrg return; 4066747b715Smrg 40705b261ecSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 40835c4bbdfSmrg if (mode->Flags & V_INTERLACE && !(flags & V_INTERLACE)) 40935c4bbdfSmrg mode->status = MODE_NO_INTERLACE; 41035c4bbdfSmrg if (mode->Flags & V_DBLSCAN && !(flags & V_DBLSCAN)) 41135c4bbdfSmrg mode->status = MODE_NO_DBLESCAN; 41205b261ecSmrg } 41305b261ecSmrg} 41405b261ecSmrg 41505b261ecSmrg/** 41605b261ecSmrg * Marks as bad any modes extending beyond the given max X, Y, or pitch. 41705b261ecSmrg * 4184642e01fSmrg * \param modeList doubly-linked list of modes. 41905b261ecSmrg */ 4206747b715Smrgvoid 42105b261ecSmrgxf86ValidateModesSize(ScrnInfoPtr pScrn, DisplayModePtr modeList, 42235c4bbdfSmrg int maxX, int maxY, int maxPitch) 42305b261ecSmrg{ 42405b261ecSmrg DisplayModePtr mode; 42505b261ecSmrg 4268223e2f2Smrg if (maxPitch <= 0) 42735c4bbdfSmrg maxPitch = MAXINT; 4288223e2f2Smrg if (maxX <= 0) 42935c4bbdfSmrg maxX = MAXINT; 4308223e2f2Smrg if (maxY <= 0) 43135c4bbdfSmrg maxY = MAXINT; 43205b261ecSmrg 4338223e2f2Smrg for (mode = modeList; mode != NULL; mode = mode->next) { 43435c4bbdfSmrg if ((xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 43535c4bbdfSmrg xf86ModeWidth(mode, RR_Rotate_0) > maxX || 43635c4bbdfSmrg xf86ModeHeight(mode, RR_Rotate_0) > maxY) && 43735c4bbdfSmrg (xf86ModeWidth(mode, RR_Rotate_90) > maxPitch || 43835c4bbdfSmrg xf86ModeWidth(mode, RR_Rotate_90) > maxX || 43935c4bbdfSmrg xf86ModeHeight(mode, RR_Rotate_90) > maxY)) { 44035c4bbdfSmrg if (xf86ModeWidth(mode, RR_Rotate_0) > maxPitch || 44135c4bbdfSmrg xf86ModeWidth(mode, RR_Rotate_90) > maxPitch) 44235c4bbdfSmrg mode->status = MODE_BAD_WIDTH; 44335c4bbdfSmrg 44435c4bbdfSmrg if (xf86ModeWidth(mode, RR_Rotate_0) > maxX || 44535c4bbdfSmrg xf86ModeWidth(mode, RR_Rotate_90) > maxX) 44635c4bbdfSmrg mode->status = MODE_VIRTUAL_X; 44735c4bbdfSmrg 44835c4bbdfSmrg if (xf86ModeHeight(mode, RR_Rotate_0) > maxY || 44935c4bbdfSmrg xf86ModeHeight(mode, RR_Rotate_90) > maxY) 45035c4bbdfSmrg mode->status = MODE_VIRTUAL_Y; 45135c4bbdfSmrg } 45235c4bbdfSmrg 45335c4bbdfSmrg if (mode->next == modeList) 45435c4bbdfSmrg break; 45505b261ecSmrg } 45605b261ecSmrg} 45705b261ecSmrg 45805b261ecSmrg/** 45905b261ecSmrg * Marks as bad any modes that aren't supported by the given monitor's 46005b261ecSmrg * hsync and vrefresh ranges. 46105b261ecSmrg * 4624642e01fSmrg * \param modeList doubly-linked list of modes. 46305b261ecSmrg */ 4646747b715Smrgvoid 46535c4bbdfSmrgxf86ValidateModesSync(ScrnInfoPtr pScrn, DisplayModePtr modeList, MonPtr mon) 46605b261ecSmrg{ 46705b261ecSmrg DisplayModePtr mode; 46805b261ecSmrg 46905b261ecSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 47035c4bbdfSmrg Bool bad; 47135c4bbdfSmrg int i; 47235c4bbdfSmrg 47335c4bbdfSmrg bad = TRUE; 47435c4bbdfSmrg for (i = 0; i < mon->nHsync; i++) { 47535c4bbdfSmrg if (xf86ModeHSync(mode) >= mon->hsync[i].lo * (1 - SYNC_TOLERANCE) 47635c4bbdfSmrg && xf86ModeHSync(mode) <= 47735c4bbdfSmrg mon->hsync[i].hi * (1 + SYNC_TOLERANCE)) { 47835c4bbdfSmrg bad = FALSE; 47935c4bbdfSmrg } 48035c4bbdfSmrg } 48135c4bbdfSmrg if (bad) 48235c4bbdfSmrg mode->status = MODE_HSYNC; 48335c4bbdfSmrg 48435c4bbdfSmrg bad = TRUE; 48535c4bbdfSmrg for (i = 0; i < mon->nVrefresh; i++) { 48635c4bbdfSmrg if (xf86ModeVRefresh(mode) >= 48735c4bbdfSmrg mon->vrefresh[i].lo * (1 - SYNC_TOLERANCE) && 48835c4bbdfSmrg xf86ModeVRefresh(mode) <= 48935c4bbdfSmrg mon->vrefresh[i].hi * (1 + SYNC_TOLERANCE)) { 49035c4bbdfSmrg bad = FALSE; 49135c4bbdfSmrg } 49235c4bbdfSmrg } 49335c4bbdfSmrg if (bad) 49435c4bbdfSmrg mode->status = MODE_VSYNC; 49535c4bbdfSmrg 49635c4bbdfSmrg if (mode->next == modeList) 49735c4bbdfSmrg break; 49805b261ecSmrg } 49905b261ecSmrg} 50005b261ecSmrg 50105b261ecSmrg/** 50205b261ecSmrg * Marks as bad any modes extending beyond outside of the given clock ranges. 50305b261ecSmrg * 5044642e01fSmrg * \param modeList doubly-linked list of modes. 50505b261ecSmrg * \param min pointer to minimums of clock ranges 50605b261ecSmrg * \param max pointer to maximums of clock ranges 50705b261ecSmrg * \param n_ranges number of ranges. 50805b261ecSmrg */ 5096747b715Smrgvoid 51005b261ecSmrgxf86ValidateModesClocks(ScrnInfoPtr pScrn, DisplayModePtr modeList, 51135c4bbdfSmrg int *min, int *max, int n_ranges) 51205b261ecSmrg{ 51305b261ecSmrg DisplayModePtr mode; 51405b261ecSmrg int i; 51505b261ecSmrg 51605b261ecSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 51735c4bbdfSmrg Bool good = FALSE; 51835c4bbdfSmrg 51935c4bbdfSmrg for (i = 0; i < n_ranges; i++) { 52035c4bbdfSmrg if (mode->Clock >= min[i] * (1 - SYNC_TOLERANCE) && 52135c4bbdfSmrg mode->Clock <= max[i] * (1 + SYNC_TOLERANCE)) { 52235c4bbdfSmrg good = TRUE; 52335c4bbdfSmrg break; 52435c4bbdfSmrg } 52535c4bbdfSmrg } 52635c4bbdfSmrg if (!good) 52735c4bbdfSmrg mode->status = MODE_CLOCK_RANGE; 52805b261ecSmrg } 52905b261ecSmrg} 53005b261ecSmrg 53105b261ecSmrg/** 53205b261ecSmrg * If the user has specified a set of mode names to use, mark as bad any modes 53305b261ecSmrg * not listed. 53405b261ecSmrg * 53505b261ecSmrg * The user mode names specified are prefixes to names of modes, so "1024x768" 53605b261ecSmrg * will match modes named "1024x768", "1024x768x75", "1024x768-good", but 53705b261ecSmrg * "1024x768x75" would only match "1024x768x75" from that list. 53805b261ecSmrg * 53905b261ecSmrg * MODE_BAD is used as the rejection flag, for lack of a better flag. 54005b261ecSmrg * 5414642e01fSmrg * \param modeList doubly-linked list of modes. 54205b261ecSmrg */ 5436747b715Smrgvoid 54405b261ecSmrgxf86ValidateModesUserConfig(ScrnInfoPtr pScrn, DisplayModePtr modeList) 54505b261ecSmrg{ 54605b261ecSmrg DisplayModePtr mode; 54705b261ecSmrg 54805b261ecSmrg if (pScrn->display->modes[0] == NULL) 54935c4bbdfSmrg return; 55005b261ecSmrg 55105b261ecSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 55235c4bbdfSmrg int i; 55335c4bbdfSmrg Bool good = FALSE; 55435c4bbdfSmrg 55535c4bbdfSmrg for (i = 0; pScrn->display->modes[i] != NULL; i++) { 55635c4bbdfSmrg if (strncmp(pScrn->display->modes[i], mode->name, 55735c4bbdfSmrg strlen(pScrn->display->modes[i])) == 0) { 55835c4bbdfSmrg good = TRUE; 55935c4bbdfSmrg break; 56035c4bbdfSmrg } 56135c4bbdfSmrg } 56235c4bbdfSmrg if (!good) 56335c4bbdfSmrg mode->status = MODE_BAD; 56405b261ecSmrg } 56505b261ecSmrg} 56605b261ecSmrg 5674642e01fSmrg/** 5684642e01fSmrg * Marks as bad any modes exceeding the given bandwidth. 5694642e01fSmrg * 5704642e01fSmrg * \param modeList doubly-linked list of modes. 5714642e01fSmrg * \param bandwidth bandwidth in MHz. 5724642e01fSmrg * \param depth color depth. 5734642e01fSmrg */ 5746747b715Smrgvoid 5754642e01fSmrgxf86ValidateModesBandwidth(ScrnInfoPtr pScrn, DisplayModePtr modeList, 57635c4bbdfSmrg unsigned int bandwidth, int depth) 5774642e01fSmrg{ 5784642e01fSmrg DisplayModePtr mode; 5794642e01fSmrg 5804642e01fSmrg for (mode = modeList; mode != NULL; mode = mode->next) { 58135c4bbdfSmrg if (xf86ModeBandwidth(mode, depth) > bandwidth) 58235c4bbdfSmrg mode->status = MODE_BANDWIDTH; 5834642e01fSmrg } 5844642e01fSmrg} 5854642e01fSmrg 5864642e01fSmrgBool 58735c4bbdfSmrgxf86ModeIsReduced(const DisplayModeRec * mode) 5884642e01fSmrg{ 5894642e01fSmrg if ((((mode->HDisplay * 5 / 4) & ~0x07) > mode->HTotal) && 5904642e01fSmrg ((mode->HTotal - mode->HDisplay) == 160) && 59135c4bbdfSmrg ((mode->HSyncEnd - mode->HDisplay) == 80) && 59235c4bbdfSmrg ((mode->HSyncEnd - mode->HSyncStart) == 32) && 59335c4bbdfSmrg ((mode->VSyncStart - mode->VDisplay) == 3)) 59435c4bbdfSmrg return TRUE; 5954642e01fSmrg return FALSE; 5964642e01fSmrg} 5974642e01fSmrg 5984642e01fSmrg/** 5994642e01fSmrg * Marks as bad any reduced-blanking modes. 6004642e01fSmrg * 6014642e01fSmrg * \param modeList doubly-linked list of modes. 6024642e01fSmrg */ 6036747b715Smrgvoid 6044642e01fSmrgxf86ValidateModesReducedBlanking(ScrnInfoPtr pScrn, DisplayModePtr modeList) 6054642e01fSmrg{ 6066747b715Smrg for (; modeList != NULL; modeList = modeList->next) 60735c4bbdfSmrg if (xf86ModeIsReduced(modeList)) 60835c4bbdfSmrg modeList->status = MODE_NO_REDUCED; 6094642e01fSmrg} 6104642e01fSmrg 61105b261ecSmrg/** 61205b261ecSmrg * Frees any modes from the list with a status other than MODE_OK. 61305b261ecSmrg * 61405b261ecSmrg * \param modeList pointer to a doubly-linked or circular list of modes. 61505b261ecSmrg * \param verbose determines whether the reason for mode invalidation is 61605b261ecSmrg * printed. 61705b261ecSmrg */ 6186747b715Smrgvoid 61935c4bbdfSmrgxf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr * modeList, 62035c4bbdfSmrg Bool verbose) 62105b261ecSmrg{ 62205b261ecSmrg DisplayModePtr mode; 62305b261ecSmrg 62405b261ecSmrg for (mode = *modeList; mode != NULL;) { 62535c4bbdfSmrg DisplayModePtr next = mode->next, first = *modeList; 62635c4bbdfSmrg 62735c4bbdfSmrg if (mode->status != MODE_OK) { 62835c4bbdfSmrg if (verbose) { 62935c4bbdfSmrg const char *type = ""; 63035c4bbdfSmrg 63135c4bbdfSmrg if (mode->type & M_T_BUILTIN) 63235c4bbdfSmrg type = "built-in "; 63335c4bbdfSmrg else if (mode->type & M_T_DEFAULT) 63435c4bbdfSmrg type = "default "; 63535c4bbdfSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 63635c4bbdfSmrg "Not using %smode \"%s\" (%s)\n", type, mode->name, 63735c4bbdfSmrg xf86ModeStatusToString(mode->status)); 63835c4bbdfSmrg } 63935c4bbdfSmrg xf86DeleteMode(modeList, mode); 64035c4bbdfSmrg } 64135c4bbdfSmrg 64235c4bbdfSmrg if (next == first) 64335c4bbdfSmrg break; 64435c4bbdfSmrg mode = next; 64505b261ecSmrg } 64605b261ecSmrg} 64705b261ecSmrg 64805b261ecSmrg/** 64905b261ecSmrg * Adds the new mode into the mode list, and returns the new list 65005b261ecSmrg * 65105b261ecSmrg * \param modes doubly-linked mode list. 65205b261ecSmrg */ 6536747b715SmrgDisplayModePtr 65405b261ecSmrgxf86ModesAdd(DisplayModePtr modes, DisplayModePtr new) 65505b261ecSmrg{ 65605b261ecSmrg if (modes == NULL) 65735c4bbdfSmrg return new; 65805b261ecSmrg 65905b261ecSmrg if (new) { 66035c4bbdfSmrg DisplayModePtr mode = modes; 66105b261ecSmrg 66235c4bbdfSmrg while (mode->next) 66335c4bbdfSmrg mode = mode->next; 66405b261ecSmrg 66535c4bbdfSmrg mode->next = new; 66635c4bbdfSmrg new->prev = mode; 66705b261ecSmrg } 66805b261ecSmrg 66905b261ecSmrg return modes; 67005b261ecSmrg} 67105b261ecSmrg 67205b261ecSmrg/** 67305b261ecSmrg * Build a mode list from a list of config file modes 67405b261ecSmrg */ 67505b261ecSmrgstatic DisplayModePtr 67635c4bbdfSmrgxf86GetConfigModes(XF86ConfModeLinePtr conf_mode) 67705b261ecSmrg{ 67835c4bbdfSmrg DisplayModePtr head = NULL, prev = NULL, mode; 67935c4bbdfSmrg 68035c4bbdfSmrg for (; conf_mode; conf_mode = (XF86ConfModeLinePtr) conf_mode->list.next) { 6816747b715Smrg mode = calloc(1, sizeof(DisplayModeRec)); 68235c4bbdfSmrg if (!mode) 68335c4bbdfSmrg continue; 68435c4bbdfSmrg mode->name = xstrdup(conf_mode->ml_identifier); 68535c4bbdfSmrg if (!mode->name) { 68635c4bbdfSmrg free(mode); 68735c4bbdfSmrg continue; 68835c4bbdfSmrg } 68935c4bbdfSmrg mode->type = 0; 69035c4bbdfSmrg mode->Clock = conf_mode->ml_clock; 69135c4bbdfSmrg mode->HDisplay = conf_mode->ml_hdisplay; 69205b261ecSmrg mode->HSyncStart = conf_mode->ml_hsyncstart; 69335c4bbdfSmrg mode->HSyncEnd = conf_mode->ml_hsyncend; 69435c4bbdfSmrg mode->HTotal = conf_mode->ml_htotal; 69535c4bbdfSmrg mode->VDisplay = conf_mode->ml_vdisplay; 69605b261ecSmrg mode->VSyncStart = conf_mode->ml_vsyncstart; 69735c4bbdfSmrg mode->VSyncEnd = conf_mode->ml_vsyncend; 69835c4bbdfSmrg mode->VTotal = conf_mode->ml_vtotal; 69935c4bbdfSmrg mode->Flags = conf_mode->ml_flags; 70035c4bbdfSmrg mode->HSkew = conf_mode->ml_hskew; 70135c4bbdfSmrg mode->VScan = conf_mode->ml_vscan; 70205b261ecSmrg 70305b261ecSmrg mode->prev = prev; 70435c4bbdfSmrg mode->next = NULL; 70535c4bbdfSmrg if (prev) 70635c4bbdfSmrg prev->next = mode; 70735c4bbdfSmrg else 70835c4bbdfSmrg head = mode; 70935c4bbdfSmrg prev = mode; 71005b261ecSmrg } 71105b261ecSmrg return head; 71205b261ecSmrg} 71305b261ecSmrg 71405b261ecSmrg/** 71505b261ecSmrg * Build a mode list from a monitor configuration 71605b261ecSmrg */ 7176747b715SmrgDisplayModePtr 71835c4bbdfSmrgxf86GetMonitorModes(ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor) 71905b261ecSmrg{ 72035c4bbdfSmrg DisplayModePtr modes = NULL; 72135c4bbdfSmrg XF86ConfModesLinkPtr modes_link; 72235c4bbdfSmrg 72305b261ecSmrg if (!conf_monitor) 72435c4bbdfSmrg return NULL; 72505b261ecSmrg 72605b261ecSmrg /* 72705b261ecSmrg * first we collect the mode lines from the UseModes directive 72805b261ecSmrg */ 72935c4bbdfSmrg for (modes_link = conf_monitor->mon_modes_sect_lst; 73035c4bbdfSmrg modes_link; modes_link = modes_link->list.next) { 73135c4bbdfSmrg /* If this modes link hasn't been resolved, go look it up now */ 73235c4bbdfSmrg if (!modes_link->ml_modes) 73335c4bbdfSmrg modes_link->ml_modes = xf86findModes(modes_link->ml_modes_str, 73435c4bbdfSmrg xf86configptr->conf_modes_lst); 73535c4bbdfSmrg if (modes_link->ml_modes) 73635c4bbdfSmrg modes = xf86ModesAdd(modes, 73735c4bbdfSmrg xf86GetConfigModes(modes_link->ml_modes-> 73835c4bbdfSmrg mon_modeline_lst)); 73905b261ecSmrg } 74005b261ecSmrg 74135c4bbdfSmrg return xf86ModesAdd(modes, 74235c4bbdfSmrg xf86GetConfigModes(conf_monitor->mon_modeline_lst)); 74305b261ecSmrg} 74405b261ecSmrg 74505b261ecSmrg/** 74605b261ecSmrg * Build a mode list containing all of the default modes 74705b261ecSmrg */ 7486747b715SmrgDisplayModePtr 74935c4bbdfSmrgxf86GetDefaultModes(void) 75005b261ecSmrg{ 75135c4bbdfSmrg DisplayModePtr head = NULL, mode; 75235c4bbdfSmrg int i; 75335c4bbdfSmrg 75435c4bbdfSmrg for (i = 0; i < xf86NumDefaultModes; i++) { 75535c4bbdfSmrg const DisplayModeRec *defMode = &xf86DefaultModes[i]; 75635c4bbdfSmrg 75735c4bbdfSmrg mode = xf86DuplicateMode(defMode); 75835c4bbdfSmrg head = xf86ModesAdd(head, mode); 75905b261ecSmrg } 76005b261ecSmrg return head; 76105b261ecSmrg} 7626747b715Smrg 7636747b715Smrg/* 7646747b715Smrg * Walk a mode list and prune out duplicates. Will preserve the preferred 7656747b715Smrg * mode of an otherwise-duplicate pair. 7666747b715Smrg * 7676747b715Smrg * Probably best to call this on lists that are all of a single class 7686747b715Smrg * (driver, default, user, etc.), otherwise, which mode gets deleted is 7696747b715Smrg * not especially well defined. 7706747b715Smrg * 7716747b715Smrg * Returns the new list. 7726747b715Smrg */ 7736747b715Smrg 7746747b715SmrgDisplayModePtr 7756747b715Smrgxf86PruneDuplicateModes(DisplayModePtr modes) 7766747b715Smrg{ 7776747b715Smrg DisplayModePtr m, n, o; 7786747b715Smrg 77935c4bbdfSmrg top: 7806747b715Smrg for (m = modes; m; m = m->next) { 78135c4bbdfSmrg for (n = m->next; n; n = o) { 78235c4bbdfSmrg o = n->next; 78335c4bbdfSmrg if (xf86ModesEqual(m, n)) { 78435c4bbdfSmrg if (n->type & M_T_PREFERRED) { 78535c4bbdfSmrg xf86DeleteMode(&modes, m); 78635c4bbdfSmrg goto top; 78735c4bbdfSmrg } 78835c4bbdfSmrg else 78935c4bbdfSmrg xf86DeleteMode(&modes, n); 79035c4bbdfSmrg } 79135c4bbdfSmrg } 7926747b715Smrg } 7936747b715Smrg 7946747b715Smrg return modes; 7956747b715Smrg} 796ed6184dfSmrg 797ed6184dfSmrg/* 798ed6184dfSmrg * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. 799ed6184dfSmrg */ 800ed6184dfSmrgDisplayModePtr 801ed6184dfSmrgxf86CVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, 802ed6184dfSmrg Bool Interlaced) 803ed6184dfSmrg{ 804ed6184dfSmrg struct libxcvt_mode_info *libxcvt_mode_info; 805ed6184dfSmrg DisplayModeRec *Mode = xnfcalloc(1, sizeof(DisplayModeRec)); 806875c6e4fSmrg char *tmp; 807ed6184dfSmrg 808ed6184dfSmrg libxcvt_mode_info = 809ed6184dfSmrg libxcvt_gen_mode_info(HDisplay, VDisplay, VRefresh, Reduced, Interlaced); 810ed6184dfSmrg 811875c6e4fSmrg XNFasprintf(&tmp, "%dx%d", HDisplay, VDisplay); 812875c6e4fSmrg Mode->name = tmp; 813875c6e4fSmrg 814ed6184dfSmrg Mode->VDisplay = libxcvt_mode_info->vdisplay; 815ed6184dfSmrg Mode->HDisplay = libxcvt_mode_info->hdisplay; 816ed6184dfSmrg Mode->Clock = libxcvt_mode_info->dot_clock; 817ed6184dfSmrg Mode->HSyncStart = libxcvt_mode_info->hsync_start; 818ed6184dfSmrg Mode->HSyncEnd = libxcvt_mode_info->hsync_end; 819ed6184dfSmrg Mode->HTotal = libxcvt_mode_info->htotal; 820ed6184dfSmrg Mode->VSyncStart = libxcvt_mode_info->vsync_start; 821ed6184dfSmrg Mode->VSyncEnd = libxcvt_mode_info->vsync_end; 822ed6184dfSmrg Mode->VTotal = libxcvt_mode_info->vtotal; 823ed6184dfSmrg Mode->VRefresh = libxcvt_mode_info->vrefresh; 824ed6184dfSmrg Mode->Flags = libxcvt_mode_info->mode_flags; 825bf7d8d8dSmacallan xf86SetModeDefaultName(Mode); 826ed6184dfSmrg 827ed6184dfSmrg free(libxcvt_mode_info); 828ed6184dfSmrg 829ed6184dfSmrg return Mode; 830ed6184dfSmrg} 831