5e518d7672
For the i386, code is already present in video.S that gets the EDID from the video BIOS. Make this visible so drivers can also use this data as fallback when i2c does not work. To ensure that the EDID block is returned for the primary graphics adapter only, by check if the IORESOURCE_ROM_SHADOW flag is set. Signed-off-by: Antonino Daplas <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2012 lines
40 KiB
ArmAsm
2012 lines
40 KiB
ArmAsm
/* video.S
|
|
*
|
|
* Display adapter & video mode setup, version 2.13 (14-May-99)
|
|
*
|
|
* Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
|
|
* Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
|
|
*
|
|
* Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
|
|
*
|
|
* For further information, look at Documentation/svga.txt.
|
|
*
|
|
*/
|
|
|
|
#include <linux/config.h> /* for CONFIG_VIDEO_* */
|
|
|
|
/* Enable autodetection of SVGA adapters and modes. */
|
|
#undef CONFIG_VIDEO_SVGA
|
|
|
|
/* Enable autodetection of VESA modes */
|
|
#define CONFIG_VIDEO_VESA
|
|
|
|
/* Enable compacting of mode table */
|
|
#define CONFIG_VIDEO_COMPACT
|
|
|
|
/* Retain screen contents when switching modes */
|
|
#define CONFIG_VIDEO_RETAIN
|
|
|
|
/* Enable local mode list */
|
|
#undef CONFIG_VIDEO_LOCAL
|
|
|
|
/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
|
|
#undef CONFIG_VIDEO_400_HACK
|
|
|
|
/* Hack that lets you force specific BIOS mode ID and specific dimensions */
|
|
#undef CONFIG_VIDEO_GFX_HACK
|
|
#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
|
|
#define VIDEO_GFX_BIOS_BX 0x0102
|
|
#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
|
|
|
|
/* This code uses an extended set of video mode numbers. These include:
|
|
* Aliases for standard modes
|
|
* NORMAL_VGA (-1)
|
|
* EXTENDED_VGA (-2)
|
|
* ASK_VGA (-3)
|
|
* Video modes numbered by menu position -- NOT RECOMMENDED because of lack
|
|
* of compatibility when extending the table. These are between 0x00 and 0xff.
|
|
*/
|
|
#define VIDEO_FIRST_MENU 0x0000
|
|
|
|
/* Standard BIOS video modes (BIOS number + 0x0100) */
|
|
#define VIDEO_FIRST_BIOS 0x0100
|
|
|
|
/* VESA BIOS video modes (VESA number + 0x0200) */
|
|
#define VIDEO_FIRST_VESA 0x0200
|
|
|
|
/* Video7 special modes (BIOS number + 0x0900) */
|
|
#define VIDEO_FIRST_V7 0x0900
|
|
|
|
/* Special video modes */
|
|
#define VIDEO_FIRST_SPECIAL 0x0f00
|
|
#define VIDEO_80x25 0x0f00
|
|
#define VIDEO_8POINT 0x0f01
|
|
#define VIDEO_80x43 0x0f02
|
|
#define VIDEO_80x28 0x0f03
|
|
#define VIDEO_CURRENT_MODE 0x0f04
|
|
#define VIDEO_80x30 0x0f05
|
|
#define VIDEO_80x34 0x0f06
|
|
#define VIDEO_80x60 0x0f07
|
|
#define VIDEO_GFX_HACK 0x0f08
|
|
#define VIDEO_LAST_SPECIAL 0x0f09
|
|
|
|
/* Video modes given by resolution */
|
|
#define VIDEO_FIRST_RESOLUTION 0x1000
|
|
|
|
/* The "recalculate timings" flag */
|
|
#define VIDEO_RECALC 0x8000
|
|
|
|
/* Positions of various video parameters passed to the kernel */
|
|
/* (see also include/linux/tty.h) */
|
|
#define PARAM_CURSOR_POS 0x00
|
|
#define PARAM_VIDEO_PAGE 0x04
|
|
#define PARAM_VIDEO_MODE 0x06
|
|
#define PARAM_VIDEO_COLS 0x07
|
|
#define PARAM_VIDEO_EGA_BX 0x0a
|
|
#define PARAM_VIDEO_LINES 0x0e
|
|
#define PARAM_HAVE_VGA 0x0f
|
|
#define PARAM_FONT_POINTS 0x10
|
|
|
|
#define PARAM_LFB_WIDTH 0x12
|
|
#define PARAM_LFB_HEIGHT 0x14
|
|
#define PARAM_LFB_DEPTH 0x16
|
|
#define PARAM_LFB_BASE 0x18
|
|
#define PARAM_LFB_SIZE 0x1c
|
|
#define PARAM_LFB_LINELENGTH 0x24
|
|
#define PARAM_LFB_COLORS 0x26
|
|
#define PARAM_VESAPM_SEG 0x2e
|
|
#define PARAM_VESAPM_OFF 0x30
|
|
#define PARAM_LFB_PAGES 0x32
|
|
#define PARAM_VESA_ATTRIB 0x34
|
|
#define PARAM_CAPABILITIES 0x36
|
|
|
|
/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
|
|
#ifdef CONFIG_VIDEO_RETAIN
|
|
#define DO_STORE call store_screen
|
|
#else
|
|
#define DO_STORE
|
|
#endif /* CONFIG_VIDEO_RETAIN */
|
|
|
|
# This is the main entry point called by setup.S
|
|
# %ds *must* be pointing to the bootsector
|
|
video: pushw %ds # We use different segments
|
|
pushw %ds # FS contains original DS
|
|
popw %fs
|
|
pushw %cs # DS is equal to CS
|
|
popw %ds
|
|
pushw %cs # ES is equal to CS
|
|
popw %es
|
|
xorw %ax, %ax
|
|
movw %ax, %gs # GS is zero
|
|
cld
|
|
call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
|
|
#ifdef CONFIG_VIDEO_SELECT
|
|
movw %fs:(0x01fa), %ax # User selected video mode
|
|
cmpw $ASK_VGA, %ax # Bring up the menu
|
|
jz vid2
|
|
|
|
call mode_set # Set the mode
|
|
jc vid1
|
|
|
|
leaw badmdt, %si # Invalid mode ID
|
|
call prtstr
|
|
vid2: call mode_menu
|
|
vid1:
|
|
#ifdef CONFIG_VIDEO_RETAIN
|
|
call restore_screen # Restore screen contents
|
|
#endif /* CONFIG_VIDEO_RETAIN */
|
|
call store_edid
|
|
#endif /* CONFIG_VIDEO_SELECT */
|
|
call mode_params # Store mode parameters
|
|
popw %ds # Restore original DS
|
|
ret
|
|
|
|
# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
|
|
basic_detect:
|
|
movb $0, %fs:(PARAM_HAVE_VGA)
|
|
movb $0x12, %ah # Check EGA/VGA
|
|
movb $0x10, %bl
|
|
int $0x10
|
|
movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
|
|
cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
|
|
je basret
|
|
|
|
incb adapter
|
|
movw $0x1a00, %ax # Check EGA or VGA?
|
|
int $0x10
|
|
cmpb $0x1a, %al # 1a means VGA...
|
|
jne basret # anything else is EGA.
|
|
|
|
incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
|
|
incb adapter
|
|
basret: ret
|
|
|
|
# Store the video mode parameters for later usage by the kernel.
|
|
# This is done by asking the BIOS except for the rows/columns
|
|
# parameters in the default 80x25 mode -- these are set directly,
|
|
# because some very obscure BIOSes supply insane values.
|
|
mode_params:
|
|
#ifdef CONFIG_VIDEO_SELECT
|
|
cmpb $0, graphic_mode
|
|
jnz mopar_gr
|
|
#endif
|
|
movb $0x03, %ah # Read cursor position
|
|
xorb %bh, %bh
|
|
int $0x10
|
|
movw %dx, %fs:(PARAM_CURSOR_POS)
|
|
movb $0x0f, %ah # Read page/mode/width
|
|
int $0x10
|
|
movw %bx, %fs:(PARAM_VIDEO_PAGE)
|
|
movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
|
|
cmpb $0x7, %al # MDA/HGA => segment differs
|
|
jnz mopar0
|
|
|
|
movw $0xb000, video_segment
|
|
mopar0: movw %gs:(0x485), %ax # Font size
|
|
movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
|
|
movw force_size, %ax # Forced size?
|
|
orw %ax, %ax
|
|
jz mopar1
|
|
|
|
movb %ah, %fs:(PARAM_VIDEO_COLS)
|
|
movb %al, %fs:(PARAM_VIDEO_LINES)
|
|
ret
|
|
|
|
mopar1: movb $25, %al
|
|
cmpb $0, adapter # If we are on CGA/MDA/HGA, the
|
|
jz mopar2 # screen must have 25 lines.
|
|
|
|
movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
|
|
incb %al # location of max lines.
|
|
mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
|
|
ret
|
|
|
|
#ifdef CONFIG_VIDEO_SELECT
|
|
# Fetching of VESA frame buffer parameters
|
|
mopar_gr:
|
|
leaw modelist+1024, %di
|
|
movb $0x23, %fs:(PARAM_HAVE_VGA)
|
|
movw 16(%di), %ax
|
|
movw %ax, %fs:(PARAM_LFB_LINELENGTH)
|
|
movw 18(%di), %ax
|
|
movw %ax, %fs:(PARAM_LFB_WIDTH)
|
|
movw 20(%di), %ax
|
|
movw %ax, %fs:(PARAM_LFB_HEIGHT)
|
|
movb 25(%di), %al
|
|
movb $0, %ah
|
|
movw %ax, %fs:(PARAM_LFB_DEPTH)
|
|
movb 29(%di), %al
|
|
movb $0, %ah
|
|
movw %ax, %fs:(PARAM_LFB_PAGES)
|
|
movl 40(%di), %eax
|
|
movl %eax, %fs:(PARAM_LFB_BASE)
|
|
movl 31(%di), %eax
|
|
movl %eax, %fs:(PARAM_LFB_COLORS)
|
|
movl 35(%di), %eax
|
|
movl %eax, %fs:(PARAM_LFB_COLORS+4)
|
|
movw 0(%di), %ax
|
|
movw %ax, %fs:(PARAM_VESA_ATTRIB)
|
|
|
|
# get video mem size
|
|
leaw modelist+1024, %di
|
|
movw $0x4f00, %ax
|
|
int $0x10
|
|
xorl %eax, %eax
|
|
movw 18(%di), %ax
|
|
movl %eax, %fs:(PARAM_LFB_SIZE)
|
|
|
|
# store mode capabilities
|
|
movl 10(%di), %eax
|
|
movl %eax, %fs:(PARAM_CAPABILITIES)
|
|
|
|
# switching the DAC to 8-bit is for <= 8 bpp only
|
|
movw %fs:(PARAM_LFB_DEPTH), %ax
|
|
cmpw $8, %ax
|
|
jg dac_done
|
|
|
|
# get DAC switching capability
|
|
xorl %eax, %eax
|
|
movb 10(%di), %al
|
|
testb $1, %al
|
|
jz dac_set
|
|
|
|
# attempt to switch DAC to 8-bit
|
|
movw $0x4f08, %ax
|
|
movw $0x0800, %bx
|
|
int $0x10
|
|
cmpw $0x004f, %ax
|
|
jne dac_set
|
|
movb %bh, dac_size # store actual DAC size
|
|
|
|
dac_set:
|
|
# set color size to DAC size
|
|
movb dac_size, %al
|
|
movb %al, %fs:(PARAM_LFB_COLORS+0)
|
|
movb %al, %fs:(PARAM_LFB_COLORS+2)
|
|
movb %al, %fs:(PARAM_LFB_COLORS+4)
|
|
movb %al, %fs:(PARAM_LFB_COLORS+6)
|
|
|
|
# set color offsets to 0
|
|
movb $0, %fs:(PARAM_LFB_COLORS+1)
|
|
movb $0, %fs:(PARAM_LFB_COLORS+3)
|
|
movb $0, %fs:(PARAM_LFB_COLORS+5)
|
|
movb $0, %fs:(PARAM_LFB_COLORS+7)
|
|
|
|
dac_done:
|
|
# get protected mode interface informations
|
|
movw $0x4f0a, %ax
|
|
xorw %bx, %bx
|
|
xorw %di, %di
|
|
int $0x10
|
|
cmp $0x004f, %ax
|
|
jnz no_pm
|
|
|
|
movw %es, %fs:(PARAM_VESAPM_SEG)
|
|
movw %di, %fs:(PARAM_VESAPM_OFF)
|
|
no_pm: ret
|
|
|
|
# The video mode menu
|
|
mode_menu:
|
|
leaw keymsg, %si # "Return/Space/Timeout" message
|
|
call prtstr
|
|
call flush
|
|
nokey: call getkt
|
|
|
|
cmpb $0x0d, %al # ENTER ?
|
|
je listm # yes - manual mode selection
|
|
|
|
cmpb $0x20, %al # SPACE ?
|
|
je defmd1 # no - repeat
|
|
|
|
call beep
|
|
jmp nokey
|
|
|
|
defmd1: ret # No mode chosen? Default 80x25
|
|
|
|
listm: call mode_table # List mode table
|
|
listm0: leaw name_bann, %si # Print adapter name
|
|
call prtstr
|
|
movw card_name, %si
|
|
orw %si, %si
|
|
jnz an2
|
|
|
|
movb adapter, %al
|
|
leaw old_name, %si
|
|
orb %al, %al
|
|
jz an1
|
|
|
|
leaw ega_name, %si
|
|
decb %al
|
|
jz an1
|
|
|
|
leaw vga_name, %si
|
|
jmp an1
|
|
|
|
an2: call prtstr
|
|
leaw svga_name, %si
|
|
an1: call prtstr
|
|
leaw listhdr, %si # Table header
|
|
call prtstr
|
|
movb $0x30, %dl # DL holds mode number
|
|
leaw modelist, %si
|
|
lm1: cmpw $ASK_VGA, (%si) # End?
|
|
jz lm2
|
|
|
|
movb %dl, %al # Menu selection number
|
|
call prtchr
|
|
call prtsp2
|
|
lodsw
|
|
call prthw # Mode ID
|
|
call prtsp2
|
|
movb 0x1(%si), %al
|
|
call prtdec # Rows
|
|
movb $0x78, %al # the letter 'x'
|
|
call prtchr
|
|
lodsw
|
|
call prtdec # Columns
|
|
movb $0x0d, %al # New line
|
|
call prtchr
|
|
movb $0x0a, %al
|
|
call prtchr
|
|
incb %dl # Next character
|
|
cmpb $0x3a, %dl
|
|
jnz lm1
|
|
|
|
movb $0x61, %dl
|
|
jmp lm1
|
|
|
|
lm2: leaw prompt, %si # Mode prompt
|
|
call prtstr
|
|
leaw edit_buf, %di # Editor buffer
|
|
lm3: call getkey
|
|
cmpb $0x0d, %al # Enter?
|
|
jz lment
|
|
|
|
cmpb $0x08, %al # Backspace?
|
|
jz lmbs
|
|
|
|
cmpb $0x20, %al # Printable?
|
|
jc lm3
|
|
|
|
cmpw $edit_buf+4, %di # Enough space?
|
|
jz lm3
|
|
|
|
stosb
|
|
call prtchr
|
|
jmp lm3
|
|
|
|
lmbs: cmpw $edit_buf, %di # Backspace
|
|
jz lm3
|
|
|
|
decw %di
|
|
movb $0x08, %al
|
|
call prtchr
|
|
call prtspc
|
|
movb $0x08, %al
|
|
call prtchr
|
|
jmp lm3
|
|
|
|
lment: movb $0, (%di)
|
|
leaw crlft, %si
|
|
call prtstr
|
|
leaw edit_buf, %si
|
|
cmpb $0, (%si) # Empty string = default mode
|
|
jz lmdef
|
|
|
|
cmpb $0, 1(%si) # One character = menu selection
|
|
jz mnusel
|
|
|
|
cmpw $0x6373, (%si) # "scan" => mode scanning
|
|
jnz lmhx
|
|
|
|
cmpw $0x6e61, 2(%si)
|
|
jz lmscan
|
|
|
|
lmhx: xorw %bx, %bx # Else => mode ID in hex
|
|
lmhex: lodsb
|
|
orb %al, %al
|
|
jz lmuse1
|
|
|
|
subb $0x30, %al
|
|
jc lmbad
|
|
|
|
cmpb $10, %al
|
|
jc lmhx1
|
|
|
|
subb $7, %al
|
|
andb $0xdf, %al
|
|
cmpb $10, %al
|
|
jc lmbad
|
|
|
|
cmpb $16, %al
|
|
jnc lmbad
|
|
|
|
lmhx1: shlw $4, %bx
|
|
orb %al, %bl
|
|
jmp lmhex
|
|
|
|
lmuse1: movw %bx, %ax
|
|
jmp lmuse
|
|
|
|
mnusel: lodsb # Menu selection
|
|
xorb %ah, %ah
|
|
subb $0x30, %al
|
|
jc lmbad
|
|
|
|
cmpb $10, %al
|
|
jc lmuse
|
|
|
|
cmpb $0x61-0x30, %al
|
|
jc lmbad
|
|
|
|
subb $0x61-0x30-10, %al
|
|
cmpb $36, %al
|
|
jnc lmbad
|
|
|
|
lmuse: call mode_set
|
|
jc lmdef
|
|
|
|
lmbad: leaw unknt, %si
|
|
call prtstr
|
|
jmp lm2
|
|
lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
|
|
jz lmbad
|
|
|
|
movw $0, mt_end # Scanning of modes is
|
|
movb $1, scanning # done as new autodetection.
|
|
call mode_table
|
|
jmp listm0
|
|
lmdef: ret
|
|
|
|
# Additional parts of mode_set... (relative jumps, you know)
|
|
setv7: # Video7 extended modes
|
|
DO_STORE
|
|
subb $VIDEO_FIRST_V7>>8, %bh
|
|
movw $0x6f05, %ax
|
|
int $0x10
|
|
stc
|
|
ret
|
|
|
|
_setrec: jmp setrec # Ugly...
|
|
_set_80x25: jmp set_80x25
|
|
|
|
# Aliases for backward compatibility.
|
|
setalias:
|
|
movw $VIDEO_80x25, %ax
|
|
incw %bx
|
|
jz mode_set
|
|
|
|
movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
|
|
incw %bx
|
|
jnz setbad # Fall-through!
|
|
|
|
# Setting of user mode (AX=mode ID) => CF=success
|
|
mode_set:
|
|
movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
|
|
movw %ax, %bx
|
|
cmpb $0xff, %ah
|
|
jz setalias
|
|
|
|
testb $VIDEO_RECALC>>8, %ah
|
|
jnz _setrec
|
|
|
|
cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
|
|
jnc setres
|
|
|
|
cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
|
|
jz setspc
|
|
|
|
cmpb $VIDEO_FIRST_V7>>8, %ah
|
|
jz setv7
|
|
|
|
cmpb $VIDEO_FIRST_VESA>>8, %ah
|
|
jnc check_vesa
|
|
|
|
orb %ah, %ah
|
|
jz setmenu
|
|
|
|
decb %ah
|
|
jz setbios
|
|
|
|
setbad: clc
|
|
movb $0, do_restore # The screen needn't be restored
|
|
ret
|
|
|
|
setvesa:
|
|
DO_STORE
|
|
subb $VIDEO_FIRST_VESA>>8, %bh
|
|
movw $0x4f02, %ax # VESA BIOS mode set call
|
|
int $0x10
|
|
cmpw $0x004f, %ax # AL=4f if implemented
|
|
jnz setbad # AH=0 if OK
|
|
|
|
stc
|
|
ret
|
|
|
|
setbios:
|
|
DO_STORE
|
|
int $0x10 # Standard BIOS mode set call
|
|
pushw %bx
|
|
movb $0x0f, %ah # Check if really set
|
|
int $0x10
|
|
popw %bx
|
|
cmpb %bl, %al
|
|
jnz setbad
|
|
|
|
stc
|
|
ret
|
|
|
|
setspc: xorb %bh, %bh # Set special mode
|
|
cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
|
|
jnc setbad
|
|
|
|
addw %bx, %bx
|
|
jmp *spec_inits(%bx)
|
|
|
|
setmenu:
|
|
orb %al, %al # 80x25 is an exception
|
|
jz _set_80x25
|
|
|
|
pushw %bx # Set mode chosen from menu
|
|
call mode_table # Build the mode table
|
|
popw %ax
|
|
shlw $2, %ax
|
|
addw %ax, %si
|
|
cmpw %di, %si
|
|
jnc setbad
|
|
|
|
movw (%si), %ax # Fetch mode ID
|
|
_m_s: jmp mode_set
|
|
|
|
setres: pushw %bx # Set mode chosen by resolution
|
|
call mode_table
|
|
popw %bx
|
|
xchgb %bl, %bh
|
|
setr1: lodsw
|
|
cmpw $ASK_VGA, %ax # End of the list?
|
|
jz setbad
|
|
|
|
lodsw
|
|
cmpw %bx, %ax
|
|
jnz setr1
|
|
|
|
movw -4(%si), %ax # Fetch mode ID
|
|
jmp _m_s
|
|
|
|
check_vesa:
|
|
leaw modelist+1024, %di
|
|
subb $VIDEO_FIRST_VESA>>8, %bh
|
|
movw %bx, %cx # Get mode information structure
|
|
movw $0x4f01, %ax
|
|
int $0x10
|
|
addb $VIDEO_FIRST_VESA>>8, %bh
|
|
cmpw $0x004f, %ax
|
|
jnz setbad
|
|
|
|
movb (%di), %al # Check capabilities.
|
|
andb $0x19, %al
|
|
cmpb $0x09, %al
|
|
jz setvesa # This is a text mode
|
|
|
|
movb (%di), %al # Check capabilities.
|
|
andb $0x99, %al
|
|
cmpb $0x99, %al
|
|
jnz _setbad # Doh! No linear frame buffer.
|
|
|
|
subb $VIDEO_FIRST_VESA>>8, %bh
|
|
orw $0x4000, %bx # Use linear frame buffer
|
|
movw $0x4f02, %ax # VESA BIOS mode set call
|
|
int $0x10
|
|
cmpw $0x004f, %ax # AL=4f if implemented
|
|
jnz _setbad # AH=0 if OK
|
|
|
|
movb $1, graphic_mode # flag graphic mode
|
|
movb $0, do_restore # no screen restore
|
|
stc
|
|
ret
|
|
|
|
_setbad: jmp setbad # Ugly...
|
|
|
|
# Recalculate vertical display end registers -- this fixes various
|
|
# inconsistencies of extended modes on many adapters. Called when
|
|
# the VIDEO_RECALC flag is set in the mode ID.
|
|
|
|
setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
|
|
call mode_set
|
|
jnc rct3
|
|
|
|
movw %gs:(0x485), %ax # Font size in pixels
|
|
movb %gs:(0x484), %bl # Number of rows
|
|
incb %bl
|
|
mulb %bl # Number of visible
|
|
decw %ax # scan lines - 1
|
|
movw $0x3d4, %dx
|
|
movw %ax, %bx
|
|
movb $0x12, %al # Lower 8 bits
|
|
movb %bl, %ah
|
|
outw %ax, %dx
|
|
movb $0x07, %al # Bits 8 and 9 in the overflow register
|
|
call inidx
|
|
xchgb %al, %ah
|
|
andb $0xbd, %ah
|
|
shrb %bh
|
|
jnc rct1
|
|
orb $0x02, %ah
|
|
rct1: shrb %bh
|
|
jnc rct2
|
|
orb $0x40, %ah
|
|
rct2: movb $0x07, %al
|
|
outw %ax, %dx
|
|
stc
|
|
rct3: ret
|
|
|
|
# Table of routines for setting of the special modes.
|
|
spec_inits:
|
|
.word set_80x25
|
|
.word set_8pixel
|
|
.word set_80x43
|
|
.word set_80x28
|
|
.word set_current
|
|
.word set_80x30
|
|
.word set_80x34
|
|
.word set_80x60
|
|
.word set_gfx
|
|
|
|
# Set the 80x25 mode. If already set, do nothing.
|
|
set_80x25:
|
|
movw $0x5019, force_size # Override possibly broken BIOS
|
|
use_80x25:
|
|
#ifdef CONFIG_VIDEO_400_HACK
|
|
movw $0x1202, %ax # Force 400 scan lines
|
|
movb $0x30, %bl
|
|
int $0x10
|
|
#else
|
|
movb $0x0f, %ah # Get current mode ID
|
|
int $0x10
|
|
cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
|
|
jz st80 # on CGA/MDA/HGA and is also available on EGAM
|
|
|
|
cmpw $0x5003, %ax # Unknown mode, force 80x25 color
|
|
jnz force3
|
|
|
|
st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
|
|
jz set80
|
|
|
|
movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
|
|
orb %al, %al # Some buggy BIOS'es set 0 rows
|
|
jz set80
|
|
|
|
cmpb $24, %al # It's hopefully correct
|
|
jz set80
|
|
#endif /* CONFIG_VIDEO_400_HACK */
|
|
force3: DO_STORE
|
|
movw $0x0003, %ax # Forced set
|
|
int $0x10
|
|
set80: stc
|
|
ret
|
|
|
|
# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
|
|
set_8pixel:
|
|
DO_STORE
|
|
call use_80x25 # The base is 80x25
|
|
set_8pt:
|
|
movw $0x1112, %ax # Use 8x8 font
|
|
xorb %bl, %bl
|
|
int $0x10
|
|
movw $0x1200, %ax # Use alternate print screen
|
|
movb $0x20, %bl
|
|
int $0x10
|
|
movw $0x1201, %ax # Turn off cursor emulation
|
|
movb $0x34, %bl
|
|
int $0x10
|
|
movb $0x01, %ah # Define cursor scan lines 6-7
|
|
movw $0x0607, %cx
|
|
int $0x10
|
|
set_current:
|
|
stc
|
|
ret
|
|
|
|
# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
|
|
# 80x25 mode with 14-point fonts instead of 16-point.
|
|
set_80x28:
|
|
DO_STORE
|
|
call use_80x25 # The base is 80x25
|
|
set14: movw $0x1111, %ax # Use 9x14 font
|
|
xorb %bl, %bl
|
|
int $0x10
|
|
movb $0x01, %ah # Define cursor scan lines 11-12
|
|
movw $0x0b0c, %cx
|
|
int $0x10
|
|
stc
|
|
ret
|
|
|
|
# Set the 80x43 mode. This mode is works on all VGA's.
|
|
# It's a 350-scanline mode with 8-pixel font.
|
|
set_80x43:
|
|
DO_STORE
|
|
movw $0x1201, %ax # Set 350 scans
|
|
movb $0x30, %bl
|
|
int $0x10
|
|
movw $0x0003, %ax # Reset video mode
|
|
int $0x10
|
|
jmp set_8pt # Use 8-pixel font
|
|
|
|
# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
|
|
set_80x30:
|
|
call use_80x25 # Start with real 80x25
|
|
DO_STORE
|
|
movw $0x3cc, %dx # Get CRTC port
|
|
inb %dx, %al
|
|
movb $0xd4, %dl
|
|
rorb %al # Mono or color?
|
|
jc set48a
|
|
|
|
movb $0xb4, %dl
|
|
set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
|
|
call outidx
|
|
movw $0x0b06, %ax # Vertical total
|
|
call outidx
|
|
movw $0x3e07, %ax # (Vertical) overflow
|
|
call outidx
|
|
movw $0xea10, %ax # Vertical sync start
|
|
call outidx
|
|
movw $0xdf12, %ax # Vertical display end
|
|
call outidx
|
|
movw $0xe715, %ax # Vertical blank start
|
|
call outidx
|
|
movw $0x0416, %ax # Vertical blank end
|
|
call outidx
|
|
pushw %dx
|
|
movb $0xcc, %dl # Misc output register (read)
|
|
inb %dx, %al
|
|
movb $0xc2, %dl # (write)
|
|
andb $0x0d, %al # Preserve clock select bits and color bit
|
|
orb $0xe2, %al # Set correct sync polarity
|
|
outb %al, %dx
|
|
popw %dx
|
|
movw $0x501e, force_size
|
|
stc # That's all.
|
|
ret
|
|
|
|
# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
|
|
set_80x34:
|
|
call set_80x30 # Set 480 scans
|
|
call set14 # And 14-pt font
|
|
movw $0xdb12, %ax # VGA vertical display end
|
|
movw $0x5022, force_size
|
|
setvde: call outidx
|
|
stc
|
|
ret
|
|
|
|
# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
|
|
set_80x60:
|
|
call set_80x30 # Set 480 scans
|
|
call set_8pt # And 8-pt font
|
|
movw $0xdf12, %ax # VGA vertical display end
|
|
movw $0x503c, force_size
|
|
jmp setvde
|
|
|
|
# Special hack for ThinkPad graphics
|
|
set_gfx:
|
|
#ifdef CONFIG_VIDEO_GFX_HACK
|
|
movw $VIDEO_GFX_BIOS_AX, %ax
|
|
movw $VIDEO_GFX_BIOS_BX, %bx
|
|
int $0x10
|
|
movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
|
|
stc
|
|
#endif
|
|
ret
|
|
|
|
#ifdef CONFIG_VIDEO_RETAIN
|
|
|
|
# Store screen contents to temporary buffer.
|
|
store_screen:
|
|
cmpb $0, do_restore # Already stored?
|
|
jnz stsr
|
|
|
|
testb $CAN_USE_HEAP, loadflags # Have we space for storing?
|
|
jz stsr
|
|
|
|
pushw %ax
|
|
pushw %bx
|
|
pushw force_size # Don't force specific size
|
|
movw $0, force_size
|
|
call mode_params # Obtain params of current mode
|
|
popw force_size
|
|
movb %fs:(PARAM_VIDEO_LINES), %ah
|
|
movb %fs:(PARAM_VIDEO_COLS), %al
|
|
movw %ax, %bx # BX=dimensions
|
|
mulb %ah
|
|
movw %ax, %cx # CX=number of characters
|
|
addw %ax, %ax # Calculate image size
|
|
addw $modelist+1024+4, %ax
|
|
cmpw heap_end_ptr, %ax
|
|
jnc sts1 # Unfortunately, out of memory
|
|
|
|
movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
|
|
leaw modelist+1024, %di
|
|
stosw
|
|
movw %bx, %ax
|
|
stosw
|
|
pushw %ds # Store the screen
|
|
movw video_segment, %ds
|
|
xorw %si, %si
|
|
rep
|
|
movsw
|
|
popw %ds
|
|
incb do_restore # Screen will be restored later
|
|
sts1: popw %bx
|
|
popw %ax
|
|
stsr: ret
|
|
|
|
# Restore screen contents from temporary buffer.
|
|
restore_screen:
|
|
cmpb $0, do_restore # Has the screen been stored?
|
|
jz res1
|
|
|
|
call mode_params # Get parameters of current mode
|
|
movb %fs:(PARAM_VIDEO_LINES), %cl
|
|
movb %fs:(PARAM_VIDEO_COLS), %ch
|
|
leaw modelist+1024, %si # Screen buffer
|
|
lodsw # Set cursor position
|
|
movw %ax, %dx
|
|
cmpb %cl, %dh
|
|
jc res2
|
|
|
|
movb %cl, %dh
|
|
decb %dh
|
|
res2: cmpb %ch, %dl
|
|
jc res3
|
|
|
|
movb %ch, %dl
|
|
decb %dl
|
|
res3: movb $0x02, %ah
|
|
movb $0x00, %bh
|
|
int $0x10
|
|
lodsw # Display size
|
|
movb %ah, %dl # DL=number of lines
|
|
movb $0, %ah # BX=phys. length of orig. line
|
|
movw %ax, %bx
|
|
cmpb %cl, %dl # Too many?
|
|
jc res4
|
|
|
|
pushw %ax
|
|
movb %dl, %al
|
|
subb %cl, %al
|
|
mulb %bl
|
|
addw %ax, %si
|
|
addw %ax, %si
|
|
popw %ax
|
|
movb %cl, %dl
|
|
res4: cmpb %ch, %al # Too wide?
|
|
jc res5
|
|
|
|
movb %ch, %al # AX=width of src. line
|
|
res5: movb $0, %cl
|
|
xchgb %ch, %cl
|
|
movw %cx, %bp # BP=width of dest. line
|
|
pushw %es
|
|
movw video_segment, %es
|
|
xorw %di, %di # Move the data
|
|
addw %bx, %bx # Convert BX and BP to _bytes_
|
|
addw %bp, %bp
|
|
res6: pushw %si
|
|
pushw %di
|
|
movw %ax, %cx
|
|
rep
|
|
movsw
|
|
popw %di
|
|
popw %si
|
|
addw %bp, %di
|
|
addw %bx, %si
|
|
decb %dl
|
|
jnz res6
|
|
|
|
popw %es # Done
|
|
res1: ret
|
|
#endif /* CONFIG_VIDEO_RETAIN */
|
|
|
|
# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
|
|
outidx: outb %al, %dx
|
|
pushw %ax
|
|
movb %ah, %al
|
|
incw %dx
|
|
outb %al, %dx
|
|
decw %dx
|
|
popw %ax
|
|
ret
|
|
|
|
# Build the table of video modes (stored after the setup.S code at the
|
|
# `modelist' label. Each video mode record looks like:
|
|
# .word MODE-ID (our special mode ID (see above))
|
|
# .byte rows (number of rows)
|
|
# .byte columns (number of columns)
|
|
# Returns address of the end of the table in DI, the end is marked
|
|
# with a ASK_VGA ID.
|
|
mode_table:
|
|
movw mt_end, %di # Already filled?
|
|
orw %di, %di
|
|
jnz mtab1x
|
|
|
|
leaw modelist, %di # Store standard modes:
|
|
movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
|
|
stosl
|
|
movb adapter, %al # CGA/MDA/HGA -- no more modes
|
|
orb %al, %al
|
|
jz mtabe
|
|
|
|
decb %al
|
|
jnz mtabv
|
|
|
|
movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
|
|
stosl
|
|
jmp mtabe
|
|
|
|
mtab1x: jmp mtab1
|
|
|
|
mtabv: leaw vga_modes, %si # All modes for std VGA
|
|
movw $vga_modes_end-vga_modes, %cx
|
|
rep # I'm unable to use movsw as I don't know how to store a half
|
|
movsb # of the expression above to cx without using explicit shr.
|
|
|
|
cmpb $0, scanning # Mode scan requested?
|
|
jz mscan1
|
|
|
|
call mode_scan
|
|
mscan1:
|
|
|
|
#ifdef CONFIG_VIDEO_LOCAL
|
|
call local_modes
|
|
#endif /* CONFIG_VIDEO_LOCAL */
|
|
|
|
#ifdef CONFIG_VIDEO_VESA
|
|
call vesa_modes # Detect VESA VGA modes
|
|
#endif /* CONFIG_VIDEO_VESA */
|
|
|
|
#ifdef CONFIG_VIDEO_SVGA
|
|
cmpb $0, scanning # Bypass when scanning
|
|
jnz mscan2
|
|
|
|
call svga_modes # Detect SVGA cards & modes
|
|
mscan2:
|
|
#endif /* CONFIG_VIDEO_SVGA */
|
|
|
|
mtabe:
|
|
|
|
#ifdef CONFIG_VIDEO_COMPACT
|
|
leaw modelist, %si
|
|
movw %di, %dx
|
|
movw %si, %di
|
|
cmt1: cmpw %dx, %si # Scan all modes
|
|
jz cmt2
|
|
|
|
leaw modelist, %bx # Find in previous entries
|
|
movw 2(%si), %cx
|
|
cmt3: cmpw %bx, %si
|
|
jz cmt4
|
|
|
|
cmpw 2(%bx), %cx # Found => don't copy this entry
|
|
jz cmt5
|
|
|
|
addw $4, %bx
|
|
jmp cmt3
|
|
|
|
cmt4: movsl # Copy entry
|
|
jmp cmt1
|
|
|
|
cmt5: addw $4, %si # Skip entry
|
|
jmp cmt1
|
|
|
|
cmt2:
|
|
#endif /* CONFIG_VIDEO_COMPACT */
|
|
|
|
movw $ASK_VGA, (%di) # End marker
|
|
movw %di, mt_end
|
|
mtab1: leaw modelist, %si # SI=mode list, DI=list end
|
|
ret0: ret
|
|
|
|
# Modes usable on all standard VGAs
|
|
vga_modes:
|
|
.word VIDEO_8POINT
|
|
.word 0x5032 # 80x50
|
|
.word VIDEO_80x43
|
|
.word 0x502b # 80x43
|
|
.word VIDEO_80x28
|
|
.word 0x501c # 80x28
|
|
.word VIDEO_80x30
|
|
.word 0x501e # 80x30
|
|
.word VIDEO_80x34
|
|
.word 0x5022 # 80x34
|
|
.word VIDEO_80x60
|
|
.word 0x503c # 80x60
|
|
#ifdef CONFIG_VIDEO_GFX_HACK
|
|
.word VIDEO_GFX_HACK
|
|
.word VIDEO_GFX_DUMMY_RESOLUTION
|
|
#endif
|
|
|
|
vga_modes_end:
|
|
# Detect VESA modes.
|
|
|
|
#ifdef CONFIG_VIDEO_VESA
|
|
vesa_modes:
|
|
cmpb $2, adapter # VGA only
|
|
jnz ret0
|
|
|
|
movw %di, %bp # BP=original mode table end
|
|
addw $0x200, %di # Buffer space
|
|
movw $0x4f00, %ax # VESA Get card info call
|
|
int $0x10
|
|
movw %bp, %di
|
|
cmpw $0x004f, %ax # Successful?
|
|
jnz ret0
|
|
|
|
cmpw $0x4556, 0x200(%di)
|
|
jnz ret0
|
|
|
|
cmpw $0x4153, 0x202(%di)
|
|
jnz ret0
|
|
|
|
movw $vesa_name, card_name # Set name to "VESA VGA"
|
|
pushw %gs
|
|
lgsw 0x20e(%di), %si # GS:SI=mode list
|
|
movw $128, %cx # Iteration limit
|
|
vesa1:
|
|
# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
|
|
# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
|
|
gs; lodsw
|
|
cmpw $0xffff, %ax # End of the table?
|
|
jz vesar
|
|
|
|
cmpw $0x0080, %ax # Check validity of mode ID
|
|
jc vesa2
|
|
|
|
orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
|
|
jz vesan # Certain BIOSes report 0x80-0xff!
|
|
|
|
cmpw $0x0800, %ax
|
|
jnc vesae
|
|
|
|
vesa2: pushw %cx
|
|
movw %ax, %cx # Get mode information structure
|
|
movw $0x4f01, %ax
|
|
int $0x10
|
|
movw %cx, %bx # BX=mode number
|
|
addb $VIDEO_FIRST_VESA>>8, %bh
|
|
popw %cx
|
|
cmpw $0x004f, %ax
|
|
jnz vesan # Don't report errors (buggy BIOSES)
|
|
|
|
movb (%di), %al # Check capabilities. We require
|
|
andb $0x19, %al # a color text mode.
|
|
cmpb $0x09, %al
|
|
jnz vesan
|
|
|
|
cmpw $0xb800, 8(%di) # Standard video memory address required
|
|
jnz vesan
|
|
|
|
testb $2, (%di) # Mode characteristics supplied?
|
|
movw %bx, (%di) # Store mode number
|
|
jz vesa3
|
|
|
|
xorw %dx, %dx
|
|
movw 0x12(%di), %bx # Width
|
|
orb %bh, %bh
|
|
jnz vesan
|
|
|
|
movb %bl, 0x3(%di)
|
|
movw 0x14(%di), %ax # Height
|
|
orb %ah, %ah
|
|
jnz vesan
|
|
|
|
movb %al, 2(%di)
|
|
mulb %bl
|
|
cmpw $8193, %ax # Small enough for Linux console driver?
|
|
jnc vesan
|
|
|
|
jmp vesaok
|
|
|
|
vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
|
|
jc vesan # so it must be a standard VESA mode.
|
|
|
|
cmpw $5, %bx
|
|
jnc vesan
|
|
|
|
movw vesa_text_mode_table(%bx), %ax
|
|
movw %ax, 2(%di)
|
|
vesaok: addw $4, %di # The mode is valid. Store it.
|
|
vesan: loop vesa1 # Next mode. Limit exceeded => error
|
|
vesae: leaw vesaer, %si
|
|
call prtstr
|
|
movw %bp, %di # Discard already found modes.
|
|
vesar: popw %gs
|
|
ret
|
|
|
|
# Dimensions of standard VESA text modes
|
|
vesa_text_mode_table:
|
|
.byte 60, 80 # 0108
|
|
.byte 25, 132 # 0109
|
|
.byte 43, 132 # 010A
|
|
.byte 50, 132 # 010B
|
|
.byte 60, 132 # 010C
|
|
#endif /* CONFIG_VIDEO_VESA */
|
|
|
|
# Scan for video modes. A bit dirty, but should work.
|
|
mode_scan:
|
|
movw $0x0100, %cx # Start with mode 0
|
|
scm1: movb $0, %ah # Test the mode
|
|
movb %cl, %al
|
|
int $0x10
|
|
movb $0x0f, %ah
|
|
int $0x10
|
|
cmpb %cl, %al
|
|
jnz scm2 # Mode not set
|
|
|
|
movw $0x3c0, %dx # Test if it's a text mode
|
|
movb $0x10, %al # Mode bits
|
|
call inidx
|
|
andb $0x03, %al
|
|
jnz scm2
|
|
|
|
movb $0xce, %dl # Another set of mode bits
|
|
movb $0x06, %al
|
|
call inidx
|
|
shrb %al
|
|
jc scm2
|
|
|
|
movb $0xd4, %dl # Cursor location
|
|
movb $0x0f, %al
|
|
call inidx
|
|
orb %al, %al
|
|
jnz scm2
|
|
|
|
movw %cx, %ax # Ok, store the mode
|
|
stosw
|
|
movb %gs:(0x484), %al # Number of rows
|
|
incb %al
|
|
stosb
|
|
movw %gs:(0x44a), %ax # Number of columns
|
|
stosb
|
|
scm2: incb %cl
|
|
jns scm1
|
|
|
|
movw $0x0003, %ax # Return back to mode 3
|
|
int $0x10
|
|
ret
|
|
|
|
tstidx: outw %ax, %dx # OUT DX,AX and inidx
|
|
inidx: outb %al, %dx # Read from indexed VGA register
|
|
incw %dx # AL=index, DX=index reg port -> AL=data
|
|
inb %dx, %al
|
|
decw %dx
|
|
ret
|
|
|
|
# Try to detect type of SVGA card and supply (usually approximate) video
|
|
# mode table for it.
|
|
|
|
#ifdef CONFIG_VIDEO_SVGA
|
|
svga_modes:
|
|
leaw svga_table, %si # Test all known SVGA adapters
|
|
dosvga: lodsw
|
|
movw %ax, %bp # Default mode table
|
|
orw %ax, %ax
|
|
jz didsv1
|
|
|
|
lodsw # Pointer to test routine
|
|
pushw %si
|
|
pushw %di
|
|
pushw %es
|
|
movw $0xc000, %bx
|
|
movw %bx, %es
|
|
call *%ax # Call test routine
|
|
popw %es
|
|
popw %di
|
|
popw %si
|
|
orw %bp, %bp
|
|
jz dosvga
|
|
|
|
movw %bp, %si # Found, copy the modes
|
|
movb svga_prefix, %ah
|
|
cpsvga: lodsb
|
|
orb %al, %al
|
|
jz didsv
|
|
|
|
stosw
|
|
movsw
|
|
jmp cpsvga
|
|
|
|
didsv: movw %si, card_name # Store pointer to card name
|
|
didsv1: ret
|
|
|
|
# Table of all known SVGA cards. For each card, we store a pointer to
|
|
# a table of video modes supported by the card and a pointer to a routine
|
|
# used for testing of presence of the card. The video mode table is always
|
|
# followed by the name of the card or the chipset.
|
|
svga_table:
|
|
.word ati_md, ati_test
|
|
.word oak_md, oak_test
|
|
.word paradise_md, paradise_test
|
|
.word realtek_md, realtek_test
|
|
.word s3_md, s3_test
|
|
.word chips_md, chips_test
|
|
.word video7_md, video7_test
|
|
.word cirrus5_md, cirrus5_test
|
|
.word cirrus6_md, cirrus6_test
|
|
.word cirrus1_md, cirrus1_test
|
|
.word ahead_md, ahead_test
|
|
.word everex_md, everex_test
|
|
.word genoa_md, genoa_test
|
|
.word trident_md, trident_test
|
|
.word tseng_md, tseng_test
|
|
.word 0
|
|
|
|
# Test routines and mode tables:
|
|
|
|
# S3 - The test algorithm was taken from the SuperProbe package
|
|
# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
|
|
s3_test:
|
|
movw $0x0f35, %cx # we store some constants in cl/ch
|
|
movw $0x03d4, %dx
|
|
movb $0x38, %al
|
|
call inidx
|
|
movb %al, %bh # store current CRT-register 0x38
|
|
movw $0x0038, %ax
|
|
call outidx # disable writing to special regs
|
|
movb %cl, %al # check whether we can write special reg 0x35
|
|
call inidx
|
|
movb %al, %bl # save the current value of CRT reg 0x35
|
|
andb $0xf0, %al # clear bits 0-3
|
|
movb %al, %ah
|
|
movb %cl, %al # and write it to CRT reg 0x35
|
|
call outidx
|
|
call inidx # now read it back
|
|
andb %ch, %al # clear the upper 4 bits
|
|
jz s3_2 # the first test failed. But we have a
|
|
|
|
movb %bl, %ah # second chance
|
|
movb %cl, %al
|
|
call outidx
|
|
jmp s3_1 # do the other tests
|
|
|
|
s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
|
|
orb %bl, %ah # set the upper 4 bits of ah with the orig value
|
|
call outidx # write ...
|
|
call inidx # ... and reread
|
|
andb %cl, %al # turn off the upper 4 bits
|
|
pushw %ax
|
|
movb %bl, %ah # restore old value in register 0x35
|
|
movb %cl, %al
|
|
call outidx
|
|
popw %ax
|
|
cmpb %ch, %al # setting lower 4 bits was successful => bad
|
|
je no_s3 # writing is allowed => this is not an S3
|
|
|
|
s3_1: movw $0x4838, %ax # allow writing to special regs by putting
|
|
call outidx # magic number into CRT-register 0x38
|
|
movb %cl, %al # check whether we can write special reg 0x35
|
|
call inidx
|
|
movb %al, %bl
|
|
andb $0xf0, %al
|
|
movb %al, %ah
|
|
movb %cl, %al
|
|
call outidx
|
|
call inidx
|
|
andb %ch, %al
|
|
jnz no_s3 # no, we can't write => no S3
|
|
|
|
movw %cx, %ax
|
|
orb %bl, %ah
|
|
call outidx
|
|
call inidx
|
|
andb %ch, %al
|
|
pushw %ax
|
|
movb %bl, %ah # restore old value in register 0x35
|
|
movb %cl, %al
|
|
call outidx
|
|
popw %ax
|
|
cmpb %ch, %al
|
|
jne no_s31 # writing not possible => no S3
|
|
movb $0x30, %al
|
|
call inidx # now get the S3 id ...
|
|
leaw idS3, %di
|
|
movw $0x10, %cx
|
|
repne
|
|
scasb
|
|
je no_s31
|
|
|
|
movb %bh, %ah
|
|
movb $0x38, %al
|
|
jmp s3rest
|
|
|
|
no_s3: movb $0x35, %al # restore CRT register 0x35
|
|
movb %bl, %ah
|
|
call outidx
|
|
no_s31: xorw %bp, %bp # Detection failed
|
|
s3rest: movb %bh, %ah
|
|
movb $0x38, %al # restore old value of CRT register 0x38
|
|
jmp outidx
|
|
|
|
idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
|
|
.byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
|
|
|
|
s3_md: .byte 0x54, 0x2b, 0x84
|
|
.byte 0x55, 0x19, 0x84
|
|
.byte 0
|
|
.ascii "S3"
|
|
.byte 0
|
|
|
|
# ATI cards.
|
|
ati_test:
|
|
leaw idati, %si
|
|
movw $0x31, %di
|
|
movw $0x09, %cx
|
|
repe
|
|
cmpsb
|
|
je atiok
|
|
|
|
xorw %bp, %bp
|
|
atiok: ret
|
|
|
|
idati: .ascii "761295520"
|
|
|
|
ati_md: .byte 0x23, 0x19, 0x84
|
|
.byte 0x33, 0x2c, 0x84
|
|
.byte 0x22, 0x1e, 0x64
|
|
.byte 0x21, 0x19, 0x64
|
|
.byte 0x58, 0x21, 0x50
|
|
.byte 0x5b, 0x1e, 0x50
|
|
.byte 0
|
|
.ascii "ATI"
|
|
.byte 0
|
|
|
|
# AHEAD
|
|
ahead_test:
|
|
movw $0x200f, %ax
|
|
movw $0x3ce, %dx
|
|
outw %ax, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
cmpb $0x20, %al
|
|
je isahed
|
|
|
|
cmpb $0x21, %al
|
|
je isahed
|
|
|
|
xorw %bp, %bp
|
|
isahed: ret
|
|
|
|
ahead_md:
|
|
.byte 0x22, 0x2c, 0x84
|
|
.byte 0x23, 0x19, 0x84
|
|
.byte 0x24, 0x1c, 0x84
|
|
.byte 0x2f, 0x32, 0xa0
|
|
.byte 0x32, 0x22, 0x50
|
|
.byte 0x34, 0x42, 0x50
|
|
.byte 0
|
|
.ascii "Ahead"
|
|
.byte 0
|
|
|
|
# Chips & Tech.
|
|
chips_test:
|
|
movw $0x3c3, %dx
|
|
inb %dx, %al
|
|
orb $0x10, %al
|
|
outb %al, %dx
|
|
movw $0x104, %dx
|
|
inb %dx, %al
|
|
movb %al, %bl
|
|
movw $0x3c3, %dx
|
|
inb %dx, %al
|
|
andb $0xef, %al
|
|
outb %al, %dx
|
|
cmpb $0xa5, %bl
|
|
je cantok
|
|
|
|
xorw %bp, %bp
|
|
cantok: ret
|
|
|
|
chips_md:
|
|
.byte 0x60, 0x19, 0x84
|
|
.byte 0x61, 0x32, 0x84
|
|
.byte 0
|
|
.ascii "Chips & Technologies"
|
|
.byte 0
|
|
|
|
# Cirrus Logic 5X0
|
|
cirrus1_test:
|
|
movw $0x3d4, %dx
|
|
movb $0x0c, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
movb %al, %bl
|
|
xorb %al, %al
|
|
outb %al, %dx
|
|
decw %dx
|
|
movb $0x1f, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
movb %al, %bh
|
|
xorb %ah, %ah
|
|
shlb $4, %al
|
|
movw %ax, %cx
|
|
movb %bh, %al
|
|
shrb $4, %al
|
|
addw %ax, %cx
|
|
shlw $8, %cx
|
|
addw $6, %cx
|
|
movw %cx, %ax
|
|
movw $0x3c4, %dx
|
|
outw %ax, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
andb %al, %al
|
|
jnz nocirr
|
|
|
|
movb %bh, %al
|
|
outb %al, %dx
|
|
inb %dx, %al
|
|
cmpb $0x01, %al
|
|
je iscirr
|
|
|
|
nocirr: xorw %bp, %bp
|
|
iscirr: movw $0x3d4, %dx
|
|
movb %bl, %al
|
|
xorb %ah, %ah
|
|
shlw $8, %ax
|
|
addw $0x0c, %ax
|
|
outw %ax, %dx
|
|
ret
|
|
|
|
cirrus1_md:
|
|
.byte 0x1f, 0x19, 0x84
|
|
.byte 0x20, 0x2c, 0x84
|
|
.byte 0x22, 0x1e, 0x84
|
|
.byte 0x31, 0x25, 0x64
|
|
.byte 0
|
|
.ascii "Cirrus Logic 5X0"
|
|
.byte 0
|
|
|
|
# Cirrus Logic 54XX
|
|
cirrus5_test:
|
|
movw $0x3c4, %dx
|
|
movb $6, %al
|
|
call inidx
|
|
movb %al, %bl # BL=backup
|
|
movw $6, %ax
|
|
call tstidx
|
|
cmpb $0x0f, %al
|
|
jne c5fail
|
|
|
|
movw $0x1206, %ax
|
|
call tstidx
|
|
cmpb $0x12, %al
|
|
jne c5fail
|
|
|
|
movb $0x1e, %al
|
|
call inidx
|
|
movb %al, %bh
|
|
movb %bh, %ah
|
|
andb $0xc0, %ah
|
|
movb $0x1e, %al
|
|
call tstidx
|
|
andb $0x3f, %al
|
|
jne c5xx
|
|
|
|
movb $0x1e, %al
|
|
movb %bh, %ah
|
|
orb $0x3f, %ah
|
|
call tstidx
|
|
xorb $0x3f, %al
|
|
andb $0x3f, %al
|
|
c5xx: pushf
|
|
movb $0x1e, %al
|
|
movb %bh, %ah
|
|
outw %ax, %dx
|
|
popf
|
|
je c5done
|
|
|
|
c5fail: xorw %bp, %bp
|
|
c5done: movb $6, %al
|
|
movb %bl, %ah
|
|
outw %ax, %dx
|
|
ret
|
|
|
|
cirrus5_md:
|
|
.byte 0x14, 0x19, 0x84
|
|
.byte 0x54, 0x2b, 0x84
|
|
.byte 0
|
|
.ascii "Cirrus Logic 54XX"
|
|
.byte 0
|
|
|
|
# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
|
|
# it's misidentified by the Ahead test.
|
|
cirrus6_test:
|
|
movw $0x3ce, %dx
|
|
movb $0x0a, %al
|
|
call inidx
|
|
movb %al, %bl # BL=backup
|
|
movw $0xce0a, %ax
|
|
call tstidx
|
|
orb %al, %al
|
|
jne c2fail
|
|
|
|
movw $0xec0a, %ax
|
|
call tstidx
|
|
cmpb $0x01, %al
|
|
jne c2fail
|
|
|
|
movb $0xaa, %al
|
|
call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
|
|
shrb $4, %al
|
|
subb $4, %al
|
|
jz c6done
|
|
|
|
decb %al
|
|
jz c6done
|
|
|
|
subb $2, %al
|
|
jz c6done
|
|
|
|
decb %al
|
|
jz c6done
|
|
|
|
c2fail: xorw %bp, %bp
|
|
c6done: movb $0x0a, %al
|
|
movb %bl, %ah
|
|
outw %ax, %dx
|
|
ret
|
|
|
|
cirrus6_md:
|
|
.byte 0
|
|
.ascii "Cirrus Logic 64XX"
|
|
.byte 0
|
|
|
|
# Everex / Trident
|
|
everex_test:
|
|
movw $0x7000, %ax
|
|
xorw %bx, %bx
|
|
int $0x10
|
|
cmpb $0x70, %al
|
|
jne noevrx
|
|
|
|
shrw $4, %dx
|
|
cmpw $0x678, %dx
|
|
je evtrid
|
|
|
|
cmpw $0x236, %dx
|
|
jne evrxok
|
|
|
|
evtrid: leaw trident_md, %bp
|
|
evrxok: ret
|
|
|
|
noevrx: xorw %bp, %bp
|
|
ret
|
|
|
|
everex_md:
|
|
.byte 0x03, 0x22, 0x50
|
|
.byte 0x04, 0x3c, 0x50
|
|
.byte 0x07, 0x2b, 0x64
|
|
.byte 0x08, 0x4b, 0x64
|
|
.byte 0x0a, 0x19, 0x84
|
|
.byte 0x0b, 0x2c, 0x84
|
|
.byte 0x16, 0x1e, 0x50
|
|
.byte 0x18, 0x1b, 0x64
|
|
.byte 0x21, 0x40, 0xa0
|
|
.byte 0x40, 0x1e, 0x84
|
|
.byte 0
|
|
.ascii "Everex/Trident"
|
|
.byte 0
|
|
|
|
# Genoa.
|
|
genoa_test:
|
|
leaw idgenoa, %si # Check Genoa 'clues'
|
|
xorw %ax, %ax
|
|
movb %es:(0x37), %al
|
|
movw %ax, %di
|
|
movw $0x04, %cx
|
|
decw %si
|
|
decw %di
|
|
l1: incw %si
|
|
incw %di
|
|
movb (%si), %al
|
|
testb %al, %al
|
|
jz l2
|
|
|
|
cmpb %es:(%di), %al
|
|
l2: loope l1
|
|
orw %cx, %cx
|
|
je isgen
|
|
|
|
xorw %bp, %bp
|
|
isgen: ret
|
|
|
|
idgenoa: .byte 0x77, 0x00, 0x99, 0x66
|
|
|
|
genoa_md:
|
|
.byte 0x58, 0x20, 0x50
|
|
.byte 0x5a, 0x2a, 0x64
|
|
.byte 0x60, 0x19, 0x84
|
|
.byte 0x61, 0x1d, 0x84
|
|
.byte 0x62, 0x20, 0x84
|
|
.byte 0x63, 0x2c, 0x84
|
|
.byte 0x64, 0x3c, 0x84
|
|
.byte 0x6b, 0x4f, 0x64
|
|
.byte 0x72, 0x3c, 0x50
|
|
.byte 0x74, 0x42, 0x50
|
|
.byte 0x78, 0x4b, 0x64
|
|
.byte 0
|
|
.ascii "Genoa"
|
|
.byte 0
|
|
|
|
# OAK
|
|
oak_test:
|
|
leaw idoakvga, %si
|
|
movw $0x08, %di
|
|
movw $0x08, %cx
|
|
repe
|
|
cmpsb
|
|
je isoak
|
|
|
|
xorw %bp, %bp
|
|
isoak: ret
|
|
|
|
idoakvga: .ascii "OAK VGA "
|
|
|
|
oak_md: .byte 0x4e, 0x3c, 0x50
|
|
.byte 0x4f, 0x3c, 0x84
|
|
.byte 0x50, 0x19, 0x84
|
|
.byte 0x51, 0x2b, 0x84
|
|
.byte 0
|
|
.ascii "OAK"
|
|
.byte 0
|
|
|
|
# WD Paradise.
|
|
paradise_test:
|
|
leaw idparadise, %si
|
|
movw $0x7d, %di
|
|
movw $0x04, %cx
|
|
repe
|
|
cmpsb
|
|
je ispara
|
|
|
|
xorw %bp, %bp
|
|
ispara: ret
|
|
|
|
idparadise: .ascii "VGA="
|
|
|
|
paradise_md:
|
|
.byte 0x41, 0x22, 0x50
|
|
.byte 0x47, 0x1c, 0x84
|
|
.byte 0x55, 0x19, 0x84
|
|
.byte 0x54, 0x2c, 0x84
|
|
.byte 0
|
|
.ascii "Paradise"
|
|
.byte 0
|
|
|
|
# Trident.
|
|
trident_test:
|
|
movw $0x3c4, %dx
|
|
movb $0x0e, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
xchgb %al, %ah
|
|
xorb %al, %al
|
|
outb %al, %dx
|
|
inb %dx, %al
|
|
xchgb %ah, %al
|
|
movb %al, %bl # Strange thing ... in the book this wasn't
|
|
andb $0x02, %bl # necessary but it worked on my card which
|
|
jz setb2 # is a trident. Without it the screen goes
|
|
# blurred ...
|
|
andb $0xfd, %al
|
|
jmp clrb2
|
|
|
|
setb2: orb $0x02, %al
|
|
clrb2: outb %al, %dx
|
|
andb $0x0f, %ah
|
|
cmpb $0x02, %ah
|
|
je istrid
|
|
|
|
xorw %bp, %bp
|
|
istrid: ret
|
|
|
|
trident_md:
|
|
.byte 0x50, 0x1e, 0x50
|
|
.byte 0x51, 0x2b, 0x50
|
|
.byte 0x52, 0x3c, 0x50
|
|
.byte 0x57, 0x19, 0x84
|
|
.byte 0x58, 0x1e, 0x84
|
|
.byte 0x59, 0x2b, 0x84
|
|
.byte 0x5a, 0x3c, 0x84
|
|
.byte 0
|
|
.ascii "Trident"
|
|
.byte 0
|
|
|
|
# Tseng.
|
|
tseng_test:
|
|
movw $0x3cd, %dx
|
|
inb %dx, %al # Could things be this simple ! :-)
|
|
movb %al, %bl
|
|
movb $0x55, %al
|
|
outb %al, %dx
|
|
inb %dx, %al
|
|
movb %al, %ah
|
|
movb %bl, %al
|
|
outb %al, %dx
|
|
cmpb $0x55, %ah
|
|
je istsen
|
|
|
|
isnot: xorw %bp, %bp
|
|
istsen: ret
|
|
|
|
tseng_md:
|
|
.byte 0x26, 0x3c, 0x50
|
|
.byte 0x2a, 0x28, 0x64
|
|
.byte 0x23, 0x19, 0x84
|
|
.byte 0x24, 0x1c, 0x84
|
|
.byte 0x22, 0x2c, 0x84
|
|
.byte 0x21, 0x3c, 0x84
|
|
.byte 0
|
|
.ascii "Tseng"
|
|
.byte 0
|
|
|
|
# Video7.
|
|
video7_test:
|
|
movw $0x3cc, %dx
|
|
inb %dx, %al
|
|
movw $0x3b4, %dx
|
|
andb $0x01, %al
|
|
jz even7
|
|
|
|
movw $0x3d4, %dx
|
|
even7: movb $0x0c, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
movb %al, %bl
|
|
movb $0x55, %al
|
|
outb %al, %dx
|
|
inb %dx, %al
|
|
decw %dx
|
|
movb $0x1f, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
inb %dx, %al
|
|
movb %al, %bh
|
|
decw %dx
|
|
movb $0x0c, %al
|
|
outb %al, %dx
|
|
incw %dx
|
|
movb %bl, %al
|
|
outb %al, %dx
|
|
movb $0x55, %al
|
|
xorb $0xea, %al
|
|
cmpb %bh, %al
|
|
jne isnot
|
|
|
|
movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
|
|
ret
|
|
|
|
video7_md:
|
|
.byte 0x40, 0x2b, 0x50
|
|
.byte 0x43, 0x3c, 0x50
|
|
.byte 0x44, 0x3c, 0x64
|
|
.byte 0x41, 0x19, 0x84
|
|
.byte 0x42, 0x2c, 0x84
|
|
.byte 0x45, 0x1c, 0x84
|
|
.byte 0
|
|
.ascii "Video 7"
|
|
.byte 0
|
|
|
|
# Realtek VGA
|
|
realtek_test:
|
|
leaw idrtvga, %si
|
|
movw $0x45, %di
|
|
movw $0x0b, %cx
|
|
repe
|
|
cmpsb
|
|
je isrt
|
|
|
|
xorw %bp, %bp
|
|
isrt: ret
|
|
|
|
idrtvga: .ascii "REALTEK VGA"
|
|
|
|
realtek_md:
|
|
.byte 0x1a, 0x3c, 0x50
|
|
.byte 0x1b, 0x19, 0x84
|
|
.byte 0x1c, 0x1e, 0x84
|
|
.byte 0x1d, 0x2b, 0x84
|
|
.byte 0x1e, 0x3c, 0x84
|
|
.byte 0
|
|
.ascii "REALTEK"
|
|
.byte 0
|
|
|
|
#endif /* CONFIG_VIDEO_SVGA */
|
|
|
|
# User-defined local mode table (VGA only)
|
|
#ifdef CONFIG_VIDEO_LOCAL
|
|
local_modes:
|
|
leaw local_mode_table, %si
|
|
locm1: lodsw
|
|
orw %ax, %ax
|
|
jz locm2
|
|
|
|
stosw
|
|
movsw
|
|
jmp locm1
|
|
|
|
locm2: ret
|
|
|
|
# This is the table of local video modes which can be supplied manually
|
|
# by the user. Each entry consists of mode ID (word) and dimensions
|
|
# (byte for column count and another byte for row count). These modes
|
|
# are placed before all SVGA and VESA modes and override them if table
|
|
# compacting is enabled. The table must end with a zero word followed
|
|
# by NUL-terminated video adapter name.
|
|
local_mode_table:
|
|
.word 0x0100 # Example: 40x25
|
|
.byte 25,40
|
|
.word 0
|
|
.ascii "Local"
|
|
.byte 0
|
|
#endif /* CONFIG_VIDEO_LOCAL */
|
|
|
|
# Read a key and return the ASCII code in al, scan code in ah
|
|
getkey: xorb %ah, %ah
|
|
int $0x16
|
|
ret
|
|
|
|
# Read a key with a timeout of 30 seconds.
|
|
# The hardware clock is used to get the time.
|
|
getkt: call gettime
|
|
addb $30, %al # Wait 30 seconds
|
|
cmpb $60, %al
|
|
jl lminute
|
|
|
|
subb $60, %al
|
|
lminute:
|
|
movb %al, %cl
|
|
again: movb $0x01, %ah
|
|
int $0x16
|
|
jnz getkey # key pressed, so get it
|
|
|
|
call gettime
|
|
cmpb %cl, %al
|
|
jne again
|
|
|
|
movb $0x20, %al # timeout, return `space'
|
|
ret
|
|
|
|
# Flush the keyboard buffer
|
|
flush: movb $0x01, %ah
|
|
int $0x16
|
|
jz empty
|
|
|
|
xorb %ah, %ah
|
|
int $0x16
|
|
jmp flush
|
|
|
|
empty: ret
|
|
|
|
# Print hexadecimal number.
|
|
prthw: pushw %ax
|
|
movb %ah, %al
|
|
call prthb
|
|
popw %ax
|
|
prthb: pushw %ax
|
|
shrb $4, %al
|
|
call prthn
|
|
popw %ax
|
|
andb $0x0f, %al
|
|
prthn: cmpb $0x0a, %al
|
|
jc prth1
|
|
|
|
addb $0x07, %al
|
|
prth1: addb $0x30, %al
|
|
jmp prtchr
|
|
|
|
# Print decimal number in al
|
|
prtdec: pushw %ax
|
|
pushw %cx
|
|
xorb %ah, %ah
|
|
movb $0x0a, %cl
|
|
idivb %cl
|
|
cmpb $0x09, %al
|
|
jbe lt100
|
|
|
|
call prtdec
|
|
jmp skip10
|
|
|
|
lt100: addb $0x30, %al
|
|
call prtchr
|
|
skip10: movb %ah, %al
|
|
addb $0x30, %al
|
|
call prtchr
|
|
popw %cx
|
|
popw %ax
|
|
ret
|
|
|
|
store_edid:
|
|
pushw %es # just save all registers
|
|
pushw %ax
|
|
pushw %bx
|
|
pushw %cx
|
|
pushw %dx
|
|
pushw %di
|
|
|
|
pushw %fs
|
|
popw %es
|
|
|
|
movl $0x13131313, %eax # memset block with 0x13
|
|
movw $32, %cx
|
|
movw $0x140, %di
|
|
cld
|
|
rep
|
|
stosl
|
|
|
|
movw $0x4f15, %ax # do VBE/DDC
|
|
movw $0x01, %bx
|
|
movw $0x00, %cx
|
|
movw $0x00, %dx
|
|
movw $0x140, %di
|
|
int $0x10
|
|
|
|
popw %di # restore all registers
|
|
popw %dx
|
|
popw %cx
|
|
popw %bx
|
|
popw %ax
|
|
popw %es
|
|
ret
|
|
|
|
# VIDEO_SELECT-only variables
|
|
mt_end: .word 0 # End of video mode table if built
|
|
edit_buf: .space 6 # Line editor buffer
|
|
card_name: .word 0 # Pointer to adapter name
|
|
scanning: .byte 0 # Performing mode scan
|
|
do_restore: .byte 0 # Screen contents altered during mode change
|
|
svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
|
|
graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
|
|
dac_size: .byte 6 # DAC bit depth
|
|
|
|
# Status messages
|
|
keymsg: .ascii "Press <RETURN> to see video modes available, "
|
|
.ascii "<SPACE> to continue or wait 30 secs"
|
|
.byte 0x0d, 0x0a, 0
|
|
|
|
listhdr: .byte 0x0d, 0x0a
|
|
.ascii "Mode: COLSxROWS:"
|
|
|
|
crlft: .byte 0x0d, 0x0a, 0
|
|
|
|
prompt: .byte 0x0d, 0x0a
|
|
.asciz "Enter mode number or `scan': "
|
|
|
|
unknt: .asciz "Unknown mode ID. Try again."
|
|
|
|
badmdt: .ascii "You passed an undefined mode number."
|
|
.byte 0x0d, 0x0a, 0
|
|
|
|
vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
|
|
.ascii "report to <mj@ucw.cz>."
|
|
.byte 0x0d, 0x0a, 0
|
|
|
|
old_name: .asciz "CGA/MDA/HGA"
|
|
|
|
ega_name: .asciz "EGA"
|
|
|
|
svga_name: .ascii " "
|
|
|
|
vga_name: .asciz "VGA"
|
|
|
|
vesa_name: .asciz "VESA"
|
|
|
|
name_bann: .asciz "Video adapter: "
|
|
#endif /* CONFIG_VIDEO_SELECT */
|
|
|
|
# Other variables:
|
|
adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
|
|
video_segment: .word 0xb800 # Video memory segment
|
|
force_size: .word 0 # Use this size instead of the one in BIOS vars
|