Commit 4ff60c0f authored by James Simmons's avatar James Simmons

Supprt for switching hardware from/to vga text mode.

parent 23dda298
......@@ -6,7 +6,7 @@
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := fbmem.o fbcmap.o fbmon.o modedb.o softcursor.o cfbfillrect.o \
cfbcopyarea.o cfbimgblt.o cyber2000fb.o
cfbcopyarea.o cfbimgblt.o cyber2000fb.o vgastate.o
# Each configuration option enables a list of files.
......@@ -50,7 +50,8 @@ obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_FM2) += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......@@ -69,7 +70,8 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbi
obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MATROX) += matrox/
obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o
......
......@@ -1770,9 +1770,12 @@ static char * __init aty128find_ROM(void)
char *rom_base;
char *rom;
int stage;
int i;
int i, j;
char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */
char R128_sig[] = "R128"; /* Rage128 ROM identifier */
char *R128_sig[] = {
"R128", /* Rage128 ROM identifier */
"128b"
};
for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
stage = 1;
......@@ -1803,10 +1806,14 @@ static char * __init aty128find_ROM(void)
/* ATI signature found. Let's see if it's a Rage128 */
for (i = 0; (i < 512) && (stage != 4); i++) {
if (R128_sig[0] == *rom)
if (strncmp(R128_sig, rom,
strlen(R128_sig)) == 0)
stage = 4;
for (j = 0; j < sizeof(R128_sig)/sizeof(char *);j++) {
if (R128_sig[j][0] == *rom)
if (strncmp(R128_sig[j], rom,
strlen(R128_sig[j])) == 0) {
stage = 4;
break;
}
}
rom++;
}
if (stage != 4) {
......
......@@ -123,11 +123,11 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
shift = start_index;
}
while (n--) {
if (p->fix.visual == FB_VISUAL_PSEUDOCOLOR)
color = *src & bitmask;
if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR )
color = palette[*src] & bitmask;
else
color = *src & bitmask;
val |= SHIFT_HIGH(color, shift);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
......
......@@ -317,18 +317,16 @@ void set_con2fb_map(int unit, int newidx)
if (newidx != con2fb_map[unit]) {
oldfb = registered_fb[oldidx];
newfb = registered_fb[newidx];
if (newfb->fbops->owner)
__MOD_INC_USE_COUNT(newfb->fbops->owner);
if (!try_module_get(newfb->fbops->owner))
return;
if (newfb->fbops->fb_open
&& newfb->fbops->fb_open(newfb, 0)) {
if (newfb->fbops->owner)
__MOD_DEC_USE_COUNT(newfb->fbops->owner);
module_put(newfb->fbops->owner);
return;
}
if (oldfb->fbops->fb_release)
oldfb->fbops->fb_release(oldfb, 0);
if (oldfb->fbops->owner)
__MOD_DEC_USE_COUNT(oldfb->fbops->owner);
module_put(oldfb->fbops->owner);
vc = fb_display[unit].conp;
fontdata = fb_display[unit].fontdata;
userfont = fb_display[unit].userfont;
......@@ -596,10 +594,10 @@ static const char *fbcon_startup(void)
info->currcon = -1;
owner = info->fbops->owner;
if (owner)
__MOD_INC_USE_COUNT(owner);
if (info->fbops->fb_open && info->fbops->fb_open(info, 0) && owner)
__MOD_DEC_USE_COUNT(owner);
if (!try_module_get(owner))
return NULL;
if (info->fbops->fb_open && info->fbops->fb_open(info, 0))
module_put(owner);
if (info->fix.type != FB_TYPE_TEXT) {
if (fbcon_softback_size) {
......@@ -2549,111 +2547,226 @@ static inline unsigned safe_shift(unsigned d, int n)
return n < 0 ? d >> -n : d << n;
}
static int __init fbcon_show_logo(void)
static void __init fbcon_set_logocmap(struct fb_info *info)
{
struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
int i, j, n;
for (i = 0; i < LINUX_LOGO_COLORS; i += n) {
n = LINUX_LOGO_COLORS - i;
if (n > 16)
/* palette_cmap provides space for only 16 colors at once */
n = 16;
palette_cmap.start = 32 + i;
palette_cmap.len = n;
for (j = 0; j < n; ++j) {
palette_cmap.red[j] =
(linux_logo_red[i + j] << 8) |
linux_logo_red[i + j];
palette_cmap.green[j] =
(linux_logo_green[i + j] << 8) |
linux_logo_green[i + j];
palette_cmap.blue[j] =
(linux_logo_blue[i + j] << 8) |
linux_logo_blue[i + j];
}
fb_set_cmap(&palette_cmap, 1, info);
}
}
static void __init fbcon_set_logo_truepalette(struct fb_info *info, u32 *palette)
{
unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
unsigned char redmask, greenmask, bluemask;
int redshift, greenshift, blueshift;
int i;
/*
* We have to create a temporary palette since console palette is only
* 16 colors long.
*/
/* Bug: Doesn't obey msb_right ... (who needs that?) */
redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8];
greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8];
redshift = info->var.red.offset - (8 - info->var.red.length);
greenshift = info->var.green.offset - (8 - info->var.green.length);
blueshift = info->var.blue.offset - (8 - info->var.blue.length);
for ( i = 0; i < LINUX_LOGO_COLORS; i++) {
palette[i+32] = (safe_shift((linux_logo_red[i] & redmask), redshift) |
safe_shift((linux_logo_green[i] & greenmask), greenshift) |
safe_shift((linux_logo_blue[i] & bluemask), blueshift));
}
}
static void __init fbcon_set_logo_directpalette(struct fb_info *info, u32 *palette)
{
int redshift, greenshift, blueshift;
int i;
redshift = info->var.red.offset;
greenshift = info->var.green.offset;
blueshift = info->var.blue.offset;
for (i = 32; i < LINUX_LOGO_COLORS; i++)
palette[i] = i << redshift | i << greenshift | i << blueshift;
}
static void __init fbcon_set_logo(struct fb_info *info, u8 *logo, int needs_logo)
{
int i, j;
switch (needs_logo) {
case 4:
for (i = 0; i < (LOGO_W * LOGO_H)/2; i++) {
logo[i*2] = linux_logo16[i] >> 4;
logo[(i*2)+1] = linux_logo16[i] & 0xf;
}
break;
case 1:
case ~1:
default:
for (i = 0; i < (LOGO_W * LOGO_H)/8; i++)
for (j = 0; j < 8; j++)
logo[i*2] = (linux_logo_bw[i] & (7 - j)) ?
((needs_logo == 1) ? 1 : 0) :
((needs_logo == 1) ? 0 : 1);
break;
}
}
/*
* Three (3) kinds of logo maps exist. linux_logo (>16 colors), linux_logo_16
* (16 colors) and linux_logo_bw (2 colors). Depending on the visual format and
* color depth of the framebuffer, the DAC, the pseudo_palette, and the logo data
* will be adjusted accordingly.
*
* Case 1 - linux_logo:
* Color exceeds the number of console colors (16), thus we set the hardware DAC
* using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set.
*
* For visuals that require color info from the pseudo_palette, we also construct
* one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
* will be set.
*
* Case 2 - linux_logo_16:
* The number of colors just matches the console colors, thus there is no need
* to set the DAC or the pseudo_palette. However, the bitmap is packed, ie,
* each byte contains color information for two pixels (upper and lower nibble).
* To be consistent with fb_imageblit() usage, we therefore separate the two
* nibbles into separate bytes. The "needs_logo" flag will be set to 4.
*
* Case 3 - linux_logo_bw:
* This is similar with Case 2. Each byte contains information for 8 pixels.
* We isolate each bit and expand each into a byte. The "needs_logo" flag will
* be set to 1.
*/
static int __init fbcon_show_logo(void)
{
struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */
struct fb_info *info = p->fb_info;
struct vc_data *vc = info->display_fg;
struct fb_image image;
u32 *palette = NULL, *saved_palette = NULL;
int depth = info->var.bits_per_pixel;
unsigned char *fb = info->screen_base;
unsigned char *logo;
int i, j, n, x;
int logo_depth, done = 0;
unsigned char *fb = info->screen_base, *logo_new = NULL;
int done = 0, x;
int needs_cmapreset = 0;
int needs_truepalette = 0;
int needs_directpalette = 0;
int needs_logo = 0;
/* Return if the frame buffer is not mapped */
if (!fb)
if (!fb || !info->fbops->fb_imageblit)
return 0;
/*
* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
* DIRECTCOLOR
* We don't have to set the colors for the 16-color logo, since that logo
* uses the standard VGA text console palette
*/
if ((info->fix.visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) ||
(info->fix.visual == FB_VISUAL_DIRECTCOLOR && depth >= 24))
for (i = 0; i < LINUX_LOGO_COLORS; i += n) {
n = LINUX_LOGO_COLORS - i;
if (n > 16)
/* palette_cmap provides space for only 16 colors at once */
n = 16;
palette_cmap.start = 32 + i;
palette_cmap.len = n;
for (j = 0; j < n; ++j) {
palette_cmap.red[j] =
(linux_logo_red[i + j] << 8) |
linux_logo_red[i + j];
palette_cmap.green[j] =
(linux_logo_green[i + j] << 8) |
linux_logo_green[i + j];
palette_cmap.blue[j] =
(linux_logo_blue[i + j] << 8) |
linux_logo_blue[i + j];
}
fb_set_cmap(&palette_cmap, 1, info);
image.depth = info->var.bits_per_pixel;
/* reasonable default */
if (image.depth >= 8)
image.data = linux_logo;
else if (image.depth >= 4)
image.data = linux_logo16;
else
image.data = linux_logo_bw;
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
needs_truepalette = 1;
if (image.depth >= 4 && image.depth <= 8)
needs_logo = 4;
else if (image.depth < 4)
needs_logo = 1;
break;
case FB_VISUAL_DIRECTCOLOR:
if (image.depth >= 24) {
needs_directpalette = 1;
needs_cmapreset = 1;
}
if (depth >= 8) {
logo = linux_logo;
logo_depth = 8;
} else if (depth >= 4) {
logo = linux_logo16;
logo_depth = 4;
} else {
logo = linux_logo_bw;
logo_depth = 1;
}
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
unsigned char mask[9] =
{ 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
unsigned char redmask, greenmask, bluemask;
int redshift, greenshift, blueshift;
/* Bug: Doesn't obey msb_right ... (who needs that?) */
redmask =
mask[info->var.red.length <
8 ? info->var.red.length : 8];
greenmask =
mask[info->var.green.length <
8 ? info->var.green.length : 8];
bluemask =
mask[info->var.blue.length <
8 ? info->var.blue.length : 8];
redshift =
info->var.red.offset - (8 - info->var.red.length);
greenshift =
info->var.green.offset - (8 - info->var.green.length);
blueshift =
info->var.blue.offset - (8 - info->var.blue.length);
/*
* We have to create a temporary palette since console palette is only
* 16 colors long.
*/
/* 16 colors */
else if (image.depth >= 16)
needs_logo = 4;
/* 2 colors */
else
needs_logo = 1;
break;
case FB_VISUAL_MONO01:
/* reversed 0 = fg, 1 = bg */
needs_logo = ~1;
break;
case FB_VISUAL_MONO10:
needs_logo = 1;
break;
case FB_VISUAL_PSEUDOCOLOR:
default:
if (image.depth >= 8)
needs_cmapreset = 1;
/* fall through */
case FB_VISUAL_STATIC_PSEUDOCOLOR:
/* 16 colors */
if (image.depth >= 4 && image.depth < 8)
needs_logo = 4;
/* 2 colors */
else if (image.depth < 4)
needs_logo = 1;
break;
}
if (needs_cmapreset)
fbcon_set_logocmap(info);
if (needs_truepalette || needs_directpalette) {
palette = kmalloc(256 * 4, GFP_KERNEL);
if (palette == NULL)
return (LOGO_H + vc->vc_font.height - 1)/vc->vc_font.height;
for (i = 0; i < LINUX_LOGO_COLORS; i++) {
palette[i + 32] =
(safe_shift
((linux_logo_red[i] & redmask),
redshift) | safe_shift((linux_logo_green[i] &
greenmask),
greenshift) |
safe_shift((linux_logo_blue[i] & bluemask),
blueshift));
}
return 1;
if (needs_truepalette)
fbcon_set_logo_truepalette(info, palette);
else
fbcon_set_logo_directpalette(info, palette);
saved_palette = info->pseudo_palette;
info->pseudo_palette = palette;
}
if (needs_logo) {
logo_new = kmalloc(LOGO_W * LOGO_H, GFP_KERNEL);
if (logo_new == NULL) {
if (palette)
kfree(palette);
if (saved_palette)
info->pseudo_palette = saved_palette;
return 1;
}
image.data = logo_new;
fbcon_set_logo(info, logo_new, needs_logo);
}
image.width = LOGO_W;
image.height = LOGO_H;
image.depth = depth;
image.data = logo;
image.dy = 0;
for (x = 0; x < num_online_cpus() * (LOGO_W + 8) &&
......@@ -2667,6 +2780,8 @@ static int __init fbcon_show_logo(void)
kfree(palette);
if (saved_palette != NULL)
info->pseudo_palette = saved_palette;
if (logo_new != NULL)
kfree(logo_new);
/*
* Modes not yet supported: packed pixels with depth != 8 (does such a
* thing exist in reality?)
......@@ -2701,7 +2816,10 @@ const struct consw fb_con = {
int __init fb_console_init(void)
{
if (!num_registered_fb)
return -ENODEV;
take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
__unsafe(THIS_MODULE);
return 0;
}
......
......@@ -730,12 +730,12 @@ fb_open(struct inode *inode, struct file *file)
#endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx]))
return -ENODEV;
if (info->fbops->owner)
__MOD_INC_USE_COUNT(info->fbops->owner);
if (!try_module_get(info->fbops->owner))
return -ENODEV;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res && info->fbops->owner)
__MOD_DEC_USE_COUNT(info->fbops->owner);
if (res)
module_put(info->fbops->owner);
}
return res;
}
......@@ -750,8 +750,7 @@ fb_release(struct inode *inode, struct file *file)
info = registered_fb[fbidx];
if (info->fbops->fb_release)
info->fbops->fb_release(info,1);
if (info->fbops->owner)
__MOD_DEC_USE_COUNT(info->fbops->owner);
module_put(info->fbops->owner);
unlock_kernel();
return 0;
}
......
......@@ -42,8 +42,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/console.h>
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
......@@ -54,7 +52,7 @@
#if defined(__powerpc__)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
#include "macmodes.h"
#ifdef CONFIG_NVRAM
#include <linux/nvram.h>
......@@ -80,10 +78,8 @@
#endif
#include <video/radeon.h>
#include <linux/radeonfb.h>
#define DEBUG 1
#if DEBUG
......@@ -681,7 +677,6 @@ static __inline__ int _max(int val1, int val2)
* globals
*/
static char fontname[40] __initdata;
static char *mode_option __initdata;
static char noaccel = 1;
static char mirror = 0;
......@@ -1295,7 +1290,6 @@ static int __devinit radeon_init_disp (struct radeonfb_info *rinfo)
var.activate = FB_ACTIVATE_NOW;
gen_set_var(&var, -1, info);
return 0;
}
......@@ -1495,7 +1489,7 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in
}
static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con,
static int radeonfb_pan_display (struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
......@@ -1509,7 +1503,6 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, int con,
OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
* var->bits_per_pixel / 8) & ~7);
return 0;
}
......@@ -2188,11 +2181,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo,
static struct fb_ops radeonfb_ops = {
.owner = THIS_MODULE,
.fb_set_var = gen_set_var,
.fb_check_var = radeonfb_check_var,
.fb_set_par = radeonfb_set_par,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = gen_set_cmap,
.fb_setcolreg = radeonfb_setcolreg,
.fb_pan_display = radeonfb_pan_display,
.fb_blank = radeonfb_blank,
......@@ -2228,11 +2218,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
info->fbops = &radeonfb_ops;
info->display_fg = NULL;
info->screen_base = (char *)rinfo->fb_base;
strncpy (info->fontname, fontname, sizeof (info->fontname));
info->fontname[sizeof (info->fontname) - 1] = 0;
info->changevar = NULL;
info->switch_con = gen_switch;
info->updatevar = gen_update_var;
/* Fill fix common fields */
strncpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
......@@ -3138,16 +3123,7 @@ int __init radeonfb_setup (char *options)
while ((this_opt = strsep (&options, ",")) != NULL) {
if (!*this_opt)
continue;
if (!strncmp (this_opt, "font:", 5)) {
char *p;
int i;
p = this_opt + 5;
for (i=0; i<sizeof (fontname) - 1; i++)
if (!*p || *p == ' ' || *p == ',')
break;
memcpy(fontname, this_opt + 5, i);
} else if (!strncmp(this_opt, "noaccel", 7)) {
if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} else if (!strncmp(this_opt, "mirror", 6)) {
mirror = 1;
......
......@@ -42,6 +42,7 @@
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include "rivafb.h"
#include "nvreg.h"
......@@ -246,15 +247,12 @@ struct riva_cursor {
/* command line data, set in rivafb_setup() */
static u32 pseudo_palette[17];
static char nomove = 0;
#ifdef CONFIG_MTRR
static char nomtrr __initdata = 0;
#endif
#ifndef MODULE
static char *mode_option __initdata = NULL;
#else
static char *font = NULL;
#endif
static struct fb_fix_screeninfo rivafb_fix = {
......@@ -428,7 +426,7 @@ static void rivafb_load_cursor_image(u8 *data, u8 *mask, struct riva_par *par,
m = *((u32 *)mask)++;
for (j = 0; j < w/2; j++) {
tmp = 0;
#if defined (__BIG_ENDIAN)
#if defined (__BIG_ENDIAN__)
if (m & (1 << 31))
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1;
......@@ -1162,6 +1160,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* framebuffer operations
*
* ------------------------------------------------------------------------- */
static int rivafb_open(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
memset(&par->state, 0, sizeof(struct fb_vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
/* save the DAC for Riva128 */
if (par->riva.Architecture == NV_ARCH_03)
par->state.flags |= VGA_SAVE_CMAP;
fb_save_vga(&par->state);
RivaGetConfig(&par->riva);
riva_save_state(par, &par->initial_state);
}
atomic_inc(&par->ref_count);
return 0;
}
static int rivafb_release(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
return -EINVAL;
if (cnt == 1) {
par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
fb_restore_vga(&par->state);
par->riva.LockUnlock(&par->riva, 1);
}
atomic_dec(&par->ref_count);
return 0;
}
static int rivafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
......@@ -1493,6 +1531,8 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
/* kernel interface */
static struct fb_ops riva_fb_ops = {
.owner = THIS_MODULE,
.fb_open = rivafb_open,
.fb_release = rivafb_release,
.fb_check_var = rivafb_check_var,
.fb_set_par = rivafb_set_par,
.fb_setcolreg = rivafb_setcolreg,
......@@ -1535,6 +1575,106 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
*
* ------------------------------------------------------------------------- */
static void __devinit rivafb_get_mem_len(struct riva_par *par,
struct fb_fix_screeninfo *fix)
{
RIVA_HW_INST *chip = &par->riva;
switch (chip->Architecture) {
case NV_ARCH_03:
if (chip->PFB[0x00000000/4] & 0x00000020) {
if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
&& ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
/*
* SDRAM 128 ZX.
*/
switch (chip->PFB[0x00000000/4] & 0x03) {
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
case 1:
fix->smem_len = 1024 * 1024 * 2;
break;
default:
fix->smem_len = 1024 * 1024 * 8;
break;
}
}
else {
fix->smem_len = 1024 * 1024 * 8;
}
}
else {
/*
* SGRAM 128.
*/
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 8;
break;
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
default:
fix->smem_len = 1024 * 1024 * 2;
break;
}
}
break;
case NV_ARCH_04:
if (chip->PFB[0x00000000/4] & 0x00000100) {
fix->smem_len = (((chip->PFB[0x00000000/4] >> 12)
& 0x0F) * 1024 * 2 + 1024 * 2) * 1024;
}
else {
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 32;
break;
case 1:
fix->smem_len = 1024 * 1024 * 4;
break;
case 2:
fix->smem_len = 1024 * 1024 * 8;
break;
case 3:
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
break;
case NV_ARCH_10:
case NV_ARCH_20:
switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) {
case 0x02:
fix->smem_len = 1024 * 1024 * 2;
break;
case 0x04:
fix->smem_len = 1024 * 1024 * 4;
break;
case 0x08:
fix->smem_len = 1024 * 1024 * 8;
break;
case 0x10:
fix->smem_len = 1024 * 1024 * 16;
break;
case 0x20:
fix->smem_len = 1024 * 1024 * 32;
break;
case 0x40:
fix->smem_len = 1024 * 1024 * 64;
break;
case 0x80:
fix->smem_len = 1024 * 1024 * 128;
break;
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
}
static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent)
{
......@@ -1586,14 +1726,22 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base + 0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base + 0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base + 0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base + 0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base + 0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base + 0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000);
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base +
0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base +
0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base +
0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base +
0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base +
0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base +
0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base +
0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base +
0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
......@@ -1603,22 +1751,26 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000);
default_par->riva.PRAMIN = (unsigned *)(info->screen_base +
0x00C00000);
default_par->dclk_max = 256000000;
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base
+ 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base
+ 0x00710000);
default_par->dclk_max = 250000000;
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
RivaGetConfig(&default_par->riva);
rivafb_get_mem_len(default_par, &rivafb_fix);
rivafb_fix.smem_len = default_par->riva.RamAmountKBytes * 1024;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
info->par = default_par;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
......@@ -1648,14 +1800,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
}
#endif /* CONFIG_MTRR */
/* unlock io */
CRTCout(default_par, 0x11, 0xFF);/* vgaHWunlock() + riva unlock(0x7F) */
default_par->riva.LockUnlock(&default_par->riva, 0);
info->par = default_par;
riva_save_state(default_par, &default_par->initial_state);
if (riva_set_fbinfo(info) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor;
......@@ -1680,7 +1824,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
return 0;
err_out_load_state:
riva_load_state(default_par, &default_par->initial_state);
err_out_cursor:
/* err_out_iounmap_fb: */
iounmap(info->screen_base);
......@@ -1704,8 +1847,6 @@ static void __devexit rivafb_remove_one(struct pci_dev *pd)
if (!info)
return;
riva_load_state(par, &par->initial_state);
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
......@@ -1742,13 +1883,11 @@ int __init rivafb_setup(char *options)
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
if (!strncmp(this_opt, "nomove", 6)) {
nomove = 1;
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
#endif
} else
#endif
mode_option = this_opt;
}
return 0;
......@@ -1773,9 +1912,7 @@ static struct pci_driver rivafb_driver = {
int __init rivafb_init(void)
{
int err;
#ifdef MODULE
if (font) strncpy(fontname, font, sizeof(fontname)-1);
#endif
err = pci_module_init(&rivafb_driver);
if (err)
return err;
......@@ -1796,8 +1933,6 @@ MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
MODULE_PARM(nomove, "i");
MODULE_PARM_DESC(nomove, "Enables YSCROLL_NOMOVE (0 or 1=enabled) (default=0)");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
......
......@@ -34,7 +34,8 @@ struct riva_par {
struct riva_regs initial_state; /* initial startup video mode */
struct riva_regs current_state;
struct fb_vgastate state;
atomic_t ref_count;
riva_cfb8_cmap_t cmap[256]; /* VGA DAC palette cache */
u32 riva_palette[16];
u32 cursor_data[32 * 32/4];
......
......@@ -7,7 +7,8 @@
*
* 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. */
* archive for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
......@@ -69,6 +70,8 @@ static struct vga16fb_par {
unsigned char ModeControl; /* CRT-Controller:17h */
unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct fb_vgastate state;
atomic_t ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C];
......@@ -295,6 +298,34 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
#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 fb_vgastate));
par->state.flags = 8;
fb_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)
fb_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)
{
......@@ -1346,6 +1377,8 @@ void vga16fb_imageblit(struct fb_info *info, struct fb_image *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,
......
/*
* linux/include/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 <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include "vga.h"
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 fb_vgastate *state)
{
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 0 */
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 < 8 * 8192; i++)
state->vga_font0[i] = vga_r(state->fbbase, i);
}
/* save font 1 */
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 < 8 * 8192; i++)
state->vga_font1[i] = vga_r(state->fbbase, i);
}
/* save font 2 */
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 < 2 * 8192; i++)
state->vga_text[i] = vga_r(state->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 < 2 * 8192; i++)
state->vga_text[i] = vga_r(state->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 fb_vgastate *state)
{
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 0 */
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 < 8 * 8192; i++)
vga_w(state->fbbase, i, state->vga_font0[i]);
}
/* restore font 1 */
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 < 8 * 8192; i++)
vga_w(state->fbbase, i, state->vga_font1[i]);
}
/* restore font 2 */
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 < 2 * 8192; i++)
vga_w(state->fbbase, i, state->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 < 2 * 8192; i++)
vga_w(state->fbbase + 2 * 8192, i,
state->vga_text[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 fb_vgastate *state)
{
unsigned short iobase;
int i;
state->misc = vga_r(state->vgabase, VGA_MIS_R);
if (state->misc & 1)
iobase = 0x3d0;
else
iobase = 0x3b0;
for (i = 0; i < state->num_crtc; i++)
state->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);
state->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++)
state->gfx[i] = vga_rgfx(state->vgabase, i);
for (i = 0; i < state->num_seq; i++)
state->seq[i] = vga_rseq(state->vgabase, i);
}
static void restore_vga_mode(struct fb_vgastate *state)
{
unsigned short iobase;
int i;
vga_w(state->vgabase, VGA_MIS_W, state->misc);
if (state->misc & 1)
iobase = 0x3d0;
else
iobase = 0x3b0;
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
state->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
for (i = 2; i < state->num_seq; i++)
vga_wseq(state->vgabase, i, state->seq[i]);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
/* unprotect vga regs */
vga_wcrtcs(state->vgabase, iobase, 17, state->crtc[17] & ~0x80);
for (i = 0; i < state->num_crtc; i++)
vga_wcrtcs(state->vgabase, iobase, i, state->crtc[i]);
for (i = 0; i < state->num_gfx; i++)
vga_wgfx(state->vgabase, i, state->gfx[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);
vga_wattr(state->vgabase, i, state->attr[i]);
}
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
state->seq[VGA_SEQ_CLOCK_MODE]);
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x20);
}
static void save_vga_cmap(struct fb_vgastate *state)
{
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++)
state->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D);
}
static void restore_vga_cmap(struct fb_vgastate *state)
{
int i;
vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
vga_w(state->vgabase, VGA_PEL_IW, 0x00);
for (i = 0; i < 768; i++)
vga_w(state->vgabase, VGA_PEL_D, state->vga_cmap[i]);
}
static void vga_cleanup(struct fb_vgastate *state)
{
if (state->vga_font0)
kfree(state->vga_font0);
if (state->vga_font1)
kfree(state->vga_font1);
if (state->vga_text)
kfree(state->vga_text);
if (state->fbbase)
iounmap(state->fbbase);
if (state->vga_cmap)
kfree(state->vga_cmap);
if (state->attr)
kfree(state->attr);
if (state->crtc)
kfree(state->crtc);
if (state->gfx)
kfree(state->gfx);
if (state->seq)
kfree(state->seq);
}
int fb_save_vga(struct fb_vgastate *state)
{
state->vga_font0 = NULL;
state->vga_font1 = NULL;
state->vga_text = NULL;
state->vga_cmap = NULL;
state->attr = NULL;
state->crtc = NULL;
state->gfx = NULL;
state->seq = NULL;
if (state->flags & VGA_SAVE_CMAP) {
state->vga_cmap = kmalloc(768, GFP_KERNEL);
if (!state->vga_cmap) {
vga_cleanup(state);
return 1;
}
save_vga_cmap(state);
}
if (state->flags & VGA_SAVE_MODE) {
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;
state->attr = kmalloc(state->num_attr, GFP_KERNEL);
state->crtc = kmalloc(state->num_crtc, GFP_KERNEL);
state->gfx = kmalloc(state->num_gfx, GFP_KERNEL);
state->seq = kmalloc(state->num_seq, GFP_KERNEL);
if (!state->attr || !state->crtc || !state->gfx ||
!state->seq) {
vga_cleanup(state);
return 1;
}
save_vga_mode(state);
}
if (state->flags & VGA_SAVE_FONT0) {
state->vga_font0 = kmalloc(8192 * 8, GFP_KERNEL);
if (!state->vga_font0) {
vga_cleanup(state);
return 1;
}
}
if (state->flags & VGA_SAVE_FONT1) {
state->vga_font1 = kmalloc(8192 * 8, GFP_KERNEL);
if (!state->vga_font1) {
vga_cleanup(state);
return 1;
}
}
if (state->flags & VGA_SAVE_TEXT) {
state->vga_text = kmalloc(8192 * 4, GFP_KERNEL);
if (!state->vga_text) {
vga_cleanup(state);
return 1;
}
}
if (state->flags & VGA_SAVE_FONTS) {
state->fbbase = ioremap(0xA0000, 8 * 8192);
if (!state->fbbase) {
vga_cleanup(state);
return 1;
}
save_vga_text(state);
iounmap(state->fbbase);
state->fbbase = NULL;
}
return 0;
}
int fb_restore_vga (struct fb_vgastate *state)
{
if (state->flags & VGA_SAVE_MODE)
restore_vga_mode(state);
if (state->flags & VGA_SAVE_FONTS) {
state->fbbase = ioremap(0xA0000, 8 * 8192);
if (!state->fbbase) {
vga_cleanup(state);
return 1;
}
restore_vga_text(state);
}
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(fb_save_vga);
EXPORT_SYMBOL(fb_restore_vga);
MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
MODULE_DESCRIPTION("VGA State Save/Restore");
MODULE_LICENSE("GPL");
......@@ -321,6 +321,37 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */
};
/* VGA State Save and Restore */
#define VGA_SAVE_FONT0 1 /* save/restore plane 2 fonts */
#define VGA_SAVE_FONT1 2 /* save/restore plane 3 fonts */
#define VGA_SAVE_TEXT 4 /* save/restore plane 0/1 fonts */
#define VGA_SAVE_FONTS 7 /* save/restore all fonts */
#define VGA_SAVE_MODE 8 /* save/restore video mode */
#define VGA_SAVE_CMAP 16 /* save/restore color map/DAC */
struct fb_vgastate {
caddr_t vgabase; /* mmio base, if supported */
__u32 flags; /* what state/s to save (see VGA_SAVE_*) */
__u32 depth; /* current fb depth, not important */
__u32 num_attr; /* number of att registers, 0 for default */
__u32 num_crtc; /* number of crt registers, 0 for default */
__u32 num_gfx; /* number of gfx registers, 0 for default */
__u32 num_seq; /* number of seq registers, 0 for default */
caddr_t fbbase; /* -- DO NOT ALTER STARTING HERE -- */
__u8 *vga_font0;
__u8 *vga_font1;
__u8 *vga_text;
__u8 *vga_cmap;
__u8 *attr;
__u8 *crtc;
__u8 *gfx;
__u8 *seq;
__u8 misc;
};
extern int fb_save_vga(struct fb_vgastate *state);
extern int fb_restore_vga(struct fb_vgastate *state);
#ifdef __KERNEL__
#include <linux/fs.h>
......
......@@ -9,8 +9,8 @@
#include <linux/config.h>
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/console_struct.h>
#include <linux/tty.h>
#include <linux/console_struct.h>
/*
* Presently, a lot of graphics programs do not restore the contents of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment