btrfs.c: check first two superblocks, for additional robustness
[oweals/busybox.git] / util-linux / fbset.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini fbset implementation for busybox
4  *
5  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  *
9  * This is a from-scratch implementation of fbset; but the de facto fbset
10  * implementation was a good reference. fbset (original) is released under
11  * the GPL, and is (c) 1995-1999 by:
12  *     Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
13  */
14
15 #include "libbb.h"
16
17 #define DEFAULTFBDEV  FB_0
18 #define DEFAULTFBMODE "/etc/fb.modes"
19
20 enum {
21         CMD_FB = 1,
22         CMD_DB = 2,
23         CMD_GEOMETRY = 3,
24         CMD_TIMING = 4,
25         CMD_ACCEL = 5,
26         CMD_HSYNC = 6,
27         CMD_VSYNC = 7,
28         CMD_LACED = 8,
29         CMD_DOUBLE = 9,
30 /*      CMD_XCOMPAT =     10, */
31         CMD_ALL = 11,
32         CMD_INFO = 12,
33         CMD_SHOW = 13,
34         CMD_CHANGE = 14,
35
36 #if ENABLE_FEATURE_FBSET_FANCY
37         CMD_XRES = 100,
38         CMD_YRES = 101,
39         CMD_VXRES = 102,
40         CMD_VYRES = 103,
41         CMD_DEPTH = 104,
42         CMD_MATCH = 105,
43         CMD_PIXCLOCK = 106,
44         CMD_LEFT = 107,
45         CMD_RIGHT = 108,
46         CMD_UPPER = 109,
47         CMD_LOWER = 110,
48         CMD_HSLEN = 111,
49         CMD_VSLEN = 112,
50         CMD_CSYNC = 113,
51         CMD_GSYNC = 114,
52         CMD_EXTSYNC = 115,
53         CMD_BCAST = 116,
54         CMD_RGBA = 117,
55         CMD_STEP = 118,
56         CMD_MOVE = 119,
57 #endif
58 };
59
60 /* Stuff stolen from the kernel's fb.h */
61 #define FB_ACTIVATE_ALL 64
62 enum {
63         FBIOGET_VSCREENINFO = 0x4600,
64         FBIOPUT_VSCREENINFO = 0x4601
65 };
66 struct fb_bitfield {
67         uint32_t offset;                /* beginning of bitfield */
68         uint32_t length;                /* length of bitfield */
69         uint32_t msb_right;             /* !=0: Most significant bit is right */
70 };
71 struct fb_var_screeninfo {
72         uint32_t xres;                  /* visible resolution */
73         uint32_t yres;
74         uint32_t xres_virtual;          /* virtual resolution */
75         uint32_t yres_virtual;
76         uint32_t xoffset;               /* offset from virtual to visible */
77         uint32_t yoffset;               /* resolution */
78
79         uint32_t bits_per_pixel;
80         uint32_t grayscale;             /* !=0 Graylevels instead of colors */
81
82         struct fb_bitfield red;         /* bitfield in fb mem if true color, */
83         struct fb_bitfield green;       /* else only length is significant */
84         struct fb_bitfield blue;
85         struct fb_bitfield transp;      /* transparency */
86
87         uint32_t nonstd;                /* !=0 Non standard pixel format */
88
89         uint32_t activate;              /* see FB_ACTIVATE_x */
90
91         uint32_t height;                /* height of picture in mm */
92         uint32_t width;                 /* width of picture in mm */
93
94         uint32_t accel_flags;           /* acceleration flags (hints) */
95
96         /* Timing: All values in pixclocks, except pixclock (of course) */
97         uint32_t pixclock;              /* pixel clock in ps (pico seconds) */
98         uint32_t left_margin;           /* time from sync to picture */
99         uint32_t right_margin;          /* time from picture to sync */
100         uint32_t upper_margin;          /* time from sync to picture */
101         uint32_t lower_margin;
102         uint32_t hsync_len;             /* length of horizontal sync */
103         uint32_t vsync_len;             /* length of vertical sync */
104         uint32_t sync;                  /* see FB_SYNC_x */
105         uint32_t vmode;                 /* see FB_VMODE_x */
106         uint32_t reserved[6];           /* Reserved for future compatibility */
107 };
108
109
110 static const struct cmdoptions_t {
111         const char name[9];
112         const unsigned char param_count;
113         const unsigned char code;
114 } g_cmdoptions[] = {
115         /*"12345678" + NUL */
116         { "fb"      , 1, CMD_FB       },
117         { "db"      , 1, CMD_DB       },
118         { "a"       , 0, CMD_ALL      },
119         { "i"       , 0, CMD_INFO     },
120         { "g"       , 5, CMD_GEOMETRY },
121         { "t"       , 7, CMD_TIMING   },
122         { "accel"   , 1, CMD_ACCEL    },
123         { "hsync"   , 1, CMD_HSYNC    },
124         { "vsync"   , 1, CMD_VSYNC    },
125         { "laced"   , 1, CMD_LACED    },
126         { "double"  , 1, CMD_DOUBLE   },
127         { "show"    , 0, CMD_SHOW     },
128         { "s"       , 0, CMD_SHOW     },
129 #if ENABLE_FEATURE_FBSET_FANCY
130         { "all"     , 0, CMD_ALL      },
131         { "xres"    , 1, CMD_XRES     },
132         { "yres"    , 1, CMD_YRES     },
133         { "vxres"   , 1, CMD_VXRES    },
134         { "vyres"   , 1, CMD_VYRES    },
135         { "depth"   , 1, CMD_DEPTH    },
136         { "match"   , 0, CMD_MATCH    },
137         { "geometry", 5, CMD_GEOMETRY },
138         { "pixclock", 1, CMD_PIXCLOCK },
139         { "left"    , 1, CMD_LEFT     },
140         { "right"   , 1, CMD_RIGHT    },
141         { "upper"   , 1, CMD_UPPER    },
142         { "lower"   , 1, CMD_LOWER    },
143         { "hslen"   , 1, CMD_HSLEN    },
144         { "vslen"   , 1, CMD_VSLEN    },
145         { "timings" , 7, CMD_TIMING   },
146         { "csync"   , 1, CMD_CSYNC    },
147         { "gsync"   , 1, CMD_GSYNC    },
148         { "extsync" , 1, CMD_EXTSYNC  },
149         { "bcast"   , 1, CMD_BCAST    },
150         { "rgba"    , 1, CMD_RGBA     },
151         { "step"    , 1, CMD_STEP     },
152         { "move"    , 1, CMD_MOVE     },
153 #endif
154 };
155
156 #if ENABLE_FEATURE_FBSET_READMODE
157 /* taken from linux/fb.h */
158 enum {
159         FB_VMODE_INTERLACED = 1,        /* interlaced */
160         FB_VMODE_DOUBLE = 2,            /* double scan */
161         FB_SYNC_HOR_HIGH_ACT = 1,       /* horizontal sync high active */
162         FB_SYNC_VERT_HIGH_ACT = 2,      /* vertical sync high active */
163         FB_SYNC_EXT = 4,                /* external sync */
164         FB_SYNC_COMP_HIGH_ACT = 8,      /* composite sync high active */
165 };
166 #endif
167
168 #if ENABLE_FEATURE_FBSET_READMODE
169 static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what)
170 {
171         if (strcmp(buf, what) == 0)
172                 *x &= ~flag;
173         else
174                 *x |= flag;
175 }
176
177 static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
178                                         const char *mode)
179 {
180         char *token[2], *p, *s;
181         parser_t *parser = config_open(fn);
182
183         while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) {
184                 if (strcmp(token[0], "mode") != 0 || !token[1])
185                         continue;
186                 p = strstr(token[1], mode);
187                 if (!p)
188                         continue;
189                 s = p + strlen(mode);
190                 //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
191                 /* exact match? */
192                 if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */
193                  || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */
194                 ) {
195                         //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
196                         break;
197                 }
198         }
199
200         if (!token[0])
201                 return 0;
202
203         while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) {
204                 int i;
205
206 //bb_info_msg("???[%s][%s]", token[0], token[1]);
207                 if (strcmp(token[0], "endmode") == 0) {
208 //bb_info_msg("OK[%s]", mode);
209                         return 1;
210                 }
211                 p = token[1];
212                 i = index_in_strings(
213                         "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0",
214                         token[0]);
215                 switch (i) {
216                 case 0:
217                         /* FIXME: catastrophic on arches with 64bit ints */
218                         sscanf(p, "%d %d %d %d %d",
219                                 &(base->xres), &(base->yres),
220                                 &(base->xres_virtual), &(base->yres_virtual),
221                                 &(base->bits_per_pixel));
222 //bb_info_msg("GEO[%s]", p);
223                         break;
224                 case 1:
225                         sscanf(p, "%d %d %d %d %d %d %d",
226                                 &(base->pixclock),
227                                 &(base->left_margin), &(base->right_margin),
228                                 &(base->upper_margin), &(base->lower_margin),
229                                 &(base->hsync_len), &(base->vsync_len));
230 //bb_info_msg("TIM[%s]", p);
231                         break;
232                 case 2:
233                 case 3: {
234                         static const uint32_t syncs[] = {FB_VMODE_INTERLACED, FB_VMODE_DOUBLE};
235                         ss(&base->vmode, syncs[i-2], p, "false");
236 //bb_info_msg("VMODE[%s]", p);
237                         break;
238                 }
239                 case 4:
240                 case 5:
241                 case 6: {
242                         static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT};
243                         ss(&base->sync, syncs[i-4], p, "low");
244 //bb_info_msg("SYNC[%s]", p);
245                         break;
246                 }
247                 case 7:
248                         ss(&base->sync, FB_SYNC_EXT, p, "false");
249 //bb_info_msg("EXTSYNC[%s]", p);
250                         break;
251                 }
252         }
253         return 0;
254 }
255 #endif
256
257 static void setfbmode(struct fb_var_screeninfo *base,
258                                         struct fb_var_screeninfo *set)
259 {
260         if ((int32_t) set->xres > 0)
261                 base->xres = set->xres;
262         if ((int32_t) set->yres > 0)
263                 base->yres = set->yres;
264         if ((int32_t) set->xres_virtual > 0)
265                 base->xres_virtual = set->xres_virtual;
266         if ((int32_t) set->yres_virtual > 0)
267                 base->yres_virtual = set->yres_virtual;
268         if ((int32_t) set->bits_per_pixel > 0)
269                 base->bits_per_pixel = set->bits_per_pixel;
270 }
271
272 static NOINLINE void showmode(struct fb_var_screeninfo *v)
273 {
274         double drate = 0, hrate = 0, vrate = 0;
275
276         if (v->pixclock) {
277                 drate = 1e12 / v->pixclock;
278                 hrate = drate / (v->left_margin + v->xres + v->right_margin + v->hsync_len);
279                 vrate = hrate / (v->upper_margin + v->yres + v->lower_margin + v->vsync_len);
280         }
281         printf("\nmode \"%ux%u-%u\"\n"
282 #if ENABLE_FEATURE_FBSET_FANCY
283         "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
284 #endif
285         "\tgeometry %u %u %u %u %u\n"
286         "\ttimings %u %u %u %u %u %u %u\n"
287         "\taccel %s\n"
288         "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
289         "endmode\n\n",
290                 v->xres, v->yres, (int) (vrate + 0.5),
291 #if ENABLE_FEATURE_FBSET_FANCY
292                 drate / 1e6, hrate / 1e3, vrate,
293 #endif
294                 v->xres, v->yres, v->xres_virtual, v->yres_virtual, v->bits_per_pixel,
295                 v->pixclock, v->left_margin, v->right_margin, v->upper_margin, v->lower_margin,
296                         v->hsync_len, v->vsync_len,
297                 (v->accel_flags > 0 ? "true" : "false"),
298                 v->red.length, v->red.offset, v->green.length, v->green.offset,
299                         v->blue.length, v->blue.offset, v->transp.length, v->transp.offset);
300 }
301
302 int fbset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
303 int fbset_main(int argc, char **argv)
304 {
305         enum {
306                 OPT_CHANGE   = (1 << 0),
307                 OPT_SHOW     = (1 << 1),
308                 OPT_READMODE = (1 << 2),
309                 OPT_ALL      = (1 << 9),
310         };
311         struct fb_var_screeninfo var, varset;
312         int fh, i;
313         unsigned options = 0;
314
315         const char *fbdev = DEFAULTFBDEV;
316         const char *modefile = DEFAULTFBMODE;
317         char *thisarg, *mode = NULL;
318
319         memset(&varset, 0xff, sizeof(varset));
320
321         /* parse cmd args.... why do they have to make things so difficult? */
322         argv++;
323         argc--;
324         for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
325                 if (thisarg[0] == '-') for (i = 0; i < ARRAY_SIZE(g_cmdoptions); i++) {
326                         if (strcmp(thisarg + 1, g_cmdoptions[i].name) != 0)
327                                 continue;
328                         if (argc <= g_cmdoptions[i].param_count)
329                                 bb_show_usage();
330
331                         switch (g_cmdoptions[i].code) {
332                         case CMD_FB:
333                                 fbdev = argv[1];
334                                 break;
335                         case CMD_DB:
336                                 modefile = argv[1];
337                                 break;
338                         case CMD_ALL:
339                                 options |= OPT_ALL;
340                                 break;
341                         case CMD_SHOW:
342                                 options |= OPT_SHOW;
343                                 break;
344                         case CMD_GEOMETRY:
345                                 varset.xres = xatou32(argv[1]);
346                                 varset.yres = xatou32(argv[2]);
347                                 varset.xres_virtual = xatou32(argv[3]);
348                                 varset.yres_virtual = xatou32(argv[4]);
349                                 varset.bits_per_pixel = xatou32(argv[5]);
350                                 break;
351                         case CMD_TIMING:
352                                 varset.pixclock = xatou32(argv[1]);
353                                 varset.left_margin = xatou32(argv[2]);
354                                 varset.right_margin = xatou32(argv[3]);
355                                 varset.upper_margin = xatou32(argv[4]);
356                                 varset.lower_margin = xatou32(argv[5]);
357                                 varset.hsync_len = xatou32(argv[6]);
358                                 varset.vsync_len = xatou32(argv[7]);
359                                 break;
360 #if ENABLE_FEATURE_FBSET_FANCY
361                         case CMD_XRES:
362                                 varset.xres = xatou32(argv[1]);
363                                 break;
364                         case CMD_YRES:
365                                 varset.yres = xatou32(argv[1]);
366                                 break;
367                         case CMD_DEPTH:
368                                 varset.bits_per_pixel = xatou32(argv[1]);
369                                 break;
370 #endif
371                         }
372                         switch (g_cmdoptions[i].code) {
373                         case CMD_FB:
374                         case CMD_DB:
375                         case CMD_ALL:
376                         case CMD_SHOW:
377                                 break;
378                         default:
379                                 options |= OPT_CHANGE; /* the other commands imply changes */
380                         }
381                         argc -= g_cmdoptions[i].param_count;
382                         argv += g_cmdoptions[i].param_count;
383                         goto contin;
384                 }
385                 if (argc != 1)
386                         bb_show_usage();
387                 mode = *argv;
388                 options |= OPT_READMODE;
389  contin: ;
390         }
391
392         fh = xopen(fbdev, O_RDONLY);
393         xioctl(fh, FBIOGET_VSCREENINFO, &var);
394         if (options & OPT_READMODE) {
395 #if !ENABLE_FEATURE_FBSET_READMODE
396                 bb_show_usage();
397 #else
398                 if (!read_mode_db(&var, modefile, mode)) {
399                         bb_error_msg_and_die("unknown video mode '%s'", mode);
400                 }
401 #endif
402         }
403
404         if (options & OPT_CHANGE) {
405                 setfbmode(&var, &varset);
406                 if (options & OPT_ALL)
407                         var.activate = FB_ACTIVATE_ALL;
408                 xioctl(fh, FBIOPUT_VSCREENINFO, &var);
409         }
410         if (options == 0 || options & OPT_SHOW)
411                 showmode(&var);
412         /* Don't close the file, as exiting will take care of that */
413         /* close(fh); */
414
415         return EXIT_SUCCESS;
416 }