source: MondoRescue/branches/3.3/mindi-busybox/util-linux/fbset.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 15.4 KB
Line 
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
37enum {
38 FBIOGET_VSCREENINFO = 0x4600,
39 FBIOPUT_VSCREENINFO = 0x4601
40};
41
42struct 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};
47struct 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
85static 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
95static 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
121enum {
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
161static 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//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 },
205#endif
206};
207
208/* taken from linux/fb.h */
209enum {
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 */
217#endif
218};
219
220#if ENABLE_FEATURE_FBSET_READMODE
221static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what)
222{
223 if (strcmp(buf, what) == 0)
224 *x &= ~flag;
225 else
226 *x |= flag;
227}
228
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
234 * laced true
235 * hsync high
236 * vsync high
237 * endmode
238 */
239static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
240 const char *mode)
241{
242 char *token[2], *p, *s;
243 parser_t *parser = config_open(fn);
244
245 while (config_read(parser, token, 2, 1, "# \t\r", PARSE_NORMAL)) {
246 if (strcmp(token[0], "mode") != 0 || !token[1])
247 continue;
248 p = strstr(token[1], mode);
249 if (!p)
250 continue;
251 s = p + strlen(mode);
252 //bb_error_msg("CHECK[%s][%s][%d]", mode, p-1, *s);
253 /* exact match? */
254 if (((!*s || isspace(*s)) && '"' != s[-1]) /* end-of-token */
255 || ('"' == *s && '"' == p[-1]) /* ends with " but starts with " too! */
256 ) {
257 //bb_error_msg("FOUND[%s][%s][%s][%d]", token[1], p, mode, isspace(*s));
258 break;
259 }
260 }
261
262 if (!token[0])
263 return 0;
264
265 while (config_read(parser, token, 2, 1, "# \t", PARSE_NORMAL)) {
266 int i;
267
268//bb_error_msg("???[%s][%s]", token[0], token[1]);
269 if (strcmp(token[0], "endmode") == 0) {
270//bb_error_msg("OK[%s]", mode);
271 return 1;
272 }
273 p = token[1];
274 i = index_in_strings(
275 "geometry\0timings\0interlaced\0double\0vsync\0hsync\0csync\0extsync\0rgba\0",
276 token[0]);
277 switch (i) {
278 case 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);
284 } else {
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;
297 }
298//bb_error_msg("GEO[%s]", p);
299 break;
300 case 1:
301 if (sizeof(int) == sizeof(base->xres)) {
302 sscanf(p, "%d %d %d %d %d %d %d",
303 &base->pixclock,
304 &base->left_margin, &base->right_margin,
305 &base->upper_margin, &base->lower_margin,
306 &base->hsync_len, &base->vsync_len);
307 } else {
308 int base_pixclock;
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",
313 &base_pixclock,
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;
324 }
325//bb_error_msg("TIM[%s]", p);
326 break;
327 case 2:
328 case 3: {
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);
332 break;
333 }
334 case 4:
335 case 5:
336 case 6: {
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);
340 break;
341 }
342 case 7:
343 ss(&base->sync, FB_SYNC_EXT, p, "false");
344//bb_error_msg("EXTSYNC[%s]", p);
345 break;
346 case 8: {
347 int red_offset, red_length;
348 int green_offset, green_length;
349 int blue_offset, blue_length;
350 int transp_offset, transp_length;
351
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;
369 }
370 }
371 }
372 return 0;
373}
374#endif
375
376static NOINLINE void showmode(struct fb_var_screeninfo *v)
377{
378 double drate = 0, hrate = 0, vrate = 0;
379
380 if (v->pixclock) {
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);
384 }
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"
388#endif
389 "\tgeometry %u %u %u %u %u\n"
390 "\ttimings %u %u %u %u %u %u %u\n"
391 "\taccel %s\n"
392 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
393 "endmode\n\n",
394 v->xres, v->yres, (int) (vrate + 0.5),
395#if ENABLE_FEATURE_FBSET_FANCY
396 drate / 1e6, hrate / 1e3, vrate,
397#endif
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);
404}
405
406int fbset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
407int fbset_main(int argc, char **argv)
408{
409 enum {
410 OPT_CHANGE = (1 << 0),
411 OPT_SHOW = (1 << 1),
412 OPT_READMODE = (1 << 2),
413 OPT_ALL = (1 << 3),
414 };
415 struct fb_var_screeninfo var_old, var_set;
416 int fh, i;
417 unsigned options = 0;
418
419 const char *fbdev = DEFAULTFBDEV;
420 IF_FEATURE_FBSET_READMODE(const char *modefile = DEFAULTFBMODE;)
421 char *thisarg;
422 char *mode = mode; /* for compiler */
423
424 memset(&var_set, 0xff, sizeof(var_set)); /* set all to -1 */
425
426 /* parse cmd args.... why do they have to make things so difficult? */
427 argv++;
428 argc--;
429 for (; argc > 0 && (thisarg = *argv) != NULL; argc--, argv++) {
430 if (thisarg[0] != '-') {
431 if (!ENABLE_FEATURE_FBSET_READMODE || argc != 1)
432 bb_show_usage();
433 mode = thisarg;
434 options |= OPT_READMODE;
435 goto contin;
436 }
437 for (i = 0; i < ARRAY_SIZE(g_cmdoptions); i++) {
438 if (strcmp(thisarg + 1, g_cmdoptions[i].name) != 0)
439 continue;
440 if (argc <= g_cmdoptions[i].param_count)
441 bb_show_usage();
442
443 switch (g_cmdoptions[i].code) {
444 case CMD_FB:
445 fbdev = argv[1];
446 break;
447 case CMD_DB:
448 IF_FEATURE_FBSET_READMODE(modefile = argv[1];)
449 break;
450 case CMD_ALL:
451 options |= OPT_ALL;
452 break;
453 case CMD_SHOW:
454 options |= OPT_SHOW;
455 break;
456 case CMD_GEOMETRY:
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]);
462 break;
463 case CMD_TIMING:
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]);
471 break;
472 case CMD_ACCEL:
473 break;
474 case CMD_HSYNC:
475 var_set.sync |= FB_SYNC_HOR_HIGH_ACT;
476 break;
477 case CMD_VSYNC:
478 var_set.sync |= FB_SYNC_VERT_HIGH_ACT;
479 break;
480#if ENABLE_FEATURE_FBSET_FANCY
481 case CMD_XRES:
482 var_set.xres = xatou32(argv[1]);
483 break;
484 case CMD_YRES:
485 var_set.yres = xatou32(argv[1]);
486 break;
487 case CMD_DEPTH:
488 var_set.bits_per_pixel = xatou32(argv[1]);
489 break;
490#endif
491 }
492 switch (g_cmdoptions[i].code) {
493 case CMD_FB:
494 case CMD_DB:
495 case CMD_ALL:
496 case CMD_SHOW:
497 break;
498 default:
499 /* other commands imply changes */
500 options |= OPT_CHANGE;
501 }
502 argc -= g_cmdoptions[i].param_count;
503 argv += g_cmdoptions[i].param_count;
504 goto contin;
505 }
506 bb_show_usage();
507 contin: ;
508 }
509
510 fh = xopen(fbdev, O_RDONLY);
511 xioctl(fh, FBIOGET_VSCREENINFO, &var_old);
512
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);
517 }
518 options |= OPT_CHANGE;
519#endif
520 }
521
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);
527 }
528
529 if (options == 0 || (options & OPT_SHOW))
530 showmode(&var_old);
531
532 if (ENABLE_FEATURE_CLEAN_UP)
533 close(fh);
534
535 return EXIT_SUCCESS;
536}
Note: See TracBrowser for help on using the repository browser.