2019-06-04 11:11:30 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-04-11 01:28:10 +04:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright 2007 - 2008 rPath , Inc . - All Rights Reserved
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* arch / i386 / boot / video - mode . c
*
* Set the video mode . This is separated out into a different
* file in order to be shared with the ACPI wakeup code .
*/
# include "boot.h"
# include "video.h"
# include "vesa.h"
2015-11-30 13:10:33 +03:00
# include <uapi/asm/boot.h>
2008-04-11 01:28:10 +04:00
/*
* Common variables
*/
2015-01-24 21:11:32 +03:00
int adapter ; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
2008-04-11 01:28:10 +04:00
int force_x , force_y ; /* Don't query the BIOS for cols/rows */
int do_restore ; /* Screen contents changed during mode flip */
int graphic_mode ; /* Graphic mode with linear frame buffer */
/* Probe the video drivers and have them generate their mode lists. */
void probe_cards ( int unsafe )
{
struct card_info * card ;
static u8 probed [ 2 ] ;
if ( probed [ unsafe ] )
return ;
probed [ unsafe ] = 1 ;
for ( card = video_cards ; card < video_cards_end ; card + + ) {
if ( card - > unsafe = = unsafe ) {
if ( card - > probe )
card - > nmodes = card - > probe ( ) ;
else
card - > nmodes = 0 ;
}
}
}
/* Test if a mode is defined */
int mode_defined ( u16 mode )
{
struct card_info * card ;
struct mode_info * mi ;
int i ;
for ( card = video_cards ; card < video_cards_end ; card + + ) {
mi = card - > modes ;
for ( i = 0 ; i < card - > nmodes ; i + + , mi + + ) {
if ( mi - > mode = = mode )
return 1 ;
}
}
return 0 ;
}
/* Set mode (without recalc) */
static int raw_set_mode ( u16 mode , u16 * real_mode )
{
int nmode , i ;
struct card_info * card ;
struct mode_info * mi ;
/* Drop the recalc bit if set */
mode & = ~ VIDEO_RECALC ;
/* Scan for mode based on fixed ID, position, or resolution */
nmode = 0 ;
for ( card = video_cards ; card < video_cards_end ; card + + ) {
mi = card - > modes ;
for ( i = 0 ; i < card - > nmodes ; i + + , mi + + ) {
int visible = mi - > x | | mi - > y ;
if ( ( mode = = nmode & & visible ) | |
mode = = mi - > mode | |
mode = = ( mi - > y < < 8 ) + mi - > x ) {
* real_mode = mi - > mode ;
return card - > set_mode ( mi ) ;
}
if ( visible )
nmode + + ;
}
}
/* Nothing found? Is it an "exceptional" (unprobed) mode? */
for ( card = video_cards ; card < video_cards_end ; card + + ) {
if ( mode > = card - > xmode_first & &
mode < card - > xmode_first + card - > xmode_n ) {
struct mode_info mix ;
* real_mode = mix . mode = mode ;
mix . x = mix . y = 0 ;
return card - > set_mode ( & mix ) ;
}
}
/* Otherwise, failure... */
return - 1 ;
}
/*
* Recalculate the vertical video cutoff ( hack ! )
*/
static void vga_recalc_vertical ( void )
{
unsigned int font_size , rows ;
u16 crtc ;
u8 pt , ov ;
set_fs ( 0 ) ;
font_size = rdfs8 ( 0x485 ) ; /* BIOS: font size (pixels) */
rows = force_y ? force_y : rdfs8 ( 0x484 ) + 1 ; /* Text rows */
rows * = font_size ; /* Visible scan lines */
rows - - ; /* ... minus one */
crtc = vga_crtc ( ) ;
pt = in_idx ( crtc , 0x11 ) ;
pt & = ~ 0x80 ; /* Unlock CR0-7 */
out_idx ( pt , crtc , 0x11 ) ;
out_idx ( ( u8 ) rows , crtc , 0x12 ) ; /* Lower height register */
ov = in_idx ( crtc , 0x07 ) ; /* Overflow register */
ov & = 0xbd ;
ov | = ( rows > > ( 8 - 1 ) ) & 0x02 ;
ov | = ( rows > > ( 9 - 6 ) ) & 0x40 ;
out_idx ( ov , crtc , 0x07 ) ;
}
/* Set mode (with recalc if specified) */
int set_mode ( u16 mode )
{
int rv ;
u16 real_mode ;
/* Very special mode numbers... */
if ( mode = = VIDEO_CURRENT_MODE )
return 0 ; /* Nothing to do... */
else if ( mode = = NORMAL_VGA )
mode = VIDEO_80x25 ;
else if ( mode = = EXTENDED_VGA )
mode = VIDEO_8POINT ;
rv = raw_set_mode ( mode , & real_mode ) ;
if ( rv )
return rv ;
if ( mode & VIDEO_RECALC )
vga_recalc_vertical ( ) ;
/* Save the canonical mode number for the kernel, not
an alias , size specification or menu position */
# ifndef _WAKEUP
boot_params . hdr . vid_mode = real_mode ;
# endif
return 0 ;
}