Bump to version 1.22.1
[platform/upstream/busybox.git] / miscutils / fbsplash.c
index 04d583d..12a77b7 100644 (file)
@@ -50,6 +50,10 @@ struct globals {
        struct fb_var_screeninfo scr_var;
        struct fb_fix_screeninfo scr_fix;
        unsigned bytes_per_pixel;
+       // cached (8 - scr_var.COLOR.length):
+       unsigned red_shift;
+       unsigned green_shift;
+       unsigned blue_shift;
 };
 #define G (*ptr_to_globals)
 #define INIT_G() do { \
@@ -139,11 +143,14 @@ static void fb_open(const char *strfb_device)
                break;
        }
 
+       G.red_shift   = 8 - G.scr_var.red.length;
+       G.green_shift = 8 - G.scr_var.green.length;
+       G.blue_shift  = 8 - G.scr_var.blue.length;
        G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3;
 
        // map the device in memory
        G.addr = mmap(NULL,
-                       G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel,
+                       G.scr_var.yres * G.scr_fix.line_length,
                        PROT_WRITE, MAP_SHARED, fbfd, 0);
        if (G.addr == MAP_FAILED)
                bb_perror_msg_and_die("mmap");
@@ -155,10 +162,13 @@ static void fb_open(const char *strfb_device)
 
 
 /**
- * Return pixel value of the passed RGB color
+ * Return pixel value of the passed RGB color.
+ * This is performance critical fn.
  */
 static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
 {
+       /* We assume that the r,g,b values are <= 255 */
+
        if (G.bytes_per_pixel == 1) {
                r = r        & 0xe0; // 3-bit red
                g = (g >> 3) & 0x1c; // 3-bit green
@@ -166,10 +176,17 @@ static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
                return r + g + b;
        }
        if (G.bytes_per_pixel == 2) {
-               r = (r & 0xf8) << 8; // 5-bit red
-               g = (g & 0xfc) << 3; // 6-bit green
-               b =  b >> 3;         // 5-bit blue
-               return r + g + b;
+               // ARM PL110 on Integrator/CP has RGBA5551 bit arrangement.
+               // We want to support bit locations like that.
+               //
+               // First shift out unused bits
+               r = r >> G.red_shift;
+               g = g >> G.green_shift;
+               b = b >> G.blue_shift;
+               // Then shift the remaining bits to their offset
+               return (r << G.scr_var.red.offset) +
+                       (g << G.scr_var.green.offset) +
+                       (b << G.scr_var.blue.offset);
        }
        // RGB 888
        return b + (g << 8) + (r << 16);
@@ -213,8 +230,8 @@ static void fb_drawrectangle(void)
        thispix = fb_pixel_value(nred, ngreen, nblue);
 
        // horizontal lines
-       ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
-       ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
+       ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
+       ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
        cnt = G.nbar_width - 1;
        do {
                fb_write_pixel(ptr1, thispix);
@@ -224,14 +241,14 @@ static void fb_drawrectangle(void)
        } while (--cnt >= 0);
 
        // vertical lines
-       ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel;
-       ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel;
+       ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
+       ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel;
        cnt = G.nbar_height - 1;
        do {
                fb_write_pixel(ptr1, thispix);
                fb_write_pixel(ptr2, thispix);
-               ptr1 += G.scr_var.xres * G.bytes_per_pixel;
-               ptr2 += G.scr_var.xres * G.bytes_per_pixel;
+               ptr1 += G.scr_fix.line_length;
+               ptr2 += G.scr_fix.line_length;
        } while (--cnt >= 0);
 }
 
@@ -254,7 +271,7 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
        cnt1 = ny2pos - ny1pos;
        nypos = ny1pos;
        do {
-               ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel;
+               ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel;
                cnt2 = nx2pos - nx1pos;
                do {
                        fb_write_pixel(ptr, thispix);
@@ -295,8 +312,7 @@ static void fb_drawprogressbar(unsigned percent)
 
        pos_x = left_x;
        if (percent > 0) {
-               int y;
-               unsigned i;
+               int i, y;
 
                // actual progress bar
                pos_x += (unsigned)(width * percent) / 100;
@@ -308,7 +324,7 @@ static void fb_drawprogressbar(unsigned percent)
                while (i >= 0) {
                        // draw one-line thick "rectangle"
                        // top line will have gray lvl 200, bottom one 100
-                       unsigned gray_level = 100 + i*100 / height;
+                       unsigned gray_level = 100 + (unsigned)i*100 / height;
                        fb_drawfullrectangle(
                                        left_x, y, pos_x, y,
                                        gray_level, gray_level, gray_level);