16104c370SDaniel Vetter /*
26104c370SDaniel Vetter  *  linux/drivers/video/console/fbcon_rotate.c -- Software Rotation
36104c370SDaniel Vetter  *
46104c370SDaniel Vetter  *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
56104c370SDaniel Vetter  *
66104c370SDaniel Vetter  *  This file is subject to the terms and conditions of the GNU General Public
76104c370SDaniel Vetter  *  License.  See the file COPYING in the main directory of this archive for
86104c370SDaniel Vetter  *  more details.
96104c370SDaniel Vetter  */
106104c370SDaniel Vetter 
116104c370SDaniel Vetter #include <linux/module.h>
126104c370SDaniel Vetter #include <linux/slab.h>
136104c370SDaniel Vetter #include <linux/string.h>
146104c370SDaniel Vetter #include <linux/fb.h>
156104c370SDaniel Vetter #include <linux/vt_kern.h>
166104c370SDaniel Vetter #include <linux/console.h>
176104c370SDaniel Vetter #include <asm/types.h>
186104c370SDaniel Vetter #include "fbcon.h"
196104c370SDaniel Vetter #include "fbcon_rotate.h"
206104c370SDaniel Vetter 
fbcon_rotate_font(struct fb_info * info,struct vc_data * vc)216104c370SDaniel Vetter static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
226104c370SDaniel Vetter {
236104c370SDaniel Vetter 	struct fbcon_ops *ops = info->fbcon_par;
246104c370SDaniel Vetter 	int len, err = 0;
256104c370SDaniel Vetter 	int s_cellsize, d_cellsize, i;
266104c370SDaniel Vetter 	const u8 *src;
276104c370SDaniel Vetter 	u8 *dst;
286104c370SDaniel Vetter 
296104c370SDaniel Vetter 	if (vc->vc_font.data == ops->fontdata &&
306104c370SDaniel Vetter 	    ops->p->con_rotate == ops->cur_rotate)
316104c370SDaniel Vetter 		goto finished;
326104c370SDaniel Vetter 
336104c370SDaniel Vetter 	src = ops->fontdata = vc->vc_font.data;
346104c370SDaniel Vetter 	ops->cur_rotate = ops->p->con_rotate;
35*a1ac250aSPeilin Ye 	len = vc->vc_font.charcount;
366104c370SDaniel Vetter 	s_cellsize = ((vc->vc_font.width + 7)/8) *
376104c370SDaniel Vetter 		vc->vc_font.height;
386104c370SDaniel Vetter 	d_cellsize = s_cellsize;
396104c370SDaniel Vetter 
406104c370SDaniel Vetter 	if (ops->rotate == FB_ROTATE_CW ||
416104c370SDaniel Vetter 	    ops->rotate == FB_ROTATE_CCW)
426104c370SDaniel Vetter 		d_cellsize = ((vc->vc_font.height + 7)/8) *
436104c370SDaniel Vetter 			vc->vc_font.width;
446104c370SDaniel Vetter 
456104c370SDaniel Vetter 	if (info->fbops->fb_sync)
466104c370SDaniel Vetter 		info->fbops->fb_sync(info);
476104c370SDaniel Vetter 
486104c370SDaniel Vetter 	if (ops->fd_size < d_cellsize * len) {
496da2ec56SKees Cook 		dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
506104c370SDaniel Vetter 
516104c370SDaniel Vetter 		if (dst == NULL) {
526104c370SDaniel Vetter 			err = -ENOMEM;
536104c370SDaniel Vetter 			goto finished;
546104c370SDaniel Vetter 		}
556104c370SDaniel Vetter 
566104c370SDaniel Vetter 		ops->fd_size = d_cellsize * len;
576104c370SDaniel Vetter 		kfree(ops->fontbuffer);
586104c370SDaniel Vetter 		ops->fontbuffer = dst;
596104c370SDaniel Vetter 	}
606104c370SDaniel Vetter 
616104c370SDaniel Vetter 	dst = ops->fontbuffer;
626104c370SDaniel Vetter 	memset(dst, 0, ops->fd_size);
636104c370SDaniel Vetter 
646104c370SDaniel Vetter 	switch (ops->rotate) {
656104c370SDaniel Vetter 	case FB_ROTATE_UD:
666104c370SDaniel Vetter 		for (i = len; i--; ) {
676104c370SDaniel Vetter 			rotate_ud(src, dst, vc->vc_font.width,
686104c370SDaniel Vetter 				  vc->vc_font.height);
696104c370SDaniel Vetter 
706104c370SDaniel Vetter 			src += s_cellsize;
716104c370SDaniel Vetter 			dst += d_cellsize;
726104c370SDaniel Vetter 		}
736104c370SDaniel Vetter 		break;
746104c370SDaniel Vetter 	case FB_ROTATE_CW:
756104c370SDaniel Vetter 		for (i = len; i--; ) {
766104c370SDaniel Vetter 			rotate_cw(src, dst, vc->vc_font.width,
776104c370SDaniel Vetter 				  vc->vc_font.height);
786104c370SDaniel Vetter 			src += s_cellsize;
796104c370SDaniel Vetter 			dst += d_cellsize;
806104c370SDaniel Vetter 		}
816104c370SDaniel Vetter 		break;
826104c370SDaniel Vetter 	case FB_ROTATE_CCW:
836104c370SDaniel Vetter 		for (i = len; i--; ) {
846104c370SDaniel Vetter 			rotate_ccw(src, dst, vc->vc_font.width,
856104c370SDaniel Vetter 				   vc->vc_font.height);
866104c370SDaniel Vetter 			src += s_cellsize;
876104c370SDaniel Vetter 			dst += d_cellsize;
886104c370SDaniel Vetter 		}
896104c370SDaniel Vetter 		break;
906104c370SDaniel Vetter 	}
916104c370SDaniel Vetter 
926104c370SDaniel Vetter finished:
936104c370SDaniel Vetter 	return err;
946104c370SDaniel Vetter }
956104c370SDaniel Vetter 
fbcon_set_rotate(struct fbcon_ops * ops)966104c370SDaniel Vetter void fbcon_set_rotate(struct fbcon_ops *ops)
976104c370SDaniel Vetter {
986104c370SDaniel Vetter 	ops->rotate_font = fbcon_rotate_font;
996104c370SDaniel Vetter 
1006104c370SDaniel Vetter 	switch(ops->rotate) {
1016104c370SDaniel Vetter 	case FB_ROTATE_CW:
1026104c370SDaniel Vetter 		fbcon_rotate_cw(ops);
1036104c370SDaniel Vetter 		break;
1046104c370SDaniel Vetter 	case FB_ROTATE_UD:
1056104c370SDaniel Vetter 		fbcon_rotate_ud(ops);
1066104c370SDaniel Vetter 		break;
1076104c370SDaniel Vetter 	case FB_ROTATE_CCW:
1086104c370SDaniel Vetter 		fbcon_rotate_ccw(ops);
1096104c370SDaniel Vetter 		break;
1106104c370SDaniel Vetter 	}
1116104c370SDaniel Vetter }
112