LCOV - code coverage report
Current view: top level - drivers/video/console - bitblit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 149 224 66.5 %
Date: 2015-04-12 14:34:49 Functions: 5 8 62.5 %

          Line data    Source code
       1             : /*
       2             :  *  linux/drivers/video/console/bitblit.c -- BitBlitting Operation
       3             :  *
       4             :  *  Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
       5             :  *
       6             :  *      Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
       7             :  *
       8             :  *  This file is subject to the terms and conditions of the GNU General Public
       9             :  *  License.  See the file COPYING in the main directory of this archive for
      10             :  *  more details.
      11             :  */
      12             : 
      13             : #include <linux/module.h>
      14             : #include <linux/slab.h>
      15             : #include <linux/string.h>
      16             : #include <linux/fb.h>
      17             : #include <linux/vt_kern.h>
      18             : #include <linux/console.h>
      19             : #include <asm/types.h>
      20             : #include "fbcon.h"
      21             : 
      22             : /*
      23             :  * Accelerated handlers.
      24             :  */
      25           0 : static void update_attr(u8 *dst, u8 *src, int attribute,
      26             :                                struct vc_data *vc)
      27             : {
      28           0 :         int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
      29           0 :         int width = DIV_ROUND_UP(vc->vc_font.width, 8);
      30           0 :         unsigned int cellsize = vc->vc_font.height * width;
      31             :         u8 c;
      32             : 
      33           0 :         offset = cellsize - (offset * width);
      34           0 :         for (i = 0; i < cellsize; i++) {
      35           0 :                 c = src[i];
      36           0 :                 if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
      37             :                         c = 0xff;
      38           0 :                 if (attribute & FBCON_ATTRIBUTE_BOLD)
      39           0 :                         c |= c >> 1;
      40           0 :                 if (attribute & FBCON_ATTRIBUTE_REVERSE)
      41           0 :                         c = ~c;
      42           0 :                 dst[i] = c;
      43             :         }
      44           0 : }
      45             : 
      46           0 : static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
      47             :                       int sx, int dy, int dx, int height, int width)
      48             : {
      49             :         struct fb_copyarea area;
      50             : 
      51           0 :         area.sx = sx * vc->vc_font.width;
      52           0 :         area.sy = sy * vc->vc_font.height;
      53           0 :         area.dx = dx * vc->vc_font.width;
      54           0 :         area.dy = dy * vc->vc_font.height;
      55           0 :         area.height = height * vc->vc_font.height;
      56           0 :         area.width = width * vc->vc_font.width;
      57             : 
      58           0 :         info->fbops->fb_copyarea(info, &area);
      59           0 : }
      60             : 
      61           0 : static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
      62             :                       int sx, int height, int width)
      63             : {
      64           0 :         int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
      65             :         struct fb_fillrect region;
      66             : 
      67           0 :         region.color = attr_bgcol_ec(bgshift, vc, info);
      68           0 :         region.dx = sx * vc->vc_font.width;
      69           0 :         region.dy = sy * vc->vc_font.height;
      70           0 :         region.width = width * vc->vc_font.width;
      71           0 :         region.height = height * vc->vc_font.height;
      72           0 :         region.rop = ROP_COPY;
      73             : 
      74           0 :         info->fbops->fb_fillrect(info, &region);
      75           0 : }
      76             : 
      77           0 : static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
      78             :                                      const u16 *s, u32 attr, u32 cnt,
      79             :                                      u32 d_pitch, u32 s_pitch, u32 cellsize,
      80             :                                      struct fb_image *image, u8 *buf, u8 *dst)
      81             : {
      82         320 :         u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
      83         320 :         u32 idx = vc->vc_font.width >> 3;
      84             :         u8 *src;
      85             : 
      86       29187 :         while (cnt--) {
      87       28867 :                 src = vc->vc_font.data + (scr_readw(s++)&
      88             :                                           charmask)*cellsize;
      89             : 
      90       28867 :                 if (attr) {
      91           0 :                         update_attr(buf, src, attr, vc);
      92             :                         src = buf;
      93             :                 }
      94             : 
      95       28867 :                 if (likely(idx == 1))
      96       28867 :                         __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
      97             :                                                 image->height);
      98             :                 else
      99           0 :                         fb_pad_aligned_buffer(dst, d_pitch, src, idx,
     100             :                                               image->height);
     101             : 
     102       28867 :                 dst += s_pitch;
     103             :         }
     104             : 
     105         320 :         info->fbops->fb_imageblit(info, image);
     106             : }
     107             : 
     108           0 : static inline void bit_putcs_unaligned(struct vc_data *vc,
     109             :                                        struct fb_info *info, const u16 *s,
     110             :                                        u32 attr, u32 cnt, u32 d_pitch,
     111             :                                        u32 s_pitch, u32 cellsize,
     112             :                                        struct fb_image *image, u8 *buf,
     113             :                                        u8 *dst)
     114             : {
     115           0 :         u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
     116           0 :         u32 shift_low = 0, mod = vc->vc_font.width % 8;
     117             :         u32 shift_high = 8;
     118           0 :         u32 idx = vc->vc_font.width >> 3;
     119             :         u8 *src;
     120             : 
     121           0 :         while (cnt--) {
     122           0 :                 src = vc->vc_font.data + (scr_readw(s++)&
     123             :                                           charmask)*cellsize;
     124             : 
     125           0 :                 if (attr) {
     126           0 :                         update_attr(buf, src, attr, vc);
     127             :                         src = buf;
     128             :                 }
     129             : 
     130           0 :                 fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
     131             :                                         image->height, shift_high,
     132             :                                         shift_low, mod);
     133           0 :                 shift_low += mod;
     134           0 :                 dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
     135           0 :                 shift_low &= 7;
     136           0 :                 shift_high = 8 - shift_low;
     137             :         }
     138             : 
     139           0 :         info->fbops->fb_imageblit(info, image);
     140             : 
     141             : }
     142             : 
     143         320 : static void bit_putcs(struct vc_data *vc, struct fb_info *info,
     144             :                       const unsigned short *s, int count, int yy, int xx,
     145             :                       int fg, int bg)
     146             : {
     147             :         struct fb_image image;
     148         320 :         u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
     149         320 :         u32 cellsize = width * vc->vc_font.height;
     150         320 :         u32 maxcnt = info->pixmap.size/cellsize;
     151         320 :         u32 scan_align = info->pixmap.scan_align - 1;
     152         320 :         u32 buf_align = info->pixmap.buf_align - 1;
     153         320 :         u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
     154         640 :         u32 attribute = get_attribute(info, scr_readw(s));
     155             :         u8 *dst, *buf = NULL;
     156             : 
     157         320 :         image.fg_color = fg;
     158         320 :         image.bg_color = bg;
     159         320 :         image.dx = xx * vc->vc_font.width;
     160         320 :         image.dy = yy * vc->vc_font.height;
     161         320 :         image.height = vc->vc_font.height;
     162         320 :         image.depth = 1;
     163             : 
     164         320 :         if (attribute) {
     165             :                 buf = kmalloc(cellsize, GFP_ATOMIC);
     166           0 :                 if (!buf)
     167           0 :                         return;
     168             :         }
     169             : 
     170         640 :         while (count) {
     171         320 :                 if (count > maxcnt)
     172             :                         cnt = maxcnt;
     173             :                 else
     174             :                         cnt = count;
     175             : 
     176         320 :                 image.width = vc->vc_font.width * cnt;
     177         320 :                 pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
     178         320 :                 pitch &= ~scan_align;
     179         320 :                 size = pitch * image.height + buf_align;
     180         320 :                 size &= ~buf_align;
     181         320 :                 dst = fb_get_buffer_offset(info, &info->pixmap, size);
     182         320 :                 image.data = dst;
     183             : 
     184         320 :                 if (!mod)
     185             :                         bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
     186             :                                           width, cellsize, &image, buf, dst);
     187             :                 else
     188             :                         bit_putcs_unaligned(vc, info, s, attribute, cnt,
     189             :                                             pitch, width, cellsize, &image,
     190             :                                             buf, dst);
     191             : 
     192         320 :                 image.dx += cnt * vc->vc_font.width;
     193         320 :                 count -= cnt;
     194         320 :                 s += cnt;
     195             :         }
     196             : 
     197             :         /* buf is always NULL except when in monochrome mode, so in this case
     198             :            it's a gain to check buf against NULL even though kfree() handles
     199             :            NULL pointers just fine */
     200         320 :         if (unlikely(buf))
     201           0 :                 kfree(buf);
     202             : 
     203             : }
     204             : 
     205           3 : static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
     206             :                               int bottom_only)
     207             : {
     208           3 :         unsigned int cw = vc->vc_font.width;
     209           3 :         unsigned int ch = vc->vc_font.height;
     210           3 :         unsigned int rw = info->var.xres - (vc->vc_cols*cw);
     211           3 :         unsigned int bh = info->var.yres - (vc->vc_rows*ch);
     212           3 :         unsigned int rs = info->var.xres - rw;
     213           3 :         unsigned int bs = info->var.yres - bh;
     214             :         struct fb_fillrect region;
     215             : 
     216           3 :         region.color = 0;
     217           3 :         region.rop = ROP_COPY;
     218             : 
     219           3 :         if (rw && !bottom_only) {
     220           0 :                 region.dx = info->var.xoffset + rs;
     221           0 :                 region.dy = 0;
     222           0 :                 region.width = rw;
     223           0 :                 region.height = info->var.yres_virtual;
     224           0 :                 info->fbops->fb_fillrect(info, &region);
     225             :         }
     226             : 
     227           3 :         if (bh) {
     228           3 :                 region.dx = info->var.xoffset;
     229           3 :                 region.dy = info->var.yoffset + bs;
     230           3 :                 region.width = rs;
     231           3 :                 region.height = bh;
     232           3 :                 info->fbops->fb_fillrect(info, &region);
     233             :         }
     234           3 : }
     235             : 
     236        9831 : static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
     237             :                        int softback_lines, int fg, int bg)
     238             : {
     239             :         struct fb_cursor cursor;
     240        9831 :         struct fbcon_ops *ops = info->fbcon_par;
     241        9831 :         unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
     242        9831 :         int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
     243        9831 :         int y = real_y(ops->p, vc->vc_y);
     244        9831 :         int attribute, use_sw = (vc->vc_cursor_type & 0x10);
     245             :         int err = 1;
     246             :         char *src;
     247             : 
     248        9831 :         cursor.set = 0;
     249             : 
     250        9831 :         if (softback_lines) {
     251           0 :                 if (y + softback_lines >= vc->vc_rows) {
     252             :                         mode = CM_ERASE;
     253           0 :                         ops->cursor_flash = 0;
     254           0 :                         return;
     255             :                 } else
     256             :                         y += softback_lines;
     257             :         }
     258             : 
     259        9831 :         c = scr_readw((u16 *) vc->vc_pos);
     260             :         attribute = get_attribute(info, c);
     261        9831 :         src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
     262             : 
     263       19650 :         if (ops->cursor_state.image.data != src ||
     264        9819 :             ops->cursor_reset) {
     265          14 :             ops->cursor_state.image.data = src;
     266          14 :             cursor.set |= FB_CUR_SETIMAGE;
     267             :         }
     268             : 
     269        9831 :         if (attribute) {
     270             :                 u8 *dst;
     271             : 
     272           0 :                 dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
     273           0 :                 if (!dst)
     274             :                         return;
     275           0 :                 kfree(ops->cursor_data);
     276           0 :                 ops->cursor_data = dst;
     277           0 :                 update_attr(dst, src, attribute, vc);
     278             :                 src = dst;
     279             :         }
     280             : 
     281       19659 :         if (ops->cursor_state.image.fg_color != fg ||
     282       19656 :             ops->cursor_state.image.bg_color != bg ||
     283        9828 :             ops->cursor_reset) {
     284           5 :                 ops->cursor_state.image.fg_color = fg;
     285           5 :                 ops->cursor_state.image.bg_color = bg;
     286           5 :                 cursor.set |= FB_CUR_SETCMAP;
     287             :         }
     288             : 
     289       19487 :         if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) ||
     290       19307 :             (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
     291        9651 :             ops->cursor_reset) {
     292         182 :                 ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x;
     293         182 :                 ops->cursor_state.image.dy = vc->vc_font.height * y;
     294         182 :                 cursor.set |= FB_CUR_SETPOS;
     295             :         }
     296             : 
     297       19661 :         if (ops->cursor_state.image.height != vc->vc_font.height ||
     298       19660 :             ops->cursor_state.image.width != vc->vc_font.width ||
     299        9830 :             ops->cursor_reset) {
     300           3 :                 ops->cursor_state.image.height = vc->vc_font.height;
     301           3 :                 ops->cursor_state.image.width = vc->vc_font.width;
     302           3 :                 cursor.set |= FB_CUR_SETSIZE;
     303             :         }
     304             : 
     305       19662 :         if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
     306        9831 :             ops->cursor_reset) {
     307           2 :                 ops->cursor_state.hot.x = cursor.hot.y = 0;
     308           2 :                 cursor.set |= FB_CUR_SETHOT;
     309             :         }
     310             : 
     311       19659 :         if (cursor.set & FB_CUR_SETSIZE ||
     312       19656 :             vc->vc_cursor_type != ops->p->cursor_shape ||
     313       19656 :             ops->cursor_state.mask == NULL ||
     314        9828 :             ops->cursor_reset) {
     315           3 :                 char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
     316             :                 int cur_height, size, i = 0;
     317             :                 u8 msk = 0xff;
     318             : 
     319           3 :                 if (!mask)
     320             :                         return;
     321             : 
     322           3 :                 kfree(ops->cursor_state.mask);
     323           3 :                 ops->cursor_state.mask = mask;
     324             : 
     325           3 :                 ops->p->cursor_shape = vc->vc_cursor_type;
     326           3 :                 cursor.set |= FB_CUR_SETSHAPE;
     327             : 
     328           3 :                 switch (ops->p->cursor_shape & CUR_HWMASK) {
     329             :                 case CUR_NONE:
     330             :                         cur_height = 0;
     331             :                         break;
     332             :                 case CUR_UNDERLINE:
     333           3 :                         cur_height = (vc->vc_font.height < 10) ? 1 : 2;
     334           3 :                         break;
     335             :                 case CUR_LOWER_THIRD:
     336           0 :                         cur_height = vc->vc_font.height/3;
     337           0 :                         break;
     338             :                 case CUR_LOWER_HALF:
     339           0 :                         cur_height = vc->vc_font.height >> 1;
     340           0 :                         break;
     341             :                 case CUR_TWO_THIRDS:
     342           0 :                         cur_height = (vc->vc_font.height << 1)/3;
     343           0 :                         break;
     344             :                 case CUR_BLOCK:
     345             :                 default:
     346           0 :                         cur_height = vc->vc_font.height;
     347           0 :                         break;
     348             :                 }
     349           3 :                 size = (vc->vc_font.height - cur_height) * w;
     350          48 :                 while (size--)
     351          42 :                         mask[i++] = ~msk;
     352           3 :                 size = cur_height * w;
     353          12 :                 while (size--)
     354           6 :                         mask[i++] = msk;
     355             :         }
     356             : 
     357        9831 :         switch (mode) {
     358             :         case CM_ERASE:
     359        4863 :                 ops->cursor_state.enable = 0;
     360        4863 :                 break;
     361             :         case CM_DRAW:
     362             :         case CM_MOVE:
     363             :         default:
     364        4968 :                 ops->cursor_state.enable = (use_sw) ? 0 : 1;
     365        4968 :                 break;
     366             :         }
     367             : 
     368        9831 :         cursor.image.data = src;
     369        9831 :         cursor.image.fg_color = ops->cursor_state.image.fg_color;
     370        9831 :         cursor.image.bg_color = ops->cursor_state.image.bg_color;
     371        9831 :         cursor.image.dx = ops->cursor_state.image.dx;
     372        9831 :         cursor.image.dy = ops->cursor_state.image.dy;
     373        9831 :         cursor.image.height = ops->cursor_state.image.height;
     374        9831 :         cursor.image.width = ops->cursor_state.image.width;
     375        9831 :         cursor.hot.x = ops->cursor_state.hot.x;
     376        9831 :         cursor.hot.y = ops->cursor_state.hot.y;
     377        9831 :         cursor.mask = ops->cursor_state.mask;
     378        9831 :         cursor.enable = ops->cursor_state.enable;
     379        9831 :         cursor.image.depth = 1;
     380        9831 :         cursor.rop = ROP_XOR;
     381             : 
     382        9831 :         if (info->fbops->fb_cursor)
     383           0 :                 err = info->fbops->fb_cursor(info, &cursor);
     384             : 
     385        9831 :         if (err)
     386        9831 :                 soft_cursor(info, &cursor);
     387             : 
     388        9831 :         ops->cursor_reset = 0;
     389             : }
     390             : 
     391           2 : static int bit_update_start(struct fb_info *info)
     392             : {
     393           2 :         struct fbcon_ops *ops = info->fbcon_par;
     394             :         int err;
     395             : 
     396           2 :         err = fb_pan_display(info, &ops->var);
     397           2 :         ops->var.xoffset = info->var.xoffset;
     398           2 :         ops->var.yoffset = info->var.yoffset;
     399           2 :         ops->var.vmode = info->var.vmode;
     400           2 :         return err;
     401             : }
     402             : 
     403           9 : void fbcon_set_bitops(struct fbcon_ops *ops)
     404             : {
     405           9 :         ops->bmove = bit_bmove;
     406           9 :         ops->clear = bit_clear;
     407           9 :         ops->putcs = bit_putcs;
     408           9 :         ops->clear_margins = bit_clear_margins;
     409           9 :         ops->cursor = bit_cursor;
     410           9 :         ops->update_start = bit_update_start;
     411           9 :         ops->rotate_font = NULL;
     412             : 
     413             :         if (ops->rotate)
     414             :                 fbcon_set_rotate(ops);
     415           9 : }
     416             : 
     417             : EXPORT_SYMBOL(fbcon_set_bitops);
     418             : 
     419             : MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
     420             : MODULE_DESCRIPTION("Bit Blitting Operation");
     421             : MODULE_LICENSE("GPL");
     422             : 

Generated by: LCOV version 1.11