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 tarball for details.
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)
17 #define DEFAULTFBDEV FB_0
18 #define DEFAULTFBMODE "/etc/fb.modes"
30 /* CMD_XCOMPAT = 10, */
36 #if ENABLE_FEATURE_FBSET_FANCY
60 /* Stuff stolen from the kernel's fb.h */
61 #define FB_ACTIVATE_ALL 64
63 FBIOGET_VSCREENINFO = 0x4600,
64 FBIOPUT_VSCREENINFO = 0x4601
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 */
71 struct fb_var_screeninfo {
72 uint32_t xres; /* visible resolution */
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 */
79 uint32_t bits_per_pixel;
80 uint32_t grayscale; /* !=0 Graylevels instead of colors */
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 */
87 uint32_t nonstd; /* !=0 Non standard pixel format */
89 uint32_t activate; /* see FB_ACTIVATE_x */
91 uint32_t height; /* height of picture in mm */
92 uint32_t width; /* width of picture in mm */
94 uint32_t accel_flags; /* acceleration flags (hints) */
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 */
110 static const struct cmdoptions_t {
112 const unsigned char param_count;
113 const unsigned char code;
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 },
156 #if ENABLE_FEATURE_FBSET_READMODE
157 /* taken from linux/fb.h */
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 */
168 #if ENABLE_FEATURE_FBSET_READMODE
169 static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what)
171 if (strcmp(buf, what) == 0)
177 static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
180 char *token[2], *p, *s;
181 parser_t *parser = config_open(fn);
183 while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) {
184 if (strcmp(token[0], "mode") != 0 || !token[1])
186 p = strstr(token[1], mode);
189 s = p + strlen(mode);
190 //bb_info_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
192 if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */
193 || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */
195 //bb_info_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
203 while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) {
206 //bb_info_msg("???[%s][%s]", token[0], token[1]);
207 if (strcmp(token[0], "endmode") == 0) {
208 //bb_info_msg("OK[%s]", mode);
212 i = index_in_strings(
213 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\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);
225 sscanf(p, "%d %d %d %d %d %d %d",
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);
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);
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);
248 ss(&base->sync, FB_SYNC_EXT, p, "false");
249 //bb_info_msg("EXTSYNC[%s]", p);
257 static void setmode(struct fb_var_screeninfo *base,
258 struct fb_var_screeninfo *set)
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;
272 static void showmode(struct fb_var_screeninfo *v)
274 double drate = 0, hrate = 0, vrate = 0;
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);
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"
285 "\tgeometry %u %u %u %u %u\n"
286 "\ttimings %u %u %u %u %u %u %u\n"
288 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
290 v->xres, v->yres, (int) (vrate + 0.5),
291 #if ENABLE_FEATURE_FBSET_FANCY
292 drate / 1e6, hrate / 1e3, vrate,
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);
302 int fbset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
303 int fbset_main(int argc, char **argv)
306 OPT_CHANGE = (1 << 0),
308 OPT_READMODE = (1 << 2),
311 struct fb_var_screeninfo var, varset;
313 unsigned options = 0;
315 const char *fbdev = DEFAULTFBDEV;
316 const char *modefile = DEFAULTFBMODE;
317 char *thisarg, *mode = NULL;
319 memset(&varset, 0xff, sizeof(varset));
321 /* parse cmd args.... why do they have to make things so difficult? */
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)
328 if (argc <= g_cmdoptions[i].param_count)
331 switch (g_cmdoptions[i].code) {
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]);
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]);
360 #if ENABLE_FEATURE_FBSET_FANCY
362 varset.xres = xatou32(argv[1]);
365 varset.yres = xatou32(argv[1]);
368 varset.bits_per_pixel = xatou32(argv[1]);
372 switch (g_cmdoptions[i].code) {
379 options |= OPT_CHANGE; /* the other commands imply changes */
381 argc -= g_cmdoptions[i].param_count;
382 argv += g_cmdoptions[i].param_count;
388 options |= OPT_READMODE;
392 fh = xopen(fbdev, O_RDONLY);
393 xioctl(fh, FBIOGET_VSCREENINFO, &var);
394 if (options & OPT_READMODE) {
395 #if !ENABLE_FEATURE_FBSET_READMODE
398 if (!read_mode_db(&var, modefile, mode)) {
399 bb_error_msg_and_die("unknown video mode '%s'", mode);
404 if (options & OPT_CHANGE) {
405 setmode(&var, &varset);
406 if (options & OPT_ALL)
407 var.activate = FB_ACTIVATE_ALL;
408 xioctl(fh, FBIOPUT_VSCREENINFO, &var);
410 if (options == 0 || options & OPT_SHOW)
412 /* Don't close the file, as exiting will take care of that */