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