2 * linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 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/string.h>
14 #include <linux/vt_kern.h>
15 #include <linux/console.h>
16 #include <asm/types.h>
18 #include "fbcon_rotate.h"
21 * Rotation 270 degrees
24 static inline void ccw_update_attr(u8
*dst
, u8
*src
, int attribute
,
27 int i
, j
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
28 int width
= (vc
->vc_font
.height
+ 7) >> 3;
29 int mod
= vc
->vc_font
.height
% 8;
30 u8 c
, msk
= ~(0xff << offset
), msk1
= 0;
38 for (i
= 0; i
< vc
->vc_font
.width
; i
++) {
39 for (j
= 0; j
< width
; j
++) {
42 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
) {
46 if (msk1
&& j
== width
- 2)
50 if (attribute
& FBCON_ATTRIBUTE_BOLD
&& i
)
53 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
62 static void ccw_bmove(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
63 int sx
, int dy
, int dx
, int height
, int width
)
65 struct fbcon_ops
*ops
= info
->fbcon_par
;
66 struct fb_copyarea area
;
67 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
69 area
.sx
= sy
* vc
->vc_font
.height
;
70 area
.sy
= vyres
- ((sx
+ width
) * vc
->vc_font
.width
);
71 area
.dx
= dy
* vc
->vc_font
.height
;
72 area
.dy
= vyres
- ((dx
+ width
) * vc
->vc_font
.width
);
73 area
.width
= height
* vc
->vc_font
.height
;
74 area
.height
= width
* vc
->vc_font
.width
;
76 info
->fbops
->fb_copyarea(info
, &area
);
79 static void ccw_clear(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
80 int sx
, int height
, int width
)
82 struct fbcon_ops
*ops
= info
->fbcon_par
;
83 struct fb_fillrect region
;
84 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
85 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
87 region
.color
= attr_bgcol_ec(bgshift
,vc
);
88 region
.dx
= sy
* vc
->vc_font
.height
;
89 region
.dy
= vyres
- ((sx
+ width
) * vc
->vc_font
.width
);
90 region
.height
= width
* vc
->vc_font
.width
;
91 region
.width
= height
* vc
->vc_font
.height
;
92 region
.rop
= ROP_COPY
;
94 info
->fbops
->fb_fillrect(info
, ®ion
);
97 static inline void ccw_putcs_aligned(struct vc_data
*vc
, struct fb_info
*info
,
98 const u16
*s
, u32 attr
, u32 cnt
,
99 u32 d_pitch
, u32 s_pitch
, u32 cellsize
,
100 struct fb_image
*image
, u8
*buf
, u8
*dst
)
102 struct fbcon_ops
*ops
= info
->fbcon_par
;
103 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
104 u32 idx
= (vc
->vc_font
.height
+ 7) >> 3;
108 src
= ops
->fontbuffer
+ (scr_readw(s
--) & charmask
)*cellsize
;
111 ccw_update_attr(buf
, src
, attr
, vc
);
115 if (likely(idx
== 1))
116 __fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
119 fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
122 dst
+= d_pitch
* vc
->vc_font
.width
;
125 info
->fbops
->fb_imageblit(info
, image
);
128 static void ccw_putcs(struct vc_data
*vc
, struct fb_info
*info
,
129 const unsigned short *s
, int count
, int yy
, int xx
,
132 struct fb_image image
;
133 struct fbcon_ops
*ops
= info
->fbcon_par
;
134 u32 width
= (vc
->vc_font
.height
+ 7)/8;
135 u32 cellsize
= width
* vc
->vc_font
.width
;
136 u32 maxcnt
= info
->pixmap
.size
/cellsize
;
137 u32 scan_align
= info
->pixmap
.scan_align
- 1;
138 u32 buf_align
= info
->pixmap
.buf_align
- 1;
139 u32 cnt
, pitch
, size
;
140 u32 attribute
= get_attribute(info
, scr_readw(s
));
141 u8
*dst
, *buf
= NULL
;
142 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
144 if (!ops
->fontbuffer
)
149 image
.dx
= yy
* vc
->vc_font
.height
;
150 image
.dy
= vyres
- ((xx
+ count
) * vc
->vc_font
.width
);
151 image
.width
= vc
->vc_font
.height
;
155 buf
= kmalloc(cellsize
, GFP_KERNEL
);
168 image
.height
= vc
->vc_font
.width
* cnt
;
169 pitch
= ((image
.width
+ 7) >> 3) + scan_align
;
170 pitch
&= ~scan_align
;
171 size
= pitch
* image
.height
+ buf_align
;
173 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
175 ccw_putcs_aligned(vc
, info
, s
, attribute
, cnt
, pitch
,
176 width
, cellsize
, &image
, buf
, dst
);
177 image
.dy
+= image
.height
;
182 /* buf is always NULL except when in monochrome mode, so in this case
183 it's a gain to check buf against NULL even though kfree() handles
184 NULL pointers just fine */
190 static void ccw_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
193 unsigned int cw
= vc
->vc_font
.width
;
194 unsigned int ch
= vc
->vc_font
.height
;
195 unsigned int rw
= info
->var
.yres
- (vc
->vc_cols
*cw
);
196 unsigned int bh
= info
->var
.xres
- (vc
->vc_rows
*ch
);
197 unsigned int bs
= vc
->vc_rows
*ch
;
198 struct fb_fillrect region
;
199 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
201 region
.color
= attr_bgcol_ec(bgshift
,vc
);
202 region
.rop
= ROP_COPY
;
204 if (rw
&& !bottom_only
) {
206 region
.dy
= info
->var
.yoffset
;
208 region
.width
= info
->var
.xres_virtual
;
209 info
->fbops
->fb_fillrect(info
, ®ion
);
213 region
.dx
= info
->var
.xoffset
+ bs
;
215 region
.height
= info
->var
.yres_virtual
;
217 info
->fbops
->fb_fillrect(info
, ®ion
);
221 static void ccw_cursor(struct vc_data
*vc
, struct fb_info
*info
, int mode
,
222 int softback_lines
, int fg
, int bg
)
224 struct fb_cursor cursor
;
225 struct fbcon_ops
*ops
= info
->fbcon_par
;
226 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
227 int w
= (vc
->vc_font
.height
+ 7) >> 3, c
;
228 int y
= real_y(ops
->p
, vc
->vc_y
);
229 int attribute
, use_sw
= (vc
->vc_cursor_type
& 0x10);
232 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
234 if (!ops
->fontbuffer
)
239 if (softback_lines
) {
240 if (y
+ softback_lines
>= vc
->vc_rows
) {
242 ops
->cursor_flash
= 0;
248 c
= scr_readw((u16
*) vc
->vc_pos
);
249 attribute
= get_attribute(info
, c
);
250 src
= ops
->fontbuffer
+ ((c
& charmask
) * (w
* vc
->vc_font
.width
));
252 if (ops
->cursor_state
.image
.data
!= src
||
254 ops
->cursor_state
.image
.data
= src
;
255 cursor
.set
|= FB_CUR_SETIMAGE
;
261 dst
= kmalloc(w
* vc
->vc_font
.width
, GFP_ATOMIC
);
264 kfree(ops
->cursor_data
);
265 ops
->cursor_data
= dst
;
266 ccw_update_attr(dst
, src
, attribute
, vc
);
270 if (ops
->cursor_state
.image
.fg_color
!= fg
||
271 ops
->cursor_state
.image
.bg_color
!= bg
||
273 ops
->cursor_state
.image
.fg_color
= fg
;
274 ops
->cursor_state
.image
.bg_color
= bg
;
275 cursor
.set
|= FB_CUR_SETCMAP
;
278 if (ops
->cursor_state
.image
.height
!= vc
->vc_font
.width
||
279 ops
->cursor_state
.image
.width
!= vc
->vc_font
.height
||
281 ops
->cursor_state
.image
.height
= vc
->vc_font
.width
;
282 ops
->cursor_state
.image
.width
= vc
->vc_font
.height
;
283 cursor
.set
|= FB_CUR_SETSIZE
;
286 dx
= y
* vc
->vc_font
.height
;
287 dy
= vyres
- ((vc
->vc_x
+ 1) * vc
->vc_font
.width
);
289 if (ops
->cursor_state
.image
.dx
!= dx
||
290 ops
->cursor_state
.image
.dy
!= dy
||
292 ops
->cursor_state
.image
.dx
= dx
;
293 ops
->cursor_state
.image
.dy
= dy
;
294 cursor
.set
|= FB_CUR_SETPOS
;
297 if (ops
->cursor_state
.hot
.x
|| ops
->cursor_state
.hot
.y
||
299 ops
->cursor_state
.hot
.x
= cursor
.hot
.y
= 0;
300 cursor
.set
|= FB_CUR_SETHOT
;
303 if (cursor
.set
& FB_CUR_SETSIZE
||
304 vc
->vc_cursor_type
!= ops
->p
->cursor_shape
||
305 ops
->cursor_state
.mask
== NULL
||
307 char *tmp
, *mask
= kmalloc(w
*vc
->vc_font
.width
, GFP_ATOMIC
);
308 int cur_height
, size
, i
= 0;
309 int width
= (vc
->vc_font
.width
+ 7)/8;
314 tmp
= kmalloc(width
* vc
->vc_font
.height
, GFP_ATOMIC
);
321 kfree(ops
->cursor_state
.mask
);
322 ops
->cursor_state
.mask
= mask
;
324 ops
->p
->cursor_shape
= vc
->vc_cursor_type
;
325 cursor
.set
|= FB_CUR_SETSHAPE
;
327 switch (ops
->p
->cursor_shape
& CUR_HWMASK
) {
332 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
334 case CUR_LOWER_THIRD
:
335 cur_height
= vc
->vc_font
.height
/3;
338 cur_height
= vc
->vc_font
.height
>> 1;
341 cur_height
= (vc
->vc_font
.height
<< 1)/3;
345 cur_height
= vc
->vc_font
.height
;
349 size
= (vc
->vc_font
.height
- cur_height
) * width
;
352 size
= cur_height
* width
;
355 memset(mask
, 0, w
* vc
->vc_font
.width
);
356 rotate_ccw(tmp
, mask
, vc
->vc_font
.width
, vc
->vc_font
.height
);
362 ops
->cursor_state
.enable
= 0;
367 ops
->cursor_state
.enable
= (use_sw
) ? 0 : 1;
371 cursor
.image
.data
= src
;
372 cursor
.image
.fg_color
= ops
->cursor_state
.image
.fg_color
;
373 cursor
.image
.bg_color
= ops
->cursor_state
.image
.bg_color
;
374 cursor
.image
.dx
= ops
->cursor_state
.image
.dx
;
375 cursor
.image
.dy
= ops
->cursor_state
.image
.dy
;
376 cursor
.image
.height
= ops
->cursor_state
.image
.height
;
377 cursor
.image
.width
= ops
->cursor_state
.image
.width
;
378 cursor
.hot
.x
= ops
->cursor_state
.hot
.x
;
379 cursor
.hot
.y
= ops
->cursor_state
.hot
.y
;
380 cursor
.mask
= ops
->cursor_state
.mask
;
381 cursor
.enable
= ops
->cursor_state
.enable
;
382 cursor
.image
.depth
= 1;
383 cursor
.rop
= ROP_XOR
;
385 if (info
->fbops
->fb_cursor
)
386 err
= info
->fbops
->fb_cursor(info
, &cursor
);
389 soft_cursor(info
, &cursor
);
391 ops
->cursor_reset
= 0;
394 int ccw_update_start(struct fb_info
*info
)
396 struct fbcon_ops
*ops
= info
->fbcon_par
;
398 u32 vyres
= GETVYRES(ops
->p
->scrollmode
, info
);
401 yoffset
= (vyres
- info
->var
.yres
) - ops
->var
.xoffset
;
402 ops
->var
.xoffset
= ops
->var
.yoffset
;
403 ops
->var
.yoffset
= yoffset
;
404 err
= fb_pan_display(info
, &ops
->var
);
405 ops
->var
.xoffset
= info
->var
.xoffset
;
406 ops
->var
.yoffset
= info
->var
.yoffset
;
407 ops
->var
.vmode
= info
->var
.vmode
;
411 void fbcon_rotate_ccw(struct fbcon_ops
*ops
)
413 ops
->bmove
= ccw_bmove
;
414 ops
->clear
= ccw_clear
;
415 ops
->putcs
= ccw_putcs
;
416 ops
->clear_margins
= ccw_clear_margins
;
417 ops
->cursor
= ccw_cursor
;
418 ops
->update_start
= ccw_update_start
;
420 EXPORT_SYMBOL(fbcon_rotate_ccw
);
422 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
423 MODULE_DESCRIPTION("Console Rotation (270 degrees) Support");
424 MODULE_LICENSE("GPL");