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 //TODO: convert to index_in_strings()
168 { "fb" , 1, CMD_FB
},
169 { "db" , 1, CMD_DB
},
170 { "a" , 0, CMD_ALL
},
171 { "i" , 0, CMD_INFO
},
172 { "g" , 5, CMD_GEOMETRY
},
173 { "t" , 7, CMD_TIMING
},
174 { "accel" , 1, CMD_ACCEL
},
175 { "hsync" , 1, CMD_HSYNC
},
176 { "vsync" , 1, CMD_VSYNC
},
177 { "laced" , 1, CMD_LACED
},
178 { "double" , 1, CMD_DOUBLE
},
179 { "show" , 0, CMD_SHOW
},
180 { "s" , 0, CMD_SHOW
},
181 #if ENABLE_FEATURE_FBSET_FANCY
182 { "all" , 0, CMD_ALL
},
183 { "xres" , 1, CMD_XRES
},
184 { "yres" , 1, CMD_YRES
},
185 { "vxres" , 1, CMD_VXRES
},
186 { "vyres" , 1, CMD_VYRES
},
187 { "depth" , 1, CMD_DEPTH
},
188 { "match" , 0, CMD_MATCH
},
189 { "geometry", 5, CMD_GEOMETRY
},
190 { "pixclock", 1, CMD_PIXCLOCK
},
191 { "left" , 1, CMD_LEFT
},
192 { "right" , 1, CMD_RIGHT
},
193 { "upper" , 1, CMD_UPPER
},
194 { "lower" , 1, CMD_LOWER
},
195 { "hslen" , 1, CMD_HSLEN
},
196 { "vslen" , 1, CMD_VSLEN
},
197 { "timings" , 7, CMD_TIMING
},
198 { "csync" , 1, CMD_CSYNC
},
199 { "gsync" , 1, CMD_GSYNC
},
200 { "extsync" , 1, CMD_EXTSYNC
},
201 { "bcast" , 1, CMD_BCAST
},
202 { "rgba" , 1, CMD_RGBA
},
203 { "step" , 1, CMD_STEP
},
204 { "move" , 1, CMD_MOVE
},
208 /* taken from linux/fb.h */
210 FB_SYNC_HOR_HIGH_ACT
= 1, /* horizontal sync high active */
211 FB_SYNC_VERT_HIGH_ACT
= 2, /* vertical sync high active */
212 #if ENABLE_FEATURE_FBSET_READMODE
213 FB_VMODE_INTERLACED
= 1, /* interlaced */
214 FB_VMODE_DOUBLE
= 2, /* double scan */
215 FB_SYNC_EXT
= 4, /* external sync */
216 FB_SYNC_COMP_HIGH_ACT
= 8, /* composite sync high active */
220 #if ENABLE_FEATURE_FBSET_READMODE
221 static void ss(uint32_t *x
, uint32_t flag
, char *buf
, const char *what
)
223 if (strcmp(buf
, what
) == 0)
229 /* Mode db file contains mode definitions like this:
230 * mode "800x600-48-lace"
231 * # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz
232 * geometry 800 600 800 600 8
233 * timings 27778 56 80 79 11 128 12
239 static int read_mode_db(struct fb_var_screeninfo
*base
, const char *fn
,
242 char *token
[2], *p
, *s
;
243 parser_t
*parser
= config_open(fn
);
245 while (config_read(parser
, token
, 2, 1, "# \t\r", PARSE_NORMAL
)) {
246 if (strcmp(token
[0], "mode") != 0 || !token
[1])
248 p
= strstr(token
[1], mode
);
251 s
= p
+ strlen(mode
);
252 //bb_error_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
254 if (((!*s
|| isspace(*s
)) && '"' != s
[-1]) /* end-of-token */
255 || ('"' == *s
&& '"' == p
[-1]) /* ends with " but starts with " too! */
257 //bb_error_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
265 while (config_read(parser
, token
, 2, 1, "# \t", PARSE_NORMAL
)) {
268 //bb_error_msg("???[%s][%s]", token[0], token[1]);
269 if (strcmp(token
[0], "endmode") == 0) {
270 //bb_error_msg("OK[%s]", mode);
274 i
= index_in_strings(
275 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\0",
279 if (sizeof(int) == sizeof(base
->xres
)) {
280 sscanf(p
, "%d %d %d %d %d",
281 &base
->xres
, &base
->yres
,
282 &base
->xres_virtual
, &base
->yres_virtual
,
283 &base
->bits_per_pixel
);
285 int base_xres
, base_yres
;
286 int base_xres_virtual
, base_yres_virtual
;
287 int base_bits_per_pixel
;
288 sscanf(p
, "%d %d %d %d %d",
289 &base_xres
, &base_yres
,
290 &base_xres_virtual
, &base_yres_virtual
,
291 &base_bits_per_pixel
);
292 base
->xres
= base_xres
;
293 base
->yres
= base_yres
;
294 base
->xres_virtual
= base_xres_virtual
;
295 base
->yres_virtual
= base_yres_virtual
;
296 base
->bits_per_pixel
= base_bits_per_pixel
;
298 //bb_error_msg("GEO[%s]", p);
301 if (sizeof(int) == sizeof(base
->xres
)) {
302 sscanf(p
, "%d %d %d %d %d %d %d",
304 &base
->left_margin
, &base
->right_margin
,
305 &base
->upper_margin
, &base
->lower_margin
,
306 &base
->hsync_len
, &base
->vsync_len
);
309 int base_left_margin
, base_right_margin
;
310 int base_upper_margin
, base_lower_margin
;
311 int base_hsync_len
, base_vsync_len
;
312 sscanf(p
, "%d %d %d %d %d %d %d",
314 &base_left_margin
, &base_right_margin
,
315 &base_upper_margin
, &base_lower_margin
,
316 &base_hsync_len
, &base_vsync_len
);
317 base
->pixclock
= base_pixclock
;
318 base
->left_margin
= base_left_margin
;
319 base
->right_margin
= base_right_margin
;
320 base
->upper_margin
= base_upper_margin
;
321 base
->lower_margin
= base_lower_margin
;
322 base
->hsync_len
= base_hsync_len
;
323 base
->vsync_len
= base_vsync_len
;
325 //bb_error_msg("TIM[%s]", p);
329 static const uint32_t syncs
[] = {FB_VMODE_INTERLACED
, FB_VMODE_DOUBLE
};
330 ss(&base
->vmode
, syncs
[i
-2], p
, "false");
331 //bb_error_msg("VMODE[%s]", p);
337 static const uint32_t syncs
[] = {FB_SYNC_VERT_HIGH_ACT
, FB_SYNC_HOR_HIGH_ACT
, FB_SYNC_COMP_HIGH_ACT
};
338 ss(&base
->sync
, syncs
[i
-4], p
, "low");
339 //bb_error_msg("SYNC[%s]", p);
343 ss(&base
->sync
, FB_SYNC_EXT
, p
, "false");
344 //bb_error_msg("EXTSYNC[%s]", p);
347 int red_offset
, red_length
;
348 int green_offset
, green_length
;
349 int blue_offset
, blue_length
;
350 int transp_offset
, transp_length
;
352 sscanf(p
, "%d/%d,%d/%d,%d/%d,%d/%d",
353 &red_length
, &red_offset
,
354 &green_length
, &green_offset
,
355 &blue_length
, &blue_offset
,
356 &transp_length
, &transp_offset
);
357 base
->red
.offset
= red_offset
;
358 base
->red
.length
= red_length
;
359 base
->red
.msb_right
= 0;
360 base
->green
.offset
= green_offset
;
361 base
->green
.length
= green_length
;
362 base
->green
.msb_right
= 0;
363 base
->blue
.offset
= blue_offset
;
364 base
->blue
.length
= blue_length
;
365 base
->blue
.msb_right
= 0;
366 base
->transp
.offset
= transp_offset
;
367 base
->transp
.length
= transp_length
;
368 base
->transp
.msb_right
= 0;
376 static NOINLINE
void showmode(struct fb_var_screeninfo
*v
)
378 double drate
= 0, hrate
= 0, vrate
= 0;
381 drate
= 1e12
/ v
->pixclock
;
382 hrate
= drate
/ (v
->left_margin
+ v
->xres
+ v
->right_margin
+ v
->hsync_len
);
383 vrate
= hrate
/ (v
->upper_margin
+ v
->yres
+ v
->lower_margin
+ v
->vsync_len
);
385 printf("\nmode \"%ux%u-%u\"\n"
386 #if ENABLE_FEATURE_FBSET_FANCY
387 "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
389 "\tgeometry %u %u %u %u %u\n"
390 "\ttimings %u %u %u %u %u %u %u\n"
392 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
394 v
->xres
, v
->yres
, (int) (vrate
+ 0.5),
395 #if ENABLE_FEATURE_FBSET_FANCY
396 drate
/ 1e6
, hrate
/ 1e3
, vrate
,
398 v
->xres
, v
->yres
, v
->xres_virtual
, v
->yres_virtual
, v
->bits_per_pixel
,
399 v
->pixclock
, v
->left_margin
, v
->right_margin
, v
->upper_margin
, v
->lower_margin
,
400 v
->hsync_len
, v
->vsync_len
,
401 (v
->accel_flags
> 0 ? "true" : "false"),
402 v
->red
.length
, v
->red
.offset
, v
->green
.length
, v
->green
.offset
,
403 v
->blue
.length
, v
->blue
.offset
, v
->transp
.length
, v
->transp
.offset
);
406 int fbset_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
407 int fbset_main(int argc
, char **argv
)
410 OPT_CHANGE
= (1 << 0),
412 OPT_READMODE
= (1 << 2),
415 struct fb_var_screeninfo var_old
, var_set
;
417 unsigned options
= 0;
419 const char *fbdev
= DEFAULTFBDEV
;
420 IF_FEATURE_FBSET_READMODE(const char *modefile
= DEFAULTFBMODE
;)
422 char *mode
= mode
; /* for compiler */
424 memset(&var_set
, 0xff, sizeof(var_set
)); /* set all to -1 */
426 /* parse cmd args.... why do they have to make things so difficult? */
429 for (; argc
> 0 && (thisarg
= *argv
) != NULL
; argc
--, argv
++) {
430 if (thisarg
[0] != '-') {
431 if (!ENABLE_FEATURE_FBSET_READMODE
|| argc
!= 1)
434 options
|= OPT_READMODE
;
437 for (i
= 0; i
< ARRAY_SIZE(g_cmdoptions
); i
++) {
438 if (strcmp(thisarg
+ 1, g_cmdoptions
[i
].name
) != 0)
440 if (argc
<= g_cmdoptions
[i
].param_count
)
443 switch (g_cmdoptions
[i
].code
) {
448 IF_FEATURE_FBSET_READMODE(modefile
= argv
[1];)
457 var_set
.xres
= xatou32(argv
[1]);
458 var_set
.yres
= xatou32(argv
[2]);
459 var_set
.xres_virtual
= xatou32(argv
[3]);
460 var_set
.yres_virtual
= xatou32(argv
[4]);
461 var_set
.bits_per_pixel
= xatou32(argv
[5]);
464 var_set
.pixclock
= xatou32(argv
[1]);
465 var_set
.left_margin
= xatou32(argv
[2]);
466 var_set
.right_margin
= xatou32(argv
[3]);
467 var_set
.upper_margin
= xatou32(argv
[4]);
468 var_set
.lower_margin
= xatou32(argv
[5]);
469 var_set
.hsync_len
= xatou32(argv
[6]);
470 var_set
.vsync_len
= xatou32(argv
[7]);
475 var_set
.sync
|= FB_SYNC_HOR_HIGH_ACT
;
478 var_set
.sync
|= FB_SYNC_VERT_HIGH_ACT
;
480 #if ENABLE_FEATURE_FBSET_FANCY
482 var_set
.xres
= xatou32(argv
[1]);
485 var_set
.yres
= xatou32(argv
[1]);
488 var_set
.bits_per_pixel
= xatou32(argv
[1]);
492 switch (g_cmdoptions
[i
].code
) {
499 /* other commands imply changes */
500 options
|= OPT_CHANGE
;
502 argc
-= g_cmdoptions
[i
].param_count
;
503 argv
+= g_cmdoptions
[i
].param_count
;
510 fh
= xopen(fbdev
, O_RDONLY
);
511 xioctl(fh
, FBIOGET_VSCREENINFO
, &var_old
);
513 if (options
& OPT_READMODE
) {
514 #if ENABLE_FEATURE_FBSET_READMODE
515 if (!read_mode_db(&var_old
, modefile
, mode
)) {
516 bb_error_msg_and_die("unknown video mode '%s'", mode
);
518 options
|= OPT_CHANGE
;
522 if (options
& OPT_CHANGE
) {
523 copy_changed_values(&var_old
, &var_set
);
524 if (options
& OPT_ALL
)
525 var_old
.activate
= FB_ACTIVATE_ALL
;
526 xioctl(fh
, FBIOPUT_VSCREENINFO
, &var_old
);
529 if (options
== 0 || (options
& OPT_SHOW
))
532 if (ENABLE_FEATURE_CLEAN_UP
)