1706f2543Smrg/* 2706f2543Smrg * Copyright 2005-2006 Luc Verhaegen. 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 */ 23706f2543Smrg 24706f2543Smrg/* Standalone VESA CVT standard timing modelines generator. */ 25706f2543Smrg 26706f2543Smrg#include "xf86.h" 27706f2543Smrg#include "xf86Modes.h" 28706f2543Smrg 29706f2543Smrg/* Error implementation used by the server code we built in */ 30706f2543Smrgvoid 31706f2543SmrgError(const char *str) 32706f2543Smrg{ 33706f2543Smrg perror(str); 34706f2543Smrg} 35706f2543Smrg 36706f2543Smrg/* FatalError implementation used by the server code we built in */ 37706f2543Smrgvoid 38706f2543SmrgFatalError(const char *f, ...) 39706f2543Smrg{ 40706f2543Smrg va_list args; 41706f2543Smrg va_start(args, f); 42706f2543Smrg vfprintf(stderr, f, args); 43706f2543Smrg va_end(args); 44706f2543Smrg exit(1); 45706f2543Smrg} 46706f2543Smrg 47706f2543Smrg/* xnfalloc implementation used by the server code we built in */ 48706f2543Smrgpointer 49706f2543SmrgXNFalloc(unsigned long n) 50706f2543Smrg{ 51706f2543Smrg pointer r; 52706f2543Smrg 53706f2543Smrg r = malloc(n); 54706f2543Smrg if (!r) { 55706f2543Smrg perror("malloc failed"); 56706f2543Smrg exit(1); 57706f2543Smrg } 58706f2543Smrg return r; 59706f2543Smrg} 60706f2543Smrg 61706f2543Smrg/* xnfcalloc implementation used by the server code we built in */ 62706f2543Smrgpointer 63706f2543SmrgXNFcalloc(unsigned long n) 64706f2543Smrg{ 65706f2543Smrg pointer r; 66706f2543Smrg 67706f2543Smrg r = calloc(1, n); 68706f2543Smrg if (!r) { 69706f2543Smrg perror("calloc failed"); 70706f2543Smrg exit(1); 71706f2543Smrg } 72706f2543Smrg return r; 73706f2543Smrg} 74706f2543Smrg 75706f2543Smrg/* 76706f2543Smrg * Quickly check wether this is a CVT standard mode. 77706f2543Smrg */ 78706f2543Smrgstatic Bool 79706f2543SmrgCVTCheckStandard(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, 80706f2543Smrg Bool Verbose) 81706f2543Smrg{ 82706f2543Smrg Bool IsCVT = TRUE; 83706f2543Smrg 84706f2543Smrg if ((!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) || 85706f2543Smrg (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) || 86706f2543Smrg (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) || 87706f2543Smrg (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) || 88706f2543Smrg (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))) 89706f2543Smrg ; 90706f2543Smrg else { 91706f2543Smrg if (Verbose) 92706f2543Smrg fprintf(stderr, "Warning: Aspect Ratio is not CVT standard.\n"); 93706f2543Smrg IsCVT = FALSE; 94706f2543Smrg } 95706f2543Smrg 96706f2543Smrg if ((VRefresh != 50.0) && (VRefresh != 60.0) && 97706f2543Smrg (VRefresh != 75.0) && (VRefresh != 85.0)) { 98706f2543Smrg if (Verbose) 99706f2543Smrg fprintf(stderr, "Warning: Refresh Rate is not CVT standard " 100706f2543Smrg "(50, 60, 75 or 85Hz).\n"); 101706f2543Smrg IsCVT = FALSE; 102706f2543Smrg } 103706f2543Smrg 104706f2543Smrg return IsCVT; 105706f2543Smrg} 106706f2543Smrg 107706f2543Smrg 108706f2543Smrg/* 109706f2543Smrg * I'm not documenting --interlaced for obvious reasons, even though I did 110706f2543Smrg * implement it. I also can't deny having looked at gtf here. 111706f2543Smrg */ 112706f2543Smrgstatic void 113706f2543SmrgPrintUsage(char *Name) 114706f2543Smrg{ 115706f2543Smrg fprintf(stderr, "\n"); 116706f2543Smrg fprintf(stderr, "usage: %s [-v|--verbose] [-r|--reduced] X Y [refresh]\n", 117706f2543Smrg Name); 118706f2543Smrg fprintf(stderr, "\n"); 119706f2543Smrg fprintf(stderr, " -v|--verbose : Warn about CVT standard adherance.\n"); 120706f2543Smrg fprintf(stderr, " -r|--reduced : Create a mode with reduced blanking " 121706f2543Smrg "(default: normal blanking).\n"); 122706f2543Smrg fprintf(stderr, " X : Desired horizontal resolution " 123706f2543Smrg "(multiple of 8, required).\n"); 124706f2543Smrg fprintf(stderr, " Y : Desired vertical resolution (required).\n"); 125706f2543Smrg fprintf(stderr, " refresh : Desired refresh rate (default: 60.0Hz).\n"); 126706f2543Smrg fprintf(stderr, "\n"); 127706f2543Smrg 128706f2543Smrg fprintf(stderr, "Calculates VESA CVT (Coordinated Video Timing) modelines" 129706f2543Smrg " for use with X.\n"); 130706f2543Smrg} 131706f2543Smrg 132706f2543Smrg 133706f2543Smrg/* 134706f2543Smrg * 135706f2543Smrg */ 136706f2543Smrgstatic void 137706f2543SmrgPrintComment(DisplayModeRec *Mode, Bool CVT, Bool Reduced) 138706f2543Smrg{ 139706f2543Smrg printf("# %dx%d %.2f Hz ", Mode->HDisplay, Mode->VDisplay, Mode->VRefresh); 140706f2543Smrg 141706f2543Smrg if (CVT) { 142706f2543Smrg printf("(CVT %.2fM", 143706f2543Smrg ((float) Mode->HDisplay * Mode->VDisplay) / 1000000.0); 144706f2543Smrg 145706f2543Smrg if (!(Mode->VDisplay % 3) && 146706f2543Smrg ((Mode->VDisplay * 4 / 3) == Mode->HDisplay)) 147706f2543Smrg printf("3"); 148706f2543Smrg else if (!(Mode->VDisplay % 9) && 149706f2543Smrg ((Mode->VDisplay * 16 / 9) == Mode->HDisplay)) 150706f2543Smrg printf("9"); 151706f2543Smrg else if (!(Mode->VDisplay % 10) && 152706f2543Smrg ((Mode->VDisplay * 16 / 10) == Mode->HDisplay)) 153706f2543Smrg printf("A"); 154706f2543Smrg else if (!(Mode->VDisplay % 4) && 155706f2543Smrg ((Mode->VDisplay * 5 / 4) == Mode->HDisplay)) 156706f2543Smrg printf("4"); 157706f2543Smrg else if (!(Mode->VDisplay % 9) && 158706f2543Smrg ((Mode->VDisplay * 15 / 9) == Mode->HDisplay)) 159706f2543Smrg printf("9"); 160706f2543Smrg 161706f2543Smrg if (Reduced) 162706f2543Smrg printf("-R"); 163706f2543Smrg 164706f2543Smrg printf(") "); 165706f2543Smrg } else 166706f2543Smrg printf("(CVT) "); 167706f2543Smrg 168706f2543Smrg printf("hsync: %.2f kHz; ", Mode->HSync); 169706f2543Smrg printf("pclk: %.2f MHz", ((float ) Mode->Clock) / 1000.0); 170706f2543Smrg 171706f2543Smrg printf("\n"); 172706f2543Smrg} 173706f2543Smrg 174706f2543Smrg 175706f2543Smrg/* 176706f2543Smrg * Originally grabbed from xf86Mode.c. 177706f2543Smrg * 178706f2543Smrg * Ignoring the actual Mode->name, as the user will want something solid 179706f2543Smrg * to grab hold of. 180706f2543Smrg */ 181706f2543Smrgstatic void 182706f2543SmrgPrintModeline(DisplayModePtr Mode, int HDisplay, int VDisplay, float VRefresh, 183706f2543Smrg Bool Reduced) 184706f2543Smrg{ 185706f2543Smrg if (Reduced) 186706f2543Smrg printf("Modeline \"%dx%dR\" ", HDisplay, VDisplay); 187706f2543Smrg else 188706f2543Smrg printf("Modeline \"%dx%d_%.2f\" ", HDisplay, VDisplay, VRefresh); 189706f2543Smrg 190706f2543Smrg printf("%6.2f %i %i %i %i %i %i %i %i", Mode->Clock/1000., Mode->HDisplay, 191706f2543Smrg Mode->HSyncStart, Mode->HSyncEnd, Mode->HTotal, Mode->VDisplay, 192706f2543Smrg Mode->VSyncStart, Mode->VSyncEnd, Mode->VTotal); 193706f2543Smrg 194706f2543Smrg if (Mode->Flags & V_INTERLACE) 195706f2543Smrg printf(" interlace"); 196706f2543Smrg if (Mode->Flags & V_PHSYNC) 197706f2543Smrg printf(" +hsync"); 198706f2543Smrg if (Mode->Flags & V_NHSYNC) 199706f2543Smrg printf(" -hsync"); 200706f2543Smrg if (Mode->Flags & V_PVSYNC) 201706f2543Smrg printf(" +vsync"); 202706f2543Smrg if (Mode->Flags & V_NVSYNC) 203706f2543Smrg printf(" -vsync"); 204706f2543Smrg 205706f2543Smrg printf("\n"); 206706f2543Smrg} 207706f2543Smrg 208706f2543Smrg 209706f2543Smrg/* 210706f2543Smrg * 211706f2543Smrg */ 212706f2543Smrgint 213706f2543Smrgmain (int argc, char *argv[]) 214706f2543Smrg{ 215706f2543Smrg DisplayModeRec *Mode; 216706f2543Smrg int HDisplay = 0, VDisplay = 0; 217706f2543Smrg float VRefresh = 0.0; 218706f2543Smrg Bool Reduced = FALSE, Verbose = FALSE, IsCVT; 219706f2543Smrg Bool Interlaced = FALSE; 220706f2543Smrg int n; 221706f2543Smrg 222706f2543Smrg if ((argc < 3) || (argc > 7)) { 223706f2543Smrg PrintUsage(argv[0]); 224706f2543Smrg return 1; 225706f2543Smrg } 226706f2543Smrg 227706f2543Smrg /* This doesn't filter out bad flags properly. Bad flags get passed down 228706f2543Smrg * to atoi/atof, which then return 0, so that these variables can get 229706f2543Smrg * filled next time round. So this is just a cosmetic problem. 230706f2543Smrg */ 231706f2543Smrg for (n = 1; n < argc; n++) { 232706f2543Smrg if (!strcmp(argv[n], "-r") || !strcmp(argv[n], "--reduced")) 233706f2543Smrg Reduced = TRUE; 234706f2543Smrg else if (!strcmp(argv[n], "-i") || !strcmp(argv[n], "--interlaced")) 235706f2543Smrg Interlaced = TRUE; 236706f2543Smrg else if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--verbose")) 237706f2543Smrg Verbose = TRUE; 238706f2543Smrg else if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help")) { 239706f2543Smrg PrintUsage(argv[0]); 240706f2543Smrg return 0; 241706f2543Smrg } else if (!HDisplay) { 242706f2543Smrg HDisplay = atoi(argv[n]); 243706f2543Smrg if (!HDisplay) { 244706f2543Smrg PrintUsage(argv[0]); 245706f2543Smrg return 1; 246706f2543Smrg } 247706f2543Smrg } 248706f2543Smrg else if (!VDisplay) { 249706f2543Smrg VDisplay = atoi(argv[n]); 250706f2543Smrg if (!VDisplay) { 251706f2543Smrg PrintUsage(argv[0]); 252706f2543Smrg return 1; 253706f2543Smrg } 254706f2543Smrg } 255706f2543Smrg else if (!VRefresh) { 256706f2543Smrg VRefresh = atof(argv[n]); 257706f2543Smrg if (!VRefresh) { 258706f2543Smrg PrintUsage(argv[0]); 259706f2543Smrg return 1; 260706f2543Smrg } 261706f2543Smrg } 262706f2543Smrg else { 263706f2543Smrg PrintUsage(argv[0]); 264706f2543Smrg return 1; 265706f2543Smrg } 266706f2543Smrg } 267706f2543Smrg 268706f2543Smrg if (!HDisplay || !VDisplay) { 269706f2543Smrg PrintUsage(argv[0]); 270706f2543Smrg return 0; 271706f2543Smrg } 272706f2543Smrg 273706f2543Smrg /* Default to 60.0Hz */ 274706f2543Smrg if (!VRefresh) 275706f2543Smrg VRefresh = 60.0; 276706f2543Smrg 277706f2543Smrg /* Horizontal timing is always a multiple of 8: round up. */ 278706f2543Smrg if (HDisplay & 0x07) { 279706f2543Smrg HDisplay &= ~0x07; 280706f2543Smrg HDisplay += 8; 281706f2543Smrg } 282706f2543Smrg 283706f2543Smrg if (Reduced) { 284706f2543Smrg if ((VRefresh / 60.0) != floor(VRefresh / 60.0)) { 285706f2543Smrg fprintf(stderr, 286706f2543Smrg "\nERROR: Multiple of 60Hz refresh rate required for " 287706f2543Smrg " reduced blanking.\n"); 288706f2543Smrg PrintUsage(argv[0]); 289706f2543Smrg return 0; 290706f2543Smrg } 291706f2543Smrg } 292706f2543Smrg 293706f2543Smrg IsCVT = CVTCheckStandard(HDisplay, VDisplay, VRefresh, Reduced, Verbose); 294706f2543Smrg 295706f2543Smrg Mode = xf86CVTMode(HDisplay, VDisplay, VRefresh, Reduced, Interlaced); 296706f2543Smrg 297706f2543Smrg PrintComment(Mode, IsCVT, Reduced); 298706f2543Smrg PrintModeline(Mode, HDisplay, VDisplay, VRefresh, Reduced); 299706f2543Smrg 300706f2543Smrg return 0; 301706f2543Smrg} 302