5bb110c411ae9b93657f77d7f8bca67796b230a8
[profile/ivi/psplash.git] / psplash-fb.c
1 /* 
2  *  pslash - a lightweight framebuffer splashscreen for embedded devices. 
3  *
4  *  Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
5  *
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)
9  *  any later version.
10  *
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.
15  *
16  */
17 #include "psplash.h"
18
19 void
20 psplash_fb_destroy (PSplashFB *fb)
21 {
22   if (fb->fd >= 0)
23     close (fb->fd);
24
25   free(fb);
26 }
27
28 PSplashFB*
29 psplash_fb_new (void)
30 {
31   struct fb_var_screeninfo fb_var;
32   struct fb_fix_screeninfo fb_fix;
33   int                      off;
34   char                    *fbdev;
35
36   PSplashFB *fb = NULL;
37
38   fbdev = getenv("FBDEV");
39   if (fbdev == NULL)
40     fbdev = "/dev/fb0";
41
42   if ((fb = malloc (sizeof(PSplashFB))) == NULL)
43     {
44       perror ("Error no memory");
45       goto fail;
46     }
47   
48   memset (fb, 0, sizeof(PSplashFB));
49
50   fb->fd = -1;  
51
52   if ((fb->fd = open (fbdev, O_RDWR)) < 0)
53     {
54       perror ("Error opening /dev/fb0");
55       goto fail;
56     }
57
58   if (ioctl (fb->fd, FBIOGET_FSCREENINFO, &fb_fix) == -1
59       || ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
60     {
61       perror ("Error getting framebuffer info");
62       goto fail;
63     }
64   
65   if (fb_var.bits_per_pixel < 16)
66     {
67       fprintf(stderr,
68               "Error, no support currently for %i bpp frame buffers\n",
69               fb_var.bits_per_pixel);
70     }
71
72   fb->width  = fb_var.xres;
73   fb->height = fb_var.yres;
74   fb->bpp    = fb_var.bits_per_pixel;
75   fb->stride = fb_fix.line_length;
76   fb->type   = fb_fix.type;
77   fb->visual = fb_fix.visual;
78
79   DBG("width: %i, height: %i, bpp: %i, stride: %i", 
80       fb->width, fb->height, fb->bpp, fb->stride);
81
82
83   fb->base = (char *) mmap ((caddr_t) NULL,
84                             /*fb_fix.smem_len */
85                             fb->stride * fb->height,
86                             PROT_READ|PROT_WRITE,
87                             MAP_SHARED,
88                             fb->fd, 0);
89     
90   if (fb->base == (char *)-1) 
91     {
92       perror("Error cannot mmap framebuffer ");
93       goto fail;
94     }
95
96   off = (unsigned long) fb_fix.smem_start % (unsigned long) getpagesize();
97
98   fb->data = fb->base + off;
99
100 #if 0
101   /* FIXME: No support for 8pp as yet  */
102   if (visual == FB_VISUAL_PSEUDOCOLOR
103       || visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
104   {
105     static struct fb_cmap cmap;
106
107     cmap.start = 0;
108     cmap.len = 16;
109     cmap.red = saved_red;
110     cmap.green = saved_green;
111     cmap.blue = saved_blue;
112     cmap.transp = NULL;
113
114     ioctl (fb, FBIOGETCMAP, &cmap);
115   }
116   
117   if (!status)
118     atexit (bogl_done);
119   status = 2;
120 #endif
121
122   return fb;
123
124  fail:
125
126   if (fb)
127     psplash_fb_destroy (fb);
128
129   return NULL;
130 }
131
132 void
133 psplash_fb_plot_pixel (PSplashFB    *fb, 
134                        int          x, 
135                        int          y, 
136                        uint8        red,
137                        uint8        green,
138                        uint8        blue)
139 {
140   int off;
141
142   if (x < 0 || x > fb->width-1 || y < 0 || y > fb->height-1)
143     return;
144
145   off = (y * fb->stride) + (x * (fb->bpp >> 3));
146
147   /* FIXME: handle no RGB orderings */
148   switch (fb->bpp)
149     {
150     case 24:
151     case 32:
152       *(fb->data + off)     = red;
153       *(fb->data + off + 1) = green;
154       *(fb->data + off + 2) = blue;
155       break;
156     case 16:
157       *(volatile uint16 *) (fb->data + off) 
158         = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
159       break;
160     default:
161       /* depth not supported yet */
162       break;
163     }
164
165 }
166
167 void
168 psplash_fb_draw_rect (PSplashFB    *fb, 
169                       int          x, 
170                       int          y, 
171                       int          width, 
172                       int          height,
173                       uint8        red,
174                       uint8        green,
175                       uint8        blue)
176 {
177   int dx, dy;
178
179   for (dy=0; dy < height; dy++)   
180     for (dx=0; dx < width; dx++)
181       {
182         /* FIXME: inline this call */
183         psplash_fb_plot_pixel (fb, x+dx, y+dy, red, green, blue); 
184       }
185 }
186
187 void
188 psplash_fb_draw_image (PSplashFB    *fb, 
189                        int          x, 
190                        int          y, 
191                        int          img_width, 
192                        int          img_height,
193                        int          img_bytes_per_pixel,
194                        uint8       *rle_data)
195 {
196   uint8 *p = rle_data;
197   int    dx = 0, dy = 0,  total_len;
198   unsigned int len;
199
200 #if 0
201   for (dy=0; dy < img_height; dy++)   
202     for (dx=0; dx < img_width; dx++)
203       {
204         psplash_fb_plot_pixel (fb, x+dx, y+dy, *p, *(p+1), *(p+2)); 
205         p += img_bytes_per_pixel;
206       }
207 #endif
208
209   total_len = img_width * img_height * img_bytes_per_pixel;
210
211   /* FIXME: Optimise, check for over runs ... */
212   while ((p - rle_data) < total_len)
213     {
214       len = *(p++);
215
216       if (len & 128)
217         {
218           len -= 128;
219
220           if (len == 0) break;
221
222           do
223             {
224               psplash_fb_plot_pixel (fb, x+dx, y+dy, *p, *(p+1), *(p+2)); 
225               if (++dx >= img_width) { dx=0; dy++; }
226             }
227           while (--len && (p - rle_data) < total_len);
228
229           p += img_bytes_per_pixel;
230         }
231       else
232         {
233           if (len == 0) break;
234
235           do
236             {
237               psplash_fb_plot_pixel (fb, x+dx, y+dy, *p, *(p+1), *(p+2)); 
238               if (++dx >= img_width) { dx=0; dy++; }
239               p += img_bytes_per_pixel;
240             }
241           while (--len && (p - rle_data) < total_len);
242         }
243     }
244 }