2 * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees
4 * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
15 #include <linux/vt_kern.h>
16 #include <linux/console.h>
17 #include <asm/types.h>
19 #include "fbcon_rotate.h"
22 * Rotation 180 degrees
25 static void ud_update_attr(u8
*dst
, u8
*src
, int attribute
,
28 int i
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
29 int width
= (vc
->vc_font
.width
+ 7) >> 3;
30 unsigned int cellsize
= vc
->vc_font
.height
* width
;
33 offset
= offset
* width
;
35 for (i
= 0; i
< cellsize
; i
++) {
37 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
&& i
< offset
)
39 if (attribute
& FBCON_ATTRIBUTE_BOLD
)
41 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
48 static void ud_bmove(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
49 int sx
, int dy
, int dx
, int height
, int width
)
51 struct fbcon_ops
*ops
= info
->fbcon_par
;
52 struct fb_copyarea area
;
53 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
54 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
56 area
.sy
= vyres
- ((sy
+ height
) * vc
->vc_font
.height
);
57 area
.sx
= vxres
- ((sx
+ width
) * vc
->vc_font
.width
);
58 area
.dy
= vyres
- ((dy
+ height
) * vc
->vc_font
.height
);
59 area
.dx
= vxres
- ((dx
+ width
) * vc
->vc_font
.width
);
60 area
.height
= height
* vc
->vc_font
.height
;
61 area
.width
= width
* vc
->vc_font
.width
;
63 info
->fbops
->fb_copyarea(info
, &area
);
66 static void ud_clear(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
67 int sx
, int height
, int width
)
69 struct fbcon_ops
*ops
= info
->fbcon_par
;
70 struct fb_fillrect region
;
71 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
72 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
73 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
75 region
.color
= attr_bgcol_ec(bgshift
,vc
,info
);
76 region
.dy
= vyres
- ((sy
+ height
) * vc
->vc_font
.height
);
77 region
.dx
= vxres
- ((sx
+ width
) * vc
->vc_font
.width
);
78 region
.width
= width
* vc
->vc_font
.width
;
79 region
.height
= height
* vc
->vc_font
.height
;
80 region
.rop
= ROP_COPY
;
82 info
->fbops
->fb_fillrect(info
, ®ion
);
85 static inline void ud_putcs_aligned(struct vc_data
*vc
, struct fb_info
*info
,
86 const u16
*s
, u32 attr
, u32 cnt
,
87 u32 d_pitch
, u32 s_pitch
, u32 cellsize
,
88 struct fb_image
*image
, u8
*buf
, u8
*dst
)
90 struct fbcon_ops
*ops
= info
->fbcon_par
;
91 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
92 u32 idx
= vc
->vc_font
.width
>> 3;
96 src
= ops
->fontbuffer
+ (scr_readw(s
--) & charmask
)*cellsize
;
99 ud_update_attr(buf
, src
, attr
, vc
);
103 if (likely(idx
== 1))
104 __fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
107 fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
113 info
->fbops
->fb_imageblit(info
, image
);
116 static inline void ud_putcs_unaligned(struct vc_data
*vc
,
117 struct fb_info
*info
, const u16
*s
,
118 u32 attr
, u32 cnt
, u32 d_pitch
,
119 u32 s_pitch
, u32 cellsize
,
120 struct fb_image
*image
, u8
*buf
,
123 struct fbcon_ops
*ops
= info
->fbcon_par
;
124 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
125 u32 shift_low
= 0, mod
= vc
->vc_font
.width
% 8;
127 u32 idx
= vc
->vc_font
.width
>> 3;
131 src
= ops
->fontbuffer
+ (scr_readw(s
--) & charmask
)*cellsize
;
134 ud_update_attr(buf
, src
, attr
, vc
);
138 fb_pad_unaligned_buffer(dst
, d_pitch
, src
, idx
,
139 image
->height
, shift_high
,
142 dst
+= (shift_low
>= 8) ? s_pitch
: s_pitch
- 1;
144 shift_high
= 8 - shift_low
;
147 info
->fbops
->fb_imageblit(info
, image
);
151 static void ud_putcs(struct vc_data
*vc
, struct fb_info
*info
,
152 const unsigned short *s
, int count
, int yy
, int xx
,
155 struct fb_image image
;
156 struct fbcon_ops
*ops
= info
->fbcon_par
;
157 u32 width
= (vc
->vc_font
.width
+ 7)/8;
158 u32 cellsize
= width
* vc
->vc_font
.height
;
159 u32 maxcnt
= info
->pixmap
.size
/cellsize
;
160 u32 scan_align
= info
->pixmap
.scan_align
- 1;
161 u32 buf_align
= info
->pixmap
.buf_align
- 1;
162 u32 mod
= vc
->vc_font
.width
% 8, cnt
, pitch
, size
;
163 u32 attribute
= get_attribute(info
, scr_readw(s
));
164 u8
*dst
, *buf
= NULL
;
165 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
166 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
168 if (!ops
->fontbuffer
)
173 image
.dy
= vyres
- ((yy
* vc
->vc_font
.height
) + vc
->vc_font
.height
);
174 image
.dx
= vxres
- ((xx
+ count
) * vc
->vc_font
.width
);
175 image
.height
= vc
->vc_font
.height
;
179 buf
= kmalloc(cellsize
, GFP_KERNEL
);
192 image
.width
= vc
->vc_font
.width
* cnt
;
193 pitch
= ((image
.width
+ 7) >> 3) + scan_align
;
194 pitch
&= ~scan_align
;
195 size
= pitch
* image
.height
+ buf_align
;
197 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
201 ud_putcs_aligned(vc
, info
, s
, attribute
, cnt
, pitch
,
202 width
, cellsize
, &image
, buf
, dst
);
204 ud_putcs_unaligned(vc
, info
, s
, attribute
, cnt
, pitch
,
205 width
, cellsize
, &image
,
208 image
.dx
+= image
.width
;
214 /* buf is always NULL except when in monochrome mode, so in this case
215 it's a gain to check buf against NULL even though kfree() handles
216 NULL pointers just fine */
222 static void ud_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
223 int color
, int bottom_only
)
225 unsigned int cw
= vc
->vc_font
.width
;
226 unsigned int ch
= vc
->vc_font
.height
;
227 unsigned int rw
= info
->var
.xres
- (vc
->vc_cols
*cw
);
228 unsigned int bh
= info
->var
.yres
- (vc
->vc_rows
*ch
);
229 struct fb_fillrect region
;
231 region
.color
= color
;
232 region
.rop
= ROP_COPY
;
234 if (rw
&& !bottom_only
) {
236 region
.dx
= info
->var
.xoffset
;
238 region
.height
= info
->var
.yres_virtual
;
239 info
->fbops
->fb_fillrect(info
, ®ion
);
243 region
.dy
= info
->var
.yoffset
;
244 region
.dx
= info
->var
.xoffset
;
246 region
.width
= info
->var
.xres
;
247 info
->fbops
->fb_fillrect(info
, ®ion
);
251 static void ud_cursor(struct vc_data
*vc
, struct fb_info
*info
, int mode
,
252 int softback_lines
, int fg
, int bg
)
254 struct fb_cursor cursor
;
255 struct fbcon_ops
*ops
= info
->fbcon_par
;
256 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
257 int w
= (vc
->vc_font
.width
+ 7) >> 3, c
;
258 int y
= real_y(ops
->p
, vc
->vc_y
);
259 int attribute
, use_sw
= (vc
->vc_cursor_type
& 0x10);
262 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
263 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
265 if (!ops
->fontbuffer
)
270 if (softback_lines
) {
271 if (y
+ softback_lines
>= vc
->vc_rows
) {
273 ops
->cursor_flash
= 0;
279 c
= scr_readw((u16
*) vc
->vc_pos
);
280 attribute
= get_attribute(info
, c
);
281 src
= ops
->fontbuffer
+ ((c
& charmask
) * (w
* vc
->vc_font
.height
));
283 if (ops
->cursor_state
.image
.data
!= src
||
285 ops
->cursor_state
.image
.data
= src
;
286 cursor
.set
|= FB_CUR_SETIMAGE
;
292 dst
= kmalloc_array(w
, vc
->vc_font
.height
, GFP_ATOMIC
);
295 kfree(ops
->cursor_data
);
296 ops
->cursor_data
= dst
;
297 ud_update_attr(dst
, src
, attribute
, vc
);
301 if (ops
->cursor_state
.image
.fg_color
!= fg
||
302 ops
->cursor_state
.image
.bg_color
!= bg
||
304 ops
->cursor_state
.image
.fg_color
= fg
;
305 ops
->cursor_state
.image
.bg_color
= bg
;
306 cursor
.set
|= FB_CUR_SETCMAP
;
309 if (ops
->cursor_state
.image
.height
!= vc
->vc_font
.height
||
310 ops
->cursor_state
.image
.width
!= vc
->vc_font
.width
||
312 ops
->cursor_state
.image
.height
= vc
->vc_font
.height
;
313 ops
->cursor_state
.image
.width
= vc
->vc_font
.width
;
314 cursor
.set
|= FB_CUR_SETSIZE
;
317 dy
= vyres
- ((y
* vc
->vc_font
.height
) + vc
->vc_font
.height
);
318 dx
= vxres
- ((vc
->vc_x
* vc
->vc_font
.width
) + vc
->vc_font
.width
);
320 if (ops
->cursor_state
.image
.dx
!= dx
||
321 ops
->cursor_state
.image
.dy
!= dy
||
323 ops
->cursor_state
.image
.dx
= dx
;
324 ops
->cursor_state
.image
.dy
= dy
;
325 cursor
.set
|= FB_CUR_SETPOS
;
328 if (ops
->cursor_state
.hot
.x
|| ops
->cursor_state
.hot
.y
||
330 ops
->cursor_state
.hot
.x
= cursor
.hot
.y
= 0;
331 cursor
.set
|= FB_CUR_SETHOT
;
334 if (cursor
.set
& FB_CUR_SETSIZE
||
335 vc
->vc_cursor_type
!= ops
->p
->cursor_shape
||
336 ops
->cursor_state
.mask
== NULL
||
338 char *mask
= kmalloc_array(w
, vc
->vc_font
.height
, GFP_ATOMIC
);
339 int cur_height
, size
, i
= 0;
345 kfree(ops
->cursor_state
.mask
);
346 ops
->cursor_state
.mask
= mask
;
348 ops
->p
->cursor_shape
= vc
->vc_cursor_type
;
349 cursor
.set
|= FB_CUR_SETSHAPE
;
351 switch (ops
->p
->cursor_shape
& CUR_HWMASK
) {
356 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
358 case CUR_LOWER_THIRD
:
359 cur_height
= vc
->vc_font
.height
/3;
362 cur_height
= vc
->vc_font
.height
>> 1;
365 cur_height
= (vc
->vc_font
.height
<< 1)/3;
369 cur_height
= vc
->vc_font
.height
;
373 size
= cur_height
* w
;
378 size
= (vc
->vc_font
.height
- cur_height
) * w
;
386 ops
->cursor_state
.enable
= 0;
391 ops
->cursor_state
.enable
= (use_sw
) ? 0 : 1;
395 cursor
.image
.data
= src
;
396 cursor
.image
.fg_color
= ops
->cursor_state
.image
.fg_color
;
397 cursor
.image
.bg_color
= ops
->cursor_state
.image
.bg_color
;
398 cursor
.image
.dx
= ops
->cursor_state
.image
.dx
;
399 cursor
.image
.dy
= ops
->cursor_state
.image
.dy
;
400 cursor
.image
.height
= ops
->cursor_state
.image
.height
;
401 cursor
.image
.width
= ops
->cursor_state
.image
.width
;
402 cursor
.hot
.x
= ops
->cursor_state
.hot
.x
;
403 cursor
.hot
.y
= ops
->cursor_state
.hot
.y
;
404 cursor
.mask
= ops
->cursor_state
.mask
;
405 cursor
.enable
= ops
->cursor_state
.enable
;
406 cursor
.image
.depth
= 1;
407 cursor
.rop
= ROP_XOR
;
409 if (info
->fbops
->fb_cursor
)
410 err
= info
->fbops
->fb_cursor(info
, &cursor
);
413 soft_cursor(info
, &cursor
);
415 ops
->cursor_reset
= 0;
418 static int ud_update_start(struct fb_info
*info
)
420 struct fbcon_ops
*ops
= info
->fbcon_par
;
421 int xoffset
, yoffset
;
422 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
423 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
426 xoffset
= vxres
- info
->var
.xres
- ops
->var
.xoffset
;
427 yoffset
= vyres
- info
->var
.yres
- ops
->var
.yoffset
;
430 ops
->var
.xoffset
= xoffset
;
431 ops
->var
.yoffset
= yoffset
;
432 err
= fb_pan_display(info
, &ops
->var
);
433 ops
->var
.xoffset
= info
->var
.xoffset
;
434 ops
->var
.yoffset
= info
->var
.yoffset
;
435 ops
->var
.vmode
= info
->var
.vmode
;
439 void fbcon_rotate_ud(struct fbcon_ops
*ops
)
441 ops
->bmove
= ud_bmove
;
442 ops
->clear
= ud_clear
;
443 ops
->putcs
= ud_putcs
;
444 ops
->clear_margins
= ud_clear_margins
;
445 ops
->cursor
= ud_cursor
;
446 ops
->update_start
= ud_update_start
;
448 EXPORT_SYMBOL(fbcon_rotate_ud
);