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/config.h>
14 #include <linux/module.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 #define FBCON_ATTRIBUTE_UNDERLINE 1
26 #define FBCON_ATTRIBUTE_REVERSE 2
27 #define FBCON_ATTRIBUTE_BOLD 4
29 static inline int real_y(struct display
*p
, int ypos
)
34 return ypos
< rows
? ypos
: ypos
- rows
;
38 static inline int get_attribute(struct fb_info
*info
, u16 c
)
42 if (fb_get_color_depth(&info
->var
) == 1) {
43 if (attr_underline(c
))
44 attribute
|= FBCON_ATTRIBUTE_UNDERLINE
;
46 attribute
|= FBCON_ATTRIBUTE_REVERSE
;
48 attribute
|= FBCON_ATTRIBUTE_BOLD
;
54 static inline void update_attr(u8
*dst
, u8
*src
, int attribute
,
57 int i
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
58 int width
= (vc
->vc_font
.width
+ 7) >> 3;
59 unsigned int cellsize
= vc
->vc_font
.height
* width
;
62 offset
= cellsize
- (offset
* width
);
63 for (i
= 0; i
< cellsize
; i
++) {
65 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
&& i
>= offset
)
67 if (attribute
& FBCON_ATTRIBUTE_BOLD
)
69 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
75 static void bit_bmove(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
76 int sx
, int dy
, int dx
, int height
, int width
)
78 struct fb_copyarea area
;
80 area
.sx
= sx
* vc
->vc_font
.width
;
81 area
.sy
= sy
* vc
->vc_font
.height
;
82 area
.dx
= dx
* vc
->vc_font
.width
;
83 area
.dy
= dy
* vc
->vc_font
.height
;
84 area
.height
= height
* vc
->vc_font
.height
;
85 area
.width
= width
* vc
->vc_font
.width
;
87 info
->fbops
->fb_copyarea(info
, &area
);
90 static void bit_clear(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
91 int sx
, int height
, int width
)
93 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
94 struct fb_fillrect region
;
96 region
.color
= attr_bgcol_ec(bgshift
, vc
);
97 region
.dx
= sx
* vc
->vc_font
.width
;
98 region
.dy
= sy
* vc
->vc_font
.height
;
99 region
.width
= width
* vc
->vc_font
.width
;
100 region
.height
= height
* vc
->vc_font
.height
;
101 region
.rop
= ROP_COPY
;
103 info
->fbops
->fb_fillrect(info
, ®ion
);
106 static void bit_putcs(struct vc_data
*vc
, struct fb_info
*info
,
107 const unsigned short *s
, int count
, int yy
, int xx
,
110 void (*move_unaligned
)(struct fb_info
*info
, struct fb_pixmap
*buf
,
111 u8
*dst
, u32 d_pitch
, u8
*src
, u32 idx
,
112 u32 height
, u32 shift_high
, u32 shift_low
,
114 void (*move_aligned
)(struct fb_info
*info
, struct fb_pixmap
*buf
,
115 u8
*dst
, u32 d_pitch
, u8
*src
, u32 s_pitch
,
117 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
118 unsigned int width
= (vc
->vc_font
.width
+ 7) >> 3;
119 unsigned int cellsize
= vc
->vc_font
.height
* width
;
120 unsigned int maxcnt
= info
->pixmap
.size
/cellsize
;
121 unsigned int scan_align
= info
->pixmap
.scan_align
- 1;
122 unsigned int buf_align
= info
->pixmap
.buf_align
- 1;
123 unsigned int shift_low
= 0, mod
= vc
->vc_font
.width
% 8;
124 unsigned int shift_high
= 8, pitch
, cnt
, size
, k
;
125 unsigned int idx
= vc
->vc_font
.width
>> 3;
126 unsigned int attribute
= get_attribute(info
, scr_readw(s
));
127 struct fb_image image
;
128 u8
*src
, *dst
, *buf
= NULL
;
131 buf
= kmalloc(cellsize
, GFP_KERNEL
);
139 image
.dx
= xx
* vc
->vc_font
.width
;
140 image
.dy
= yy
* vc
->vc_font
.height
;
141 image
.height
= vc
->vc_font
.height
;
144 if (info
->pixmap
.outbuf
&& info
->pixmap
.inbuf
) {
145 move_aligned
= fb_iomove_buf_aligned
;
146 move_unaligned
= fb_iomove_buf_unaligned
;
148 move_aligned
= fb_sysmove_buf_aligned
;
149 move_unaligned
= fb_sysmove_buf_unaligned
;
157 image
.width
= vc
->vc_font
.width
* cnt
;
158 pitch
= ((image
.width
+ 7) >> 3) + scan_align
;
159 pitch
&= ~scan_align
;
160 size
= pitch
* image
.height
+ buf_align
;
162 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
166 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
170 update_attr(buf
, src
, attribute
, vc
);
174 move_unaligned(info
, &info
->pixmap
, dst
, pitch
,
175 src
, idx
, image
.height
,
176 shift_high
, shift_low
, mod
);
178 dst
+= (shift_low
>= 8) ? width
: width
- 1;
180 shift_high
= 8 - shift_low
;
184 src
= vc
->vc_font
.data
+ (scr_readw(s
++)&
188 update_attr(buf
, src
, attribute
, vc
);
192 move_aligned(info
, &info
->pixmap
, dst
, pitch
,
193 src
, idx
, image
.height
);
197 info
->fbops
->fb_imageblit(info
, &image
);
198 image
.dx
+= cnt
* vc
->vc_font
.width
;
202 /* buf is always NULL except when in monochrome mode, so in this case
203 it's a gain to check buf against NULL even though kfree() handles
204 NULL pointers just fine */
209 static void bit_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
212 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
213 unsigned int cw
= vc
->vc_font
.width
;
214 unsigned int ch
= vc
->vc_font
.height
;
215 unsigned int rw
= info
->var
.xres
- (vc
->vc_cols
*cw
);
216 unsigned int bh
= info
->var
.yres
- (vc
->vc_rows
*ch
);
217 unsigned int rs
= info
->var
.xres
- rw
;
218 unsigned int bs
= info
->var
.yres
- bh
;
219 struct fb_fillrect region
;
221 region
.color
= attr_bgcol_ec(bgshift
, vc
);
222 region
.rop
= ROP_COPY
;
224 if (rw
&& !bottom_only
) {
225 region
.dx
= info
->var
.xoffset
+ rs
;
228 region
.height
= info
->var
.yres_virtual
;
229 info
->fbops
->fb_fillrect(info
, ®ion
);
233 region
.dx
= info
->var
.xoffset
;
234 region
.dy
= info
->var
.yoffset
+ bs
;
237 info
->fbops
->fb_fillrect(info
, ®ion
);
241 static void bit_cursor(struct vc_data
*vc
, struct fb_info
*info
,
242 struct display
*p
, int mode
, int softback_lines
, int fg
, int bg
)
244 struct fb_cursor cursor
;
245 struct fbcon_ops
*ops
= (struct fbcon_ops
*) info
->fbcon_par
;
246 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
247 int w
= (vc
->vc_font
.width
+ 7) >> 3, c
;
248 int y
= real_y(p
, vc
->vc_y
);
249 int attribute
, use_sw
= (vc
->vc_cursor_type
& 0x10);
254 if (softback_lines
) {
255 if (y
+ softback_lines
>= vc
->vc_rows
) {
257 ops
->cursor_flash
= 0;
263 c
= scr_readw((u16
*) vc
->vc_pos
);
264 attribute
= get_attribute(info
, c
);
265 src
= vc
->vc_font
.data
+ ((c
& charmask
) * (w
* vc
->vc_font
.height
));
267 if (ops
->cursor_state
.image
.data
!= src
||
269 ops
->cursor_state
.image
.data
= src
;
270 cursor
.set
|= FB_CUR_SETIMAGE
;
276 dst
= kmalloc(w
* vc
->vc_font
.height
, GFP_ATOMIC
);
279 kfree(ops
->cursor_data
);
280 ops
->cursor_data
= dst
;
281 update_attr(dst
, src
, attribute
, vc
);
285 if (ops
->cursor_state
.image
.fg_color
!= fg
||
286 ops
->cursor_state
.image
.bg_color
!= bg
||
288 ops
->cursor_state
.image
.fg_color
= fg
;
289 ops
->cursor_state
.image
.bg_color
= bg
;
290 cursor
.set
|= FB_CUR_SETCMAP
;
293 if ((ops
->cursor_state
.image
.dx
!= (vc
->vc_font
.width
* vc
->vc_x
)) ||
294 (ops
->cursor_state
.image
.dy
!= (vc
->vc_font
.height
* y
)) ||
296 ops
->cursor_state
.image
.dx
= vc
->vc_font
.width
* vc
->vc_x
;
297 ops
->cursor_state
.image
.dy
= vc
->vc_font
.height
* y
;
298 cursor
.set
|= FB_CUR_SETPOS
;
301 if (ops
->cursor_state
.image
.height
!= vc
->vc_font
.height
||
302 ops
->cursor_state
.image
.width
!= vc
->vc_font
.width
||
304 ops
->cursor_state
.image
.height
= vc
->vc_font
.height
;
305 ops
->cursor_state
.image
.width
= vc
->vc_font
.width
;
306 cursor
.set
|= FB_CUR_SETSIZE
;
309 if (ops
->cursor_state
.hot
.x
|| ops
->cursor_state
.hot
.y
||
311 ops
->cursor_state
.hot
.x
= cursor
.hot
.y
= 0;
312 cursor
.set
|= FB_CUR_SETHOT
;
315 if (cursor
.set
& FB_CUR_SETSIZE
||
316 vc
->vc_cursor_type
!= p
->cursor_shape
||
317 ops
->cursor_state
.mask
== NULL
||
319 char *mask
= kmalloc(w
*vc
->vc_font
.height
, GFP_ATOMIC
);
320 int cur_height
, size
, i
= 0;
326 kfree(ops
->cursor_state
.mask
);
327 ops
->cursor_state
.mask
= mask
;
329 p
->cursor_shape
= vc
->vc_cursor_type
;
330 cursor
.set
|= FB_CUR_SETSHAPE
;
332 switch (p
->cursor_shape
& CUR_HWMASK
) {
337 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
339 case CUR_LOWER_THIRD
:
340 cur_height
= vc
->vc_font
.height
/3;
343 cur_height
= vc
->vc_font
.height
>> 1;
346 cur_height
= (vc
->vc_font
.height
<< 1)/3;
350 cur_height
= vc
->vc_font
.height
;
353 size
= (vc
->vc_font
.height
- cur_height
) * w
;
356 size
= cur_height
* w
;
363 ops
->cursor_state
.enable
= 0;
368 ops
->cursor_state
.enable
= (use_sw
) ? 0 : 1;
372 cursor
.image
.data
= src
;
373 cursor
.image
.fg_color
= ops
->cursor_state
.image
.fg_color
;
374 cursor
.image
.bg_color
= ops
->cursor_state
.image
.bg_color
;
375 cursor
.image
.dx
= ops
->cursor_state
.image
.dx
;
376 cursor
.image
.dy
= ops
->cursor_state
.image
.dy
;
377 cursor
.image
.height
= ops
->cursor_state
.image
.height
;
378 cursor
.image
.width
= ops
->cursor_state
.image
.width
;
379 cursor
.hot
.x
= ops
->cursor_state
.hot
.x
;
380 cursor
.hot
.y
= ops
->cursor_state
.hot
.y
;
381 cursor
.mask
= ops
->cursor_state
.mask
;
382 cursor
.enable
= ops
->cursor_state
.enable
;
383 cursor
.image
.depth
= 1;
384 cursor
.rop
= ROP_XOR
;
386 info
->fbops
->fb_cursor(info
, &cursor
);
388 ops
->cursor_reset
= 0;
391 void fbcon_set_bitops(struct fbcon_ops
*ops
)
393 ops
->bmove
= bit_bmove
;
394 ops
->clear
= bit_clear
;
395 ops
->putcs
= bit_putcs
;
396 ops
->clear_margins
= bit_clear_margins
;
397 ops
->cursor
= bit_cursor
;
400 EXPORT_SYMBOL(fbcon_set_bitops
);
402 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
403 MODULE_DESCRIPTION("Bit Blitting Operation");
404 MODULE_LICENSE("GPL");