diff options
Diffstat (limited to 'miscutils/fbsplash.c')
-rw-r--r-- | miscutils/fbsplash.c | 130 |
1 files changed, 86 insertions, 44 deletions
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 150992343..c761a88ca 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c | |||
@@ -21,16 +21,25 @@ | |||
21 | * "exit" (or just close fifo) - well you guessed it. | 21 | * "exit" (or just close fifo) - well you guessed it. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | //usage:#define fbsplash_trivial_usage | ||
25 | //usage: "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" | ||
26 | //usage:#define fbsplash_full_usage "\n\n" | ||
27 | //usage: "Options:" | ||
28 | //usage: "\n -s Image" | ||
29 | //usage: "\n -c Hide cursor" | ||
30 | //usage: "\n -d Framebuffer device (default /dev/fb0)" | ||
31 | //usage: "\n -i Config file (var=value):" | ||
32 | //usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" | ||
33 | //usage: "\n BAR_R,BAR_G,BAR_B" | ||
34 | //usage: "\n -f Control pipe (else exit after drawing image)" | ||
35 | //usage: "\n commands: 'NN' (% for progress bar) or 'exit'" | ||
36 | |||
24 | #include "libbb.h" | 37 | #include "libbb.h" |
25 | #include <linux/fb.h> | 38 | #include <linux/fb.h> |
26 | 39 | ||
27 | /* If you want logging messages on /tmp/fbsplash.log... */ | 40 | /* If you want logging messages on /tmp/fbsplash.log... */ |
28 | #define DEBUG 0 | 41 | #define DEBUG 0 |
29 | 42 | ||
30 | #define BYTES_PER_PIXEL 2 | ||
31 | |||
32 | typedef unsigned short DATA; | ||
33 | |||
34 | struct globals { | 43 | struct globals { |
35 | #if DEBUG | 44 | #if DEBUG |
36 | bool bdebug_messages; // enable/disable logging | 45 | bool bdebug_messages; // enable/disable logging |
@@ -41,6 +50,7 @@ struct globals { | |||
41 | const char *image_filename; | 50 | const char *image_filename; |
42 | struct fb_var_screeninfo scr_var; | 51 | struct fb_var_screeninfo scr_var; |
43 | struct fb_fix_screeninfo scr_fix; | 52 | struct fb_fix_screeninfo scr_fix; |
53 | unsigned bytes_per_pixel; | ||
44 | }; | 54 | }; |
45 | #define G (*ptr_to_globals) | 55 | #define G (*ptr_to_globals) |
46 | #define INIT_G() do { \ | 56 | #define INIT_G() do { \ |
@@ -67,7 +77,7 @@ struct globals { | |||
67 | 77 | ||
68 | 78 | ||
69 | /** | 79 | /** |
70 | * Open and initialize the framebuffer device | 80 | * Open and initialize the framebuffer device |
71 | * \param *strfb_device pointer to framebuffer device | 81 | * \param *strfb_device pointer to framebuffer device |
72 | */ | 82 | */ |
73 | static void fb_open(const char *strfb_device) | 83 | static void fb_open(const char *strfb_device) |
@@ -78,62 +88,98 @@ static void fb_open(const char *strfb_device) | |||
78 | xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var); | 88 | xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var); |
79 | xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix); | 89 | xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix); |
80 | 90 | ||
81 | if (G.scr_var.bits_per_pixel != 16) | 91 | if (G.scr_var.bits_per_pixel < 16 || G.scr_var.bits_per_pixel > 32) |
82 | bb_error_msg_and_die("only 16 bpp is supported"); | 92 | bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel); |
93 | G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; | ||
83 | 94 | ||
84 | // map the device in memory | 95 | // map the device in memory |
85 | G.addr = mmap(NULL, | 96 | G.addr = mmap(NULL, |
86 | G.scr_var.xres * G.scr_var.yres_virtual | 97 | G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel, |
87 | * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/, | ||
88 | PROT_WRITE, MAP_SHARED, fbfd, 0); | 98 | PROT_WRITE, MAP_SHARED, fbfd, 0); |
89 | if (G.addr == MAP_FAILED) | 99 | if (G.addr == MAP_FAILED) |
90 | bb_perror_msg_and_die("mmap"); | 100 | bb_perror_msg_and_die("mmap"); |
91 | 101 | ||
92 | // point to the start of the visible screen | 102 | // point to the start of the visible screen |
93 | G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * BYTES_PER_PIXEL; | 103 | G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel; |
94 | close(fbfd); | 104 | close(fbfd); |
95 | } | 105 | } |
96 | 106 | ||
97 | 107 | ||
98 | /** | 108 | /** |
99 | * Draw hollow rectangle on framebuffer | 109 | * Return pixel value of the passed RGB color |
110 | */ | ||
111 | static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b) | ||
112 | { | ||
113 | if (G.bytes_per_pixel == 2) { | ||
114 | r >>= 3; // 5-bit red | ||
115 | g >>= 2; // 6-bit green | ||
116 | b >>= 3; // 5-bit blue | ||
117 | return b + (g << 5) + (r << (5+6)); | ||
118 | } | ||
119 | // RGB 888 | ||
120 | return b + (g << 8) + (r << 16); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * Draw pixel on framebuffer | ||
125 | */ | ||
126 | static void fb_write_pixel(unsigned char *addr, unsigned pixel) | ||
127 | { | ||
128 | switch (G.bytes_per_pixel) { | ||
129 | case 2: | ||
130 | *(uint16_t *)addr = pixel; | ||
131 | break; | ||
132 | case 4: | ||
133 | *(uint32_t *)addr = pixel; | ||
134 | break; | ||
135 | default: // 24 bits per pixel | ||
136 | addr[0] = pixel; | ||
137 | addr[1] = pixel >> 8; | ||
138 | addr[2] = pixel >> 16; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Draw hollow rectangle on framebuffer | ||
100 | */ | 145 | */ |
101 | static void fb_drawrectangle(void) | 146 | static void fb_drawrectangle(void) |
102 | { | 147 | { |
103 | int cnt; | 148 | int cnt; |
104 | DATA thispix; | 149 | unsigned thispix; |
105 | DATA *ptr1, *ptr2; | 150 | unsigned char *ptr1, *ptr2; |
106 | unsigned char nred = G.nbar_colr/2; | 151 | unsigned char nred = G.nbar_colr/2; |
107 | unsigned char ngreen = G.nbar_colg/2; | 152 | unsigned char ngreen = G.nbar_colg/2; |
108 | unsigned char nblue = G.nbar_colb/2; | 153 | unsigned char nblue = G.nbar_colb/2; |
109 | 154 | ||
110 | nred >>= 3; // 5-bit red | 155 | thispix = fb_pixel_value(nred, ngreen, nblue); |
111 | ngreen >>= 2; // 6-bit green | ||
112 | nblue >>= 3; // 5-bit blue | ||
113 | thispix = nblue + (ngreen << 5) + (nred << (5+6)); | ||
114 | 156 | ||
115 | // horizontal lines | 157 | // horizontal lines |
116 | ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); | 158 | ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
117 | ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); | 159 | ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
118 | cnt = G.nbar_width - 1; | 160 | cnt = G.nbar_width - 1; |
119 | do { | 161 | do { |
120 | *ptr1++ = thispix; | 162 | fb_write_pixel(ptr1, thispix); |
121 | *ptr2++ = thispix; | 163 | fb_write_pixel(ptr2, thispix); |
164 | ptr1 += G.bytes_per_pixel; | ||
165 | ptr2 += G.bytes_per_pixel; | ||
122 | } while (--cnt >= 0); | 166 | } while (--cnt >= 0); |
123 | 167 | ||
124 | // vertical lines | 168 | // vertical lines |
125 | ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); | 169 | ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; |
126 | ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL); | 170 | ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; |
127 | cnt = G.nbar_height - 1; | 171 | cnt = G.nbar_height - 1; |
128 | do { | 172 | do { |
129 | *ptr1 = thispix; ptr1 += G.scr_var.xres; | 173 | fb_write_pixel(ptr1, thispix); |
130 | *ptr2 = thispix; ptr2 += G.scr_var.xres; | 174 | fb_write_pixel(ptr2, thispix); |
175 | ptr1 += G.scr_var.xres * G.bytes_per_pixel; | ||
176 | ptr2 += G.scr_var.xres * G.bytes_per_pixel; | ||
131 | } while (--cnt >= 0); | 177 | } while (--cnt >= 0); |
132 | } | 178 | } |
133 | 179 | ||
134 | 180 | ||
135 | /** | 181 | /** |
136 | * Draw filled rectangle on framebuffer | 182 | * Draw filled rectangle on framebuffer |
137 | * \param nx1pos,ny1pos upper left position | 183 | * \param nx1pos,ny1pos upper left position |
138 | * \param nx2pos,ny2pos down right position | 184 | * \param nx2pos,ny2pos down right position |
139 | * \param nred,ngreen,nblue rgb color | 185 | * \param nred,ngreen,nblue rgb color |
@@ -142,21 +188,19 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, | |||
142 | unsigned char nred, unsigned char ngreen, unsigned char nblue) | 188 | unsigned char nred, unsigned char ngreen, unsigned char nblue) |
143 | { | 189 | { |
144 | int cnt1, cnt2, nypos; | 190 | int cnt1, cnt2, nypos; |
145 | DATA thispix; | 191 | unsigned thispix; |
146 | DATA *ptr; | 192 | unsigned char *ptr; |
147 | 193 | ||
148 | nred >>= 3; // 5-bit red | 194 | thispix = fb_pixel_value(nred, ngreen, nblue); |
149 | ngreen >>= 2; // 6-bit green | ||
150 | nblue >>= 3; // 5-bit blue | ||
151 | thispix = nblue + (ngreen << 5) + (nred << (5+6)); | ||
152 | 195 | ||
153 | cnt1 = ny2pos - ny1pos; | 196 | cnt1 = ny2pos - ny1pos; |
154 | nypos = ny1pos; | 197 | nypos = ny1pos; |
155 | do { | 198 | do { |
156 | ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL); | 199 | ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel; |
157 | cnt2 = nx2pos - nx1pos; | 200 | cnt2 = nx2pos - nx1pos; |
158 | do { | 201 | do { |
159 | *ptr++ = thispix; | 202 | fb_write_pixel(ptr, thispix); |
203 | ptr += G.bytes_per_pixel; | ||
160 | } while (--cnt2 >= 0); | 204 | } while (--cnt2 >= 0); |
161 | 205 | ||
162 | nypos++; | 206 | nypos++; |
@@ -165,7 +209,7 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, | |||
165 | 209 | ||
166 | 210 | ||
167 | /** | 211 | /** |
168 | * Draw a progress bar on framebuffer | 212 | * Draw a progress bar on framebuffer |
169 | * \param percent percentage of loading | 213 | * \param percent percentage of loading |
170 | */ | 214 | */ |
171 | static void fb_drawprogressbar(unsigned percent) | 215 | static void fb_drawprogressbar(unsigned percent) |
@@ -215,7 +259,7 @@ static void fb_drawprogressbar(unsigned percent) | |||
215 | 259 | ||
216 | 260 | ||
217 | /** | 261 | /** |
218 | * Draw image from PPM file | 262 | * Draw image from PPM file |
219 | */ | 263 | */ |
220 | static void fb_drawimage(void) | 264 | static void fb_drawimage(void) |
221 | { | 265 | { |
@@ -276,18 +320,16 @@ static void fb_drawimage(void) | |||
276 | height = G.scr_var.yres; | 320 | height = G.scr_var.yres; |
277 | for (j = 0; j < height; j++) { | 321 | for (j = 0; j < height; j++) { |
278 | unsigned char *pixel; | 322 | unsigned char *pixel; |
279 | DATA *src; | 323 | unsigned char *src; |
280 | 324 | ||
281 | if (fread(pixline, 1, line_size, theme_file) != line_size) | 325 | if (fread(pixline, 1, line_size, theme_file) != line_size) |
282 | bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); | 326 | bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); |
283 | pixel = pixline; | 327 | pixel = pixline; |
284 | src = (DATA *)(G.addr + j * G.scr_fix.line_length); | 328 | src = G.addr + j * G.scr_fix.line_length; |
285 | for (i = 0; i < width; i++) { | 329 | for (i = 0; i < width; i++) { |
286 | unsigned thispix; | 330 | unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]); |
287 | thispix = (((unsigned)pixel[0] << 8) & 0xf800) | 331 | fb_write_pixel(src, thispix); |
288 | | (((unsigned)pixel[1] << 3) & 0x07e0) | 332 | src += G.bytes_per_pixel; |
289 | | (((unsigned)pixel[2] >> 3)); | ||
290 | *src++ = thispix; | ||
291 | pixel += 3; | 333 | pixel += 3; |
292 | } | 334 | } |
293 | } | 335 | } |
@@ -297,7 +339,7 @@ static void fb_drawimage(void) | |||
297 | 339 | ||
298 | 340 | ||
299 | /** | 341 | /** |
300 | * Parse configuration file | 342 | * Parse configuration file |
301 | * \param *cfg_filename name of the configuration file | 343 | * \param *cfg_filename name of the configuration file |
302 | */ | 344 | */ |
303 | static void init(const char *cfg_filename) | 345 | static void init(const char *cfg_filename) |