Merge tag 'fbdev-v4.14' of git://github.com/bzolnier/linux
Pull fbdev updates from Bartlomiej Zolnierkiewicz: - make fbcon a built-time depency for fbdev (fbcon was tristate option before, now it is a bool) - this is a first step in preparations for making console_lock usage saner (currently it acts like the BKL for all things fbdev/fbcon) (Daniel Vetter) - add fbcon=margin:<color> command line option to select the fbcon margin color (David Lechner) - add DMI quirk table for x86 systems which need fbcon rotation (devices like Asus T100HA, GPD Pocket, the GPD win and the I.T.Works TW891) (Hans de Goede) - fix 1bpp logo support for unusual width (needed by LEGO MINDSTORMS EV3) (David Lechner) - enable Xilinx FB driver for ARM ZynqMP platform (Michal Simek) - fix use after free in the error path of udlfb driver (Anton Vasilyev) - fix error return code handling in pxa3xx_gcu driver (Gustavo A. R. Silva) - fix bootparams.screeninfo arguments checking in vgacon (Jan H. Schönherr) - do not leak uninitialized padding in clk to userspace in the debug code of atyfb driver (Vladis Dronov) - fix compiler warnings in fbcon code and matroxfb driver (Arnd Bergmann) - convert fbdev susbsytem to using %pOF instead of full_name (Rob Herring) - structures constifications (Arvind Yadav, Bhumika Goyal, Gustavo A. R. Silva, Julia Lawall) - misc cleanups (Gustavo A. R. Silva, Hyun Kwon, Julia Lawall, Kuninori Morimoto, Lynn Lei) * tag 'fbdev-v4.14' of git://github.com/bzolnier/linux: (75 commits) video/console: Update BIOS dates list for GPD win console rotation DMI quirk video/console: Add rotated LCD-panel DMI quirk for the VIOS LTH17 video: fbdev: sis: fix duplicated code for different branches video: fbdev: make fb_var_screeninfo const video: fbdev: aty: do not leak uninitialized padding in clk to userspace vgacon: Prevent faulty bootparams.screeninfo from causing harm video: fbdev: make fb_videomode const video/console: Add new BIOS date for GPD pocket to dmi quirk table fbcon: remove restriction on margin color video: ARM CLCD: constify amba_id video: fm2fb: constify zorro_device_id video: fbdev: annotate fb_fix_screeninfo with const and __initconst omapfb: constify omap_video_timings structures video: fbdev: udlfb: Fix use after free on dlfb_usb_probe error path fbdev: i810: make fb_ops const fbdev: matrox: make fb_ops const video: fbdev: pxa3xx_gcu: fix error return code in pxa3xx_gcu_probe() video: fbdev: Enable Xilinx FB for ZynqMP video: fbdev: Fix multiple style issues in xilinxfb video: fbdev: udlfb: constify usb_device_id. ...
This commit is contained in:
@@ -117,7 +117,7 @@ config DUMMY_CONSOLE_ROWS
|
||||
Select 25 if you use a 640x480 resolution by default.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE
|
||||
tristate "Framebuffer Console support"
|
||||
bool "Framebuffer Console support"
|
||||
depends on FB && !UML
|
||||
select VT_HW_CONSOLE_BINDING
|
||||
select CRC32
|
||||
|
@@ -7,13 +7,5 @@ obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
|
||||
obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o
|
||||
obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
|
||||
obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
|
||||
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o softcursor.o
|
||||
ifeq ($(CONFIG_FB_TILEBLITTING),y)
|
||||
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o
|
||||
endif
|
||||
ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y)
|
||||
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
|
||||
fbcon_ccw.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_FB_STI) += sticore.o
|
||||
|
@@ -1,422 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/bitblit.c -- BitBlitting Operation
|
||||
*
|
||||
* Originally from the 'accel_*' routines in drivers/video/console/fbcon.c
|
||||
*
|
||||
* Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
|
||||
/*
|
||||
* Accelerated handlers.
|
||||
*/
|
||||
static void update_attr(u8 *dst, u8 *src, int attribute,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
int width = DIV_ROUND_UP(vc->vc_font.width, 8);
|
||||
unsigned int cellsize = vc->vc_font.height * width;
|
||||
u8 c;
|
||||
|
||||
offset = cellsize - (offset * width);
|
||||
for (i = 0; i < cellsize; i++) {
|
||||
c = src[i];
|
||||
if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i >= offset)
|
||||
c = 0xff;
|
||||
if (attribute & FBCON_ATTRIBUTE_BOLD)
|
||||
c |= c >> 1;
|
||||
if (attribute & FBCON_ATTRIBUTE_REVERSE)
|
||||
c = ~c;
|
||||
dst[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fb_copyarea area;
|
||||
|
||||
area.sx = sx * vc->vc_font.width;
|
||||
area.sy = sy * vc->vc_font.height;
|
||||
area.dx = dx * vc->vc_font.width;
|
||||
area.dy = dy * vc->vc_font.height;
|
||||
area.height = height * vc->vc_font.height;
|
||||
area.width = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
struct fb_fillrect region;
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift, vc, info);
|
||||
region.dx = sx * vc->vc_font.width;
|
||||
region.dy = sy * vc->vc_font.height;
|
||||
region.width = width * vc->vc_font.width;
|
||||
region.height = height * vc->vc_font.height;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info,
|
||||
const u16 *s, u32 attr, u32 cnt,
|
||||
u32 d_pitch, u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf, u8 *dst)
|
||||
{
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 idx = vc->vc_font.width >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = vc->vc_font.data + (scr_readw(s++)&
|
||||
charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
if (likely(idx == 1))
|
||||
__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height);
|
||||
else
|
||||
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height);
|
||||
|
||||
dst += s_pitch;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
}
|
||||
|
||||
static inline void bit_putcs_unaligned(struct vc_data *vc,
|
||||
struct fb_info *info, const u16 *s,
|
||||
u32 attr, u32 cnt, u32 d_pitch,
|
||||
u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf,
|
||||
u8 *dst)
|
||||
{
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 shift_low = 0, mod = vc->vc_font.width % 8;
|
||||
u32 shift_high = 8;
|
||||
u32 idx = vc->vc_font.width >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = vc->vc_font.data + (scr_readw(s++)&
|
||||
charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height, shift_high,
|
||||
shift_low, mod);
|
||||
shift_low += mod;
|
||||
dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
|
||||
shift_low &= 7;
|
||||
shift_high = 8 - shift_low;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
|
||||
}
|
||||
|
||||
static void bit_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg)
|
||||
{
|
||||
struct fb_image image;
|
||||
u32 width = DIV_ROUND_UP(vc->vc_font.width, 8);
|
||||
u32 cellsize = width * vc->vc_font.height;
|
||||
u32 maxcnt = info->pixmap.size/cellsize;
|
||||
u32 scan_align = info->pixmap.scan_align - 1;
|
||||
u32 buf_align = info->pixmap.buf_align - 1;
|
||||
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
|
||||
image.fg_color = fg;
|
||||
image.bg_color = bg;
|
||||
image.dx = xx * vc->vc_font.width;
|
||||
image.dy = yy * vc->vc_font.height;
|
||||
image.height = vc->vc_font.height;
|
||||
image.depth = 1;
|
||||
|
||||
if (attribute) {
|
||||
buf = kmalloc(cellsize, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
if (count > maxcnt)
|
||||
cnt = maxcnt;
|
||||
else
|
||||
cnt = count;
|
||||
|
||||
image.width = vc->vc_font.width * cnt;
|
||||
pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
|
||||
pitch &= ~scan_align;
|
||||
size = pitch * image.height + buf_align;
|
||||
size &= ~buf_align;
|
||||
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
image.data = dst;
|
||||
|
||||
if (!mod)
|
||||
bit_putcs_aligned(vc, info, s, attribute, cnt, pitch,
|
||||
width, cellsize, &image, buf, dst);
|
||||
else
|
||||
bit_putcs_unaligned(vc, info, s, attribute, cnt,
|
||||
pitch, width, cellsize, &image,
|
||||
buf, dst);
|
||||
|
||||
image.dx += cnt * vc->vc_font.width;
|
||||
count -= cnt;
|
||||
s += cnt;
|
||||
}
|
||||
|
||||
/* buf is always NULL except when in monochrome mode, so in this case
|
||||
it's a gain to check buf against NULL even though kfree() handles
|
||||
NULL pointers just fine */
|
||||
if (unlikely(buf))
|
||||
kfree(buf);
|
||||
|
||||
}
|
||||
|
||||
static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only)
|
||||
{
|
||||
unsigned int cw = vc->vc_font.width;
|
||||
unsigned int ch = vc->vc_font.height;
|
||||
unsigned int rw = info->var.xres - (vc->vc_cols*cw);
|
||||
unsigned int bh = info->var.yres - (vc->vc_rows*ch);
|
||||
unsigned int rs = info->var.xres - rw;
|
||||
unsigned int bs = info->var.yres - bh;
|
||||
struct fb_fillrect region;
|
||||
|
||||
region.color = 0;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
if (rw && !bottom_only) {
|
||||
region.dx = info->var.xoffset + rs;
|
||||
region.dy = 0;
|
||||
region.width = rw;
|
||||
region.height = info->var.yres_virtual;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
if (bh) {
|
||||
region.dx = info->var.xoffset;
|
||||
region.dy = info->var.yoffset + bs;
|
||||
region.width = rs;
|
||||
region.height = bh;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
|
||||
int y = real_y(ops->p, vc->vc_y);
|
||||
int attribute, use_sw = (vc->vc_cursor_type & 0x10);
|
||||
int err = 1;
|
||||
char *src;
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
if (softback_lines) {
|
||||
if (y + softback_lines >= vc->vc_rows) {
|
||||
mode = CM_ERASE;
|
||||
ops->cursor_flash = 0;
|
||||
return;
|
||||
} else
|
||||
y += softback_lines;
|
||||
}
|
||||
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
|
||||
|
||||
if (ops->cursor_state.image.data != src ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.data = src;
|
||||
cursor.set |= FB_CUR_SETIMAGE;
|
||||
}
|
||||
|
||||
if (attribute) {
|
||||
u8 *dst;
|
||||
|
||||
dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
|
||||
if (!dst)
|
||||
return;
|
||||
kfree(ops->cursor_data);
|
||||
ops->cursor_data = dst;
|
||||
update_attr(dst, src, attribute, vc);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.fg_color != fg ||
|
||||
ops->cursor_state.image.bg_color != bg ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.fg_color = fg;
|
||||
ops->cursor_state.image.bg_color = bg;
|
||||
cursor.set |= FB_CUR_SETCMAP;
|
||||
}
|
||||
|
||||
if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->vc_x)) ||
|
||||
(ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.dx = vc->vc_font.width * vc->vc_x;
|
||||
ops->cursor_state.image.dy = vc->vc_font.height * y;
|
||||
cursor.set |= FB_CUR_SETPOS;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.height != vc->vc_font.height ||
|
||||
ops->cursor_state.image.width != vc->vc_font.width ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.height = vc->vc_font.height;
|
||||
ops->cursor_state.image.width = vc->vc_font.width;
|
||||
cursor.set |= FB_CUR_SETSIZE;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.hot.x = cursor.hot.y = 0;
|
||||
cursor.set |= FB_CUR_SETHOT;
|
||||
}
|
||||
|
||||
if (cursor.set & FB_CUR_SETSIZE ||
|
||||
vc->vc_cursor_type != ops->p->cursor_shape ||
|
||||
ops->cursor_state.mask == NULL ||
|
||||
ops->cursor_reset) {
|
||||
char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
|
||||
int cur_height, size, i = 0;
|
||||
u8 msk = 0xff;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
kfree(ops->cursor_state.mask);
|
||||
ops->cursor_state.mask = mask;
|
||||
|
||||
ops->p->cursor_shape = vc->vc_cursor_type;
|
||||
cursor.set |= FB_CUR_SETSHAPE;
|
||||
|
||||
switch (ops->p->cursor_shape & CUR_HWMASK) {
|
||||
case CUR_NONE:
|
||||
cur_height = 0;
|
||||
break;
|
||||
case CUR_UNDERLINE:
|
||||
cur_height = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
cur_height = vc->vc_font.height/3;
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
cur_height = vc->vc_font.height >> 1;
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
cur_height = (vc->vc_font.height << 1)/3;
|
||||
break;
|
||||
case CUR_BLOCK:
|
||||
default:
|
||||
cur_height = vc->vc_font.height;
|
||||
break;
|
||||
}
|
||||
size = (vc->vc_font.height - cur_height) * w;
|
||||
while (size--)
|
||||
mask[i++] = ~msk;
|
||||
size = cur_height * w;
|
||||
while (size--)
|
||||
mask[i++] = msk;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
ops->cursor_state.enable = 0;
|
||||
break;
|
||||
case CM_DRAW:
|
||||
case CM_MOVE:
|
||||
default:
|
||||
ops->cursor_state.enable = (use_sw) ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.image.data = src;
|
||||
cursor.image.fg_color = ops->cursor_state.image.fg_color;
|
||||
cursor.image.bg_color = ops->cursor_state.image.bg_color;
|
||||
cursor.image.dx = ops->cursor_state.image.dx;
|
||||
cursor.image.dy = ops->cursor_state.image.dy;
|
||||
cursor.image.height = ops->cursor_state.image.height;
|
||||
cursor.image.width = ops->cursor_state.image.width;
|
||||
cursor.hot.x = ops->cursor_state.hot.x;
|
||||
cursor.hot.y = ops->cursor_state.hot.y;
|
||||
cursor.mask = ops->cursor_state.mask;
|
||||
cursor.enable = ops->cursor_state.enable;
|
||||
cursor.image.depth = 1;
|
||||
cursor.rop = ROP_XOR;
|
||||
|
||||
if (info->fbops->fb_cursor)
|
||||
err = info->fbops->fb_cursor(info, &cursor);
|
||||
|
||||
if (err)
|
||||
soft_cursor(info, &cursor);
|
||||
|
||||
ops->cursor_reset = 0;
|
||||
}
|
||||
|
||||
static int bit_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int err;
|
||||
|
||||
err = fb_pan_display(info, &ops->var);
|
||||
ops->var.xoffset = info->var.xoffset;
|
||||
ops->var.yoffset = info->var.yoffset;
|
||||
ops->var.vmode = info->var.vmode;
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_set_bitops(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = bit_bmove;
|
||||
ops->clear = bit_clear;
|
||||
ops->putcs = bit_putcs;
|
||||
ops->clear_margins = bit_clear_margins;
|
||||
ops->cursor = bit_cursor;
|
||||
ops->update_start = bit_update_start;
|
||||
ops->rotate_font = NULL;
|
||||
|
||||
if (ops->rotate)
|
||||
fbcon_set_rotate(ops);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fbcon_set_bitops);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Bit Blitting Operation");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon.h -- Low level frame buffer based console driver
|
||||
*
|
||||
* Copyright (C) 1997 Geert Uytterhoeven
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef _VIDEO_FBCON_H
|
||||
#define _VIDEO_FBCON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/vt_buffer.h>
|
||||
#include <linux/vt_kern.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#define FBCON_FLAGS_INIT 1
|
||||
#define FBCON_FLAGS_CURSOR_TIMER 2
|
||||
|
||||
/*
|
||||
* This is the interface between the low-level console driver and the
|
||||
* low-level frame buffer device
|
||||
*/
|
||||
|
||||
struct display {
|
||||
/* Filled in by the low-level console driver */
|
||||
const u_char *fontdata;
|
||||
int userfont; /* != 0 if fontdata kmalloc()ed */
|
||||
u_short scrollmode; /* Scroll Method */
|
||||
u_short inverse; /* != 0 text black on white as default */
|
||||
short yscroll; /* Hardware scrolling */
|
||||
int vrows; /* number of virtual rows */
|
||||
int cursor_shape;
|
||||
int con_rotate;
|
||||
u32 xres_virtual;
|
||||
u32 yres_virtual;
|
||||
u32 height;
|
||||
u32 width;
|
||||
u32 bits_per_pixel;
|
||||
u32 grayscale;
|
||||
u32 nonstd;
|
||||
u32 accel_flags;
|
||||
u32 rotate;
|
||||
struct fb_bitfield red;
|
||||
struct fb_bitfield green;
|
||||
struct fb_bitfield blue;
|
||||
struct fb_bitfield transp;
|
||||
const struct fb_videomode *mode;
|
||||
};
|
||||
|
||||
struct fbcon_ops {
|
||||
void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width);
|
||||
void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width);
|
||||
void (*putcs)(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg);
|
||||
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only);
|
||||
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg);
|
||||
int (*update_start)(struct fb_info *info);
|
||||
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
|
||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
||||
struct timer_list cursor_timer; /* Cursor timer */
|
||||
struct fb_cursor cursor_state;
|
||||
struct display *p;
|
||||
int currcon; /* Current VC. */
|
||||
int cur_blink_jiffies;
|
||||
int cursor_flash;
|
||||
int cursor_reset;
|
||||
int blank_state;
|
||||
int graphics;
|
||||
int save_graphics; /* for debug enter/leave */
|
||||
int flags;
|
||||
int rotate;
|
||||
int cur_rotate;
|
||||
char *cursor_data;
|
||||
u8 *fontbuffer;
|
||||
u8 *fontdata;
|
||||
u8 *cursor_src;
|
||||
u32 cursor_size;
|
||||
u32 fd_size;
|
||||
};
|
||||
/*
|
||||
* Attribute Decoding
|
||||
*/
|
||||
|
||||
/* Color */
|
||||
#define attr_fgcol(fgshift,s) \
|
||||
(((s) >> (fgshift)) & 0x0f)
|
||||
#define attr_bgcol(bgshift,s) \
|
||||
(((s) >> (bgshift)) & 0x0f)
|
||||
|
||||
/* Monochrome */
|
||||
#define attr_bold(s) \
|
||||
((s) & 0x200)
|
||||
#define attr_reverse(s) \
|
||||
((s) & 0x800)
|
||||
#define attr_underline(s) \
|
||||
((s) & 0x400)
|
||||
#define attr_blink(s) \
|
||||
((s) & 0x8000)
|
||||
|
||||
|
||||
static inline int mono_col(const struct fb_info *info)
|
||||
{
|
||||
__u32 max_len;
|
||||
max_len = max(info->var.green.length, info->var.red.length);
|
||||
max_len = max(info->var.blue.length, max_len);
|
||||
return (~(0xfff << max_len)) & 0xff;
|
||||
}
|
||||
|
||||
static inline int attr_col_ec(int shift, struct vc_data *vc,
|
||||
struct fb_info *info, int is_fg)
|
||||
{
|
||||
int is_mono01;
|
||||
int col;
|
||||
int fg;
|
||||
int bg;
|
||||
|
||||
if (!vc)
|
||||
return 0;
|
||||
|
||||
if (vc->vc_can_do_color)
|
||||
return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char)
|
||||
: attr_bgcol(shift,vc->vc_video_erase_char);
|
||||
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
col = mono_col(info);
|
||||
is_mono01 = info->fix.visual == FB_VISUAL_MONO01;
|
||||
|
||||
if (attr_reverse(vc->vc_video_erase_char)) {
|
||||
fg = is_mono01 ? col : 0;
|
||||
bg = is_mono01 ? 0 : col;
|
||||
}
|
||||
else {
|
||||
fg = is_mono01 ? 0 : col;
|
||||
bg = is_mono01 ? col : 0;
|
||||
}
|
||||
|
||||
return is_fg ? fg : bg;
|
||||
}
|
||||
|
||||
#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
|
||||
#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
|
||||
|
||||
/* Font */
|
||||
#define REFCOUNT(fd) (((int *)(fd))[-1])
|
||||
#define FNTSIZE(fd) (((int *)(fd))[-2])
|
||||
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
|
||||
#define FNTSUM(fd) (((int *)(fd))[-4])
|
||||
#define FONT_EXTRA_WORDS 4
|
||||
|
||||
/*
|
||||
* Scroll Method
|
||||
*/
|
||||
|
||||
/* There are several methods fbcon can use to move text around the screen:
|
||||
*
|
||||
* Operation Pan Wrap
|
||||
*---------------------------------------------
|
||||
* SCROLL_MOVE copyarea No No
|
||||
* SCROLL_PAN_MOVE copyarea Yes No
|
||||
* SCROLL_WRAP_MOVE copyarea No Yes
|
||||
* SCROLL_REDRAW imageblit No No
|
||||
* SCROLL_PAN_REDRAW imageblit Yes No
|
||||
* SCROLL_WRAP_REDRAW imageblit No Yes
|
||||
*
|
||||
* (SCROLL_WRAP_REDRAW is not implemented yet)
|
||||
*
|
||||
* In general, fbcon will choose the best scrolling
|
||||
* method based on the rule below:
|
||||
*
|
||||
* Pan/Wrap > accel imageblit > accel copyarea >
|
||||
* soft imageblit > (soft copyarea)
|
||||
*
|
||||
* Exception to the rule: Pan + accel copyarea is
|
||||
* preferred over Pan + accel imageblit.
|
||||
*
|
||||
* The above is typical for PCI/AGP cards. Unless
|
||||
* overridden, fbcon will never use soft copyarea.
|
||||
*
|
||||
* If you need to override the above rule, set the
|
||||
* appropriate flags in fb_info->flags. For example,
|
||||
* to prefer copyarea over imageblit, set
|
||||
* FBINFO_READS_FAST.
|
||||
*
|
||||
* Other notes:
|
||||
* + use the hardware engine to move the text
|
||||
* (hw-accelerated copyarea() and fillrect())
|
||||
* + use hardware-supported panning on a large virtual screen
|
||||
* + amifb can not only pan, but also wrap the display by N lines
|
||||
* (i.e. visible line i = physical line (i+N) % yres).
|
||||
* + read what's already rendered on the screen and
|
||||
* write it in a different place (this is cfb_copyarea())
|
||||
* + re-render the text to the screen
|
||||
*
|
||||
* Whether to use wrapping or panning can only be figured out at
|
||||
* runtime (when we know whether our font height is a multiple
|
||||
* of the pan/wrap step)
|
||||
*
|
||||
*/
|
||||
|
||||
#define SCROLL_MOVE 0x001
|
||||
#define SCROLL_PAN_MOVE 0x002
|
||||
#define SCROLL_WRAP_MOVE 0x003
|
||||
#define SCROLL_REDRAW 0x004
|
||||
#define SCROLL_PAN_REDRAW 0x005
|
||||
|
||||
#ifdef CONFIG_FB_TILEBLITTING
|
||||
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
|
||||
#endif
|
||||
extern void fbcon_set_bitops(struct fbcon_ops *ops);
|
||||
extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
|
||||
|
||||
#define FBCON_ATTRIBUTE_UNDERLINE 1
|
||||
#define FBCON_ATTRIBUTE_REVERSE 2
|
||||
#define FBCON_ATTRIBUTE_BOLD 4
|
||||
|
||||
static inline int real_y(struct display *p, int ypos)
|
||||
{
|
||||
int rows = p->vrows;
|
||||
|
||||
ypos += p->yscroll;
|
||||
return ypos < rows ? ypos : ypos - rows;
|
||||
}
|
||||
|
||||
|
||||
static inline int get_attribute(struct fb_info *info, u16 c)
|
||||
{
|
||||
int attribute = 0;
|
||||
|
||||
if (fb_get_color_depth(&info->var, &info->fix) == 1) {
|
||||
if (attr_underline(c))
|
||||
attribute |= FBCON_ATTRIBUTE_UNDERLINE;
|
||||
if (attr_reverse(c))
|
||||
attribute |= FBCON_ATTRIBUTE_REVERSE;
|
||||
if (attr_bold(c))
|
||||
attribute |= FBCON_ATTRIBUTE_BOLD;
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
#define FBCON_SWAP(i,r,v) ({ \
|
||||
typeof(r) _r = (r); \
|
||||
typeof(v) _v = (v); \
|
||||
(void) (&_r == &_v); \
|
||||
(i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
|
||||
|
||||
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
|
||||
extern void fbcon_set_rotate(struct fbcon_ops *ops);
|
||||
#else
|
||||
#define fbcon_set_rotate(x) do {} while(0)
|
||||
#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
|
||||
|
||||
#endif /* _VIDEO_FBCON_H */
|
||||
|
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
#include "fbcon_rotate.h"
|
||||
|
||||
/*
|
||||
* Rotation 270 degrees
|
||||
*/
|
||||
|
||||
static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
int width = (vc->vc_font.height + 7) >> 3;
|
||||
int mod = vc->vc_font.height % 8;
|
||||
u8 c, msk = ~(0xff << offset), msk1 = 0;
|
||||
|
||||
if (mod)
|
||||
msk <<= (8 - mod);
|
||||
|
||||
if (offset > mod)
|
||||
msk1 |= 0x01;
|
||||
|
||||
for (i = 0; i < vc->vc_font.width; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
c = *src;
|
||||
|
||||
if (attribute & FBCON_ATTRIBUTE_UNDERLINE) {
|
||||
if (j == width - 1)
|
||||
c |= msk;
|
||||
|
||||
if (msk1 && j == width - 2)
|
||||
c |= msk1;
|
||||
}
|
||||
|
||||
if (attribute & FBCON_ATTRIBUTE_BOLD && i)
|
||||
*(dst - width) |= c;
|
||||
|
||||
if (attribute & FBCON_ATTRIBUTE_REVERSE)
|
||||
c = ~c;
|
||||
src++;
|
||||
*dst++ = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
|
||||
area.sx = sy * vc->vc_font.height;
|
||||
area.sy = vyres - ((sx + width) * vc->vc_font.width);
|
||||
area.dx = dy * vc->vc_font.height;
|
||||
area.dy = vyres - ((dx + width) * vc->vc_font.width);
|
||||
area.width = height * vc->vc_font.height;
|
||||
area.height = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dx = sy * vc->vc_font.height;
|
||||
region.dy = vyres - ((sx + width) * vc->vc_font.width);
|
||||
region.height = width * vc->vc_font.width;
|
||||
region.width = height * vc->vc_font.height;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
|
||||
const u16 *s, u32 attr, u32 cnt,
|
||||
u32 d_pitch, u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf, u8 *dst)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 idx = (vc->vc_font.height + 7) >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
ccw_update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
if (likely(idx == 1))
|
||||
__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
vc->vc_font.width);
|
||||
else
|
||||
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
vc->vc_font.width);
|
||||
|
||||
dst += d_pitch * vc->vc_font.width;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
}
|
||||
|
||||
static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg)
|
||||
{
|
||||
struct fb_image image;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 width = (vc->vc_font.height + 7)/8;
|
||||
u32 cellsize = width * vc->vc_font.width;
|
||||
u32 maxcnt = info->pixmap.size/cellsize;
|
||||
u32 scan_align = info->pixmap.scan_align - 1;
|
||||
u32 buf_align = info->pixmap.buf_align - 1;
|
||||
u32 cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
image.fg_color = fg;
|
||||
image.bg_color = bg;
|
||||
image.dx = yy * vc->vc_font.height;
|
||||
image.dy = vyres - ((xx + count) * vc->vc_font.width);
|
||||
image.width = vc->vc_font.height;
|
||||
image.depth = 1;
|
||||
|
||||
if (attribute) {
|
||||
buf = kmalloc(cellsize, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
}
|
||||
|
||||
s += count - 1;
|
||||
|
||||
while (count) {
|
||||
if (count > maxcnt)
|
||||
cnt = maxcnt;
|
||||
else
|
||||
cnt = count;
|
||||
|
||||
image.height = vc->vc_font.width * cnt;
|
||||
pitch = ((image.width + 7) >> 3) + scan_align;
|
||||
pitch &= ~scan_align;
|
||||
size = pitch * image.height + buf_align;
|
||||
size &= ~buf_align;
|
||||
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
image.data = dst;
|
||||
ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
|
||||
width, cellsize, &image, buf, dst);
|
||||
image.dy += image.height;
|
||||
count -= cnt;
|
||||
s -= cnt;
|
||||
}
|
||||
|
||||
/* buf is always NULL except when in monochrome mode, so in this case
|
||||
it's a gain to check buf against NULL even though kfree() handles
|
||||
NULL pointers just fine */
|
||||
if (unlikely(buf))
|
||||
kfree(buf);
|
||||
|
||||
}
|
||||
|
||||
static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only)
|
||||
{
|
||||
unsigned int cw = vc->vc_font.width;
|
||||
unsigned int ch = vc->vc_font.height;
|
||||
unsigned int rw = info->var.yres - (vc->vc_cols*cw);
|
||||
unsigned int bh = info->var.xres - (vc->vc_rows*ch);
|
||||
unsigned int bs = vc->vc_rows*ch;
|
||||
struct fb_fillrect region;
|
||||
|
||||
region.color = 0;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
if (rw && !bottom_only) {
|
||||
region.dx = 0;
|
||||
region.dy = info->var.yoffset;
|
||||
region.height = rw;
|
||||
region.width = info->var.xres_virtual;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
if (bh) {
|
||||
region.dx = info->var.xoffset + bs;
|
||||
region.dy = 0;
|
||||
region.height = info->var.yres_virtual;
|
||||
region.width = bh;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
int w = (vc->vc_font.height + 7) >> 3, c;
|
||||
int y = real_y(ops->p, vc->vc_y);
|
||||
int attribute, use_sw = (vc->vc_cursor_type & 0x10);
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
if (softback_lines) {
|
||||
if (y + softback_lines >= vc->vc_rows) {
|
||||
mode = CM_ERASE;
|
||||
ops->cursor_flash = 0;
|
||||
return;
|
||||
} else
|
||||
y += softback_lines;
|
||||
}
|
||||
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
|
||||
if (ops->cursor_state.image.data != src ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.data = src;
|
||||
cursor.set |= FB_CUR_SETIMAGE;
|
||||
}
|
||||
|
||||
if (attribute) {
|
||||
u8 *dst;
|
||||
|
||||
dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
|
||||
if (!dst)
|
||||
return;
|
||||
kfree(ops->cursor_data);
|
||||
ops->cursor_data = dst;
|
||||
ccw_update_attr(dst, src, attribute, vc);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.fg_color != fg ||
|
||||
ops->cursor_state.image.bg_color != bg ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.fg_color = fg;
|
||||
ops->cursor_state.image.bg_color = bg;
|
||||
cursor.set |= FB_CUR_SETCMAP;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.height != vc->vc_font.width ||
|
||||
ops->cursor_state.image.width != vc->vc_font.height ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.height = vc->vc_font.width;
|
||||
ops->cursor_state.image.width = vc->vc_font.height;
|
||||
cursor.set |= FB_CUR_SETSIZE;
|
||||
}
|
||||
|
||||
dx = y * vc->vc_font.height;
|
||||
dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width);
|
||||
|
||||
if (ops->cursor_state.image.dx != dx ||
|
||||
ops->cursor_state.image.dy != dy ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.dx = dx;
|
||||
ops->cursor_state.image.dy = dy;
|
||||
cursor.set |= FB_CUR_SETPOS;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.hot.x = cursor.hot.y = 0;
|
||||
cursor.set |= FB_CUR_SETHOT;
|
||||
}
|
||||
|
||||
if (cursor.set & FB_CUR_SETSIZE ||
|
||||
vc->vc_cursor_type != ops->p->cursor_shape ||
|
||||
ops->cursor_state.mask == NULL ||
|
||||
ops->cursor_reset) {
|
||||
char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
|
||||
int cur_height, size, i = 0;
|
||||
int width = (vc->vc_font.width + 7)/8;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
|
||||
|
||||
if (!tmp) {
|
||||
kfree(mask);
|
||||
return;
|
||||
}
|
||||
|
||||
kfree(ops->cursor_state.mask);
|
||||
ops->cursor_state.mask = mask;
|
||||
|
||||
ops->p->cursor_shape = vc->vc_cursor_type;
|
||||
cursor.set |= FB_CUR_SETSHAPE;
|
||||
|
||||
switch (ops->p->cursor_shape & CUR_HWMASK) {
|
||||
case CUR_NONE:
|
||||
cur_height = 0;
|
||||
break;
|
||||
case CUR_UNDERLINE:
|
||||
cur_height = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
cur_height = vc->vc_font.height/3;
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
cur_height = vc->vc_font.height >> 1;
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
cur_height = (vc->vc_font.height << 1)/3;
|
||||
break;
|
||||
case CUR_BLOCK:
|
||||
default:
|
||||
cur_height = vc->vc_font.height;
|
||||
break;
|
||||
}
|
||||
|
||||
size = (vc->vc_font.height - cur_height) * width;
|
||||
while (size--)
|
||||
tmp[i++] = 0;
|
||||
size = cur_height * width;
|
||||
while (size--)
|
||||
tmp[i++] = 0xff;
|
||||
memset(mask, 0, w * vc->vc_font.width);
|
||||
rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
|
||||
kfree(tmp);
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
ops->cursor_state.enable = 0;
|
||||
break;
|
||||
case CM_DRAW:
|
||||
case CM_MOVE:
|
||||
default:
|
||||
ops->cursor_state.enable = (use_sw) ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.image.data = src;
|
||||
cursor.image.fg_color = ops->cursor_state.image.fg_color;
|
||||
cursor.image.bg_color = ops->cursor_state.image.bg_color;
|
||||
cursor.image.dx = ops->cursor_state.image.dx;
|
||||
cursor.image.dy = ops->cursor_state.image.dy;
|
||||
cursor.image.height = ops->cursor_state.image.height;
|
||||
cursor.image.width = ops->cursor_state.image.width;
|
||||
cursor.hot.x = ops->cursor_state.hot.x;
|
||||
cursor.hot.y = ops->cursor_state.hot.y;
|
||||
cursor.mask = ops->cursor_state.mask;
|
||||
cursor.enable = ops->cursor_state.enable;
|
||||
cursor.image.depth = 1;
|
||||
cursor.rop = ROP_XOR;
|
||||
|
||||
if (info->fbops->fb_cursor)
|
||||
err = info->fbops->fb_cursor(info, &cursor);
|
||||
|
||||
if (err)
|
||||
soft_cursor(info, &cursor);
|
||||
|
||||
ops->cursor_reset = 0;
|
||||
}
|
||||
|
||||
static int ccw_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 yoffset;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
int err;
|
||||
|
||||
yoffset = (vyres - info->var.yres) - ops->var.xoffset;
|
||||
ops->var.xoffset = ops->var.yoffset;
|
||||
ops->var.yoffset = yoffset;
|
||||
err = fb_pan_display(info, &ops->var);
|
||||
ops->var.xoffset = info->var.xoffset;
|
||||
ops->var.yoffset = info->var.yoffset;
|
||||
ops->var.vmode = info->var.vmode;
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_rotate_ccw(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = ccw_bmove;
|
||||
ops->clear = ccw_clear;
|
||||
ops->putcs = ccw_putcs;
|
||||
ops->clear_margins = ccw_clear_margins;
|
||||
ops->cursor = ccw_cursor;
|
||||
ops->update_start = ccw_update_start;
|
||||
}
|
||||
EXPORT_SYMBOL(fbcon_rotate_ccw);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Console Rotation (270 degrees) Support");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,407 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
#include "fbcon_rotate.h"
|
||||
|
||||
/*
|
||||
* Rotation 90 degrees
|
||||
*/
|
||||
|
||||
static void cw_update_attr(u8 *dst, u8 *src, int attribute,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
int width = (vc->vc_font.height + 7) >> 3;
|
||||
u8 c, msk = ~(0xff >> offset);
|
||||
|
||||
for (i = 0; i < vc->vc_font.width; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
c = *src;
|
||||
if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
|
||||
c |= msk;
|
||||
if (attribute & FBCON_ATTRIBUTE_BOLD && i)
|
||||
c |= *(src-width);
|
||||
if (attribute & FBCON_ATTRIBUTE_REVERSE)
|
||||
c = ~c;
|
||||
src++;
|
||||
*dst++ = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
area.sx = vxres - ((sy + height) * vc->vc_font.height);
|
||||
area.sy = sx * vc->vc_font.width;
|
||||
area.dx = vxres - ((dy + height) * vc->vc_font.height);
|
||||
area.dy = dx * vc->vc_font.width;
|
||||
area.width = height * vc->vc_font.height;
|
||||
area.height = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dx = vxres - ((sy + height) * vc->vc_font.height);
|
||||
region.dy = sx * vc->vc_font.width;
|
||||
region.height = width * vc->vc_font.width;
|
||||
region.width = height * vc->vc_font.height;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
|
||||
const u16 *s, u32 attr, u32 cnt,
|
||||
u32 d_pitch, u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf, u8 *dst)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 idx = (vc->vc_font.height + 7) >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
cw_update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
if (likely(idx == 1))
|
||||
__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
vc->vc_font.width);
|
||||
else
|
||||
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
vc->vc_font.width);
|
||||
|
||||
dst += d_pitch * vc->vc_font.width;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
}
|
||||
|
||||
static void cw_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg)
|
||||
{
|
||||
struct fb_image image;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 width = (vc->vc_font.height + 7)/8;
|
||||
u32 cellsize = width * vc->vc_font.width;
|
||||
u32 maxcnt = info->pixmap.size/cellsize;
|
||||
u32 scan_align = info->pixmap.scan_align - 1;
|
||||
u32 buf_align = info->pixmap.buf_align - 1;
|
||||
u32 cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
image.fg_color = fg;
|
||||
image.bg_color = bg;
|
||||
image.dx = vxres - ((yy + 1) * vc->vc_font.height);
|
||||
image.dy = xx * vc->vc_font.width;
|
||||
image.width = vc->vc_font.height;
|
||||
image.depth = 1;
|
||||
|
||||
if (attribute) {
|
||||
buf = kmalloc(cellsize, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
}
|
||||
|
||||
while (count) {
|
||||
if (count > maxcnt)
|
||||
cnt = maxcnt;
|
||||
else
|
||||
cnt = count;
|
||||
|
||||
image.height = vc->vc_font.width * cnt;
|
||||
pitch = ((image.width + 7) >> 3) + scan_align;
|
||||
pitch &= ~scan_align;
|
||||
size = pitch * image.height + buf_align;
|
||||
size &= ~buf_align;
|
||||
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
image.data = dst;
|
||||
cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
|
||||
width, cellsize, &image, buf, dst);
|
||||
image.dy += image.height;
|
||||
count -= cnt;
|
||||
s += cnt;
|
||||
}
|
||||
|
||||
/* buf is always NULL except when in monochrome mode, so in this case
|
||||
it's a gain to check buf against NULL even though kfree() handles
|
||||
NULL pointers just fine */
|
||||
if (unlikely(buf))
|
||||
kfree(buf);
|
||||
|
||||
}
|
||||
|
||||
static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only)
|
||||
{
|
||||
unsigned int cw = vc->vc_font.width;
|
||||
unsigned int ch = vc->vc_font.height;
|
||||
unsigned int rw = info->var.yres - (vc->vc_cols*cw);
|
||||
unsigned int bh = info->var.xres - (vc->vc_rows*ch);
|
||||
unsigned int rs = info->var.yres - rw;
|
||||
struct fb_fillrect region;
|
||||
|
||||
region.color = 0;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
if (rw && !bottom_only) {
|
||||
region.dx = 0;
|
||||
region.dy = info->var.yoffset + rs;
|
||||
region.height = rw;
|
||||
region.width = info->var.xres_virtual;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
if (bh) {
|
||||
region.dx = info->var.xoffset;
|
||||
region.dy = info->var.yoffset;
|
||||
region.height = info->var.yres;
|
||||
region.width = bh;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
int w = (vc->vc_font.height + 7) >> 3, c;
|
||||
int y = real_y(ops->p, vc->vc_y);
|
||||
int attribute, use_sw = (vc->vc_cursor_type & 0x10);
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
if (softback_lines) {
|
||||
if (y + softback_lines >= vc->vc_rows) {
|
||||
mode = CM_ERASE;
|
||||
ops->cursor_flash = 0;
|
||||
return;
|
||||
} else
|
||||
y += softback_lines;
|
||||
}
|
||||
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
|
||||
if (ops->cursor_state.image.data != src ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.data = src;
|
||||
cursor.set |= FB_CUR_SETIMAGE;
|
||||
}
|
||||
|
||||
if (attribute) {
|
||||
u8 *dst;
|
||||
|
||||
dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
|
||||
if (!dst)
|
||||
return;
|
||||
kfree(ops->cursor_data);
|
||||
ops->cursor_data = dst;
|
||||
cw_update_attr(dst, src, attribute, vc);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.fg_color != fg ||
|
||||
ops->cursor_state.image.bg_color != bg ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.fg_color = fg;
|
||||
ops->cursor_state.image.bg_color = bg;
|
||||
cursor.set |= FB_CUR_SETCMAP;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.height != vc->vc_font.width ||
|
||||
ops->cursor_state.image.width != vc->vc_font.height ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.height = vc->vc_font.width;
|
||||
ops->cursor_state.image.width = vc->vc_font.height;
|
||||
cursor.set |= FB_CUR_SETSIZE;
|
||||
}
|
||||
|
||||
dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
|
||||
dy = vc->vc_x * vc->vc_font.width;
|
||||
|
||||
if (ops->cursor_state.image.dx != dx ||
|
||||
ops->cursor_state.image.dy != dy ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.dx = dx;
|
||||
ops->cursor_state.image.dy = dy;
|
||||
cursor.set |= FB_CUR_SETPOS;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.hot.x = cursor.hot.y = 0;
|
||||
cursor.set |= FB_CUR_SETHOT;
|
||||
}
|
||||
|
||||
if (cursor.set & FB_CUR_SETSIZE ||
|
||||
vc->vc_cursor_type != ops->p->cursor_shape ||
|
||||
ops->cursor_state.mask == NULL ||
|
||||
ops->cursor_reset) {
|
||||
char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
|
||||
int cur_height, size, i = 0;
|
||||
int width = (vc->vc_font.width + 7)/8;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
|
||||
|
||||
if (!tmp) {
|
||||
kfree(mask);
|
||||
return;
|
||||
}
|
||||
|
||||
kfree(ops->cursor_state.mask);
|
||||
ops->cursor_state.mask = mask;
|
||||
|
||||
ops->p->cursor_shape = vc->vc_cursor_type;
|
||||
cursor.set |= FB_CUR_SETSHAPE;
|
||||
|
||||
switch (ops->p->cursor_shape & CUR_HWMASK) {
|
||||
case CUR_NONE:
|
||||
cur_height = 0;
|
||||
break;
|
||||
case CUR_UNDERLINE:
|
||||
cur_height = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
cur_height = vc->vc_font.height/3;
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
cur_height = vc->vc_font.height >> 1;
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
cur_height = (vc->vc_font.height << 1)/3;
|
||||
break;
|
||||
case CUR_BLOCK:
|
||||
default:
|
||||
cur_height = vc->vc_font.height;
|
||||
break;
|
||||
}
|
||||
|
||||
size = (vc->vc_font.height - cur_height) * width;
|
||||
while (size--)
|
||||
tmp[i++] = 0;
|
||||
size = cur_height * width;
|
||||
while (size--)
|
||||
tmp[i++] = 0xff;
|
||||
memset(mask, 0, w * vc->vc_font.width);
|
||||
rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
|
||||
kfree(tmp);
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
ops->cursor_state.enable = 0;
|
||||
break;
|
||||
case CM_DRAW:
|
||||
case CM_MOVE:
|
||||
default:
|
||||
ops->cursor_state.enable = (use_sw) ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.image.data = src;
|
||||
cursor.image.fg_color = ops->cursor_state.image.fg_color;
|
||||
cursor.image.bg_color = ops->cursor_state.image.bg_color;
|
||||
cursor.image.dx = ops->cursor_state.image.dx;
|
||||
cursor.image.dy = ops->cursor_state.image.dy;
|
||||
cursor.image.height = ops->cursor_state.image.height;
|
||||
cursor.image.width = ops->cursor_state.image.width;
|
||||
cursor.hot.x = ops->cursor_state.hot.x;
|
||||
cursor.hot.y = ops->cursor_state.hot.y;
|
||||
cursor.mask = ops->cursor_state.mask;
|
||||
cursor.enable = ops->cursor_state.enable;
|
||||
cursor.image.depth = 1;
|
||||
cursor.rop = ROP_XOR;
|
||||
|
||||
if (info->fbops->fb_cursor)
|
||||
err = info->fbops->fb_cursor(info, &cursor);
|
||||
|
||||
if (err)
|
||||
soft_cursor(info, &cursor);
|
||||
|
||||
ops->cursor_reset = 0;
|
||||
}
|
||||
|
||||
static int cw_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
u32 xoffset;
|
||||
int err;
|
||||
|
||||
xoffset = vxres - (info->var.xres + ops->var.yoffset);
|
||||
ops->var.yoffset = ops->var.xoffset;
|
||||
ops->var.xoffset = xoffset;
|
||||
err = fb_pan_display(info, &ops->var);
|
||||
ops->var.xoffset = info->var.xoffset;
|
||||
ops->var.yoffset = info->var.yoffset;
|
||||
ops->var.vmode = info->var.vmode;
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_rotate_cw(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = cw_bmove;
|
||||
ops->clear = cw_clear;
|
||||
ops->putcs = cw_putcs;
|
||||
ops->clear_margins = cw_clear_margins;
|
||||
ops->cursor = cw_cursor;
|
||||
ops->update_start = cw_update_start;
|
||||
}
|
||||
EXPORT_SYMBOL(fbcon_rotate_cw);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Console Rotation (90 degrees) Support");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon_rotate.c -- Software Rotation
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
#include "fbcon_rotate.h"
|
||||
|
||||
static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int len, err = 0;
|
||||
int s_cellsize, d_cellsize, i;
|
||||
const u8 *src;
|
||||
u8 *dst;
|
||||
|
||||
if (vc->vc_font.data == ops->fontdata &&
|
||||
ops->p->con_rotate == ops->cur_rotate)
|
||||
goto finished;
|
||||
|
||||
src = ops->fontdata = vc->vc_font.data;
|
||||
ops->cur_rotate = ops->p->con_rotate;
|
||||
len = (!ops->p->userfont) ? 256 : FNTCHARCNT(src);
|
||||
s_cellsize = ((vc->vc_font.width + 7)/8) *
|
||||
vc->vc_font.height;
|
||||
d_cellsize = s_cellsize;
|
||||
|
||||
if (ops->rotate == FB_ROTATE_CW ||
|
||||
ops->rotate == FB_ROTATE_CCW)
|
||||
d_cellsize = ((vc->vc_font.height + 7)/8) *
|
||||
vc->vc_font.width;
|
||||
|
||||
if (info->fbops->fb_sync)
|
||||
info->fbops->fb_sync(info);
|
||||
|
||||
if (ops->fd_size < d_cellsize * len) {
|
||||
dst = kmalloc(d_cellsize * len, GFP_KERNEL);
|
||||
|
||||
if (dst == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
ops->fd_size = d_cellsize * len;
|
||||
kfree(ops->fontbuffer);
|
||||
ops->fontbuffer = dst;
|
||||
}
|
||||
|
||||
dst = ops->fontbuffer;
|
||||
memset(dst, 0, ops->fd_size);
|
||||
|
||||
switch (ops->rotate) {
|
||||
case FB_ROTATE_UD:
|
||||
for (i = len; i--; ) {
|
||||
rotate_ud(src, dst, vc->vc_font.width,
|
||||
vc->vc_font.height);
|
||||
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
case FB_ROTATE_CW:
|
||||
for (i = len; i--; ) {
|
||||
rotate_cw(src, dst, vc->vc_font.width,
|
||||
vc->vc_font.height);
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
case FB_ROTATE_CCW:
|
||||
for (i = len; i--; ) {
|
||||
rotate_ccw(src, dst, vc->vc_font.width,
|
||||
vc->vc_font.height);
|
||||
src += s_cellsize;
|
||||
dst += d_cellsize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
finished:
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_set_rotate(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->rotate_font = fbcon_rotate_font;
|
||||
|
||||
switch(ops->rotate) {
|
||||
case FB_ROTATE_CW:
|
||||
fbcon_rotate_cw(ops);
|
||||
break;
|
||||
case FB_ROTATE_UD:
|
||||
fbcon_rotate_ud(ops);
|
||||
break;
|
||||
case FB_ROTATE_CCW:
|
||||
fbcon_rotate_ccw(ops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(fbcon_set_rotate);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Console Rotation Support");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FBCON_ROTATE_H
|
||||
#define _FBCON_ROTATE_H
|
||||
|
||||
#define GETVYRES(s,i) ({ \
|
||||
(s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
|
||||
(i)->var.yres : (i)->var.yres_virtual; })
|
||||
|
||||
#define GETVXRES(s,i) ({ \
|
||||
(s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
|
||||
(i)->var.xres : (i)->var.xres_virtual; })
|
||||
|
||||
|
||||
static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
|
||||
{
|
||||
u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
|
||||
|
||||
pat +=index;
|
||||
return (*pat) & (0x80 >> bit);
|
||||
}
|
||||
|
||||
static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
|
||||
{
|
||||
u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
|
||||
|
||||
pat += index;
|
||||
|
||||
(*pat) |= 0x80 >> bit;
|
||||
}
|
||||
|
||||
static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
|
||||
{
|
||||
int i, j;
|
||||
int shift = (8 - (width % 8)) & 7;
|
||||
|
||||
width = (width + 7) & ~7;
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width - shift; j++) {
|
||||
if (pattern_test_bit(j, i, width, in))
|
||||
pattern_set_bit(width - (1 + j + shift),
|
||||
height - (1 + i),
|
||||
width, out);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
|
||||
{
|
||||
int i, j, h = height, w = width;
|
||||
int shift = (8 - (height % 8)) & 7;
|
||||
|
||||
width = (width + 7) & ~7;
|
||||
height = (height + 7) & ~7;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
if (pattern_test_bit(j, i, width, in))
|
||||
pattern_set_bit(height - 1 - i - shift, j,
|
||||
height, out);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
|
||||
{
|
||||
int i, j, h = height, w = width;
|
||||
int shift = (8 - (width % 8)) & 7;
|
||||
|
||||
width = (width + 7) & ~7;
|
||||
height = (height + 7) & ~7;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
if (pattern_test_bit(j, i, width, in))
|
||||
pattern_set_bit(i, width - 1 - j - shift,
|
||||
height, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void fbcon_rotate_cw(struct fbcon_ops *ops);
|
||||
extern void fbcon_rotate_ud(struct fbcon_ops *ops);
|
||||
extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
|
||||
#endif
|
@@ -1,452 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees
|
||||
*
|
||||
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
#include "fbcon_rotate.h"
|
||||
|
||||
/*
|
||||
* Rotation 180 degrees
|
||||
*/
|
||||
|
||||
static void ud_update_attr(u8 *dst, u8 *src, int attribute,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
int width = (vc->vc_font.width + 7) >> 3;
|
||||
unsigned int cellsize = vc->vc_font.height * width;
|
||||
u8 c;
|
||||
|
||||
offset = offset * width;
|
||||
|
||||
for (i = 0; i < cellsize; i++) {
|
||||
c = src[i];
|
||||
if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset)
|
||||
c = 0xff;
|
||||
if (attribute & FBCON_ATTRIBUTE_BOLD)
|
||||
c |= c << 1;
|
||||
if (attribute & FBCON_ATTRIBUTE_REVERSE)
|
||||
c = ~c;
|
||||
dst[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_copyarea area;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
area.sy = vyres - ((sy + height) * vc->vc_font.height);
|
||||
area.sx = vxres - ((sx + width) * vc->vc_font.width);
|
||||
area.dy = vyres - ((dy + height) * vc->vc_font.height);
|
||||
area.dx = vxres - ((dx + width) * vc->vc_font.width);
|
||||
area.height = height * vc->vc_font.height;
|
||||
area.width = width * vc->vc_font.width;
|
||||
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
|
||||
static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
struct fb_fillrect region;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
region.color = attr_bgcol_ec(bgshift,vc,info);
|
||||
region.dy = vyres - ((sy + height) * vc->vc_font.height);
|
||||
region.dx = vxres - ((sx + width) * vc->vc_font.width);
|
||||
region.width = width * vc->vc_font.width;
|
||||
region.height = height * vc->vc_font.height;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
|
||||
const u16 *s, u32 attr, u32 cnt,
|
||||
u32 d_pitch, u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf, u8 *dst)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 idx = vc->vc_font.width >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
ud_update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
if (likely(idx == 1))
|
||||
__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height);
|
||||
else
|
||||
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height);
|
||||
|
||||
dst += s_pitch;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
}
|
||||
|
||||
static inline void ud_putcs_unaligned(struct vc_data *vc,
|
||||
struct fb_info *info, const u16 *s,
|
||||
u32 attr, u32 cnt, u32 d_pitch,
|
||||
u32 s_pitch, u32 cellsize,
|
||||
struct fb_image *image, u8 *buf,
|
||||
u8 *dst)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
u32 shift_low = 0, mod = vc->vc_font.width % 8;
|
||||
u32 shift_high = 8;
|
||||
u32 idx = vc->vc_font.width >> 3;
|
||||
u8 *src;
|
||||
|
||||
while (cnt--) {
|
||||
src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
|
||||
|
||||
if (attr) {
|
||||
ud_update_attr(buf, src, attr, vc);
|
||||
src = buf;
|
||||
}
|
||||
|
||||
fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
|
||||
image->height, shift_high,
|
||||
shift_low, mod);
|
||||
shift_low += mod;
|
||||
dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
|
||||
shift_low &= 7;
|
||||
shift_high = 8 - shift_low;
|
||||
}
|
||||
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
|
||||
}
|
||||
|
||||
static void ud_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg)
|
||||
{
|
||||
struct fb_image image;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
u32 width = (vc->vc_font.width + 7)/8;
|
||||
u32 cellsize = width * vc->vc_font.height;
|
||||
u32 maxcnt = info->pixmap.size/cellsize;
|
||||
u32 scan_align = info->pixmap.scan_align - 1;
|
||||
u32 buf_align = info->pixmap.buf_align - 1;
|
||||
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
|
||||
u32 attribute = get_attribute(info, scr_readw(s));
|
||||
u8 *dst, *buf = NULL;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
image.fg_color = fg;
|
||||
image.bg_color = bg;
|
||||
image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height);
|
||||
image.dx = vxres - ((xx + count) * vc->vc_font.width);
|
||||
image.height = vc->vc_font.height;
|
||||
image.depth = 1;
|
||||
|
||||
if (attribute) {
|
||||
buf = kmalloc(cellsize, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
}
|
||||
|
||||
s += count - 1;
|
||||
|
||||
while (count) {
|
||||
if (count > maxcnt)
|
||||
cnt = maxcnt;
|
||||
else
|
||||
cnt = count;
|
||||
|
||||
image.width = vc->vc_font.width * cnt;
|
||||
pitch = ((image.width + 7) >> 3) + scan_align;
|
||||
pitch &= ~scan_align;
|
||||
size = pitch * image.height + buf_align;
|
||||
size &= ~buf_align;
|
||||
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
image.data = dst;
|
||||
|
||||
if (!mod)
|
||||
ud_putcs_aligned(vc, info, s, attribute, cnt, pitch,
|
||||
width, cellsize, &image, buf, dst);
|
||||
else
|
||||
ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch,
|
||||
width, cellsize, &image,
|
||||
buf, dst);
|
||||
|
||||
image.dx += image.width;
|
||||
count -= cnt;
|
||||
s -= cnt;
|
||||
xx += cnt;
|
||||
}
|
||||
|
||||
/* buf is always NULL except when in monochrome mode, so in this case
|
||||
it's a gain to check buf against NULL even though kfree() handles
|
||||
NULL pointers just fine */
|
||||
if (unlikely(buf))
|
||||
kfree(buf);
|
||||
|
||||
}
|
||||
|
||||
static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only)
|
||||
{
|
||||
unsigned int cw = vc->vc_font.width;
|
||||
unsigned int ch = vc->vc_font.height;
|
||||
unsigned int rw = info->var.xres - (vc->vc_cols*cw);
|
||||
unsigned int bh = info->var.yres - (vc->vc_rows*ch);
|
||||
struct fb_fillrect region;
|
||||
|
||||
region.color = 0;
|
||||
region.rop = ROP_COPY;
|
||||
|
||||
if (rw && !bottom_only) {
|
||||
region.dy = 0;
|
||||
region.dx = info->var.xoffset;
|
||||
region.width = rw;
|
||||
region.height = info->var.yres_virtual;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
|
||||
if (bh) {
|
||||
region.dy = info->var.yoffset;
|
||||
region.dx = info->var.xoffset;
|
||||
region.height = bh;
|
||||
region.width = info->var.xres;
|
||||
info->fbops->fb_fillrect(info, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
int w = (vc->vc_font.width + 7) >> 3, c;
|
||||
int y = real_y(ops->p, vc->vc_y);
|
||||
int attribute, use_sw = (vc->vc_cursor_type & 0x10);
|
||||
int err = 1, dx, dy;
|
||||
char *src;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
|
||||
if (!ops->fontbuffer)
|
||||
return;
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
if (softback_lines) {
|
||||
if (y + softback_lines >= vc->vc_rows) {
|
||||
mode = CM_ERASE;
|
||||
ops->cursor_flash = 0;
|
||||
return;
|
||||
} else
|
||||
y += softback_lines;
|
||||
}
|
||||
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
|
||||
|
||||
if (ops->cursor_state.image.data != src ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.data = src;
|
||||
cursor.set |= FB_CUR_SETIMAGE;
|
||||
}
|
||||
|
||||
if (attribute) {
|
||||
u8 *dst;
|
||||
|
||||
dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
|
||||
if (!dst)
|
||||
return;
|
||||
kfree(ops->cursor_data);
|
||||
ops->cursor_data = dst;
|
||||
ud_update_attr(dst, src, attribute, vc);
|
||||
src = dst;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.fg_color != fg ||
|
||||
ops->cursor_state.image.bg_color != bg ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.fg_color = fg;
|
||||
ops->cursor_state.image.bg_color = bg;
|
||||
cursor.set |= FB_CUR_SETCMAP;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.image.height != vc->vc_font.height ||
|
||||
ops->cursor_state.image.width != vc->vc_font.width ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.height = vc->vc_font.height;
|
||||
ops->cursor_state.image.width = vc->vc_font.width;
|
||||
cursor.set |= FB_CUR_SETSIZE;
|
||||
}
|
||||
|
||||
dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
|
||||
dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width);
|
||||
|
||||
if (ops->cursor_state.image.dx != dx ||
|
||||
ops->cursor_state.image.dy != dy ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.image.dx = dx;
|
||||
ops->cursor_state.image.dy = dy;
|
||||
cursor.set |= FB_CUR_SETPOS;
|
||||
}
|
||||
|
||||
if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
|
||||
ops->cursor_reset) {
|
||||
ops->cursor_state.hot.x = cursor.hot.y = 0;
|
||||
cursor.set |= FB_CUR_SETHOT;
|
||||
}
|
||||
|
||||
if (cursor.set & FB_CUR_SETSIZE ||
|
||||
vc->vc_cursor_type != ops->p->cursor_shape ||
|
||||
ops->cursor_state.mask == NULL ||
|
||||
ops->cursor_reset) {
|
||||
char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
|
||||
int cur_height, size, i = 0;
|
||||
u8 msk = 0xff;
|
||||
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
kfree(ops->cursor_state.mask);
|
||||
ops->cursor_state.mask = mask;
|
||||
|
||||
ops->p->cursor_shape = vc->vc_cursor_type;
|
||||
cursor.set |= FB_CUR_SETSHAPE;
|
||||
|
||||
switch (ops->p->cursor_shape & CUR_HWMASK) {
|
||||
case CUR_NONE:
|
||||
cur_height = 0;
|
||||
break;
|
||||
case CUR_UNDERLINE:
|
||||
cur_height = (vc->vc_font.height < 10) ? 1 : 2;
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
cur_height = vc->vc_font.height/3;
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
cur_height = vc->vc_font.height >> 1;
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
cur_height = (vc->vc_font.height << 1)/3;
|
||||
break;
|
||||
case CUR_BLOCK:
|
||||
default:
|
||||
cur_height = vc->vc_font.height;
|
||||
break;
|
||||
}
|
||||
|
||||
size = cur_height * w;
|
||||
|
||||
while (size--)
|
||||
mask[i++] = msk;
|
||||
|
||||
size = (vc->vc_font.height - cur_height) * w;
|
||||
|
||||
while (size--)
|
||||
mask[i++] = ~msk;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
ops->cursor_state.enable = 0;
|
||||
break;
|
||||
case CM_DRAW:
|
||||
case CM_MOVE:
|
||||
default:
|
||||
ops->cursor_state.enable = (use_sw) ? 0 : 1;
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.image.data = src;
|
||||
cursor.image.fg_color = ops->cursor_state.image.fg_color;
|
||||
cursor.image.bg_color = ops->cursor_state.image.bg_color;
|
||||
cursor.image.dx = ops->cursor_state.image.dx;
|
||||
cursor.image.dy = ops->cursor_state.image.dy;
|
||||
cursor.image.height = ops->cursor_state.image.height;
|
||||
cursor.image.width = ops->cursor_state.image.width;
|
||||
cursor.hot.x = ops->cursor_state.hot.x;
|
||||
cursor.hot.y = ops->cursor_state.hot.y;
|
||||
cursor.mask = ops->cursor_state.mask;
|
||||
cursor.enable = ops->cursor_state.enable;
|
||||
cursor.image.depth = 1;
|
||||
cursor.rop = ROP_XOR;
|
||||
|
||||
if (info->fbops->fb_cursor)
|
||||
err = info->fbops->fb_cursor(info, &cursor);
|
||||
|
||||
if (err)
|
||||
soft_cursor(info, &cursor);
|
||||
|
||||
ops->cursor_reset = 0;
|
||||
}
|
||||
|
||||
static int ud_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int xoffset, yoffset;
|
||||
u32 vyres = GETVYRES(ops->p->scrollmode, info);
|
||||
u32 vxres = GETVXRES(ops->p->scrollmode, info);
|
||||
int err;
|
||||
|
||||
xoffset = vxres - info->var.xres - ops->var.xoffset;
|
||||
yoffset = vyres - info->var.yres - ops->var.yoffset;
|
||||
if (yoffset < 0)
|
||||
yoffset += vyres;
|
||||
ops->var.xoffset = xoffset;
|
||||
ops->var.yoffset = yoffset;
|
||||
err = fb_pan_display(info, &ops->var);
|
||||
ops->var.xoffset = info->var.xoffset;
|
||||
ops->var.yoffset = info->var.yoffset;
|
||||
ops->var.vmode = info->var.vmode;
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_rotate_ud(struct fbcon_ops *ops)
|
||||
{
|
||||
ops->bmove = ud_bmove;
|
||||
ops->clear = ud_clear;
|
||||
ops->putcs = ud_putcs;
|
||||
ops->clear_margins = ud_clear_margins;
|
||||
ops->cursor = ud_cursor;
|
||||
ops->update_start = ud_update_start;
|
||||
}
|
||||
EXPORT_SYMBOL(fbcon_rotate_ud);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Console Rotation (180 degrees) Support");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/softcursor.c
|
||||
*
|
||||
* Generic software cursor for frame buffer devices
|
||||
*
|
||||
* Created 14 Nov 2002 by James Simmons
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file COPYING in the main directory of this
|
||||
* archive for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "fbcon.h"
|
||||
|
||||
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
unsigned int scan_align = info->pixmap.scan_align - 1;
|
||||
unsigned int buf_align = info->pixmap.buf_align - 1;
|
||||
unsigned int i, size, dsize, s_pitch, d_pitch;
|
||||
struct fb_image *image;
|
||||
u8 *src, *dst;
|
||||
|
||||
if (info->state != FBINFO_STATE_RUNNING)
|
||||
return 0;
|
||||
|
||||
s_pitch = (cursor->image.width + 7) >> 3;
|
||||
dsize = s_pitch * cursor->image.height;
|
||||
|
||||
if (dsize + sizeof(struct fb_image) != ops->cursor_size) {
|
||||
kfree(ops->cursor_src);
|
||||
ops->cursor_size = dsize + sizeof(struct fb_image);
|
||||
|
||||
ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC);
|
||||
if (!ops->cursor_src) {
|
||||
ops->cursor_size = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
src = ops->cursor_src + sizeof(struct fb_image);
|
||||
image = (struct fb_image *)ops->cursor_src;
|
||||
*image = cursor->image;
|
||||
d_pitch = (s_pitch + scan_align) & ~scan_align;
|
||||
|
||||
size = d_pitch * image->height + buf_align;
|
||||
size &= ~buf_align;
|
||||
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
|
||||
if (cursor->enable) {
|
||||
switch (cursor->rop) {
|
||||
case ROP_XOR:
|
||||
for (i = 0; i < dsize; i++)
|
||||
src[i] = image->data[i] ^ cursor->mask[i];
|
||||
break;
|
||||
case ROP_COPY:
|
||||
default:
|
||||
for (i = 0; i < dsize; i++)
|
||||
src[i] = image->data[i] & cursor->mask[i];
|
||||
break;
|
||||
}
|
||||
} else
|
||||
memcpy(src, image->data, dsize);
|
||||
|
||||
fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
|
||||
image->data = dst;
|
||||
info->fbops->fb_imageblit(info, image);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(soft_cursor);
|
||||
|
||||
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
|
||||
MODULE_DESCRIPTION("Generic software cursor");
|
||||
MODULE_LICENSE("GPL");
|
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* linux/drivers/video/console/tileblit.c -- Tile Blitting Operation
|
||||
*
|
||||
* Copyright (C) 2004 Antonino Daplas <adaplas @pol.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
|
||||
static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int dy, int dx, int height, int width)
|
||||
{
|
||||
struct fb_tilearea area;
|
||||
|
||||
area.sx = sx;
|
||||
area.sy = sy;
|
||||
area.dx = dx;
|
||||
area.dy = dy;
|
||||
area.height = height;
|
||||
area.width = width;
|
||||
|
||||
info->tileops->fb_tilecopy(info, &area);
|
||||
}
|
||||
|
||||
static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
int sx, int height, int width)
|
||||
{
|
||||
struct fb_tilerect rect;
|
||||
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
||||
int fgshift = (vc->vc_hi_font_mask) ? 9 : 8;
|
||||
|
||||
rect.index = vc->vc_video_erase_char &
|
||||
((vc->vc_hi_font_mask) ? 0x1ff : 0xff);
|
||||
rect.fg = attr_fgcol_ec(fgshift, vc, info);
|
||||
rect.bg = attr_bgcol_ec(bgshift, vc, info);
|
||||
rect.sx = sx;
|
||||
rect.sy = sy;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
rect.rop = ROP_COPY;
|
||||
|
||||
info->tileops->fb_tilefill(info, &rect);
|
||||
}
|
||||
|
||||
static void tile_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
const unsigned short *s, int count, int yy, int xx,
|
||||
int fg, int bg)
|
||||
{
|
||||
struct fb_tileblit blit;
|
||||
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
||||
int size = sizeof(u32) * count, i;
|
||||
|
||||
blit.sx = xx;
|
||||
blit.sy = yy;
|
||||
blit.width = count;
|
||||
blit.height = 1;
|
||||
blit.fg = fg;
|
||||
blit.bg = bg;
|
||||
blit.length = count;
|
||||
blit.indices = (u32 *) fb_get_buffer_offset(info, &info->pixmap, size);
|
||||
for (i = 0; i < count; i++)
|
||||
blit.indices[i] = (u32)(scr_readw(s++) & charmask);
|
||||
|
||||
info->tileops->fb_tileblit(info, &blit);
|
||||
}
|
||||
|
||||
static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
int bottom_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
int softback_lines, int fg, int bg)
|
||||
{
|
||||
struct fb_tilecursor cursor;
|
||||
int use_sw = (vc->vc_cursor_type & 0x10);
|
||||
|
||||
cursor.sx = vc->vc_x;
|
||||
cursor.sy = vc->vc_y;
|
||||
cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
|
||||
cursor.fg = fg;
|
||||
cursor.bg = bg;
|
||||
|
||||
switch (vc->vc_cursor_type & 0x0f) {
|
||||
case CUR_NONE:
|
||||
cursor.shape = FB_TILE_CURSOR_NONE;
|
||||
break;
|
||||
case CUR_UNDERLINE:
|
||||
cursor.shape = FB_TILE_CURSOR_UNDERLINE;
|
||||
break;
|
||||
case CUR_LOWER_THIRD:
|
||||
cursor.shape = FB_TILE_CURSOR_LOWER_THIRD;
|
||||
break;
|
||||
case CUR_LOWER_HALF:
|
||||
cursor.shape = FB_TILE_CURSOR_LOWER_HALF;
|
||||
break;
|
||||
case CUR_TWO_THIRDS:
|
||||
cursor.shape = FB_TILE_CURSOR_TWO_THIRDS;
|
||||
break;
|
||||
case CUR_BLOCK:
|
||||
default:
|
||||
cursor.shape = FB_TILE_CURSOR_BLOCK;
|
||||
break;
|
||||
}
|
||||
|
||||
info->tileops->fb_tilecursor(info, &cursor);
|
||||
}
|
||||
|
||||
static int tile_update_start(struct fb_info *info)
|
||||
{
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
int err;
|
||||
|
||||
err = fb_pan_display(info, &ops->var);
|
||||
ops->var.xoffset = info->var.xoffset;
|
||||
ops->var.yoffset = info->var.yoffset;
|
||||
ops->var.vmode = info->var.vmode;
|
||||
return err;
|
||||
}
|
||||
|
||||
void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
|
||||
{
|
||||
struct fb_tilemap map;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
ops->bmove = tile_bmove;
|
||||
ops->clear = tile_clear;
|
||||
ops->putcs = tile_putcs;
|
||||
ops->clear_margins = tile_clear_margins;
|
||||
ops->cursor = tile_cursor;
|
||||
ops->update_start = tile_update_start;
|
||||
|
||||
if (ops->p) {
|
||||
map.width = vc->vc_font.width;
|
||||
map.height = vc->vc_font.height;
|
||||
map.depth = 1;
|
||||
map.length = (ops->p->userfont) ?
|
||||
FNTCHARCNT(ops->p->fontdata) : 256;
|
||||
map.data = ops->p->fontdata;
|
||||
info->tileops->fb_settile(info, &map);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fbcon_set_tileops);
|
||||
|
||||
MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
|
||||
MODULE_DESCRIPTION("Tile Blitting Operation");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -398,9 +398,8 @@ static const char *vgacon_startup(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* boot_params.screen_info initialized? */
|
||||
if ((screen_info.orig_video_mode == 0) &&
|
||||
(screen_info.orig_video_lines == 0) &&
|
||||
/* boot_params.screen_info reasonably initialized? */
|
||||
if ((screen_info.orig_video_lines == 0) ||
|
||||
(screen_info.orig_video_cols == 0))
|
||||
goto no_vga;
|
||||
|
||||
|
Reference in New Issue
Block a user