aboutsummaryrefslogtreecommitdiff
path: root/miscutils/fbsplash.c
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils/fbsplash.c')
-rw-r--r--miscutils/fbsplash.c130
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
32typedef unsigned short DATA;
33
34struct globals { 43struct 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 */
73static void fb_open(const char *strfb_device) 83static 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 */
111static 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 */
126static 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 */
101static void fb_drawrectangle(void) 146static 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 */
171static void fb_drawprogressbar(unsigned percent) 215static 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 */
220static void fb_drawimage(void) 264static 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 */
303static void init(const char *cfg_filename) 345static void init(const char *cfg_filename)