1/* $NetBSD: grfconfig.c,v 1.16 2016/02/29 18:59:52 christos 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.16 2016/02/29 18:59:52 christos Exp $"); 40#endif /* not lint */ 41 42#include <sys/file.h> 43#include <sys/ioctl.h> 44#include <err.h> 45#include <ctype.h> 46#include <limits.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <unistd.h> 51 52#include <amiga/dev/grfioctl.h> 53 54static void print_modeline(FILE *fp, struct grfvideo_mode *, int); 55static void suggest(struct grfvideo_mode *, const char *, const char *); 56 57static struct grf_flag { 58 u_short grf_flag_number; 59 const char *grf_flag_name; 60} grf_flags[] = { 61 {GRF_FLAGS_DBLSCAN, "doublescan"}, 62 {GRF_FLAGS_LACE, "interlace"}, 63 {GRF_FLAGS_PHSYNC, "+hsync"}, 64 {GRF_FLAGS_NHSYNC, "-hsync"}, 65 {GRF_FLAGS_PVSYNC, "+vsync"}, 66 {GRF_FLAGS_NVSYNC, "-vsync"}, 67 {GRF_FLAGS_SYNC_ON_GREEN, "sync-on-green"}, 68 {0, 0} 69}; 70 71/* 72 * Dynamic mode loader for NetBSD/Amiga grf devices. 73 */ 74int 75main(int ac, char **av) 76{ 77 struct grfvideo_mode gv[1]; 78 struct grf_flag *grf_flagp; 79 FILE *fp; 80 int c, y, grffd; 81 size_t i; 82 int lineno = 0; 83 int uplim, lowlim; 84 char rawdata = 0, testmode = 0; 85 char *grfdevice = 0, *ptr; 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 errx(EXIT_FAILURE, "No grf device specified"); 112 grfdevice = av[0]; 113 114 if (ac >= 2) 115 modefile = av[1]; 116 117 if ((grffd = open(grfdevice, O_RDWR)) == -1) 118 err(EXIT_FAILURE, "Can't open grf device `%s'", grfdevice); 119 120 /* If a mode file is specificied, load it in, don't display any info. */ 121 122 if (modefile) { 123 if (!(fp = fopen(modefile, "r"))) 124 err(EXIT_FAILURE, 125 "Cannot open mode definition file `%s'", modefile); 126 127 while (fgets(buf, sizeof(buf), fp)) { 128 char *obuf, tbuf[_POSIX2_LINE_MAX], *tbuf2; 129 /* 130 * check for end-of-section, comments, strip off trailing 131 * spaces and newline character. 132 */ 133 for (p = buf; isspace((unsigned char)*p); ++p) 134 continue; 135 if (*p == '\0' || *p == '#') 136 continue; 137 for (p = strchr(buf, '\0'); isspace((unsigned char)*--p);) 138 continue; 139 *++p = '\0'; 140 141 obuf = buf; 142 tbuf2 = tbuf; 143 while ((*tbuf2 = *obuf) != '\0') { 144 if (*tbuf2 == '#') { 145 *tbuf2 = '\0'; 146 break; 147 } 148 if (isupper((unsigned char)*tbuf2)) { 149 *tbuf2 = tolower((unsigned char)*tbuf2); 150 } 151 obuf++; 152 tbuf2++; 153 } 154 obuf = tbuf; 155 156 lineno = lineno + 1; 157 158#define SP " \b\t\r\n" 159 memset(cps, 0, sizeof(cps)); 160 for (i = 0, ptr = strtok(buf, SP); 161 ptr != NULL && i < __arraycount(cps); 162 i++, ptr = strtok(NULL, SP)) 163 cps[i] = ptr; 164 165 166 if (i < 14) 167 errx(EXIT_FAILURE, "Too few values in mode " 168 "definition file: `%s'\n", obuf); 169 170 gv->pixel_clock = atoi(cps[1]); 171 gv->disp_width = atoi(cps[2]); 172 gv->disp_height = atoi(cps[3]); 173 gv->depth = atoi(cps[4]); 174 gv->hblank_start = atoi(cps[5]); 175 gv->hsync_start = atoi(cps[6]); 176 gv->hsync_stop = atoi(cps[7]); 177 gv->htotal = atoi(cps[8]); 178 gv->vblank_start = atoi(cps[9]); 179 gv->vsync_start = atoi(cps[10]); 180 gv->vsync_stop = atoi(cps[11]); 181 gv->vtotal = atoi(cps[12]); 182 183 if ((y = atoi(cps[0]))) 184 gv->mode_num = y; 185 else 186 if (strncasecmp("c", cps[0], 1) == 0) { 187 gv->mode_num = 255; 188 gv->depth = 4; 189 } else { 190 errx(EXIT_FAILURE, 191 "Illegal mode number: %s", cps[0]); 192 } 193 194 if ((gv->pixel_clock == 0) || 195 (gv->disp_width == 0) || 196 (gv->disp_height == 0) || 197 (gv->depth == 0) || 198 (gv->hblank_start == 0) || 199 (gv->hsync_start == 0) || 200 (gv->hsync_stop == 0) || 201 (gv->htotal == 0) || 202 (gv->vblank_start == 0) || 203 (gv->vsync_start == 0) || 204 (gv->vsync_stop == 0) || 205 (gv->vtotal == 0)) { 206 errx(EXIT_FAILURE, "Illegal value in " 207 "mode #%d: `%s'", gv->mode_num, obuf); 208 } 209 210 if (strstr(obuf, "default") != NULL) { 211 gv->disp_flags = GRF_FLAGS_DEFAULT; 212 } else { 213 gv->disp_flags = GRF_FLAGS_DEFAULT; 214 for (grf_flagp = grf_flags; 215 grf_flagp->grf_flag_number; grf_flagp++) { 216 if (strstr(obuf, grf_flagp->grf_flag_name) != NULL) { 217 gv->disp_flags |= grf_flagp->grf_flag_number; 218 } 219 } 220 if (gv->disp_flags == GRF_FLAGS_DEFAULT) 221 errx(EXIT_FAILURE, "Your are using a " 222 "mode file with an obsolete " 223 "format"); 224 } 225 226 /* 227 * Check for impossible gv->disp_flags: 228 * doublescan and interlace, 229 * +hsync and -hsync 230 * +vsync and -vsync. 231 */ 232 errortext = NULL; 233 if ((gv->disp_flags & GRF_FLAGS_DBLSCAN) && 234 (gv->disp_flags & GRF_FLAGS_LACE)) 235 errortext = "Interlace and Doublescan"; 236 if ((gv->disp_flags & GRF_FLAGS_PHSYNC) && 237 (gv->disp_flags & GRF_FLAGS_NHSYNC)) 238 errortext = "+hsync and -hsync"; 239 if ((gv->disp_flags & GRF_FLAGS_PVSYNC) && 240 (gv->disp_flags & GRF_FLAGS_NVSYNC)) 241 errortext = "+vsync and -vsync"; 242 243 if (errortext != NULL) 244 errx(EXIT_FAILURE, "Illegal flags in " 245 "mode #%d: `%s' are both defined", 246 gv->mode_num, errortext); 247 248 /* Check for old horizontal cycle values */ 249 if ((gv->htotal < (gv->disp_width / 4))) { 250 gv->hblank_start *= 8; 251 gv->hsync_start *= 8; 252 gv->hsync_stop *= 8; 253 gv->htotal *= 8; 254 suggest(gv, "horizontal videoclock cycle " 255 "values", obuf); 256 return EXIT_FAILURE; 257 } 258 259 /* Check for old interlace or doublescan modes */ 260 uplim = gv->disp_height + (gv->disp_height / 4); 261 lowlim = gv->disp_height - (gv->disp_height / 4); 262 if (((gv->vtotal * 2) > lowlim) && 263 ((gv->vtotal * 2) < uplim)) { 264 gv->vblank_start *= 2; 265 gv->vsync_start *= 2; 266 gv->vsync_stop *= 2; 267 gv->vtotal *= 2; 268 gv->disp_flags &= ~GRF_FLAGS_DBLSCAN; 269 gv->disp_flags |= GRF_FLAGS_LACE; 270 suggest(gv, "vertical values for interlace " 271 "modes", obuf); 272 return EXIT_FAILURE; 273 } else if (((gv->vtotal / 2) > lowlim) && 274 ((gv->vtotal / 2) < uplim)) { 275 gv->vblank_start /= 2; 276 gv->vsync_start /= 2; 277 gv->vsync_stop /= 2; 278 gv->vtotal /= 2; 279 gv->disp_flags &= ~GRF_FLAGS_LACE; 280 gv->disp_flags |= GRF_FLAGS_DBLSCAN; 281 suggest(gv, "vertical values for doublescan " 282 "modes", obuf); 283 return EXIT_FAILURE; 284 } 285 286 if (testmode == 1) { 287 if (lineno == 1) 288 printf("num clk wid hi dep hbs " 289 "hss hse ht vbs vss vse vt " 290 "flags\n"); 291 print_modeline(stdout, gv, 1); 292 } else { 293 gv->mode_descr[0] = 0; 294 if (ioctl(grffd, GRFIOCSETMON, (char *) gv) < 0) 295 err(EXIT_FAILURE, "bad monitor " 296 "definition for mode #%d", 297 gv->mode_num); 298 } 299 } 300 fclose(fp); 301 } else { 302 ioctl(grffd, GRFGETNUMVM, &y); 303 y += 2; 304 for (c = 1; c < y; c++) { 305 c = gv->mode_num = (c != (y - 1)) ? c : 255; 306 if (ioctl(grffd, GRFGETVMODE, gv) < 0) 307 continue; 308 if (rawdata) { 309 print_modeline(stdout, gv, 0); 310 continue; 311 } 312 if (c == 255) 313 printf("Console: "); 314 else 315 printf("%2d: ", gv->mode_num); 316 317 printf("%dx%d", 318 gv->disp_width, 319 gv->disp_height); 320 321 if (c != 255) 322 printf("x%d", gv->depth); 323 else 324 printf(" (%dx%d)", 325 gv->disp_width / 8, 326 gv->disp_height / gv->depth); 327 328 printf("\t%ld.%ldkHz @ %ldHz", 329 gv->pixel_clock / (gv->htotal * 1000), 330 (gv->pixel_clock / (gv->htotal * 100)) 331 % 10, 332 gv->pixel_clock / (gv->htotal * gv->vtotal)); 333 printf(" flags:"); 334 335 if (gv->disp_flags == GRF_FLAGS_DEFAULT) { 336 printf(" default\n"); 337 continue; 338 } 339 340 for (grf_flagp = grf_flags; 341 grf_flagp->grf_flag_number; grf_flagp++) 342 if (gv->disp_flags & grf_flagp->grf_flag_number) 343 printf(" %s", grf_flagp->grf_flag_name); 344 printf("\n"); 345 } 346 } 347 348 close(grffd); 349 return EXIT_SUCCESS; 350} 351 352static void 353suggest(struct grfvideo_mode *gv, const char *d, const char *s) 354{ 355 warnx("Old and no longer supported %s: %s", d, s); 356 warnx("Wrong mode line, this could be a possible good model line:"); 357 fprintf(stderr, "%s: ", getprogname()); 358 print_modeline(stderr, gv, 0); 359} 360 361static void 362print_modeline(FILE *fp, struct grfvideo_mode *gv, int rawflags) 363{ 364 struct grf_flag *grf_flagp; 365 366 if (gv->mode_num == 255) 367 fprintf(fp, "c "); 368 else 369 fprintf(fp, "%d ", gv->mode_num); 370 371 fprintf(fp, "%ld %d %d %d %d %d %d %d %d %d %d %d", 372 gv->pixel_clock, 373 gv->disp_width, 374 gv->disp_height, 375 gv->depth, 376 gv->hblank_start, 377 gv->hsync_start, 378 gv->hsync_stop, 379 gv->htotal, 380 gv->vblank_start, 381 gv->vsync_start, 382 gv->vsync_stop, 383 gv->vtotal); 384 385 if (rawflags) { 386 fprintf(fp, " 0x%.2x\n", gv->disp_flags); 387 return; 388 } 389 if (gv->disp_flags == GRF_FLAGS_DEFAULT) { 390 fprintf(fp, " default\n"); 391 return; 392 } 393 394 for (grf_flagp = grf_flags; grf_flagp->grf_flag_number; grf_flagp++) 395 if (gv->disp_flags & grf_flagp->grf_flag_number) 396 fprintf(fp, " %s", grf_flagp->grf_flag_name); 397 fprintf(fp, "\n"); 398} 399