grfconfig.c revision 1.16 1 1.16 christos /* $NetBSD: grfconfig.c,v 1.16 2016/02/29 18:59:52 christos Exp $ */
2 1.1 chopps
3 1.5 veego /*-
4 1.5 veego * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 1.1 chopps * All rights reserved.
6 1.1 chopps *
7 1.5 veego * This code is derived from software contributed to The NetBSD Foundation
8 1.5 veego * by Ezra Story and Bernd Ernesti.
9 1.5 veego *
10 1.1 chopps * Redistribution and use in source and binary forms, with or without
11 1.1 chopps * modification, are permitted provided that the following conditions
12 1.1 chopps * are met:
13 1.1 chopps * 1. Redistributions of source code must retain the above copyright
14 1.1 chopps * notice, this list of conditions and the following disclaimer.
15 1.1 chopps * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 chopps * notice, this list of conditions and the following disclaimer in the
17 1.1 chopps * documentation and/or other materials provided with the distribution.
18 1.1 chopps *
19 1.5 veego * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.5 veego * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.5 veego * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.7 jtc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.7 jtc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.5 veego * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.5 veego * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.5 veego * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.5 veego * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.5 veego * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.5 veego * POSSIBILITY OF SUCH DAMAGE.
30 1.1 chopps */
31 1.5 veego
32 1.5 veego #include <sys/cdefs.h>
33 1.5 veego #ifndef lint
34 1.13 lukem __COPYRIGHT("@(#) Copyright (c) 1997\
35 1.13 lukem The NetBSD Foundation, Inc. All rights reserved.");
36 1.5 veego #endif /* not lint */
37 1.5 veego
38 1.5 veego #ifndef lint
39 1.16 christos __RCSID("$NetBSD: grfconfig.c,v 1.16 2016/02/29 18:59:52 christos Exp $");
40 1.5 veego #endif /* not lint */
41 1.5 veego
42 1.5 veego #include <sys/file.h>
43 1.5 veego #include <sys/ioctl.h>
44 1.16 christos #include <err.h>
45 1.5 veego #include <ctype.h>
46 1.5 veego #include <limits.h>
47 1.1 chopps #include <stdio.h>
48 1.1 chopps #include <stdlib.h>
49 1.1 chopps #include <string.h>
50 1.5 veego #include <unistd.h>
51 1.1 chopps
52 1.1 chopps #include <amiga/dev/grfioctl.h>
53 1.1 chopps
54 1.16 christos static void print_modeline(FILE *fp, struct grfvideo_mode *, int);
55 1.16 christos static void suggest(struct grfvideo_mode *, const char *, const char *);
56 1.5 veego
57 1.5 veego static struct grf_flag {
58 1.5 veego u_short grf_flag_number;
59 1.14 mlelstv const char *grf_flag_name;
60 1.5 veego } grf_flags[] = {
61 1.5 veego {GRF_FLAGS_DBLSCAN, "doublescan"},
62 1.5 veego {GRF_FLAGS_LACE, "interlace"},
63 1.5 veego {GRF_FLAGS_PHSYNC, "+hsync"},
64 1.5 veego {GRF_FLAGS_NHSYNC, "-hsync"},
65 1.5 veego {GRF_FLAGS_PVSYNC, "+vsync"},
66 1.5 veego {GRF_FLAGS_NVSYNC, "-vsync"},
67 1.5 veego {GRF_FLAGS_SYNC_ON_GREEN, "sync-on-green"},
68 1.5 veego {0, 0}
69 1.5 veego };
70 1.5 veego
71 1.1 chopps /*
72 1.1 chopps * Dynamic mode loader for NetBSD/Amiga grf devices.
73 1.1 chopps */
74 1.1 chopps int
75 1.16 christos main(int ac, char **av)
76 1.1 chopps {
77 1.5 veego struct grfvideo_mode gv[1];
78 1.5 veego struct grf_flag *grf_flagp;
79 1.5 veego FILE *fp;
80 1.5 veego int c, y, grffd;
81 1.16 christos size_t i;
82 1.16 christos int lineno = 0;
83 1.5 veego int uplim, lowlim;
84 1.5 veego char rawdata = 0, testmode = 0;
85 1.16 christos char *grfdevice = 0, *ptr;
86 1.5 veego char *modefile = 0;
87 1.9 veego char buf[_POSIX2_LINE_MAX];
88 1.5 veego char *cps[31];
89 1.5 veego char *p;
90 1.14 mlelstv const char *errortext;
91 1.5 veego
92 1.1 chopps
93 1.5 veego while ((c = getopt(ac, av, "rt")) != -1) {
94 1.1 chopps switch (c) {
95 1.1 chopps case 'r': /* raw output */
96 1.1 chopps rawdata = 1;
97 1.1 chopps break;
98 1.5 veego case 't': /* test the modefile without setting it */
99 1.5 veego testmode = 1;
100 1.5 veego break;
101 1.1 chopps default:
102 1.2 chopps printf("grfconfig [-r] device [file]\n");
103 1.1 chopps return (1);
104 1.1 chopps }
105 1.1 chopps }
106 1.1 chopps ac -= optind;
107 1.1 chopps av += optind;
108 1.1 chopps
109 1.1 chopps
110 1.16 christos if (ac < 1)
111 1.16 christos errx(EXIT_FAILURE, "No grf device specified");
112 1.16 christos grfdevice = av[0];
113 1.1 chopps
114 1.1 chopps if (ac >= 2)
115 1.1 chopps modefile = av[1];
116 1.1 chopps
117 1.16 christos if ((grffd = open(grfdevice, O_RDWR)) == -1)
118 1.16 christos err(EXIT_FAILURE, "Can't open grf device `%s'", grfdevice);
119 1.16 christos
120 1.1 chopps /* If a mode file is specificied, load it in, don't display any info. */
121 1.1 chopps
122 1.1 chopps if (modefile) {
123 1.16 christos if (!(fp = fopen(modefile, "r")))
124 1.16 christos err(EXIT_FAILURE,
125 1.16 christos "Cannot open mode definition file `%s'", modefile);
126 1.16 christos
127 1.5 veego while (fgets(buf, sizeof(buf), fp)) {
128 1.9 veego char *obuf, tbuf[_POSIX2_LINE_MAX], *tbuf2;
129 1.5 veego /*
130 1.5 veego * check for end-of-section, comments, strip off trailing
131 1.5 veego * spaces and newline character.
132 1.5 veego */
133 1.11 he for (p = buf; isspace((unsigned char)*p); ++p)
134 1.1 chopps continue;
135 1.5 veego if (*p == '\0' || *p == '#')
136 1.5 veego continue;
137 1.11 he for (p = strchr(buf, '\0'); isspace((unsigned char)*--p);)
138 1.5 veego continue;
139 1.5 veego *++p = '\0';
140 1.5 veego
141 1.9 veego obuf = buf;
142 1.9 veego tbuf2 = tbuf;
143 1.9 veego while ((*tbuf2 = *obuf) != '\0') {
144 1.9 veego if (*tbuf2 == '#') {
145 1.9 veego *tbuf2 = '\0';
146 1.9 veego break;
147 1.9 veego }
148 1.11 he if (isupper((unsigned char)*tbuf2)) {
149 1.11 he *tbuf2 = tolower((unsigned char)*tbuf2);
150 1.9 veego }
151 1.9 veego obuf++;
152 1.9 veego tbuf2++;
153 1.9 veego }
154 1.9 veego obuf = tbuf;
155 1.9 veego
156 1.5 veego lineno = lineno + 1;
157 1.5 veego
158 1.16 christos #define SP " \b\t\r\n"
159 1.16 christos memset(cps, 0, sizeof(cps));
160 1.16 christos for (i = 0, ptr = strtok(buf, SP);
161 1.16 christos ptr != NULL && i < __arraycount(cps);
162 1.16 christos i++, ptr = strtok(NULL, SP))
163 1.16 christos cps[i] = ptr;
164 1.16 christos
165 1.16 christos
166 1.16 christos if (i < 14)
167 1.16 christos errx(EXIT_FAILURE, "Too few values in mode "
168 1.16 christos "definition file: `%s'\n", obuf);
169 1.5 veego
170 1.5 veego gv->pixel_clock = atoi(cps[1]);
171 1.5 veego gv->disp_width = atoi(cps[2]);
172 1.5 veego gv->disp_height = atoi(cps[3]);
173 1.5 veego gv->depth = atoi(cps[4]);
174 1.5 veego gv->hblank_start = atoi(cps[5]);
175 1.5 veego gv->hsync_start = atoi(cps[6]);
176 1.5 veego gv->hsync_stop = atoi(cps[7]);
177 1.5 veego gv->htotal = atoi(cps[8]);
178 1.5 veego gv->vblank_start = atoi(cps[9]);
179 1.5 veego gv->vsync_start = atoi(cps[10]);
180 1.5 veego gv->vsync_stop = atoi(cps[11]);
181 1.5 veego gv->vtotal = atoi(cps[12]);
182 1.1 chopps
183 1.5 veego if ((y = atoi(cps[0])))
184 1.5 veego gv->mode_num = y;
185 1.5 veego else
186 1.5 veego if (strncasecmp("c", cps[0], 1) == 0) {
187 1.5 veego gv->mode_num = 255;
188 1.5 veego gv->depth = 4;
189 1.5 veego } else {
190 1.16 christos errx(EXIT_FAILURE,
191 1.16 christos "Illegal mode number: %s", cps[0]);
192 1.5 veego }
193 1.5 veego
194 1.5 veego if ((gv->pixel_clock == 0) ||
195 1.5 veego (gv->disp_width == 0) ||
196 1.5 veego (gv->disp_height == 0) ||
197 1.5 veego (gv->depth == 0) ||
198 1.5 veego (gv->hblank_start == 0) ||
199 1.5 veego (gv->hsync_start == 0) ||
200 1.5 veego (gv->hsync_stop == 0) ||
201 1.5 veego (gv->htotal == 0) ||
202 1.5 veego (gv->vblank_start == 0) ||
203 1.5 veego (gv->vsync_start == 0) ||
204 1.5 veego (gv->vsync_stop == 0) ||
205 1.5 veego (gv->vtotal == 0)) {
206 1.16 christos errx(EXIT_FAILURE, "Illegal value in "
207 1.16 christos "mode #%d: `%s'", gv->mode_num, obuf);
208 1.5 veego }
209 1.5 veego
210 1.5 veego if (strstr(obuf, "default") != NULL) {
211 1.5 veego gv->disp_flags = GRF_FLAGS_DEFAULT;
212 1.5 veego } else {
213 1.5 veego gv->disp_flags = GRF_FLAGS_DEFAULT;
214 1.5 veego for (grf_flagp = grf_flags;
215 1.5 veego grf_flagp->grf_flag_number; grf_flagp++) {
216 1.5 veego if (strstr(obuf, grf_flagp->grf_flag_name) != NULL) {
217 1.5 veego gv->disp_flags |= grf_flagp->grf_flag_number;
218 1.5 veego }
219 1.5 veego }
220 1.16 christos if (gv->disp_flags == GRF_FLAGS_DEFAULT)
221 1.16 christos errx(EXIT_FAILURE, "Your are using a "
222 1.5 veego "mode file with an obsolete "
223 1.16 christos "format");
224 1.5 veego }
225 1.1 chopps
226 1.5 veego /*
227 1.5 veego * Check for impossible gv->disp_flags:
228 1.5 veego * doublescan and interlace,
229 1.5 veego * +hsync and -hsync
230 1.5 veego * +vsync and -vsync.
231 1.5 veego */
232 1.5 veego errortext = NULL;
233 1.5 veego if ((gv->disp_flags & GRF_FLAGS_DBLSCAN) &&
234 1.5 veego (gv->disp_flags & GRF_FLAGS_LACE))
235 1.5 veego errortext = "Interlace and Doublescan";
236 1.5 veego if ((gv->disp_flags & GRF_FLAGS_PHSYNC) &&
237 1.5 veego (gv->disp_flags & GRF_FLAGS_NHSYNC))
238 1.5 veego errortext = "+hsync and -hsync";
239 1.5 veego if ((gv->disp_flags & GRF_FLAGS_PVSYNC) &&
240 1.5 veego (gv->disp_flags & GRF_FLAGS_NVSYNC))
241 1.5 veego errortext = "+vsync and -vsync";
242 1.5 veego
243 1.16 christos if (errortext != NULL)
244 1.16 christos errx(EXIT_FAILURE, "Illegal flags in "
245 1.16 christos "mode #%d: `%s' are both defined",
246 1.5 veego gv->mode_num, errortext);
247 1.5 veego
248 1.5 veego /* Check for old horizontal cycle values */
249 1.5 veego if ((gv->htotal < (gv->disp_width / 4))) {
250 1.5 veego gv->hblank_start *= 8;
251 1.5 veego gv->hsync_start *= 8;
252 1.5 veego gv->hsync_stop *= 8;
253 1.5 veego gv->htotal *= 8;
254 1.16 christos suggest(gv, "horizontal videoclock cycle "
255 1.16 christos "values", obuf);
256 1.16 christos return EXIT_FAILURE;
257 1.5 veego }
258 1.5 veego
259 1.5 veego /* Check for old interlace or doublescan modes */
260 1.5 veego uplim = gv->disp_height + (gv->disp_height / 4);
261 1.5 veego lowlim = gv->disp_height - (gv->disp_height / 4);
262 1.5 veego if (((gv->vtotal * 2) > lowlim) &&
263 1.5 veego ((gv->vtotal * 2) < uplim)) {
264 1.5 veego gv->vblank_start *= 2;
265 1.5 veego gv->vsync_start *= 2;
266 1.5 veego gv->vsync_stop *= 2;
267 1.5 veego gv->vtotal *= 2;
268 1.6 veego gv->disp_flags &= ~GRF_FLAGS_DBLSCAN;
269 1.6 veego gv->disp_flags |= GRF_FLAGS_LACE;
270 1.16 christos suggest(gv, "vertical values for interlace "
271 1.16 christos "modes", obuf);
272 1.16 christos return EXIT_FAILURE;
273 1.6 veego } else if (((gv->vtotal / 2) > lowlim) &&
274 1.5 veego ((gv->vtotal / 2) < uplim)) {
275 1.5 veego gv->vblank_start /= 2;
276 1.5 veego gv->vsync_start /= 2;
277 1.5 veego gv->vsync_stop /= 2;
278 1.5 veego gv->vtotal /= 2;
279 1.6 veego gv->disp_flags &= ~GRF_FLAGS_LACE;
280 1.6 veego gv->disp_flags |= GRF_FLAGS_DBLSCAN;
281 1.16 christos suggest(gv, "vertical values for doublescan "
282 1.16 christos "modes", obuf);
283 1.16 christos return EXIT_FAILURE;
284 1.5 veego }
285 1.5 veego
286 1.5 veego if (testmode == 1) {
287 1.5 veego if (lineno == 1)
288 1.5 veego printf("num clk wid hi dep hbs "
289 1.5 veego "hss hse ht vbs vss vse vt "
290 1.5 veego "flags\n");
291 1.16 christos print_modeline(stdout, gv, 1);
292 1.5 veego } else {
293 1.1 chopps gv->mode_descr[0] = 0;
294 1.1 chopps if (ioctl(grffd, GRFIOCSETMON, (char *) gv) < 0)
295 1.16 christos err(EXIT_FAILURE, "bad monitor "
296 1.16 christos "definition for mode #%d",
297 1.4 veego gv->mode_num);
298 1.1 chopps }
299 1.1 chopps }
300 1.1 chopps fclose(fp);
301 1.1 chopps } else {
302 1.1 chopps ioctl(grffd, GRFGETNUMVM, &y);
303 1.1 chopps y += 2;
304 1.1 chopps for (c = 1; c < y; c++) {
305 1.1 chopps c = gv->mode_num = (c != (y - 1)) ? c : 255;
306 1.1 chopps if (ioctl(grffd, GRFGETVMODE, gv) < 0)
307 1.1 chopps continue;
308 1.1 chopps if (rawdata) {
309 1.16 christos print_modeline(stdout, gv, 0);
310 1.1 chopps continue;
311 1.1 chopps }
312 1.1 chopps if (c == 255)
313 1.1 chopps printf("Console: ");
314 1.1 chopps else
315 1.1 chopps printf("%2d: ", gv->mode_num);
316 1.1 chopps
317 1.1 chopps printf("%dx%d",
318 1.1 chopps gv->disp_width,
319 1.1 chopps gv->disp_height);
320 1.1 chopps
321 1.1 chopps if (c != 255)
322 1.1 chopps printf("x%d", gv->depth);
323 1.1 chopps else
324 1.1 chopps printf(" (%dx%d)",
325 1.1 chopps gv->disp_width / 8,
326 1.1 chopps gv->disp_height / gv->depth);
327 1.1 chopps
328 1.5 veego printf("\t%ld.%ldkHz @ %ldHz",
329 1.5 veego gv->pixel_clock / (gv->htotal * 1000),
330 1.5 veego (gv->pixel_clock / (gv->htotal * 100))
331 1.1 chopps % 10,
332 1.5 veego gv->pixel_clock / (gv->htotal * gv->vtotal));
333 1.5 veego printf(" flags:");
334 1.5 veego
335 1.5 veego if (gv->disp_flags == GRF_FLAGS_DEFAULT) {
336 1.16 christos printf(" default\n");
337 1.16 christos continue;
338 1.16 christos }
339 1.16 christos
340 1.16 christos for (grf_flagp = grf_flags;
341 1.16 christos grf_flagp->grf_flag_number; grf_flagp++)
342 1.16 christos if (gv->disp_flags & grf_flagp->grf_flag_number)
343 1.5 veego printf(" %s", grf_flagp->grf_flag_name);
344 1.5 veego printf("\n");
345 1.1 chopps }
346 1.1 chopps }
347 1.1 chopps
348 1.1 chopps close(grffd);
349 1.16 christos return EXIT_SUCCESS;
350 1.16 christos }
351 1.16 christos
352 1.16 christos static void
353 1.16 christos suggest(struct grfvideo_mode *gv, const char *d, const char *s)
354 1.16 christos {
355 1.16 christos warnx("Old and no longer supported %s: %s", d, s);
356 1.16 christos warnx("Wrong mode line, this could be a possible good model line:");
357 1.16 christos fprintf(stderr, "%s: ", getprogname());
358 1.16 christos print_modeline(stderr, gv, 0);
359 1.5 veego }
360 1.5 veego
361 1.5 veego static void
362 1.16 christos print_modeline(FILE *fp, struct grfvideo_mode *gv, int rawflags)
363 1.5 veego {
364 1.5 veego struct grf_flag *grf_flagp;
365 1.5 veego
366 1.16 christos if (gv->mode_num == 255)
367 1.16 christos fprintf(fp, "c ");
368 1.16 christos else
369 1.16 christos fprintf(fp, "%d ", gv->mode_num);
370 1.16 christos
371 1.16 christos fprintf(fp, "%ld %d %d %d %d %d %d %d %d %d %d %d",
372 1.5 veego gv->pixel_clock,
373 1.5 veego gv->disp_width,
374 1.5 veego gv->disp_height,
375 1.5 veego gv->depth,
376 1.5 veego gv->hblank_start,
377 1.5 veego gv->hsync_start,
378 1.5 veego gv->hsync_stop,
379 1.5 veego gv->htotal,
380 1.5 veego gv->vblank_start,
381 1.5 veego gv->vsync_start,
382 1.5 veego gv->vsync_stop,
383 1.5 veego gv->vtotal);
384 1.16 christos
385 1.16 christos if (rawflags) {
386 1.16 christos fprintf(fp, " 0x%.2x\n", gv->disp_flags);
387 1.16 christos return;
388 1.16 christos }
389 1.16 christos if (gv->disp_flags == GRF_FLAGS_DEFAULT) {
390 1.16 christos fprintf(fp, " default\n");
391 1.16 christos return;
392 1.16 christos }
393 1.16 christos
394 1.16 christos for (grf_flagp = grf_flags; grf_flagp->grf_flag_number; grf_flagp++)
395 1.16 christos if (gv->disp_flags & grf_flagp->grf_flag_number)
396 1.16 christos fprintf(fp, " %s", grf_flagp->grf_flag_name);
397 1.16 christos fprintf(fp, "\n");
398 1.1 chopps }
399