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