2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / vgastate . c - - VGA state save / restore
*
* Copyright 2002 James Simmons
*
* Copyright history from vga16fb . c :
* Copyright 1999 Ben Pfaff and Petr Vandrovec
* Based on VGA info at http : //www.goodnet.com/~tinara/FreeVGA/home.htm
* Based on VESA framebuffer ( c ) 1998 Gerd Knorr
*
* This file is subject to the terms and conditions of the GNU General
* Public License . See the file COPYING in the main directory of this
* archive for more details .
*
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/fb.h>
# include <linux/vmalloc.h>
# include <video/vga.h>
struct regstate {
__u8 * vga_font0 ;
__u8 * vga_font1 ;
__u8 * vga_text ;
__u8 * vga_cmap ;
__u8 * attr ;
__u8 * crtc ;
__u8 * gfx ;
__u8 * seq ;
__u8 misc ;
} ;
static inline unsigned char vga_rcrtcs ( void __iomem * regbase , unsigned short iobase ,
unsigned char reg )
{
vga_w ( regbase , iobase + 0x4 , reg ) ;
return vga_r ( regbase , iobase + 0x5 ) ;
}
static inline void vga_wcrtcs ( void __iomem * regbase , unsigned short iobase ,
unsigned char reg , unsigned char val )
{
vga_w ( regbase , iobase + 0x4 , reg ) ;
vga_w ( regbase , iobase + 0x5 , val ) ;
}
static void save_vga_text ( struct vgastate * state , void __iomem * fbbase )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
int i ;
u8 misc , attr10 , gr4 , gr5 , gr6 , seq1 , seq2 , seq4 ;
2007-05-08 11:39:41 +04:00
unsigned short iobase ;
2005-04-17 02:20:36 +04:00
/* if in graphics mode, no need to save */
2007-05-08 11:39:41 +04:00
misc = vga_r ( state - > vgabase , VGA_MIS_R ) ;
iobase = ( misc & 1 ) ? 0x3d0 : 0x3b0 ;
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x00 ) ;
2005-04-17 02:20:36 +04:00
attr10 = vga_rattr ( state - > vgabase , 0x10 ) ;
2007-05-08 11:39:41 +04:00
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x20 ) ;
2005-04-17 02:20:36 +04:00
if ( attr10 & 1 )
return ;
2007-05-08 11:39:41 +04:00
2005-04-17 02:20:36 +04:00
/* save regs */
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 ) ;
/* blank screen */
seq1 = vga_rseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 | 1 < < 5 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x3 ) ;
/* save font at plane 2 */
if ( state - > flags & VGA_SAVE_FONT0 ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x4 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x2 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 4 * 8192 ; i + + )
saved - > vga_font0 [ i ] = vga_r ( fbbase , i ) ;
}
/* save font at plane 3 */
if ( state - > flags & VGA_SAVE_FONT1 ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x8 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x3 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < state - > memsize ; i + + )
saved - > vga_font1 [ i ] = vga_r ( fbbase , i ) ;
}
/* save font at plane 0/1 */
if ( state - > flags & VGA_SAVE_TEXT ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 8192 ; i + + )
saved - > vga_text [ i ] = vga_r ( fbbase , i ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x2 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x1 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 8192 ; i + + )
saved - > vga_text [ 8192 + i ] = vga_r ( fbbase + 2 * 8192 , i ) ;
}
/* restore regs */
vga_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 ) ;
/* unblank screen */
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 & ~ ( 1 < < 5 ) ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x3 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 ) ;
}
static void restore_vga_text ( struct vgastate * state , void __iomem * fbbase )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
int i ;
2007-05-08 11:39:41 +04:00
u8 gr1 , gr3 , gr4 , gr5 , gr6 , gr8 ;
2005-04-17 02:20:36 +04:00
u8 seq1 , seq2 , seq4 ;
/* save regs */
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 ) ;
/* blank screen */
seq1 = vga_rseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 | 1 < < 5 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x3 ) ;
if ( state - > depth = = 4 ) {
vga_wgfx ( state - > vgabase , VGA_GFX_DATA_ROTATE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_BIT_MASK , 0xff ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_SR_ENABLE , 0x00 ) ;
}
/* restore font at plane 2 */
if ( state - > flags & VGA_SAVE_FONT0 ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x4 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x2 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 4 * 8192 ; i + + )
vga_w ( fbbase , i , saved - > vga_font0 [ i ] ) ;
}
/* restore font at plane 3 */
if ( state - > flags & VGA_SAVE_FONT1 ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x8 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x3 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < state - > memsize ; i + + )
vga_w ( fbbase , i , saved - > vga_font1 [ i ] ) ;
}
/* restore font at plane 0/1 */
if ( state - > flags & VGA_SAVE_TEXT ) {
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 8192 ; i + + )
vga_w ( fbbase , i , saved - > vga_text [ i ] ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , 0x2 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , 0x6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , 0x1 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , 0x0 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , 0x5 ) ;
for ( i = 0 ; i < 8192 ; i + + )
vga_w ( fbbase , i , saved - > vga_text [ 8192 + i ] ) ;
}
/* unblank screen */
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 & ~ ( 1 < < 5 ) ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x3 ) ;
/* restore regs */
vga_wgfx ( state - > vgabase , VGA_GFX_SR_ENABLE , gr1 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_DATA_ROTATE , gr3 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_PLANE_READ , gr4 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MODE , gr5 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_MISC , gr6 ) ;
vga_wgfx ( state - > vgabase , VGA_GFX_BIT_MASK , gr8 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE , seq1 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_PLANE_WRITE , seq2 ) ;
vga_wseq ( state - > vgabase , VGA_SEQ_MEMORY_MODE , seq4 ) ;
}
static void save_vga_mode ( struct vgastate * state )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
unsigned short iobase ;
int i ;
saved - > misc = vga_r ( state - > vgabase , VGA_MIS_R ) ;
if ( saved - > misc & 1 )
iobase = 0x3d0 ;
else
iobase = 0x3b0 ;
for ( i = 0 ; i < state - > num_crtc ; i + + )
saved - > crtc [ i ] = vga_rcrtcs ( state - > vgabase , iobase , i ) ;
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x00 ) ;
for ( i = 0 ; i < state - > num_attr ; i + + ) {
vga_r ( state - > vgabase , iobase + 0xa ) ;
saved - > attr [ i ] = vga_rattr ( state - > vgabase , i ) ;
}
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x20 ) ;
for ( i = 0 ; i < state - > num_gfx ; i + + )
saved - > gfx [ i ] = vga_rgfx ( state - > vgabase , i ) ;
for ( i = 0 ; i < state - > num_seq ; i + + )
saved - > seq [ i ] = vga_rseq ( state - > vgabase , i ) ;
}
static void restore_vga_mode ( struct vgastate * state )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
unsigned short iobase ;
int i ;
vga_w ( state - > vgabase , VGA_MIS_W , saved - > misc ) ;
if ( saved - > misc & 1 )
iobase = 0x3d0 ;
else
iobase = 0x3b0 ;
/* turn off display */
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE ,
saved - > seq [ VGA_SEQ_CLOCK_MODE ] | 0x20 ) ;
/* disable sequencer */
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x01 ) ;
/* enable palette addressing */
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x00 ) ;
for ( i = 2 ; i < state - > num_seq ; i + + )
vga_wseq ( state - > vgabase , i , saved - > seq [ i ] ) ;
/* unprotect vga regs */
vga_wcrtcs ( state - > vgabase , iobase , 17 , saved - > crtc [ 17 ] & ~ 0x80 ) ;
for ( i = 0 ; i < state - > num_crtc ; i + + )
vga_wcrtcs ( state - > vgabase , iobase , i , saved - > crtc [ i ] ) ;
for ( i = 0 ; i < state - > num_gfx ; i + + )
vga_wgfx ( state - > vgabase , i , saved - > gfx [ i ] ) ;
for ( i = 0 ; i < state - > num_attr ; i + + ) {
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_wattr ( state - > vgabase , i , saved - > attr [ i ] ) ;
}
/* reenable sequencer */
vga_wseq ( state - > vgabase , VGA_SEQ_RESET , 0x03 ) ;
/* turn display on */
vga_wseq ( state - > vgabase , VGA_SEQ_CLOCK_MODE ,
saved - > seq [ VGA_SEQ_CLOCK_MODE ] & ~ ( 1 < < 5 ) ) ;
/* disable video/palette source */
vga_r ( state - > vgabase , iobase + 0xa ) ;
vga_w ( state - > vgabase , VGA_ATT_W , 0x20 ) ;
}
static void save_vga_cmap ( struct vgastate * state )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
int i ;
vga_w ( state - > vgabase , VGA_PEL_MSK , 0xff ) ;
/* assumes DAC is readable and writable */
vga_w ( state - > vgabase , VGA_PEL_IR , 0x00 ) ;
for ( i = 0 ; i < 768 ; i + + )
saved - > vga_cmap [ i ] = vga_r ( state - > vgabase , VGA_PEL_D ) ;
}
static void restore_vga_cmap ( struct vgastate * state )
{
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
int i ;
vga_w ( state - > vgabase , VGA_PEL_MSK , 0xff ) ;
/* assumes DAC is readable and writable */
vga_w ( state - > vgabase , VGA_PEL_IW , 0x00 ) ;
for ( i = 0 ; i < 768 ; i + + )
vga_w ( state - > vgabase , VGA_PEL_D , saved - > vga_cmap [ i ] ) ;
}
static void vga_cleanup ( struct vgastate * state )
{
if ( state - > vidstate ! = NULL ) {
struct regstate * saved = ( struct regstate * ) state - > vidstate ;
2005-09-10 11:26:54 +04:00
vfree ( saved - > vga_font0 ) ;
vfree ( saved - > vga_font1 ) ;
vfree ( saved - > vga_text ) ;
vfree ( saved - > vga_cmap ) ;
vfree ( saved - > attr ) ;
2005-04-17 02:20:36 +04:00
kfree ( saved ) ;
state - > vidstate = NULL ;
}
}
int save_vga ( struct vgastate * state )
{
struct regstate * saved ;
2006-01-10 07:53:45 +03:00
saved = kzalloc ( sizeof ( struct regstate ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( saved = = NULL )
return 1 ;
2006-01-10 07:53:45 +03:00
2005-04-17 02:20:36 +04:00
state - > vidstate = ( void * ) saved ;
if ( state - > flags & VGA_SAVE_CMAP ) {
saved - > vga_cmap = vmalloc ( 768 ) ;
if ( ! saved - > vga_cmap ) {
vga_cleanup ( state ) ;
return 1 ;
}
save_vga_cmap ( state ) ;
}
if ( state - > flags & VGA_SAVE_MODE ) {
int total ;
if ( state - > num_attr < 21 )
state - > num_attr = 21 ;
if ( state - > num_crtc < 25 )
state - > num_crtc = 25 ;
if ( state - > num_gfx < 9 )
state - > num_gfx = 9 ;
if ( state - > num_seq < 5 )
state - > num_seq = 5 ;
total = state - > num_attr + state - > num_crtc +
state - > num_gfx + state - > num_seq ;
saved - > attr = vmalloc ( total ) ;
if ( ! saved - > attr ) {
vga_cleanup ( state ) ;
return 1 ;
}
saved - > crtc = saved - > attr + state - > num_attr ;
saved - > gfx = saved - > crtc + state - > num_crtc ;
saved - > seq = saved - > gfx + state - > num_gfx ;
save_vga_mode ( state ) ;
}
if ( state - > flags & VGA_SAVE_FONTS ) {
void __iomem * fbbase ;
/* exit if window is less than 32K */
if ( state - > memsize & & state - > memsize < 4 * 8192 ) {
vga_cleanup ( state ) ;
return 1 ;
}
if ( ! state - > memsize )
state - > memsize = 8 * 8192 ;
if ( ! state - > membase )
state - > membase = 0xA0000 ;
fbbase = ioremap ( state - > membase , state - > memsize ) ;
if ( ! fbbase ) {
vga_cleanup ( state ) ;
return 1 ;
}
/*
* save only first 32 K used by vgacon
*/
if ( state - > flags & VGA_SAVE_FONT0 ) {
saved - > vga_font0 = vmalloc ( 4 * 8192 ) ;
if ( ! saved - > vga_font0 ) {
iounmap ( fbbase ) ;
vga_cleanup ( state ) ;
return 1 ;
}
}
/*
* largely unused , but if required by the caller
* we ' ll just save everything .
*/
if ( state - > flags & VGA_SAVE_FONT1 ) {
saved - > vga_font1 = vmalloc ( state - > memsize ) ;
if ( ! saved - > vga_font1 ) {
iounmap ( fbbase ) ;
vga_cleanup ( state ) ;
return 1 ;
}
}
/*
* Save 8 K at plane0 [ 0 ] , and 8 K at plane1 [ 16 K ]
*/
if ( state - > flags & VGA_SAVE_TEXT ) {
saved - > vga_text = vmalloc ( 8192 * 2 ) ;
if ( ! saved - > vga_text ) {
iounmap ( fbbase ) ;
vga_cleanup ( state ) ;
return 1 ;
}
}
save_vga_text ( state , fbbase ) ;
iounmap ( fbbase ) ;
}
return 0 ;
}
int restore_vga ( struct vgastate * state )
{
if ( state - > vidstate = = NULL )
return 1 ;
if ( state - > flags & VGA_SAVE_MODE )
restore_vga_mode ( state ) ;
if ( state - > flags & VGA_SAVE_FONTS ) {
void __iomem * fbbase = ioremap ( state - > membase , state - > memsize ) ;
if ( ! fbbase ) {
vga_cleanup ( state ) ;
return 1 ;
}
restore_vga_text ( state , fbbase ) ;
iounmap ( fbbase ) ;
}
if ( state - > flags & VGA_SAVE_CMAP )
restore_vga_cmap ( state ) ;
vga_cleanup ( state ) ;
return 0 ;
}
EXPORT_SYMBOL ( save_vga ) ;
EXPORT_SYMBOL ( restore_vga ) ;
MODULE_AUTHOR ( " James Simmons <jsimmons@users.sf.net> " ) ;
MODULE_DESCRIPTION ( " VGA State Save/Restore " ) ;
MODULE_LICENSE ( " GPL " ) ;