xref: /netbsd-src/usr.sbin/grfconfig/grfconfig.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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 
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 			return (1);
131 		}
132 		while (fgets(buf, sizeof(buf), fp)) {
133 			char *obuf, tbuf[_POSIX2_LINE_MAX], *tbuf2;
134 			/*
135 			 * check for end-of-section, comments, strip off trailing
136 			 * spaces and newline character.
137 			 */
138 			for (p = buf; isspace((unsigned char)*p); ++p)
139 				continue;
140 			if (*p == '\0' || *p == '#')
141 				continue;
142 			for (p = strchr(buf, '\0'); isspace((unsigned char)*--p);)
143 				continue;
144 			*++p = '\0';
145 
146 			obuf = buf;
147 			tbuf2 = tbuf;
148 			while ((*tbuf2 = *obuf) != '\0') {
149 				if (*tbuf2 == '#') {
150 					*tbuf2 = '\0';
151 					break;
152 				}
153 				if (isupper((unsigned char)*tbuf2)) {
154 					*tbuf2 = tolower((unsigned char)*tbuf2);
155 				}
156 				obuf++;
157 				tbuf2++;
158 			}
159 			obuf = tbuf;
160 
161 			lineno = lineno + 1;
162 
163 			for (i = 0, *cps = strtok(buf, " \b\t\r\n");
164 			    cps[i] != NULL && i < 30; i++)
165 				cps[i + 1] = strtok(NULL, " \b\t\r\n");
166 			cps[i] = NULL;
167 
168 			if (i < 14) {
169 				printf("grfconfig: too few values in mode "
170 				    "definition file:\n %s\n", obuf);
171 				return (1);
172 			}
173 
174 			gv->pixel_clock	= atoi(cps[1]);
175 			gv->disp_width	= atoi(cps[2]);
176 			gv->disp_height	= atoi(cps[3]);
177 			gv->depth	= atoi(cps[4]);
178 			gv->hblank_start	= atoi(cps[5]);
179 			gv->hsync_start	= atoi(cps[6]);
180 			gv->hsync_stop	= atoi(cps[7]);
181 			gv->htotal	= atoi(cps[8]);
182 			gv->vblank_start	= atoi(cps[9]);
183 			gv->vsync_start	= atoi(cps[10]);
184 			gv->vsync_stop	= atoi(cps[11]);
185 			gv->vtotal	= atoi(cps[12]);
186 
187 			if ((y = atoi(cps[0])))
188 				gv->mode_num = y;
189 			else
190 				if (strncasecmp("c", cps[0], 1) == 0) {
191 					gv->mode_num = 255;
192 					gv->depth = 4;
193 				} else {
194 					printf("grfconfig: Illegal mode "
195 					    "number: %s\n", cps[0]);
196 					return (1);
197 				}
198 
199 			if ((gv->pixel_clock == 0) ||
200 			    (gv->disp_width == 0) ||
201 			    (gv->disp_height == 0) ||
202 			    (gv->depth == 0) ||
203 			    (gv->hblank_start == 0) ||
204 			    (gv->hsync_start == 0) ||
205 			    (gv->hsync_stop == 0) ||
206 			    (gv->htotal == 0) ||
207 			    (gv->vblank_start == 0) ||
208 			    (gv->vsync_start == 0) ||
209 			    (gv->vsync_stop == 0) ||
210 			    (gv->vtotal == 0)) {
211 				printf("grfconfig: Illegal value in "
212 				    "mode #%d:\n %s\n", gv->mode_num, obuf);
213 				return (1);
214 			}
215 
216 			if (strstr(obuf, "default") != NULL) {
217 				gv->disp_flags = GRF_FLAGS_DEFAULT;
218 			} else {
219 				gv->disp_flags = GRF_FLAGS_DEFAULT;
220 				for (grf_flagp = grf_flags;
221 				  grf_flagp->grf_flag_number; grf_flagp++) {
222 				    if (strstr(obuf, grf_flagp->grf_flag_name) != NULL) {
223 					gv->disp_flags |= grf_flagp->grf_flag_number;
224 				    }
225 				}
226 				if (gv->disp_flags == GRF_FLAGS_DEFAULT) {
227 					printf("grfconfig: Your are using an "
228 					    "mode file with an obsolete "
229 					    "format.\n See the manpage of "
230 					    "grfconfig for more information "
231 					    "about the new mode definition "
232 					    "file.\n");
233 					return (1);
234 				}
235 			}
236 
237 			/*
238 			 * Check for impossible gv->disp_flags:
239 			 * doublescan and interlace,
240 			 * +hsync and -hsync
241 			 * +vsync and -vsync.
242 			 */
243 			errortext = NULL;
244 			if ((gv->disp_flags & GRF_FLAGS_DBLSCAN) &&
245 			    (gv->disp_flags & GRF_FLAGS_LACE))
246 				errortext = "Interlace and Doublescan";
247 			if ((gv->disp_flags & GRF_FLAGS_PHSYNC) &&
248 			    (gv->disp_flags & GRF_FLAGS_NHSYNC))
249 				errortext = "+hsync and -hsync";
250 			if ((gv->disp_flags & GRF_FLAGS_PVSYNC) &&
251 			    (gv->disp_flags & GRF_FLAGS_NVSYNC))
252 				errortext = "+vsync and -vsync";
253 
254 			if (errortext != NULL) {
255 				printf("grfconfig: Illegal flags in "
256 				    "mode #%d: %s are both defined!\n",
257 				    gv->mode_num, errortext);
258 				return (1);
259 			}
260 
261 			/* Check for old horizontal cycle values */
262 			if ((gv->htotal < (gv->disp_width / 4))) {
263 				gv->hblank_start *= 8;
264 				gv->hsync_start *= 8;
265 				gv->hsync_stop *= 8;
266 				gv->htotal *= 8;
267 				printf("grfconfig: Old and no longer "
268 				    "supported horizontal videoclock cycle "
269 				    "values.\n Wrong mode line:\n  %s\n "
270 				    "This could be a possible good mode "
271 				    "line:\n  ", obuf);
272 				printf("%d ", gv->mode_num);
273 				print_rawdata(gv, 0);
274 				printf(" See the manpage of grfconfig for "
275 				    "more information about the new mode "
276 				    "definition file.\n");
277 				return (1);
278 			}
279 
280 			/* Check for old interlace or doublescan modes */
281 			uplim = gv->disp_height + (gv->disp_height / 4);
282 			lowlim = gv->disp_height - (gv->disp_height / 4);
283 			if (((gv->vtotal * 2) > lowlim) &&
284 			    ((gv->vtotal * 2) < uplim)) {
285 				gv->vblank_start *= 2;
286 				gv->vsync_start *= 2;
287 				gv->vsync_stop *= 2;
288 				gv->vtotal *= 2;
289 				gv->disp_flags &= ~GRF_FLAGS_DBLSCAN;
290 				gv->disp_flags |= GRF_FLAGS_LACE;
291 				printf("grfconfig: Old and no longer "
292 				    "supported vertical values for "
293 				    "interlace modes.\n Wrong mode "
294 				    "line:\n  %s\n This could be a "
295 				    "possible good mode line:\n  ", obuf);
296 				printf("%d ", gv->mode_num);
297 				print_rawdata(gv, 0);
298 				printf(" See the manpage of grfconfig for "
299 				    "more information about the new mode "
300 				    "definition file.\n");
301 				return (1);
302 			} else if (((gv->vtotal / 2) > lowlim) &&
303 			    ((gv->vtotal / 2) < uplim)) {
304 				gv->vblank_start /= 2;
305 				gv->vsync_start /= 2;
306 				gv->vsync_stop /= 2;
307 				gv->vtotal /= 2;
308 				gv->disp_flags &= ~GRF_FLAGS_LACE;
309 				gv->disp_flags |= GRF_FLAGS_DBLSCAN;
310 				printf("grfconfig: Old and no longer "
311 				    "supported vertical values for "
312 				    "doublescan modes.\n Wrong mode "
313 				    "line:\n  %s\n This could be a "
314 				    "possible good mode line:\n  ", obuf);
315 				printf("%d ", gv->mode_num);
316 				print_rawdata(gv, 0);
317 				printf(" See the manpage of grfconfig for "
318 				    "more information about the new mode "
319 				    "definition file.\n");
320 				return (1);
321 			}
322 
323 			if (testmode == 1) {
324 				if (lineno == 1)
325 					printf("num clk wid hi dep hbs "
326 					    "hss hse ht vbs vss vse vt "
327 					    "flags\n");
328 				printf("%d ", gv->mode_num);
329 				print_rawdata(gv, 1);
330 			} else {
331 				gv->mode_descr[0] = 0;
332 				if (ioctl(grffd, GRFIOCSETMON, (char *) gv) < 0)
333 					printf("grfconfig: bad monitor "
334 					    "definition for mode #%d.\n",
335 					    gv->mode_num);
336 			}
337 		}
338 		fclose(fp);
339 	} else {
340 		ioctl(grffd, GRFGETNUMVM, &y);
341 		y += 2;
342 		for (c = 1; c < y; c++) {
343 			c = gv->mode_num = (c != (y - 1)) ? c : 255;
344 			if (ioctl(grffd, GRFGETVMODE, gv) < 0)
345 				continue;
346 			if (rawdata) {
347 				if (c == 255)
348 					printf("c ");
349 				else
350 					printf("%d ", c);
351 				print_rawdata(gv, 0);
352 				continue;
353 			}
354 			if (c == 255)
355 				printf("Console: ");
356 			else
357 				printf("%2d: ", gv->mode_num);
358 
359 			printf("%dx%d",
360 			    gv->disp_width,
361 			    gv->disp_height);
362 
363 			if (c != 255)
364 				printf("x%d", gv->depth);
365 			else
366 				printf(" (%dx%d)",
367 				    gv->disp_width / 8,
368 				    gv->disp_height / gv->depth);
369 
370 			printf("\t%ld.%ldkHz @ %ldHz",
371 			    gv->pixel_clock / (gv->htotal * 1000),
372 			    (gv->pixel_clock / (gv->htotal * 100))
373     	    	    	    	% 10,
374 			    gv->pixel_clock / (gv->htotal * gv->vtotal));
375 			printf(" flags:");
376 
377 			if (gv->disp_flags == GRF_FLAGS_DEFAULT) {
378 				printf(" default");
379 			} else {
380 				for (grf_flagp = grf_flags;
381 				  grf_flagp->grf_flag_number; grf_flagp++) {
382 				    if (gv->disp_flags & grf_flagp->grf_flag_number) {
383 					printf(" %s", grf_flagp->grf_flag_name);
384 				    }
385 				}
386 			}
387 			printf("\n");
388 		}
389 	}
390 
391 	close(grffd);
392 	return (0);
393 }
394 
395 static void
396 print_rawdata(gv, rawflags)
397 	struct grfvideo_mode *gv;
398 	int rawflags;
399 {
400 	struct	grf_flag *grf_flagp;
401 
402 	printf("%ld %d %d %d %d %d %d %d %d %d %d %d",
403 		gv->pixel_clock,
404 		gv->disp_width,
405 		gv->disp_height,
406 		gv->depth,
407 		gv->hblank_start,
408 		gv->hsync_start,
409 		gv->hsync_stop,
410 		gv->htotal,
411 		gv->vblank_start,
412 		gv->vsync_start,
413 		gv->vsync_stop,
414 		gv->vtotal);
415 		if (rawflags) {
416 			printf(" 0x%.2x", gv->disp_flags);
417 		} else {
418 			if (gv->disp_flags == GRF_FLAGS_DEFAULT) {
419 				printf(" default");
420 			} else {
421 				for (grf_flagp = grf_flags;
422 				  grf_flagp->grf_flag_number; grf_flagp++) {
423 				    if (gv->disp_flags & grf_flagp->grf_flag_number) {
424 					printf(" %s", grf_flagp->grf_flag_name);
425 				    }
426 				}
427 			}
428 		}
429 		printf("\n");
430 }
431