3 * Display adapter & video mode setup, version 2.13 (14-May-99)
5 * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
6 * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
8 * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
10 * For further information, look at Documentation/svga.txt.
14 #include <linux/config.h> /* for CONFIG_VIDEO_* */
16 /* Enable autodetection of SVGA adapters and modes. */
17 #undef CONFIG_VIDEO_SVGA
19 /* Enable autodetection of VESA modes */
20 #define CONFIG_VIDEO_VESA
22 /* Enable compacting of mode table */
23 #define CONFIG_VIDEO_COMPACT
25 /* Retain screen contents when switching modes */
26 #define CONFIG_VIDEO_RETAIN
28 /* Enable local mode list */
29 #undef CONFIG_VIDEO_LOCAL
31 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
32 #undef CONFIG_VIDEO_400_HACK
34 /* Hack that lets you force specific BIOS mode ID and specific dimensions */
35 #undef CONFIG_VIDEO_GFX_HACK
36 #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
37 #define VIDEO_GFX_BIOS_BX 0x0102
38 #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
40 /* This code uses an extended set of video mode numbers. These include:
41 * Aliases for standard modes
45 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
46 * of compatibility when extending the table. These are between 0x00 and 0xff.
48 #define VIDEO_FIRST_MENU 0x0000
50 /* Standard BIOS video modes (BIOS number + 0x0100) */
51 #define VIDEO_FIRST_BIOS 0x0100
53 /* VESA BIOS video modes (VESA number + 0x0200) */
54 #define VIDEO_FIRST_VESA 0x0200
56 /* Video7 special modes (BIOS number + 0x0900) */
57 #define VIDEO_FIRST_V7 0x0900
59 /* Special video modes */
60 #define VIDEO_FIRST_SPECIAL 0x0f00
61 #define VIDEO_80x25 0x0f00
62 #define VIDEO_8POINT 0x0f01
63 #define VIDEO_80x43 0x0f02
64 #define VIDEO_80x28 0x0f03
65 #define VIDEO_CURRENT_MODE 0x0f04
66 #define VIDEO_80x30 0x0f05
67 #define VIDEO_80x34 0x0f06
68 #define VIDEO_80x60 0x0f07
69 #define VIDEO_GFX_HACK 0x0f08
70 #define VIDEO_LAST_SPECIAL 0x0f09
72 /* Video modes given by resolution */
73 #define VIDEO_FIRST_RESOLUTION 0x1000
75 /* The "recalculate timings" flag */
76 #define VIDEO_RECALC 0x8000
78 /* Positions of various video parameters passed to the kernel */
79 /* (see also include/linux/tty.h) */
80 #define PARAM_CURSOR_POS 0x00
81 #define PARAM_VIDEO_PAGE 0x04
82 #define PARAM_VIDEO_MODE 0x06
83 #define PARAM_VIDEO_COLS 0x07
84 #define PARAM_VIDEO_EGA_BX 0x0a
85 #define PARAM_VIDEO_LINES 0x0e
86 #define PARAM_HAVE_VGA 0x0f
87 #define PARAM_FONT_POINTS 0x10
89 #define PARAM_LFB_WIDTH 0x12
90 #define PARAM_LFB_HEIGHT 0x14
91 #define PARAM_LFB_DEPTH 0x16
92 #define PARAM_LFB_BASE 0x18
93 #define PARAM_LFB_SIZE 0x1c
94 #define PARAM_LFB_LINELENGTH 0x24
95 #define PARAM_LFB_COLORS 0x26
96 #define PARAM_VESAPM_SEG 0x2e
97 #define PARAM_VESAPM_OFF 0x30
98 #define PARAM_LFB_PAGES 0x32
99 #define PARAM_VESA_ATTRIB 0x34
100 #define PARAM_CAPABILITIES 0x36
102 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
103 #ifdef CONFIG_VIDEO_RETAIN
104 #define DO_STORE call store_screen
107 #endif /* CONFIG_VIDEO_RETAIN */
109 # This is the main entry point called by setup.S
110 # %ds *must* be pointing to the bootsector
111 video: pushw %ds # We use different segments
112 pushw %ds # FS contains original DS
114 pushw %cs # DS is equal to CS
116 pushw %cs # ES is equal to CS
119 movw %ax, %gs # GS is zero
121 call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
122 #ifdef CONFIG_VIDEO_SELECT
123 movw %fs:(0x01fa), %ax # User selected video mode
124 cmpw $ASK_VGA, %ax # Bring up the menu
127 call mode_set # Set the mode
130 leaw badmdt, %si # Invalid mode ID
134 #ifdef CONFIG_VIDEO_RETAIN
135 call restore_screen # Restore screen contents
136 #endif /* CONFIG_VIDEO_RETAIN */
138 #endif /* CONFIG_VIDEO_SELECT */
139 call mode_params # Store mode parameters
140 popw %ds # Restore original DS
143 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
145 movb $0, %fs:(PARAM_HAVE_VGA)
146 movb $0x12, %ah # Check EGA/VGA
149 movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
150 cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
154 movw $0x1a00, %ax # Check EGA or VGA?
156 cmpb $0x1a, %al # 1a means VGA...
157 jne basret # anything else is EGA.
159 incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
163 # Store the video mode parameters for later usage by the kernel.
164 # This is done by asking the BIOS except for the rows/columns
165 # parameters in the default 80x25 mode -- these are set directly,
166 # because some very obscure BIOSes supply insane values.
168 #ifdef CONFIG_VIDEO_SELECT
169 cmpb $0, graphic_mode
172 movb $0x03, %ah # Read cursor position
175 movw %dx, %fs:(PARAM_CURSOR_POS)
176 movb $0x0f, %ah # Read page/mode/width
178 movw %bx, %fs:(PARAM_VIDEO_PAGE)
179 movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
180 cmpb $0x7, %al # MDA/HGA => segment differs
183 movw $0xb000, video_segment
184 mopar0: movw %gs:(0x485), %ax # Font size
185 movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
186 movw force_size, %ax # Forced size?
190 movb %ah, %fs:(PARAM_VIDEO_COLS)
191 movb %al, %fs:(PARAM_VIDEO_LINES)
194 mopar1: movb $25, %al
195 cmpb $0, adapter # If we are on CGA/MDA/HGA, the
196 jz mopar2 # screen must have 25 lines.
198 movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
199 incb %al # location of max lines.
200 mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
203 #ifdef CONFIG_VIDEO_SELECT
204 # Fetching of VESA frame buffer parameters
206 leaw modelist+1024, %di
207 movb $0x23, %fs:(PARAM_HAVE_VGA)
209 movw %ax, %fs:(PARAM_LFB_LINELENGTH)
211 movw %ax, %fs:(PARAM_LFB_WIDTH)
213 movw %ax, %fs:(PARAM_LFB_HEIGHT)
216 movw %ax, %fs:(PARAM_LFB_DEPTH)
219 movw %ax, %fs:(PARAM_LFB_PAGES)
221 movl %eax, %fs:(PARAM_LFB_BASE)
223 movl %eax, %fs:(PARAM_LFB_COLORS)
225 movl %eax, %fs:(PARAM_LFB_COLORS+4)
227 movw %ax, %fs:(PARAM_VESA_ATTRIB)
230 leaw modelist+1024, %di
235 movl %eax, %fs:(PARAM_LFB_SIZE)
237 # store mode capabilities
239 movl %eax, %fs:(PARAM_CAPABILITIES)
241 # switching the DAC to 8-bit is for <= 8 bpp only
242 movw %fs:(PARAM_LFB_DEPTH), %ax
246 # get DAC switching capability
252 # attempt to switch DAC to 8-bit
258 movb %bh, dac_size # store actual DAC size
261 # set color size to DAC size
263 movb %al, %fs:(PARAM_LFB_COLORS+0)
264 movb %al, %fs:(PARAM_LFB_COLORS+2)
265 movb %al, %fs:(PARAM_LFB_COLORS+4)
266 movb %al, %fs:(PARAM_LFB_COLORS+6)
268 # set color offsets to 0
269 movb $0, %fs:(PARAM_LFB_COLORS+1)
270 movb $0, %fs:(PARAM_LFB_COLORS+3)
271 movb $0, %fs:(PARAM_LFB_COLORS+5)
272 movb $0, %fs:(PARAM_LFB_COLORS+7)
275 # get protected mode interface informations
283 movw %es, %fs:(PARAM_VESAPM_SEG)
284 movw %di, %fs:(PARAM_VESAPM_OFF)
287 # The video mode menu
289 leaw keymsg, %si # "Return/Space/Timeout" message
294 cmpb $0x0d, %al # ENTER ?
295 je listm # yes - manual mode selection
297 cmpb $0x20, %al # SPACE ?
298 je defmd1 # no - repeat
303 defmd1: ret # No mode chosen? Default 80x25
305 listm: call mode_table # List mode table
306 listm0: leaw name_bann, %si # Print adapter name
327 leaw listhdr, %si # Table header
329 movb $0x30, %dl # DL holds mode number
331 lm1: cmpw $ASK_VGA, (%si) # End?
334 movb %dl, %al # Menu selection number
342 movb $0x78, %al # the letter 'x'
345 call prtdec # Columns
346 movb $0x0d, %al # New line
350 incb %dl # Next character
357 lm2: leaw prompt, %si # Mode prompt
359 leaw edit_buf, %di # Editor buffer
361 cmpb $0x0d, %al # Enter?
364 cmpb $0x08, %al # Backspace?
367 cmpb $0x20, %al # Printable?
370 cmpw $edit_buf+4, %di # Enough space?
377 lmbs: cmpw $edit_buf, %di # Backspace
388 lment: movb $0, (%di)
392 cmpb $0, (%si) # Empty string = default mode
395 cmpb $0, 1(%si) # One character = menu selection
398 cmpw $0x6373, (%si) # "scan" => mode scanning
404 lmhx: xorw %bx, %bx # Else => mode ID in hex
427 lmuse1: movw %bx, %ax
430 mnusel: lodsb # Menu selection
441 subb $0x61-0x30-10, %al
448 lmbad: leaw unknt, %si
451 lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
454 movw $0, mt_end # Scanning of modes is
455 movb $1, scanning # done as new autodetection.
460 # Additional parts of mode_set... (relative jumps, you know)
461 setv7: # Video7 extended modes
463 subb $VIDEO_FIRST_V7>>8, %bh
469 _setrec: jmp setrec # Ugly...
470 _set_80x25: jmp set_80x25
472 # Aliases for backward compatibility.
474 movw $VIDEO_80x25, %ax
478 movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
480 jnz setbad # Fall-through!
482 # Setting of user mode (AX=mode ID) => CF=success
484 movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
489 testb $VIDEO_RECALC>>8, %ah
492 cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
495 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
498 cmpb $VIDEO_FIRST_V7>>8, %ah
501 cmpb $VIDEO_FIRST_VESA>>8, %ah
511 movb $0, do_restore # The screen needn't be restored
516 subb $VIDEO_FIRST_VESA>>8, %bh
517 movw $0x4f02, %ax # VESA BIOS mode set call
519 cmpw $0x004f, %ax # AL=4f if implemented
520 jnz setbad # AH=0 if OK
527 int $0x10 # Standard BIOS mode set call
529 movb $0x0f, %ah # Check if really set
538 setspc: xorb %bh, %bh # Set special mode
539 cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
546 orb %al, %al # 80x25 is an exception
549 pushw %bx # Set mode chosen from menu
550 call mode_table # Build the mode table
557 movw (%si), %ax # Fetch mode ID
560 setres: pushw %bx # Set mode chosen by resolution
565 cmpw $ASK_VGA, %ax # End of the list?
572 movw -4(%si), %ax # Fetch mode ID
576 leaw modelist+1024, %di
577 subb $VIDEO_FIRST_VESA>>8, %bh
578 movw %bx, %cx # Get mode information structure
581 addb $VIDEO_FIRST_VESA>>8, %bh
585 movb (%di), %al # Check capabilities.
588 jz setvesa # This is a text mode
590 movb (%di), %al # Check capabilities.
593 jnz _setbad # Doh! No linear frame buffer.
595 subb $VIDEO_FIRST_VESA>>8, %bh
596 orw $0x4000, %bx # Use linear frame buffer
597 movw $0x4f02, %ax # VESA BIOS mode set call
599 cmpw $0x004f, %ax # AL=4f if implemented
600 jnz _setbad # AH=0 if OK
602 movb $1, graphic_mode # flag graphic mode
603 movb $0, do_restore # no screen restore
607 _setbad: jmp setbad # Ugly...
609 # Recalculate vertical display end registers -- this fixes various
610 # inconsistencies of extended modes on many adapters. Called when
611 # the VIDEO_RECALC flag is set in the mode ID.
613 setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
617 movw %gs:(0x485), %ax # Font size in pixels
618 movb %gs:(0x484), %bl # Number of rows
620 mulb %bl # Number of visible
621 decw %ax # scan lines - 1
624 movb $0x12, %al # Lower 8 bits
627 movb $0x07, %al # Bits 8 and 9 in the overflow register
637 rct2: movb $0x07, %al
642 # Table of routines for setting of the special modes.
654 # Set the 80x25 mode. If already set, do nothing.
656 movw $0x5019, force_size # Override possibly broken BIOS
658 #ifdef CONFIG_VIDEO_400_HACK
659 movw $0x1202, %ax # Force 400 scan lines
663 movb $0x0f, %ah # Get current mode ID
665 cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
666 jz st80 # on CGA/MDA/HGA and is also available on EGAM
668 cmpw $0x5003, %ax # Unknown mode, force 80x25 color
671 st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
674 movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
675 orb %al, %al # Some buggy BIOS'es set 0 rows
678 cmpb $24, %al # It's hopefully correct
680 #endif /* CONFIG_VIDEO_400_HACK */
682 movw $0x0003, %ax # Forced set
687 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
690 call use_80x25 # The base is 80x25
692 movw $0x1112, %ax # Use 8x8 font
695 movw $0x1200, %ax # Use alternate print screen
698 movw $0x1201, %ax # Turn off cursor emulation
701 movb $0x01, %ah # Define cursor scan lines 6-7
708 # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
709 # 80x25 mode with 14-point fonts instead of 16-point.
712 call use_80x25 # The base is 80x25
713 set14: movw $0x1111, %ax # Use 9x14 font
716 movb $0x01, %ah # Define cursor scan lines 11-12
722 # Set the 80x43 mode. This mode is works on all VGA's.
723 # It's a 350-scanline mode with 8-pixel font.
726 movw $0x1201, %ax # Set 350 scans
729 movw $0x0003, %ax # Reset video mode
731 jmp set_8pt # Use 8-pixel font
733 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
735 call use_80x25 # Start with real 80x25
737 movw $0x3cc, %dx # Get CRTC port
740 rorb %al # Mono or color?
744 set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
746 movw $0x0b06, %ax # Vertical total
748 movw $0x3e07, %ax # (Vertical) overflow
750 movw $0xea10, %ax # Vertical sync start
752 movw $0xdf12, %ax # Vertical display end
754 movw $0xe715, %ax # Vertical blank start
756 movw $0x0416, %ax # Vertical blank end
759 movb $0xcc, %dl # Misc output register (read)
761 movb $0xc2, %dl # (write)
762 andb $0x0d, %al # Preserve clock select bits and color bit
763 orb $0xe2, %al # Set correct sync polarity
766 movw $0x501e, force_size
770 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
772 call set_80x30 # Set 480 scans
773 call set14 # And 14-pt font
774 movw $0xdb12, %ax # VGA vertical display end
775 movw $0x5022, force_size
780 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
782 call set_80x30 # Set 480 scans
783 call set_8pt # And 8-pt font
784 movw $0xdf12, %ax # VGA vertical display end
785 movw $0x503c, force_size
788 # Special hack for ThinkPad graphics
790 #ifdef CONFIG_VIDEO_GFX_HACK
791 movw $VIDEO_GFX_BIOS_AX, %ax
792 movw $VIDEO_GFX_BIOS_BX, %bx
794 movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
799 #ifdef CONFIG_VIDEO_RETAIN
801 # Store screen contents to temporary buffer.
803 cmpb $0, do_restore # Already stored?
806 testb $CAN_USE_HEAP, loadflags # Have we space for storing?
811 pushw force_size # Don't force specific size
813 call mode_params # Obtain params of current mode
815 movb %fs:(PARAM_VIDEO_LINES), %ah
816 movb %fs:(PARAM_VIDEO_COLS), %al
817 movw %ax, %bx # BX=dimensions
819 movw %ax, %cx # CX=number of characters
820 addw %ax, %ax # Calculate image size
821 addw $modelist+1024+4, %ax
822 cmpw heap_end_ptr, %ax
823 jnc sts1 # Unfortunately, out of memory
825 movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
826 leaw modelist+1024, %di
830 pushw %ds # Store the screen
831 movw video_segment, %ds
836 incb do_restore # Screen will be restored later
841 # Restore screen contents from temporary buffer.
843 cmpb $0, do_restore # Has the screen been stored?
846 call mode_params # Get parameters of current mode
847 movb %fs:(PARAM_VIDEO_LINES), %cl
848 movb %fs:(PARAM_VIDEO_COLS), %ch
849 leaw modelist+1024, %si # Screen buffer
850 lodsw # Set cursor position
862 res3: movb $0x02, %ah
866 movb %ah, %dl # DL=number of lines
867 movb $0, %ah # BX=phys. length of orig. line
869 cmpb %cl, %dl # Too many?
880 res4: cmpb %ch, %al # Too wide?
883 movb %ch, %al # AX=width of src. line
886 movw %cx, %bp # BP=width of dest. line
888 movw video_segment, %es
889 xorw %di, %di # Move the data
890 addw %bx, %bx # Convert BX and BP to _bytes_
906 #endif /* CONFIG_VIDEO_RETAIN */
908 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
909 outidx: outb %al, %dx
918 # Build the table of video modes (stored after the setup.S code at the
919 # `modelist' label. Each video mode record looks like:
920 # .word MODE-ID (our special mode ID (see above))
921 # .byte rows (number of rows)
922 # .byte columns (number of columns)
923 # Returns address of the end of the table in DI, the end is marked
926 movw mt_end, %di # Already filled?
930 leaw modelist, %di # Store standard modes:
931 movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
933 movb adapter, %al # CGA/MDA/HGA -- no more modes
940 movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
946 mtabv: leaw vga_modes, %si # All modes for std VGA
947 movw $vga_modes_end-vga_modes, %cx
948 rep # I'm unable to use movsw as I don't know how to store a half
949 movsb # of the expression above to cx without using explicit shr.
951 cmpb $0, scanning # Mode scan requested?
957 #ifdef CONFIG_VIDEO_LOCAL
959 #endif /* CONFIG_VIDEO_LOCAL */
961 #ifdef CONFIG_VIDEO_VESA
962 call vesa_modes # Detect VESA VGA modes
963 #endif /* CONFIG_VIDEO_VESA */
965 #ifdef CONFIG_VIDEO_SVGA
966 cmpb $0, scanning # Bypass when scanning
969 call svga_modes # Detect SVGA cards & modes
971 #endif /* CONFIG_VIDEO_SVGA */
975 #ifdef CONFIG_VIDEO_COMPACT
979 cmt1: cmpw %dx, %si # Scan all modes
982 leaw modelist, %bx # Find in previous entries
987 cmpw 2(%bx), %cx # Found => don't copy this entry
993 cmt4: movsl # Copy entry
996 cmt5: addw $4, %si # Skip entry
1000 #endif /* CONFIG_VIDEO_COMPACT */
1002 movw $ASK_VGA, (%di) # End marker
1004 mtab1: leaw modelist, %si # SI=mode list, DI=list end
1007 # Modes usable on all standard VGAs
1010 .word 0x5032 # 80x50
1012 .word 0x502b # 80x43
1014 .word 0x501c # 80x28
1016 .word 0x501e # 80x30
1018 .word 0x5022 # 80x34
1020 .word 0x503c # 80x60
1021 #ifdef CONFIG_VIDEO_GFX_HACK
1022 .word VIDEO_GFX_HACK
1023 .word VIDEO_GFX_DUMMY_RESOLUTION
1027 # Detect VESA modes.
1029 #ifdef CONFIG_VIDEO_VESA
1031 cmpb $2, adapter # VGA only
1034 movw %di, %bp # BP=original mode table end
1035 addw $0x200, %di # Buffer space
1036 movw $0x4f00, %ax # VESA Get card info call
1039 cmpw $0x004f, %ax # Successful?
1042 cmpw $0x4556, 0x200(%di)
1045 cmpw $0x4153, 0x202(%di)
1048 movw $vesa_name, card_name # Set name to "VESA VGA"
1050 lgsw 0x20e(%di), %si # GS:SI=mode list
1051 movw $128, %cx # Iteration limit
1053 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
1054 # XXX: lodsw %gs:(%si), %ax # Get next mode in the list
1056 cmpw $0xffff, %ax # End of the table?
1059 cmpw $0x0080, %ax # Check validity of mode ID
1062 orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
1063 jz vesan # Certain BIOSes report 0x80-0xff!
1069 movw %ax, %cx # Get mode information structure
1072 movw %cx, %bx # BX=mode number
1073 addb $VIDEO_FIRST_VESA>>8, %bh
1076 jnz vesan # Don't report errors (buggy BIOSES)
1078 movb (%di), %al # Check capabilities. We require
1079 andb $0x19, %al # a color text mode.
1083 cmpw $0xb800, 8(%di) # Standard video memory address required
1086 testb $2, (%di) # Mode characteristics supplied?
1087 movw %bx, (%di) # Store mode number
1091 movw 0x12(%di), %bx # Width
1096 movw 0x14(%di), %ax # Height
1102 cmpw $8193, %ax # Small enough for Linux console driver?
1107 vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
1108 jc vesan # so it must be a standard VESA mode.
1113 movw vesa_text_mode_table(%bx), %ax
1115 vesaok: addw $4, %di # The mode is valid. Store it.
1116 vesan: loop vesa1 # Next mode. Limit exceeded => error
1117 vesae: leaw vesaer, %si
1119 movw %bp, %di # Discard already found modes.
1123 # Dimensions of standard VESA text modes
1124 vesa_text_mode_table:
1126 .byte 25, 132 # 0109
1127 .byte 43, 132 # 010A
1128 .byte 50, 132 # 010B
1129 .byte 60, 132 # 010C
1130 #endif /* CONFIG_VIDEO_VESA */
1132 # Scan for video modes. A bit dirty, but should work.
1134 movw $0x0100, %cx # Start with mode 0
1135 scm1: movb $0, %ah # Test the mode
1141 jnz scm2 # Mode not set
1143 movw $0x3c0, %dx # Test if it's a text mode
1144 movb $0x10, %al # Mode bits
1149 movb $0xce, %dl # Another set of mode bits
1155 movb $0xd4, %dl # Cursor location
1161 movw %cx, %ax # Ok, store the mode
1163 movb %gs:(0x484), %al # Number of rows
1166 movw %gs:(0x44a), %ax # Number of columns
1171 movw $0x0003, %ax # Return back to mode 3
1175 tstidx: outw %ax, %dx # OUT DX,AX and inidx
1176 inidx: outb %al, %dx # Read from indexed VGA register
1177 incw %dx # AL=index, DX=index reg port -> AL=data
1182 # Try to detect type of SVGA card and supply (usually approximate) video
1183 # mode table for it.
1185 #ifdef CONFIG_VIDEO_SVGA
1187 leaw svga_table, %si # Test all known SVGA adapters
1189 movw %ax, %bp # Default mode table
1193 lodsw # Pointer to test routine
1199 call *%ax # Call test routine
1206 movw %bp, %si # Found, copy the modes
1207 movb svga_prefix, %ah
1216 didsv: movw %si, card_name # Store pointer to card name
1219 # Table of all known SVGA cards. For each card, we store a pointer to
1220 # a table of video modes supported by the card and a pointer to a routine
1221 # used for testing of presence of the card. The video mode table is always
1222 # followed by the name of the card or the chipset.
1224 .word ati_md, ati_test
1225 .word oak_md, oak_test
1226 .word paradise_md, paradise_test
1227 .word realtek_md, realtek_test
1228 .word s3_md, s3_test
1229 .word chips_md, chips_test
1230 .word video7_md, video7_test
1231 .word cirrus5_md, cirrus5_test
1232 .word cirrus6_md, cirrus6_test
1233 .word cirrus1_md, cirrus1_test
1234 .word ahead_md, ahead_test
1235 .word everex_md, everex_test
1236 .word genoa_md, genoa_test
1237 .word trident_md, trident_test
1238 .word tseng_md, tseng_test
1241 # Test routines and mode tables:
1243 # S3 - The test algorithm was taken from the SuperProbe package
1244 # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
1246 movw $0x0f35, %cx # we store some constants in cl/ch
1250 movb %al, %bh # store current CRT-register 0x38
1252 call outidx # disable writing to special regs
1253 movb %cl, %al # check whether we can write special reg 0x35
1255 movb %al, %bl # save the current value of CRT reg 0x35
1256 andb $0xf0, %al # clear bits 0-3
1258 movb %cl, %al # and write it to CRT reg 0x35
1260 call inidx # now read it back
1261 andb %ch, %al # clear the upper 4 bits
1262 jz s3_2 # the first test failed. But we have a
1264 movb %bl, %ah # second chance
1267 jmp s3_1 # do the other tests
1269 s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
1270 orb %bl, %ah # set the upper 4 bits of ah with the orig value
1271 call outidx # write ...
1272 call inidx # ... and reread
1273 andb %cl, %al # turn off the upper 4 bits
1275 movb %bl, %ah # restore old value in register 0x35
1279 cmpb %ch, %al # setting lower 4 bits was successful => bad
1280 je no_s3 # writing is allowed => this is not an S3
1282 s3_1: movw $0x4838, %ax # allow writing to special regs by putting
1283 call outidx # magic number into CRT-register 0x38
1284 movb %cl, %al # check whether we can write special reg 0x35
1293 jnz no_s3 # no, we can't write => no S3
1301 movb %bl, %ah # restore old value in register 0x35
1306 jne no_s31 # writing not possible => no S3
1308 call inidx # now get the S3 id ...
1319 no_s3: movb $0x35, %al # restore CRT register 0x35
1322 no_s31: xorw %bp, %bp # Detection failed
1323 s3rest: movb %bh, %ah
1324 movb $0x38, %al # restore old value of CRT register 0x38
1327 idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
1328 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
1330 s3_md: .byte 0x54, 0x2b, 0x84
1331 .byte 0x55, 0x19, 0x84
1348 idati: .ascii "761295520"
1350 ati_md: .byte 0x23, 0x19, 0x84
1351 .byte 0x33, 0x2c, 0x84
1352 .byte 0x22, 0x1e, 0x64
1353 .byte 0x21, 0x19, 0x64
1354 .byte 0x58, 0x21, 0x50
1355 .byte 0x5b, 0x1e, 0x50
1377 .byte 0x22, 0x2c, 0x84
1378 .byte 0x23, 0x19, 0x84
1379 .byte 0x24, 0x1c, 0x84
1380 .byte 0x2f, 0x32, 0xa0
1381 .byte 0x32, 0x22, 0x50
1382 .byte 0x34, 0x42, 0x50
1407 .byte 0x60, 0x19, 0x84
1408 .byte 0x61, 0x32, 0x84
1410 .ascii "Chips & Technologies"
1451 nocirr: xorw %bp, %bp
1452 iscirr: movw $0x3d4, %dx
1461 .byte 0x1f, 0x19, 0x84
1462 .byte 0x20, 0x2c, 0x84
1463 .byte 0x22, 0x1e, 0x84
1464 .byte 0x31, 0x25, 0x64
1466 .ascii "Cirrus Logic 5X0"
1474 movb %al, %bl # BL=backup
1508 c5fail: xorw %bp, %bp
1509 c5done: movb $6, %al
1515 .byte 0x14, 0x19, 0x84
1516 .byte 0x54, 0x2b, 0x84
1518 .ascii "Cirrus Logic 54XX"
1521 # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
1522 # it's misidentified by the Ahead test.
1527 movb %al, %bl # BL=backup
1539 call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
1553 c2fail: xorw %bp, %bp
1554 c6done: movb $0x0a, %al
1561 .ascii "Cirrus Logic 64XX"
1579 evtrid: leaw trident_md, %bp
1582 noevrx: xorw %bp, %bp
1586 .byte 0x03, 0x22, 0x50
1587 .byte 0x04, 0x3c, 0x50
1588 .byte 0x07, 0x2b, 0x64
1589 .byte 0x08, 0x4b, 0x64
1590 .byte 0x0a, 0x19, 0x84
1591 .byte 0x0b, 0x2c, 0x84
1592 .byte 0x16, 0x1e, 0x50
1593 .byte 0x18, 0x1b, 0x64
1594 .byte 0x21, 0x40, 0xa0
1595 .byte 0x40, 0x1e, 0x84
1597 .ascii "Everex/Trident"
1602 leaw idgenoa, %si # Check Genoa 'clues'
1604 movb %es:(0x37), %al
1623 idgenoa: .byte 0x77, 0x00, 0x99, 0x66
1626 .byte 0x58, 0x20, 0x50
1627 .byte 0x5a, 0x2a, 0x64
1628 .byte 0x60, 0x19, 0x84
1629 .byte 0x61, 0x1d, 0x84
1630 .byte 0x62, 0x20, 0x84
1631 .byte 0x63, 0x2c, 0x84
1632 .byte 0x64, 0x3c, 0x84
1633 .byte 0x6b, 0x4f, 0x64
1634 .byte 0x72, 0x3c, 0x50
1635 .byte 0x74, 0x42, 0x50
1636 .byte 0x78, 0x4b, 0x64
1653 idoakvga: .ascii "OAK VGA "
1655 oak_md: .byte 0x4e, 0x3c, 0x50
1656 .byte 0x4f, 0x3c, 0x84
1657 .byte 0x50, 0x19, 0x84
1658 .byte 0x51, 0x2b, 0x84
1665 leaw idparadise, %si
1675 idparadise: .ascii "VGA="
1678 .byte 0x41, 0x22, 0x50
1679 .byte 0x47, 0x1c, 0x84
1680 .byte 0x55, 0x19, 0x84
1681 .byte 0x54, 0x2c, 0x84
1698 movb %al, %bl # Strange thing ... in the book this wasn't
1699 andb $0x02, %bl # necessary but it worked on my card which
1700 jz setb2 # is a trident. Without it the screen goes
1705 setb2: orb $0x02, %al
1706 clrb2: outb %al, %dx
1715 .byte 0x50, 0x1e, 0x50
1716 .byte 0x51, 0x2b, 0x50
1717 .byte 0x52, 0x3c, 0x50
1718 .byte 0x57, 0x19, 0x84
1719 .byte 0x58, 0x1e, 0x84
1720 .byte 0x59, 0x2b, 0x84
1721 .byte 0x5a, 0x3c, 0x84
1729 inb %dx, %al # Could things be this simple ! :-)
1740 isnot: xorw %bp, %bp
1744 .byte 0x26, 0x3c, 0x50
1745 .byte 0x2a, 0x28, 0x64
1746 .byte 0x23, 0x19, 0x84
1747 .byte 0x24, 0x1c, 0x84
1748 .byte 0x22, 0x2c, 0x84
1749 .byte 0x21, 0x3c, 0x84
1763 even7: movb $0x0c, %al
1788 movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
1792 .byte 0x40, 0x2b, 0x50
1793 .byte 0x43, 0x3c, 0x50
1794 .byte 0x44, 0x3c, 0x64
1795 .byte 0x41, 0x19, 0x84
1796 .byte 0x42, 0x2c, 0x84
1797 .byte 0x45, 0x1c, 0x84
1814 idrtvga: .ascii "REALTEK VGA"
1817 .byte 0x1a, 0x3c, 0x50
1818 .byte 0x1b, 0x19, 0x84
1819 .byte 0x1c, 0x1e, 0x84
1820 .byte 0x1d, 0x2b, 0x84
1821 .byte 0x1e, 0x3c, 0x84
1826 #endif /* CONFIG_VIDEO_SVGA */
1828 # User-defined local mode table (VGA only)
1829 #ifdef CONFIG_VIDEO_LOCAL
1831 leaw local_mode_table, %si
1842 # This is the table of local video modes which can be supplied manually
1843 # by the user. Each entry consists of mode ID (word) and dimensions
1844 # (byte for column count and another byte for row count). These modes
1845 # are placed before all SVGA and VESA modes and override them if table
1846 # compacting is enabled. The table must end with a zero word followed
1847 # by NUL-terminated video adapter name.
1849 .word 0x0100 # Example: 40x25
1854 #endif /* CONFIG_VIDEO_LOCAL */
1856 # Read a key and return the ASCII code in al, scan code in ah
1857 getkey: xorb %ah, %ah
1861 # Read a key with a timeout of 30 seconds.
1862 # The hardware clock is used to get the time.
1864 addb $30, %al # Wait 30 seconds
1871 again: movb $0x01, %ah
1873 jnz getkey # key pressed, so get it
1879 movb $0x20, %al # timeout, return `space'
1882 # Flush the keyboard buffer
1883 flush: movb $0x01, %ah
1893 # Print hexadecimal number.
1903 prthn: cmpb $0x0a, %al
1907 prth1: addb $0x30, %al
1910 # Print decimal number in al
1922 lt100: addb $0x30, %al
1924 skip10: movb %ah, %al
1932 pushw %es # just save all registers
1942 movl $0x13131313, %eax # memset block with 0x13
1949 movw $0x4f15, %ax # do VBE/DDC
1956 popw %di # restore all registers
1964 # VIDEO_SELECT-only variables
1965 mt_end: .word 0 # End of video mode table if built
1966 edit_buf: .space 6 # Line editor buffer
1967 card_name: .word 0 # Pointer to adapter name
1968 scanning: .byte 0 # Performing mode scan
1969 do_restore: .byte 0 # Screen contents altered during mode change
1970 svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
1971 graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
1972 dac_size: .byte 6 # DAC bit depth
1975 keymsg: .ascii "Press <RETURN> to see video modes available, "
1976 .ascii "<SPACE> to continue or wait 30 secs"
1979 listhdr: .byte 0x0d, 0x0a
1980 .ascii "Mode: COLSxROWS:"
1982 crlft: .byte 0x0d, 0x0a, 0
1984 prompt: .byte 0x0d, 0x0a
1985 .asciz "Enter mode number or `scan': "
1987 unknt: .asciz "Unknown mode ID. Try again."
1989 badmdt: .ascii "You passed an undefined mode number."
1992 vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
1993 .ascii "report to <mj@ucw.cz>."
1996 old_name: .asciz "CGA/MDA/HGA"
1998 ega_name: .asciz "EGA"
2000 svga_name: .ascii " "
2002 vga_name: .asciz "VGA"
2004 vesa_name: .asciz "VESA"
2006 name_bann: .asciz "Video adapter: "
2007 #endif /* CONFIG_VIDEO_SELECT */
2010 adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
2011 video_segment: .word 0xb800 # Video memory segment
2012 force_size: .word 0 # Use this size instead of the one in BIOS vars