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"
21 OPT_CHANGE
= (1 << 0),
23 OPT_READMODE
= (1 << 2),
35 /* CMD_XCOMPAT = 10, */
40 #if ENABLE_FEATURE_FBSET_FANCY
64 static unsigned g_options
;
66 /* Stuff stolen from the kernel's fb.h */
67 #define FB_ACTIVATE_ALL 64
69 FBIOGET_VSCREENINFO
= 0x4600,
70 FBIOPUT_VSCREENINFO
= 0x4601
73 uint32_t offset
; /* beginning of bitfield */
74 uint32_t length
; /* length of bitfield */
75 uint32_t msb_right
; /* !=0: Most significant bit is right */
77 struct fb_var_screeninfo
{
78 uint32_t xres
; /* visible resolution */
80 uint32_t xres_virtual
; /* virtual resolution */
81 uint32_t yres_virtual
;
82 uint32_t xoffset
; /* offset from virtual to visible */
83 uint32_t yoffset
; /* resolution */
85 uint32_t bits_per_pixel
;
86 uint32_t grayscale
; /* !=0 Graylevels instead of colors */
88 struct fb_bitfield red
; /* bitfield in fb mem if true color, */
89 struct fb_bitfield green
; /* else only length is significant */
90 struct fb_bitfield blue
;
91 struct fb_bitfield transp
; /* transparency */
93 uint32_t nonstd
; /* !=0 Non standard pixel format */
95 uint32_t activate
; /* see FB_ACTIVATE_x */
97 uint32_t height
; /* height of picture in mm */
98 uint32_t width
; /* width of picture in mm */
100 uint32_t accel_flags
; /* acceleration flags (hints) */
102 /* Timing: All values in pixclocks, except pixclock (of course) */
103 uint32_t pixclock
; /* pixel clock in ps (pico seconds) */
104 uint32_t left_margin
; /* time from sync to picture */
105 uint32_t right_margin
; /* time from picture to sync */
106 uint32_t upper_margin
; /* time from sync to picture */
107 uint32_t lower_margin
;
108 uint32_t hsync_len
; /* length of horizontal sync */
109 uint32_t vsync_len
; /* length of vertical sync */
110 uint32_t sync
; /* see FB_SYNC_x */
111 uint32_t vmode
; /* see FB_VMODE_x */
112 uint32_t reserved
[6]; /* Reserved for future compatibility */
116 static const struct cmdoptions_t
{
118 const unsigned char param_count
;
119 const unsigned char code
;
121 { "-fb", 1, CMD_FB
},
122 { "-db", 1, CMD_DB
},
123 { "-a", 0, CMD_ALL
},
124 { "-i", 0, CMD_INFO
},
125 { "-g", 5, CMD_GEOMETRY
},
126 { "-t", 7, CMD_TIMING
},
127 { "-accel", 1, CMD_ACCEL
},
128 { "-hsync", 1, CMD_HSYNC
},
129 { "-vsync", 1, CMD_VSYNC
},
130 { "-laced", 1, CMD_LACED
},
131 { "-double", 1, CMD_DOUBLE
},
132 { "-n", 0, CMD_CHANGE
},
133 #if ENABLE_FEATURE_FBSET_FANCY
134 { "-all", 0, CMD_ALL
},
135 { "-xres", 1, CMD_XRES
},
136 { "-yres", 1, CMD_YRES
},
137 { "-vxres", 1, CMD_VXRES
},
138 { "-vyres", 1, CMD_VYRES
},
139 { "-depth", 1, CMD_DEPTH
},
140 { "-match", 0, CMD_MATCH
},
141 { "-geometry", 5, CMD_GEOMETRY
},
142 { "-pixclock", 1, CMD_PIXCLOCK
},
143 { "-left", 1, CMD_LEFT
},
144 { "-right", 1, CMD_RIGHT
},
145 { "-upper", 1, CMD_UPPER
},
146 { "-lower", 1, CMD_LOWER
},
147 { "-hslen", 1, CMD_HSLEN
},
148 { "-vslen", 1, CMD_VSLEN
},
149 { "-timings", 7, CMD_TIMING
},
150 { "-csync", 1, CMD_CSYNC
},
151 { "-gsync", 1, CMD_GSYNC
},
152 { "-extsync", 1, CMD_EXTSYNC
},
153 { "-bcast", 1, CMD_BCAST
},
154 { "-rgba", 1, CMD_RGBA
},
155 { "-step", 1, CMD_STEP
},
156 { "-move", 1, CMD_MOVE
},
161 #if ENABLE_FEATURE_FBSET_READMODE
162 /* taken from linux/fb.h */
164 FB_VMODE_INTERLACED
= 1, /* interlaced */
165 FB_VMODE_DOUBLE
= 2, /* double scan */
166 FB_SYNC_HOR_HIGH_ACT
= 1, /* horizontal sync high active */
167 FB_SYNC_VERT_HIGH_ACT
= 2, /* vertical sync high active */
168 FB_SYNC_EXT
= 4, /* external sync */
169 FB_SYNC_COMP_HIGH_ACT
= 8 /* composite sync high active */
173 static int readmode(struct fb_var_screeninfo
*base
, const char *fn
,
176 #if ENABLE_FEATURE_FBSET_READMODE
183 fgets(buf
, sizeof(buf
), f
);
184 if (!(p
= strstr(buf
, "mode ")) && !(p
= strstr(buf
, "mode\t")))
187 if (!(p
= strstr(buf
, mode
)))
190 if (!isspace(*p
) && (*p
!= 0) && (*p
!= '"')
191 && (*p
!= '\r') && (*p
!= '\n'))
192 continue; /* almost, but not quite */
195 fgets(buf
, sizeof(buf
), f
);
196 if ((p
= strstr(buf
, "geometry "))) {
198 /* FIXME: catastrophic on arches with 64bit ints */
199 sscanf(p
, "%d %d %d %d %d",
200 &(base
->xres
), &(base
->yres
),
201 &(base
->xres_virtual
), &(base
->yres_virtual
),
202 &(base
->bits_per_pixel
));
203 } else if ((p
= strstr(buf
, "timings "))) {
205 sscanf(p
, "%d %d %d %d %d %d %d",
207 &(base
->left_margin
), &(base
->right_margin
),
208 &(base
->upper_margin
), &(base
->lower_margin
),
209 &(base
->hsync_len
), &(base
->vsync_len
));
210 } else if ((p
= strstr(buf
, "laced "))) {
212 if (strstr(buf
, "false")) {
213 base
->vmode
&= ~FB_VMODE_INTERLACED
;
215 base
->vmode
|= FB_VMODE_INTERLACED
;
217 } else if ((p
= strstr(buf
, "double "))) {
219 if (strstr(buf
, "false")) {
220 base
->vmode
&= ~FB_VMODE_DOUBLE
;
222 base
->vmode
|= FB_VMODE_DOUBLE
;
224 } else if ((p
= strstr(buf
, "vsync "))) {
226 if (strstr(buf
, "low")) {
227 base
->sync
&= ~FB_SYNC_VERT_HIGH_ACT
;
229 base
->sync
|= FB_SYNC_VERT_HIGH_ACT
;
231 } else if ((p
= strstr(buf
, "hsync "))) {
233 if (strstr(buf
, "low")) {
234 base
->sync
&= ~FB_SYNC_HOR_HIGH_ACT
;
236 base
->sync
|= FB_SYNC_HOR_HIGH_ACT
;
238 } else if ((p
= strstr(buf
, "csync "))) {
240 if (strstr(buf
, "low")) {
241 base
->sync
&= ~FB_SYNC_COMP_HIGH_ACT
;
243 base
->sync
|= FB_SYNC_COMP_HIGH_ACT
;
245 } else if ((p
= strstr(buf
, "extsync "))) {
247 if (strstr(buf
, "false")) {
248 base
->sync
&= ~FB_SYNC_EXT
;
250 base
->sync
|= FB_SYNC_EXT
;
254 if (strstr(buf
, "endmode"))
259 bb_error_msg("mode reading not compiled in");
264 static inline void setmode(struct fb_var_screeninfo
*base
,
265 struct fb_var_screeninfo
*set
)
267 if ((int) set
->xres
> 0)
268 base
->xres
= set
->xres
;
269 if ((int) set
->yres
> 0)
270 base
->yres
= set
->yres
;
271 if ((int) set
->xres_virtual
> 0)
272 base
->xres_virtual
= set
->xres_virtual
;
273 if ((int) set
->yres_virtual
> 0)
274 base
->yres_virtual
= set
->yres_virtual
;
275 if ((int) set
->bits_per_pixel
> 0)
276 base
->bits_per_pixel
= set
->bits_per_pixel
;
279 static inline void showmode(struct fb_var_screeninfo
*v
)
281 double drate
= 0, hrate
= 0, vrate
= 0;
284 drate
= 1e12
/ v
->pixclock
;
285 hrate
= drate
/ (v
->left_margin
+ v
->xres
+ v
->right_margin
+ v
->hsync_len
);
286 vrate
= hrate
/ (v
->upper_margin
+ v
->yres
+ v
->lower_margin
+ v
->vsync_len
);
288 printf("\nmode \"%ux%u-%u\"\n"
289 #if ENABLE_FEATURE_FBSET_FANCY
290 "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
292 "\tgeometry %u %u %u %u %u\n"
293 "\ttimings %u %u %u %u %u %u %u\n"
295 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
297 v
->xres
, v
->yres
, (int) (vrate
+ 0.5),
298 #if ENABLE_FEATURE_FBSET_FANCY
299 drate
/ 1e6
, hrate
/ 1e3
, vrate
,
301 v
->xres
, v
->yres
, v
->xres_virtual
, v
->yres_virtual
, v
->bits_per_pixel
,
302 v
->pixclock
, v
->left_margin
, v
->right_margin
, v
->upper_margin
, v
->lower_margin
,
303 v
->hsync_len
, v
->vsync_len
,
304 (v
->accel_flags
> 0 ? "true" : "false"),
305 v
->red
.length
, v
->red
.offset
, v
->green
.length
, v
->green
.offset
,
306 v
->blue
.length
, v
->blue
.offset
, v
->transp
.length
, v
->transp
.offset
);
310 int main(int argc
, char **argv
)
312 int fbset_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
313 int fbset_main(int argc
, char **argv
)
316 struct fb_var_screeninfo var
, varset
;
318 const char *fbdev
= DEFAULTFBDEV
;
319 const char *modefile
= DEFAULTFBMODE
;
320 char *thisarg
, *mode
= NULL
;
322 memset(&varset
, 0xFF, sizeof(varset
));
324 /* parse cmd args.... why do they have to make things so difficult? */
327 for (; argc
> 0 && (thisarg
= *argv
); argc
--, argv
++) {
328 for (i
= 0; g_cmdoptions
[i
].name
[0]; i
++) {
329 if (strcmp(thisarg
, g_cmdoptions
[i
].name
))
331 if (argc
-1 < g_cmdoptions
[i
].param_count
)
334 switch (g_cmdoptions
[i
].code
) {
342 varset
.xres
= xatou32(argv
[1]);
343 varset
.yres
= xatou32(argv
[2]);
344 varset
.xres_virtual
= xatou32(argv
[3]);
345 varset
.yres_virtual
= xatou32(argv
[4]);
346 varset
.bits_per_pixel
= xatou32(argv
[5]);
349 varset
.pixclock
= xatou32(argv
[1]);
350 varset
.left_margin
= xatou32(argv
[2]);
351 varset
.right_margin
= xatou32(argv
[3]);
352 varset
.upper_margin
= xatou32(argv
[4]);
353 varset
.lower_margin
= xatou32(argv
[5]);
354 varset
.hsync_len
= xatou32(argv
[6]);
355 varset
.vsync_len
= xatou32(argv
[7]);
358 g_options
|= OPT_ALL
;
361 g_options
|= OPT_CHANGE
;
363 #if ENABLE_FEATURE_FBSET_FANCY
365 varset
.xres
= xatou32(argv
[1]);
368 varset
.yres
= xatou32(argv
[1]);
371 varset
.bits_per_pixel
= xatou32(argv
[1]);
375 argc
-= g_cmdoptions
[i
].param_count
;
376 argv
+= g_cmdoptions
[i
].param_count
;
379 if (!g_cmdoptions
[i
].name
[0]) {
383 g_options
|= OPT_READMODE
;
387 fh
= xopen(fbdev
, O_RDONLY
);
388 xioctl(fh
, FBIOGET_VSCREENINFO
, &var
);
389 if (g_options
& OPT_READMODE
) {
390 if (!readmode(&var
, modefile
, mode
)) {
391 bb_error_msg_and_die("unknown video mode '%s'", mode
);
395 setmode(&var
, &varset
);
396 if (g_options
& OPT_CHANGE
) {
397 if (g_options
& OPT_ALL
)
398 var
.activate
= FB_ACTIVATE_ALL
;
399 xioctl(fh
, FBIOPUT_VSCREENINFO
, &var
);
402 /* Don't close the file, as exiting will take care of that */