Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 466 → Rev 468

/shark/trunk/drivers/fb/cfbcopyarea.c
0,0 → 1,435
/*
* Generic function for frame buffer with packed pixels of any depth.
*
* Copyright (C) June 1999 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.
*
* NOTES:
*
* This is for cfb packed pixels. Iplan and such are incorporated in the
* drivers that need them.
*
* FIXME
* The code for 24 bit is horrible. It copies byte by byte size instead of
* longs like the other sizes. Needs to be optimized.
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <linux/slab.h>
#include <asm/types.h>
#include <asm/io.h>
 
#define LONG_MASK (BITS_PER_LONG - 1)
 
#if BITS_PER_LONG == 32
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
#define SHIFT_PER_LONG 5
#define BYTES_PER_LONG 4
#else
#define FB_WRITEL fb_writeq
#define FB_READL fb_readq
#define SHIFT_PER_LONG 6
#define BYTES_PER_LONG 8
#endif
 
static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
int src_idx, unsigned long n)
{
unsigned long first, last;
int shift = dst_idx-src_idx, left, right;
unsigned long d0, d1;
int m;
if (!n)
return;
shift = dst_idx-src_idx;
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (!shift) {
// Same alignment for source and dest
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL((FB_READL(src) & first) |
(FB_READL(dst) & ~first), dst);
dst++;
src++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
FB_WRITEL(FB_READL(src++), dst++);
n -= 8;
}
while (n--)
FB_WRITEL(FB_READL(src++), dst++);
// Trailing bits
if (last)
FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
}
} else {
// Different alignment for source and dest
right = shift & (BITS_PER_LONG-1);
left = -shift & (BITS_PER_LONG-1);
if (dst_idx+n <= BITS_PER_LONG) {
// Single destination word
if (last)
first &= last;
if (shift > 0) {
// Single source word
FB_WRITEL(((FB_READL(src) >> right) & first) |
(FB_READL(dst) & ~first), dst);
} else if (src_idx+n <= BITS_PER_LONG) {
// Single source word
FB_WRITEL(((FB_READL(src) << left) & first) |
(FB_READL(dst) & ~first), dst);
} else {
// 2 source words
d0 = FB_READL(src++);
d1 = FB_READL(src);
FB_WRITEL(((d0<<left | d1>>right) & first) |
(FB_READL(dst) & ~first), dst);
}
} else {
// Multiple destination words
d0 = FB_READL(src++);
// Leading bits
if (shift > 0) {
// Single source word
FB_WRITEL(((d0 >> right) & first) |
(FB_READL(dst) & ~first), dst);
dst++;
n -= BITS_PER_LONG-dst_idx;
} else {
// 2 source words
d1 = FB_READL(src++);
FB_WRITEL(((d0<<left | d1>>right) & first) |
(FB_READL(dst) & ~first), dst);
d0 = d1;
dst++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
m = n % BITS_PER_LONG;
n /= BITS_PER_LONG;
while (n >= 4) {
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
}
// Trailing bits
if (last) {
if (m <= right) {
// Single source word
FB_WRITEL(((d0 << left) & last) |
(FB_READL(dst) & ~last),
dst);
} else {
// 2 source words
d1 = FB_READL(src);
FB_WRITEL(((d0<<left | d1>>right) &
last) | (FB_READL(dst) &
~last), dst);
}
}
}
}
}
 
static void bitcpy_rev(unsigned long *dst, int dst_idx,
const unsigned long *src, int src_idx, unsigned long n)
{
unsigned long first, last;
int shift = dst_idx-src_idx, left, right;
unsigned long d0, d1;
int m;
if (!n)
return;
dst += (n-1)/BITS_PER_LONG;
src += (n-1)/BITS_PER_LONG;
if ((n-1) % BITS_PER_LONG) {
dst_idx += (n-1) % BITS_PER_LONG;
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= BITS_PER_LONG-1;
src_idx += (n-1) % BITS_PER_LONG;
src += src_idx >> SHIFT_PER_LONG;
src_idx &= BITS_PER_LONG-1;
}
shift = dst_idx-src_idx;
first = ~0UL << (BITS_PER_LONG-1-dst_idx);
last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
if (!shift) {
// Same alignment for source and dest
if ((unsigned long)dst_idx+1 >= n) {
// Single word
if (last)
first &= last;
FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), dst);
dst--;
src--;
n -= dst_idx+1;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
FB_WRITEL(FB_READL(src--), dst--);
n -= 8;
}
while (n--)
FB_WRITEL(FB_READL(src--), dst--);
// Trailing bits
if (last)
FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & ~last), dst);
}
} else {
// Different alignment for source and dest
right = shift & (BITS_PER_LONG-1);
left = -shift & (BITS_PER_LONG-1);
if ((unsigned long)dst_idx+1 >= n) {
// Single destination word
if (last)
first &= last;
if (shift < 0) {
// Single source word
FB_WRITEL((FB_READL(src) << left & first) |
(FB_READL(dst) & ~first), dst);
} else if (1+(unsigned long)src_idx >= n) {
// Single source word
FB_WRITEL(((FB_READL(src) >> right) & first) |
(FB_READL(dst) & ~first), dst);
} else {
// 2 source words
d0 = FB_READL(src--);
d1 = FB_READL(src);
FB_WRITEL(((d0>>right | d1<<left) & first) |
(FB_READL(dst) & ~first), dst);
}
} else {
// Multiple destination words
d0 = FB_READL(src--);
// Leading bits
if (shift < 0) {
// Single source word
FB_WRITEL(((d0 << left) & first) |
(FB_READL(dst) & ~first), dst);
dst--;
n -= dst_idx+1;
} else {
// 2 source words
d1 = FB_READL(src--);
FB_WRITEL(((d0>>right | d1<<left) & first) |
(FB_READL(dst) & ~first), dst);
d0 = d1;
dst--;
n -= dst_idx+1;
}
// Main chunk
m = n % BITS_PER_LONG;
n /= BITS_PER_LONG;
while (n >= 4) {
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
n -= 4;
}
while (n--) {
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
}
// Trailing bits
if (last) {
if (m <= left) {
// Single source word
FB_WRITEL(((d0 >> right) & last) |
(FB_READL(dst) & ~last),
dst);
} else {
// 2 source words
d1 = FB_READL(src);
FB_WRITEL(((d0>>right | d1<<left) &
last) | (FB_READL(dst) &
~last), dst);
}
}
}
}
}
 
void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width;
int x2, y2, old_dx, old_dy, vxres, vyres;
unsigned long next_line = p->fix.line_length;
int dst_idx = 0, src_idx = 0, rev_copy = 0;
unsigned long *dst = NULL, *src = NULL;
 
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
 
if (area->dx > vxres || area->sx > vxres ||
area->dy > vyres || area->sy > vyres)
return;
 
/* clip the destination */
old_dx = area->dx;
old_dy = area->dy;
 
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly.
*/
x2 = area->dx + area->width;
y2 = area->dy + area->height;
dx = area->dx > 0 ? area->dx : 0;
dy = area->dy > 0 ? area->dy : 0;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
width = x2 - dx;
height = y2 - dy;
 
/* update sx1,sy1 */
sx += (dx - old_dx);
sy += (dy - old_dy);
 
/* the source must be completely inside the virtual screen */
if (sx < 0 || sy < 0 ||
(sx + width) > vxres ||
(sy + height) > vyres)
return;
 
if ((dy == sy && dx > sx) ||
(dy > sy)) {
dy += height;
sy += height;
rev_copy = 1;
}
 
dst = src = (unsigned long *)((unsigned long)p->screen_base &
~(BYTES_PER_LONG-1));
dst_idx = src_idx = (unsigned long)p->screen_base & (BYTES_PER_LONG-1);
dst_idx += dy*next_line*8 + dx*p->var.bits_per_pixel;
src_idx += sy*next_line*8 + sx*p->var.bits_per_pixel;
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
if (rev_copy) {
while (height--) {
dst_idx -= next_line*8;
src_idx -= next_line*8;
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BYTES_PER_LONG-1);
src += src_idx >> SHIFT_PER_LONG;
src_idx &= (BYTES_PER_LONG-1);
bitcpy_rev(dst, dst_idx, src, src_idx,
width*p->var.bits_per_pixel);
}
} else {
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BYTES_PER_LONG-1);
src += src_idx >> SHIFT_PER_LONG;
src_idx &= (BYTES_PER_LONG-1);
bitcpy(dst, dst_idx, src, src_idx,
width*p->var.bits_per_pixel);
dst_idx += next_line*8;
src_idx += next_line*8;
}
}
}
 
EXPORT_SYMBOL(cfb_copyarea);
 
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("Generic software accelerated copyarea");
MODULE_LICENSE("GPL");
 
/shark/trunk/drivers/fb/vgastate.c
0,0 → 1,505
/*
* linux/drivers/video/vgastate.c -- VGA state save/restore
*
* Copyright 2002 James Simmons
*
* Copyright history from vga16fb.c:
* Copyright 1999 Ben Pfaff and Petr Vandrovec
* Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
* Based on VESA framebuffer (c) 1998 Gerd Knorr
*
* 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 <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
#include <video/vga.h>
 
struct regstate {
__u8 *vga_font0;
__u8 *vga_font1;
__u8 *vga_text;
__u8 *vga_cmap;
__u8 *attr;
__u8 *crtc;
__u8 *gfx;
__u8 *seq;
__u8 misc;
};
 
static inline unsigned char vga_rcrtcs(caddr_t regbase, unsigned short iobase,
unsigned char reg)
{
vga_w(regbase, iobase + 0x4, reg);
return vga_r(regbase, iobase + 0x5);
}
 
static inline void vga_wcrtcs(caddr_t regbase, unsigned short iobase,
unsigned char reg, unsigned char val)
{
vga_w(regbase, iobase + 0x4, reg);
vga_w(regbase, iobase + 0x5, val);
}
 
static void save_vga_text(struct vgastate *state, caddr_t fbbase)
{
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4;
 
/* if in graphics mode, no need to save */
attr10 = vga_rattr(state->vgabase, 0x10);
if (attr10 & 1)
return;
/* save regs */
misc = vga_r(state->vgabase, VGA_MIS_R);
gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
/* force graphics mode */
vga_w(state->vgabase, VGA_MIS_W, misc | 1);
 
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
 
/* save font at plane 2 */
if (state->flags & VGA_SAVE_FONT0) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 4 * 8192; i++)
saved->vga_font0[i] = vga_r(fbbase, i);
}
 
/* save font at plane 3 */
if (state->flags & VGA_SAVE_FONT1) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < state->memsize; i++)
saved->vga_font1[i] = vga_r(fbbase, i);
}
/* save font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
saved->vga_text[i] = vga_r(fbbase, i);
 
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
}
 
/* restore regs */
vga_wattr(state->vgabase, 0x10, attr10);
 
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
 
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
vga_w(state->vgabase, VGA_MIS_W, misc);
 
/* unblank screen */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5));
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
 
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1);
}
 
static void restore_vga_text(struct vgastate *state, caddr_t fbbase)
{
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
u8 misc, gr1, gr3, gr4, gr5, gr6, gr8;
u8 seq1, seq2, seq4;
 
/* save regs */
misc = vga_r(state->vgabase, VGA_MIS_R);
gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE);
gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE);
gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
/* force graphics mode */
vga_w(state->vgabase, VGA_MIS_W, misc | 1);
 
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
 
if (state->depth == 4) {
vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff);
vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00);
}
/* restore font at plane 2 */
if (state->flags & VGA_SAVE_FONT0) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 4 * 8192; i++)
vga_w(fbbase, i, saved->vga_font0[i]);
}
 
/* restore font at plane 3 */
if (state->flags & VGA_SAVE_FONT1) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < state->memsize; i++)
vga_w(fbbase, i, saved->vga_font1[i]);
}
/* restore font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[i]);
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[8192+i]);
}
 
/* unblank screen */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5));
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
 
/* restore regs */
vga_w(state->vgabase, VGA_MIS_W, misc);
 
vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1);
vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, gr8);
 
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1);
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
}
static void save_vga_mode(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
unsigned short iobase;
int i;
 
saved->misc = vga_r(state->vgabase, VGA_MIS_R);
if (saved->misc & 1)
iobase = 0x3d0;
else
iobase = 0x3b0;
 
for (i = 0; i < state->num_crtc; i++)
saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i);
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
for (i = 0; i < state->num_attr; i++) {
vga_r(state->vgabase, iobase + 0xa);
saved->attr[i] = vga_rattr(state->vgabase, i);
}
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x20);
 
for (i = 0; i < state->num_gfx; i++)
saved->gfx[i] = vga_rgfx(state->vgabase, i);
 
for (i = 0; i < state->num_seq; i++)
saved->seq[i] = vga_rseq(state->vgabase, i);
}
 
static void restore_vga_mode(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
unsigned short iobase;
int i;
 
vga_w(state->vgabase, VGA_MIS_W, saved->misc);
 
if (saved->misc & 1)
iobase = 0x3d0;
else
iobase = 0x3b0;
 
/* turn off display */
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
 
/* disable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
/* enable palette addressing */
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
 
for (i = 2; i < state->num_seq; i++)
vga_wseq(state->vgabase, i, saved->seq[i]);
 
 
/* unprotect vga regs */
vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80);
for (i = 0; i < state->num_crtc; i++)
vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]);
for (i = 0; i < state->num_gfx; i++)
vga_wgfx(state->vgabase, i, saved->gfx[i]);
 
for (i = 0; i < state->num_attr; i++) {
vga_r(state->vgabase, iobase + 0xa);
vga_wattr(state->vgabase, i, saved->attr[i]);
}
 
/* reenable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
/* turn display on */
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5));
 
/* disable video/palette source */
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x20);
}
 
static void save_vga_cmap(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
 
vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
/* assumes DAC is readable and writable */
vga_w(state->vgabase, VGA_PEL_IR, 0x00);
for (i = 0; i < 768; i++)
saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D);
}
 
static void restore_vga_cmap(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
 
vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
 
/* assumes DAC is readable and writable */
vga_w(state->vgabase, VGA_PEL_IW, 0x00);
for (i = 0; i < 768; i++)
vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]);
}
 
static void vga_cleanup(struct vgastate *state)
{
if (state->vidstate != NULL) {
struct regstate *saved = (struct regstate *) state->vidstate;
 
if (saved->vga_font0)
vfree(saved->vga_font0);
if (saved->vga_font1)
vfree(saved->vga_font1);
if (saved->vga_text)
vfree(saved->vga_text);
if (saved->vga_cmap)
vfree(saved->vga_cmap);
if (saved->attr)
vfree(saved->attr);
kfree(saved);
state->vidstate = NULL;
}
}
int save_vga(struct vgastate *state)
{
struct regstate *saved;
 
saved = kmalloc(sizeof(struct regstate), GFP_KERNEL);
if (saved == NULL)
return 1;
memset (saved, 0, sizeof(struct regstate));
(struct regstate *) state->vidstate = saved;
if (state->flags & VGA_SAVE_CMAP) {
saved->vga_cmap = vmalloc(768);
if (!saved->vga_cmap) {
vga_cleanup(state);
return 1;
}
save_vga_cmap(state);
}
 
if (state->flags & VGA_SAVE_MODE) {
int total;
 
if (state->num_attr < 21)
state->num_attr = 21;
if (state->num_crtc < 25)
state->num_crtc = 25;
if (state->num_gfx < 9)
state->num_gfx = 9;
if (state->num_seq < 5)
state->num_seq = 5;
total = state->num_attr + state->num_crtc +
state->num_gfx + state->num_seq;
 
saved->attr = vmalloc(total);
if (!saved->attr) {
vga_cleanup(state);
return 1;
}
saved->crtc = saved->attr + state->num_attr;
saved->gfx = saved->crtc + state->num_crtc;
saved->seq = saved->gfx + state->num_gfx;
 
save_vga_mode(state);
}
 
if (state->flags & VGA_SAVE_FONTS) {
caddr_t fbbase;
 
/* exit if window is less than 32K */
if (state->memsize && state->memsize < 4 * 8192) {
vga_cleanup(state);
return 1;
}
if (!state->memsize)
state->memsize = 8 * 8192;
if (!state->membase)
state->membase = 0xA0000;
 
fbbase = ioremap(state->membase, state->memsize);
 
if (!fbbase) {
vga_cleanup(state);
iounmap(fbbase);
return 1;
}
 
/*
* save only first 32K used by vgacon
*/
if (state->flags & VGA_SAVE_FONT0) {
saved->vga_font0 = vmalloc(4 * 8192);
if (!saved->vga_font0) {
vga_cleanup(state);
return 1;
}
}
/*
* largely unused, but if required by the caller
* we'll just save everything.
*/
if (state->flags & VGA_SAVE_FONT1) {
saved->vga_font1 = vmalloc(state->memsize);
if (!saved->vga_font1) {
vga_cleanup(state);
return 1;
}
}
/*
* Save 8K at plane0[0], and 8K at plane1[16K]
*/
if (state->flags & VGA_SAVE_TEXT) {
saved->vga_text = vmalloc(8192 * 2);
if (!saved->vga_text) {
vga_cleanup(state);
return 1;
}
}
save_vga_text(state, fbbase);
iounmap(fbbase);
}
return 0;
}
 
int restore_vga (struct vgastate *state)
{
if (state->vidstate == NULL)
return 1;
 
if (state->flags & VGA_SAVE_MODE)
restore_vga_mode(state);
 
if (state->flags & VGA_SAVE_FONTS) {
caddr_t fbbase = ioremap(state->membase, state->memsize);
 
if (!fbbase) {
vga_cleanup(state);
iounmap(fbbase);
return 1;
}
restore_vga_text(state, fbbase);
iounmap(fbbase);
}
 
if (state->flags & VGA_SAVE_CMAP)
restore_vga_cmap(state);
 
vga_cleanup(state);
return 0;
}
 
#ifdef MODULE
int init_module(void) { return 0; };
void cleanup_module(void) {};
#endif
 
EXPORT_SYMBOL(save_vga);
EXPORT_SYMBOL(restore_vga);
 
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("VGA State Save/Restore");
MODULE_LICENSE("GPL");
 
/shark/trunk/drivers/fb/cfbfillrect.c
0,0 → 1,461
/*
* Generic fillrect for frame buffers with packed pixels of any depth.
*
* Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org)
*
* 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.
*
* NOTES:
*
* The code for depths like 24 that don't have integer number of pixels per
* long is broken and needs to be fixed. For now I turned these types of
* mode off.
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
 
#if BITS_PER_LONG == 32
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
#define BYTES_PER_LONG 4
#define SHIFT_PER_LONG 5
#else
#define FB_WRITEL fb_writeq
#define FB_READL fb_readq
#define BYTES_PER_LONG 8
#define SHIFT_PER_LONG 6
#endif
 
#define EXP1(x) 0xffffffffU*x
#define EXP2(x) 0x55555555U*x
#define EXP4(x) 0x11111111U*0x ## x
 
typedef u32 pixel_t;
 
static const u32 bpp1tab[2] = {
EXP1(0), EXP1(1)
};
 
static const u32 bpp2tab[4] = {
EXP2(0), EXP2(1), EXP2(2), EXP2(3)
};
 
static const u32 bpp4tab[16] = {
EXP4(0), EXP4(1), EXP4(2), EXP4(3), EXP4(4), EXP4(5), EXP4(6), EXP4(7),
EXP4(8), EXP4(9), EXP4(a), EXP4(b), EXP4(c), EXP4(d), EXP4(e), EXP4(f)
};
 
/*
* Compose two values, using a bitmask as decision value
* This is equivalent to (a & mask) | (b & ~mask)
*/
 
static inline unsigned long comp(unsigned long a, unsigned long b,
unsigned long mask)
{
return ((a ^ b) & mask) ^ b;
}
 
static inline u32 pixel_to_pat32(const struct fb_info *p, pixel_t pixel)
{
u32 pat = pixel;
 
switch (p->var.bits_per_pixel) {
case 1:
pat = bpp1tab[pat];
break;
 
case 2:
pat = bpp2tab[pat];
break;
 
case 4:
pat = bpp4tab[pat];
break;
 
case 8:
pat |= pat << 8;
// Fall through
case 16:
pat |= pat << 16;
// Fall through
case 32:
break;
}
return pat;
}
 
/*
* Expand a pixel value to a generic 32/64-bit pattern and rotate it to
* the correct start position
*/
 
static inline unsigned long pixel_to_pat(const struct fb_info *p,
pixel_t pixel, int left)
{
unsigned long pat = pixel;
u32 bpp = p->var.bits_per_pixel;
int i;
 
/* expand pixel value */
for (i = bpp; i < BITS_PER_LONG; i *= 2)
pat |= pat << i;
 
/* rotate pattern to correct start position */
pat = pat << left | pat >> (bpp-left);
return pat;
}
 
/*
* Unaligned 32-bit pattern fill using 32/64-bit memory accesses
*/
 
void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
{
unsigned long val = pat;
unsigned long first, last;
if (!n)
return;
#if BITS_PER_LONG == 64
val |= val << 32;
#endif
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
dst++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
FB_WRITEL(val, dst++);
n -= 8;
}
while (n--)
FB_WRITEL(val, dst++);
// Trailing bits
if (last)
FB_WRITEL(comp(val, FB_READL(dst), first), dst);
}
}
 
 
/*
* Unaligned generic pattern fill using 32/64-bit memory accesses
* The pattern must have been expanded to a full 32/64-bit value
* Left/right are the appropriate shifts to convert to the pattern to be
* used for the next 32/64-bit word
*/
 
void bitfill(unsigned long *dst, int dst_idx, unsigned long pat, int left,
int right, u32 n)
{
unsigned long first, last;
 
if (!n)
return;
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
dst++;
pat = pat << left | pat >> right;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 4) {
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
n -= 4;
}
while (n--) {
FB_WRITEL(pat, dst++);
pat = pat << left | pat >> right;
}
// Trailing bits
if (last)
FB_WRITEL(comp(pat, FB_READL(dst), first), dst);
}
}
 
void bitfill32_rev(unsigned long *dst, int dst_idx, u32 pat, u32 n)
{
unsigned long val = pat, dat;
unsigned long first, last;
if (!n)
return;
#if BITS_PER_LONG == 64
val |= val << 32;
#endif
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
dst++;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 8) {
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
n -= 8;
}
while (n--) {
FB_WRITEL(FB_READL(dst) ^ val, dst);
dst++;
}
// Trailing bits
if (last) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ val, dat, first), dst);
}
}
}
 
 
/*
* Unaligned generic pattern fill using 32/64-bit memory accesses
* The pattern must have been expanded to a full 32/64-bit value
* Left/right are the appropriate shifts to convert to the pattern to be
* used for the next 32/64-bit word
*/
 
void bitfill_rev(unsigned long *dst, int dst_idx, unsigned long pat, int left,
int right, u32 n)
{
unsigned long first, last, dat;
 
if (!n)
return;
first = ~0UL >> dst_idx;
last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
if (dst_idx+n <= BITS_PER_LONG) {
// Single word
if (last)
first &= last;
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
} else {
// Multiple destination words
// Leading bits
if (first) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
dst++;
pat = pat << left | pat >> right;
n -= BITS_PER_LONG-dst_idx;
}
// Main chunk
n /= BITS_PER_LONG;
while (n >= 4) {
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
n -= 4;
}
while (n--) {
FB_WRITEL(FB_READL(dst) ^ pat, dst);
dst++;
pat = pat << left | pat >> right;
}
// Trailing bits
if (last) {
dat = FB_READL(dst);
FB_WRITEL(comp(dat ^ pat, dat, first), dst);
}
}
}
 
void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
{
u32 bpp = p->var.bits_per_pixel;
unsigned long x2, y2, vxres, vyres;
unsigned long height, width, fg;
unsigned long *dst;
int dst_idx, left;
 
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
 
if (!rect->width || !rect->height ||
rect->dx > vxres || rect->dy > vyres)
return;
 
/* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly. */
x2 = rect->dx + rect->width;
y2 = rect->dy + rect->height;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
width = x2 - rect->dx;
height = y2 - rect->dy;
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR )
fg = ((u32 *) (p->pseudo_palette))[rect->color];
else
fg = rect->color;
dst = (unsigned long *)((unsigned long)p->screen_base &
~(BYTES_PER_LONG-1));
dst_idx = ((unsigned long)p->screen_base & (BYTES_PER_LONG-1))*8;
dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
/* FIXME For now we support 1-32 bpp only */
left = BITS_PER_LONG % bpp;
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
if (!left) {
u32 pat = pixel_to_pat32(p, fg);
void (*fill_op32)(unsigned long *dst, int dst_idx, u32 pat,
u32 n) = NULL;
switch (rect->rop) {
case ROP_XOR:
fill_op32 = bitfill32_rev;
break;
case ROP_COPY:
default:
fill_op32 = bitfill32;
break;
}
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
fill_op32(dst, dst_idx, pat, width*bpp);
dst_idx += p->fix.line_length*8;
}
} else {
unsigned long pat = pixel_to_pat(p, fg, (left-dst_idx) % bpp);
int right = bpp-left;
int r;
void (*fill_op)(unsigned long *dst, int dst_idx,
unsigned long pat, int left, int right,
u32 n) = NULL;
switch (rect->rop) {
case ROP_XOR:
fill_op = bitfill_rev;
break;
case ROP_COPY:
default:
fill_op = bitfill;
break;
}
while (height--) {
dst += dst_idx >> SHIFT_PER_LONG;
dst_idx &= (BITS_PER_LONG-1);
fill_op(dst, dst_idx, pat, left, right,
width*bpp);
r = (p->fix.line_length*8) % bpp;
pat = pat << (bpp-r) | pat >> r;
dst_idx += p->fix.line_length*8;
}
}
}
 
EXPORT_SYMBOL(cfb_fillrect);
 
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("Generic software accelerated fill rectangle");
MODULE_LICENSE("GPL");
/shark/trunk/drivers/fb/fbmem.c
387,7 → 387,7
#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
#define FBPIXMAPSIZE 8192
 
extern const char *global_mode_option;
//extern const char *global_mode_option;
 
static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0;
1126,8 → 1126,8
#elif defined(__alpha__)
/* Caching is off in the I/O space quadrant by design. */
#elif defined(__i386__) || defined(__x86_64__)
if (boot_cpu_data.x86 > 3)
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
//if (boot_cpu_data.x86 > 3)
// pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
#elif defined(__mips__)
pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
1367,7 → 1367,7
* If we get here no fb was specified.
* We consider the argument to be a global video mode option.
*/
global_mode_option = options;
//global_mode_option = options;
return 0;
}
 
/shark/trunk/drivers/fb/fbcmap.c
0,0 → 1,332
/*
* linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices
*
* Created 15 Jun 1997 by Geert Uytterhoeven
*
* 2001 - Documented with DocBook
* - Brad Douglas <brad@neruo.com>
*
* 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 <linuxcomp.h>
 
#include <linux/string.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
 
#include <asm/uaccess.h>
 
static u16 red2[] = {
0x0000, 0xaaaa
};
static u16 green2[] = {
0x0000, 0xaaaa
};
static u16 blue2[] = {
0x0000, 0xaaaa
};
 
static u16 red4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
static u16 green4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
static u16 blue4[] = {
0x0000, 0xaaaa, 0x5555, 0xffff
};
 
static u16 red8[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa
};
static u16 green8[] = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa
};
static u16 blue8[] = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa
};
 
static u16 red16[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
};
static u16 green16[] = {
0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
};
static u16 blue16[] = {
0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
};
 
static struct fb_cmap default_2_colors = {
0, 2, red2, green2, blue2, NULL
};
static struct fb_cmap default_8_colors = {
0, 8, red8, green8, blue8, NULL
};
static struct fb_cmap default_4_colors = {
0, 4, red4, green4, blue4, NULL
};
static struct fb_cmap default_16_colors = {
0, 16, red16, green16, blue16, NULL
};
 
 
/**
* fb_alloc_cmap - allocate a colormap
* @cmap: frame buffer colormap structure
* @len: length of @cmap
* @transp: boolean, 1 if there is transparency, 0 otherwise
*
* Allocates memory for a colormap @cmap. @len is the
* number of entries in the palette.
*
* Returns -1 errno on error, or zero on success.
*
*/
 
int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
{
int size = len*sizeof(u16);
 
if (cmap->len != len) {
fb_dealloc_cmap(cmap);
if (!len)
return 0;
if (!(cmap->red = kmalloc(size, GFP_ATOMIC)))
return -1;
if (!(cmap->green = kmalloc(size, GFP_ATOMIC)))
return -1;
if (!(cmap->blue = kmalloc(size, GFP_ATOMIC)))
return -1;
if (transp) {
if (!(cmap->transp = kmalloc(size, GFP_ATOMIC)))
return -1;
} else
cmap->transp = NULL;
}
cmap->start = 0;
cmap->len = len;
fb_copy_cmap(fb_default_cmap(len), cmap, 0);
return 0;
}
 
/**
* fb_dealloc_cmap - deallocate a colormap
* @cmap: frame buffer colormap structure
*
* Deallocates a colormap that was previously allocated with
* fb_alloc_cmap().
*
*/
 
void fb_dealloc_cmap(struct fb_cmap *cmap)
{
if (cmap->red)
kfree(cmap->red);
if (cmap->green)
kfree(cmap->green);
if (cmap->blue)
kfree(cmap->blue);
if (cmap->transp)
kfree(cmap->transp);
 
cmap->red = cmap->green = cmap->blue = cmap->transp = NULL;
cmap->len = 0;
}
 
/**
* fb_copy_cmap - copy a colormap
* @from: frame buffer colormap structure
* @to: frame buffer colormap structure
* @fsfromto: determine copy method
*
* Copy contents of colormap from @from to @to.
*
* @fsfromto accepts the following integer parameters:
* 0: memcpy function
* 1: copy_from_user() function to copy from userspace
* 2: copy_to_user() function to copy to userspace
*
*/
 
int fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
{
int tooff = 0, fromoff = 0;
int size;
if (to->start > from->start)
fromoff = to->start-from->start;
else
tooff = from->start-to->start;
size = to->len-tooff;
if (size > (int) (from->len - fromoff))
size = from->len-fromoff;
if (size <= 0)
return -EINVAL;
size *= sizeof(u16);
switch (fsfromto) {
case 0:
memcpy(to->red+tooff, from->red+fromoff, size);
memcpy(to->green+tooff, from->green+fromoff, size);
memcpy(to->blue+tooff, from->blue+fromoff, size);
if (from->transp && to->transp)
memcpy(to->transp+tooff, from->transp+fromoff, size);
break;
case 1:
if (copy_from_user(to->red+tooff, from->red+fromoff, size))
return -EFAULT;
if (copy_from_user(to->green+tooff, from->green+fromoff, size))
return -EFAULT;
if (copy_from_user(to->blue+tooff, from->blue+fromoff, size))
return -EFAULT;
if (from->transp && to->transp)
if (copy_from_user(to->transp+tooff, from->transp+fromoff, size))
return -EFAULT;
break;
case 2:
if (copy_to_user(to->red+tooff, from->red+fromoff, size))
return -EFAULT;
if (copy_to_user(to->green+tooff, from->green+fromoff, size))
return -EFAULT;
if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
return -EFAULT;
if (from->transp && to->transp)
if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
return -EFAULT;
break;
}
return 0;
}
 
/**
* fb_set_cmap - set the colormap
* @cmap: frame buffer colormap structure
* @kspc: boolean, 0 copy local, 1 get_user() function
* @info: frame buffer info structure
*
* Sets the colormap @cmap for a screen of device @info.
*
* Returns negative errno on error, or zero on success.
*
*/
 
int fb_set_cmap(struct fb_cmap *cmap, int kspc, struct fb_info *info)
{
int i, start;
u16 *red, *green, *blue, *transp;
u_int hred, hgreen, hblue, htransp;
 
red = cmap->red;
green = cmap->green;
blue = cmap->blue;
transp = cmap->transp;
start = cmap->start;
 
if (start < 0 || !info->fbops->fb_setcolreg)
return -EINVAL;
for (i = 0; i < cmap->len; i++) {
if (kspc) {
hred = *red;
hgreen = *green;
hblue = *blue;
htransp = transp ? *transp : 0xffff;
} else {
hred = *red;
hgreen = *green;
hblue = *blue;
htransp = transp ? *transp : 0xffff;
//get_user(hred, red);
//get_user(hgreen, green);
//get_user(hblue, blue);
//if (transp)
//get_user(htransp, transp);
//else
//htransp = 0xffff;
}
red++;
green++;
blue++;
if (transp)
transp++;
if (info->fbops->fb_setcolreg(start++, hred, hgreen, hblue, htransp, info))
return 0;
}
return 0;
}
 
 
/**
* fb_default_cmap - get default colormap
* @len: size of palette for a depth
*
* Gets the default colormap for a specific screen depth. @len
* is the size of the palette for a particular screen depth.
*
* Returns pointer to a frame buffer colormap structure.
*
*/
 
struct fb_cmap *fb_default_cmap(int len)
{
if (len <= 2)
return &default_2_colors;
if (len <= 4)
return &default_4_colors;
if (len <= 8)
return &default_8_colors;
return &default_16_colors;
}
 
 
/**
* fb_invert_cmaps - invert all defaults colormaps
*
* Invert all default colormaps.
*
*/
 
void fb_invert_cmaps(void)
{
u_int i;
 
for (i = 0; i < 2; i++) {
red2[i] = ~red2[i];
green2[i] = ~green2[i];
blue2[i] = ~blue2[i];
}
for (i = 0; i < 4; i++) {
red4[i] = ~red4[i];
green4[i] = ~green4[i];
blue4[i] = ~blue4[i];
}
for (i = 0; i < 8; i++) {
red8[i] = ~red8[i];
green8[i] = ~green8[i];
blue8[i] = ~blue8[i];
}
for (i = 0; i < 16; i++) {
red16[i] = ~red16[i];
green16[i] = ~green16[i];
blue16[i] = ~blue16[i];
}
}
 
 
/*
* Visible symbols for modules
*/
 
EXPORT_SYMBOL(fb_alloc_cmap);
EXPORT_SYMBOL(fb_dealloc_cmap);
EXPORT_SYMBOL(fb_copy_cmap);
EXPORT_SYMBOL(fb_set_cmap);
EXPORT_SYMBOL(fb_default_cmap);
EXPORT_SYMBOL(fb_invert_cmaps);
/shark/trunk/drivers/fb/softcursor.c
0,0 → 1,88
/*
* linux/drivers/video/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 <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
 
#include <asm/uaccess.h>
#include <asm/io.h>
 
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
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;
u8 *dst, src[64];
 
if (cursor->set & FB_CUR_SETSIZE) {
info->cursor.image.height = cursor->image.height;
info->cursor.image.width = cursor->image.width;
}
 
if (cursor->set & FB_CUR_SETPOS) {
info->cursor.image.dx = cursor->image.dx;
info->cursor.image.dy = cursor->image.dy;
}
 
if (cursor->set & FB_CUR_SETHOT)
info->cursor.hot = cursor->hot;
if (cursor->set & FB_CUR_SETCMAP) {
if (cursor->image.depth == 1) {
info->cursor.image.bg_color = cursor->image.bg_color;
info->cursor.image.fg_color = cursor->image.fg_color;
} else {
if (cursor->image.cmap.len)
fb_copy_cmap(&cursor->image.cmap, &info->cursor.image.cmap, 0);
}
info->cursor.image.depth = cursor->image.depth;
}
 
s_pitch = (info->cursor.image.width + 7) >> 3;
dsize = s_pitch * info->cursor.image.height;
d_pitch = (s_pitch + scan_align) & ~scan_align;
size = d_pitch * info->cursor.image.height + buf_align;
size &= ~buf_align;
dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
 
if (info->cursor.enable) {
switch (info->cursor.rop) {
case ROP_XOR:
for (i = 0; i < dsize; i++)
src[i] = cursor->image.data[i] ^ info->cursor.mask[i];
break;
case ROP_COPY:
default:
for (i = 0; i < dsize; i++)
src[i] = cursor->image.data[i] & info->cursor.mask[i];
break;
}
} else
memcpy(src, cursor->image.data, dsize);
move_buf_aligned(info, dst, src, d_pitch, s_pitch, info->cursor.image.height);
info->cursor.image.data = dst;
info->fbops->fb_imageblit(info, &info->cursor.image);
atomic_dec(&info->pixmap.count);
smp_mb__after_atomic_dec();
return 0;
}
 
EXPORT_SYMBOL(soft_cursor);
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("Generic software cursor");
MODULE_LICENSE("GPL");
/shark/trunk/drivers/fb/cfbimgblt.c
0,0 → 1,340
/*
* Generic BitBLT function for frame buffer with packed pixels of any depth.
*
* Copyright (C) June 1999 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.
*
* NOTES:
*
* This function copys a image from system memory to video memory. The
* image can be a bitmap where each 0 represents the background color and
* each 1 represents the foreground color. Great for font handling. It can
* also be a color image. This is determined by image_depth. The color image
* must be laid out exactly in the same format as the framebuffer. Yes I know
* their are cards with hardware that coverts images of various depths to the
* framebuffer depth. But not every card has this. All images must be rounded
* up to the nearest byte. For example a bitmap 12 bits wide must be two
* bytes width.
*
* Tony:
* Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds
* up the code significantly.
*
* Code for depths not multiples of BITS_PER_LONG is still kludgy, which is
* still processed a bit at a time.
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
 
#define DEBUG
 
#ifdef DEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
#else
#define DPRINTK(fmt, args...)
#endif
 
static u32 cfb_tab8[] = {
#if defined(__BIG_ENDIAN)
0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
0xffff0000,0xffff00ff,0xffffff00,0xffffffff
#elif defined(__LITTLE_ENDIAN)
0x00000000,0xff000000,0x00ff0000,0xffff0000,
0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
#else
#error FIXME: No endianness??
#endif
};
 
static u32 cfb_tab16[] = {
#if defined(__BIG_ENDIAN)
0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
#elif defined(__LITTLE_ENDIAN)
0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
#else
#error FIXME: No endianness??
#endif
};
 
static u32 cfb_tab32[] = {
0x00000000, 0xffffffff
};
 
#define FB_WRITEL fb_writel
#define FB_READL fb_readl
 
#if defined (__BIG_ENDIAN)
#define LEFT_POS(bpp) (32 - bpp)
#define SHIFT_HIGH(val, bits) ((val) >> (bits))
#define SHIFT_LOW(val, bits) ((val) << (bits))
#else
#define LEFT_POS(bpp) (0)
#define SHIFT_HIGH(val, bits) ((val) << (bits))
#define SHIFT_LOW(val, bits) ((val) >> (bits))
#endif
 
static inline void color_imageblit(const struct fb_image *image,
struct fb_info *p, u8 *dst1,
u32 start_index,
u32 pitch_index)
{
/* Draw the penguin */
u32 *dst, *dst2, color = 0, val, shift;
int i, n, bpp = p->var.bits_per_pixel;
u32 null_bits = 32 - bpp;
u32 *palette = (u32 *) p->pseudo_palette;
const u8 *src = image->data;
 
dst2 = (u32 *) dst1;
for (i = image->height; i--; ) {
n = image->width;
dst = (u32 *) dst1;
shift = 0;
val = 0;
if (start_index) {
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
val = FB_READL(dst) & start_mask;
shift = start_index;
}
while (n--) {
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR )
color = palette[*src];
else
color = *src;
color <<= LEFT_POS(bpp);
val |= SHIFT_HIGH(color, shift);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 :
SHIFT_LOW(color, 32 - shift);
}
shift += bpp;
shift &= (32 - 1);
src++;
}
if (shift) {
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
 
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
dst1 += p->fix.line_length;
if (pitch_index) {
dst2 += p->fix.line_length;
dst1 = (char *) dst2;
(unsigned long) dst1 &= ~(sizeof(u32) - 1);
 
start_index += pitch_index;
start_index &= 32 - 1;
}
}
}
 
static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p,
u8 *dst1, u32 fgcolor,
u32 bgcolor,
u32 start_index,
u32 pitch_index)
{
u32 shift, color = 0, bpp = p->var.bits_per_pixel;
u32 *dst, *dst2, val, pitch = p->fix.line_length;
u32 null_bits = 32 - bpp;
u32 spitch = (image->width+7)/8;
const u8 *src = image->data, *s;
u32 i, j, l;
dst2 = (u32 *) dst1;
 
for (i = image->height; i--; ) {
shift = val = 0;
l = 8;
j = image->width;
dst = (u32 *) dst1;
s = src;
 
/* write leading bits */
if (start_index) {
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
val = FB_READL(dst) & start_mask;
shift = start_index;
}
 
while (j--) {
l--;
color = (*s & (1 << l)) ? fgcolor : bgcolor;
color <<= LEFT_POS(bpp);
val |= SHIFT_HIGH(color, shift);
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
val = (shift == null_bits) ? 0 :
SHIFT_LOW(color,32 - shift);
}
shift += bpp;
shift &= (32 - 1);
if (!l) { l = 8; s++; };
}
 
/* write trailing bits */
if (shift) {
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
 
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
dst1 += pitch;
src += spitch;
if (pitch_index) {
dst2 += pitch;
dst1 = (char *) dst2;
(unsigned long) dst1 &= ~(sizeof(u32) - 1);
 
start_index += pitch_index;
start_index &= 32 - 1;
}
}
}
 
/*
* fast_imageblit - optimized monochrome color expansion
*
* Only if: bits_per_pixel == 8, 16, or 32
* image->width is divisible by pixel/dword (ppw);
* fix->line_legth is divisible by 4;
* beginning and end of a scanline is dword aligned
*/
static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p,
u8 *dst1, u32 fgcolor,
u32 bgcolor)
{
u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
u32 bit_mask, end_mask, eorx, shift;
const char *s = image->data, *src;
u32 *dst;
u32 *tab = NULL;
int i, j, k;
switch (bpp) {
case 8:
tab = cfb_tab8;
break;
case 16:
tab = cfb_tab16;
break;
case 32:
tab = cfb_tab32;
break;
}
 
for (i = ppw-1; i--; ) {
fgx <<= bpp;
bgx <<= bpp;
fgx |= fgcolor;
bgx |= bgcolor;
}
bit_mask = (1 << ppw) - 1;
eorx = fgx ^ bgx;
k = image->width/ppw;
 
for (i = image->height; i--; ) {
dst = (u32 *) dst1, shift = 8; src = s;
for (j = k; j--; ) {
shift -= ppw;
end_mask = tab[(*src >> shift) & bit_mask];
FB_WRITEL((end_mask & eorx)^bgx, dst++);
if (!shift) { shift = 8; src++; }
}
dst1 += p->fix.line_length;
s += spitch;
}
}
void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
{
u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
u32 width = image->width, height = image->height;
u32 dx = image->dx, dy = image->dy;
int x2, y2, vxres, vyres;
u8 *dst1;
 
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly like we are
* doing here.
*/
if (image->dx > vxres || image->dy > vyres)
return;
 
x2 = image->dx + image->width;
y2 = image->dy + image->height;
dx = image->dx > 0 ? image->dx : 0;
dy = image->dy > 0 ? image->dy : 0;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
width = x2 - dx;
height = y2 - dy;
 
bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
start_index = bitstart & (32 - 1);
pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
 
bitstart /= 8;
bitstart &= ~(bpl - 1);
dst1 = p->screen_base + bitstart;
 
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
 
if (image->depth == 1) {
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
} else {
fgcolor = image->fg_color;
bgcolor = image->bg_color;
}
if (32 % bpp == 0 && !start_index && !pitch_index &&
((width & (32/bpp-1)) == 0) &&
bpp >= 8 && bpp <= 32)
fast_imageblit(image, p, dst1, fgcolor, bgcolor);
else
slow_imageblit(image, p, dst1, fgcolor, bgcolor,
start_index, pitch_index);
} else if (image->depth <= bpp)
color_imageblit(image, p, dst1, start_index, pitch_index);
}
 
EXPORT_SYMBOL(cfb_imageblit);
 
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("Generic software accelerated imaging drawing");
MODULE_LICENSE("GPL");
 
/shark/trunk/drivers/fb/makefile
10,11 → 10,12
 
OBJS_PATH = $(BASE)/drivers/fb
 
OBJS = fbmem.o vesafb.o
OBJS = fbmem.o fbcmap.o cfbfillrect.o softcursor.o cfbcopyarea.o cfbimgblt.o\
vga16fb.o vgastate.o vesafb.o
 
OTHERINCL += -I$(BASE)/drivers/linuxc26/include
 
C_OPT += -D__KERNEL__ -D__i386__
C_OPT += -D__KERNEL__ -D__i386__ -DCONFIG_FB_VGA16
 
include $(BASE)/config/lib.mk
 
/shark/trunk/drivers/fb/vga16fb.c
0,0 → 1,1415
/*
* linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
*
* Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
* Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
* Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
* 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 <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
 
#include <asm/io.h>
#include <video/vga.h>
 
#define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */
#define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */
 
#define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */
#define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */
#define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */
#define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */
#define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */
 
#define dac_reg (VGA_PEL_IW)
#define dac_val (VGA_PEL_D)
 
#define VGA_FB_PHYS 0xA0000
#define VGA_FB_PHYS_LEN 65536
 
#define MODE_SKIP4 1
#define MODE_8BPP 2
#define MODE_CFB 4
#define MODE_TEXT 8
 
/* --------------------------------------------------------------------- */
 
/*
* card parameters
*/
 
static struct fb_info vga16fb;
 
static struct vga16fb_par {
/* structure holding original VGA register settings when the
screen is blanked */
struct {
unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
unsigned char CrtMiscIO; /* Miscellaneous register */
unsigned char HorizontalTotal; /* CRT-Controller:00h */
unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
unsigned char StartHorizRetrace; /* CRT-Controller:04h */
unsigned char EndHorizRetrace; /* CRT-Controller:05h */
unsigned char Overflow; /* CRT-Controller:07h */
unsigned char StartVertRetrace; /* CRT-Controller:10h */
unsigned char EndVertRetrace; /* CRT-Controller:11h */
unsigned char ModeControl; /* CRT-Controller:17h */
unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct vgastate state;
atomic_t ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C];
} vga16_par;
 
/* --------------------------------------------------------------------- */
 
static struct fb_var_screeninfo vga16fb_defined = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.bits_per_pixel = 4,
.activate = FB_ACTIVATE_TEST,
.height = -1,
.width = -1,
.pixclock = 39721,
.left_margin = 48,
.right_margin = 16,
.upper_margin = 39,
.lower_margin = 8,
.hsync_len = 96,
.vsync_len = 2,
.vmode = FB_VMODE_NONINTERLACED,
};
 
/* name should not depend on EGA/VGA */
static struct fb_fix_screeninfo vga16fb_fix __initdata = {
.id = "VGA16 VGA",
.smem_start = VGA_FB_PHYS,
.smem_len = VGA_FB_PHYS_LEN,
.type = FB_TYPE_VGA_PLANES,
.type_aux = FB_AUX_VGA_PLANES_VGA4,
.visual = FB_VISUAL_PSEUDOCOLOR,
.xpanstep = 8,
.ypanstep = 1,
.line_length = 640/8,
.accel = FB_ACCEL_NONE
};
 
/* The VGA's weird architecture often requires that we read a byte and
write a byte to the same location. It doesn't matter *what* byte
we write, however. This is because all the action goes on behind
the scenes in the VGA's 32-bit latch register, and reading and writing
video memory just invokes latch behavior.
 
To avoid race conditions (is this necessary?), reading and writing
the memory byte should be done with a single instruction. One
suitable instruction is the x86 bitwise OR. The following
read-modify-write routine should optimize to one such bitwise
OR. */
static inline void rmw(volatile char *p)
{
readb(p);
writeb(1, p);
}
 
/* Set the Graphics Mode Register, and return its previous value.
Bits 0-1 are write mode, bit 3 is read mode. */
static inline int setmode(int mode)
{
int oldmode;
vga_io_w(GRAPHICS_ADDR_REG, GRAPHICS_MODE_INDEX);
oldmode = vga_io_r(GRAPHICS_DATA_REG);
vga_io_w(GRAPHICS_DATA_REG, mode);
return oldmode;
}
 
/* Select the Bit Mask Register and return its value. */
static inline int selectmask(void)
{
return vga_io_rgfx(BIT_MASK_INDEX);
}
 
/* Set the value of the Bit Mask Register. It must already have been
selected with selectmask(). */
static inline void setmask(int mask)
{
vga_io_w(GRAPHICS_DATA_REG, mask);
}
 
/* Set the Data Rotate Register and return its old value.
Bits 0-2 are rotate count, bits 3-4 are logical operation
(0=NOP, 1=AND, 2=OR, 3=XOR). */
static inline int setop(int op)
{
int oldop;
vga_io_w(GRAPHICS_ADDR_REG, DATA_ROTATE_INDEX);
oldop = vga_io_r(GRAPHICS_DATA_REG);
vga_io_w(GRAPHICS_DATA_REG, op);
return oldop;
}
 
/* Set the Enable Set/Reset Register and return its old value.
The code here always uses value 0xf for thsi register. */
static inline int setsr(int sr)
{
int oldsr;
 
vga_io_w(GRAPHICS_ADDR_REG, ENABLE_SET_RESET_INDEX);
oldsr = vga_io_r(GRAPHICS_DATA_REG);
vga_io_w(GRAPHICS_DATA_REG, sr);
return oldsr;
}
 
/* Set the Set/Reset Register and return its old value. */
static inline int setcolor(int color)
{
int oldcolor;
 
vga_io_w(GRAPHICS_ADDR_REG, SET_RESET_INDEX);
oldcolor = vga_io_r(GRAPHICS_DATA_REG);
vga_io_w(GRAPHICS_DATA_REG, color);
return oldcolor;
}
 
/* Return the value in the Graphics Address Register. */
static inline int getindex(void)
{
return vga_io_r(GRAPHICS_ADDR_REG);
}
 
/* Set the value in the Graphics Address Register. */
static inline void setindex(int index)
{
vga_io_w(GRAPHICS_ADDR_REG, index);
}
 
static void vga16fb_pan_var(struct fb_info *info,
struct fb_var_screeninfo *var)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
u32 xoffset, pos;
 
xoffset = var->xoffset;
if (info->var.bits_per_pixel == 8) {
pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
} else if (par->mode & MODE_TEXT) {
int fh = 16; // FIXME !!! font height. Fugde for now.
pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
} else {
if (info->var.nonstd)
xoffset--;
pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
}
vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
/* if we support CFB4, then we must! support xoffset with pixel
* granularity if someone supports xoffset in bit resolution */
vga_io_r(VGA_IS1_RC); /* reset flip-flop */
vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
if (var->bits_per_pixel == 8)
vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
else
vga_io_w(VGA_ATT_IW, xoffset & 7);
vga_io_r(VGA_IS1_RC);
vga_io_w(VGA_ATT_IW, 0x20);
}
 
static void vga16fb_update_fix(struct fb_info *info)
{
if (info->var.bits_per_pixel == 4) {
if (info->var.nonstd) {
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.line_length = info->var.xres_virtual / 2;
} else {
info->fix.type = FB_TYPE_VGA_PLANES;
info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
info->fix.line_length = info->var.xres_virtual / 8;
}
} else if (info->var.bits_per_pixel == 0) {
info->fix.type = FB_TYPE_TEXT;
info->fix.type_aux = FB_AUX_TEXT_CGA;
info->fix.line_length = info->var.xres_virtual / 4;
} else { /* 8bpp */
if (info->var.nonstd) {
info->fix.type = FB_TYPE_VGA_PLANES;
info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
info->fix.line_length = info->var.xres_virtual / 4;
} else {
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.line_length = info->var.xres_virtual;
}
}
}
 
static void vga16fb_clock_chip(struct vga16fb_par *par,
unsigned int pixclock,
const struct fb_info *info,
int mul, int div)
{
static struct {
u32 pixclock;
u8 misc;
u8 seq_clock_mode;
} *ptr, *best, vgaclocks[] = {
{ 79442 /* 12.587 */, 0x00, 0x08},
{ 70616 /* 14.161 */, 0x04, 0x08},
{ 39721 /* 25.175 */, 0x00, 0x00},
{ 35308 /* 28.322 */, 0x04, 0x00},
{ 0 /* bad */, 0x00, 0x00}};
int err;
 
pixclock = (pixclock * mul) / div;
best = vgaclocks;
err = pixclock - best->pixclock;
if (err < 0) err = -err;
for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
int tmp;
 
tmp = pixclock - ptr->pixclock;
if (tmp < 0) tmp = -tmp;
if (tmp < err) {
err = tmp;
best = ptr;
}
}
par->misc |= best->misc;
par->clkdiv = best->seq_clock_mode;
pixclock = (best->pixclock * div) / mul;
}
#define FAIL(X) return -EINVAL
 
static int vga16fb_open(struct fb_info *info, int user)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
int cnt = atomic_read(&par->ref_count);
 
if (!cnt) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
VGA_SAVE_CMAP;
save_vga(&par->state);
}
atomic_inc(&par->ref_count);
return 0;
}
 
static int vga16fb_release(struct fb_info *info, int user)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
int cnt = atomic_read(&par->ref_count);
 
if (!cnt)
return -EINVAL;
if (cnt == 1)
restore_vga(&par->state);
atomic_dec(&par->ref_count);
 
return 0;
}
 
static int vga16fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
u32 xres, right, hslen, left, xtotal;
u32 yres, lower, vslen, upper, ytotal;
u32 vxres, xoffset, vyres, yoffset;
u32 pos;
u8 r7, rMode;
int shift;
int mode;
u32 maxmem;
 
par->pel_msk = 0xFF;
 
if (var->bits_per_pixel == 4) {
if (var->nonstd) {
if (!par->isVGA)
return -EINVAL;
shift = 3;
mode = MODE_SKIP4 | MODE_CFB;
maxmem = 16384;
par->pel_msk = 0x0F;
} else {
shift = 3;
mode = 0;
maxmem = 65536;
}
} else if (var->bits_per_pixel == 8) {
if (!par->isVGA)
return -EINVAL; /* no support on EGA */
shift = 2;
if (var->nonstd) {
mode = MODE_8BPP | MODE_CFB;
maxmem = 65536;
} else {
mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
maxmem = 16384;
}
} else
return -EINVAL;
 
xres = (var->xres + 7) & ~7;
vxres = (var->xres_virtual + 0xF) & ~0xF;
xoffset = (var->xoffset + 7) & ~7;
left = (var->left_margin + 7) & ~7;
right = (var->right_margin + 7) & ~7;
hslen = (var->hsync_len + 7) & ~7;
 
if (vxres < xres)
vxres = xres;
if (xres + xoffset > vxres)
xoffset = vxres - xres;
 
var->xres = xres;
var->right_margin = right;
var->hsync_len = hslen;
var->left_margin = left;
var->xres_virtual = vxres;
var->xoffset = xoffset;
 
xres >>= shift;
right >>= shift;
hslen >>= shift;
left >>= shift;
vxres >>= shift;
xtotal = xres + right + hslen + left;
if (xtotal >= 256)
FAIL("xtotal too big");
if (hslen > 32)
FAIL("hslen too big");
if (right + hslen + left > 64)
FAIL("hblank too big");
par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
par->crtc[VGA_CRTC_H_DISP] = xres - 1;
pos = xres + right;
par->crtc[VGA_CRTC_H_SYNC_START] = pos;
pos += hslen;
par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
pos += left - 2; /* blank_end + 2 <= total + 5 */
par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
if (pos & 0x20)
par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
 
yres = var->yres;
lower = var->lower_margin;
vslen = var->vsync_len;
upper = var->upper_margin;
vyres = var->yres_virtual;
yoffset = var->yoffset;
 
if (yres > vyres)
vyres = yres;
if (vxres * vyres > maxmem) {
vyres = maxmem / vxres;
if (vyres < yres)
return -ENOMEM;
}
if (yoffset + yres > vyres)
yoffset = vyres - yres;
var->yres = yres;
var->lower_margin = lower;
var->vsync_len = vslen;
var->upper_margin = upper;
var->yres_virtual = vyres;
var->yoffset = yoffset;
 
if (var->vmode & FB_VMODE_DOUBLE) {
yres <<= 1;
lower <<= 1;
vslen <<= 1;
upper <<= 1;
}
ytotal = yres + lower + vslen + upper;
if (ytotal > 1024) {
ytotal >>= 1;
yres >>= 1;
lower >>= 1;
vslen >>= 1;
upper >>= 1;
rMode = 0x04;
} else
rMode = 0x00;
if (ytotal > 1024)
FAIL("ytotal too big");
if (vslen > 16)
FAIL("vslen too big");
par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
r7 = 0x10; /* disable linecompare */
if (ytotal & 0x100) r7 |= 0x01;
if (ytotal & 0x200) r7 |= 0x20;
par->crtc[VGA_CRTC_PRESET_ROW] = 0;
par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
if (var->vmode & FB_VMODE_DOUBLE)
par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
xoffset--;
pos = yoffset * vxres + (xoffset >> shift);
par->crtc[VGA_CRTC_START_HI] = pos >> 8;
par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
pos = yres - 1;
par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
if (pos & 0x100)
r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
if (pos & 0x200) {
r7 |= 0x40; /* 0x40 -> DISP_END */
par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
}
pos += lower;
par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
if (pos & 0x100)
r7 |= 0x04;
if (pos & 0x200)
r7 |= 0x80;
pos += vslen;
par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
but some SVGA chips requires all 8 bits to set */
if (vxres >= 512)
FAIL("vxres too long");
par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
if (mode & MODE_SKIP4)
par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */
else
par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */
par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
par->crtc[VGA_CRTC_OVERFLOW] = r7;
 
par->vss = 0x00; /* 3DA */
 
par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
if (var->sync & FB_SYNC_HOR_HIGH_ACT)
par->misc &= ~0x40;
if (var->sync & FB_SYNC_VERT_HIGH_ACT)
par->misc &= ~0x80;
par->mode = mode;
 
if (mode & MODE_8BPP)
/* pixel clock == vga clock / 2 */
vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
else
/* pixel clock == vga clock */
vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
var->red.offset = var->green.offset = var->blue.offset =
var->transp.offset = 0;
var->red.length = var->green.length = var->blue.length =
(par->isVGA) ? 6 : 2;
var->transp.length = 0;
var->activate = FB_ACTIVATE_NOW;
var->height = -1;
var->width = -1;
var->accel_flags = 0;
return 0;
}
#undef FAIL
 
static int vga16fb_set_par(struct fb_info *info)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
u8 gdc[VGA_GFX_C];
u8 seq[VGA_SEQ_C];
u8 atc[VGA_ATT_C];
int fh, i;
 
seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
if (par->mode & MODE_TEXT)
seq[VGA_SEQ_PLANE_WRITE] = 0x03;
else
seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
if (par->mode & MODE_TEXT)
seq[VGA_SEQ_MEMORY_MODE] = 0x03;
else if (par->mode & MODE_SKIP4)
seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
else
seq[VGA_SEQ_MEMORY_MODE] = 0x06;
 
gdc[VGA_GFX_SR_VALUE] = 0x00;
gdc[VGA_GFX_SR_ENABLE] = 0x00;
gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
gdc[VGA_GFX_DATA_ROTATE] = 0x00;
gdc[VGA_GFX_PLANE_READ] = 0;
if (par->mode & MODE_TEXT) {
gdc[VGA_GFX_MODE] = 0x10;
gdc[VGA_GFX_MISC] = 0x06;
} else {
if (par->mode & MODE_CFB)
gdc[VGA_GFX_MODE] = 0x40;
else
gdc[VGA_GFX_MODE] = 0x00;
gdc[VGA_GFX_MISC] = 0x05;
}
gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
gdc[VGA_GFX_BIT_MASK] = 0xFF;
 
for (i = 0x00; i < 0x10; i++)
atc[i] = i;
if (par->mode & MODE_TEXT)
atc[VGA_ATC_MODE] = 0x04;
else if (par->mode & MODE_8BPP)
atc[VGA_ATC_MODE] = 0x41;
else
atc[VGA_ATC_MODE] = 0x81;
atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
if (par->mode & MODE_8BPP)
atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
else
atc[VGA_ATC_PEL] = info->var.xoffset & 7;
atc[VGA_ATC_COLOR_PAGE] = 0x00;
if (par->mode & MODE_TEXT) {
fh = 16; // FIXME !!! Fudge font height.
par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
& ~0x1F) | (fh - 1);
}
 
vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
 
/* Enable graphics register modification */
if (!par->isVGA) {
vga_io_w(EGA_GFX_E0, 0x00);
vga_io_w(EGA_GFX_E1, 0x01);
}
/* update misc output register */
vga_io_w(VGA_MIS_W, par->misc);
/* synchronous reset on */
vga_io_wseq(0x00, 0x01);
 
if (par->isVGA)
vga_io_w(VGA_PEL_MSK, par->pel_msk);
 
/* write sequencer registers */
vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
for (i = 2; i < VGA_SEQ_C; i++) {
vga_io_wseq(i, seq[i]);
}
/* synchronous reset off */
vga_io_wseq(0x00, 0x03);
 
/* deprotect CRT registers 0-7 */
vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
 
/* write CRT registers */
for (i = 0; i < VGA_CRTC_REGS; i++) {
vga_io_wcrt(i, par->crtc[i]);
}
/* write graphics controller registers */
for (i = 0; i < VGA_GFX_C; i++) {
vga_io_wgfx(i, gdc[i]);
}
/* write attribute controller registers */
for (i = 0; i < VGA_ATT_C; i++) {
vga_io_r(VGA_IS1_RC); /* reset flip-flop */
vga_io_wattr(i, atc[i]);
}
 
/* Wait for screen to stabilize. */
mdelay(50);
 
vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
 
vga_io_r(VGA_IS1_RC);
vga_io_w(VGA_ATT_IW, 0x20);
 
vga16fb_update_fix(info);
return 0;
}
 
static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
{
static unsigned char map[] = { 000, 001, 010, 011 };
int val;
if (regno >= 16)
return;
val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
vga_io_r(VGA_IS1_RC); /* ! 0x3BA */
vga_io_wattr(regno, val);
vga_io_r(VGA_IS1_RC); /* some clones need it */
vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
}
 
static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
{
outb(regno, dac_reg);
outb(red >> 10, dac_val);
outb(green >> 10, dac_val);
outb(blue >> 10, dac_val);
}
 
static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
int gray;
 
/*
* Set a single color register. The values supplied are
* already rounded down to the hardware's capabilities
* (according to the entries in the `var' structure). Return
* != 0 for invalid regno.
*/
if (regno >= 256)
return 1;
 
gray = info->var.grayscale;
if (gray) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
if (par->isVGA)
vga16_setpalette(regno,red,green,blue);
else
ega16_setpalette(regno,red,green,blue);
return 0;
}
 
static int vga16fb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
if (var->xoffset + info->var.xres > info->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
 
vga16fb_pan_var(info, var);
 
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
info->var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
 
/* The following VESA blanking code is taken from vgacon.c. The VGA
blanking code was originally by Huang shi chao, and modified by
Christoph Rimek (chrimek@toppoint.de) and todd j. derr
(tjd@barefoot.org) for Linux. */
#define attrib_port VGA_ATC_IW
#define seq_port_reg VGA_SEQ_I
#define seq_port_val VGA_SEQ_D
#define gr_port_reg VGA_GFX_I
#define gr_port_val VGA_GFX_D
#define video_misc_rd VGA_MIS_R
#define video_misc_wr VGA_MIS_W
#define vga_video_port_reg VGA_CRT_IC
#define vga_video_port_val VGA_CRT_DC
 
static void vga_vesa_blank(struct vga16fb_par *par, int mode)
{
unsigned char SeqCtrlIndex;
unsigned char CrtCtrlIndex;
//cli();
SeqCtrlIndex = vga_io_r(seq_port_reg);
CrtCtrlIndex = vga_io_r(vga_video_port_reg);
 
/* save original values of VGA controller registers */
if(!par->vesa_blanked) {
par->vga_state.CrtMiscIO = vga_io_r(video_misc_rd);
//sti();
 
par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */
par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */
par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */
par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */
par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */
}
 
/* assure that video is enabled */
/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
//cli();
vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
 
/* test for vertical retrace in process.... */
if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO & 0xef);
 
/*
* Set <End of vertical retrace> to minimum (0) and
* <Start of vertical Retrace> to maximum (incl. overflow)
* Result: turn off vertical sync (VSync) pulse.
*/
if (mode & VESA_VSYNC_SUSPEND) {
outb_p(0x10,vga_video_port_reg); /* StartVertRetrace */
outb_p(0xff,vga_video_port_val); /* maximum value */
outb_p(0x11,vga_video_port_reg); /* EndVertRetrace */
outb_p(0x40,vga_video_port_val); /* minimum (bits 0..3) */
outb_p(0x07,vga_video_port_reg); /* Overflow */
outb_p(par->vga_state.Overflow | 0x84,vga_video_port_val); /* bits 9,10 of vert. retrace */
}
 
if (mode & VESA_HSYNC_SUSPEND) {
/*
* Set <End of horizontal retrace> to minimum (0) and
* <Start of horizontal Retrace> to maximum
* Result: turn off horizontal sync (HSync) pulse.
*/
outb_p(0x04,vga_video_port_reg); /* StartHorizRetrace */
outb_p(0xff,vga_video_port_val); /* maximum */
outb_p(0x05,vga_video_port_reg); /* EndHorizRetrace */
outb_p(0x00,vga_video_port_val); /* minimum (0) */
}
 
/* restore both index registers */
outb_p(SeqCtrlIndex,seq_port_reg);
outb_p(CrtCtrlIndex,vga_video_port_reg);
//sti();
}
 
static void vga_vesa_unblank(struct vga16fb_par *par)
{
unsigned char SeqCtrlIndex;
unsigned char CrtCtrlIndex;
//cli();
SeqCtrlIndex = vga_io_r(seq_port_reg);
CrtCtrlIndex = vga_io_r(vga_video_port_reg);
 
/* restore original values of VGA controller registers */
vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO);
 
/* HorizontalTotal */
vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
/* HorizDisplayEnd */
vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
/* StartHorizRetrace */
vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
/* EndHorizRetrace */
vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
/* Overflow */
vga_io_wcrt(0x07, par->vga_state.Overflow);
/* StartVertRetrace */
vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
/* EndVertRetrace */
vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
/* ModeControl */
vga_io_wcrt(0x17, par->vga_state.ModeControl);
/* ClockingMode */
vga_io_wseq(0x01, par->vga_state.ClockingMode);
 
/* restore index/control registers */
vga_io_w(seq_port_reg, SeqCtrlIndex);
vga_io_w(vga_video_port_reg, CrtCtrlIndex);
//sti();
}
 
static void vga_pal_blank(void)
{
int i;
 
for (i=0; i<16; i++) {
outb_p (i, dac_reg) ;
outb_p (0, dac_val) ;
outb_p (0, dac_val) ;
outb_p (0, dac_val) ;
}
}
 
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
static int vga16fb_blank(int blank, struct fb_info *info)
{
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
 
switch (blank) {
case 0: /* Unblank */
if (par->vesa_blanked) {
vga_vesa_unblank(par);
par->vesa_blanked = 0;
}
if (par->palette_blanked) {
//do_install_cmap(info->currcon, info);
par->palette_blanked = 0;
}
break;
case 1: /* blank */
vga_pal_blank();
par->palette_blanked = 1;
break;
default: /* VESA blanking */
vga_vesa_blank(par, blank-1);
par->vesa_blanked = 1;
break;
}
return 0;
}
 
void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
u32 dx = rect->dx, width = rect->width;
char oldindex = getindex();
char oldmode = setmode(0x40);
char oldmask = selectmask();
int line_ofs, height;
char oldop, oldsr;
char *where;
 
dx /= 4;
where = info->screen_base + dx + rect->dy * info->fix.line_length;
 
if (rect->rop == ROP_COPY) {
oldop = setop(0);
oldsr = setsr(0);
 
width /= 4;
line_ofs = info->fix.line_length - width;
setmask(0xff);
 
height = rect->height;
 
while (height--) {
int x;
 
/* we can do memset... */
for (x = width; x > 0; --x) {
writeb(rect->color, where);
where++;
}
where += line_ofs;
}
} else {
char oldcolor = setcolor(0xf);
int y;
 
oldop = setop(0x18);
oldsr = setsr(0xf);
setmask(0x0F);
for (y = 0; y < rect->height; y++) {
rmw(where);
rmw(where+1);
where += info->fix.line_length;
}
setcolor(oldcolor);
}
setmask(oldmask);
setsr(oldsr);
setop(oldop);
setmode(oldmode);
setindex(oldindex);
}
 
void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
int x, x2, y2, vxres, vyres, width, height, line_ofs;
char *dst;
 
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
 
if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
return;
 
/* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly. */
 
x2 = rect->dx + rect->width;
y2 = rect->dy + rect->height;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
width = x2 - rect->dx;
 
switch (info->fix.type) {
case FB_TYPE_VGA_PLANES:
if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
 
height = y2 - rect->dy;
width = rect->width/8;
 
line_ofs = info->fix.line_length - width;
dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
 
switch (rect->rop) {
case ROP_COPY:
setmode(0);
setop(0);
setsr(0xf);
setcolor(rect->color);
selectmask();
 
setmask(0xff);
 
while (height--) {
for (x = 0; x < width; x++) {
writeb(0, dst);
dst++;
}
dst += line_ofs;
}
break;
case ROP_XOR:
setmode(0);
setop(0x18);
setsr(0xf);
setcolor(0xf);
selectmask();
 
setmask(0xff);
while (height--) {
for (x = 0; x < width; x++) {
rmw(dst);
dst++;
}
dst += line_ofs;
}
break;
}
} else
vga_8planes_fillrect(info, rect);
break;
case FB_TYPE_PACKED_PIXELS:
default:
cfb_fillrect(info, rect);
break;
}
}
 
void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
char oldindex = getindex();
char oldmode = setmode(0x41);
char oldop = setop(0);
char oldsr = setsr(0xf);
int height, line_ofs, x;
u32 sx, dx, width;
char *dest, *src;
 
height = area->height;
 
sx = area->sx / 4;
dx = area->dx / 4;
width = area->width / 4;
 
if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
line_ofs = info->fix.line_length - width;
dest = info->screen_base + dx + area->dy * info->fix.line_length;
src = info->screen_base + sx + area->sy * info->fix.line_length;
while (height--) {
for (x = 0; x < width; x++) {
readb(src);
writeb(0, dest);
src++;
dest++;
}
src += line_ofs;
dest += line_ofs;
}
} else {
line_ofs = info->fix.line_length - width;
dest = info->screen_base + dx + width +
(area->dy + height - 1) * info->fix.line_length;
src = info->screen_base + sx + width +
(area->sy + height - 1) * info->fix.line_length;
while (height--) {
for (x = 0; x < width; x++) {
--src;
--dest;
readb(src);
writeb(0, dest);
}
src -= line_ofs;
dest -= line_ofs;
}
}
 
setsr(oldsr);
setop(oldop);
setmode(oldmode);
setindex(oldindex);
}
 
void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
int x, x2, y2, old_dx, old_dy, vxres, vyres;
int height, width, line_ofs;
char *dst = NULL, *src = NULL;
 
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
 
if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
area->sy > vyres)
return;
 
/* clip the destination */
old_dx = area->dx;
old_dy = area->dy;
 
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly.
*/
x2 = area->dx + area->width;
y2 = area->dy + area->height;
dx = area->dx > 0 ? area->dx : 0;
dy = area->dy > 0 ? area->dy : 0;
x2 = x2 < vxres ? x2 : vxres;
y2 = y2 < vyres ? y2 : vyres;
width = x2 - dx;
height = y2 - dy;
 
/* update sx1,sy1 */
sx += (dx - old_dx);
sy += (dy - old_dy);
 
/* the source must be completely inside the virtual screen */
if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
return;
 
switch (info->fix.type) {
case FB_TYPE_VGA_PLANES:
if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
width = width/8;
height = height;
line_ofs = info->fix.line_length - width;
 
setmode(1);
setop(0);
setsr(0xf);
 
if (dy < sy || (dy == sy && dx < sx)) {
dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
src = info->screen_base + (sx/8) + sy * info->fix.line_length;
while (height--) {
for (x = 0; x < width; x++) {
readb(src);
writeb(0, dst);
dst++;
src++;
}
src += line_ofs;
dst += line_ofs;
}
} else {
dst = info->screen_base + (dx/8) + width +
(dy + height - 1) * info->fix.line_length;
src = info->screen_base + (sx/8) + width +
(sy + height - 1) * info->fix.line_length;
while (height--) {
for (x = 0; x < width; x++) {
dst--;
src--;
readb(src);
writeb(0, dst);
}
src -= line_ofs;
dst -= line_ofs;
}
}
} else
vga_8planes_copyarea(info, area);
break;
case FB_TYPE_PACKED_PIXELS:
default:
cfb_copyarea(info, area);
break;
}
}
 
#ifdef __LITTLE_ENDIAN
static unsigned int transl_l[] =
{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
static unsigned int transl_h[] =
{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
#else
#ifdef __BIG_ENDIAN
static unsigned int transl_h[] =
{0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
static unsigned int transl_l[] =
{0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
#else
#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
#endif
#endif
 
void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
{
char oldindex = getindex();
char oldmode = setmode(0x40);
char oldop = setop(0);
char oldsr = setsr(0);
char oldmask = selectmask();
const char *cdat = image->data;
u32 dx = image->dx;
char *where;
int y;
 
dx /= 4;
where = info->screen_base + dx + image->dy * info->fix.line_length;
 
setmask(0xff);
writeb(image->bg_color, where);
readb(where);
selectmask();
setmask(image->fg_color ^ image->bg_color);
setmode(0x42);
setop(0x18);
for (y = 0; y < image->height; y++, where += info->fix.line_length)
writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
setmask(oldmask);
setsr(oldsr);
setop(oldop);
setmode(oldmode);
setindex(oldindex);
}
 
void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
{
char *where = info->screen_base + (image->dx/8) +
image->dy * info->fix.line_length;
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
char *cdat = (char *) image->data, *dst;
int x, y;
 
switch (info->fix.type) {
case FB_TYPE_VGA_PLANES:
if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
if (par->isVGA) {
setmode(2);
setop(0);
setsr(0xf);
setcolor(image->fg_color);
selectmask();
setmask(0xff);
writeb(image->bg_color, where);
rmb();
readb(where); /* fill latches */
setmode(3);
wmb();
for (y = 0; y < image->height; y++) {
dst = where;
for (x = image->width/8; x--;)
writeb(*cdat++, dst++);
where += info->fix.line_length;
}
wmb();
} else {
setmode(0);
setop(0);
setsr(0xf);
setcolor(image->bg_color);
selectmask();
setmask(0xff);
for (y = 0; y < image->height; y++) {
dst = where;
for (x=image->width/8; x--;){
rmw(dst);
setcolor(image->fg_color);
selectmask();
if (*cdat) {
setmask(*cdat++);
rmw(dst++);
}
}
where += info->fix.line_length;
}
}
} else
vga_8planes_imageblit(info, image);
break;
case FB_TYPE_PACKED_PIXELS:
default:
cfb_imageblit(info, image);
break;
}
}
 
void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
{
/*
* Draw logo
*/
struct vga16fb_par *par = (struct vga16fb_par *) info->par;
char *where = info->screen_base + image->dy * info->fix.line_length +
image->dx/8;
const char *cdat = image->data, *dst;
int x, y;
 
switch (info->fix.type) {
case FB_TYPE_VGA_PLANES:
if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
par->isVGA) {
setsr(0xf);
setop(0);
setmode(0);
for (y = 0; y < image->height; y++) {
for (x = 0; x < image->width; x++) {
dst = where + x/8;
 
setcolor(*cdat);
selectmask();
setmask(1 << (7 - (x % 8)));
fb_readb(dst);
fb_writeb(0, dst);
 
cdat++;
}
where += info->fix.line_length;
}
}
break;
case FB_TYPE_PACKED_PIXELS:
cfb_imageblit(info, image);
break;
default:
break;
}
}
void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
{
if (image->depth == 1)
vga_imageblit_expand(info, image);
else if (image->depth <= info->var.bits_per_pixel)
vga_imageblit_color(info, image);
}
 
static struct fb_ops vga16fb_ops = {
.owner = THIS_MODULE,
.fb_open = vga16fb_open,
.fb_release = vga16fb_release,
.fb_check_var = vga16fb_check_var,
.fb_set_par = vga16fb_set_par,
.fb_setcolreg = vga16fb_setcolreg,
.fb_pan_display = vga16fb_pan_display,
.fb_blank = vga16fb_blank,
.fb_fillrect = vga16fb_fillrect,
.fb_copyarea = vga16fb_copyarea,
.fb_imageblit = vga16fb_imageblit,
.fb_cursor = soft_cursor,
};
 
int vga16fb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
}
return 0;
}
 
int __init vga16fb_init(void)
{
int i;
 
printk(KERN_DEBUG "vga16fb: initializing\n");
 
/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
 
vga16fb.screen_base = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
if (!vga16fb.screen_base) {
printk(KERN_ERR "vga16fb: unable to map device\n");
return -ENOMEM;
}
printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
 
vga16_par.isVGA = ORIG_VIDEO_ISVGA;
vga16_par.palette_blanked = 0;
vga16_par.vesa_blanked = 0;
 
i = vga16_par.isVGA? 6 : 2;
vga16fb_defined.red.length = i;
vga16fb_defined.green.length = i;
vga16fb_defined.blue.length = i;
 
/* name should not depend on EGA/VGA */
vga16fb.fbops = &vga16fb_ops;
vga16fb.var = vga16fb_defined;
vga16fb.fix = vga16fb_fix;
vga16fb.par = &vga16_par;
vga16fb.flags = FBINFO_FLAG_DEFAULT;
 
i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
fb_alloc_cmap(&vga16fb.cmap, i, 0);
 
if (vga16fb_check_var(&vga16fb.var, &vga16fb))
return -EINVAL;
 
vga16fb_update_fix(&vga16fb);
 
if (register_framebuffer(&vga16fb) < 0) {
iounmap(vga16fb.screen_base);
return -EINVAL;
}
 
printk(KERN_INFO "fb%d: %s frame buffer device\n",
vga16fb.node, vga16fb.fix.id);
 
return 0;
}
 
static void __exit vga16fb_exit(void)
{
unregister_framebuffer(&vga16fb);
iounmap(vga16fb.screen_base);
/* XXX unshare VGA regions */
}
 
#ifdef MODULE
MODULE_LICENSE("GPL");
module_init(vga16fb_init);
#endif
module_exit(vga16fb_exit);
 
 
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/