17 |
#define DEFAULTFBDEV FB_0 |
#define DEFAULTFBDEV FB_0 |
18 |
#define DEFAULTFBMODE "/etc/fb.modes" |
#define DEFAULTFBMODE "/etc/fb.modes" |
19 |
|
|
|
enum { |
|
|
CMD_FB = 1, |
|
|
CMD_DB = 2, |
|
|
CMD_GEOMETRY = 3, |
|
|
CMD_TIMING = 4, |
|
|
CMD_ACCEL = 5, |
|
|
CMD_HSYNC = 6, |
|
|
CMD_VSYNC = 7, |
|
|
CMD_LACED = 8, |
|
|
CMD_DOUBLE = 9, |
|
|
/* CMD_XCOMPAT = 10, */ |
|
|
CMD_ALL = 11, |
|
|
CMD_INFO = 12, |
|
|
CMD_CHANGE = 13, |
|
|
|
|
|
#if ENABLE_FEATURE_FBSET_FANCY |
|
|
CMD_XRES = 100, |
|
|
CMD_YRES = 101, |
|
|
CMD_VXRES = 102, |
|
|
CMD_VYRES = 103, |
|
|
CMD_DEPTH = 104, |
|
|
CMD_MATCH = 105, |
|
|
CMD_PIXCLOCK = 106, |
|
|
CMD_LEFT = 107, |
|
|
CMD_RIGHT = 108, |
|
|
CMD_UPPER = 109, |
|
|
CMD_LOWER = 110, |
|
|
CMD_HSLEN = 111, |
|
|
CMD_VSLEN = 112, |
|
|
CMD_CSYNC = 113, |
|
|
CMD_GSYNC = 114, |
|
|
CMD_EXTSYNC = 115, |
|
|
CMD_BCAST = 116, |
|
|
CMD_RGBA = 117, |
|
|
CMD_STEP = 118, |
|
|
CMD_MOVE = 119, |
|
|
#endif |
|
|
}; |
|
|
|
|
20 |
/* Stuff stolen from the kernel's fb.h */ |
/* Stuff stolen from the kernel's fb.h */ |
21 |
#define FB_ACTIVATE_ALL 64 |
#define FB_ACTIVATE_ALL 64 |
22 |
enum { |
enum { |
23 |
FBIOGET_VSCREENINFO = 0x4600, |
FBIOGET_VSCREENINFO = 0x4600, |
24 |
FBIOPUT_VSCREENINFO = 0x4601 |
FBIOPUT_VSCREENINFO = 0x4601 |
25 |
}; |
}; |
26 |
|
|
27 |
struct fb_bitfield { |
struct fb_bitfield { |
28 |
uint32_t offset; /* beginning of bitfield */ |
uint32_t offset; /* beginning of bitfield */ |
29 |
uint32_t length; /* length of bitfield */ |
uint32_t length; /* length of bitfield */ |
52 |
uint32_t height; /* height of picture in mm */ |
uint32_t height; /* height of picture in mm */ |
53 |
uint32_t width; /* width of picture in mm */ |
uint32_t width; /* width of picture in mm */ |
54 |
|
|
55 |
uint32_t accel_flags; /* acceleration flags (hints) */ |
uint32_t accel_flags; /* acceleration flags (hints) */ |
56 |
|
|
57 |
/* Timing: All values in pixclocks, except pixclock (of course) */ |
/* Timing: All values in pixclocks, except pixclock (of course) */ |
58 |
uint32_t pixclock; /* pixel clock in ps (pico seconds) */ |
uint32_t pixclock; /* pixel clock in ps (pico seconds) */ |
67 |
uint32_t reserved[6]; /* Reserved for future compatibility */ |
uint32_t reserved[6]; /* Reserved for future compatibility */ |
68 |
}; |
}; |
69 |
|
|
70 |
|
static void copy_if_gt0(uint32_t *src, uint32_t *dst, unsigned cnt) |
71 |
|
{ |
72 |
|
do { |
73 |
|
if ((int32_t) *src > 0) |
74 |
|
*dst = *src; |
75 |
|
src++; |
76 |
|
dst++; |
77 |
|
} while (--cnt); |
78 |
|
} |
79 |
|
|
80 |
|
static NOINLINE void copy_changed_values( |
81 |
|
struct fb_var_screeninfo *base, |
82 |
|
struct fb_var_screeninfo *set) |
83 |
|
{ |
84 |
|
//if ((int32_t) set->xres > 0) base->xres = set->xres; |
85 |
|
//if ((int32_t) set->yres > 0) base->yres = set->yres; |
86 |
|
//if ((int32_t) set->xres_virtual > 0) base->xres_virtual = set->xres_virtual; |
87 |
|
//if ((int32_t) set->yres_virtual > 0) base->yres_virtual = set->yres_virtual; |
88 |
|
copy_if_gt0(&set->xres, &base->xres, 4); |
89 |
|
|
90 |
|
if ((int32_t) set->bits_per_pixel > 0) base->bits_per_pixel = set->bits_per_pixel; |
91 |
|
//copy_if_gt0(&set->bits_per_pixel, &base->bits_per_pixel, 1); |
92 |
|
|
93 |
|
//if ((int32_t) set->pixclock > 0) base->pixclock = set->pixclock; |
94 |
|
//if ((int32_t) set->left_margin > 0) base->left_margin = set->left_margin; |
95 |
|
//if ((int32_t) set->right_margin > 0) base->right_margin = set->right_margin; |
96 |
|
//if ((int32_t) set->upper_margin > 0) base->upper_margin = set->upper_margin; |
97 |
|
//if ((int32_t) set->lower_margin > 0) base->lower_margin = set->lower_margin; |
98 |
|
//if ((int32_t) set->hsync_len > 0) base->hsync_len = set->hsync_len; |
99 |
|
//if ((int32_t) set->vsync_len > 0) base->vsync_len = set->vsync_len; |
100 |
|
//if ((int32_t) set->sync > 0) base->sync = set->sync; |
101 |
|
//if ((int32_t) set->vmode > 0) base->vmode = set->vmode; |
102 |
|
copy_if_gt0(&set->pixclock, &base->pixclock, 9); |
103 |
|
} |
104 |
|
|
105 |
|
|
106 |
|
enum { |
107 |
|
CMD_FB = 1, |
108 |
|
CMD_DB = 2, |
109 |
|
CMD_GEOMETRY = 3, |
110 |
|
CMD_TIMING = 4, |
111 |
|
CMD_ACCEL = 5, |
112 |
|
CMD_HSYNC = 6, |
113 |
|
CMD_VSYNC = 7, |
114 |
|
CMD_LACED = 8, |
115 |
|
CMD_DOUBLE = 9, |
116 |
|
/* CMD_XCOMPAT = 10, */ |
117 |
|
CMD_ALL = 11, |
118 |
|
CMD_INFO = 12, |
119 |
|
CMD_SHOW = 13, |
120 |
|
CMD_CHANGE = 14, |
121 |
|
|
122 |
|
#if ENABLE_FEATURE_FBSET_FANCY |
123 |
|
CMD_XRES = 100, |
124 |
|
CMD_YRES = 101, |
125 |
|
CMD_VXRES = 102, |
126 |
|
CMD_VYRES = 103, |
127 |
|
CMD_DEPTH = 104, |
128 |
|
CMD_MATCH = 105, |
129 |
|
CMD_PIXCLOCK = 106, |
130 |
|
CMD_LEFT = 107, |
131 |
|
CMD_RIGHT = 108, |
132 |
|
CMD_UPPER = 109, |
133 |
|
CMD_LOWER = 110, |
134 |
|
CMD_HSLEN = 111, |
135 |
|
CMD_VSLEN = 112, |
136 |
|
CMD_CSYNC = 113, |
137 |
|
CMD_GSYNC = 114, |
138 |
|
CMD_EXTSYNC = 115, |
139 |
|
CMD_BCAST = 116, |
140 |
|
CMD_RGBA = 117, |
141 |
|
CMD_STEP = 118, |
142 |
|
CMD_MOVE = 119, |
143 |
|
#endif |
144 |
|
}; |
145 |
|
|
146 |
static const struct cmdoptions_t { |
static const struct cmdoptions_t { |
147 |
const char name[9]; |
const char name[9]; |
160 |
{ "vsync" , 1, CMD_VSYNC }, |
{ "vsync" , 1, CMD_VSYNC }, |
161 |
{ "laced" , 1, CMD_LACED }, |
{ "laced" , 1, CMD_LACED }, |
162 |
{ "double" , 1, CMD_DOUBLE }, |
{ "double" , 1, CMD_DOUBLE }, |
163 |
{ "n" , 0, CMD_CHANGE }, |
{ "show" , 0, CMD_SHOW }, |
164 |
|
{ "s" , 0, CMD_SHOW }, |
165 |
#if ENABLE_FEATURE_FBSET_FANCY |
#if ENABLE_FEATURE_FBSET_FANCY |
166 |
{ "all" , 0, CMD_ALL }, |
{ "all" , 0, CMD_ALL }, |
167 |
{ "xres" , 1, CMD_XRES }, |
{ "xres" , 1, CMD_XRES }, |
189 |
#endif |
#endif |
190 |
}; |
}; |
191 |
|
|
|
#if ENABLE_FEATURE_FBSET_READMODE |
|
192 |
/* taken from linux/fb.h */ |
/* taken from linux/fb.h */ |
193 |
enum { |
enum { |
|
FB_VMODE_INTERLACED = 1, /* interlaced */ |
|
|
FB_VMODE_DOUBLE = 2, /* double scan */ |
|
194 |
FB_SYNC_HOR_HIGH_ACT = 1, /* horizontal sync high active */ |
FB_SYNC_HOR_HIGH_ACT = 1, /* horizontal sync high active */ |
195 |
FB_SYNC_VERT_HIGH_ACT = 2, /* vertical sync high active */ |
FB_SYNC_VERT_HIGH_ACT = 2, /* vertical sync high active */ |
196 |
|
#if ENABLE_FEATURE_FBSET_READMODE |
197 |
|
FB_VMODE_INTERLACED = 1, /* interlaced */ |
198 |
|
FB_VMODE_DOUBLE = 2, /* double scan */ |
199 |
FB_SYNC_EXT = 4, /* external sync */ |
FB_SYNC_EXT = 4, /* external sync */ |
200 |
FB_SYNC_COMP_HIGH_ACT = 8, /* composite sync high active */ |
FB_SYNC_COMP_HIGH_ACT = 8, /* composite sync high active */ |
|
}; |
|
201 |
#endif |
#endif |
202 |
|
}; |
203 |
|
|
204 |
#if ENABLE_FEATURE_FBSET_READMODE |
#if ENABLE_FEATURE_FBSET_READMODE |
205 |
static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what) |
static void ss(uint32_t *x, uint32_t flag, char *buf, const char *what) |
210 |
*x |= flag; |
*x |= flag; |
211 |
} |
} |
212 |
|
|
213 |
static int readmode(struct fb_var_screeninfo *base, const char *fn, |
/* Mode db file contains mode definitions like this: |
214 |
|
* mode "800x600-48-lace" |
215 |
|
* # D: 36.00 MHz, H: 33.835 kHz, V: 96.39 Hz |
216 |
|
* geometry 800 600 800 600 8 |
217 |
|
* timings 27778 56 80 79 11 128 12 |
218 |
|
* laced true |
219 |
|
* hsync high |
220 |
|
* vsync high |
221 |
|
* endmode |
222 |
|
*/ |
223 |
|
static int read_mode_db(struct fb_var_screeninfo *base, const char *fn, |
224 |
const char *mode) |
const char *mode) |
225 |
{ |
{ |
226 |
char *token[2], *p, *s; |
char *token[2], *p, *s; |
260 |
token[0]); |
token[0]); |
261 |
switch (i) { |
switch (i) { |
262 |
case 0: |
case 0: |
263 |
/* FIXME: catastrophic on arches with 64bit ints */ |
if (sizeof(int) == sizeof(base->xres)) { |
264 |
sscanf(p, "%d %d %d %d %d", |
sscanf(p, "%d %d %d %d %d", |
265 |
&(base->xres), &(base->yres), |
&base->xres, &base->yres, |
266 |
&(base->xres_virtual), &(base->yres_virtual), |
&base->xres_virtual, &base->yres_virtual, |
267 |
&(base->bits_per_pixel)); |
&base->bits_per_pixel); |
268 |
|
} else { |
269 |
|
int base_xres, base_yres; |
270 |
|
int base_xres_virtual, base_yres_virtual; |
271 |
|
int base_bits_per_pixel; |
272 |
|
sscanf(p, "%d %d %d %d %d", |
273 |
|
&base_xres, &base_yres, |
274 |
|
&base_xres_virtual, &base_yres_virtual, |
275 |
|
&base_bits_per_pixel); |
276 |
|
base->xres = base_xres; |
277 |
|
base->yres = base_yres; |
278 |
|
base->xres_virtual = base_xres_virtual; |
279 |
|
base->yres_virtual = base_yres_virtual; |
280 |
|
base->bits_per_pixel = base_bits_per_pixel; |
281 |
|
} |
282 |
//bb_info_msg("GEO[%s]", p); |
//bb_info_msg("GEO[%s]", p); |
283 |
break; |
break; |
284 |
case 1: |
case 1: |
285 |
sscanf(p, "%d %d %d %d %d %d %d", |
if (sizeof(int) == sizeof(base->xres)) { |
286 |
&(base->pixclock), |
sscanf(p, "%d %d %d %d %d %d %d", |
287 |
&(base->left_margin), &(base->right_margin), |
&base->pixclock, |
288 |
&(base->upper_margin), &(base->lower_margin), |
&base->left_margin, &base->right_margin, |
289 |
&(base->hsync_len), &(base->vsync_len)); |
&base->upper_margin, &base->lower_margin, |
290 |
|
&base->hsync_len, &base->vsync_len); |
291 |
|
} else { |
292 |
|
int base_pixclock; |
293 |
|
int base_left_margin, base_right_margin; |
294 |
|
int base_upper_margin, base_lower_margin; |
295 |
|
int base_hsync_len, base_vsync_len; |
296 |
|
sscanf(p, "%d %d %d %d %d %d %d", |
297 |
|
&base_pixclock, |
298 |
|
&base_left_margin, &base_right_margin, |
299 |
|
&base_upper_margin, &base_lower_margin, |
300 |
|
&base_hsync_len, &base_vsync_len); |
301 |
|
base->pixclock = base_pixclock; |
302 |
|
base->left_margin = base_left_margin; |
303 |
|
base->right_margin = base_right_margin; |
304 |
|
base->upper_margin = base_upper_margin; |
305 |
|
base->lower_margin = base_lower_margin; |
306 |
|
base->hsync_len = base_hsync_len; |
307 |
|
base->vsync_len = base_vsync_len; |
308 |
|
} |
309 |
//bb_info_msg("TIM[%s]", p); |
//bb_info_msg("TIM[%s]", p); |
310 |
break; |
break; |
311 |
case 2: |
case 2: |
333 |
} |
} |
334 |
#endif |
#endif |
335 |
|
|
336 |
static void setmode(struct fb_var_screeninfo *base, |
static NOINLINE void showmode(struct fb_var_screeninfo *v) |
|
struct fb_var_screeninfo *set) |
|
|
{ |
|
|
if ((int32_t) set->xres > 0) |
|
|
base->xres = set->xres; |
|
|
if ((int32_t) set->yres > 0) |
|
|
base->yres = set->yres; |
|
|
if ((int32_t) set->xres_virtual > 0) |
|
|
base->xres_virtual = set->xres_virtual; |
|
|
if ((int32_t) set->yres_virtual > 0) |
|
|
base->yres_virtual = set->yres_virtual; |
|
|
if ((int32_t) set->bits_per_pixel > 0) |
|
|
base->bits_per_pixel = set->bits_per_pixel; |
|
|
} |
|
|
|
|
|
static void showmode(struct fb_var_screeninfo *v) |
|
337 |
{ |
{ |
338 |
double drate = 0, hrate = 0, vrate = 0; |
double drate = 0, hrate = 0, vrate = 0; |
339 |
|
|
368 |
{ |
{ |
369 |
enum { |
enum { |
370 |
OPT_CHANGE = (1 << 0), |
OPT_CHANGE = (1 << 0), |
371 |
/*OPT_INFO = (1 << 1), ??*/ |
OPT_SHOW = (1 << 1), |
372 |
OPT_READMODE = (1 << 2), |
OPT_READMODE = (1 << 2), |
373 |
OPT_ALL = (1 << 9), |
OPT_ALL = (1 << 9), |
374 |
}; |
}; |
375 |
struct fb_var_screeninfo var, varset; |
struct fb_var_screeninfo var_old, var_set; |
376 |
int fh, i; |
int fh, i; |
377 |
unsigned options = 0; |
unsigned options = 0; |
378 |
|
|
379 |
const char *fbdev = DEFAULTFBDEV; |
const char *fbdev = DEFAULTFBDEV; |
380 |
const char *modefile = DEFAULTFBMODE; |
const char *modefile = DEFAULTFBMODE; |
381 |
char *thisarg, *mode = NULL; |
char *thisarg; |
382 |
|
char *mode = mode; /* for compiler */ |
383 |
|
|
384 |
memset(&varset, 0xff, sizeof(varset)); |
memset(&var_set, 0xff, sizeof(var_set)); /* set all to -1 */ |
385 |
|
|
386 |
/* parse cmd args.... why do they have to make things so difficult? */ |
/* parse cmd args.... why do they have to make things so difficult? */ |
387 |
argv++; |
argv++; |
400 |
case CMD_DB: |
case CMD_DB: |
401 |
modefile = argv[1]; |
modefile = argv[1]; |
402 |
break; |
break; |
403 |
|
case CMD_ALL: |
404 |
|
options |= OPT_ALL; |
405 |
|
break; |
406 |
|
case CMD_SHOW: |
407 |
|
options |= OPT_SHOW; |
408 |
|
break; |
409 |
case CMD_GEOMETRY: |
case CMD_GEOMETRY: |
410 |
varset.xres = xatou32(argv[1]); |
var_set.xres = xatou32(argv[1]); |
411 |
varset.yres = xatou32(argv[2]); |
var_set.yres = xatou32(argv[2]); |
412 |
varset.xres_virtual = xatou32(argv[3]); |
var_set.xres_virtual = xatou32(argv[3]); |
413 |
varset.yres_virtual = xatou32(argv[4]); |
var_set.yres_virtual = xatou32(argv[4]); |
414 |
varset.bits_per_pixel = xatou32(argv[5]); |
var_set.bits_per_pixel = xatou32(argv[5]); |
415 |
break; |
break; |
416 |
case CMD_TIMING: |
case CMD_TIMING: |
417 |
varset.pixclock = xatou32(argv[1]); |
var_set.pixclock = xatou32(argv[1]); |
418 |
varset.left_margin = xatou32(argv[2]); |
var_set.left_margin = xatou32(argv[2]); |
419 |
varset.right_margin = xatou32(argv[3]); |
var_set.right_margin = xatou32(argv[3]); |
420 |
varset.upper_margin = xatou32(argv[4]); |
var_set.upper_margin = xatou32(argv[4]); |
421 |
varset.lower_margin = xatou32(argv[5]); |
var_set.lower_margin = xatou32(argv[5]); |
422 |
varset.hsync_len = xatou32(argv[6]); |
var_set.hsync_len = xatou32(argv[6]); |
423 |
varset.vsync_len = xatou32(argv[7]); |
var_set.vsync_len = xatou32(argv[7]); |
424 |
break; |
break; |
425 |
case CMD_ALL: |
case CMD_ACCEL: |
|
options |= OPT_ALL; |
|
426 |
break; |
break; |
427 |
case CMD_CHANGE: |
case CMD_HSYNC: |
428 |
options |= OPT_CHANGE; |
var_set.sync |= FB_SYNC_HOR_HIGH_ACT; |
429 |
|
break; |
430 |
|
case CMD_VSYNC: |
431 |
|
var_set.sync |= FB_SYNC_VERT_HIGH_ACT; |
432 |
break; |
break; |
433 |
#if ENABLE_FEATURE_FBSET_FANCY |
#if ENABLE_FEATURE_FBSET_FANCY |
434 |
case CMD_XRES: |
case CMD_XRES: |
435 |
varset.xres = xatou32(argv[1]); |
var_set.xres = xatou32(argv[1]); |
436 |
break; |
break; |
437 |
case CMD_YRES: |
case CMD_YRES: |
438 |
varset.yres = xatou32(argv[1]); |
var_set.yres = xatou32(argv[1]); |
439 |
break; |
break; |
440 |
case CMD_DEPTH: |
case CMD_DEPTH: |
441 |
varset.bits_per_pixel = xatou32(argv[1]); |
var_set.bits_per_pixel = xatou32(argv[1]); |
442 |
break; |
break; |
443 |
#endif |
#endif |
444 |
} |
} |
445 |
|
switch (g_cmdoptions[i].code) { |
446 |
|
case CMD_FB: |
447 |
|
case CMD_DB: |
448 |
|
case CMD_ALL: |
449 |
|
case CMD_SHOW: |
450 |
|
break; |
451 |
|
default: |
452 |
|
/* other commands imply changes */ |
453 |
|
options |= OPT_CHANGE; |
454 |
|
} |
455 |
argc -= g_cmdoptions[i].param_count; |
argc -= g_cmdoptions[i].param_count; |
456 |
argv += g_cmdoptions[i].param_count; |
argv += g_cmdoptions[i].param_count; |
457 |
goto contin; |
goto contin; |
458 |
} |
} |
459 |
if (argc != 1) |
if (!ENABLE_FEATURE_FBSET_READMODE || argc != 1) |
460 |
bb_show_usage(); |
bb_show_usage(); |
461 |
mode = *argv; |
mode = *argv; |
462 |
options |= OPT_READMODE; |
options |= OPT_READMODE; |
464 |
} |
} |
465 |
|
|
466 |
fh = xopen(fbdev, O_RDONLY); |
fh = xopen(fbdev, O_RDONLY); |
467 |
xioctl(fh, FBIOGET_VSCREENINFO, &var); |
xioctl(fh, FBIOGET_VSCREENINFO, &var_old); |
468 |
|
|
469 |
if (options & OPT_READMODE) { |
if (options & OPT_READMODE) { |
470 |
#if !ENABLE_FEATURE_FBSET_READMODE |
#if ENABLE_FEATURE_FBSET_READMODE |
471 |
bb_show_usage(); |
if (!read_mode_db(&var_old, modefile, mode)) { |
|
#else |
|
|
if (!readmode(&var, modefile, mode)) { |
|
472 |
bb_error_msg_and_die("unknown video mode '%s'", mode); |
bb_error_msg_and_die("unknown video mode '%s'", mode); |
473 |
} |
} |
474 |
#endif |
#endif |
475 |
} |
} |
476 |
|
|
|
setmode(&var, &varset); |
|
477 |
if (options & OPT_CHANGE) { |
if (options & OPT_CHANGE) { |
478 |
|
copy_changed_values(&var_old, &var_set); |
479 |
if (options & OPT_ALL) |
if (options & OPT_ALL) |
480 |
var.activate = FB_ACTIVATE_ALL; |
var_old.activate = FB_ACTIVATE_ALL; |
481 |
xioctl(fh, FBIOPUT_VSCREENINFO, &var); |
xioctl(fh, FBIOPUT_VSCREENINFO, &var_old); |
482 |
} |
} |
483 |
showmode(&var); |
|
484 |
/* Don't close the file, as exiting will take care of that */ |
if (options == 0 || (options & OPT_SHOW)) |
485 |
/* close(fh); */ |
showmode(&var_old); |
486 |
|
|
487 |
|
if (ENABLE_FEATURE_CLEAN_UP) |
488 |
|
close(fh); |
489 |
|
|
490 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
491 |
} |
} |