2 * linux/drivers/video/console/bitblit.c -- BitBlitting Operation
4 * Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
6 * Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
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
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include <linux/string.h>
17 #include <linux/vt_kern.h>
18 #include <linux/console.h>
19 #include <asm/types.h>
23 * Accelerated handlers.
25 static void update_attr(u8
*dst
, u8
*src
, int attribute
,
28 int i
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
29 int width
= DIV_ROUND_UP(vc
->vc_font
.width
, 8);
30 unsigned int cellsize
= vc
->vc_font
.height
* width
;
33 offset
= cellsize
- (offset
* width
);
34 for (i
= 0; i
< cellsize
; i
++) {
36 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
&& i
>= offset
)
38 if (attribute
& FBCON_ATTRIBUTE_BOLD
)
40 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
46 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
)
49 struct fb_copyarea area
;
51 area
.sx
= sx
* vc
->vc_font
.width
;
52 area
.sy
= sy
* vc
->vc_font
.height
;
53 area
.dx
= dx
* vc
->vc_font
.width
;
54 area
.dy
= dy
* vc
->vc_font
.height
;
55 area
.height
= height
* vc
->vc_font
.height
;
56 area
.width
= width
* vc
->vc_font
.width
;
58 info
->fbops
->fb_copyarea(info
, &area
);
61 static void bit_clear(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
62 int sx
, int height
, int width
)
64 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
65 struct fb_fillrect region
;
67 region
.color
= attr_bgcol_ec(bgshift
, vc
, info
);
68 region
.dx
= sx
* vc
->vc_font
.width
;
69 region
.dy
= sy
* vc
->vc_font
.height
;
70 region
.width
= width
* vc
->vc_font
.width
;
71 region
.height
= height
* vc
->vc_font
.height
;
72 region
.rop
= ROP_COPY
;
74 info
->fbops
->fb_fillrect(info
, ®ion
);
77 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
)
82 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
83 u32 idx
= vc
->vc_font
.width
>> 3;
87 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
91 update_attr(buf
, src
, attr
, vc
);
96 __fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
99 fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
105 info
->fbops
->fb_imageblit(info
, image
);
108 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
,
115 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
116 u32 shift_low
= 0, mod
= vc
->vc_font
.width
% 8;
118 u32 idx
= vc
->vc_font
.width
>> 3;
122 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
126 update_attr(buf
, src
, attr
, vc
);
130 fb_pad_unaligned_buffer(dst
, d_pitch
, src
, idx
,
131 image
->height
, shift_high
,
134 dst
+= (shift_low
>= 8) ? s_pitch
: s_pitch
- 1;
136 shift_high
= 8 - shift_low
;
139 info
->fbops
->fb_imageblit(info
, image
);
143 static void bit_putcs(struct vc_data
*vc
, struct fb_info
*info
,
144 const unsigned short *s
, int count
, int yy
, int xx
,
147 struct fb_image image
;
148 u32 width
= DIV_ROUND_UP(vc
->vc_font
.width
, 8);
149 u32 cellsize
= width
* vc
->vc_font
.height
;
150 u32 maxcnt
= info
->pixmap
.size
/cellsize
;
151 u32 scan_align
= info
->pixmap
.scan_align
- 1;
152 u32 buf_align
= info
->pixmap
.buf_align
- 1;
153 u32 mod
= vc
->vc_font
.width
% 8, cnt
, pitch
, size
;
154 u32 attribute
= get_attribute(info
, scr_readw(s
));
155 u8
*dst
, *buf
= NULL
;
159 image
.dx
= xx
* vc
->vc_font
.width
;
160 image
.dy
= yy
* vc
->vc_font
.height
;
161 image
.height
= vc
->vc_font
.height
;
165 buf
= kmalloc(cellsize
, GFP_ATOMIC
);
176 image
.width
= vc
->vc_font
.width
* cnt
;
177 pitch
= DIV_ROUND_UP(image
.width
, 8) + scan_align
;
178 pitch
&= ~scan_align
;
179 size
= pitch
* image
.height
+ buf_align
;
181 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
185 bit_putcs_aligned(vc
, info
, s
, attribute
, cnt
, pitch
,
186 width
, cellsize
, &image
, buf
, dst
);
188 bit_putcs_unaligned(vc
, info
, s
, attribute
, cnt
,
189 pitch
, width
, cellsize
, &image
,
192 image
.dx
+= cnt
* vc
->vc_font
.width
;
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 */
205 static void bit_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
206 int color
, int bottom_only
)
208 unsigned int cw
= vc
->vc_font
.width
;
209 unsigned int ch
= vc
->vc_font
.height
;
210 unsigned int rw
= info
->var
.xres
- (vc
->vc_cols
*cw
);
211 unsigned int bh
= info
->var
.yres
- (vc
->vc_rows
*ch
);
212 unsigned int rs
= info
->var
.xres
- rw
;
213 unsigned int bs
= info
->var
.yres
- bh
;
214 struct fb_fillrect region
;
216 region
.color
= color
;
217 region
.rop
= ROP_COPY
;
219 if (rw
&& !bottom_only
) {
220 region
.dx
= info
->var
.xoffset
+ rs
;
223 region
.height
= info
->var
.yres_virtual
;
224 info
->fbops
->fb_fillrect(info
, ®ion
);
228 region
.dx
= info
->var
.xoffset
;
229 region
.dy
= info
->var
.yoffset
+ bs
;
232 info
->fbops
->fb_fillrect(info
, ®ion
);
236 static void bit_cursor(struct vc_data
*vc
, struct fb_info
*info
, int mode
,
237 int softback_lines
, int fg
, int bg
)
239 struct fb_cursor cursor
;
240 struct fbcon_ops
*ops
= info
->fbcon_par
;
241 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
242 int w
= DIV_ROUND_UP(vc
->vc_font
.width
, 8), c
;
243 int y
= real_y(ops
->p
, vc
->vc_y
);
244 int attribute
, use_sw
= (vc
->vc_cursor_type
& 0x10);
250 if (softback_lines
) {
251 if (y
+ softback_lines
>= vc
->vc_rows
) {
253 ops
->cursor_flash
= 0;
259 c
= scr_readw((u16
*) vc
->vc_pos
);
260 attribute
= get_attribute(info
, c
);
261 src
= vc
->vc_font
.data
+ ((c
& charmask
) * (w
* vc
->vc_font
.height
));
263 if (ops
->cursor_state
.image
.data
!= src
||
265 ops
->cursor_state
.image
.data
= src
;
266 cursor
.set
|= FB_CUR_SETIMAGE
;
272 dst
= kmalloc_array(w
, vc
->vc_font
.height
, GFP_ATOMIC
);
275 kfree(ops
->cursor_data
);
276 ops
->cursor_data
= dst
;
277 update_attr(dst
, src
, attribute
, vc
);
281 if (ops
->cursor_state
.image
.fg_color
!= fg
||
282 ops
->cursor_state
.image
.bg_color
!= bg
||
284 ops
->cursor_state
.image
.fg_color
= fg
;
285 ops
->cursor_state
.image
.bg_color
= bg
;
286 cursor
.set
|= FB_CUR_SETCMAP
;
289 if ((ops
->cursor_state
.image
.dx
!= (vc
->vc_font
.width
* vc
->vc_x
)) ||
290 (ops
->cursor_state
.image
.dy
!= (vc
->vc_font
.height
* y
)) ||
292 ops
->cursor_state
.image
.dx
= vc
->vc_font
.width
* vc
->vc_x
;
293 ops
->cursor_state
.image
.dy
= vc
->vc_font
.height
* y
;
294 cursor
.set
|= FB_CUR_SETPOS
;
297 if (ops
->cursor_state
.image
.height
!= vc
->vc_font
.height
||
298 ops
->cursor_state
.image
.width
!= vc
->vc_font
.width
||
300 ops
->cursor_state
.image
.height
= vc
->vc_font
.height
;
301 ops
->cursor_state
.image
.width
= vc
->vc_font
.width
;
302 cursor
.set
|= FB_CUR_SETSIZE
;
305 if (ops
->cursor_state
.hot
.x
|| ops
->cursor_state
.hot
.y
||
307 ops
->cursor_state
.hot
.x
= cursor
.hot
.y
= 0;
308 cursor
.set
|= FB_CUR_SETHOT
;
311 if (cursor
.set
& FB_CUR_SETSIZE
||
312 vc
->vc_cursor_type
!= ops
->p
->cursor_shape
||
313 ops
->cursor_state
.mask
== NULL
||
315 char *mask
= kmalloc_array(w
, vc
->vc_font
.height
, GFP_ATOMIC
);
316 int cur_height
, size
, i
= 0;
322 kfree(ops
->cursor_state
.mask
);
323 ops
->cursor_state
.mask
= mask
;
325 ops
->p
->cursor_shape
= vc
->vc_cursor_type
;
326 cursor
.set
|= FB_CUR_SETSHAPE
;
328 switch (ops
->p
->cursor_shape
& CUR_HWMASK
) {
333 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
335 case CUR_LOWER_THIRD
:
336 cur_height
= vc
->vc_font
.height
/3;
339 cur_height
= vc
->vc_font
.height
>> 1;
342 cur_height
= (vc
->vc_font
.height
<< 1)/3;
346 cur_height
= vc
->vc_font
.height
;
349 size
= (vc
->vc_font
.height
- cur_height
) * w
;
352 size
= cur_height
* w
;
359 ops
->cursor_state
.enable
= 0;
364 ops
->cursor_state
.enable
= (use_sw
) ? 0 : 1;
368 cursor
.image
.data
= src
;
369 cursor
.image
.fg_color
= ops
->cursor_state
.image
.fg_color
;
370 cursor
.image
.bg_color
= ops
->cursor_state
.image
.bg_color
;
371 cursor
.image
.dx
= ops
->cursor_state
.image
.dx
;
372 cursor
.image
.dy
= ops
->cursor_state
.image
.dy
;
373 cursor
.image
.height
= ops
->cursor_state
.image
.height
;
374 cursor
.image
.width
= ops
->cursor_state
.image
.width
;
375 cursor
.hot
.x
= ops
->cursor_state
.hot
.x
;
376 cursor
.hot
.y
= ops
->cursor_state
.hot
.y
;
377 cursor
.mask
= ops
->cursor_state
.mask
;
378 cursor
.enable
= ops
->cursor_state
.enable
;
379 cursor
.image
.depth
= 1;
380 cursor
.rop
= ROP_XOR
;
382 if (info
->fbops
->fb_cursor
)
383 err
= info
->fbops
->fb_cursor(info
, &cursor
);
386 soft_cursor(info
, &cursor
);
388 ops
->cursor_reset
= 0;
391 static int bit_update_start(struct fb_info
*info
)
393 struct fbcon_ops
*ops
= info
->fbcon_par
;
396 err
= fb_pan_display(info
, &ops
->var
);
397 ops
->var
.xoffset
= info
->var
.xoffset
;
398 ops
->var
.yoffset
= info
->var
.yoffset
;
399 ops
->var
.vmode
= info
->var
.vmode
;
403 void fbcon_set_bitops(struct fbcon_ops
*ops
)
405 ops
->bmove
= bit_bmove
;
406 ops
->clear
= bit_clear
;
407 ops
->putcs
= bit_putcs
;
408 ops
->clear_margins
= bit_clear_margins
;
409 ops
->cursor
= bit_cursor
;
410 ops
->update_start
= bit_update_start
;
411 ops
->rotate_font
= NULL
;
414 fbcon_set_rotate(ops
);
417 EXPORT_SYMBOL(fbcon_set_bitops
);