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
main(int ac,char ** av)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
suggest(struct grfvideo_mode * gv,const char * d,const char * s)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
print_modeline(FILE * fp,struct grfvideo_mode * gv,int rawflags)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