Home | History | Annotate | Line # | Download | only in grfconfig
      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 
     54 static void print_modeline(FILE *fp, struct grfvideo_mode *, int);
     55 static void suggest(struct grfvideo_mode *, const char *, const char *);
     56 
     57 static 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  */
     74 int
     75 main(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 
    352 static void
    353 suggest(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 
    361 static void
    362 print_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