- Update to 3.3-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / video / bootsplash / render.c
1 /*
2  *    linux/drivers/video/bootsplash/render.c - splash screen render functions.
3  */
4
5 #include <linux/module.h>
6 #include <linux/types.h>
7 #include <linux/fb.h>
8 #include <linux/vt_kern.h>
9 #include <linux/selection.h>
10 #include <asm/irq.h>
11 #include <asm/system.h>
12
13 #include "../console/fbcon.h"
14 #include <linux/bootsplash.h>
15
16 #ifndef DEBUG
17 # define SPLASH_DEBUG(fmt, args...)
18 #else
19 # define SPLASH_DEBUG(fmt, args...) \
20         printk(KERN_WARNING "%s: " fmt "\n", __func__, ##args)
21 #endif
22
23 /* fake a region sync */
24 void splash_sync_region(struct fb_info *info, int x, int y,
25                         int width, int height)
26 {
27         struct splash_data *sd = info->splash_data;
28         if (sd && sd->need_sync) {
29                 /* issue a fake copyarea (copy to the very same position)
30                  * for marking the dirty region; this is required for Xen fb
31                  * (bnc#739020)
32                  */
33                 struct fb_copyarea area;
34                 area.sx = area.dx = x;
35                 area.sy = area.dy = y;
36                 area.width = width;
37                 area.height = height;
38                 info->fbops->fb_copyarea(info, &area);
39         }
40 }
41
42 void splash_putcs(struct vc_data *vc, struct fb_info *info,
43                    const unsigned short *s, int count, int ypos, int xpos)
44 {
45         struct splash_data *sd;
46         unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
47         int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
48         int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
49         union pt src;
50         union pt dst, splashsrc;
51         unsigned int d, x, y;
52         u32 dd, fgx, bgx;
53         u16 c = scr_readw(s);
54         int fg_color, bg_color, transparent;
55         int n;
56         int octpp = (info->var.bits_per_pixel + 1) >> 3;
57         int drawn_width;
58
59         if (!oops_in_progress
60             && (console_blanked || info->splash_data->splash_dosilent))
61                 return;
62         sd = info->splash_data;
63
64         fg_color = attr_fgcol(fgshift, c);
65         bg_color = attr_bgcol(bgshift, c);
66         transparent = sd->imgd->splash_color == bg_color;
67         xpos = xpos * vc->vc_font.width + sd->imgd->splash_text_xo;
68         ypos = ypos * vc->vc_font.height + sd->imgd->splash_text_yo;
69         splashsrc.ub = (u8 *)(sd->pic->splash_pic
70                               + ypos * sd->pic->splash_pic_stride
71                               + xpos * octpp);
72         dst.ub = (u8 *)(info->screen_base
73                         + ypos * info->fix.line_length
74                         + xpos * octpp);
75         fgx = ((u32 *)info->pseudo_palette)[fg_color];
76         if (transparent && sd->imgd->splash_color == 15) {
77                 if (fgx == 0xffea)
78                         fgx = 0xfe4a;
79                 else if (fgx == 0x57ea)
80                         fgx = 0x0540;
81                 else if (fgx == 0xffff)
82                         fgx = 0x52aa;
83         }
84         bgx = ((u32 *)info->pseudo_palette)[bg_color];
85         d = 0;
86         drawn_width = 0;
87         while (count--) {
88                 c = scr_readw(s++);
89                 src.ub = vc->vc_font.data
90                         + ((c & charmask)
91                            * vc->vc_font.height
92                            * ((vc->vc_font.width + 7) >> 3));
93                 for (y = 0; y < vc->vc_font.height; y++) {
94                         for (x = 0; x < vc->vc_font.width; ) {
95                                 if ((x & 7) == 0)
96                                         d = *src.ub++;
97                                 switch (octpp) {
98                                 case 2:
99                                         if (d & 0x80)
100                                                 dd = fgx;
101                                         else
102                                                 dd = (transparent ?
103                                                       *splashsrc.us : bgx);
104                                         splashsrc.us += 1;
105                                         if (d & 0x40)
106                                                 dd |= fgx << 16;
107                                         else
108                                                 dd |= (transparent ? *splashsrc.us : bgx) << 16;
109                                         splashsrc.us += 1;
110                                         d <<= 2;
111                                         x += 2;
112                                         fb_writel(dd, dst.ul);
113                                         dst.ul += 1;
114                                         break;
115                                 case 3:
116                                         for (n = 0; n <= 16; n += 8) {
117                                                 if (d & 0x80)
118                                                         dd = (fgx >> n) & 0xff;
119                                                 else
120                                                         dd = (transparent ? *splashsrc.ul : ((bgx >> n) & 0xff));
121                                                 splashsrc.ub += 1;
122                                                 fb_writeb(dd, dst.ub);
123                                                 dst.ub += 1;
124                                         }
125                                         d <<= 1;
126                                         x += 1;
127                                         break;
128                                 case 4:
129                                         if (d & 0x80)
130                                                 dd = fgx;
131                                         else
132                                                 dd = (transparent ? *splashsrc.ul : bgx);
133                                         splashsrc.ul += 1;
134                                         d <<= 1;
135                                         x += 1;
136                                         fb_writel(dd, dst.ul);
137                                         dst.ul += 1;
138                                         break;
139                                 }
140                         }
141                         dst.ub += info->fix.line_length
142                                 - vc->vc_font.width * octpp;
143                         splashsrc.ub += sd->pic->splash_pic_stride
144                                 - vc->vc_font.width * octpp;
145                 }
146                 dst.ub -= info->fix.line_length * vc->vc_font.height
147                         - vc->vc_font.width * octpp;
148                 splashsrc.ub -= sd->pic->splash_pic_stride * vc->vc_font.height
149                         - vc->vc_font.width * octpp;
150                 drawn_width += vc->vc_font.width;
151         }
152         splash_sync_region(info, xpos, ypos, drawn_width, vc->vc_font.height);
153 }
154
155 static void splash_renderc(struct fb_info *info,
156                            int fg_color, int bg_color,
157                            u8 *src,
158                            int ypos, int xpos,
159                            int height, int width)
160 {
161         struct splash_data *sd;
162         int transparent;
163         u32 dd, fgx, bgx;
164         union pt dst, splashsrc;
165         unsigned int d, x, y;
166         int n;
167         int octpp = (info->var.bits_per_pixel + 1) >> 3;
168
169         if (!oops_in_progress
170             && (console_blanked || info->splash_data->splash_dosilent))
171                 return;
172
173         sd = info->splash_data;
174
175         transparent = sd->imgd->splash_color == bg_color;
176         splashsrc.ub = (u8 *)(sd->pic->splash_pic
177                              + ypos * sd->pic->splash_pic_stride
178                              + xpos * octpp);
179         dst.ub = (u8 *)(info->screen_base
180                        + ypos * info->fix.line_length
181                        + xpos * octpp);
182         fgx = ((u32 *)info->pseudo_palette)[fg_color];
183         if (transparent && (sd->imgd->splash_color == 15)) {
184                 if (fgx == 0xffea)
185                         fgx = 0xfe4a;
186                 else if (fgx == 0x57ea)
187                         fgx = 0x0540;
188                 else if (fgx == 0xffff)
189                         fgx = 0x52aa;
190         }
191         bgx = ((u32 *)info->pseudo_palette)[bg_color];
192         d = 0;
193         for (y = 0; y < height; y++) {
194                 for (x = 0; x < width; ) {
195                         if ((x & 7) == 0)
196                                 d = *src++;
197                         switch (octpp) {
198                         case 2:
199                                 if (d & 0x80)
200                                         dd = fgx;
201                                 else
202                                         dd = (transparent ? *splashsrc.us : bgx);
203                                 splashsrc.us += 1;
204                                 if (d & 0x40)
205                                         dd |= fgx << 16;
206                                 else
207                                         dd |= (transparent ? *splashsrc.us : bgx) << 16;
208                                 splashsrc.us += 1;
209                                 d <<= 2;
210                                 x += 2;
211                                 fb_writel(dd, dst.ul);
212                                 dst.ul += 1;
213                                 break;
214                         case 3:
215                                 for (n = 0; n <= 16; n += 8) {
216                                         if (d & 0x80)
217                                                 dd = (fgx >> n) & 0xff;
218                                         else
219                                                 dd = (transparent ? *splashsrc.ub : bgx);
220                                         splashsrc.ub += 1;
221                                         fb_writeb(dd, dst.ub);
222                                         dst.ub += 1;
223                                 }
224                                 d <<= 1;
225                                 x += 1;
226                                 break;
227                         case 4:
228                                 if (d & 0x80)
229                                         dd = fgx;
230                                 else
231                                         dd = (transparent ? *splashsrc.ul : bgx);
232                                 splashsrc.ul += 1;
233                                 d <<= 1;
234                                 x += 1;
235                                 fb_writel(dd, dst.ul);
236                                 dst.ul += 1;
237                                 break;
238                         }
239                 }
240                 dst.ub += info->fix.line_length - width * octpp;
241                 splashsrc.ub += sd->pic->splash_pic_stride - width * octpp;
242         }
243         splash_sync_region(info, xpos, ypos, width, height);
244 }
245
246 void splashcopy(u8 *dst, u8 *src, int height, int width,
247                 int dstbytes, int srcbytes, int octpp)
248 {
249         int i;
250
251         width *= octpp;
252         while (height-- > 0) {
253                 union pt p, q;
254                 p.ul = (u32 *)dst;
255                 q.ul = (u32 *)src;
256                 for (i = 0; i < width / 4; i++)
257                         fb_writel(*q.ul++, p.ul++);
258                 if (width & 2)
259                         fb_writew(*q.us++, p.us++);
260                 if (width & 1)
261                         fb_writeb(*q.ub, p.ub);
262                 dst += dstbytes;
263                 src += srcbytes;
264         }
265 }
266
267 static void splashset(u8 *dst, int height, int width,
268                       int dstbytes, u32 bgx, int octpp) {
269         int i;
270
271         width *= octpp;
272         if (octpp == 2)
273                 bgx |= bgx << 16;
274         while (height-- > 0) {
275                 union pt p;
276                 p.ul = (u32 *)dst;
277                 if (!(octpp & 1)) {
278                         for (i = 0; i < width / 4; i++)
279                                 fb_writel(bgx, p.ul++);
280                         if (width & 2)
281                                 fb_writew(bgx, p.us++);
282                         if (width & 1)
283                                 fb_writeb(bgx, p.ub);
284                         dst += dstbytes;
285                 } else { /* slow! */
286                         for (i = 0; i < width; i++)
287                                 fb_writeb((bgx >> ((i % 3) * 8)) & 0xff,
288                                           p.ub++);
289                 }
290         }
291 }
292
293 static void splashfill(struct fb_info *info, int sy, int sx,
294                        int height, int width) {
295         int octpp = (info->var.bits_per_pixel + 1) >> 3;
296         struct splash_data *sd = info->splash_data;
297
298         splashcopy((u8 *)(info->screen_base
299                           + sy * info->fix.line_length + sx * octpp),
300                    (u8 *)(sd->pic->splash_pic
301                           + sy * sd->pic->splash_pic_stride
302                           + sx * octpp),
303                    height, width, info->fix.line_length,
304                    sd->pic->splash_pic_stride,
305                    octpp);
306         splash_sync_region(info, sx, sy, width, height);
307 }
308
309 void splash_clear(struct vc_data *vc, struct fb_info *info, int sy,
310                         int sx, int height, int width)
311 {
312         struct splash_data *sd;
313         int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
314         int bg_color = attr_bgcol_ec(bgshift, vc, info);
315         int transparent;
316         int octpp = (info->var.bits_per_pixel + 1) >> 3;
317         u32 bgx;
318         u8 *dst;
319
320         if (!oops_in_progress
321             && (console_blanked || info->splash_data->splash_dosilent))
322                 return;
323
324         sd = info->splash_data;
325
326         transparent = sd->imgd->splash_color == bg_color;
327
328         sy = sy * vc->vc_font.height + sd->imgd->splash_text_yo;
329         sx = sx * vc->vc_font.width + sd->imgd->splash_text_xo;
330         height *= vc->vc_font.height;
331         width *= vc->vc_font.width;
332         if (transparent) {
333                 splashfill(info, sy, sx, height, width);
334                 return;
335         }
336         dst = (u8 *)(info->screen_base
337                      + sy * info->fix.line_length
338                      + sx * octpp);
339         bgx = ((u32 *)info->pseudo_palette)[bg_color];
340         splashset(dst,
341                   height, width,
342                   info->fix.line_length,
343                   bgx,
344                   (info->var.bits_per_pixel + 1) >> 3);
345         splash_sync_region(info, sx, sy, width, height);
346 }
347
348 void splash_bmove(struct vc_data *vc, struct fb_info *info, int sy,
349                 int sx, int dy, int dx, int height, int width)
350 {
351         struct splash_data *sd;
352         struct fb_copyarea area;
353
354         if (!oops_in_progress
355             && (console_blanked || info->splash_data->splash_dosilent))
356                 return;
357
358         sd = info->splash_data;
359
360         area.sx = sx * vc->vc_font.width;
361         area.sy = sy * vc->vc_font.height;
362         area.dx = dx * vc->vc_font.width;
363         area.dy = dy * vc->vc_font.height;
364         area.sx += sd->imgd->splash_text_xo;
365         area.sy += sd->imgd->splash_text_yo;
366         area.dx += sd->imgd->splash_text_xo;
367         area.dy += sd->imgd->splash_text_yo;
368         area.height = height * vc->vc_font.height;
369         area.width = width * vc->vc_font.width;
370
371         info->fbops->fb_copyarea(info, &area);
372 }
373
374 void splash_clear_margins(struct vc_data *vc, struct fb_info *info,
375                                 int bottom_only)
376 {
377         struct splash_data *sd;
378         unsigned int tw = vc->vc_cols*vc->vc_font.width;
379         unsigned int th = vc->vc_rows*vc->vc_font.height;
380         SPLASH_DEBUG();
381
382         if (!oops_in_progress
383             && (console_blanked || info->splash_data->splash_dosilent))
384                 return;
385
386         sd = info->splash_data;
387
388         if (!bottom_only) {
389                 /* top margin */
390                 splashfill(info,
391                            0,
392                            0,
393                            sd->imgd->splash_text_yo,
394                            info->var.xres);
395                 /* left margin */
396                 splashfill(info,
397                            sd->imgd->splash_text_yo,
398                            0,
399                            th,
400                            sd->imgd->splash_text_xo);
401                 /* right margin */
402                 splashfill(info,
403                            sd->imgd->splash_text_yo,
404                            sd->imgd->splash_text_xo + tw,
405                            th,
406                            info->var.xres - sd->imgd->splash_text_xo - tw);
407         }
408         splashfill(info,
409                    sd->imgd->splash_text_yo + th,
410                    0,
411                    info->var.yres - sd->imgd->splash_text_yo - th,
412                    info->var.xres);
413 }
414
415 int splash_cursor(struct fb_info *info, struct fb_cursor *cursor)
416 {
417         struct splash_data *sd;
418         int i;
419         unsigned int dsize, s_pitch;
420
421         if (info->state != FBINFO_STATE_RUNNING)
422                 return 0;
423
424         sd = info->splash_data;
425
426         s_pitch = (cursor->image.width + 7) >> 3;
427         dsize = s_pitch * cursor->image.height;
428         if (cursor->enable) {
429                 switch (cursor->rop) {
430                 case ROP_XOR:
431                         for (i = 0; i < dsize; i++)
432                                 info->fb_cursordata[i] = cursor->image.data[i]
433                                         ^ cursor->mask[i];
434                         break;
435                 case ROP_COPY:
436                 default:
437                         for (i = 0; i < dsize; i++)
438                                 info->fb_cursordata[i] = cursor->image.data[i]
439                                         & cursor->mask[i];
440                         break;
441                 }
442         } else if (info->fb_cursordata != cursor->image.data)
443                 memcpy(info->fb_cursordata, cursor->image.data, dsize);
444         cursor->image.data = info->fb_cursordata;
445         splash_renderc(info, cursor->image.fg_color, cursor->image.bg_color,
446                        (u8 *)info->fb_cursordata,
447                        cursor->image.dy + sd->imgd->splash_text_yo,
448                        cursor->image.dx + sd->imgd->splash_text_xo,
449                        cursor->image.height,
450                        cursor->image.width);
451         return 0;
452 }
453
454 void splash_bmove_redraw(struct vc_data *vc, struct fb_info *info,
455                          int y, int sx, int dx, int width)
456 {
457         struct splash_data *sd;
458         unsigned short *d = (unsigned short *) (vc->vc_origin
459                                                 + vc->vc_size_row * y
460                                                 + dx * 2);
461         unsigned short *s = d + (dx - sx);
462         unsigned short *start = d;
463         unsigned short *ls = d;
464         unsigned short *le = d + width;
465         unsigned short c;
466         int x = dx;
467         unsigned short attr = 1;
468
469         if (console_blanked || info->splash_data->splash_dosilent)
470                 return;
471
472         sd = info->splash_data;
473
474         do {
475                 c = scr_readw(d);
476                 if (attr != (c & 0xff00)) {
477                         attr = c & 0xff00;
478                         if (d > start) {
479                                 splash_putcs(vc, info, start, d - start, y, x);
480                                 x += d - start;
481                                 start = d;
482                         }
483                 }
484                 if (s >= ls && s < le && c == scr_readw(s)) {
485                         if (d > start) {
486                                 splash_putcs(vc, info, start, d - start, y, x);
487                                 x += d - start + 1;
488                                 start = d + 1;
489                         } else {
490                                 x++;
491                                 start++;
492                         }
493                 }
494                 s++;
495                 d++;
496         } while (d < le);
497         if (d > start)
498                 splash_putcs(vc, info, start, d - start, y, x);
499 }
500
501 void splash_blank(struct vc_data *vc, struct fb_info *info, int blank)
502 {
503         SPLASH_DEBUG();
504
505         if (blank) {
506                 splashset((u8 *)info->screen_base,
507                           info->var.yres, info->var.xres,
508                           info->fix.line_length,
509                           0,
510                           (info->var.bits_per_pixel + 1) >> 3);
511                 splash_sync_region(info, 0, 0, info->var.xres, info->var.yres);
512         } else {
513                 /* splash_prepare(vc, info);  *//* do we really need this? */
514                 splash_clear_margins(vc, info, 0);
515                 /* no longer needed, done in fbcon_blank */
516                 /* update_screen(vc->vc_num); */
517         }
518 }