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 //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"
20 //usage:#define fbset_example_usage
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"
32 #define DEFAULTFBDEV FB_0
33 #define DEFAULTFBMODE "/etc/fb.modes"
35 /* Stuff stolen from the kernel's fb.h */
36 #define FB_ACTIVATE_ALL 64
38 FBIOGET_VSCREENINFO
= 0x4600,
39 FBIOPUT_VSCREENINFO
= 0x4601
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 */
47 struct fb_var_screeninfo
{
48 uint32_t xres
; /* visible resolution */
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 */
55 uint32_t bits_per_pixel
;
56 uint32_t grayscale
; /* !=0 Graylevels instead of colors */
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 */
63 uint32_t nonstd
; /* !=0 Non standard pixel format */
65 uint32_t activate
; /* see FB_ACTIVATE_x */
67 uint32_t height
; /* height of picture in mm */
68 uint32_t width
; /* width of picture in mm */
70 uint32_t accel_flags
; /* acceleration flags (hints) */
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 */
85 static void copy_if_gt0(uint32_t *src
, uint32_t *dst
, unsigned cnt
)
88 if ((int32_t) *src
> 0)
95 static NOINLINE
void copy_changed_values(
96 struct fb_var_screeninfo
*base
,
97 struct fb_var_screeninfo
*set
)
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);
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);
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);
131 /* CMD_XCOMPAT = 10, */
137 #if ENABLE_FEATURE_FBSET_FANCY
161 static const struct cmdoptions_t
{
163 const unsigned char param_count
;
164 const unsigned char code
;
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
},
207 /* taken from linux/fb.h */
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 */
219 #if ENABLE_FEATURE_FBSET_READMODE
220 static void ss(uint32_t *x
, uint32_t flag
, char *buf
, const char *what
)
222 if (strcmp(buf
, what
) == 0)
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
238 static int read_mode_db(struct fb_var_screeninfo
*base
, const char *fn
,
241 char *token
[2], *p
, *s
;
242 parser_t
*parser
= config_open(fn
);
244 while (config_read(parser
, token
, 2, 1, "# \t\r", PARSE_NORMAL
)) {
245 if (strcmp(token
[0], "mode") != 0 || !token
[1])
247 p
= strstr(token
[1], mode
);
250 s
= p
+ strlen(mode
);
251 //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
253 if (((!*s
|| isspace(*s
)) && '"' != s
[-1]) /* end-of-token */
254 || ('"' == *s
&& '"' == p
[-1]) /* ends with " but starts with " too! */
256 //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
264 while (config_read(parser
, token
, 2, 1, "# \t", PARSE_NORMAL
)) {
267 //bb_info_msg("???[%s][%s]", token[0], token[1]);
268 if (strcmp(token
[0], "endmode") == 0) {
269 //bb_info_msg("OK[%s]", mode);
273 i
= index_in_strings(
274 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\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
);
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
;
297 //bb_info_msg("GEO[%s]", p);
300 if (sizeof(int) == sizeof(base
->xres
)) {
301 sscanf(p
, "%d %d %d %d %d %d %d",
303 &base
->left_margin
, &base
->right_margin
,
304 &base
->upper_margin
, &base
->lower_margin
,
305 &base
->hsync_len
, &base
->vsync_len
);
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",
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
;
324 //bb_info_msg("TIM[%s]", p);
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);
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);
342 ss(&base
->sync
, FB_SYNC_EXT
, p
, "false");
343 //bb_info_msg("EXTSYNC[%s]", p);
346 int red_offset
, red_length
;
347 int green_offset
, green_length
;
348 int blue_offset
, blue_length
;
349 int transp_offset
, transp_length
;
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;
375 static NOINLINE
void showmode(struct fb_var_screeninfo
*v
)
377 double drate
= 0, hrate
= 0, vrate
= 0;
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
);
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"
388 "\tgeometry %u %u %u %u %u\n"
389 "\ttimings %u %u %u %u %u %u %u\n"
391 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
393 v
->xres
, v
->yres
, (int) (vrate
+ 0.5),
394 #if ENABLE_FEATURE_FBSET_FANCY
395 drate
/ 1e6
, hrate
/ 1e3
, vrate
,
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
);
405 int fbset_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
406 int fbset_main(int argc
, char **argv
)
409 OPT_CHANGE
= (1 << 0),
411 OPT_READMODE
= (1 << 2),
414 struct fb_var_screeninfo var_old
, var_set
;
416 unsigned options
= 0;
418 const char *fbdev
= DEFAULTFBDEV
;
419 const char *modefile
= DEFAULTFBMODE
;
421 char *mode
= mode
; /* for compiler */
423 memset(&var_set
, 0xff, sizeof(var_set
)); /* set all to -1 */
425 /* parse cmd args.... why do they have to make things so difficult? */
428 for (; argc
> 0 && (thisarg
= *argv
) != NULL
; argc
--, argv
++) {
429 if (thisarg
[0] != '-') {
430 if (!ENABLE_FEATURE_FBSET_READMODE
|| argc
!= 1)
433 options
|= OPT_READMODE
;
436 for (i
= 0; i
< ARRAY_SIZE(g_cmdoptions
); i
++) {
437 if (strcmp(thisarg
+ 1, g_cmdoptions
[i
].name
) != 0)
439 if (argc
<= g_cmdoptions
[i
].param_count
)
442 switch (g_cmdoptions
[i
].code
) {
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]);
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]);
474 var_set
.sync
|= FB_SYNC_HOR_HIGH_ACT
;
477 var_set
.sync
|= FB_SYNC_VERT_HIGH_ACT
;
479 #if ENABLE_FEATURE_FBSET_FANCY
481 var_set
.xres
= xatou32(argv
[1]);
484 var_set
.yres
= xatou32(argv
[1]);
487 var_set
.bits_per_pixel
= xatou32(argv
[1]);
491 switch (g_cmdoptions
[i
].code
) {
498 /* other commands imply changes */
499 options
|= OPT_CHANGE
;
501 argc
-= g_cmdoptions
[i
].param_count
;
502 argv
+= g_cmdoptions
[i
].param_count
;
509 fh
= xopen(fbdev
, O_RDONLY
);
510 xioctl(fh
, FBIOGET_VSCREENINFO
, &var_old
);
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
);
517 options
|= OPT_CHANGE
;
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
);
528 if (options
== 0 || (options
& OPT_SHOW
))
531 if (ENABLE_FEATURE_CLEAN_UP
)