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 { \
#define DEBUG_MESSAGE(...) ((void)0)
#endif
+/**
+ * Configure palette for RGB:332
+ */
+static void fb_setpal(int fd)
+{
+ struct fb_cmap cmap;
+ /* fb colors are 16 bit */
+ unsigned short red[256], green[256], blue[256];
+ unsigned i;
+
+ /* RGB:332 */
+ for (i = 0; i < 256; i++) {
+ /* Color is encoded in pixel value as rrrgggbb.
+ * 3-bit color is mapped to 16-bit one as:
+ * 000 -> 00000000 00000000
+ * 001 -> 00100100 10010010
+ * ...
+ * 011 -> 01101101 10110110
+ * 100 -> 10010010 01001001
+ * ...
+ * 111 -> 11111111 11111111
+ */
+ red[i] = (( i >> 5 ) * 0x9249) >> 2; // rrr * 00 10010010 01001001 >> 2
+ green[i] = (((i >> 2) & 0x7) * 0x9249) >> 2; // ggg * 00 10010010 01001001 >> 2
+ /* 2-bit color is easier: */
+ blue[i] = ( i & 0x3) * 0x5555; // bb * 01010101 01010101
+ }
+
+ cmap.start = 0;
+ cmap.len = 256;
+ cmap.red = red;
+ cmap.green = green;
+ cmap.blue = blue;
+ cmap.transp = 0;
+
+ xioctl(fd, FBIOPUTCMAP, &cmap);
+}
/**
* Open and initialize the framebuffer device
xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
- if (G.scr_var.bits_per_pixel < 16 || G.scr_var.bits_per_pixel > 32)
+ switch (G.scr_var.bits_per_pixel) {
+ case 8:
+ fb_setpal(fbfd);
+ break;
+
+ case 16:
+ case 24:
+ case 32:
+ break;
+
+ default:
bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel);
+ 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");
/**
- * 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
+ b = b >> 6; // 2-bit blue
+ return r + g + b;
+ }
if (G.bytes_per_pixel == 2) {
- r >>= 3; // 5-bit red
- g >>= 2; // 6-bit green
- b >>= 3; // 5-bit blue
- return b + (g << 5) + (r << (5+6));
+ // 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);
static void fb_write_pixel(unsigned char *addr, unsigned pixel)
{
switch (G.bytes_per_pixel) {
+ case 1:
+ *addr = pixel;
+ break;
case 2:
*(uint16_t *)addr = pixel;
break;
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);
} 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);
}
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);
*/
static void fb_drawprogressbar(unsigned percent)
{
- int i, left_x, top_y, width, height;
+ int left_x, top_y, pos_x;
+ unsigned width, height;
// outer box
left_x = G.nbar_posx;
top_y = G.nbar_posy;
width = G.nbar_width - 1;
height = G.nbar_height - 1;
- if ((height | width) < 0)
+ if ((int)(height | width) < 0)
return;
// NB: "width" of 1 actually makes rect with width of 2!
fb_drawrectangle();
top_y++;
width -= 2;
height -= 2;
- if ((height | width) < 0)
+ if ((int)(height | width) < 0)
return;
- fb_drawfullrectangle(
- left_x, top_y,
- left_x + width, top_y + height,
- G.nbar_colr, G.nbar_colg, G.nbar_colb);
+ pos_x = left_x;
if (percent > 0) {
+ int i, y;
+
// actual progress bar
- width = width * percent / 100;
+ pos_x += (unsigned)(width * percent) / 100;
+
+ y = top_y;
i = height;
if (height == 0)
height++; // divide by 0 is bad
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, top_y, left_x + width, top_y,
+ left_x, y, pos_x, y,
gray_level, gray_level, gray_level);
- top_y++;
+ y++;
i--;
}
}
+
+ fb_drawfullrectangle(
+ pos_x, top_y,
+ left_x + width, top_y + height,
+ G.nbar_colr, G.nbar_colg, G.nbar_colb);
}