xref: /netbsd-src/usr.sbin/grfconfig/grfconfig.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: grfconfig.c,v 1.15 2011/01/04 09:32:31 wiz 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.15 2011/01/04 09:32:31 wiz 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 
53 int main __P((int, char **));
54 static void print_rawdata __P((struct grfvideo_mode *, int));
55 
56 static 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  */
73 int
74 main(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 
412 static void
413 print_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