2007-07-11 23:18:52 +04:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright 2007 rPath , Inc . - All Rights Reserved
*
* This file is part of the Linux kernel , and is made available under
* the terms of the GNU General Public License version 2.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* VESA text modes
*/
# include "boot.h"
# include "video.h"
# include "vesa.h"
/* VESA information */
static struct vesa_general_info vginfo ;
static struct vesa_mode_info vminfo ;
__videocard video_vesa ;
2008-04-11 01:28:10 +04:00
# ifndef _WAKEUP
2007-07-11 23:18:52 +04:00
static void vesa_store_mode_params_graphics ( void ) ;
2008-04-11 01:28:10 +04:00
# else /* _WAKEUP */
static inline void vesa_store_mode_params_graphics ( void ) { }
# endif /* _WAKEUP */
2007-07-11 23:18:52 +04:00
static int vesa_probe ( void )
{
# if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
2007-08-31 22:30:31 +04:00
u16 ax , cx , di ;
2007-07-11 23:18:52 +04:00
u16 mode ;
addr_t mode_ptr ;
struct mode_info * mi ;
int nmodes = 0 ;
video_vesa . modes = GET_HEAP ( struct mode_info , 0 ) ;
ax = 0x4f00 ;
2007-08-31 22:30:31 +04:00
di = ( size_t ) & vginfo ;
asm ( INT10
: " +a " ( ax ) , " +D " ( di ) , " =m " ( vginfo )
: : " ebx " , " ecx " , " edx " , " esi " ) ;
2007-07-11 23:18:52 +04:00
if ( ax ! = 0x004f | |
vginfo . signature ! = VESA_MAGIC | |
vginfo . version < 0x0102 )
return 0 ; /* Not present */
# endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
# ifdef CONFIG_VIDEO_VESA
set_fs ( vginfo . video_mode_ptr . seg ) ;
mode_ptr = vginfo . video_mode_ptr . off ;
while ( ( mode = rdfs16 ( mode_ptr ) ) ! = 0xffff ) {
mode_ptr + = 2 ;
2007-10-26 03:09:38 +04:00
if ( ! heap_free ( sizeof ( struct mode_info ) ) )
2007-07-11 23:18:52 +04:00
break ; /* Heap full, can't save mode info */
if ( mode & ~ 0x1ff )
continue ;
memset ( & vminfo , 0 , sizeof vminfo ) ; /* Just in case... */
ax = 0x4f01 ;
2007-08-31 22:30:31 +04:00
cx = mode ;
di = ( size_t ) & vminfo ;
asm ( INT10
: " +a " ( ax ) , " +c " ( cx ) , " +D " ( di ) , " =m " ( vminfo )
: : " ebx " , " edx " , " esi " ) ;
2007-07-11 23:18:52 +04:00
if ( ax ! = 0x004f )
continue ;
if ( ( vminfo . mode_attr & 0x15 ) = = 0x05 ) {
/* Text Mode, TTY BIOS supported,
supported by hardware */
mi = GET_HEAP ( struct mode_info , 1 ) ;
2008-01-30 15:33:02 +03:00
mi - > mode = mode + VIDEO_FIRST_VESA ;
mi - > depth = 0 ; /* text */
mi - > x = vminfo . h_res ;
mi - > y = vminfo . v_res ;
2007-07-11 23:18:52 +04:00
nmodes + + ;
2008-01-30 15:33:02 +03:00
} else if ( ( vminfo . mode_attr & 0x99 ) = = 0x99 & &
( vminfo . memory_layout = = 4 | |
vminfo . memory_layout = = 6 ) & &
vminfo . memory_planes = = 1 ) {
2007-07-11 23:18:52 +04:00
# ifdef CONFIG_FB
/* Graphics mode, color, linear frame buffer
2008-01-30 15:33:02 +03:00
supported . Only register the mode if
if framebuffer is configured , however ,
otherwise the user will be left without a screen .
We don ' t require CONFIG_FB_VESA , however , since
some of the other framebuffer drivers can use
this mode - setting , too . */
2007-07-11 23:18:52 +04:00
mi = GET_HEAP ( struct mode_info , 1 ) ;
mi - > mode = mode + VIDEO_FIRST_VESA ;
2008-01-30 15:33:02 +03:00
mi - > depth = vminfo . bpp ;
mi - > x = vminfo . h_res ;
mi - > y = vminfo . v_res ;
2007-07-11 23:18:52 +04:00
nmodes + + ;
# endif
}
}
return nmodes ;
# else
return 0 ;
# endif /* CONFIG_VIDEO_VESA */
}
static int vesa_set_mode ( struct mode_info * mode )
{
2007-08-31 22:30:31 +04:00
u16 ax , bx , cx , di ;
2007-07-11 23:18:52 +04:00
int is_graphic ;
u16 vesa_mode = mode - > mode - VIDEO_FIRST_VESA ;
memset ( & vminfo , 0 , sizeof vminfo ) ; /* Just in case... */
ax = 0x4f01 ;
2007-08-31 22:30:31 +04:00
cx = vesa_mode ;
di = ( size_t ) & vminfo ;
asm ( INT10
: " +a " ( ax ) , " +c " ( cx ) , " +D " ( di ) , " =m " ( vminfo )
: : " ebx " , " edx " , " esi " ) ;
2007-07-11 23:18:52 +04:00
if ( ax ! = 0x004f )
return - 1 ;
if ( ( vminfo . mode_attr & 0x15 ) = = 0x05 ) {
/* It's a supported text mode */
is_graphic = 0 ;
} else if ( ( vminfo . mode_attr & 0x99 ) = = 0x99 ) {
/* It's a graphics mode with linear frame buffer */
is_graphic = 1 ;
vesa_mode | = 0x4000 ; /* Request linear frame buffer */
} else {
return - 1 ; /* Invalid mode */
}
ax = 0x4f02 ;
2007-08-31 22:30:31 +04:00
bx = vesa_mode ;
di = 0 ;
asm volatile ( INT10
: " +a " ( ax ) , " +b " ( bx ) , " +D " ( di )
: : " ecx " , " edx " , " esi " ) ;
2007-07-11 23:18:52 +04:00
if ( ax ! = 0x004f )
return - 1 ;
graphic_mode = is_graphic ;
if ( ! is_graphic ) {
/* Text mode */
force_x = mode - > x ;
force_y = mode - > y ;
do_restore = 1 ;
} else {
/* Graphics mode */
vesa_store_mode_params_graphics ( ) ;
}
return 0 ;
}
2008-04-11 01:28:10 +04:00
# ifndef _WAKEUP
2007-07-11 23:18:52 +04:00
/* Switch DAC to 8-bit mode */
static void vesa_dac_set_8bits ( void )
{
u8 dac_size = 6 ;
/* If possible, switch the DAC to 8-bit mode */
if ( vginfo . capabilities & 1 ) {
u16 ax , bx ;
ax = 0x4f08 ;
bx = 0x0800 ;
asm volatile ( INT10
: " +a " ( ax ) , " +b " ( bx )
: : " ecx " , " edx " , " esi " , " edi " ) ;
if ( ax = = 0x004f )
dac_size = bx > > 8 ;
}
/* Set the color sizes to the DAC size, and offsets to 0 */
boot_params . screen_info . red_size = dac_size ;
boot_params . screen_info . green_size = dac_size ;
boot_params . screen_info . blue_size = dac_size ;
boot_params . screen_info . rsvd_size = dac_size ;
boot_params . screen_info . red_pos = 0 ;
boot_params . screen_info . green_pos = 0 ;
boot_params . screen_info . blue_pos = 0 ;
boot_params . screen_info . rsvd_pos = 0 ;
}
/* Save the VESA protected mode info */
static void vesa_store_pm_info ( void )
{
u16 ax , bx , di , es ;
ax = 0x4f0a ;
bx = di = 0 ;
asm ( " pushw %%es; " INT10 " ; movw %%es,%0; popw %%es "
: " =d " ( es ) , " +a " ( ax ) , " +b " ( bx ) , " +D " ( di )
: : " ecx " , " esi " ) ;
if ( ax ! = 0x004f )
return ;
boot_params . screen_info . vesapm_seg = es ;
boot_params . screen_info . vesapm_off = di ;
}
/*
* Save video mode parameters for graphics mode
*/
static void vesa_store_mode_params_graphics ( void )
{
/* Tell the kernel we're in VESA graphics mode */
boot_params . screen_info . orig_video_isVGA = 0x23 ;
/* Mode parameters */
boot_params . screen_info . vesa_attributes = vminfo . mode_attr ;
boot_params . screen_info . lfb_linelength = vminfo . logical_scan ;
boot_params . screen_info . lfb_width = vminfo . h_res ;
boot_params . screen_info . lfb_height = vminfo . v_res ;
boot_params . screen_info . lfb_depth = vminfo . bpp ;
boot_params . screen_info . pages = vminfo . image_planes ;
boot_params . screen_info . lfb_base = vminfo . lfb_ptr ;
memcpy ( & boot_params . screen_info . red_size ,
& vminfo . rmask , 8 ) ;
/* General parameters */
boot_params . screen_info . lfb_size = vginfo . total_memory ;
if ( vminfo . bpp < = 8 )
vesa_dac_set_8bits ( ) ;
vesa_store_pm_info ( ) ;
}
/*
* Save EDID information for the kernel ; this is invoked , separately ,
* after mode - setting .
*/
void vesa_store_edid ( void )
{
# ifdef CONFIG_FIRMWARE_EDID
u16 ax , bx , cx , dx , di ;
/* Apparently used as a nonsense token... */
memset ( & boot_params . edid_info , 0x13 , sizeof boot_params . edid_info ) ;
if ( vginfo . version < 0x0200 )
return ; /* EDID requires VBE 2.0+ */
ax = 0x4f15 ; /* VBE DDC */
bx = 0x0000 ; /* Report DDC capabilities */
cx = 0 ; /* Controller 0 */
di = 0 ; /* ES:DI must be 0 by spec */
/* Note: The VBE DDC spec is different from the main VESA spec;
we genuinely have to assume all registers are destroyed here . */
asm ( " pushw %%es; movw %2,%%es; " INT10 " ; popw %%es "
: " +a " ( ax ) , " +b " ( bx )
: " c " ( cx ) , " D " ( di )
: " esi " ) ;
if ( ax ! = 0x004f )
return ; /* No EDID */
/* BH = time in seconds to transfer EDD information */
/* BL = DDC level supported */
ax = 0x4f15 ; /* VBE DDC */
bx = 0x0001 ; /* Read EDID */
cx = 0 ; /* Controller 0 */
dx = 0 ; /* EDID block number */
di = ( size_t ) & boot_params . edid_info ; /* (ES:)Pointer to block */
asm ( INT10
2007-08-02 14:16:46 +04:00
: " +a " ( ax ) , " +b " ( bx ) , " +d " ( dx ) , " =m " ( boot_params . edid_info )
2007-07-11 23:18:52 +04:00
: " c " ( cx ) , " D " ( di )
: " esi " ) ;
# endif /* CONFIG_FIRMWARE_EDID */
}
2008-04-11 01:28:10 +04:00
# endif /* not _WAKEUP */
2007-07-11 23:18:52 +04:00
__videocard video_vesa =
{
. card_name = " VESA " ,
. probe = vesa_probe ,
. set_mode = vesa_set_mode ,
. xmode_first = VIDEO_FIRST_VESA ,
. xmode_n = 0x200 ,
} ;