2 * pslash - a lightweight framebuffer splashscreen for embedded devices.
4 * Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
20 psplash_fb_destroy (PSplashFB *fb)
29 attempt_to_change_pixel_format (PSplashFB *fb,
30 struct fb_var_screeninfo *fb_var)
32 /* By default the framebuffer driver may have set an oversized
33 * yres_virtual to support VT scrolling via the panning interface.
35 * We don't try and maintain this since it's more likely that we
36 * will fail to increase the bpp if the driver's pre allocated
37 * framebuffer isn't large enough.
39 fb_var->yres_virtual = fb_var->yres;
41 /* First try setting an 8,8,8,0 pixel format so we don't have to do
42 * any conversions while drawing. */
44 fb_var->bits_per_pixel = 32;
46 fb_var->red.offset = 0;
47 fb_var->red.length = 8;
49 fb_var->green.offset = 8;
50 fb_var->green.length = 8;
52 fb_var->blue.offset = 16;
53 fb_var->blue.length = 8;
55 fb_var->transp.offset = 0;
56 fb_var->transp.length = 0;
58 if (ioctl (fb->fd, FBIOPUT_VSCREENINFO, fb_var) == 0)
60 fprintf(stdout, "Switched to a 32 bpp 8,8,8 frame buffer\n");
66 "Error, failed to switch to a 32 bpp 8,8,8 frame buffer\n");
69 /* Otherwise try a 16bpp 5,6,5 format */
71 fb_var->bits_per_pixel = 16;
73 fb_var->red.offset = 11;
74 fb_var->red.length = 5;
76 fb_var->green.offset = 5;
77 fb_var->green.length = 6;
79 fb_var->blue.offset = 0;
80 fb_var->blue.length = 5;
82 fb_var->transp.offset = 0;
83 fb_var->transp.length = 0;
85 if (ioctl (fb->fd, FBIOPUT_VSCREENINFO, fb_var) == 0)
87 fprintf(stdout, "Switched to a 16 bpp 5,6,5 frame buffer\n");
93 "Error, failed to switch to a 16 bpp 5,6,5 frame buffer\n");
100 psplash_fb_new (int angle)
102 struct fb_var_screeninfo fb_var;
103 struct fb_fix_screeninfo fb_fix;
107 PSplashFB *fb = NULL;
109 fbdev = getenv("FBDEV");
113 if ((fb = malloc (sizeof(PSplashFB))) == NULL)
115 perror ("Error no memory");
119 memset (fb, 0, sizeof(PSplashFB));
123 if ((fb->fd = open (fbdev, O_RDWR)) < 0)
125 perror ("Error opening /dev/fb0");
129 if (ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
131 perror ("Error getting variable framebuffer info");
135 if (fb_var.bits_per_pixel < 16)
138 "Error, no support currently for %i bpp frame buffers\n"
139 "Trying to change pixel format...\n",
140 fb_var.bits_per_pixel);
141 if (!attempt_to_change_pixel_format (fb, &fb_var))
145 if (ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
147 perror ("Error getting variable framebuffer info (2)");
151 /* NB: It looks like the fbdev concept of fixed vs variable screen info is
152 * broken. The line_length is part of the fixed info but it can be changed
153 * if you set a new pixel format. */
154 if (ioctl (fb->fd, FBIOGET_FSCREENINFO, &fb_fix) == -1)
156 perror ("Error getting fixed framebuffer info");
160 fb->real_width = fb->width = fb_var.xres;
161 fb->real_height = fb->height = fb_var.yres;
162 fb->bpp = fb_var.bits_per_pixel;
163 fb->stride = fb_fix.line_length;
164 fb->type = fb_fix.type;
165 fb->visual = fb_fix.visual;
167 fb->red_offset = fb_var.red.offset;
168 fb->red_length = fb_var.red.length;
169 fb->green_offset = fb_var.green.offset;
170 fb->green_length = fb_var.green.length;
171 fb->blue_offset = fb_var.blue.offset;
172 fb->blue_length = fb_var.blue.length;
174 if (fb->red_offset == 11 && fb->red_length == 5 &&
175 fb->green_offset == 5 && fb->green_length == 6 &&
176 fb->blue_offset == 0 && fb->blue_length == 5) {
177 fb->rgbmode = RGB565;
178 } else if (fb->red_offset == 0 && fb->red_length == 5 &&
179 fb->green_offset == 5 && fb->green_length == 6 &&
180 fb->blue_offset == 11 && fb->blue_length == 5) {
181 fb->rgbmode = BGR565;
182 } else if (fb->red_offset == 16 && fb->red_length == 8 &&
183 fb->green_offset == 8 && fb->green_length == 8 &&
184 fb->blue_offset == 0 && fb->blue_length == 8) {
185 fb->rgbmode = RGB888;
186 } else if (fb->red_offset == 0 && fb->red_length == 8 &&
187 fb->green_offset == 8 && fb->green_length == 8 &&
188 fb->blue_offset == 8 && fb->blue_length == 8) {
189 fb->rgbmode = BGR888;
191 fb->rgbmode = GENERIC;
194 DBG("width: %i, height: %i, bpp: %i, stride: %i",
195 fb->width, fb->height, fb->bpp, fb->stride);
197 fb->base = (char *) mmap ((caddr_t) NULL,
199 fb->stride * fb->height,
200 PROT_READ|PROT_WRITE,
204 if (fb->base == (char *)-1)
206 perror("Error cannot mmap framebuffer ");
210 off = (unsigned long) fb_fix.smem_start % (unsigned long) getpagesize();
212 fb->data = fb->base + off;
215 /* FIXME: No support for 8pp as yet */
216 if (visual == FB_VISUAL_PSEUDOCOLOR
217 || visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
219 static struct fb_cmap cmap;
223 cmap.red = saved_red;
224 cmap.green = saved_green;
225 cmap.blue = saved_blue;
228 ioctl (fb, FBIOGETCMAP, &cmap);
242 fb->width = fb->real_height;
243 fb->height = fb->real_width;
256 psplash_fb_destroy (fb);
261 #define OFFSET(fb,x,y) (((y) * (fb)->stride) + ((x) * ((fb)->bpp >> 3)))
264 psplash_fb_plot_pixel (PSplashFB *fb,
273 if (x < 0 || x > fb->width-1 || y < 0 || y > fb->height-1)
279 off = OFFSET (fb, fb->height - y - 1, x);
282 off = OFFSET (fb, fb->width - x - 1, fb->height - y - 1);
285 off = OFFSET (fb, y, fb->width - x - 1);
289 off = OFFSET (fb, x, y);
293 if (fb->rgbmode == RGB565 || fb->rgbmode == RGB888) {
298 *(fb->data + off) = blue;
299 *(fb->data + off + 1) = green;
300 *(fb->data + off + 2) = red;
303 *(volatile uint16_t *) (fb->data + off)
304 = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
307 /* depth not supported yet */
310 } else if (fb->rgbmode == BGR565 || fb->rgbmode == BGR888) {
315 *(fb->data + off) = red;
316 *(fb->data + off + 1) = green;
317 *(fb->data + off + 2) = blue;
320 *(volatile uint16_t *) (fb->data + off)
321 = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3);
324 /* depth not supported yet */
331 *(volatile uint32_t *) (fb->data + off)
332 = ((red >> (8 - fb->red_length)) << fb->red_offset)
333 | ((green >> (8 - fb->green_length)) << fb->green_offset)
334 | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
337 *(volatile uint16_t *) (fb->data + off)
338 = ((red >> (8 - fb->red_length)) << fb->red_offset)
339 | ((green >> (8 - fb->green_length)) << fb->green_offset)
340 | ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
343 /* depth not supported yet */
350 psplash_fb_draw_rect (PSplashFB *fb,
361 for (dy=0; dy < height; dy++)
362 for (dx=0; dx < width; dx++)
363 psplash_fb_plot_pixel (fb, x+dx, y+dy, red, green, blue);
367 psplash_fb_draw_image (PSplashFB *fb,
372 int img_bytes_per_pixel,
376 int dx = 0, dy = 0, total_len;
379 total_len = img_width * img_height * img_bytes_per_pixel;
381 /* FIXME: Optimise, check for over runs ... */
382 while ((p - rle_data) < total_len)
394 if (img_bytes_per_pixel < 4 || *(p+3))
395 psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
396 if (++dx >= img_width) { dx=0; dy++; }
398 while (--len && (p - rle_data) < total_len);
400 p += img_bytes_per_pixel;
408 if (img_bytes_per_pixel < 4 || *(p+3))
409 psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
410 if (++dx >= img_width) { dx=0; dy++; }
411 p += img_bytes_per_pixel;
413 while (--len && (p - rle_data) < total_len);
418 /* Font rendering code based on BOGL by Ben Pfaff */
421 psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap)
423 int mask = font->index_mask;
428 for (i = font->offset[wc & mask]; font->index[i]; i += 2)
430 if ((font->index[i] & ~mask) == (wc & ~mask))
433 *bitmap = &font->content[font->index[i+1]];
434 return font->index[i] & mask;
442 psplash_fb_text_size (PSplashFB *fb,
445 const PSplashFont *font,
448 char *c = (char*)text;
456 for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
466 w += psplash_font_glyph (font, wc, NULL);
469 *width = (w > mw) ? w : mw;
470 *height = (h == 0) ? font->height : h;
474 psplash_fb_draw_text (PSplashFB *fb,
480 const PSplashFont *font,
483 int h, w, k, n, cx, cy, dx, dy;
484 char *c = (char*)text;
492 for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
494 u_int32_t *glyph = NULL;
503 w = psplash_font_glyph (font, wc, &glyph);
508 for (cy = 0; cy < h; cy++)
510 u_int32_t g = *glyph++;
512 for (cx = 0; cx < w; cx++)
515 psplash_fb_plot_pixel (fb, x+dx+cx, y+dy+cy,