1 /* vi: set sw=4 ts=4: */
3 * Mini fbset implementation for busybox
5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
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)
15 //config: bool "fbset (5.9 kb)"
18 //config: fbset is used to show or change the settings of a Linux frame buffer
19 //config: device. The frame buffer device provides a simple and unique
20 //config: interface to access a graphics display. Enable this option
21 //config: if you wish to enable the 'fbset' utility.
23 //config:config FEATURE_FBSET_FANCY
24 //config: bool "Enable extra options"
26 //config: depends on FBSET
28 //config: This option enables extended fbset options, allowing one to set the
29 //config: framebuffer size, color depth, etc. interface to access a graphics
30 //config: display. Enable this option if you wish to enable extended fbset
33 //config:config FEATURE_FBSET_READMODE
34 //config: bool "Enable readmode support"
36 //config: depends on FBSET
38 //config: This option allows fbset to read the video mode database stored by
39 //config: default as /etc/fb.modes, which can be used to set frame buffer
40 //config: device to pre-defined video modes.
42 //applet:IF_FBSET(APPLET(fbset, BB_DIR_USR_SBIN, BB_SUID_DROP))
44 //kbuild:lib-$(CONFIG_FBSET) += fbset.o
46 //usage:#define fbset_trivial_usage
47 //usage: "[OPTIONS] [MODE]"
48 //usage:#define fbset_full_usage "\n\n"
49 //usage: "Show and modify frame buffer settings"
51 //usage:#define fbset_example_usage
53 //usage: "mode \"1024x768-76\"\n"
54 //usage: " # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n"
55 //usage: " geometry 1024 768 1024 768 16\n"
56 //usage: " timings 12714 128 32 16 4 128 4\n"
57 //usage: " accel false\n"
58 //usage: " rgba 5/11,6/5,5/0,0/0\n"
63 #define DEFAULTFBDEV FB_0
64 #define DEFAULTFBMODE "/etc/fb.modes"
66 /* Stuff stolen from the kernel's fb.h */
67 #define FB_ACTIVATE_ALL 64
69 FBIOGET_VSCREENINFO
= 0x4600,
70 FBIOPUT_VSCREENINFO
= 0x4601
74 uint32_t offset
; /* beginning of bitfield */
75 uint32_t length
; /* length of bitfield */
76 uint32_t msb_right
; /* !=0: Most significant bit is right */
78 struct fb_var_screeninfo
{
79 uint32_t xres
; /* visible resolution */
81 uint32_t xres_virtual
; /* virtual resolution */
82 uint32_t yres_virtual
;
83 uint32_t xoffset
; /* offset from virtual to visible */
84 uint32_t yoffset
; /* resolution */
86 uint32_t bits_per_pixel
;
87 uint32_t grayscale
; /* !=0 Graylevels instead of colors */
89 struct fb_bitfield red
; /* bitfield in fb mem if true color, */
90 struct fb_bitfield green
; /* else only length is significant */
91 struct fb_bitfield blue
;
92 struct fb_bitfield transp
; /* transparency */
94 uint32_t nonstd
; /* !=0 Non standard pixel format */
96 uint32_t activate
; /* see FB_ACTIVATE_x */
98 uint32_t height
; /* height of picture in mm */
99 uint32_t width
; /* width of picture in mm */
101 uint32_t accel_flags
; /* acceleration flags (hints) */
103 /* Timing: All values in pixclocks, except pixclock (of course) */
104 uint32_t pixclock
; /* pixel clock in ps (pico seconds) */
105 uint32_t left_margin
; /* time from sync to picture */
106 uint32_t right_margin
; /* time from picture to sync */
107 uint32_t upper_margin
; /* time from sync to picture */
108 uint32_t lower_margin
;
109 uint32_t hsync_len
; /* length of horizontal sync */
110 uint32_t vsync_len
; /* length of vertical sync */
111 uint32_t sync
; /* see FB_SYNC_x */
112 uint32_t vmode
; /* see FB_VMODE_x */
113 uint32_t reserved
[6]; /* Reserved for future compatibility */
116 static void copy_if_gt0(uint32_t *src
, uint32_t *dst
, unsigned cnt
)
119 if ((int32_t) *src
> 0)
126 static NOINLINE
void copy_changed_values(
127 struct fb_var_screeninfo
*base
,
128 struct fb_var_screeninfo
*set
)
130 //if ((int32_t) set->xres > 0) base->xres = set->xres;
131 //if ((int32_t) set->yres > 0) base->yres = set->yres;
132 //if ((int32_t) set->xres_virtual > 0) base->xres_virtual = set->xres_virtual;
133 //if ((int32_t) set->yres_virtual > 0) base->yres_virtual = set->yres_virtual;
134 copy_if_gt0(&set
->xres
, &base
->xres
, 4);
136 if ((int32_t) set
->bits_per_pixel
> 0) base
->bits_per_pixel
= set
->bits_per_pixel
;
137 //copy_if_gt0(&set->bits_per_pixel, &base->bits_per_pixel, 1);
139 //if ((int32_t) set->pixclock > 0) base->pixclock = set->pixclock;
140 //if ((int32_t) set->left_margin > 0) base->left_margin = set->left_margin;
141 //if ((int32_t) set->right_margin > 0) base->right_margin = set->right_margin;
142 //if ((int32_t) set->upper_margin > 0) base->upper_margin = set->upper_margin;
143 //if ((int32_t) set->lower_margin > 0) base->lower_margin = set->lower_margin;
144 //if ((int32_t) set->hsync_len > 0) base->hsync_len = set->hsync_len;
145 //if ((int32_t) set->vsync_len > 0) base->vsync_len = set->vsync_len;
146 //if ((int32_t) set->sync > 0) base->sync = set->sync;
147 //if ((int32_t) set->vmode > 0) base->vmode = set->vmode;
148 copy_if_gt0(&set
->pixclock
, &base
->pixclock
, 9);
162 /* CMD_XCOMPAT = 10, */
168 #if ENABLE_FEATURE_FBSET_FANCY
192 static const struct cmdoptions_t
{
194 const unsigned char param_count
;
195 const unsigned char code
;
196 } g_cmdoptions
[] ALIGN1
= {
197 /*"12345678" + NUL */
198 //TODO: convert to index_in_strings()
199 { "fb" , 1, CMD_FB
},
200 { "db" , 1, CMD_DB
},
201 { "a" , 0, CMD_ALL
},
202 { "i" , 0, CMD_INFO
},
203 { "g" , 5, CMD_GEOMETRY
},
204 { "t" , 7, CMD_TIMING
},
205 { "accel" , 1, CMD_ACCEL
},
206 { "hsync" , 1, CMD_HSYNC
},
207 { "vsync" , 1, CMD_VSYNC
},
208 { "laced" , 1, CMD_LACED
},
209 { "double" , 1, CMD_DOUBLE
},
210 { "show" , 0, CMD_SHOW
},
211 { "s" , 0, CMD_SHOW
},
212 #if ENABLE_FEATURE_FBSET_FANCY
213 { "all" , 0, CMD_ALL
},
214 { "xres" , 1, CMD_XRES
},
215 { "yres" , 1, CMD_YRES
},
216 { "vxres" , 1, CMD_VXRES
},
217 { "vyres" , 1, CMD_VYRES
},
218 { "depth" , 1, CMD_DEPTH
},
219 { "match" , 0, CMD_MATCH
},
220 { "geometry", 5, CMD_GEOMETRY
},
221 { "pixclock", 1, CMD_PIXCLOCK
},
222 { "left" , 1, CMD_LEFT
},
223 { "right" , 1, CMD_RIGHT
},
224 { "upper" , 1, CMD_UPPER
},
225 { "lower" , 1, CMD_LOWER
},
226 { "hslen" , 1, CMD_HSLEN
},
227 { "vslen" , 1, CMD_VSLEN
},
228 { "timings" , 7, CMD_TIMING
},
229 { "csync" , 1, CMD_CSYNC
},
230 { "gsync" , 1, CMD_GSYNC
},
231 { "extsync" , 1, CMD_EXTSYNC
},
232 { "bcast" , 1, CMD_BCAST
},
233 { "rgba" , 1, CMD_RGBA
},
234 { "step" , 1, CMD_STEP
},
235 { "move" , 1, CMD_MOVE
},
239 /* taken from linux/fb.h */
241 FB_SYNC_HOR_HIGH_ACT
= 1, /* horizontal sync high active */
242 FB_SYNC_VERT_HIGH_ACT
= 2, /* vertical sync high active */
243 #if ENABLE_FEATURE_FBSET_READMODE
244 FB_VMODE_INTERLACED
= 1, /* interlaced */
245 FB_VMODE_DOUBLE
= 2, /* double scan */
246 FB_SYNC_EXT
= 4, /* external sync */
247 FB_SYNC_COMP_HIGH_ACT
= 8, /* composite sync high active */
251 #if ENABLE_FEATURE_FBSET_READMODE
252 static void ss(uint32_t *x
, uint32_t flag
, char *buf
, const char *what
)
254 if (strcmp(buf
, what
) == 0)
260 /* Mode db file contains mode definitions like this:
261 * mode "800x600-48-lace"
262 * # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz
263 * geometry 800 600 800 600 8
264 * timings 27778 56 80 79 11 128 12
270 static NOINLINE
int read_mode_db(struct fb_var_screeninfo
*base
, const char *fn
,
273 char *token
[2], *p
, *s
;
274 parser_t
*parser
= config_open(fn
);
276 while (config_read(parser
, token
, 2, 1, "# \t\r", PARSE_NORMAL
)) {
277 if (strcmp(token
[0], "mode") != 0 || !token
[1])
279 p
= strstr(token
[1], mode
);
282 s
= p
+ strlen(mode
);
283 //bb_error_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
285 if (((!*s
|| isspace(*s
)) && '"' != s
[-1]) /* end-of-token */
286 || ('"' == *s
&& '"' == p
[-1]) /* ends with " but starts with " too! */
288 //bb_error_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
296 while (config_read(parser
, token
, 2, 1, "# \t", PARSE_NORMAL
)) {
299 //bb_error_msg("???[%s][%s]", token[0], token[1]);
300 if (strcmp(token
[0], "endmode") == 0) {
301 //bb_error_msg("OK[%s]", mode);
305 i
= index_in_strings(
306 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\0",
310 if (sizeof(int) == sizeof(base
->xres
)) {
311 sscanf(p
, "%d %d %d %d %d",
312 &base
->xres
, &base
->yres
,
313 &base
->xres_virtual
, &base
->yres_virtual
,
314 &base
->bits_per_pixel
);
316 int base_xres
, base_yres
;
317 int base_xres_virtual
, base_yres_virtual
;
318 int base_bits_per_pixel
;
319 sscanf(p
, "%d %d %d %d %d",
320 &base_xres
, &base_yres
,
321 &base_xres_virtual
, &base_yres_virtual
,
322 &base_bits_per_pixel
);
323 base
->xres
= base_xres
;
324 base
->yres
= base_yres
;
325 base
->xres_virtual
= base_xres_virtual
;
326 base
->yres_virtual
= base_yres_virtual
;
327 base
->bits_per_pixel
= base_bits_per_pixel
;
329 //bb_error_msg("GEO[%s]", p);
332 if (sizeof(int) == sizeof(base
->xres
)) {
333 sscanf(p
, "%d %d %d %d %d %d %d",
335 &base
->left_margin
, &base
->right_margin
,
336 &base
->upper_margin
, &base
->lower_margin
,
337 &base
->hsync_len
, &base
->vsync_len
);
340 int base_left_margin
, base_right_margin
;
341 int base_upper_margin
, base_lower_margin
;
342 int base_hsync_len
, base_vsync_len
;
343 sscanf(p
, "%d %d %d %d %d %d %d",
345 &base_left_margin
, &base_right_margin
,
346 &base_upper_margin
, &base_lower_margin
,
347 &base_hsync_len
, &base_vsync_len
);
348 base
->pixclock
= base_pixclock
;
349 base
->left_margin
= base_left_margin
;
350 base
->right_margin
= base_right_margin
;
351 base
->upper_margin
= base_upper_margin
;
352 base
->lower_margin
= base_lower_margin
;
353 base
->hsync_len
= base_hsync_len
;
354 base
->vsync_len
= base_vsync_len
;
356 //bb_error_msg("TIM[%s]", p);
360 static const uint32_t syncs
[] = {FB_VMODE_INTERLACED
, FB_VMODE_DOUBLE
};
361 ss(&base
->vmode
, syncs
[i
-2], p
, "false");
362 //bb_error_msg("VMODE[%s]", p);
368 static const uint32_t syncs
[] = {FB_SYNC_VERT_HIGH_ACT
, FB_SYNC_HOR_HIGH_ACT
, FB_SYNC_COMP_HIGH_ACT
};
369 ss(&base
->sync
, syncs
[i
-4], p
, "low");
370 //bb_error_msg("SYNC[%s]", p);
374 ss(&base
->sync
, FB_SYNC_EXT
, p
, "false");
375 //bb_error_msg("EXTSYNC[%s]", p);
378 int red_offset
, red_length
;
379 int green_offset
, green_length
;
380 int blue_offset
, blue_length
;
381 int transp_offset
, transp_length
;
383 sscanf(p
, "%d/%d,%d/%d,%d/%d,%d/%d",
384 &red_length
, &red_offset
,
385 &green_length
, &green_offset
,
386 &blue_length
, &blue_offset
,
387 &transp_length
, &transp_offset
);
388 base
->red
.offset
= red_offset
;
389 base
->red
.length
= red_length
;
390 base
->red
.msb_right
= 0;
391 base
->green
.offset
= green_offset
;
392 base
->green
.length
= green_length
;
393 base
->green
.msb_right
= 0;
394 base
->blue
.offset
= blue_offset
;
395 base
->blue
.length
= blue_length
;
396 base
->blue
.msb_right
= 0;
397 base
->transp
.offset
= transp_offset
;
398 base
->transp
.length
= transp_length
;
399 base
->transp
.msb_right
= 0;
407 static NOINLINE
void showmode(struct fb_var_screeninfo
*v
)
409 double drate
= 0, hrate
= 0, vrate
= 0;
412 drate
= 1e12
/ v
->pixclock
;
413 hrate
= drate
/ (v
->left_margin
+ v
->xres
+ v
->right_margin
+ v
->hsync_len
);
414 vrate
= hrate
/ (v
->upper_margin
+ v
->yres
+ v
->lower_margin
+ v
->vsync_len
);
416 printf("\nmode \"%ux%u-%u\"\n"
417 #if ENABLE_FEATURE_FBSET_FANCY
418 "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
420 "\tgeometry %u %u %u %u %u\n"
421 "\ttimings %u %u %u %u %u %u %u\n"
423 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
425 v
->xres
, v
->yres
, (int) (vrate
+ 0.5),
426 #if ENABLE_FEATURE_FBSET_FANCY
427 drate
/ 1e6
, hrate
/ 1e3
, vrate
,
429 v
->xres
, v
->yres
, v
->xres_virtual
, v
->yres_virtual
, v
->bits_per_pixel
,
430 v
->pixclock
, v
->left_margin
, v
->right_margin
, v
->upper_margin
, v
->lower_margin
,
431 v
->hsync_len
, v
->vsync_len
,
432 (v
->accel_flags
> 0 ? "true" : "false"),
433 v
->red
.length
, v
->red
.offset
, v
->green
.length
, v
->green
.offset
,
434 v
->blue
.length
, v
->blue
.offset
, v
->transp
.length
, v
->transp
.offset
);
437 int fbset_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
438 int fbset_main(int argc
, char **argv
)
441 OPT_CHANGE
= (1 << 0),
443 OPT_READMODE
= (1 << 2),
446 struct fb_var_screeninfo var_old
, var_set
;
448 unsigned options
= 0;
450 const char *fbdev
= DEFAULTFBDEV
;
451 IF_FEATURE_FBSET_READMODE(const char *modefile
= DEFAULTFBMODE
;)
453 char *mode
= mode
; /* for compiler */
455 memset(&var_set
, 0xff, sizeof(var_set
)); /* set all to -1 */
457 /* parse cmd args.... why do they have to make things so difficult? */
460 for (; argc
> 0 && (thisarg
= *argv
) != NULL
; argc
--, argv
++) {
461 if (thisarg
[0] != '-') {
462 if (!ENABLE_FEATURE_FBSET_READMODE
|| argc
!= 1)
465 options
|= OPT_READMODE
;
468 for (i
= 0; i
< ARRAY_SIZE(g_cmdoptions
); i
++) {
469 if (strcmp(thisarg
+ 1, g_cmdoptions
[i
].name
) != 0)
471 if (argc
<= g_cmdoptions
[i
].param_count
)
474 switch (g_cmdoptions
[i
].code
) {
479 IF_FEATURE_FBSET_READMODE(modefile
= argv
[1];)
488 var_set
.xres
= xatou32(argv
[1]);
489 var_set
.yres
= xatou32(argv
[2]);
490 var_set
.xres_virtual
= xatou32(argv
[3]);
491 var_set
.yres_virtual
= xatou32(argv
[4]);
492 var_set
.bits_per_pixel
= xatou32(argv
[5]);
495 var_set
.pixclock
= xatou32(argv
[1]);
496 var_set
.left_margin
= xatou32(argv
[2]);
497 var_set
.right_margin
= xatou32(argv
[3]);
498 var_set
.upper_margin
= xatou32(argv
[4]);
499 var_set
.lower_margin
= xatou32(argv
[5]);
500 var_set
.hsync_len
= xatou32(argv
[6]);
501 var_set
.vsync_len
= xatou32(argv
[7]);
506 var_set
.sync
|= FB_SYNC_HOR_HIGH_ACT
;
509 var_set
.sync
|= FB_SYNC_VERT_HIGH_ACT
;
511 #if ENABLE_FEATURE_FBSET_FANCY
513 var_set
.xres
= xatou32(argv
[1]);
516 var_set
.yres
= xatou32(argv
[1]);
519 var_set
.bits_per_pixel
= xatou32(argv
[1]);
523 bb_perror_msg_and_die("option '%s' not handled",
524 g_cmdoptions
[i
].name
);
526 switch (g_cmdoptions
[i
].code
) {
533 /* other commands imply changes */
534 options
|= OPT_CHANGE
;
536 argc
-= g_cmdoptions
[i
].param_count
;
537 argv
+= g_cmdoptions
[i
].param_count
;
544 fh
= xopen(fbdev
, O_RDONLY
);
545 xioctl(fh
, FBIOGET_VSCREENINFO
, &var_old
);
547 if (options
& OPT_READMODE
) {
548 #if ENABLE_FEATURE_FBSET_READMODE
549 if (!read_mode_db(&var_old
, modefile
, mode
)) {
550 bb_error_msg_and_die("unknown video mode '%s'", mode
);
552 options
|= OPT_CHANGE
;
556 if (options
& OPT_CHANGE
) {
557 copy_changed_values(&var_old
, &var_set
);
558 if (options
& OPT_ALL
)
559 var_old
.activate
= FB_ACTIVATE_ALL
;
560 xioctl(fh
, FBIOPUT_VSCREENINFO
, &var_old
);
563 if (options
== 0 || (options
& OPT_SHOW
))
566 if (ENABLE_FEATURE_CLEAN_UP
)