1/* 2 * Copyright 2005-2006 Luc Verhaegen. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24/* Standalone VESA CVT standard timing modelines generator. */ 25 26#include "xf86.h" 27#include "xf86Modes.h" 28 29/* Error implementation used by the server code we built in */ 30void 31Error(const char *str) 32{ 33 perror(str); 34} 35 36/* FatalError implementation used by the server code we built in */ 37void 38FatalError(const char *f, ...) 39{ 40 va_list args; 41 va_start(args, f); 42 vfprintf(stderr, f, args); 43 va_end(args); 44 exit(1); 45} 46 47/* xnfalloc implementation used by the server code we built in */ 48pointer 49XNFalloc(unsigned long n) 50{ 51 pointer r; 52 53 r = malloc(n); 54 if (!r) { 55 perror("malloc failed"); 56 exit(1); 57 } 58 return r; 59} 60 61/* xnfcalloc implementation used by the server code we built in */ 62pointer 63XNFcalloc(unsigned long n) 64{ 65 pointer r; 66 67 r = calloc(1, n); 68 if (!r) { 69 perror("calloc failed"); 70 exit(1); 71 } 72 return r; 73} 74 75/* 76 * Quickly check wether this is a CVT standard mode. 77 */ 78static Bool 79CVTCheckStandard(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, 80 Bool Verbose) 81{ 82 Bool IsCVT = TRUE; 83 84 if ((!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) || 85 (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) || 86 (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) || 87 (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) || 88 (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))) 89 ; 90 else { 91 if (Verbose) 92 fprintf(stderr, "Warning: Aspect Ratio is not CVT standard.\n"); 93 IsCVT = FALSE; 94 } 95 96 if ((VRefresh != 50.0) && (VRefresh != 60.0) && 97 (VRefresh != 75.0) && (VRefresh != 85.0)) { 98 if (Verbose) 99 fprintf(stderr, "Warning: Refresh Rate is not CVT standard " 100 "(50, 60, 75 or 85Hz).\n"); 101 IsCVT = FALSE; 102 } 103 104 return IsCVT; 105} 106 107 108/* 109 * I'm not documenting --interlaced for obvious reasons, even though I did 110 * implement it. I also can't deny having looked at gtf here. 111 */ 112static void 113PrintUsage(char *Name) 114{ 115 fprintf(stderr, "\n"); 116 fprintf(stderr, "usage: %s [-v|--verbose] [-r|--reduced] X Y [refresh]\n", 117 Name); 118 fprintf(stderr, "\n"); 119 fprintf(stderr, " -v|--verbose : Warn about CVT standard adherance.\n"); 120 fprintf(stderr, " -r|--reduced : Create a mode with reduced blanking " 121 "(default: normal blanking).\n"); 122 fprintf(stderr, " X : Desired horizontal resolution " 123 "(multiple of 8, required).\n"); 124 fprintf(stderr, " Y : Desired vertical resolution (required).\n"); 125 fprintf(stderr, " refresh : Desired refresh rate (default: 60.0Hz).\n"); 126 fprintf(stderr, "\n"); 127 128 fprintf(stderr, "Calculates VESA CVT (Coordinated Video Timing) modelines" 129 " for use with X.\n"); 130} 131 132 133/* 134 * 135 */ 136static void 137PrintComment(DisplayModeRec *Mode, Bool CVT, Bool Reduced) 138{ 139 printf("# %dx%d %.2f Hz ", Mode->HDisplay, Mode->VDisplay, Mode->VRefresh); 140 141 if (CVT) { 142 printf("(CVT %.2fM", 143 ((float) Mode->HDisplay * Mode->VDisplay) / 1000000.0); 144 145 if (!(Mode->VDisplay % 3) && 146 ((Mode->VDisplay * 4 / 3) == Mode->HDisplay)) 147 printf("3"); 148 else if (!(Mode->VDisplay % 9) && 149 ((Mode->VDisplay * 16 / 9) == Mode->HDisplay)) 150 printf("9"); 151 else if (!(Mode->VDisplay % 10) && 152 ((Mode->VDisplay * 16 / 10) == Mode->HDisplay)) 153 printf("A"); 154 else if (!(Mode->VDisplay % 4) && 155 ((Mode->VDisplay * 5 / 4) == Mode->HDisplay)) 156 printf("4"); 157 else if (!(Mode->VDisplay % 9) && 158 ((Mode->VDisplay * 15 / 9) == Mode->HDisplay)) 159 printf("9"); 160 161 if (Reduced) 162 printf("-R"); 163 164 printf(") "); 165 } else 166 printf("(CVT) "); 167 168 printf("hsync: %.2f kHz; ", Mode->HSync); 169 printf("pclk: %.2f MHz", ((float ) Mode->Clock) / 1000.0); 170 171 printf("\n"); 172} 173 174 175/* 176 * Originally grabbed from xf86Mode.c. 177 * 178 * Ignoring the actual Mode->name, as the user will want something solid 179 * to grab hold of. 180 */ 181static void 182PrintModeline(DisplayModePtr Mode, int HDisplay, int VDisplay, float VRefresh, 183 Bool Reduced) 184{ 185 if (Reduced) 186 printf("Modeline \"%dx%dR\" ", HDisplay, VDisplay); 187 else 188 printf("Modeline \"%dx%d_%.2f\" ", HDisplay, VDisplay, VRefresh); 189 190 printf("%6.2f %i %i %i %i %i %i %i %i", Mode->Clock/1000., Mode->HDisplay, 191 Mode->HSyncStart, Mode->HSyncEnd, Mode->HTotal, Mode->VDisplay, 192 Mode->VSyncStart, Mode->VSyncEnd, Mode->VTotal); 193 194 if (Mode->Flags & V_INTERLACE) 195 printf(" interlace"); 196 if (Mode->Flags & V_PHSYNC) 197 printf(" +hsync"); 198 if (Mode->Flags & V_NHSYNC) 199 printf(" -hsync"); 200 if (Mode->Flags & V_PVSYNC) 201 printf(" +vsync"); 202 if (Mode->Flags & V_NVSYNC) 203 printf(" -vsync"); 204 205 printf("\n"); 206} 207 208 209/* 210 * 211 */ 212int 213main (int argc, char *argv[]) 214{ 215 DisplayModeRec *Mode; 216 int HDisplay = 0, VDisplay = 0; 217 float VRefresh = 0.0; 218 Bool Reduced = FALSE, Verbose = FALSE, IsCVT; 219 Bool Interlaced = FALSE; 220 int n; 221 222 if ((argc < 3) || (argc > 7)) { 223 PrintUsage(argv[0]); 224 return 1; 225 } 226 227 /* This doesn't filter out bad flags properly. Bad flags get passed down 228 * to atoi/atof, which then return 0, so that these variables can get 229 * filled next time round. So this is just a cosmetic problem. 230 */ 231 for (n = 1; n < argc; n++) { 232 if (!strcmp(argv[n], "-r") || !strcmp(argv[n], "--reduced")) 233 Reduced = TRUE; 234 else if (!strcmp(argv[n], "-i") || !strcmp(argv[n], "--interlaced")) 235 Interlaced = TRUE; 236 else if (!strcmp(argv[n], "-v") || !strcmp(argv[n], "--verbose")) 237 Verbose = TRUE; 238 else if (!strcmp(argv[n], "-h") || !strcmp(argv[n], "--help")) { 239 PrintUsage(argv[0]); 240 return 0; 241 } else if (!HDisplay) { 242 HDisplay = atoi(argv[n]); 243 if (!HDisplay) { 244 PrintUsage(argv[0]); 245 return 1; 246 } 247 } 248 else if (!VDisplay) { 249 VDisplay = atoi(argv[n]); 250 if (!VDisplay) { 251 PrintUsage(argv[0]); 252 return 1; 253 } 254 } 255 else if (!VRefresh) { 256 VRefresh = atof(argv[n]); 257 if (!VRefresh) { 258 PrintUsage(argv[0]); 259 return 1; 260 } 261 } 262 else { 263 PrintUsage(argv[0]); 264 return 1; 265 } 266 } 267 268 if (!HDisplay || !VDisplay) { 269 PrintUsage(argv[0]); 270 return 0; 271 } 272 273 /* Default to 60.0Hz */ 274 if (!VRefresh) 275 VRefresh = 60.0; 276 277 /* Horizontal timing is always a multiple of 8: round up. */ 278 if (HDisplay & 0x07) { 279 HDisplay &= ~0x07; 280 HDisplay += 8; 281 } 282 283 if (Reduced) { 284 if ((VRefresh / 60.0) != floor(VRefresh / 60.0)) { 285 fprintf(stderr, 286 "\nERROR: Multiple of 60Hz refresh rate required for " 287 " reduced blanking.\n"); 288 PrintUsage(argv[0]); 289 return 0; 290 } 291 } 292 293 IsCVT = CVTCheckStandard(HDisplay, VDisplay, VRefresh, Reduced, Verbose); 294 295 Mode = xf86CVTMode(HDisplay, VDisplay, VRefresh, Reduced, Interlaced); 296 297 PrintComment(Mode, IsCVT, Reduced); 298 PrintModeline(Mode, HDisplay, VDisplay, VRefresh, Reduced); 299 300 return 0; 301} 302