mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
140
drivers/video/console/Kconfig
Normal file
140
drivers/video/console/Kconfig
Normal file
|
@ -0,0 +1,140 @@
|
|||
#
|
||||
# Video configuration
|
||||
#
|
||||
|
||||
menu "Console display driver support"
|
||||
|
||||
config VGA_CONSOLE
|
||||
bool "VGA text console" if EXPERT || !X86
|
||||
depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \
|
||||
!SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \
|
||||
(!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \
|
||||
!ARM64
|
||||
default y
|
||||
help
|
||||
Saying Y here will allow you to use Linux in text mode through a
|
||||
display that complies with the generic VGA standard. Virtually
|
||||
everyone wants that.
|
||||
|
||||
The program SVGATextMode can be used to utilize SVGA video cards to
|
||||
their full potential in text mode. Download it from
|
||||
<ftp://ibiblio.org/pub/Linux/utils/console/>.
|
||||
|
||||
Say Y.
|
||||
|
||||
config VGACON_SOFT_SCROLLBACK
|
||||
bool "Enable Scrollback Buffer in System RAM"
|
||||
depends on VGA_CONSOLE
|
||||
default n
|
||||
help
|
||||
The scrollback buffer of the standard VGA console is located in
|
||||
the VGA RAM. The size of this RAM is fixed and is quite small.
|
||||
If you require a larger scrollback buffer, this can be placed in
|
||||
System RAM which is dynamically allocated during initialization.
|
||||
Placing the scrollback buffer in System RAM will slightly slow
|
||||
down the console.
|
||||
|
||||
If you want this feature, say 'Y' here and enter the amount of
|
||||
RAM to allocate for this buffer. If unsure, say 'N'.
|
||||
|
||||
config VGACON_SOFT_SCROLLBACK_SIZE
|
||||
int "Scrollback Buffer Size (in KB)"
|
||||
depends on VGACON_SOFT_SCROLLBACK
|
||||
range 1 1024
|
||||
default "64"
|
||||
help
|
||||
Enter the amount of System RAM to allocate for the scrollback
|
||||
buffer. Each 64KB will give you approximately 16 80x25
|
||||
screenfuls of scrollback buffer
|
||||
|
||||
config MDA_CONSOLE
|
||||
depends on !M68K && !PARISC && ISA
|
||||
tristate "MDA text console (dual-headed)"
|
||||
---help---
|
||||
Say Y here if you have an old MDA or monochrome Hercules graphics
|
||||
adapter in your system acting as a second head ( = video card). You
|
||||
will then be able to use two monitors with your Linux system. Do not
|
||||
say Y here if your MDA card is the primary card in your system; the
|
||||
normal VGA driver will handle it.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mdacon.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SGI_NEWPORT_CONSOLE
|
||||
tristate "SGI Newport Console support"
|
||||
depends on SGI_IP22
|
||||
select FONT_SUPPORT
|
||||
help
|
||||
Say Y here if you want the console on the Newport aka XL graphics
|
||||
card of your Indy. Most people say Y here.
|
||||
|
||||
config DUMMY_CONSOLE
|
||||
bool
|
||||
depends on VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y
|
||||
default y
|
||||
|
||||
config DUMMY_CONSOLE_COLUMNS
|
||||
int "Initial number of console screen columns"
|
||||
depends on PARISC && DUMMY_CONSOLE
|
||||
default "160"
|
||||
help
|
||||
The default value is 160, which should fit a 1280x1024 monitor.
|
||||
Select 80 if you use a 640x480 resolution by default.
|
||||
|
||||
config DUMMY_CONSOLE_ROWS
|
||||
int "Initial number of console screen rows"
|
||||
depends on PARISC && DUMMY_CONSOLE
|
||||
default "64"
|
||||
help
|
||||
The default value is 64, which should fit a 1280x1024 monitor.
|
||||
Select 25 if you use a 640x480 resolution by default.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE
|
||||
tristate "Framebuffer Console support"
|
||||
depends on FB && !UML
|
||||
select VT_HW_CONSOLE_BINDING
|
||||
select CRC32
|
||||
select FONT_SUPPORT
|
||||
help
|
||||
Low-level framebuffer-based console driver.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
|
||||
bool "Map the console to the primary display device"
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
default n
|
||||
---help---
|
||||
If this option is selected, the framebuffer console will
|
||||
automatically select the primary display device (if the architecture
|
||||
supports this feature). Otherwise, the framebuffer console will
|
||||
always select the first framebuffer driver that is loaded. The latter
|
||||
is the default behavior.
|
||||
|
||||
You can always override the automatic selection of the primary device
|
||||
by using the fbcon=map: boot option.
|
||||
|
||||
If unsure, select n.
|
||||
|
||||
config FRAMEBUFFER_CONSOLE_ROTATION
|
||||
bool "Framebuffer Console Rotation"
|
||||
depends on FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Enable display rotation for the framebuffer console. This is done
|
||||
in software and may be significantly slower than a normally oriented
|
||||
display. Note that the rotation is done at the console level only
|
||||
such that other users of the framebuffer will remain normally
|
||||
oriented.
|
||||
|
||||
config STI_CONSOLE
|
||||
bool "STI text console"
|
||||
depends on PARISC
|
||||
select FONT_SUPPORT
|
||||
default y
|
||||
help
|
||||
The STI console is the builtin display/keyboard on HP-PARISC
|
||||
machines. Say Y here to build support for it into your kernel.
|
||||
The alternative is to use your primary serial port as a console.
|
||||
|
||||
endmenu
|
||||
|
19
drivers/video/console/Makefile
Normal file
19
drivers/video/console/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Makefile for the Linux graphics to console drivers.
|
||||
# 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
|
||||
# Rewritten to use lists instead of if-statements.
|
||||
|
||||
obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
|
||||
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
|
422
drivers/video/console/bitblit.c
Normal file
422
drivers/video/console/bitblit.c
Normal file
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* 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");
|
||||
|
80
drivers/video/console/dummycon.c
Normal file
80
drivers/video/console/dummycon.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* linux/drivers/video/dummycon.c -- A dummy console driver
|
||||
*
|
||||
* To be used if there's no other console driver (e.g. for plain VGA text)
|
||||
* available, usually until fbcon takes console over.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/screen_info.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Dummy console driver
|
||||
*/
|
||||
|
||||
#if defined(__arm__)
|
||||
#define DUMMY_COLUMNS screen_info.orig_video_cols
|
||||
#define DUMMY_ROWS screen_info.orig_video_lines
|
||||
#elif defined(__hppa__)
|
||||
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
|
||||
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
|
||||
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
|
||||
#else
|
||||
#define DUMMY_COLUMNS 80
|
||||
#define DUMMY_ROWS 25
|
||||
#endif
|
||||
|
||||
static const char *dummycon_startup(void)
|
||||
{
|
||||
return "dummy device";
|
||||
}
|
||||
|
||||
static void dummycon_init(struct vc_data *vc, int init)
|
||||
{
|
||||
vc->vc_can_do_color = 1;
|
||||
if (init) {
|
||||
vc->vc_cols = DUMMY_COLUMNS;
|
||||
vc->vc_rows = DUMMY_ROWS;
|
||||
} else
|
||||
vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS);
|
||||
}
|
||||
|
||||
static int dummycon_dummy(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DUMMY (void *)dummycon_dummy
|
||||
|
||||
/*
|
||||
* The console `switch' structure for the dummy console
|
||||
*
|
||||
* Most of the operations are dummies.
|
||||
*/
|
||||
|
||||
const struct consw dummy_con = {
|
||||
.owner = THIS_MODULE,
|
||||
.con_startup = dummycon_startup,
|
||||
.con_init = dummycon_init,
|
||||
.con_deinit = DUMMY,
|
||||
.con_clear = DUMMY,
|
||||
.con_putc = DUMMY,
|
||||
.con_putcs = DUMMY,
|
||||
.con_cursor = DUMMY,
|
||||
.con_scroll = DUMMY,
|
||||
.con_bmove = DUMMY,
|
||||
.con_switch = DUMMY,
|
||||
.con_blank = DUMMY,
|
||||
.con_font_set = DUMMY,
|
||||
.con_font_get = DUMMY,
|
||||
.con_font_default = DUMMY,
|
||||
.con_font_copy = DUMMY,
|
||||
.con_set_palette = DUMMY,
|
||||
.con_scrolldelta = DUMMY,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dummy_con);
|
3658
drivers/video/console/fbcon.c
Normal file
3658
drivers/video/console/fbcon.c
Normal file
File diff suppressed because it is too large
Load diff
264
drivers/video/console/fbcon.h
Normal file
264
drivers/video/console/fbcon.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* 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 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 */
|
||||
|
424
drivers/video/console/fbcon_ccw.c
Normal file
424
drivers/video/console/fbcon_ccw.c
Normal file
|
@ -0,0 +1,424 @@
|
|||
/*
|
||||
* 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");
|
407
drivers/video/console/fbcon_cw.c
Normal file
407
drivers/video/console/fbcon_cw.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* 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");
|
116
drivers/video/console/fbcon_rotate.c
Normal file
116
drivers/video/console/fbcon_rotate.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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");
|
96
drivers/video/console/fbcon_rotate.h
Normal file
96
drivers/video/console/fbcon_rotate.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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
|
452
drivers/video/console/fbcon_ud.c
Normal file
452
drivers/video/console/fbcon_ud.c
Normal file
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
* 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");
|
607
drivers/video/console/mdacon.c
Normal file
607
drivers/video/console/mdacon.c
Normal file
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
* linux/drivers/video/mdacon.c -- Low level MDA based console driver
|
||||
*
|
||||
* (c) 1998 Andrew Apted <ajapted@netspace.net.au>
|
||||
*
|
||||
* including portions (c) 1995-1998 Patrick Caulfield.
|
||||
*
|
||||
* slight improvements (c) 2000 Edward Betts <edward@debian.org>
|
||||
*
|
||||
* This file is based on the VGA console driver (vgacon.c):
|
||||
*
|
||||
* Created 28 Sep 1997 by Geert Uytterhoeven
|
||||
*
|
||||
* Rewritten by Martin Mares <mj@ucw.cz>, July 1998
|
||||
*
|
||||
* and on the old console.c, vga.c and vesa_blank.c drivers:
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* 1995 Jay Estabrook
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Changelog:
|
||||
* Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/vt_buffer.h>
|
||||
#include <linux/selection.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
static DEFINE_SPINLOCK(mda_lock);
|
||||
|
||||
/* description of the hardware layout */
|
||||
|
||||
static unsigned long mda_vram_base; /* Base of video memory */
|
||||
static unsigned long mda_vram_len; /* Size of video memory */
|
||||
static unsigned int mda_num_columns; /* Number of text columns */
|
||||
static unsigned int mda_num_lines; /* Number of text lines */
|
||||
|
||||
static unsigned int mda_index_port; /* Register select port */
|
||||
static unsigned int mda_value_port; /* Register value port */
|
||||
static unsigned int mda_mode_port; /* Mode control port */
|
||||
static unsigned int mda_status_port; /* Status and Config port */
|
||||
static unsigned int mda_gfx_port; /* Graphics control port */
|
||||
|
||||
/* current hardware state */
|
||||
|
||||
static int mda_cursor_loc=-1;
|
||||
static int mda_cursor_size_from=-1;
|
||||
static int mda_cursor_size_to=-1;
|
||||
|
||||
static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type;
|
||||
static char *mda_type_name;
|
||||
|
||||
/* console information */
|
||||
|
||||
static int mda_first_vc = 13;
|
||||
static int mda_last_vc = 16;
|
||||
|
||||
static struct vc_data *mda_display_fg = NULL;
|
||||
|
||||
module_param(mda_first_vc, int, 0);
|
||||
MODULE_PARM_DESC(mda_first_vc, "First virtual console. Default: 13");
|
||||
module_param(mda_last_vc, int, 0);
|
||||
MODULE_PARM_DESC(mda_last_vc, "Last virtual console. Default: 16");
|
||||
|
||||
/* MDA register values
|
||||
*/
|
||||
|
||||
#define MDA_CURSOR_BLINKING 0x00
|
||||
#define MDA_CURSOR_OFF 0x20
|
||||
#define MDA_CURSOR_SLOWBLINK 0x60
|
||||
|
||||
#define MDA_MODE_GRAPHICS 0x02
|
||||
#define MDA_MODE_VIDEO_EN 0x08
|
||||
#define MDA_MODE_BLINK_EN 0x20
|
||||
#define MDA_MODE_GFX_PAGE1 0x80
|
||||
|
||||
#define MDA_STATUS_HSYNC 0x01
|
||||
#define MDA_STATUS_VSYNC 0x80
|
||||
#define MDA_STATUS_VIDEO 0x08
|
||||
|
||||
#define MDA_CONFIG_COL132 0x08
|
||||
#define MDA_GFX_MODE_EN 0x01
|
||||
#define MDA_GFX_PAGE_EN 0x02
|
||||
|
||||
|
||||
/*
|
||||
* MDA could easily be classified as "pre-dinosaur hardware".
|
||||
*/
|
||||
|
||||
static void write_mda_b(unsigned int val, unsigned char reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mda_lock, flags);
|
||||
|
||||
outb_p(reg, mda_index_port);
|
||||
outb_p(val, mda_value_port);
|
||||
|
||||
spin_unlock_irqrestore(&mda_lock, flags);
|
||||
}
|
||||
|
||||
static void write_mda_w(unsigned int val, unsigned char reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mda_lock, flags);
|
||||
|
||||
outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port);
|
||||
outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port);
|
||||
|
||||
spin_unlock_irqrestore(&mda_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef TEST_MDA_B
|
||||
static int test_mda_b(unsigned char val, unsigned char reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mda_lock, flags);
|
||||
|
||||
outb_p(reg, mda_index_port);
|
||||
outb (val, mda_value_port);
|
||||
|
||||
udelay(20); val = (inb_p(mda_value_port) == val);
|
||||
|
||||
spin_unlock_irqrestore(&mda_lock, flags);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void mda_set_cursor(unsigned int location)
|
||||
{
|
||||
if (mda_cursor_loc == location)
|
||||
return;
|
||||
|
||||
write_mda_w(location >> 1, 0x0e);
|
||||
|
||||
mda_cursor_loc = location;
|
||||
}
|
||||
|
||||
static inline void mda_set_cursor_size(int from, int to)
|
||||
{
|
||||
if (mda_cursor_size_from==from && mda_cursor_size_to==to)
|
||||
return;
|
||||
|
||||
if (from > to) {
|
||||
write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */
|
||||
} else {
|
||||
write_mda_b(from, 0x0a); /* cursor start */
|
||||
write_mda_b(to, 0x0b); /* cursor end */
|
||||
}
|
||||
|
||||
mda_cursor_size_from = from;
|
||||
mda_cursor_size_to = to;
|
||||
}
|
||||
|
||||
|
||||
#ifndef MODULE
|
||||
static int __init mdacon_setup(char *str)
|
||||
{
|
||||
/* command line format: mdacon=<first>,<last> */
|
||||
|
||||
int ints[3];
|
||||
|
||||
str = get_options(str, ARRAY_SIZE(ints), ints);
|
||||
|
||||
if (ints[0] < 2)
|
||||
return 0;
|
||||
|
||||
if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES ||
|
||||
ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
|
||||
return 0;
|
||||
|
||||
mda_first_vc = ints[1];
|
||||
mda_last_vc = ints[2];
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("mdacon=", mdacon_setup);
|
||||
#endif
|
||||
|
||||
static int mda_detect(void)
|
||||
{
|
||||
int count=0;
|
||||
u16 *p, p_save;
|
||||
u16 *q, q_save;
|
||||
|
||||
/* do a memory check */
|
||||
|
||||
p = (u16 *) mda_vram_base;
|
||||
q = (u16 *) (mda_vram_base + 0x01000);
|
||||
|
||||
p_save = scr_readw(p); q_save = scr_readw(q);
|
||||
|
||||
scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++;
|
||||
scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++;
|
||||
scr_writew(p_save, p);
|
||||
|
||||
if (count != 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check if we have 4K or 8K */
|
||||
|
||||
scr_writew(0xA55A, q); scr_writew(0x0000, p);
|
||||
if (scr_readw(q) == 0xA55A) count++;
|
||||
|
||||
scr_writew(0x5AA5, q); scr_writew(0x0000, p);
|
||||
if (scr_readw(q) == 0x5AA5) count++;
|
||||
|
||||
scr_writew(p_save, p); scr_writew(q_save, q);
|
||||
|
||||
if (count == 4) {
|
||||
mda_vram_len = 0x02000;
|
||||
}
|
||||
|
||||
/* Ok, there is definitely a card registering at the correct
|
||||
* memory location, so now we do an I/O port test.
|
||||
*/
|
||||
|
||||
#ifdef TEST_MDA_B
|
||||
/* Edward: These two mess `tests' mess up my cursor on bootup */
|
||||
|
||||
/* cursor low register */
|
||||
if (! test_mda_b(0x66, 0x0f)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cursor low register */
|
||||
if (! test_mda_b(0x99, 0x0f)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See if the card is a Hercules, by checking whether the vsync
|
||||
* bit of the status register is changing. This test lasts for
|
||||
* approximately 1/10th of a second.
|
||||
*/
|
||||
|
||||
p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC;
|
||||
|
||||
for (count=0; count < 50000 && p_save == q_save; count++) {
|
||||
q_save = inb(mda_status_port) & MDA_STATUS_VSYNC;
|
||||
udelay(2);
|
||||
}
|
||||
|
||||
if (p_save != q_save) {
|
||||
switch (inb_p(mda_status_port) & 0x70) {
|
||||
case 0x10:
|
||||
mda_type = TYPE_HERCPLUS;
|
||||
mda_type_name = "HerculesPlus";
|
||||
break;
|
||||
case 0x50:
|
||||
mda_type = TYPE_HERCCOLOR;
|
||||
mda_type_name = "HerculesColor";
|
||||
break;
|
||||
default:
|
||||
mda_type = TYPE_HERC;
|
||||
mda_type_name = "Hercules";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mda_initialize(void)
|
||||
{
|
||||
write_mda_b(97, 0x00); /* horizontal total */
|
||||
write_mda_b(80, 0x01); /* horizontal displayed */
|
||||
write_mda_b(82, 0x02); /* horizontal sync pos */
|
||||
write_mda_b(15, 0x03); /* horizontal sync width */
|
||||
|
||||
write_mda_b(25, 0x04); /* vertical total */
|
||||
write_mda_b(6, 0x05); /* vertical total adjust */
|
||||
write_mda_b(25, 0x06); /* vertical displayed */
|
||||
write_mda_b(25, 0x07); /* vertical sync pos */
|
||||
|
||||
write_mda_b(2, 0x08); /* interlace mode */
|
||||
write_mda_b(13, 0x09); /* maximum scanline */
|
||||
write_mda_b(12, 0x0a); /* cursor start */
|
||||
write_mda_b(13, 0x0b); /* cursor end */
|
||||
|
||||
write_mda_w(0x0000, 0x0c); /* start address */
|
||||
write_mda_w(0x0000, 0x0e); /* cursor location */
|
||||
|
||||
outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port);
|
||||
outb_p(0x00, mda_status_port);
|
||||
outb_p(0x00, mda_gfx_port);
|
||||
}
|
||||
|
||||
static const char *mdacon_startup(void)
|
||||
{
|
||||
mda_num_columns = 80;
|
||||
mda_num_lines = 25;
|
||||
|
||||
mda_vram_len = 0x01000;
|
||||
mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len);
|
||||
|
||||
mda_index_port = 0x3b4;
|
||||
mda_value_port = 0x3b5;
|
||||
mda_mode_port = 0x3b8;
|
||||
mda_status_port = 0x3ba;
|
||||
mda_gfx_port = 0x3bf;
|
||||
|
||||
mda_type = TYPE_MDA;
|
||||
mda_type_name = "MDA";
|
||||
|
||||
if (! mda_detect()) {
|
||||
printk("mdacon: MDA card not detected.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mda_type != TYPE_MDA) {
|
||||
mda_initialize();
|
||||
}
|
||||
|
||||
/* cursor looks ugly during boot-up, so turn it off */
|
||||
mda_set_cursor(mda_vram_len - 1);
|
||||
|
||||
printk("mdacon: %s with %ldK of memory detected.\n",
|
||||
mda_type_name, mda_vram_len/1024);
|
||||
|
||||
return "MDA-2";
|
||||
}
|
||||
|
||||
static void mdacon_init(struct vc_data *c, int init)
|
||||
{
|
||||
c->vc_complement_mask = 0x0800; /* reverse video */
|
||||
c->vc_display_fg = &mda_display_fg;
|
||||
|
||||
if (init) {
|
||||
c->vc_cols = mda_num_columns;
|
||||
c->vc_rows = mda_num_lines;
|
||||
} else
|
||||
vc_resize(c, mda_num_columns, mda_num_lines);
|
||||
|
||||
/* make the first MDA console visible */
|
||||
|
||||
if (mda_display_fg == NULL)
|
||||
mda_display_fg = c;
|
||||
}
|
||||
|
||||
static void mdacon_deinit(struct vc_data *c)
|
||||
{
|
||||
/* con_set_default_unimap(c->vc_num); */
|
||||
|
||||
if (mda_display_fg == c)
|
||||
mda_display_fg = NULL;
|
||||
}
|
||||
|
||||
static inline u16 mda_convert_attr(u16 ch)
|
||||
{
|
||||
u16 attr = 0x0700;
|
||||
|
||||
/* Underline and reverse-video are mutually exclusive on MDA.
|
||||
* Since reverse-video is used for cursors and selected areas,
|
||||
* it takes precedence.
|
||||
*/
|
||||
|
||||
if (ch & 0x0800) attr = 0x7000; /* reverse */
|
||||
else if (ch & 0x0400) attr = 0x0100; /* underline */
|
||||
|
||||
return ((ch & 0x0200) << 2) | /* intensity */
|
||||
(ch & 0x8000) | /* blink */
|
||||
(ch & 0x00ff) | attr;
|
||||
}
|
||||
|
||||
static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
|
||||
u8 blink, u8 underline, u8 reverse, u8 italic)
|
||||
{
|
||||
/* The attribute is just a bit vector:
|
||||
*
|
||||
* Bit 0..1 : intensity (0..2)
|
||||
* Bit 2 : underline
|
||||
* Bit 3 : reverse
|
||||
* Bit 7 : blink
|
||||
*/
|
||||
|
||||
return (intensity & 3) |
|
||||
((underline & 1) << 2) |
|
||||
((reverse & 1) << 3) |
|
||||
(!!italic << 4) |
|
||||
((blink & 1) << 7);
|
||||
}
|
||||
|
||||
static void mdacon_invert_region(struct vc_data *c, u16 *p, int count)
|
||||
{
|
||||
for (; count > 0; count--) {
|
||||
scr_writew(scr_readw(p) ^ 0x0800, p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
#define MDA_ADDR(x,y) ((u16 *) mda_vram_base + (y)*mda_num_columns + (x))
|
||||
|
||||
static void mdacon_putc(struct vc_data *c, int ch, int y, int x)
|
||||
{
|
||||
scr_writew(mda_convert_attr(ch), MDA_ADDR(x, y));
|
||||
}
|
||||
|
||||
static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
|
||||
int count, int y, int x)
|
||||
{
|
||||
u16 *dest = MDA_ADDR(x, y);
|
||||
|
||||
for (; count > 0; count--) {
|
||||
scr_writew(mda_convert_attr(scr_readw(s++)), dest++);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdacon_clear(struct vc_data *c, int y, int x,
|
||||
int height, int width)
|
||||
{
|
||||
u16 *dest = MDA_ADDR(x, y);
|
||||
u16 eattr = mda_convert_attr(c->vc_video_erase_char);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
if (x==0 && width==mda_num_columns) {
|
||||
scr_memsetw(dest, eattr, height*width*2);
|
||||
} else {
|
||||
for (; height > 0; height--, dest+=mda_num_columns)
|
||||
scr_memsetw(dest, eattr, width*2);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdacon_bmove(struct vc_data *c, int sy, int sx,
|
||||
int dy, int dx, int height, int width)
|
||||
{
|
||||
u16 *src, *dest;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
if (sx==0 && dx==0 && width==mda_num_columns) {
|
||||
scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2);
|
||||
|
||||
} else if (dy < sy || (dy == sy && dx < sx)) {
|
||||
src = MDA_ADDR(sx, sy);
|
||||
dest = MDA_ADDR(dx, dy);
|
||||
|
||||
for (; height > 0; height--) {
|
||||
scr_memmovew(dest, src, width*2);
|
||||
src += mda_num_columns;
|
||||
dest += mda_num_columns;
|
||||
}
|
||||
} else {
|
||||
src = MDA_ADDR(sx, sy+height-1);
|
||||
dest = MDA_ADDR(dx, dy+height-1);
|
||||
|
||||
for (; height > 0; height--) {
|
||||
scr_memmovew(dest, src, width*2);
|
||||
src -= mda_num_columns;
|
||||
dest -= mda_num_columns;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mdacon_switch(struct vc_data *c)
|
||||
{
|
||||
return 1; /* redrawing needed */
|
||||
}
|
||||
|
||||
static int mdacon_set_palette(struct vc_data *c, unsigned char *table)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
|
||||
{
|
||||
if (mda_type == TYPE_MDA) {
|
||||
if (blank)
|
||||
scr_memsetw((void *)mda_vram_base,
|
||||
mda_convert_attr(c->vc_video_erase_char),
|
||||
c->vc_screenbuf_size);
|
||||
/* Tell console.c that it has to restore the screen itself */
|
||||
return 1;
|
||||
} else {
|
||||
if (blank)
|
||||
outb_p(0x00, mda_mode_port); /* disable video */
|
||||
else
|
||||
outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN,
|
||||
mda_mode_port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdacon_scrolldelta(struct vc_data *c, int lines)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mdacon_cursor(struct vc_data *c, int mode)
|
||||
{
|
||||
if (mode == CM_ERASE) {
|
||||
mda_set_cursor(mda_vram_len - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
mda_set_cursor(c->vc_y*mda_num_columns*2 + c->vc_x*2);
|
||||
|
||||
switch (c->vc_cursor_type & 0x0f) {
|
||||
|
||||
case CUR_LOWER_THIRD: mda_set_cursor_size(10, 13); break;
|
||||
case CUR_LOWER_HALF: mda_set_cursor_size(7, 13); break;
|
||||
case CUR_TWO_THIRDS: mda_set_cursor_size(4, 13); break;
|
||||
case CUR_BLOCK: mda_set_cursor_size(1, 13); break;
|
||||
case CUR_NONE: mda_set_cursor_size(14, 13); break;
|
||||
default: mda_set_cursor_size(12, 13); break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
|
||||
{
|
||||
u16 eattr = mda_convert_attr(c->vc_video_erase_char);
|
||||
|
||||
if (!lines)
|
||||
return 0;
|
||||
|
||||
if (lines > c->vc_rows) /* maximum realistic size */
|
||||
lines = c->vc_rows;
|
||||
|
||||
switch (dir) {
|
||||
|
||||
case SM_UP:
|
||||
scr_memmovew(MDA_ADDR(0,t), MDA_ADDR(0,t+lines),
|
||||
(b-t-lines)*mda_num_columns*2);
|
||||
scr_memsetw(MDA_ADDR(0,b-lines), eattr,
|
||||
lines*mda_num_columns*2);
|
||||
break;
|
||||
|
||||
case SM_DOWN:
|
||||
scr_memmovew(MDA_ADDR(0,t+lines), MDA_ADDR(0,t),
|
||||
(b-t-lines)*mda_num_columns*2);
|
||||
scr_memsetw(MDA_ADDR(0,t), eattr, lines*mda_num_columns*2);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The console `switch' structure for the MDA based console
|
||||
*/
|
||||
|
||||
static const struct consw mda_con = {
|
||||
.owner = THIS_MODULE,
|
||||
.con_startup = mdacon_startup,
|
||||
.con_init = mdacon_init,
|
||||
.con_deinit = mdacon_deinit,
|
||||
.con_clear = mdacon_clear,
|
||||
.con_putc = mdacon_putc,
|
||||
.con_putcs = mdacon_putcs,
|
||||
.con_cursor = mdacon_cursor,
|
||||
.con_scroll = mdacon_scroll,
|
||||
.con_bmove = mdacon_bmove,
|
||||
.con_switch = mdacon_switch,
|
||||
.con_blank = mdacon_blank,
|
||||
.con_set_palette = mdacon_set_palette,
|
||||
.con_scrolldelta = mdacon_scrolldelta,
|
||||
.con_build_attr = mdacon_build_attr,
|
||||
.con_invert_region = mdacon_invert_region,
|
||||
};
|
||||
|
||||
int __init mda_console_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mda_first_vc > mda_last_vc)
|
||||
return 1;
|
||||
console_lock();
|
||||
err = do_take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0);
|
||||
console_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit mda_console_exit(void)
|
||||
{
|
||||
give_up_console(&mda_con);
|
||||
}
|
||||
|
||||
module_init(mda_console_init);
|
||||
module_exit(mda_console_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
802
drivers/video/console/newport_con.c
Normal file
802
drivers/video/console/newport_con.c
Normal file
|
@ -0,0 +1,802 @@
|
|||
/*
|
||||
* newport_con.c: Abscon for newport hardware
|
||||
*
|
||||
* (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
|
||||
* (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com)
|
||||
*
|
||||
* This driver is based on sgicons.c and cons_newport.
|
||||
*
|
||||
* Copyright (C) 1996 David S. Miller (davem@davemloft.net)
|
||||
* Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/selection.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/gio_device.h>
|
||||
|
||||
#include <video/newport.h>
|
||||
|
||||
#include <linux/linux_logo.h>
|
||||
#include <linux/font.h>
|
||||
|
||||
#define FONT_DATA ((unsigned char *)font_vga_8x16.data)
|
||||
|
||||
/* borrowed from fbcon.c */
|
||||
#define REFCOUNT(fd) (((int *)(fd))[-1])
|
||||
#define FNTSIZE(fd) (((int *)(fd))[-2])
|
||||
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
|
||||
#define FONT_EXTRA_WORDS 3
|
||||
|
||||
static unsigned char *font_data[MAX_NR_CONSOLES];
|
||||
|
||||
static struct newport_regs *npregs;
|
||||
|
||||
static int logo_active;
|
||||
static int topscan;
|
||||
static int xcurs_correction = 29;
|
||||
static int newport_xsize;
|
||||
static int newport_ysize;
|
||||
static int newport_has_init;
|
||||
|
||||
static int newport_set_def_font(int unit, struct console_font *op);
|
||||
|
||||
#define BMASK(c) (c << 24)
|
||||
|
||||
#define RENDER(regs, cp) do { \
|
||||
(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
|
||||
(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
|
||||
} while(0)
|
||||
|
||||
#define TESTVAL 0xdeadbeef
|
||||
#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
|
||||
|
||||
static inline void newport_render_background(int xstart, int ystart,
|
||||
int xend, int yend, int ci)
|
||||
{
|
||||
newport_wait(npregs);
|
||||
npregs->set.wrmask = 0xffffffff;
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
|
||||
| NPORT_DMODE0_STOPY);
|
||||
npregs->set.colori = ci;
|
||||
npregs->set.xystarti =
|
||||
(xstart << 16) | ((ystart + topscan) & 0x3ff);
|
||||
npregs->go.xyendi =
|
||||
((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff);
|
||||
}
|
||||
|
||||
static inline void newport_init_cmap(void)
|
||||
{
|
||||
unsigned short i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
newport_bfwait(npregs);
|
||||
newport_cmap_setaddr(npregs, color_table[i]);
|
||||
newport_cmap_setrgb(npregs,
|
||||
default_red[i],
|
||||
default_grn[i], default_blu[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct linux_logo *newport_show_logo(void)
|
||||
{
|
||||
#ifdef CONFIG_LOGO_SGI_CLUT224
|
||||
const struct linux_logo *logo = fb_find_logo(8);
|
||||
const unsigned char *clut;
|
||||
const unsigned char *data;
|
||||
unsigned long i;
|
||||
|
||||
if (!logo)
|
||||
return NULL;
|
||||
clut = logo->clut;
|
||||
data = logo->data;
|
||||
|
||||
for (i = 0; i < logo->clutsize; i++) {
|
||||
newport_bfwait(npregs);
|
||||
newport_cmap_setaddr(npregs, i + 0x20);
|
||||
newport_cmap_setrgb(npregs, clut[0], clut[1], clut[2]);
|
||||
clut += 3;
|
||||
}
|
||||
|
||||
newport_wait(npregs);
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_CHOST);
|
||||
|
||||
npregs->set.xystarti = ((newport_xsize - logo->width) << 16) | (0);
|
||||
npregs->set.xyendi = ((newport_xsize - 1) << 16);
|
||||
newport_wait(npregs);
|
||||
|
||||
for (i = 0; i < logo->width*logo->height; i++)
|
||||
npregs->go.hostrw0 = *data++ << 24;
|
||||
|
||||
return logo;
|
||||
#endif /* CONFIG_LOGO_SGI_CLUT224 */
|
||||
}
|
||||
|
||||
static inline void newport_clear_screen(int xstart, int ystart, int xend,
|
||||
int yend, int ci)
|
||||
{
|
||||
if (logo_active)
|
||||
return;
|
||||
|
||||
newport_wait(npregs);
|
||||
npregs->set.wrmask = 0xffffffff;
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
|
||||
| NPORT_DMODE0_STOPY);
|
||||
npregs->set.colori = ci;
|
||||
npregs->set.xystarti = (xstart << 16) | ystart;
|
||||
npregs->go.xyendi = (xend << 16) | yend;
|
||||
}
|
||||
|
||||
static inline void newport_clear_lines(int ystart, int yend, int ci)
|
||||
{
|
||||
ystart = ((ystart << 4) + topscan) & 0x3ff;
|
||||
yend = ((yend << 4) + topscan + 15) & 0x3ff;
|
||||
newport_clear_screen(0, ystart, 1280 + 63, yend, ci);
|
||||
}
|
||||
|
||||
static void newport_reset(void)
|
||||
{
|
||||
unsigned short treg;
|
||||
int i;
|
||||
|
||||
newport_wait(npregs);
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
|
||||
newport_vc2_set(npregs, VC2_IREG_CONTROL,
|
||||
(treg | VC2_CTRL_EVIDEO));
|
||||
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CENTRY);
|
||||
newport_vc2_set(npregs, VC2_IREG_RADDR, treg);
|
||||
npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
|
||||
NPORT_DMODE_W2 | VC2_PROTOCOL);
|
||||
for (i = 0; i < 128; i++) {
|
||||
newport_bfwait(npregs);
|
||||
if (i == 92 || i == 94)
|
||||
npregs->set.dcbdata0.byshort.s1 = 0xff00;
|
||||
else
|
||||
npregs->set.dcbdata0.byshort.s1 = 0x0000;
|
||||
}
|
||||
|
||||
newport_init_cmap();
|
||||
|
||||
/* turn off popup plane */
|
||||
npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
|
||||
XM9_CRS_CONFIG | NPORT_DMODE_W1);
|
||||
npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
|
||||
npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL |
|
||||
XM9_CRS_CONFIG | NPORT_DMODE_W1);
|
||||
npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
|
||||
|
||||
topscan = 0;
|
||||
npregs->cset.topscan = 0x3ff;
|
||||
npregs->cset.xywin = (4096 << 16) | 4096;
|
||||
|
||||
/* Clear the screen. */
|
||||
newport_clear_screen(0, 0, 1280 + 63, 1024, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* calculate the actual screen size by reading
|
||||
* the video timing out of the VC2
|
||||
*/
|
||||
static void newport_get_screensize(void)
|
||||
{
|
||||
int i, cols;
|
||||
unsigned short ventry, treg;
|
||||
unsigned short linetable[128]; /* should be enough */
|
||||
|
||||
ventry = newport_vc2_get(npregs, VC2_IREG_VENTRY);
|
||||
newport_vc2_set(npregs, VC2_IREG_RADDR, ventry);
|
||||
npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
|
||||
NPORT_DMODE_W2 | VC2_PROTOCOL);
|
||||
for (i = 0; i < 128; i++) {
|
||||
newport_bfwait(npregs);
|
||||
linetable[i] = npregs->set.dcbdata0.byshort.s1;
|
||||
}
|
||||
|
||||
newport_xsize = newport_ysize = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(linetable) - 1 && linetable[i + 1]; i += 2) {
|
||||
cols = 0;
|
||||
newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]);
|
||||
npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
|
||||
NPORT_DMODE_W2 | VC2_PROTOCOL);
|
||||
do {
|
||||
newport_bfwait(npregs);
|
||||
treg = npregs->set.dcbdata0.byshort.s1;
|
||||
if ((treg & 1) == 0)
|
||||
cols += (treg >> 7) & 0xfe;
|
||||
if ((treg & 0x80) == 0) {
|
||||
newport_bfwait(npregs);
|
||||
treg = npregs->set.dcbdata0.byshort.s1;
|
||||
}
|
||||
} while ((treg & 0x8000) == 0);
|
||||
if (cols) {
|
||||
if (cols > newport_xsize)
|
||||
newport_xsize = cols;
|
||||
newport_ysize += linetable[i + 1];
|
||||
}
|
||||
}
|
||||
printk("NG1: Screensize %dx%d\n", newport_xsize, newport_ysize);
|
||||
}
|
||||
|
||||
static void newport_get_revisions(void)
|
||||
{
|
||||
unsigned int tmp;
|
||||
unsigned int board_rev;
|
||||
unsigned int rex3_rev;
|
||||
unsigned int vc2_rev;
|
||||
unsigned int cmap_rev;
|
||||
unsigned int xmap9_rev;
|
||||
unsigned int bt445_rev;
|
||||
unsigned int bitplanes;
|
||||
|
||||
rex3_rev = npregs->cset.status & NPORT_STAT_VERS;
|
||||
|
||||
npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL |
|
||||
NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
|
||||
tmp = npregs->set.dcbdata0.bybytes.b3;
|
||||
cmap_rev = tmp & 7;
|
||||
board_rev = (tmp >> 4) & 7;
|
||||
bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24;
|
||||
|
||||
npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL |
|
||||
NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
|
||||
tmp = npregs->set.dcbdata0.bybytes.b3;
|
||||
if ((tmp & 7) < cmap_rev)
|
||||
cmap_rev = (tmp & 7);
|
||||
|
||||
vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7;
|
||||
|
||||
npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
|
||||
XM9_CRS_REVISION | NPORT_DMODE_W1);
|
||||
xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7;
|
||||
|
||||
npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
|
||||
BT445_CSR_ADDR_REG | NPORT_DMODE_W1);
|
||||
npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG;
|
||||
npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
|
||||
BT445_CSR_REVISION | NPORT_DMODE_W1);
|
||||
bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a;
|
||||
|
||||
#define L(a) (char)('A'+(a))
|
||||
printk
|
||||
("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
|
||||
board_rev, bitplanes, L(rex3_rev), L(vc2_rev), L(xmap9_rev),
|
||||
L(cmap_rev ? (cmap_rev + 1) : 0), L(bt445_rev));
|
||||
#undef L
|
||||
|
||||
if (board_rev == 3) /* I don't know all affected revisions */
|
||||
xcurs_correction = 21;
|
||||
}
|
||||
|
||||
static void newport_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* free memory used by user font */
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++)
|
||||
newport_set_def_font(i, NULL);
|
||||
}
|
||||
|
||||
/* Can't be __init, do_take_over_console may call it later */
|
||||
static const char *newport_startup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
npregs->cset.config = NPORT_CFG_GD0;
|
||||
|
||||
if (newport_wait(npregs))
|
||||
goto out_unmap;
|
||||
|
||||
npregs->set.xstarti = TESTVAL;
|
||||
if (npregs->set._xstart.word != XSTI_TO_FXSTART(TESTVAL))
|
||||
goto out_unmap;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++)
|
||||
font_data[i] = FONT_DATA;
|
||||
|
||||
newport_reset();
|
||||
newport_get_revisions();
|
||||
newport_get_screensize();
|
||||
newport_has_init = 1;
|
||||
|
||||
return "SGI Newport";
|
||||
|
||||
out_unmap:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void newport_init(struct vc_data *vc, int init)
|
||||
{
|
||||
int cols, rows;
|
||||
|
||||
cols = newport_xsize / 8;
|
||||
rows = newport_ysize / 16;
|
||||
vc->vc_can_do_color = 1;
|
||||
if (init) {
|
||||
vc->vc_cols = cols;
|
||||
vc->vc_rows = rows;
|
||||
} else
|
||||
vc_resize(vc, cols, rows);
|
||||
}
|
||||
|
||||
static void newport_deinit(struct vc_data *c)
|
||||
{
|
||||
if (!con_is_bound(&newport_con) && newport_has_init) {
|
||||
newport_exit();
|
||||
newport_has_init = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
|
||||
int width)
|
||||
{
|
||||
int xend = ((sx + width) << 3) - 1;
|
||||
int ystart = ((sy << 4) + topscan) & 0x3ff;
|
||||
int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
|
||||
|
||||
if (logo_active)
|
||||
return;
|
||||
|
||||
if (ystart < yend) {
|
||||
newport_clear_screen(sx << 3, ystart, xend, yend,
|
||||
(vc->vc_color & 0xf0) >> 4);
|
||||
} else {
|
||||
newport_clear_screen(sx << 3, ystart, xend, 1023,
|
||||
(vc->vc_color & 0xf0) >> 4);
|
||||
newport_clear_screen(sx << 3, 0, xend, yend,
|
||||
(vc->vc_color & 0xf0) >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
static void newport_putc(struct vc_data *vc, int charattr, int ypos,
|
||||
int xpos)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
|
||||
charattr = (charattr >> 8) & 0xff;
|
||||
xpos <<= 3;
|
||||
ypos <<= 4;
|
||||
|
||||
newport_render_background(xpos, ypos, xpos, ypos,
|
||||
(charattr & 0xf0) >> 4);
|
||||
|
||||
/* Set the color and drawing mode. */
|
||||
newport_wait(npregs);
|
||||
npregs->set.colori = charattr & 0xf;
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
|
||||
NPORT_DMODE0_L32);
|
||||
|
||||
/* Set coordinates for bitmap operation. */
|
||||
npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
|
||||
npregs->set.xyendi = ((xpos + 7) << 16);
|
||||
newport_wait(npregs);
|
||||
|
||||
/* Go, baby, go... */
|
||||
RENDER(npregs, p);
|
||||
}
|
||||
|
||||
static void newport_putcs(struct vc_data *vc, const unsigned short *s,
|
||||
int count, int ypos, int xpos)
|
||||
{
|
||||
int i;
|
||||
int charattr;
|
||||
unsigned char *p;
|
||||
|
||||
charattr = (scr_readw(s) >> 8) & 0xff;
|
||||
|
||||
xpos <<= 3;
|
||||
ypos <<= 4;
|
||||
|
||||
if (!logo_active)
|
||||
/* Clear the area behing the string */
|
||||
newport_render_background(xpos, ypos,
|
||||
xpos + ((count - 1) << 3), ypos,
|
||||
(charattr & 0xf0) >> 4);
|
||||
|
||||
newport_wait(npregs);
|
||||
|
||||
/* Set the color and drawing mode. */
|
||||
npregs->set.colori = charattr & 0xf;
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
|
||||
NPORT_DMODE0_L32);
|
||||
|
||||
for (i = 0; i < count; i++, xpos += 8) {
|
||||
p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
|
||||
|
||||
newport_wait(npregs);
|
||||
|
||||
/* Set coordinates for bitmap operation. */
|
||||
npregs->set.xystarti =
|
||||
(xpos << 16) | ((ypos + topscan) & 0x3ff);
|
||||
npregs->set.xyendi = ((xpos + 7) << 16);
|
||||
|
||||
/* Go, baby, go... */
|
||||
RENDER(npregs, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void newport_cursor(struct vc_data *vc, int mode)
|
||||
{
|
||||
unsigned short treg;
|
||||
int xcurs, ycurs;
|
||||
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
|
||||
newport_vc2_set(npregs, VC2_IREG_CONTROL,
|
||||
(treg & ~(VC2_CTRL_ECDISP)));
|
||||
break;
|
||||
|
||||
case CM_MOVE:
|
||||
case CM_DRAW:
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
|
||||
newport_vc2_set(npregs, VC2_IREG_CONTROL,
|
||||
(treg | VC2_CTRL_ECDISP));
|
||||
xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
|
||||
ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
|
||||
xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
|
||||
newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
|
||||
newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
|
||||
}
|
||||
}
|
||||
|
||||
static int newport_switch(struct vc_data *vc)
|
||||
{
|
||||
static int logo_drawn = 0;
|
||||
|
||||
topscan = 0;
|
||||
npregs->cset.topscan = 0x3ff;
|
||||
|
||||
if (!logo_drawn) {
|
||||
if (newport_show_logo()) {
|
||||
logo_drawn = 1;
|
||||
logo_active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int newport_blank(struct vc_data *c, int blank, int mode_switch)
|
||||
{
|
||||
unsigned short treg;
|
||||
|
||||
if (blank == 0) {
|
||||
/* unblank console */
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
|
||||
newport_vc2_set(npregs, VC2_IREG_CONTROL,
|
||||
(treg | VC2_CTRL_EDISP));
|
||||
} else {
|
||||
/* blank console */
|
||||
treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
|
||||
newport_vc2_set(npregs, VC2_IREG_CONTROL,
|
||||
(treg & ~(VC2_CTRL_EDISP)));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int newport_set_font(int unit, struct console_font *op)
|
||||
{
|
||||
int w = op->width;
|
||||
int h = op->height;
|
||||
int size = h * op->charcount;
|
||||
int i;
|
||||
unsigned char *new_data, *data = op->data, *p;
|
||||
|
||||
/* ladis: when I grow up, there will be a day... and more sizes will
|
||||
* be supported ;-) */
|
||||
if ((w != 8) || (h != 16)
|
||||
|| (op->charcount != 256 && op->charcount != 512))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size,
|
||||
GFP_USER))) return -ENOMEM;
|
||||
|
||||
new_data += FONT_EXTRA_WORDS * sizeof(int);
|
||||
FNTSIZE(new_data) = size;
|
||||
FNTCHARCNT(new_data) = op->charcount;
|
||||
REFCOUNT(new_data) = 0; /* usage counter */
|
||||
|
||||
p = new_data;
|
||||
for (i = 0; i < op->charcount; i++) {
|
||||
memcpy(p, data, h);
|
||||
data += 32;
|
||||
p += h;
|
||||
}
|
||||
|
||||
/* check if font is already used by other console */
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (font_data[i] != FONT_DATA
|
||||
&& FNTSIZE(font_data[i]) == size
|
||||
&& !memcmp(font_data[i], new_data, size)) {
|
||||
kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
|
||||
/* current font is the same as the new one */
|
||||
if (i == unit)
|
||||
return 0;
|
||||
new_data = font_data[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* old font is user font */
|
||||
if (font_data[unit] != FONT_DATA) {
|
||||
if (--REFCOUNT(font_data[unit]) == 0)
|
||||
kfree(font_data[unit] -
|
||||
FONT_EXTRA_WORDS * sizeof(int));
|
||||
}
|
||||
REFCOUNT(new_data)++;
|
||||
font_data[unit] = new_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int newport_set_def_font(int unit, struct console_font *op)
|
||||
{
|
||||
if (font_data[unit] != FONT_DATA) {
|
||||
if (--REFCOUNT(font_data[unit]) == 0)
|
||||
kfree(font_data[unit] -
|
||||
FONT_EXTRA_WORDS * sizeof(int));
|
||||
font_data[unit] = FONT_DATA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name)
|
||||
{
|
||||
return newport_set_def_font(vc->vc_num, op);
|
||||
}
|
||||
|
||||
static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags)
|
||||
{
|
||||
return newport_set_font(vc->vc_num, font);
|
||||
}
|
||||
|
||||
static int newport_set_palette(struct vc_data *vc, unsigned char *table)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int newport_scrolldelta(struct vc_data *vc, int lines)
|
||||
{
|
||||
/* there is (nearly) no off-screen memory, so we can't scroll back */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
|
||||
int lines)
|
||||
{
|
||||
int count, x, y;
|
||||
unsigned short *s, *d;
|
||||
unsigned short chattr;
|
||||
|
||||
logo_active = 0; /* it's time to disable the logo now.. */
|
||||
|
||||
if (t == 0 && b == vc->vc_rows) {
|
||||
if (dir == SM_UP) {
|
||||
topscan = (topscan + (lines << 4)) & 0x3ff;
|
||||
newport_clear_lines(vc->vc_rows - lines,
|
||||
vc->vc_rows - 1,
|
||||
(vc->vc_color & 0xf0) >> 4);
|
||||
} else {
|
||||
topscan = (topscan + (-lines << 4)) & 0x3ff;
|
||||
newport_clear_lines(0, lines - 1,
|
||||
(vc->vc_color & 0xf0) >> 4);
|
||||
}
|
||||
npregs->cset.topscan = (topscan - 1) & 0x3ff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = (b - t - lines) * vc->vc_cols;
|
||||
if (dir == SM_UP) {
|
||||
x = 0;
|
||||
y = t;
|
||||
s = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * (t + lines));
|
||||
d = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * t);
|
||||
while (count--) {
|
||||
chattr = scr_readw(s++);
|
||||
if (chattr != scr_readw(d)) {
|
||||
newport_putc(vc, chattr, y, x);
|
||||
scr_writew(chattr, d);
|
||||
}
|
||||
d++;
|
||||
if (++x == vc->vc_cols) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
d = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * (b - lines));
|
||||
x = 0;
|
||||
y = b - lines;
|
||||
for (count = 0; count < (lines * vc->vc_cols); count++) {
|
||||
if (scr_readw(d) != vc->vc_video_erase_char) {
|
||||
newport_putc(vc, vc->vc_video_erase_char,
|
||||
y, x);
|
||||
scr_writew(vc->vc_video_erase_char, d);
|
||||
}
|
||||
d++;
|
||||
if (++x == vc->vc_cols) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
x = vc->vc_cols - 1;
|
||||
y = b - 1;
|
||||
s = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * (b - lines) - 2);
|
||||
d = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * b - 2);
|
||||
while (count--) {
|
||||
chattr = scr_readw(s--);
|
||||
if (chattr != scr_readw(d)) {
|
||||
newport_putc(vc, chattr, y, x);
|
||||
scr_writew(chattr, d);
|
||||
}
|
||||
d--;
|
||||
if (x-- == 0) {
|
||||
x = vc->vc_cols - 1;
|
||||
y--;
|
||||
}
|
||||
}
|
||||
d = (unsigned short *) (vc->vc_origin +
|
||||
vc->vc_size_row * t);
|
||||
x = 0;
|
||||
y = t;
|
||||
for (count = 0; count < (lines * vc->vc_cols); count++) {
|
||||
if (scr_readw(d) != vc->vc_video_erase_char) {
|
||||
newport_putc(vc, vc->vc_video_erase_char,
|
||||
y, x);
|
||||
scr_writew(vc->vc_video_erase_char, d);
|
||||
}
|
||||
d++;
|
||||
if (++x == vc->vc_cols) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy,
|
||||
int dx, int h, int w)
|
||||
{
|
||||
short xs, ys, xe, ye, xoffs, yoffs, tmp;
|
||||
|
||||
xs = sx << 3;
|
||||
xe = ((sx + w) << 3) - 1;
|
||||
/*
|
||||
* as bmove is only used to move stuff around in the same line
|
||||
* (h == 1), we don't care about wrap arounds caused by topscan != 0
|
||||
*/
|
||||
ys = ((sy << 4) + topscan) & 0x3ff;
|
||||
ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff;
|
||||
xoffs = (dx - sx) << 3;
|
||||
yoffs = (dy - sy) << 4;
|
||||
if (xoffs > 0) {
|
||||
/* move to the right, exchange starting points */
|
||||
tmp = xe;
|
||||
xe = xs;
|
||||
xs = tmp;
|
||||
}
|
||||
newport_wait(npregs);
|
||||
npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
|
||||
NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
|
||||
| NPORT_DMODE0_STOPY);
|
||||
npregs->set.xystarti = (xs << 16) | ys;
|
||||
npregs->set.xyendi = (xe << 16) | ye;
|
||||
npregs->go.xymove = (xoffs << 16) | yoffs;
|
||||
}
|
||||
|
||||
static int newport_dummy(struct vc_data *c)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DUMMY (void *) newport_dummy
|
||||
|
||||
const struct consw newport_con = {
|
||||
.owner = THIS_MODULE,
|
||||
.con_startup = newport_startup,
|
||||
.con_init = newport_init,
|
||||
.con_deinit = newport_deinit,
|
||||
.con_clear = newport_clear,
|
||||
.con_putc = newport_putc,
|
||||
.con_putcs = newport_putcs,
|
||||
.con_cursor = newport_cursor,
|
||||
.con_scroll = newport_scroll,
|
||||
.con_bmove = newport_bmove,
|
||||
.con_switch = newport_switch,
|
||||
.con_blank = newport_blank,
|
||||
.con_font_set = newport_font_set,
|
||||
.con_font_default = newport_font_default,
|
||||
.con_set_palette = newport_set_palette,
|
||||
.con_scrolldelta = newport_scrolldelta,
|
||||
.con_set_origin = DUMMY,
|
||||
.con_save_screen = DUMMY
|
||||
};
|
||||
|
||||
static int newport_probe(struct gio_device *dev,
|
||||
const struct gio_device_id *id)
|
||||
{
|
||||
unsigned long newport_addr;
|
||||
int err;
|
||||
|
||||
if (!dev->resource.start)
|
||||
return -EINVAL;
|
||||
|
||||
if (npregs)
|
||||
return -EBUSY; /* we only support one Newport as console */
|
||||
|
||||
newport_addr = dev->resource.start + 0xF0000;
|
||||
if (!request_mem_region(newport_addr, 0x10000, "Newport"))
|
||||
return -ENODEV;
|
||||
|
||||
npregs = (struct newport_regs *)/* ioremap cannot fail */
|
||||
ioremap(newport_addr, sizeof(struct newport_regs));
|
||||
console_lock();
|
||||
err = do_take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
|
||||
console_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static void newport_remove(struct gio_device *dev)
|
||||
{
|
||||
give_up_console(&newport_con);
|
||||
iounmap((void *)npregs);
|
||||
}
|
||||
|
||||
static struct gio_device_id newport_ids[] = {
|
||||
{ .id = 0x7e },
|
||||
{ .id = 0xff }
|
||||
};
|
||||
|
||||
MODULE_ALIAS("gio:7e");
|
||||
|
||||
static struct gio_driver newport_driver = {
|
||||
.name = "newport",
|
||||
.id_table = newport_ids,
|
||||
.probe = newport_probe,
|
||||
.remove = newport_remove,
|
||||
};
|
||||
|
||||
int __init newport_console_init(void)
|
||||
{
|
||||
return gio_register_driver(&newport_driver);
|
||||
}
|
||||
|
||||
void __exit newport_console_exit(void)
|
||||
{
|
||||
gio_unregister_driver(&newport_driver);
|
||||
}
|
||||
|
||||
module_init(newport_console_init);
|
||||
module_exit(newport_console_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
82
drivers/video/console/softcursor.c
Normal file
82
drivers/video/console/softcursor.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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");
|
395
drivers/video/console/sticon.c
Normal file
395
drivers/video/console/sticon.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* linux/drivers/video/console/sticon.c - console driver using HP's STI firmware
|
||||
*
|
||||
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
|
||||
* Copyright (C) 2002 Helge Deller <deller@gmx.de>
|
||||
*
|
||||
* Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
|
||||
* which were
|
||||
*
|
||||
* Created 28 Sep 1997 by Geert Uytterhoeven
|
||||
* Rewritten by Martin Mares <mj@ucw.cz>, July 1998
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* 1995 Jay Estabrook
|
||||
* Copyright (C) 1995 Geert Uytterhoeven
|
||||
* Copyright (C) 1993 Bjoern Brauel
|
||||
* Roman Hodek
|
||||
* Copyright (C) 1993 Hamish Macdonald
|
||||
* Greg Harp
|
||||
* Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]
|
||||
*
|
||||
* with work by William Rucklidge (wjr@cs.cornell.edu)
|
||||
* Geert Uytterhoeven
|
||||
* Jes Sorensen (jds@kom.auc.dk)
|
||||
* Martin Apel
|
||||
* with work by Guenther Kelleter
|
||||
* Martin Schaller
|
||||
* Andreas Schwab
|
||||
* Emmanuel Marty (core@ggi-project.org)
|
||||
* Jakub Jelinek (jj@ultra.linux.cz)
|
||||
* Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/selection.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "../fbdev/sticore.h"
|
||||
|
||||
/* switching to graphics mode */
|
||||
#define BLANK 0
|
||||
static int vga_is_gfx;
|
||||
|
||||
/* this is the sti_struct used for this console */
|
||||
static struct sti_struct *sticon_sti;
|
||||
|
||||
/* Software scrollback */
|
||||
static unsigned long softback_buf, softback_curr;
|
||||
static unsigned long softback_in;
|
||||
static unsigned long /* softback_top, */ softback_end;
|
||||
static int softback_lines;
|
||||
|
||||
/* software cursor */
|
||||
static int cursor_drawn;
|
||||
#define CURSOR_DRAW_DELAY (1)
|
||||
#define DEFAULT_CURSOR_BLINK_RATE (20)
|
||||
|
||||
static int vbl_cursor_cnt;
|
||||
|
||||
static inline void cursor_undrawn(void)
|
||||
{
|
||||
vbl_cursor_cnt = 0;
|
||||
cursor_drawn = 0;
|
||||
}
|
||||
|
||||
static const char *sticon_startup(void)
|
||||
{
|
||||
return "STI console";
|
||||
}
|
||||
|
||||
static int sticon_set_palette(struct vc_data *c, unsigned char *table)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
|
||||
{
|
||||
int redraw_cursor = 0;
|
||||
|
||||
if (vga_is_gfx || console_blanked)
|
||||
return;
|
||||
|
||||
if (conp->vc_mode != KD_TEXT)
|
||||
return;
|
||||
#if 0
|
||||
if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
|
||||
cursor_undrawn();
|
||||
redraw_cursor = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
sti_putc(sticon_sti, c, ypos, xpos);
|
||||
|
||||
if (redraw_cursor)
|
||||
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
|
||||
}
|
||||
|
||||
static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
|
||||
int count, int ypos, int xpos)
|
||||
{
|
||||
int redraw_cursor = 0;
|
||||
|
||||
if (vga_is_gfx || console_blanked)
|
||||
return;
|
||||
|
||||
if (conp->vc_mode != KD_TEXT)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
|
||||
(p->cursor_x < (xpos + count))) {
|
||||
cursor_undrawn();
|
||||
redraw_cursor = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (count--) {
|
||||
sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++);
|
||||
}
|
||||
|
||||
if (redraw_cursor)
|
||||
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
|
||||
}
|
||||
|
||||
static void sticon_cursor(struct vc_data *conp, int mode)
|
||||
{
|
||||
unsigned short car1;
|
||||
|
||||
car1 = conp->vc_screenbuf[conp->vc_x + conp->vc_y * conp->vc_cols];
|
||||
switch (mode) {
|
||||
case CM_ERASE:
|
||||
sti_putc(sticon_sti, car1, conp->vc_y, conp->vc_x);
|
||||
break;
|
||||
case CM_MOVE:
|
||||
case CM_DRAW:
|
||||
switch (conp->vc_cursor_type & 0x0f) {
|
||||
case CUR_UNDERLINE:
|
||||
case CUR_LOWER_THIRD:
|
||||
case CUR_LOWER_HALF:
|
||||
case CUR_TWO_THIRDS:
|
||||
case CUR_BLOCK:
|
||||
sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
|
||||
conp->vc_y, conp->vc_x);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
|
||||
{
|
||||
struct sti_struct *sti = sticon_sti;
|
||||
|
||||
if (vga_is_gfx)
|
||||
return 0;
|
||||
|
||||
sticon_cursor(conp, CM_ERASE);
|
||||
|
||||
switch (dir) {
|
||||
case SM_UP:
|
||||
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
|
||||
sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
|
||||
break;
|
||||
|
||||
case SM_DOWN:
|
||||
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
|
||||
sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sticon_bmove(struct vc_data *conp, int sy, int sx,
|
||||
int dy, int dx, int height, int width)
|
||||
{
|
||||
if (!width || !height)
|
||||
return;
|
||||
#if 0
|
||||
if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
|
||||
(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
|
||||
((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
|
||||
(dx <= p->cursor_x) && (p->cursor_x < dx+width)))
|
||||
sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/);
|
||||
#endif
|
||||
|
||||
sti_bmove(sticon_sti, sy, sx, dy, dx, height, width);
|
||||
}
|
||||
|
||||
static void sticon_init(struct vc_data *c, int init)
|
||||
{
|
||||
struct sti_struct *sti = sticon_sti;
|
||||
int vc_cols, vc_rows;
|
||||
|
||||
sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
|
||||
vc_cols = sti_onscreen_x(sti) / sti->font_width;
|
||||
vc_rows = sti_onscreen_y(sti) / sti->font_height;
|
||||
c->vc_can_do_color = 1;
|
||||
|
||||
if (init) {
|
||||
c->vc_cols = vc_cols;
|
||||
c->vc_rows = vc_rows;
|
||||
} else {
|
||||
/* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */
|
||||
/* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */
|
||||
vc_resize(c, vc_cols, vc_rows);
|
||||
/* vc_resize_con(vc_rows, vc_cols, c->vc_num); */
|
||||
}
|
||||
}
|
||||
|
||||
static void sticon_deinit(struct vc_data *c)
|
||||
{
|
||||
}
|
||||
|
||||
static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
|
||||
int width)
|
||||
{
|
||||
if (!height || !width)
|
||||
return;
|
||||
|
||||
sti_clear(sticon_sti, sy, sx, height, width, conp->vc_video_erase_char);
|
||||
}
|
||||
|
||||
static int sticon_switch(struct vc_data *conp)
|
||||
{
|
||||
return 1; /* needs refreshing */
|
||||
}
|
||||
|
||||
static int sticon_set_origin(struct vc_data *conp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
|
||||
{
|
||||
if (blank == 0) {
|
||||
if (mode_switch)
|
||||
vga_is_gfx = 0;
|
||||
return 1;
|
||||
}
|
||||
sticon_set_origin(c);
|
||||
sti_clear(sticon_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
|
||||
if (mode_switch)
|
||||
vga_is_gfx = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sticon_scrolldelta(struct vc_data *conp, int lines)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
|
||||
{
|
||||
int line;
|
||||
unsigned long p;
|
||||
|
||||
if (conp->vc_num != fg_console || !softback_lines)
|
||||
return (u16 *)(conp->vc_origin + offset);
|
||||
line = offset / conp->vc_size_row;
|
||||
if (line >= softback_lines)
|
||||
return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
|
||||
p = softback_curr + offset;
|
||||
if (p >= softback_end)
|
||||
p += softback_buf - softback_end;
|
||||
return (u16 *)p;
|
||||
}
|
||||
|
||||
static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
|
||||
int *px, int *py)
|
||||
{
|
||||
int x, y;
|
||||
unsigned long ret;
|
||||
if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
|
||||
unsigned long offset = (pos - conp->vc_origin) / 2;
|
||||
|
||||
x = offset % conp->vc_cols;
|
||||
y = offset / conp->vc_cols;
|
||||
if (conp->vc_num == fg_console)
|
||||
y += softback_lines;
|
||||
ret = pos + (conp->vc_cols - x) * 2;
|
||||
} else if (conp->vc_num == fg_console && softback_lines) {
|
||||
unsigned long offset = pos - softback_curr;
|
||||
|
||||
if (pos < softback_curr)
|
||||
offset += softback_end - softback_buf;
|
||||
offset /= 2;
|
||||
x = offset % conp->vc_cols;
|
||||
y = offset / conp->vc_cols;
|
||||
ret = pos + (conp->vc_cols - x) * 2;
|
||||
if (ret == softback_end)
|
||||
ret = softback_buf;
|
||||
if (ret == softback_in)
|
||||
ret = conp->vc_origin;
|
||||
} else {
|
||||
/* Should not happen */
|
||||
x = y = 0;
|
||||
ret = conp->vc_origin;
|
||||
}
|
||||
if (px) *px = x;
|
||||
if (py) *py = y;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
|
||||
u8 blink, u8 underline, u8 reverse, u8 italic)
|
||||
{
|
||||
u8 attr = ((color & 0x70) >> 1) | ((color & 7));
|
||||
|
||||
if (reverse) {
|
||||
color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
|
||||
{
|
||||
int col = 1; /* vga_can_do_color; */
|
||||
|
||||
while (count--) {
|
||||
u16 a = scr_readw(p);
|
||||
|
||||
if (col)
|
||||
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
|
||||
else
|
||||
a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
|
||||
|
||||
scr_writew(a, p++);
|
||||
}
|
||||
}
|
||||
|
||||
static void sticon_save_screen(struct vc_data *conp)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct consw sti_con = {
|
||||
.owner = THIS_MODULE,
|
||||
.con_startup = sticon_startup,
|
||||
.con_init = sticon_init,
|
||||
.con_deinit = sticon_deinit,
|
||||
.con_clear = sticon_clear,
|
||||
.con_putc = sticon_putc,
|
||||
.con_putcs = sticon_putcs,
|
||||
.con_cursor = sticon_cursor,
|
||||
.con_scroll = sticon_scroll,
|
||||
.con_bmove = sticon_bmove,
|
||||
.con_switch = sticon_switch,
|
||||
.con_blank = sticon_blank,
|
||||
.con_set_palette = sticon_set_palette,
|
||||
.con_scrolldelta = sticon_scrolldelta,
|
||||
.con_set_origin = sticon_set_origin,
|
||||
.con_save_screen = sticon_save_screen,
|
||||
.con_build_attr = sticon_build_attr,
|
||||
.con_invert_region = sticon_invert_region,
|
||||
.con_screen_pos = sticon_screen_pos,
|
||||
.con_getxy = sticon_getxy,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int __init sticonsole_init(void)
|
||||
{
|
||||
int err;
|
||||
/* already initialized ? */
|
||||
if (sticon_sti)
|
||||
return 0;
|
||||
|
||||
sticon_sti = sti_get_rom(0);
|
||||
if (!sticon_sti)
|
||||
return -ENODEV;
|
||||
|
||||
if (conswitchp == &dummy_con) {
|
||||
printk(KERN_INFO "sticon: Initializing STI text console.\n");
|
||||
console_lock();
|
||||
err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
|
||||
console_unlock();
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(sticonsole_init);
|
||||
MODULE_LICENSE("GPL");
|
1119
drivers/video/console/sticore.c
Normal file
1119
drivers/video/console/sticore.c
Normal file
File diff suppressed because it is too large
Load diff
159
drivers/video/console/tileblit.c
Normal file
159
drivers/video/console/tileblit.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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");
|
||||
|
1446
drivers/video/console/vgacon.c
Normal file
1446
drivers/video/console/vgacon.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue