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 @@ ...@@ -6,7 +6,7 @@
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
export-objs := fbmem.o fbcmap.o fbmon.o modedb.o softcursor.o cfbfillrect.o \ 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. # Each configuration option enables a list of files.
...@@ -50,7 +50,8 @@ obj-$(CONFIG_FB_TRIDENT) += tridentfb.o ...@@ -50,7 +50,8 @@ obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
obj-$(CONFIG_FB_S3TRIO) += S3triofb.o obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
obj-$(CONFIG_FB_TGA) += tgafb.o obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.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_VIRGE) += virgefb.o
obj-$(CONFIG_FB_G364) += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.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 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 ...@@ -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_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MATROX) += matrox/ 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_SIS) += sis/
obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o obj-$(CONFIG_FB_ATY) += aty/ cfbimgblt.o
......
...@@ -1770,9 +1770,12 @@ static char * __init aty128find_ROM(void) ...@@ -1770,9 +1770,12 @@ static char * __init aty128find_ROM(void)
char *rom_base; char *rom_base;
char *rom; char *rom;
int stage; int stage;
int i; int i, j;
char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */ 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) { for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
stage = 1; stage = 1;
...@@ -1803,10 +1806,14 @@ static char * __init aty128find_ROM(void) ...@@ -1803,10 +1806,14 @@ static char * __init aty128find_ROM(void)
/* ATI signature found. Let's see if it's a Rage128 */ /* ATI signature found. Let's see if it's a Rage128 */
for (i = 0; (i < 512) && (stage != 4); i++) { for (i = 0; (i < 512) && (stage != 4); i++) {
if (R128_sig[0] == *rom) for (j = 0; j < sizeof(R128_sig)/sizeof(char *);j++) {
if (strncmp(R128_sig, rom, if (R128_sig[j][0] == *rom)
strlen(R128_sig)) == 0) if (strncmp(R128_sig[j], rom,
stage = 4; strlen(R128_sig[j])) == 0) {
stage = 4;
break;
}
}
rom++; rom++;
} }
if (stage != 4) { if (stage != 4) {
......
...@@ -123,11 +123,11 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8 ...@@ -123,11 +123,11 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
shift = start_index; shift = start_index;
} }
while (n--) { while (n--) {
if (p->fix.visual == FB_VISUAL_PSEUDOCOLOR)
color = *src & bitmask;
if (p->fix.visual == FB_VISUAL_TRUECOLOR || if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
p->fix.visual == FB_VISUAL_DIRECTCOLOR ) p->fix.visual == FB_VISUAL_DIRECTCOLOR )
color = palette[*src] & bitmask; color = palette[*src] & bitmask;
else
color = *src & bitmask;
val |= SHIFT_HIGH(color, shift); val |= SHIFT_HIGH(color, shift);
if (shift >= null_bits) { if (shift >= null_bits) {
FB_WRITEL(val, dst++); FB_WRITEL(val, dst++);
......
...@@ -317,18 +317,16 @@ void set_con2fb_map(int unit, int newidx) ...@@ -317,18 +317,16 @@ void set_con2fb_map(int unit, int newidx)
if (newidx != con2fb_map[unit]) { if (newidx != con2fb_map[unit]) {
oldfb = registered_fb[oldidx]; oldfb = registered_fb[oldidx];
newfb = registered_fb[newidx]; newfb = registered_fb[newidx];
if (newfb->fbops->owner) if (!try_module_get(newfb->fbops->owner))
__MOD_INC_USE_COUNT(newfb->fbops->owner); return;
if (newfb->fbops->fb_open if (newfb->fbops->fb_open
&& newfb->fbops->fb_open(newfb, 0)) { && newfb->fbops->fb_open(newfb, 0)) {
if (newfb->fbops->owner) module_put(newfb->fbops->owner);
__MOD_DEC_USE_COUNT(newfb->fbops->owner);
return; return;
} }
if (oldfb->fbops->fb_release) if (oldfb->fbops->fb_release)
oldfb->fbops->fb_release(oldfb, 0); oldfb->fbops->fb_release(oldfb, 0);
if (oldfb->fbops->owner) module_put(oldfb->fbops->owner);
__MOD_DEC_USE_COUNT(oldfb->fbops->owner);
vc = fb_display[unit].conp; vc = fb_display[unit].conp;
fontdata = fb_display[unit].fontdata; fontdata = fb_display[unit].fontdata;
userfont = fb_display[unit].userfont; userfont = fb_display[unit].userfont;
...@@ -596,10 +594,10 @@ static const char *fbcon_startup(void) ...@@ -596,10 +594,10 @@ static const char *fbcon_startup(void)
info->currcon = -1; info->currcon = -1;
owner = info->fbops->owner; owner = info->fbops->owner;
if (owner) if (!try_module_get(owner))
__MOD_INC_USE_COUNT(owner); return NULL;
if (info->fbops->fb_open && info->fbops->fb_open(info, 0) && owner) if (info->fbops->fb_open && info->fbops->fb_open(info, 0))
__MOD_DEC_USE_COUNT(owner); module_put(owner);
if (info->fix.type != FB_TYPE_TEXT) { if (info->fix.type != FB_TYPE_TEXT) {
if (fbcon_softback_size) { if (fbcon_softback_size) {
...@@ -2549,111 +2547,226 @@ static inline unsigned safe_shift(unsigned d, int n) ...@@ -2549,111 +2547,226 @@ static inline unsigned safe_shift(unsigned d, int n)
return n < 0 ? d >> -n : d << 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 fb_info *info = p->fb_info;
struct vc_data *vc = info->display_fg; struct vc_data *vc = info->display_fg;
struct fb_image image; struct fb_image image;
u32 *palette = NULL, *saved_palette = NULL; u32 *palette = NULL, *saved_palette = NULL;
int depth = info->var.bits_per_pixel; unsigned char *fb = info->screen_base, *logo_new = NULL;
unsigned char *fb = info->screen_base; int done = 0, x;
unsigned char *logo; int needs_cmapreset = 0;
int i, j, n, x; int needs_truepalette = 0;
int logo_depth, done = 0; int needs_directpalette = 0;
int needs_logo = 0;
/* Return if the frame buffer is not mapped */ /* Return if the frame buffer is not mapped */
if (!fb) if (!fb || !info->fbops->fb_imageblit)
return 0; return 0;
/* image.depth = info->var.bits_per_pixel;
* Set colors if visual is PSEUDOCOLOR and we have enough colors, or for
* DIRECTCOLOR /* reasonable default */
* We don't have to set the colors for the 16-color logo, since that logo if (image.depth >= 8)
* uses the standard VGA text console palette image.data = linux_logo;
*/ else if (image.depth >= 4)
if ((info->fix.visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) || image.data = linux_logo16;
(info->fix.visual == FB_VISUAL_DIRECTCOLOR && depth >= 24)) else
for (i = 0; i < LINUX_LOGO_COLORS; i += n) { image.data = linux_logo_bw;
n = LINUX_LOGO_COLORS - i;
if (n > 16) switch (info->fix.visual) {
/* palette_cmap provides space for only 16 colors at once */ case FB_VISUAL_TRUECOLOR:
n = 16; needs_truepalette = 1;
palette_cmap.start = 32 + i; if (image.depth >= 4 && image.depth <= 8)
palette_cmap.len = n; needs_logo = 4;
for (j = 0; j < n; ++j) { else if (image.depth < 4)
palette_cmap.red[j] = needs_logo = 1;
(linux_logo_red[i + j] << 8) | break;
linux_logo_red[i + j]; case FB_VISUAL_DIRECTCOLOR:
palette_cmap.green[j] = if (image.depth >= 24) {
(linux_logo_green[i + j] << 8) | needs_directpalette = 1;
linux_logo_green[i + j]; needs_cmapreset = 1;
palette_cmap.blue[j] =
(linux_logo_blue[i + j] << 8) |
linux_logo_blue[i + j];
}
fb_set_cmap(&palette_cmap, 1, info);
} }
/* 16 colors */
if (depth >= 8) { else if (image.depth >= 16)
logo = linux_logo; needs_logo = 4;
logo_depth = 8; /* 2 colors */
} else if (depth >= 4) { else
logo = linux_logo16; needs_logo = 1;
logo_depth = 4; break;
} else { case FB_VISUAL_MONO01:
logo = linux_logo_bw; /* reversed 0 = fg, 1 = bg */
logo_depth = 1; needs_logo = ~1;
} break;
case FB_VISUAL_MONO10:
if (info->fix.visual == FB_VISUAL_TRUECOLOR) { needs_logo = 1;
unsigned char mask[9] = break;
{ 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; case FB_VISUAL_PSEUDOCOLOR:
unsigned char redmask, greenmask, bluemask; default:
int redshift, greenshift, blueshift; if (image.depth >= 8)
needs_cmapreset = 1;
/* Bug: Doesn't obey msb_right ... (who needs that?) */ /* fall through */
redmask = case FB_VISUAL_STATIC_PSEUDOCOLOR:
mask[info->var.red.length < /* 16 colors */
8 ? info->var.red.length : 8]; if (image.depth >= 4 && image.depth < 8)
greenmask = needs_logo = 4;
mask[info->var.green.length < /* 2 colors */
8 ? info->var.green.length : 8]; else if (image.depth < 4)
bluemask = needs_logo = 1;
mask[info->var.blue.length < break;
8 ? info->var.blue.length : 8]; }
redshift =
info->var.red.offset - (8 - info->var.red.length); if (needs_cmapreset)
greenshift = fbcon_set_logocmap(info);
info->var.green.offset - (8 - info->var.green.length);
blueshift = if (needs_truepalette || needs_directpalette) {
info->var.blue.offset - (8 - info->var.blue.length);
/*
* We have to create a temporary palette since console palette is only
* 16 colors long.
*/
palette = kmalloc(256 * 4, GFP_KERNEL); palette = kmalloc(256 * 4, GFP_KERNEL);
if (palette == NULL) if (palette == NULL)
return (LOGO_H + vc->vc_font.height - 1)/vc->vc_font.height; return 1;
for (i = 0; i < LINUX_LOGO_COLORS; i++) { if (needs_truepalette)
palette[i + 32] = fbcon_set_logo_truepalette(info, palette);
(safe_shift else
((linux_logo_red[i] & redmask), fbcon_set_logo_directpalette(info, palette);
redshift) | safe_shift((linux_logo_green[i] &
greenmask),
greenshift) |
safe_shift((linux_logo_blue[i] & bluemask),
blueshift));
}
saved_palette = info->pseudo_palette; saved_palette = info->pseudo_palette;
info->pseudo_palette = 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.width = LOGO_W;
image.height = LOGO_H; image.height = LOGO_H;
image.depth = depth;
image.data = logo;
image.dy = 0; image.dy = 0;
for (x = 0; x < num_online_cpus() * (LOGO_W + 8) && for (x = 0; x < num_online_cpus() * (LOGO_W + 8) &&
...@@ -2667,6 +2780,8 @@ static int __init fbcon_show_logo(void) ...@@ -2667,6 +2780,8 @@ static int __init fbcon_show_logo(void)
kfree(palette); kfree(palette);
if (saved_palette != NULL) if (saved_palette != NULL)
info->pseudo_palette = saved_palette; info->pseudo_palette = saved_palette;
if (logo_new != NULL)
kfree(logo_new);
/* /*
* Modes not yet supported: packed pixels with depth != 8 (does such a * Modes not yet supported: packed pixels with depth != 8 (does such a
* thing exist in reality?) * thing exist in reality?)
...@@ -2701,7 +2816,10 @@ const struct consw fb_con = { ...@@ -2701,7 +2816,10 @@ const struct consw fb_con = {
int __init fb_console_init(void) 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); take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
__unsafe(THIS_MODULE);
return 0; return 0;
} }
......
...@@ -730,12 +730,12 @@ fb_open(struct inode *inode, struct file *file) ...@@ -730,12 +730,12 @@ fb_open(struct inode *inode, struct file *file)
#endif /* CONFIG_KMOD */ #endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx])) if (!(info = registered_fb[fbidx]))
return -ENODEV; return -ENODEV;
if (info->fbops->owner) if (!try_module_get(info->fbops->owner))
__MOD_INC_USE_COUNT(info->fbops->owner); return -ENODEV;
if (info->fbops->fb_open) { if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1); res = info->fbops->fb_open(info,1);
if (res && info->fbops->owner) if (res)
__MOD_DEC_USE_COUNT(info->fbops->owner); module_put(info->fbops->owner);
} }
return res; return res;
} }
...@@ -750,8 +750,7 @@ fb_release(struct inode *inode, struct file *file) ...@@ -750,8 +750,7 @@ fb_release(struct inode *inode, struct file *file)
info = registered_fb[fbidx]; info = registered_fb[fbidx];
if (info->fbops->fb_release) if (info->fbops->fb_release)
info->fbops->fb_release(info,1); info->fbops->fb_release(info,1);
if (info->fbops->owner) module_put(info->fbops->owner);
__MOD_DEC_USE_COUNT(info->fbops->owner);
unlock_kernel(); unlock_kernel();
return 0; return 0;
} }
......
...@@ -42,8 +42,6 @@ ...@@ -42,8 +42,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/console.h>
#include <linux/selection.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -54,7 +52,7 @@ ...@@ -54,7 +52,7 @@
#if defined(__powerpc__) #if defined(__powerpc__)
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#include <video/macmodes.h> #include "macmodes.h"
#ifdef CONFIG_NVRAM #ifdef CONFIG_NVRAM
#include <linux/nvram.h> #include <linux/nvram.h>
...@@ -80,10 +78,8 @@ ...@@ -80,10 +78,8 @@
#endif #endif
#include <video/radeon.h> #include <video/radeon.h>
#include <linux/radeonfb.h> #include <linux/radeonfb.h>
#define DEBUG 1 #define DEBUG 1
#if DEBUG #if DEBUG
...@@ -681,7 +677,6 @@ static __inline__ int _max(int val1, int val2) ...@@ -681,7 +677,6 @@ static __inline__ int _max(int val1, int val2)
* globals * globals
*/ */
static char fontname[40] __initdata;
static char *mode_option __initdata; static char *mode_option __initdata;
static char noaccel = 1; static char noaccel = 1;
static char mirror = 0; static char mirror = 0;
...@@ -1295,7 +1290,6 @@ static int __devinit radeon_init_disp (struct radeonfb_info *rinfo) ...@@ -1295,7 +1290,6 @@ static int __devinit radeon_init_disp (struct radeonfb_info *rinfo)
var.activate = FB_ACTIVATE_NOW; var.activate = FB_ACTIVATE_NOW;
gen_set_var(&var, -1, info); gen_set_var(&var, -1, info);
return 0; return 0;
} }
...@@ -1495,7 +1489,7 @@ static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *in ...@@ -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 fb_info *info)
{ {
struct radeonfb_info *rinfo = (struct radeonfb_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, ...@@ -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) OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
* var->bits_per_pixel / 8) & ~7); * var->bits_per_pixel / 8) & ~7);
return 0; return 0;
} }
...@@ -2188,11 +2181,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo, ...@@ -2188,11 +2181,8 @@ static void radeon_write_mode (struct radeonfb_info *rinfo,
static struct fb_ops radeonfb_ops = { static struct fb_ops radeonfb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_set_var = gen_set_var,
.fb_check_var = radeonfb_check_var, .fb_check_var = radeonfb_check_var,
.fb_set_par = radeonfb_set_par, .fb_set_par = radeonfb_set_par,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = gen_set_cmap,
.fb_setcolreg = radeonfb_setcolreg, .fb_setcolreg = radeonfb_setcolreg,
.fb_pan_display = radeonfb_pan_display, .fb_pan_display = radeonfb_pan_display,
.fb_blank = radeonfb_blank, .fb_blank = radeonfb_blank,
...@@ -2228,11 +2218,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo) ...@@ -2228,11 +2218,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
info->fbops = &radeonfb_ops; info->fbops = &radeonfb_ops;
info->display_fg = NULL; info->display_fg = NULL;
info->screen_base = (char *)rinfo->fb_base; 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 */ /* Fill fix common fields */
strncpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); strncpy(info->fix.id, rinfo->name, sizeof(info->fix.id));
...@@ -3138,16 +3123,7 @@ int __init radeonfb_setup (char *options) ...@@ -3138,16 +3123,7 @@ int __init radeonfb_setup (char *options)
while ((this_opt = strsep (&options, ",")) != NULL) { while ((this_opt = strsep (&options, ",")) != NULL) {
if (!*this_opt) if (!*this_opt)
continue; continue;
if (!strncmp (this_opt, "font:", 5)) { if (!strncmp(this_opt, "noaccel", 7)) {
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)) {
noaccel = 1; noaccel = 1;
} else if (!strncmp(this_opt, "mirror", 6)) { } else if (!strncmp(this_opt, "mirror", 6)) {
mirror = 1; mirror = 1;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
#include <asm/mtrr.h> #include <asm/mtrr.h>
#endif #endif
#include "rivafb.h" #include "rivafb.h"
#include "nvreg.h" #include "nvreg.h"
...@@ -246,15 +247,12 @@ struct riva_cursor { ...@@ -246,15 +247,12 @@ struct riva_cursor {
/* command line data, set in rivafb_setup() */ /* command line data, set in rivafb_setup() */
static u32 pseudo_palette[17]; static u32 pseudo_palette[17];
static char nomove = 0;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
static char nomtrr __initdata = 0; static char nomtrr __initdata = 0;
#endif #endif
#ifndef MODULE #ifndef MODULE
static char *mode_option __initdata = NULL; static char *mode_option __initdata = NULL;
#else
static char *font = NULL;
#endif #endif
static struct fb_fix_screeninfo rivafb_fix = { 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, ...@@ -428,7 +426,7 @@ static void rivafb_load_cursor_image(u8 *data, u8 *mask, struct riva_par *par,
m = *((u32 *)mask)++; m = *((u32 *)mask)++;
for (j = 0; j < w/2; j++) { for (j = 0; j < w/2; j++) {
tmp = 0; tmp = 0;
#if defined (__BIG_ENDIAN) #if defined (__BIG_ENDIAN__)
if (m & (1 << 31)) if (m & (1 << 31))
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16; tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1; b <<= 1;
...@@ -1162,6 +1160,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1162,6 +1160,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* framebuffer operations * 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, static int rivafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info) struct fb_info *info)
...@@ -1493,6 +1531,8 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -1493,6 +1531,8 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
/* kernel interface */ /* kernel interface */
static struct fb_ops riva_fb_ops = { static struct fb_ops riva_fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_open = rivafb_open,
.fb_release = rivafb_release,
.fb_check_var = rivafb_check_var, .fb_check_var = rivafb_check_var,
.fb_set_par = rivafb_set_par, .fb_set_par = rivafb_set_par,
.fb_setcolreg = rivafb_setcolreg, .fb_setcolreg = rivafb_setcolreg,
...@@ -1535,6 +1575,106 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) ...@@ -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, static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
...@@ -1586,14 +1726,22 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, ...@@ -1586,14 +1726,22 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
} }
default_par->riva.EnableIRQ = 0; default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000); default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base +
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base + 0x00100000); 0x00680000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base + 0x00002000); default_par->riva.PFB = (unsigned *)(default_par->ctrl_base +
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base + 0x00400000); 0x00100000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base + 0x00101000); default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base +
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base + 0x00009000); 0x00002000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base + 0x00000000); default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base +
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000); 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.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000); default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
...@@ -1603,22 +1751,26 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, ...@@ -1603,22 +1751,26 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
switch (default_par->riva.Architecture) { switch (default_par->riva.Architecture) {
case NV_ARCH_03: 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; rivafb_fix.accel = FB_ACCEL_NV3;
break; break;
case NV_ARCH_04: case NV_ARCH_04:
case NV_ARCH_10: case NV_ARCH_10:
case NV_ARCH_20: case NV_ARCH_20:
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000); default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000); + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base
+ 0x00710000);
default_par->dclk_max = 250000000;
rivafb_fix.accel = FB_ACCEL_NV4; rivafb_fix.accel = FB_ACCEL_NV4;
break; break;
} }
RivaGetConfig(&default_par->riva); rivafb_get_mem_len(default_par, &rivafb_fix);
rivafb_fix.smem_len = default_par->riva.RamAmountKBytes * 1024; info->par = default_par;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
if (!request_mem_region(rivafb_fix.smem_start, if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) { rivafb_fix.smem_len, "rivafb")) {
...@@ -1648,14 +1800,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, ...@@ -1648,14 +1800,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
} }
#endif /* CONFIG_MTRR */ #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) { if (riva_set_fbinfo(info) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n"); printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor; goto err_out_cursor;
...@@ -1680,7 +1824,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd, ...@@ -1680,7 +1824,6 @@ static int __devinit rivafb_init_one(struct pci_dev *pd,
return 0; return 0;
err_out_load_state: err_out_load_state:
riva_load_state(default_par, &default_par->initial_state);
err_out_cursor: err_out_cursor:
/* err_out_iounmap_fb: */ /* err_out_iounmap_fb: */
iounmap(info->screen_base); iounmap(info->screen_base);
...@@ -1704,8 +1847,6 @@ static void __devexit rivafb_remove_one(struct pci_dev *pd) ...@@ -1704,8 +1847,6 @@ static void __devexit rivafb_remove_one(struct pci_dev *pd)
if (!info) if (!info)
return; return;
riva_load_state(par, &par->initial_state);
unregister_framebuffer(info); unregister_framebuffer(info);
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
...@@ -1742,13 +1883,11 @@ int __init rivafb_setup(char *options) ...@@ -1742,13 +1883,11 @@ int __init rivafb_setup(char *options)
while ((this_opt = strsep(&options, ",")) != NULL) { while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) if (!*this_opt)
continue; continue;
if (!strncmp(this_opt, "nomove", 6)) {
nomove = 1;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) { if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1; nomtrr = 1;
#endif
} else } else
#endif
mode_option = this_opt; mode_option = this_opt;
} }
return 0; return 0;
...@@ -1773,9 +1912,7 @@ static struct pci_driver rivafb_driver = { ...@@ -1773,9 +1912,7 @@ static struct pci_driver rivafb_driver = {
int __init rivafb_init(void) int __init rivafb_init(void)
{ {
int err; int err;
#ifdef MODULE
if (font) strncpy(fontname, font, sizeof(fontname)-1);
#endif
err = pci_module_init(&rivafb_driver); err = pci_module_init(&rivafb_driver);
if (err) if (err)
return err; return err;
...@@ -1796,8 +1933,6 @@ MODULE_PARM(font, "s"); ...@@ -1796,8 +1933,6 @@ MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)"); MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
MODULE_PARM(noaccel, "i"); MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)"); 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 #ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i"); MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)"); MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
......
...@@ -34,7 +34,8 @@ struct riva_par { ...@@ -34,7 +34,8 @@ struct riva_par {
struct riva_regs initial_state; /* initial startup video mode */ struct riva_regs initial_state; /* initial startup video mode */
struct riva_regs current_state; struct riva_regs current_state;
struct fb_vgastate state;
atomic_t ref_count;
riva_cfb8_cmap_t cmap[256]; /* VGA DAC palette cache */ riva_cfb8_cmap_t cmap[256]; /* VGA DAC palette cache */
u32 riva_palette[16]; u32 riva_palette[16];
u32 cursor_data[32 * 32/4]; u32 cursor_data[32 * 32/4];
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
* *
* This file is subject to the terms and conditions of the GNU General * 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 * 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/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -69,6 +70,8 @@ static struct vga16fb_par { ...@@ -69,6 +70,8 @@ static struct vga16fb_par {
unsigned char ModeControl; /* CRT-Controller:17h */ unsigned char ModeControl; /* CRT-Controller:17h */
unsigned char ClockingMode; /* Seq-Controller:01h */ unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state; } vga_state;
struct fb_vgastate state;
atomic_t ref_count;
int palette_blanked, vesa_blanked, mode, isVGA; int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv; u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C]; u8 crtc[VGA_CRT_C];
...@@ -295,6 +298,34 @@ static void vga16fb_clock_chip(struct vga16fb_par *par, ...@@ -295,6 +298,34 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
#define FAIL(X) return -EINVAL #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, static int vga16fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info) struct fb_info *info)
{ {
...@@ -1346,6 +1377,8 @@ void vga16fb_imageblit(struct fb_info *info, struct fb_image *image) ...@@ -1346,6 +1377,8 @@ void vga16fb_imageblit(struct fb_info *info, struct fb_image *image)
static struct fb_ops vga16fb_ops = { static struct fb_ops vga16fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_open = vga16fb_open,
.fb_release = vga16fb_release,
.fb_check_var = vga16fb_check_var, .fb_check_var = vga16fb_check_var,
.fb_set_par = vga16fb_set_par, .fb_set_par = vga16fb_set_par,
.fb_setcolreg = vga16fb_setcolreg, .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 { ...@@ -321,6 +321,37 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */ 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__ #ifdef __KERNEL__
#include <linux/fs.h> #include <linux/fs.h>
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/vt.h> #include <linux/vt.h>
#include <linux/kd.h> #include <linux/kd.h>
#include <linux/console_struct.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/console_struct.h>
/* /*
* Presently, a lot of graphics programs do not restore the contents of * 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