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
53int main __P((int, char **));
54static void print_rawdata __P((struct grfvideo_mode *, int));
55
56static 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 */
73int
74main(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
412static void
413print_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