blkid: add type display for btrfs
[platform/upstream/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 source tree.
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 //usage:#define fbset_trivial_usage
16 //usage:       "[OPTIONS] [MODE]"
17 //usage:#define fbset_full_usage "\n\n"
18 //usage:       "Show and modify frame buffer settings"
19 //usage:
20 //usage:#define fbset_example_usage
21 //usage:       "$ fbset\n"
22 //usage:       "mode \"1024x768-76\"\n"
23 //usage:       "        # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n"
24 //usage:       "        geometry 1024 768 1024 768 16\n"
25 //usage:       "        timings 12714 128 32 16 4 128 4\n"
26 //usage:       "        accel false\n"
27 //usage:       "        rgba 5/11,6/5,5/0,0/0\n"
28 //usage:       "endmode\n"
29
30 #include "libbb.h"
31
32 #define DEFAULTFBDEV  FB_0
33 #define DEFAULTFBMODE "/etc/fb.modes"
34
35 /* Stuff stolen from the kernel's fb.h */
36 #define FB_ACTIVATE_ALL 64
37 enum {
38         FBIOGET_VSCREENINFO = 0x4600,
39         FBIOPUT_VSCREENINFO = 0x4601
40 };
41
42 struct fb_bitfield {
43         uint32_t offset;                /* beginning of bitfield */
44         uint32_t length;                /* length of bitfield */
45         uint32_t msb_right;             /* !=0: Most significant bit is right */
46 };
47 struct fb_var_screeninfo {
48         uint32_t xres;                  /* visible resolution */
49         uint32_t yres;
50         uint32_t xres_virtual;          /* virtual resolution */
51         uint32_t yres_virtual;
52         uint32_t xoffset;               /* offset from virtual to visible */
53         uint32_t yoffset;               /* resolution */
54
55         uint32_t bits_per_pixel;
56         uint32_t grayscale;             /* !=0 Graylevels instead of colors */
57
58         struct fb_bitfield red;         /* bitfield in fb mem if true color, */
59         struct fb_bitfield green;       /* else only length is significant */
60         struct fb_bitfield blue;
61         struct fb_bitfield transp;      /* transparency */
62
63         uint32_t nonstd;                /* !=0 Non standard pixel format */
64
65         uint32_t activate;              /* see FB_ACTIVATE_x */
66
67         uint32_t height;                /* height of picture in mm */
68         uint32_t width;                 /* width of picture in mm */
69
70         uint32_t accel_flags;           /* acceleration flags (hints) */
71
72         /* Timing: All values in pixclocks, except pixclock (of course) */
73         uint32_t pixclock;              /* pixel clock in ps (pico seconds) */
74         uint32_t left_margin;           /* time from sync to picture */
75         uint32_t right_margin;          /* time from picture to sync */
76         uint32_t upper_margin;          /* time from sync to picture */
77         uint32_t lower_margin;
78         uint32_t hsync_len;             /* length of horizontal sync */
79         uint32_t vsync_len;             /* length of vertical sync */
80         uint32_t sync;                  /* see FB_SYNC_x */
81         uint32_t vmode;                 /* see FB_VMODE_x */
82         uint32_t reserved[6];           /* Reserved for future compatibility */
83 };
84
85 static void copy_if_gt0(uint32_t *src, uint32_t *dst, unsigned cnt)
86 {
87         do {
88                 if ((int32_t) *src > 0)
89                         *dst = *src;
90                 src++;
91                 dst++;
92         } while (--cnt);
93 }
94
95 static NOINLINE void copy_changed_values(
96                 struct fb_var_screeninfo *base,
97                 struct fb_var_screeninfo *set)
98 {
99         //if ((int32_t) set->xres > 0) base->xres = set->xres;
100         //if ((int32_t) set->yres > 0) base->yres = set->yres;
101         //if ((int32_t) set->xres_virtual > 0)   base->xres_virtual = set->xres_virtual;
102         //if ((int32_t) set->yres_virtual > 0)   base->yres_virtual = set->yres_virtual;
103         copy_if_gt0(&set->xres, &base->xres, 4);
104
105         if ((int32_t) set->bits_per_pixel > 0) base->bits_per_pixel = set->bits_per_pixel;
106         //copy_if_gt0(&set->bits_per_pixel, &base->bits_per_pixel, 1);
107
108         //if ((int32_t) set->pixclock > 0)       base->pixclock = set->pixclock;
109         //if ((int32_t) set->left_margin > 0)    base->left_margin = set->left_margin;
110         //if ((int32_t) set->right_margin > 0)   base->right_margin = set->right_margin;
111         //if ((int32_t) set->upper_margin > 0)   base->upper_margin = set->upper_margin;
112         //if ((int32_t) set->lower_margin > 0)   base->lower_margin = set->lower_margin;
113         //if ((int32_t) set->hsync_len > 0) base->hsync_len = set->hsync_len;
114         //if ((int32_t) set->vsync_len > 0) base->vsync_len = set->vsync_len;
115         //if ((int32_t) set->sync > 0)  base->sync = set->sync;
116         //if ((int32_t) set->vmode > 0) base->vmode = set->vmode;
117         copy_if_gt0(&set->pixclock, &base->pixclock, 9);
118 }
119
120
121 enum {
122         CMD_FB = 1,
123         CMD_DB = 2,
124         CMD_GEOMETRY = 3,
125         CMD_TIMING = 4,
126         CMD_ACCEL = 5,
127         CMD_HSYNC = 6,
128         CMD_VSYNC = 7,
129         CMD_LACED = 8,
130         CMD_DOUBLE = 9,
131 /*      CMD_XCOMPAT =     10, */
132         CMD_ALL = 11,
133         CMD_INFO = 12,
134         CMD_SHOW = 13,
135         CMD_CHANGE = 14,
136
137 #if ENABLE_FEATURE_FBSET_FANCY
138         CMD_XRES = 100,
139         CMD_YRES = 101,
140         CMD_VXRES = 102,
141         CMD_VYRES = 103,
142         CMD_DEPTH = 104,
143         CMD_MATCH = 105,
144         CMD_PIXCLOCK = 106,
145         CMD_LEFT = 107,
146         CMD_RIGHT = 108,
147         CMD_UPPER = 109,
148         CMD_LOWER = 110,
149         CMD_HSLEN = 111,
150         CMD_VSLEN = 112,
151         CMD_CSYNC = 113,
152         CMD_GSYNC = 114,
153         CMD_EXTSYNC = 115,
154         CMD_BCAST = 116,
155         CMD_RGBA = 117,
156         CMD_STEP = 118,
157         CMD_MOVE = 119,
158 #endif
159 };
160
161 static const struct cmdoptions_t {
162         const char name[9];
163         const unsigned char param_count;
164         const unsigned char code;
165 } g_cmdoptions[] = {
166         /*"12345678" + NUL */
167         { "fb"      , 1, CMD_FB       },
168         { "db"      , 1, CMD_DB       },
169         { "a"       , 0, CMD_ALL      },
170         { "i"       , 0, CMD_INFO     },
171         { "g"       , 5, CMD_GEOMETRY },
172         { "t"       , 7, CMD_TIMING   },
173         { "accel"   , 1, CMD_ACCEL    },
174         { "hsync"   , 1, CMD_HSYNC    },
175         { "vsync"   , 1, CMD_VSYNC    },
176         { "laced"   , 1, CMD_LACED    },
177         { "double"  , 1, CMD_DOUBLE   },
178         { "show"    , 0, CMD_SHOW     },
179         { "s"       , 0, CMD_SHOW     },
180 #if ENABLE_FEATURE_FBSET_FANCY
181         { "all"     , 0, CMD_ALL      },
182         { "xres"    , 1, CMD_XRES     },
183         { "yres"    , 1, CMD_YRES     },
184         { "vxres"   , 1, CMD_VXRES    },
185         { "vyres"   , 1, CMD_VYRES    },
186         { "depth"   , 1, CMD_DEPTH    },
187         { "match"   , 0, CMD_MATCH    },
188         { "geometry", 5, CMD_GEOMETRY },
189         { "pixclock", 1, CMD_PIXCLOCK },
190         { "left"    , 1, CMD_LEFT     },
191         { "right"   , 1, CMD_RIGHT    },
192         { "upper"   , 1, CMD_UPPER    },
193         { "lower"   , 1, CMD_LOWER    },
194         { "hslen"   , 1, CMD_HSLEN    },
195         { "vslen"   , 1, CMD_VSLEN    },
196         { "timings" , 7, CMD_TIMING   },
197         { "csync"   , 1, CMD_CSYNC    },
198         { "gsync"   , 1, CMD_GSYNC    },
199         { "extsync" , 1, CMD_EXTSYNC  },
200         { "bcast"   , 1, CMD_BCAST    },
201         { "rgba"    , 1, CMD_RGBA     },
202         { "step"    , 1, CMD_STEP     },
203         { "move"    , 1, CMD_MOVE     },
204 #endif
205 };
206
207 /* taken from linux/fb.h */
208 enum {
209         FB_SYNC_HOR_HIGH_ACT = 1,       /* horizontal sync high active */
210         FB_SYNC_VERT_HIGH_ACT = 2,      /* vertical sync high active */
211 #if ENABLE_FEATURE_FBSET_READMODE
212         FB_VMODE_INTERLACED = 1,        /* interlaced */
213         FB_VMODE_DOUBLE = 2,            /* double scan */
214         FB_SYNC_EXT = 4,                /* external sync */
215         FB_SYNC_COMP_HIGH_ACT = 8,      /* composite sync high active */
216 #endif
217 };
218
219 #if ENABLE_FEATURE_FBSET_READMODE
220 static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what)
221 {
222         if (strcmp(buf, what) == 0)
223                 *x &= ~flag;
224         else
225                 *x |= flag;
226 }
227
228 /* Mode db file contains mode definitions like this:
229  * mode "800x600-48-lace"
230  *     # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz
231  *     geometry 800 600 800 600 8
232  *     timings 27778 56 80 79 11 128 12
233  *     laced true
234  *     hsync high
235  *     vsync high
236  * endmode
237  */
238 static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
239                                         const char *mode)
240 {
241         char *token[2], *p, *s;
242         parser_t *parser = config_open(fn);
243
244         while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) {
245                 if (strcmp(token[0], "mode") != 0 || !token[1])
246                         continue;
247                 p = strstr(token[1], mode);
248                 if (!p)
249                         continue;
250                 s = p + strlen(mode);
251                 //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
252                 /* exact match? */
253                 if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */
254                  || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */
255                 ) {
256                         //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
257                         break;
258                 }
259         }
260
261         if (!token[0])
262                 return 0;
263
264         while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) {
265                 int i;
266
267 //bb_info_msg("???[%s][%s]", token[0], token[1]);
268                 if (strcmp(token[0], "endmode") == 0) {
269 //bb_info_msg("OK[%s]", mode);
270                         return 1;
271                 }
272                 p = token[1];
273                 i = index_in_strings(
274                         "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\0",
275                         token[0]);
276                 switch (i) {
277                 case 0:
278                         if (sizeof(int) == sizeof(base->xres)) {
279                                 sscanf(p, "%d %d %d %d %d",
280                                         &base->xres, &base->yres,
281                                         &base->xres_virtual, &base->yres_virtual,
282                                         &base->bits_per_pixel);
283                         } else {
284                                 int base_xres, base_yres;
285                                 int base_xres_virtual, base_yres_virtual;
286                                 int base_bits_per_pixel;
287                                 sscanf(p, "%d %d %d %d %d",
288                                         &base_xres, &base_yres,
289                                         &base_xres_virtual, &base_yres_virtual,
290                                         &base_bits_per_pixel);
291                                 base->xres = base_xres;
292                                 base->yres = base_yres;
293                                 base->xres_virtual = base_xres_virtual;
294                                 base->yres_virtual = base_yres_virtual;
295                                 base->bits_per_pixel = base_bits_per_pixel;
296                         }
297 //bb_info_msg("GEO[%s]", p);
298                         break;
299                 case 1:
300                         if (sizeof(int) == sizeof(base->xres)) {
301                                 sscanf(p, "%d %d %d %d %d %d %d",
302                                         &base->pixclock,
303                                         &base->left_margin, &base->right_margin,
304                                         &base->upper_margin, &base->lower_margin,
305                                         &base->hsync_len, &base->vsync_len);
306                         } else {
307                                 int base_pixclock;
308                                 int base_left_margin, base_right_margin;
309                                 int base_upper_margin, base_lower_margin;
310                                 int base_hsync_len, base_vsync_len;
311                                 sscanf(p, "%d %d %d %d %d %d %d",
312                                         &base_pixclock,
313                                         &base_left_margin, &base_right_margin,
314                                         &base_upper_margin, &base_lower_margin,
315                                         &base_hsync_len, &base_vsync_len);
316                                 base->pixclock = base_pixclock;
317                                 base->left_margin = base_left_margin;
318                                 base->right_margin = base_right_margin;
319                                 base->upper_margin = base_upper_margin;
320                                 base->lower_margin = base_lower_margin;
321                                 base->hsync_len = base_hsync_len;
322                                 base->vsync_len = base_vsync_len;
323                         }
324 //bb_info_msg("TIM[%s]", p);
325                         break;
326                 case 2:
327                 case 3: {
328                         static const uint32_t syncs[] = {FB_VMODE_INTERLACED, FB_VMODE_DOUBLE};
329                         ss(&base->vmode, syncs[i-2], p, "false");
330 //bb_info_msg("VMODE[%s]", p);
331                         break;
332                 }
333                 case 4:
334                 case 5:
335                 case 6: {
336                         static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT};
337                         ss(&base->sync, syncs[i-4], p, "low");
338 //bb_info_msg("SYNC[%s]", p);
339                         break;
340                 }
341                 case 7:
342                         ss(&base->sync, FB_SYNC_EXT, p, "false");
343 //bb_info_msg("EXTSYNC[%s]", p);
344                         break;
345                 case 8: {
346                         int red_offset, red_length;
347                         int green_offset, green_length;
348                         int blue_offset, blue_length;
349                         int transp_offset, transp_length;
350
351                         sscanf(p, "%d/%d,%d/%d,%d/%d,%d/%d",
352                                 &red_offset, &red_length,
353                                 &green_offset, &green_length,
354                                 &blue_offset, &blue_length,
355                                 &transp_offset, &transp_length);
356                         base->red.offset = red_offset;
357                         base->red.length = red_length;
358                         base->red.msb_right = 0;
359                         base->green.offset = green_offset;
360                         base->green.length = green_length;
361                         base->green.msb_right = 0;
362                         base->blue.offset = blue_offset;
363                         base->blue.length = blue_length;
364                         base->blue.msb_right = 0;
365                         base->transp.offset = transp_offset;
366                         base->transp.length = transp_length;
367                         base->transp.msb_right = 0;
368                 }
369                 }
370         }
371         return 0;
372 }
373 #endif
374
375 static NOINLINE void showmode(struct fb_var_screeninfo *v)
376 {
377         double drate = 0, hrate = 0, vrate = 0;
378
379         if (v->pixclock) {
380                 drate = 1e12 / v->pixclock;
381                 hrate = drate / (v->left_margin + v->xres + v->right_margin + v->hsync_len);
382                 vrate = hrate / (v->upper_margin + v->yres + v->lower_margin + v->vsync_len);
383         }
384         printf("\nmode \"%ux%u-%u\"\n"
385 #if ENABLE_FEATURE_FBSET_FANCY
386         "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
387 #endif
388         "\tgeometry %u %u %u %u %u\n"
389         "\ttimings %u %u %u %u %u %u %u\n"
390         "\taccel %s\n"
391         "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
392         "endmode\n\n",
393                 v->xres, v->yres, (int) (vrate + 0.5),
394 #if ENABLE_FEATURE_FBSET_FANCY
395                 drate / 1e6, hrate / 1e3, vrate,
396 #endif
397                 v->xres, v->yres, v->xres_virtual, v->yres_virtual, v->bits_per_pixel,
398                 v->pixclock, v->left_margin, v->right_margin, v->upper_margin, v->lower_margin,
399                         v->hsync_len, v->vsync_len,
400                 (v->accel_flags > 0 ? "true" : "false"),
401                 v->red.length, v->red.offset, v->green.length, v->green.offset,
402                         v->blue.length, v->blue.offset, v->transp.length, v->transp.offset);
403 }
404
405 int fbset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
406 int fbset_main(int argc, char **argv)
407 {
408         enum {
409                 OPT_CHANGE   = (1 << 0),
410                 OPT_SHOW     = (1 << 1),
411                 OPT_READMODE = (1 << 2),
412                 OPT_ALL      = (1 << 3),
413         };
414         struct fb_var_screeninfo var_old, var_set;
415         int fh, i;
416         unsigned options = 0;
417
418         const char *fbdev = DEFAULTFBDEV;
419         const char *modefile = DEFAULTFBMODE;
420         char *thisarg;
421         char *mode = mode; /* for compiler */
422
423         memset(&var_set, 0xff, sizeof(var_set)); /* set all to -1 */
424
425         /* parse cmd args.... why do they have to make things so difficult? */
426         argv++;
427         argc--;
428         for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
429                 if (thisarg[0] != '-') {
430                         if (!ENABLE_FEATURE_FBSET_READMODE || argc != 1)
431                                 bb_show_usage();
432                         mode = thisarg;
433                         options |= OPT_READMODE;
434                         goto contin;
435                 }
436                 for (i = 0; i < ARRAY_SIZE(g_cmdoptions); i++) {
437                         if (strcmp(thisarg + 1, g_cmdoptions[i].name) != 0)
438                                 continue;
439                         if (argc <= g_cmdoptions[i].param_count)
440                                 bb_show_usage();
441
442                         switch (g_cmdoptions[i].code) {
443                         case CMD_FB:
444                                 fbdev = argv[1];
445                                 break;
446                         case CMD_DB:
447                                 modefile = argv[1];
448                                 break;
449                         case CMD_ALL:
450                                 options |= OPT_ALL;
451                                 break;
452                         case CMD_SHOW:
453                                 options |= OPT_SHOW;
454                                 break;
455                         case CMD_GEOMETRY:
456                                 var_set.xres = xatou32(argv[1]);
457                                 var_set.yres = xatou32(argv[2]);
458                                 var_set.xres_virtual = xatou32(argv[3]);
459                                 var_set.yres_virtual = xatou32(argv[4]);
460                                 var_set.bits_per_pixel = xatou32(argv[5]);
461                                 break;
462                         case CMD_TIMING:
463                                 var_set.pixclock = xatou32(argv[1]);
464                                 var_set.left_margin = xatou32(argv[2]);
465                                 var_set.right_margin = xatou32(argv[3]);
466                                 var_set.upper_margin = xatou32(argv[4]);
467                                 var_set.lower_margin = xatou32(argv[5]);
468                                 var_set.hsync_len = xatou32(argv[6]);
469                                 var_set.vsync_len = xatou32(argv[7]);
470                                 break;
471                         case CMD_ACCEL:
472                                 break;
473                         case CMD_HSYNC:
474                                 var_set.sync |= FB_SYNC_HOR_HIGH_ACT;
475                                 break;
476                         case CMD_VSYNC:
477                                 var_set.sync |= FB_SYNC_VERT_HIGH_ACT;
478                                 break;
479 #if ENABLE_FEATURE_FBSET_FANCY
480                         case CMD_XRES:
481                                 var_set.xres = xatou32(argv[1]);
482                                 break;
483                         case CMD_YRES:
484                                 var_set.yres = xatou32(argv[1]);
485                                 break;
486                         case CMD_DEPTH:
487                                 var_set.bits_per_pixel = xatou32(argv[1]);
488                                 break;
489 #endif
490                         }
491                         switch (g_cmdoptions[i].code) {
492                         case CMD_FB:
493                         case CMD_DB:
494                         case CMD_ALL:
495                         case CMD_SHOW:
496                                 break;
497                         default:
498                                 /* other commands imply changes */
499                                 options |= OPT_CHANGE;
500                         }
501                         argc -= g_cmdoptions[i].param_count;
502                         argv += g_cmdoptions[i].param_count;
503                         goto contin;
504                 }
505                 bb_show_usage();
506  contin: ;
507         }
508
509         fh = xopen(fbdev, O_RDONLY);
510         xioctl(fh, FBIOGET_VSCREENINFO, &var_old);
511
512         if (options & OPT_READMODE) {
513 #if ENABLE_FEATURE_FBSET_READMODE
514                 if (!read_mode_db(&var_old, modefile, mode)) {
515                         bb_error_msg_and_die("unknown video mode '%s'", mode);
516                 }
517                 options |= OPT_CHANGE;
518 #endif
519         }
520
521         if (options & OPT_CHANGE) {
522                 copy_changed_values(&var_old, &var_set);
523                 if (options & OPT_ALL)
524                         var_old.activate = FB_ACTIVATE_ALL;
525                 xioctl(fh, FBIOPUT_VSCREENINFO, &var_old);
526         }
527
528         if (options == 0 || (options & OPT_SHOW))
529                 showmode(&var_old);
530
531         if (ENABLE_FEATURE_CLEAN_UP)
532                 close(fh);
533
534         return EXIT_SUCCESS;
535 }