patch-1.3.75 linux/arch/i386/boot/video.S
Next file: linux/arch/i386/defconfig
Previous file: linux/arch/i386/boot/setup.S
Back to the patch index
Back to the overall index
- Lines: 1633
- Date:
Sat Mar 16 14:47:59 1996
- Orig file:
v1.3.74/linux/arch/i386/boot/video.S
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.74/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
@@ -0,0 +1,1632 @@
+!
+! Display adapter & video mode setup, version 2.3 (15-Mar-96)
+!
+! Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
+! Based on the original setup.S code (C) Linus Torvalds
+!
+
+! Enable autodetection of SVGA adapters and modes
+#define 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
+
+! 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
+! 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_LAST_SPECIAL 0x0f05
+! 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
+#define PARAM_CURSOR_POS 0
+#define PARAM_VIDEO_PAGE 4
+#define PARAM_VIDEO_MODE 6
+#define PARAM_VIDEO_COLS 7
+#define PARAM_VIDEO_EGA_BX 10
+#define PARAM_VIDEO_LINES 14
+#define PARAM_HAVE_VGA 15
+#define PARAM_FONT_POINTS 16
+
+! Define DO_STORE according to CONFIG_VIDEO_RETAIN
+#ifdef CONFIG_VIDEO_RETAIN
+#define DO_STORE call store_screen
+#else
+#define DO_STORE
+#endif
+
+!
+! This is the main entry point called by setup.S
+!
+
+video: push ds ! We use different segments
+ push ds ! FS contains original DS
+ pop fs
+ push cs ! DS is equal to CS
+ pop ds
+ push cs ! ES is equal to CS
+ pop es
+ xor ax,ax
+ mov gs,ax ! GS is zero
+ cld
+ call basic_detect ! Basic adapter type testing (EGA/VGA/MDA/CGA)
+ seg fs ! User-selected video mode
+ mov ax,[0x01fa]
+ cmp ax,#ASK_VGA ! Bring up the menu
+ jz vid2
+ call mode_set ! Set the mode
+ jc vid1
+ lea si,badmdt ! Invalid mode ID
+ call prtstr
+vid2: call mode_menu
+vid1:
+#ifdef CONFIG_VIDEO_RETAIN
+ call restore_screen ! Restore screen contents
+#endif
+ call mode_params ! Store mode parameters
+ pop ds ! Restore original DS
+ ret
+
+!
+! Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
+!
+
+basic_detect:
+ seg fs ! Default is no VGA
+ movb [PARAM_HAVE_VGA],#0
+
+ mov ah,#0x12 ! Check EGA/VGA
+ mov bl,#0x10
+ int 0x10
+ seg fs
+ mov [PARAM_VIDEO_EGA_BX],bx ! Used for identification of EGA in the kernel
+ cmp bl,#0x10 ! No, this is a CGA/MDA/HGA card.
+ je basret
+ incb [adapter]
+
+ mov ax,#0x1a00 ! Check for EGA/VGA discrimination
+ int 0x10
+ cmp al,#0x1a ! 1a means VGA, anything else EGA
+ jne basret
+ seg fs
+ incb [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:
+ mov ah,#0x03 ! Read cursor position
+ xor bh,bh
+ int 0x10
+ seg fs
+ mov [PARAM_CURSOR_POS],dx
+
+ mov ah,#0x0f ! Read page/mode/width
+ int 0x10
+ seg fs
+ mov [PARAM_VIDEO_PAGE],bx
+ seg fs
+ mov [PARAM_VIDEO_MODE],ax ! Video mode and screen width
+ cmp al,#7 ! MDA/HGA => segment differs
+ jnz mopar0
+ mov [video_segment],#0xb000
+mopar0: seg gs ! Font size
+ mov ax,[0x485]
+ seg fs
+ mov [PARAM_FONT_POINTS],ax ! (valid only on EGA/VGA)
+
+ cmpb [def_mode],#0 ! Default mode -- force sane values
+ jz mopar1
+ seg fs
+ movb [PARAM_VIDEO_COLS],#80
+mopar2: seg fs
+ movb [PARAM_VIDEO_LINES],#25
+ ret
+
+mopar1: cmpb [adapter],#0 ! If we are on CGA/MDA/HGA, the screen must
+ jz mopar2 ! have 25 lines.
+ seg gs ! On EGA/VGA, use the EGA+ BIOS variable
+ mov al,[0x484] ! containing maximal line number.
+ inc al
+ seg fs
+ movb [PARAM_VIDEO_LINES],al
+ ret
+
+!
+! The video mode menu
+!
+
+mode_menu:
+ lea si,keymsg ! "Return/Space/Timeout" message
+ call prtstr
+ call flush
+nokey: call getkt
+ cmp al,#0x0d ! ENTER ?
+ je listm ! yes - manual mode selection
+ cmp al,#0x20 ! SPACE ?
+ je defmd1 ! no - repeat
+ call beep
+ jmp nokey
+defmd1: ret ! No mode selected => use the 80x25 default
+
+listm: call mode_table ! We need a mode table to be listed
+listm0: lea si,name_bann ! Print adapter name
+ call prtstr
+ mov si,[card_name]
+ or si,si
+ jnz an2
+ mov al,[adapter]
+ lea si,old_name
+ or al,al
+ jz an1
+ lea si,ega_name
+ dec al
+ jz an1
+ lea si,vga_name
+ jmp an1
+an2: call prtstr
+ lea si,svga_name
+an1: call prtstr
+ lea si,listhdr ! Table header
+ call prtstr
+ mov dl,#0x30 ! DL holds mode number
+ lea si,modelist
+lm1: cmp (si),#ASK_VGA ! End?
+ jz lm2
+ mov al,dl ! Menu selection number
+ call prtchr
+ call prtsp2
+ lodsw
+ call prthw ! Mode ID
+ call prtsp2
+ mov al,(si+1)
+ call prtdec ! Rows
+ mov al,#0x78 ! 'x'
+ call prtchr
+ lodsw
+ call prtdec ! Columns
+ mov al,#0x0d ! New line
+ call prtchr
+ mov al,#0x0a
+ call prtchr
+ inc dl ! Next character
+ cmp dl,#0x3a
+ jnz lm1
+ mov dl,#0x61
+ jmp lm1
+
+lm2: lea si,prompt ! Mode prompt
+ call prtstr
+ lea di,edit_buf ! Editor buffer
+lm3: call getkey
+ cmp al,#0x0d ! Enter?
+ jz lment
+ cmp al,#0x08 ! Backspace?
+ jz lmbs
+ cmp al,#0x20 ! Printable?
+ jc lm3
+ cmp di,#edit_buf+4 ! Enough space?
+ jz lm3
+ stosb
+ call prtchr
+ jmp lm3
+
+lmbs: cmp di,#edit_buf ! Backspace
+ jz lm3
+ dec di
+ mov al,#0x08
+ call prtchr
+ call prtspc
+ mov al,#0x08
+ call prtchr
+ jmp lm3
+
+lment: movb (di),#0
+ lea si,crlft
+ call prtstr
+ lea si,edit_buf
+ cmpb (si),#0 ! Empty string => use default mode
+ jz lmdef
+ cmpb (si+1),#0 ! One character => menu selection
+ jz mnusel
+ cmp (si),#0x6373 ! "scan" => mode scanning
+ jnz lmhx
+ cmp (si+2),#0x6e61
+ jz lmscan
+lmhx: xor bx,bx ! Else => mode ID in hex
+lmhex: lodsb
+ or al,al
+ jz lmuse1
+ sub al,#0x30
+ jc lmbad
+ cmp al,#10
+ jc lmhx1
+ sub al,#7
+ and al,#0xdf
+ cmp al,#10
+ jc lmbad
+ cmp al,#16
+ jnc lmbad
+lmhx1: shl bx,#4
+ or bl,al
+ jmp lmhex
+lmuse1: mov ax,bx
+ jmp lmuse
+
+mnusel: lodsb ! Menu selection
+ xor ah,ah
+ sub al,#0x30
+ jc lmbad
+ cmp al,#10
+ jc lmuse
+ cmp al,#0x61-0x30
+ jc lmbad
+ sub al,#0x61-0x30-10
+ cmp al,#36
+ jnc lmbad
+lmuse: call mode_set
+ jc lmdef
+lmbad: lea si,unknt
+ call prtstr
+ br lm2
+
+lmscan: cmpb [adapter],#0 ! Scanning supported only on EGA/VGA
+ jz lmbad
+ mov [mt_end],#0 ! Scanning of modes: done as new autodetection
+ movb [scanning],#1
+ call mode_table
+ br listm0
+
+lmdef: ret
+
+!
+! Aliases for backward compatibility.
+!
+
+setalias:
+ mov ax,#VIDEO_80x25
+ inc bx
+ jz mode_set
+ mov al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL
+ inc bx
+ jnz setbad
+
+ ! Fall-thru !
+
+!
+! Setting of user mode (AX=mode ID) => CF=success
+!
+
+mode_set:
+ mov bx,ax
+ cmp ah,#0xff
+ jz setalias
+ test ah,#VIDEO_RECALC>>8
+ jnz setrec
+ cmp ah,#VIDEO_FIRST_RESOLUTION>>8
+ jnc setres
+ cmp ah,#VIDEO_FIRST_SPECIAL>>8
+ jz setspc
+ cmp ah,#VIDEO_FIRST_VESA>>8
+ jnc setvesa
+ or ah,ah
+ jz setmenu
+ dec ah
+ jz setbios
+setbad: clc
+ movb [do_restore],#0 ! The screen needn't be restored
+ ret
+
+setvesa:
+ DO_STORE
+ sub bh,#VIDEO_FIRST_VESA>>8
+ mov ax,#0x4f02 ! VESA BIOS mode set call
+ int 0x10
+ cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK
+ jnz setbad
+ stc
+ ret
+
+setbios:
+ DO_STORE
+ int 0x10 ! Standard BIOS mode set call
+ push bx
+ mov ah,#0x0f ! Check if really set
+ int 0x10
+ pop bx
+ cmp al,bl
+ jnz setbad
+ stc
+ ret
+
+setspc: xor bh,bh ! Set special mode
+ cmp bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL
+ jnc setbad
+ add bx,bx
+ .word 0xa7ff, spec_inits ! JMP [BX+spec_inits]
+
+setmenu:
+ push bx ! Set mode chosen from menu
+ call mode_table ! Build the mode table
+ pop ax
+ shl ax,#2
+ add si,ax
+ cmp si,di
+ jnc setbad
+ mov ax,(si) ! Fetch mode ID
+_m_s: jmp mode_set
+
+setres:
+ push bx ! Set mode chosen by its resolution
+ call mode_table
+ pop bx
+ xchg bh,bl
+setr1: lodsw
+ cmp ax,#ASK_VGA ! End of the list?
+ jz setbad
+ lodsw
+ cmp ax,bx
+ jnz setr1
+ mov ax,(si-4) ! Fetch mode ID
+ jmp _m_s
+
+!
+! 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: sub ah,#VIDEO_RECALC>>8 ! Set the base mode
+ call mode_set
+ jnc rct3
+ seg gs ! Font size in pixels
+ mov ax,[0x485]
+ seg gs ! Number of rows
+ mov bl,[0x484]
+ inc bl
+ mul bl ! Number of visible
+ dec ax ! scan lines - 1
+ mov dx,#0x3d4
+ mov bx,ax
+ mov al,#0x12 ! Lower 8 bits
+ mov ah,bl
+ out dx,ax
+ mov al,#0x07 ! Bits 8 and 9 in the overflow register
+ call inidx
+ xchg ah,al
+ and ah,#0xbd
+ shr bh,#1
+ jnc rct1
+ or ah,#0x02
+rct1: shr bh,#1
+ jnc rct2
+ or ah,#0x40
+rct2: mov al,#0x07
+ out dx,ax
+ 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
+
+!
+! Set the 80x25 mode. If already set, do nothing.
+!
+
+set_80x25:
+ incb [def_mode] ! Signal "we use default mode"
+use_80x25:
+ mov ah,#0x0f ! Get current mode ID
+ int 0x10
+ cmp ax,#0x5007 ! Mode 7 (80x25 mono) is the only one available
+ jz st80 ! on CGA/MDA/HGA and is also available on EGAM
+ cmp ax,#0x5003 ! Unknown mode => force 80x25 color
+ jnz force3
+st80: cmpb [adapter],#0 ! CGA/MDA/HGA => mode 3/7 is always 80x25
+ jz set80
+ seg gs ! This is EGA+ -- beware of 80x50 etc.
+ mov al,[0x0484]
+ or al,al ! Some buggy BIOS'es set 0 rows
+ jz set80
+ cmp al,#24 ! It's hopefully correct
+ jz set80
+force3: DO_STORE
+ mov ax,#0x0003 ! 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:
+ mov ax,#0x1112 ! Use 8x8 font
+ xor bl,bl
+ int 0x10
+ mov ax,#0x1200 ! Use alternate print screen
+ mov bl,#0x20
+ int 0x10
+ mov ax,#0x1201 ! Turn off cursor emulation
+ mov bl,#0x34
+ int 0x10
+ mov ah,#0x01 ! Define cursor (scan lines 6 to 7)
+ mov cx,#0x0607
+ 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
+ mov ax,#0x1111 ! Use 9x14 font
+ xor bl,bl
+ int 0x10
+ mov ah,#0x01 ! Define cursor (scan lines 11 to 12)
+ mov cx,#0x0b0c
+ 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
+ mov ax,#0x1201 ! Set 350 scans
+ mov bl,#0x30
+ int 0x10
+ mov ax,#0x0003 ! Reset video mode
+ int 0x10
+ jmp set_8pt ! Use 8-pixel font
+
+#ifdef CONFIG_VIDEO_RETAIN
+
+!
+! Store screen contents to temporary buffer.
+!
+
+store_screen:
+ cmpb [do_restore],#0 ! Already stored?
+ jnz stsr
+ push ax
+ push bx
+ incb [do_restore] ! Screen will be restored later
+ mov al,[def_mode] ! "Default mode" flag overriden
+ push ax
+ movb [def_mode],#0
+ call mode_params ! Obtain and store basic parameters
+ pop ax
+ mov [def_mode],al
+ seg fs ! of the current mode.
+ mov ax,[PARAM_CURSOR_POS]
+ lea di,modelist+8192
+ stosw
+ seg fs
+ mov ah,[PARAM_VIDEO_LINES]
+ seg fs
+ mov al,[PARAM_VIDEO_COLS]
+ stosw
+ mul ah
+ mov cx,ax ! CX=number of characters to store
+
+ push ds ! Store the screen
+ mov ds,[video_segment]
+ xor si,si
+ rep
+ movsw
+ pop ds
+ pop bx
+ pop ax
+stsr: ret
+
+!
+! Restore screen contents from temporary buffer.
+!
+
+restore_screen:
+ cmpb [do_restore],#0 ! Has the screen been stored?
+ jz res1
+ call mode_params ! Get parameters of current mode
+ seg fs
+ mov cl,[PARAM_VIDEO_LINES]
+ seg fs
+ mov ch,[PARAM_VIDEO_COLS]
+ lea si,modelist+8192 ! Screen buffer
+ lodsw ! Set cursor position
+ mov dx,ax
+ cmp dh,cl
+ jc res2
+ mov dh,cl
+ dec dh
+res2: cmp dl,ch
+ jc res3
+ mov dl,ch
+ dec dl
+res3: mov ah,#0x02
+ mov bh,#0x00
+ int 0x10
+ lodsw ! Display size
+ mov dl,ah ! DL=number of lines
+ mov ah,#0 ! BX=physical length of orig. line
+ mov bx,ax
+ cmp dl,cl ! Too many?
+ jc res4
+ push ax
+ mov al,dl
+ sub al,cl
+ mul bl
+ add si,ax
+ add si,ax
+ pop ax
+ mov dl,cl
+res4: cmp al,ch ! Too wide?
+ jc res5
+ mov al,ch ! AX=width of src. line
+res5: mov cl,#0
+ xchg cl,ch
+ mov bp,cx ! BP=width of dest. line
+ push es
+ mov es,[video_segment]
+ xor di,di ! Move the data
+ add bx,bx ! Convert BX and BP to _bytes_
+ add bp,bp
+res6: push si
+ push di
+ mov cx,ax
+ rep
+ movsw
+ pop di
+ pop si
+ add di,bp
+ add si,bx
+ dec dl
+ jnz res6
+ pop es ! Done
+res1: ret
+
+#endif /* CONFIG_VIDEO_RETAIN */
+
+!
+! 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:
+ mov di,[mt_end] ! Already filled?
+ or di,di
+ jnz mtab1x
+ lea di,modelist ! Store standard modes:
+
+ mov eax,#VIDEO_80x25 + 0x50190000 ! The 80x25 mode (ALL)
+ stosd
+ mov al,[adapter] ! CGA/MDA/HGA -- no more modes
+ or al,al
+ jz mtabe
+ dec al
+ jnz mtabv
+ mov eax,#VIDEO_8POINT + 0x502b0000 ! The 80x43 EGA mode
+ stosd
+ jmp mtabe
+mtab1x: jmp mtab1
+
+mtabv: mov eax,#VIDEO_8POINT + 0x50320000 ! The 80x50 mode (VGA only)
+ stosd
+ mov eax,#VIDEO_80x43 + 0x502b0000 ! The 80x43 mode (VGA only)
+ stosd
+ mov eax,#VIDEO_80x28 + 0x501c0000 ! The 80x28 mode (VGA only)
+ stosd
+
+ cmpb [scanning],#0 ! Mode scan requested?
+ jz mscan1
+ call mode_scan
+mscan1:
+
+#ifdef CONFIG_VIDEO_LOCAL
+ call local_modes
+#endif
+#ifdef CONFIG_VIDEO_VESA
+ call vesa_modes ! Detect VESA VGA modes
+#endif
+#ifdef CONFIG_VIDEO_SVGA
+ cmpb [scanning],#0 ! Bypass when scanning
+ jnz mscan2
+ call svga_modes ! Detect SVGA cards & modes
+mscan2:
+#endif
+
+mtabe:
+
+#ifdef CONFIG_VIDEO_COMPACT
+ lea si,modelist ! Compact video mode list if requested.
+ mov dx,di
+ mov di,si
+cmt1: cmp si,dx ! Scan all modes
+ jz cmt2
+ lea bx,modelist ! Find in previous entries
+ mov cx,(si+2)
+cmt3: cmp si,bx
+ jz cmt4
+ cmp cx,(bx+2) ! Found => don't copy this entry
+ jz cmt5
+ add bx,#4
+ jmp cmt3
+
+cmt4: movsd ! Copy entry
+ jmp cmt1
+
+cmt5: add si,#4 ! Skip entry
+ jmp cmt1
+
+cmt2:
+#endif /* CONFIG_VIDEO_COMPACT */
+
+ mov (di),#ASK_VGA ! End marker
+ mov [mt_end],di
+mtab1: lea si,modelist ! Returning: SI=mode list, DI=list end
+ret0: ret
+
+!
+! Detect VESA modes.
+!
+
+#ifdef CONFIG_VIDEO_VESA
+
+vesa_modes:
+ cmpb [adapter],#2 ! VGA only
+ jnz ret0
+ mov bp,di ! BP=original mode table end
+ add di,#0x400 ! Buffer space
+ mov ax,#0x4f00 ! VESA Get card info call
+ int #0x10
+ mov di,bp
+ cmp ax,#0x004f ! Successful?
+ jnz ret0
+ cmp (di+0x400),#0x4556
+ jnz ret0
+ cmp (di+0x402),#0x4153
+ jnz ret0
+ mov [card_name],#vesa_name ! Set name to "VESA VGA"
+ push gs
+ lgs si,(di+0x40e) ! GS:SI=mode list
+ mov cx,#128 ! Iteration limit
+vesa1: seg gs ! Get next mode in the list
+ lodsw
+ cmp ax,#0xffff ! End of the table?
+ jz vesar
+ cmp ax,#0x0080 ! Check validity of mode ID
+ jc vesa2
+ or ah,ah ! Valid ID's are 0x0000-0x007f
+ jz vesae ! and 0x0100-0x02ff.
+ cmp ax,#0x0300
+ jnc vesae
+vesa2: push cx
+ mov cx,ax ! Get mode information structure
+ mov ax,#0x4f01
+ int 0x10
+ mov bx,cx ! BX=mode number
+ add bh,#VIDEO_FIRST_VESA>>8
+ pop cx
+ cmp ax,#0x004f
+ jnz vesae
+ mov al,(di) ! Check capabilities. We require
+ and al,#0x19 ! a color text mode.
+ cmp al,#0x09
+ jnz vesan
+ cmp (di+8),#0xb800 ! Standard video memory address required
+ jnz vesan
+ testb (di),#2 ! Mode characteristics supplied?
+ mov (di),bx ! Store mode number
+ jz vesa3
+ xor dx,dx
+ mov bx,(di+0x12) ! Width
+ or bh,bh
+ jnz vesan
+ mov (di+3),bl
+ mov ax,(di+0x14) ! Height
+ or ah,ah
+ jnz vesan
+ mov (di+2),al
+ mul bl
+ cmp ax,#8193 ! Small enough for Linux console driver?
+ jnc vesan
+ jmp vesaok
+
+vesa3: sub bx,#0x8108 ! This mode has no detailed info specified,
+ jc vesan ! so it must be a standard VESA mode.
+ cmp bx,#5
+ jnc vesan
+ mov ax,(bx+vesa_text_mode_table)
+ mov (di+2),ax
+vesaok: add di,#4 ! The mode is valid. Store it.
+vesan: loop vesa1 ! Next mode. Limit exceeded => error
+vesae: lea si,vesaer
+ call prtstr
+ mov di,bp ! Discard already found modes.
+vesar: pop gs
+ ret
+
+!
+! Dimensions of standard VESA text modes
+!
+
+vesa_text_mode_table:
+ db 60, 80 ! 0108
+ db 25, 132 ! 0109
+ db 43, 132 ! 010A
+ db 50, 132 ! 010B
+ db 60, 132 ! 010C
+
+#endif /* CONFIG_VIDEO_VESA */
+
+!
+! Scan for video modes. A bit dirty, but should work.
+!
+
+mode_scan:
+ mov cx,#0x0100 ! Start with mode 0
+scm1: mov ah,#0 ! Test the mode
+ mov al,cl
+ int 0x10
+ mov ah,#0x0f
+ int 0x10
+ cmp al,cl
+ jnz scm2 ! Mode not set
+ mov dx,#0x3c0 ! Test if it's a text mode
+ mov al,#0x10 ! Mode bits
+ call inidx
+ and al,#0x03
+ jnz scm2
+ mov dx,#0x3d4 ! Cursor location
+ mov al,#0x0f
+ call inidx
+ or al,al
+ jnz scm2
+ mov ax,cx ! OK, store the mode
+ stosw
+ seg gs ! Number of rows
+ mov al,[0x484]
+ inc al
+ stosb
+ seg gs ! Number of columns
+ mov ax,[0x44a]
+ stosb
+scm2: inc cl
+ jns scm1
+ mov ax,#0x0003 ! Return back to mode 3
+ int 0x10
+ ret
+
+tstidx: out dx,ax ! OUT DX,AX and inidx
+inidx: out dx,al ! Read from indexed VGA register
+ inc dx ! AL=index, DX=index reg port -> AL=data
+ in al,dx
+ dec dx
+ ret
+
+!
+! Try to detect type of SVGA card and supply (usually approximate) video
+! mode table for it.
+!
+
+#ifdef CONFIG_VIDEO_SVGA
+
+svga_modes:
+ lea si,svga_table ! Test all known SVGA adapters
+dosvga: lodsw
+ mov bp,ax ! Default mode table
+ or ax,ax
+ jz didsv1
+ lodsw ! Pointer to test routine
+ push si
+ push di
+ push es
+ mov bx,#0xc000
+ mov es,bx
+ call ax ! Call test routine
+ pop es
+ pop di
+ pop si
+ or bp,bp
+ jz dosvga
+ mov si,bp ! Found, copy the modes
+ mov ah,#0x01
+cpsvga: lodsb
+ or al,al
+ jz didsv
+ stosw
+ movsw
+ jmp cpsvga
+
+didsv: mov [card_name],si ! 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 s3_md, s3_test
+ .word ati_md, ati_test
+ .word chips_md, chips_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 oak_md, oak_test
+ .word paradise_md, paradise_test
+ .word trident_md, trident_test
+ .word tseng_md, tseng_test
+ .word video7_md, video7_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:
+ mov cx,#0x0f35 ! we store some constants in cl/ch
+ mov dx,#0x03d4
+ movb al,#0x38
+ call inidx
+ mov bh,al ! store current value of CRT-register 0x38
+ mov ax,#0x0038
+ call outidx ! disable writing to special regs
+ movb al,cl ! check whether we can write special reg 0x35
+ call inidx
+ movb bl,al ! save the current value of CRT reg 0x35
+ andb al,#0xf0 ! clear bits 0-3
+ movb ah,al
+ movb al,cl ! and write it to CRT reg 0x35
+ call outidx
+ call inidx ! now read it back
+ andb al,ch ! clear the upper 4 bits
+ jz s3_2 ! the first test failed. But we have a
+ movb ah,bl ! second chance
+ mov al,cl
+ call outidx
+ jmp s3_1 ! do the other tests
+s3_2: mov ax,cx ! load ah with 0xf and al with 0x35
+ orb ah,bl ! set the upper 4 bits of ah with the orig value
+ call outidx ! write ...
+ call inidx ! ... and reread
+ andb al,cl ! turn off the upper 4 bits
+ push ax
+ movb ah,bl ! restore old value in register 0x35
+ movb al,cl
+ call outidx
+ pop ax
+ cmp al,ch ! setting lower 4 bits was successful => bad
+ je no_s3 ! writing is allowed => this is not an S3
+s3_1: mov ax,#0x4838 ! allow writing to special regs by putting
+ call outidx ! magic number into CRT-register 0x38
+ movb al,cl ! check whether we can write special reg 0x35
+ call inidx
+ movb bl,al
+ andb al,#0xf0
+ movb ah,al
+ movb al,cl
+ call outidx
+ call inidx
+ andb al,ch
+ jnz no_s3 ! no, we can't write => no S3
+ mov ax,cx
+ orb ah,bl
+ call outidx
+ call inidx
+ andb al,ch
+ push ax
+ movb ah,bl ! restore old value in register 0x35
+ movb al,cl
+ call outidx
+ pop ax
+ cmp al,ch
+ jne no_s31 ! writing not possible => no S3
+ movb al,#0x30
+ call inidx ! now get the S3 id ...
+ lea di,idS3
+ mov cx,#0x10
+ repne
+ scasb
+ je no_s31
+ movb ah,bh
+ movb al,#0x38
+ jmp s3rest
+no_s3: movb al,#0x35 ! restore CRT register 0x35
+ movb ah,bl
+ call outidx
+no_s31: xor bp,bp ! Detection failed
+s3rest: movb ah,bh
+ movb al,#0x38 ! restore old value of CRT register 0x38
+outidx: out dx,al ! Write to indexed VGA register
+ push ax ! AL=index, AH=data, DX=index reg port
+ mov al,ah
+ inc dx
+ out dx,al
+ dec dx
+ pop ax
+ ret
+
+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:
+ lea si,idati
+ mov di,#0x31
+ mov cx,#0x09
+ repe
+ cmpsb
+ je atiok
+ xor 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:
+ mov ax,#0x200f
+ mov dx,#0x3ce
+ out dx,ax
+ inc dx
+ in al,dx
+ cmp al,#0x20
+ je isahed
+ cmp al,#0x21
+ je isahed
+ xor 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:
+ mov dx,#0x3c3
+ in al,dx
+ or al,#0x10
+ out dx,al
+ mov dx,#0x104
+ in al,dx
+ mov bl,al
+ mov dx,#0x3c3
+ in al,dx
+ and al,#0xef
+ out dx,al
+ cmp bl,#0xa5
+ je cantok
+ xor 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:
+ mov dx,#0x3d4
+ mov al,#0x0c
+ out dx,al
+ inc dx
+ in al,dx
+ mov bl,al
+ xor al,al
+ out dx,al
+ dec dx
+ mov al,#0x1f
+ out dx,al
+ inc dx
+ in al,dx
+ mov bh,al
+ xor ah,ah
+ shl al,#4
+ mov cx,ax
+ mov al,bh
+ shr al,#4
+ add cx,ax
+ shl cx,#8
+ add cx,#6
+ mov ax,cx
+ mov dx,#0x3c4
+ out dx,ax
+ inc dx
+ in al,dx
+ and al,al
+ jnz nocirr
+ mov al,bh
+ out dx,al
+ in al,dx
+ cmp al,#0x01
+ je iscirr
+nocirr: xor bp,bp
+iscirr: mov dx,#0x3d4
+ mov al,bl
+ xor ah,ah
+ shl ax,#8
+ add ax,#0x0c
+ out dx,ax
+ 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:
+ mov dx,#0x3c4
+ mov al,#6
+ call inidx
+ mov bl,al ! BL=backup
+ mov ax,#6
+ call tstidx
+ cmp al,#0x0f
+ jne c5fail
+ mov ax,#0x1206
+ call tstidx
+ cmp al,#0x12
+ jne c5fail
+ mov al,#0x1e
+ call inidx
+ mov bh,al
+ mov ah,bh
+ and ah,#0xc0
+ mov al,#0x1e
+ call tstidx
+ and al,#0x3f
+ jne c5xx
+ mov al,#0x1e
+ mov ah,bh
+ or ah,#0x3f
+ call tstidx
+ xor al,#0x3f
+ and al,#0x3f
+c5xx: pushf
+ mov al,#0x1e
+ mov ah,bh
+ out dx,ax
+ popf
+ je c5done
+c5fail: xor bp,bp
+c5done: mov al,#6
+ mov ah,bl
+ out dx,ax
+ 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:
+ mov dx,#0x3ce
+ mov al,#0x0a
+ call inidx
+ mov bl,al ! BL=backup
+ mov ax,#0xce0a
+ call tstidx
+ or al,al
+ jne c2fail
+ mov ax,#0xec0a
+ call tstidx
+ cmp al,#0x01
+ jne c2fail
+ mov al,#0xaa
+ call inidx ! 4X, 5X, 7X and 8X are valid 64XX chip ID's
+ shr al,#4
+ sub al,#4
+ jz c6done
+ dec al
+ jz c6done
+ sub al,#2
+ jz c6done
+ dec al
+ jz c6done
+c2fail: xor bp,bp
+c6done: mov al,#0x0a
+ mov ah,bl
+ out dx,ax
+ ret
+
+cirrus6_md:
+ .byte 0
+ .ascii "Cirrus Logic 64XX"
+ .byte 0
+
+! Everex / Trident
+
+everex_test:
+ mov ax,#0x7000
+ xor bx,bx
+ int 0x10
+ cmp al,#0x70
+ jne noevrx
+ shr dx,#4
+ cmp dx,#0x678
+ je evtrid
+ cmp dx,#0x236
+ jne evrxok
+evtrid: lea bp,trident_md
+evrxok: ret
+
+noevrx: xor 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:
+ lea si,idgenoa ! Check Genoa 'clues'
+ xor ax,ax
+ seg es
+ mov al,[0x37]
+ mov di,ax
+ mov cx,#0x04
+ dec si
+ dec di
+l1: inc si
+ inc di
+ mov al,(si)
+ test al,al
+ jz l2
+ seg es
+ cmp al,(di)
+l2: loope l1
+ or cx,cx
+ je isgen
+ xor 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:
+ lea si,idoakvga
+ mov di,#0x08
+ mov cx,#0x08
+ repe
+ cmpsb
+ je isoak
+ xor 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:
+ lea si,idparadise
+ mov di,#0x7d
+ mov cx,#0x04
+ repe
+ cmpsb
+ je ispara
+ xor 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:
+ mov dx,#0x3c4
+ mov al,#0x0e
+ out dx,al
+ inc dx
+ in al,dx
+ xchg ah,al
+ xor al,al
+ out dx,al
+ in al,dx
+ xchg al,ah
+ mov bl,al ! Strange thing ... in the book this wasn't
+ and bl,#0x02 ! necessary but it worked on my card which
+ jz setb2 ! is a trident. Without it the screen goes
+ and al,#0xfd ! blurred ...
+ jmp clrb2 !
+setb2: or al,#0x02 !
+clrb2: out dx,al
+ and ah,#0x0f
+ cmp ah,#0x02
+ je istrid
+ xor 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:
+ mov dx,#0x3cd
+ in al,dx ! Could things be this simple ! :-)
+ mov bl,al
+ mov al,#0x55
+ out dx,al
+ in al,dx
+ mov ah,al
+ mov al,bl
+ out dx,al
+ cmp ah,#0x55
+ je istsen
+ xor 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 0
+ .ascii "Tseng"
+ .byte 0
+
+! Video7.
+
+video7_test:
+ mov dx,#0x3cc
+ in al,dx
+ mov dx,#0x3b4
+ and al,#0x01
+ jz even7
+ mov dx,#0x3d4
+even7: mov al,#0x0c
+ out dx,al
+ inc dx
+ in al,dx
+ mov bl,al
+ mov al,#0x55
+ out dx,al
+ in al,dx
+ dec dx
+ mov al,#0x1f
+ out dx,al
+ inc dx
+ in al,dx
+ mov bh,al
+ dec dx
+ mov al,#0x0c
+ out dx,al
+ inc dx
+ mov al,bl
+ out dx,al
+ mov al,#0x55
+ xor al,#0xea
+ cmp al,bh
+ je isvid7
+ xor bp,bp
+isvid7: 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
+
+#endif /* CONFIG_VIDEO_SVGA */
+
+!
+! User-defined local mode table (VGA only)
+!
+
+#ifdef CONFIG_VIDEO_LOCAL
+
+local_modes:
+ lea si,local_mode_table
+locm1: lodsw
+ or 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: xor 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
+ add al,#30 ! Wait 30 seconds
+ cmp al,#60
+ jl lminute
+ sub al,#60
+lminute:
+ mov cl,al
+again: mov ah,#0x01
+ int 0x16
+ jnz getkey ! key pressed, so get it
+ call gettime
+ cmp al,cl
+ jne again
+ mov al,#0x20 ! timeout, return default char `space'
+ ret
+
+!
+! Flush the keyboard buffer
+!
+
+flush: mov ah,#0x01
+ int 0x16
+ jz empty
+ xor ah,ah
+ int 0x16
+ jmp flush
+empty: ret
+
+!
+! Print hexadecimal number.
+!
+
+prthw: push ax
+ mov al,ah
+ call prthb
+ pop ax
+prthb: push ax
+ shr al,#4
+ call prthn
+ pop ax
+ and al,#0x0f
+prthn: cmp al,#0x0a
+ jc prth1
+ add al,#0x07
+prth1: add al,#0x30
+ br prtchr
+
+!
+! Print decimal number (AL).
+!
+
+prtdec: push ax
+ push cx
+ xor ah,ah ! Clear ah
+ mov cl,#0x0a
+ idiv cl
+ cmp al,#0x09
+ jbe lt100
+ call prtdec
+ jmp skip10
+lt100: add al,#0x30
+ call prtchr
+skip10: mov al,ah
+ add al,#0x30
+ call prtchr
+ pop cx
+ pop ax
+ ret
+
+! Variables:
+
+adapter: .byte 0 ! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
+def_mode: .byte 0 ! "Default mode selected" flag
+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
+video_segment: .word 0xb800 ! Video memory segment
+
+! Messages:
+
+keymsg: .ascii "Press <RETURN> to see video modes available, "
+ .ascii "<SPACE> to continue or wait 30 secs"
+ db 0x0d, 0x0a, 0
+listhdr: db 0x0d, 0x0a
+ .ascii "Mode: COLSxROWS:"
+crlft: db 0x0d, 0x0a, 0
+prompt: db 0x0d, 0x0a
+ .ascii "Enter mode number: "
+ db 0
+unknt: .ascii "Unknown mode ID. Try again."
+ db 0
+badmdt: .ascii "You passed an undefined mode number to setup."
+ db 0x0d, 0x0a, 0
+vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
+ .ascii "report to <mj@k332.feld.cvut.cz>."
+ db 0x0d, 0x0a, 0
+old_name: .ascii "CGA/MDA/HGA"
+ db 0
+ega_name: .ascii "EGA"
+ db 0
+svga_name: .ascii " "
+vga_name: .ascii "VGA"
+ db 0
+vesa_name: .ascii "VESA"
+ db 0
+name_bann: .ascii "Video adapter: "
+ db 0
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this