2 * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 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/config.h>
12 #include <linux/module.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"
25 static inline void cw_update_attr(u8
*dst
, u8
*src
, int attribute
,
28 int i
, j
, offset
= (vc
->vc_font
.height
< 10) ? 1 : 2;
29 int width
= (vc
->vc_font
.height
+ 7) >> 3;
30 u8 c
, t
= 0, msk
= ~(0xff >> offset
);
32 for (i
= 0; i
< vc
->vc_font
.width
; i
++) {
33 for (j
= 0; j
< width
; j
++) {
35 if (attribute
& FBCON_ATTRIBUTE_UNDERLINE
&& !j
)
37 if (attribute
& FBCON_ATTRIBUTE_BOLD
&& i
)
39 if (attribute
& FBCON_ATTRIBUTE_REVERSE
)
49 static void cw_bmove(struct vc_data
*vc
, struct fb_info
*info
, int sy
,
50 int sx
, int dy
, int dx
, int height
, int width
)
52 struct fbcon_ops
*ops
= info
->fbcon_par
;
53 struct fb_copyarea area
;
54 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
56 area
.sx
= vxres
- ((sy
+ height
) * vc
->vc_font
.height
);
57 area
.sy
= sx
* vc
->vc_font
.width
;
58 area
.dx
= vxres
- ((dy
+ height
) * vc
->vc_font
.height
);
59 area
.dy
= dx
* vc
->vc_font
.width
;
60 area
.width
= height
* vc
->vc_font
.height
;
61 area
.height
= width
* vc
->vc_font
.width
;
63 info
->fbops
->fb_copyarea(info
, &area
);
66 static void cw_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 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
74 region
.color
= attr_bgcol_ec(bgshift
,vc
);
75 region
.dx
= vxres
- ((sy
+ height
) * vc
->vc_font
.height
);
76 region
.dy
= sx
* vc
->vc_font
.width
;
77 region
.height
= width
* vc
->vc_font
.width
;
78 region
.width
= height
* vc
->vc_font
.height
;
79 region
.rop
= ROP_COPY
;
81 info
->fbops
->fb_fillrect(info
, ®ion
);
84 static inline void cw_putcs_aligned(struct vc_data
*vc
, struct fb_info
*info
,
85 const u16
*s
, u32 attr
, u32 cnt
,
86 u32 d_pitch
, u32 s_pitch
, u32 cellsize
,
87 struct fb_image
*image
, u8
*buf
, u8
*dst
)
89 struct fbcon_ops
*ops
= info
->fbcon_par
;
90 u16 charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
91 u32 idx
= (vc
->vc_font
.height
+ 7) >> 3;
95 src
= ops
->fontbuffer
+ (scr_readw(s
++) & charmask
)*cellsize
;
98 cw_update_attr(buf
, src
, attr
, vc
);
102 if (likely(idx
== 1))
103 __fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
106 fb_pad_aligned_buffer(dst
, d_pitch
, src
, idx
,
109 dst
+= d_pitch
* vc
->vc_font
.width
;
112 info
->fbops
->fb_imageblit(info
, image
);
115 static void cw_putcs(struct vc_data
*vc
, struct fb_info
*info
,
116 const unsigned short *s
, int count
, int yy
, int xx
,
119 struct fb_image image
;
120 struct fbcon_ops
*ops
= info
->fbcon_par
;
121 u32 width
= (vc
->vc_font
.height
+ 7)/8;
122 u32 cellsize
= width
* vc
->vc_font
.width
;
123 u32 maxcnt
= info
->pixmap
.size
/cellsize
;
124 u32 scan_align
= info
->pixmap
.scan_align
- 1;
125 u32 buf_align
= info
->pixmap
.buf_align
- 1;
126 u32 cnt
, pitch
, size
;
127 u32 attribute
= get_attribute(info
, scr_readw(s
));
128 u8
*dst
, *buf
= NULL
;
129 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
131 if (!ops
->fontbuffer
)
136 image
.dx
= vxres
- ((yy
+ 1) * vc
->vc_font
.height
);
137 image
.dy
= xx
* vc
->vc_font
.width
;
138 image
.width
= vc
->vc_font
.height
;
142 buf
= kmalloc(cellsize
, GFP_KERNEL
);
153 image
.height
= vc
->vc_font
.width
* cnt
;
154 pitch
= ((image
.width
+ 7) >> 3) + scan_align
;
155 pitch
&= ~scan_align
;
156 size
= pitch
* image
.height
+ buf_align
;
158 dst
= fb_get_buffer_offset(info
, &info
->pixmap
, size
);
160 cw_putcs_aligned(vc
, info
, s
, attribute
, cnt
, pitch
,
161 width
, cellsize
, &image
, buf
, dst
);
162 image
.dy
+= image
.height
;
167 /* buf is always NULL except when in monochrome mode, so in this case
168 it's a gain to check buf against NULL even though kfree() handles
169 NULL pointers just fine */
175 static void cw_clear_margins(struct vc_data
*vc
, struct fb_info
*info
,
178 unsigned int cw
= vc
->vc_font
.width
;
179 unsigned int ch
= vc
->vc_font
.height
;
180 unsigned int rw
= info
->var
.yres
- (vc
->vc_cols
*cw
);
181 unsigned int bh
= info
->var
.xres
- (vc
->vc_rows
*ch
);
182 unsigned int rs
= info
->var
.yres
- rw
;
183 struct fb_fillrect region
;
184 int bgshift
= (vc
->vc_hi_font_mask
) ? 13 : 12;
186 region
.color
= attr_bgcol_ec(bgshift
,vc
);
187 region
.rop
= ROP_COPY
;
189 if (rw
&& !bottom_only
) {
191 region
.dy
= info
->var
.yoffset
+ rs
;
193 region
.width
= info
->var
.xres_virtual
;
194 info
->fbops
->fb_fillrect(info
, ®ion
);
198 region
.dx
= info
->var
.xoffset
;
199 region
.dy
= info
->var
.yoffset
;
200 region
.height
= info
->var
.yres
;
202 info
->fbops
->fb_fillrect(info
, ®ion
);
206 static void cw_cursor(struct vc_data
*vc
, struct fb_info
*info
,
207 struct display
*p
, int mode
, int softback_lines
,
210 struct fb_cursor cursor
;
211 struct fbcon_ops
*ops
= (struct fbcon_ops
*) info
->fbcon_par
;
212 unsigned short charmask
= vc
->vc_hi_font_mask
? 0x1ff : 0xff;
213 int w
= (vc
->vc_font
.height
+ 7) >> 3, c
;
214 int y
= real_y(p
, vc
->vc_y
);
215 int attribute
, use_sw
= (vc
->vc_cursor_type
& 0x10);
218 u32 vxres
= GETVXRES(p
->scrollmode
, info
);
220 if (!ops
->fontbuffer
)
225 if (softback_lines
) {
226 if (y
+ softback_lines
>= vc
->vc_rows
) {
228 ops
->cursor_flash
= 0;
234 c
= scr_readw((u16
*) vc
->vc_pos
);
235 attribute
= get_attribute(info
, c
);
236 src
= ops
->fontbuffer
+ ((c
& charmask
) * (w
* vc
->vc_font
.width
));
238 if (ops
->cursor_state
.image
.data
!= src
||
240 ops
->cursor_state
.image
.data
= src
;
241 cursor
.set
|= FB_CUR_SETIMAGE
;
247 dst
= kmalloc(w
* vc
->vc_font
.width
, GFP_ATOMIC
);
250 kfree(ops
->cursor_data
);
251 ops
->cursor_data
= dst
;
252 cw_update_attr(dst
, src
, attribute
, vc
);
256 if (ops
->cursor_state
.image
.fg_color
!= fg
||
257 ops
->cursor_state
.image
.bg_color
!= bg
||
259 ops
->cursor_state
.image
.fg_color
= fg
;
260 ops
->cursor_state
.image
.bg_color
= bg
;
261 cursor
.set
|= FB_CUR_SETCMAP
;
264 if (ops
->cursor_state
.image
.height
!= vc
->vc_font
.width
||
265 ops
->cursor_state
.image
.width
!= vc
->vc_font
.height
||
267 ops
->cursor_state
.image
.height
= vc
->vc_font
.width
;
268 ops
->cursor_state
.image
.width
= vc
->vc_font
.height
;
269 cursor
.set
|= FB_CUR_SETSIZE
;
272 dx
= vxres
- ((y
* vc
->vc_font
.height
) + vc
->vc_font
.height
);
273 dy
= vc
->vc_x
* vc
->vc_font
.width
;
275 if (ops
->cursor_state
.image
.dx
!= dx
||
276 ops
->cursor_state
.image
.dy
!= dy
||
278 ops
->cursor_state
.image
.dx
= dx
;
279 ops
->cursor_state
.image
.dy
= dy
;
280 cursor
.set
|= FB_CUR_SETPOS
;
283 if (ops
->cursor_state
.hot
.x
|| ops
->cursor_state
.hot
.y
||
285 ops
->cursor_state
.hot
.x
= cursor
.hot
.y
= 0;
286 cursor
.set
|= FB_CUR_SETHOT
;
289 if (cursor
.set
& FB_CUR_SETSIZE
||
290 vc
->vc_cursor_type
!= p
->cursor_shape
||
291 ops
->cursor_state
.mask
== NULL
||
293 char *tmp
, *mask
= kmalloc(w
*vc
->vc_font
.width
, GFP_ATOMIC
);
294 int cur_height
, size
, i
= 0;
295 int width
= (vc
->vc_font
.width
+ 7)/8;
300 tmp
= kmalloc(width
* vc
->vc_font
.height
, GFP_ATOMIC
);
307 kfree(ops
->cursor_state
.mask
);
308 ops
->cursor_state
.mask
= mask
;
310 p
->cursor_shape
= vc
->vc_cursor_type
;
311 cursor
.set
|= FB_CUR_SETSHAPE
;
313 switch (p
->cursor_shape
& CUR_HWMASK
) {
318 cur_height
= (vc
->vc_font
.height
< 10) ? 1 : 2;
320 case CUR_LOWER_THIRD
:
321 cur_height
= vc
->vc_font
.height
/3;
324 cur_height
= vc
->vc_font
.height
>> 1;
327 cur_height
= (vc
->vc_font
.height
<< 1)/3;
331 cur_height
= vc
->vc_font
.height
;
335 size
= (vc
->vc_font
.height
- cur_height
) * width
;
338 size
= cur_height
* width
;
341 memset(mask
, 0, w
* vc
->vc_font
.width
);
342 rotate_cw(tmp
, mask
, vc
->vc_font
.width
, vc
->vc_font
.height
);
348 ops
->cursor_state
.enable
= 0;
353 ops
->cursor_state
.enable
= (use_sw
) ? 0 : 1;
357 cursor
.image
.data
= src
;
358 cursor
.image
.fg_color
= ops
->cursor_state
.image
.fg_color
;
359 cursor
.image
.bg_color
= ops
->cursor_state
.image
.bg_color
;
360 cursor
.image
.dx
= ops
->cursor_state
.image
.dx
;
361 cursor
.image
.dy
= ops
->cursor_state
.image
.dy
;
362 cursor
.image
.height
= ops
->cursor_state
.image
.height
;
363 cursor
.image
.width
= ops
->cursor_state
.image
.width
;
364 cursor
.hot
.x
= ops
->cursor_state
.hot
.x
;
365 cursor
.hot
.y
= ops
->cursor_state
.hot
.y
;
366 cursor
.mask
= ops
->cursor_state
.mask
;
367 cursor
.enable
= ops
->cursor_state
.enable
;
368 cursor
.image
.depth
= 1;
369 cursor
.rop
= ROP_XOR
;
371 if (info
->fbops
->fb_cursor
)
372 err
= info
->fbops
->fb_cursor(info
, &cursor
);
375 soft_cursor(info
, &cursor
);
377 ops
->cursor_reset
= 0;
380 int cw_update_start(struct fb_info
*info
)
382 struct fbcon_ops
*ops
= info
->fbcon_par
;
383 u32 vxres
= GETVXRES(ops
->p
->scrollmode
, info
);
387 xoffset
= vxres
- (info
->var
.xres
+ ops
->var
.yoffset
);
388 ops
->var
.yoffset
= ops
->var
.xoffset
;
389 ops
->var
.xoffset
= xoffset
;
390 err
= fb_pan_display(info
, &ops
->var
);
391 ops
->var
.xoffset
= info
->var
.xoffset
;
392 ops
->var
.yoffset
= info
->var
.yoffset
;
393 ops
->var
.vmode
= info
->var
.vmode
;
397 void fbcon_rotate_cw(struct fbcon_ops
*ops
)
399 ops
->bmove
= cw_bmove
;
400 ops
->clear
= cw_clear
;
401 ops
->putcs
= cw_putcs
;
402 ops
->clear_margins
= cw_clear_margins
;
403 ops
->cursor
= cw_cursor
;
404 ops
->update_start
= cw_update_start
;
406 EXPORT_SYMBOL(fbcon_rotate_cw
);
408 MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
409 MODULE_DESCRIPTION("Console Rotation (90 degrees) Support");
410 MODULE_LICENSE("GPL");