1/* $NetBSD: grfconfig.c,v 1.14 2009/04/26 19:24:18 mlelstv Exp $ */ 2 3/*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Ezra Story and Bernd Ernesti. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1997\ 35 The NetBSD Foundation, Inc. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39__RCSID("$NetBSD: grfconfig.c,v 1.14 2009/04/26 19:24:18 mlelstv Exp $"); 40#endif /* not lint */ 41 42#include <sys/file.h> 43#include <sys/ioctl.h> 44#include <ctype.h> 45#include <limits.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49#include <unistd.h> 50 51#include <amiga/dev/grfioctl.h> 52 53int main __P((int, char **)); 54static void print_rawdata __P((struct grfvideo_mode *, int)); 55 56static struct grf_flag { 57 u_short grf_flag_number; 58 const char *grf_flag_name; 59} grf_flags[] = { 60 {GRF_FLAGS_DBLSCAN, "doublescan"}, 61 {GRF_FLAGS_LACE, "interlace"}, 62 {GRF_FLAGS_PHSYNC, "+hsync"}, 63 {GRF_FLAGS_NHSYNC, "-hsync"}, 64 {GRF_FLAGS_PVSYNC, "+vsync"}, 65 {GRF_FLAGS_NVSYNC, "-vsync"}, 66 {GRF_FLAGS_SYNC_ON_GREEN, "sync-on-green"}, 67 {0, 0} 68}; 69 70/* 71 * Dynamic mode loader for NetBSD/Amiga grf devices. 72 */ 73int 74main(ac, av) 75 int ac; 76 char **av; 77{ 78 struct grfvideo_mode gv[1]; 79 struct grf_flag *grf_flagp; 80 FILE *fp; 81 int c, y, grffd; 82 int i, lineno = 0; 83 int uplim, lowlim; 84 char rawdata = 0, testmode = 0; 85 char *grfdevice = 0; 86 char *modefile = 0; 87 char buf[_POSIX2_LINE_MAX]; 88 char *cps[31]; 89 char *p; 90 const char *errortext; 91 92 93 while ((c = getopt(ac, av, "rt")) != -1) { 94 switch (c) { 95 case 'r': /* raw output */ 96 rawdata = 1; 97 break; 98 case 't': /* test the modefile without setting it */ 99 testmode = 1; 100 break; 101 default: 102 printf("grfconfig [-r] device [file]\n"); 103 return (1); 104 } 105 } 106 ac -= optind; 107 av += optind; 108 109 110 if (ac >= 1) 111 grfdevice = av[0]; 112 else { 113 printf("grfconfig: No grf device specified.\n"); 114 return (1); 115 } 116 117 if (ac >= 2) 118 modefile = av[1]; 119 120 if ((grffd = open(grfdevice, O_RDWR)) < 0) { 121 printf("grfconfig: can't open grf device.\n"); 122 return (1); 123 } 124 /* If a mode file is specificied, load it in, don't display any info. */ 125 126 if (modefile) { 127 if (!(fp = fopen(modefile, "r"))) { 128 printf("grfconfig: Cannot open mode definition " 129 "file.\n"); 130 (void)close(grffd); 131 return (1); 132 } 133 while (fgets(buf, sizeof(buf), fp)) { 134 char *obuf, tbuf[_POSIX2_LINE_MAX], *tbuf2; 135 /* 136 * check for end-of-section, comments, strip off trailing 137 * spaces and newline character. 138 */ 139 for (p = buf; isspace((unsigned char)*p); ++p) 140 continue; 141 if (*p == '\0' || *p == '#') 142 continue; 143 for (p = strchr(buf, '\0'); isspace((unsigned char)*--p);) 144 continue; 145 *++p = '\0'; 146 147 obuf = buf; 148 tbuf2 = tbuf; 149 while ((*tbuf2 = *obuf) != '\0') { 150 if (*tbuf2 == '#') { 151 *tbuf2 = '\0'; 152 break; 153 } 154 if (isupper((unsigned char)*tbuf2)) { 155 *tbuf2 = tolower((unsigned char)*tbuf2); 156 } 157 obuf++; 158 tbuf2++; 159 } 160 obuf = tbuf; 161 162 lineno = lineno + 1; 163 164 for (i = 0, *cps = strtok(buf, " \b\t\r\n"); 165 cps[i] != NULL && i < 30; i++) 166 cps[i + 1] = strtok(NULL, " \b\t\r\n"); 167 cps[i] = NULL; 168 169 if (i < 14) { 170 printf("grfconfig: too few values in mode " 171 "definition file:\n %s\n", obuf); 172 (void)fclose(fp); 173 (void)close(grffd); 174 return (1); 175 } 176 177 gv->pixel_clock = atoi(cps[1]); 178 gv->disp_width = atoi(cps[2]); 179 gv->disp_height = atoi(cps[3]); 180 gv->depth = atoi(cps[4]); 181 gv->hblank_start = atoi(cps[5]); 182 gv->hsync_start = atoi(cps[6]); 183 gv->hsync_stop = atoi(cps[7]); 184 gv->htotal = atoi(cps[8]); 185 gv->vblank_start = atoi(cps[9]); 186 gv->vsync_start = atoi(cps[10]); 187 gv->vsync_stop = atoi(cps[11]); 188 gv->vtotal = atoi(cps[12]); 189 190 if ((y = atoi(cps[0]))) 191 gv->mode_num = y; 192 else 193 if (strncasecmp("c", cps[0], 1) == 0) { 194 gv->mode_num = 255; 195 gv->depth = 4; 196 } else { 197 printf("grfconfig: Illegal mode " 198 "number: %s\n", cps[0]); 199 (void)fclose(fp); 200 (void)close(grffd); 201 return (1); 202 } 203 204 if ((gv->pixel_clock == 0) || 205 (gv->disp_width == 0) || 206 (gv->disp_height == 0) || 207 (gv->depth == 0) || 208 (gv->hblank_start == 0) || 209 (gv->hsync_start == 0) || 210 (gv->hsync_stop == 0) || 211 (gv->htotal == 0) || 212 (gv->vblank_start == 0) || 213 (gv->vsync_start == 0) || 214 (gv->vsync_stop == 0) || 215 (gv->vtotal == 0)) { 216 printf("grfconfig: Illegal value in " 217 "mode #%d:\n %s\n", gv->mode_num, obuf); 218 (void)fclose(fp); 219 (void)close(grffd); 220 return (1); 221 } 222 223 if (strstr(obuf, "default") != NULL) { 224 gv->disp_flags = GRF_FLAGS_DEFAULT; 225 } else { 226 gv->disp_flags = GRF_FLAGS_DEFAULT; 227 for (grf_flagp = grf_flags; 228 grf_flagp->grf_flag_number; grf_flagp++) { 229 if (strstr(obuf, grf_flagp->grf_flag_name) != NULL) { 230 gv->disp_flags |= grf_flagp->grf_flag_number; 231 } 232 } 233 if (gv->disp_flags == GRF_FLAGS_DEFAULT) { 234 printf("grfconfig: Your are using an " 235 "mode file with an obsolete " 236 "format.\n See the manpage of " 237 "grfconfig for more information " 238 "about the new mode definition " 239 "file.\n"); 240 (void)fclose(fp); 241 (void)close(grffd); 242 return (1); 243 } 244 } 245 246 /* 247 * Check for impossible gv->disp_flags: 248 * doublescan and interlace, 249 * +hsync and -hsync 250 * +vsync and -vsync. 251 */ 252 errortext = NULL; 253 if ((gv->disp_flags & GRF_FLAGS_DBLSCAN) && 254 (gv->disp_flags & GRF_FLAGS_LACE)) 255 errortext = "Interlace and Doublescan"; 256 if ((gv->disp_flags & GRF_FLAGS_PHSYNC) && 257 (gv->disp_flags & GRF_FLAGS_NHSYNC)) 258 errortext = "+hsync and -hsync"; 259 if ((gv->disp_flags & GRF_FLAGS_PVSYNC) && 260 (gv->disp_flags & GRF_FLAGS_NVSYNC)) 261 errortext = "+vsync and -vsync"; 262 263 if (errortext != NULL) { 264 printf("grfconfig: Illegal flags in " 265 "mode #%d: %s are both defined!\n", 266 gv->mode_num, errortext); 267 (void)fclose(fp); 268 (void)close(grffd); 269 return (1); 270 } 271 272 /* Check for old horizontal cycle values */ 273 if ((gv->htotal < (gv->disp_width / 4))) { 274 gv->hblank_start *= 8; 275 gv->hsync_start *= 8; 276 gv->hsync_stop *= 8; 277 gv->htotal *= 8; 278 printf("grfconfig: Old and no longer " 279 "supported horizontal videoclock cycle " 280 "values.\n Wrong mode line:\n %s\n " 281 "This could be a possible good mode " 282 "line:\n ", obuf); 283 printf("%d ", gv->mode_num); 284 print_rawdata(gv, 0); 285 printf(" See the manpage of grfconfig for " 286 "more information about the new mode " 287 "definition file.\n"); 288 (void)fclose(fp); 289 (void)close(grffd); 290 return (1); 291 } 292 293 /* Check for old interlace or doublescan modes */ 294 uplim = gv->disp_height + (gv->disp_height / 4); 295 lowlim = gv->disp_height - (gv->disp_height / 4); 296 if (((gv->vtotal * 2) > lowlim) && 297 ((gv->vtotal * 2) < uplim)) { 298 gv->vblank_start *= 2; 299 gv->vsync_start *= 2; 300 gv->vsync_stop *= 2; 301 gv->vtotal *= 2; 302 gv->disp_flags &= ~GRF_FLAGS_DBLSCAN; 303 gv->disp_flags |= GRF_FLAGS_LACE; 304 printf("grfconfig: Old and no longer " 305 "supported vertical values for " 306 "interlace modes.\n Wrong mode " 307 "line:\n %s\n This could be a " 308 "possible good mode line:\n ", obuf); 309 printf("%d ", gv->mode_num); 310 print_rawdata(gv, 0); 311 printf(" See the manpage of grfconfig for " 312 "more information about the new mode " 313 "definition file.\n"); 314 (void)fclose(fp); 315 (void)close(grffd); 316 return (1); 317 } else if (((gv->vtotal / 2) > lowlim) && 318 ((gv->vtotal / 2) < uplim)) { 319 gv->vblank_start /= 2; 320 gv->vsync_start /= 2; 321 gv->vsync_stop /= 2; 322 gv->vtotal /= 2; 323 gv->disp_flags &= ~GRF_FLAGS_LACE; 324 gv->disp_flags |= GRF_FLAGS_DBLSCAN; 325 printf("grfconfig: Old and no longer " 326 "supported vertical values for " 327 "doublescan modes.\n Wrong mode " 328 "line:\n %s\n This could be a " 329 "possible good mode line:\n ", obuf); 330 printf("%d ", gv->mode_num); 331 print_rawdata(gv, 0); 332 printf(" See the manpage of grfconfig for " 333 "more information about the new mode " 334 "definition file.\n"); 335 (void)fclose(fp); 336 (void)close(grffd); 337 return (1); 338 } 339 340 if (testmode == 1) { 341 if (lineno == 1) 342 printf("num clk wid hi dep hbs " 343 "hss hse ht vbs vss vse vt " 344 "flags\n"); 345 printf("%d ", gv->mode_num); 346 print_rawdata(gv, 1); 347 } else { 348 gv->mode_descr[0] = 0; 349 if (ioctl(grffd, GRFIOCSETMON, (char *) gv) < 0) 350 printf("grfconfig: bad monitor " 351 "definition for mode #%d.\n", 352 gv->mode_num); 353 } 354 } 355 fclose(fp); 356 } else { 357 ioctl(grffd, GRFGETNUMVM, &y); 358 y += 2; 359 for (c = 1; c < y; c++) { 360 c = gv->mode_num = (c != (y - 1)) ? c : 255; 361 if (ioctl(grffd, GRFGETVMODE, gv) < 0) 362 continue; 363 if (rawdata) { 364 if (c == 255) 365 printf("c "); 366 else 367 printf("%d ", c); 368 print_rawdata(gv, 0); 369 continue; 370 } 371 if (c == 255) 372 printf("Console: "); 373 else 374 printf("%2d: ", gv->mode_num); 375 376 printf("%dx%d", 377 gv->disp_width, 378 gv->disp_height); 379 380 if (c != 255) 381 printf("x%d", gv->depth); 382 else 383 printf(" (%dx%d)", 384 gv->disp_width / 8, 385 gv->disp_height / gv->depth); 386 387 printf("\t%ld.%ldkHz @ %ldHz", 388 gv->pixel_clock / (gv->htotal * 1000), 389 (gv->pixel_clock / (gv->htotal * 100)) 390 % 10, 391 gv->pixel_clock / (gv->htotal * gv->vtotal)); 392 printf(" flags:"); 393 394 if (gv->disp_flags == GRF_FLAGS_DEFAULT) { 395 printf(" default"); 396 } else { 397 for (grf_flagp = grf_flags; 398 grf_flagp->grf_flag_number; grf_flagp++) { 399 if (gv->disp_flags & grf_flagp->grf_flag_number) { 400 printf(" %s", grf_flagp->grf_flag_name); 401 } 402 } 403 } 404 printf("\n"); 405 } 406 } 407 408 close(grffd); 409 return (0); 410} 411 412static void 413print_rawdata(gv, rawflags) 414 struct grfvideo_mode *gv; 415 int rawflags; 416{ 417 struct grf_flag *grf_flagp; 418 419 printf("%ld %d %d %d %d %d %d %d %d %d %d %d", 420 gv->pixel_clock, 421 gv->disp_width, 422 gv->disp_height, 423 gv->depth, 424 gv->hblank_start, 425 gv->hsync_start, 426 gv->hsync_stop, 427 gv->htotal, 428 gv->vblank_start, 429 gv->vsync_start, 430 gv->vsync_stop, 431 gv->vtotal); 432 if (rawflags) { 433 printf(" 0x%.2x", gv->disp_flags); 434 } else { 435 if (gv->disp_flags == GRF_FLAGS_DEFAULT) { 436 printf(" default"); 437 } else { 438 for (grf_flagp = grf_flags; 439 grf_flagp->grf_flag_number; grf_flagp++) { 440 if (gv->disp_flags & grf_flagp->grf_flag_number) { 441 printf(" %s", grf_flagp->grf_flag_name); 442 } 443 } 444 } 445 } 446 printf("\n"); 447} 448