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 /* Enable autodetection of SVGA adapters and modes. */
15 #undef CONFIG_VIDEO_SVGA
17 /* Enable autodetection of VESA modes */
18 #define CONFIG_VIDEO_VESA
20 /* Enable compacting of mode table */
21 #define CONFIG_VIDEO_COMPACT
23 /* Retain screen contents when switching modes */
24 #define CONFIG_VIDEO_RETAIN
26 /* Enable local mode list */
27 #undef CONFIG_VIDEO_LOCAL
29 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
30 #undef CONFIG_VIDEO_400_HACK
32 /* Hack that lets you force specific BIOS mode ID and specific dimensions */
33 #undef CONFIG_VIDEO_GFX_HACK
34 #define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
35 #define VIDEO_GFX_BIOS_BX 0x0102
36 #define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
38 /* This code uses an extended set of video mode numbers. These include:
39 * Aliases for standard modes
43 * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
44 * of compatibility when extending the table. These are between 0x00 and 0xff.
46 #define VIDEO_FIRST_MENU 0x0000
48 /* Standard BIOS video modes (BIOS number + 0x0100) */
49 #define VIDEO_FIRST_BIOS 0x0100
51 /* VESA BIOS video modes (VESA number + 0x0200) */
52 #define VIDEO_FIRST_VESA 0x0200
54 /* Video7 special modes (BIOS number + 0x0900) */
55 #define VIDEO_FIRST_V7 0x0900
57 /* Special video modes */
58 #define VIDEO_FIRST_SPECIAL 0x0f00
59 #define VIDEO_80x25 0x0f00
60 #define VIDEO_8POINT 0x0f01
61 #define VIDEO_80x43 0x0f02
62 #define VIDEO_80x28 0x0f03
63 #define VIDEO_CURRENT_MODE 0x0f04
64 #define VIDEO_80x30 0x0f05
65 #define VIDEO_80x34 0x0f06
66 #define VIDEO_80x60 0x0f07
67 #define VIDEO_GFX_HACK 0x0f08
68 #define VIDEO_LAST_SPECIAL 0x0f09
70 /* Video modes given by resolution */
71 #define VIDEO_FIRST_RESOLUTION 0x1000
73 /* The "recalculate timings" flag */
74 #define VIDEO_RECALC 0x8000
76 /* Positions of various video parameters passed to the kernel */
77 /* (see also include/linux/tty.h) */
78 #define PARAM_CURSOR_POS 0x00
79 #define PARAM_VIDEO_PAGE 0x04
80 #define PARAM_VIDEO_MODE 0x06
81 #define PARAM_VIDEO_COLS 0x07
82 #define PARAM_VIDEO_EGA_BX 0x0a
83 #define PARAM_VIDEO_LINES 0x0e
84 #define PARAM_HAVE_VGA 0x0f
85 #define PARAM_FONT_POINTS 0x10
87 #define PARAM_LFB_WIDTH 0x12
88 #define PARAM_LFB_HEIGHT 0x14
89 #define PARAM_LFB_DEPTH 0x16
90 #define PARAM_LFB_BASE 0x18
91 #define PARAM_LFB_SIZE 0x1c
92 #define PARAM_LFB_LINELENGTH 0x24
93 #define PARAM_LFB_COLORS 0x26
94 #define PARAM_VESAPM_SEG 0x2e
95 #define PARAM_VESAPM_OFF 0x30
96 #define PARAM_LFB_PAGES 0x32
97 #define PARAM_VESA_ATTRIB 0x34
98 #define PARAM_CAPABILITIES 0x36
100 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
101 #ifdef CONFIG_VIDEO_RETAIN
102 #define DO_STORE call store_screen
105 #endif /* CONFIG_VIDEO_RETAIN */
107 # This is the main entry point called by setup.S
108 # %ds *must* be pointing to the bootsector
109 video: pushw %ds # We use different segments
110 pushw %ds # FS contains original DS
112 pushw %cs # DS is equal to CS
114 pushw %cs # ES is equal to CS
117 movw %ax, %gs # GS is zero
119 call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
120 #ifdef CONFIG_VIDEO_SELECT
121 movw %fs:(0x01fa), %ax # User selected video mode
122 cmpw $ASK_VGA, %ax # Bring up the menu
125 call mode_set # Set the mode
128 leaw badmdt, %si # Invalid mode ID
132 #ifdef CONFIG_VIDEO_RETAIN
133 call restore_screen # Restore screen contents
134 #endif /* CONFIG_VIDEO_RETAIN */
136 #endif /* CONFIG_VIDEO_SELECT */
137 call mode_params # Store mode parameters
138 popw %ds # Restore original DS
141 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
143 movb $0, %fs:(PARAM_HAVE_VGA)
144 movb $0x12, %ah # Check EGA/VGA
147 movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
148 cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
152 movw $0x1a00, %ax # Check EGA or VGA?
154 cmpb $0x1a, %al # 1a means VGA...
155 jne basret # anything else is EGA.
157 incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
161 # Store the video mode parameters for later usage by the kernel.
162 # This is done by asking the BIOS except for the rows/columns
163 # parameters in the default 80x25 mode -- these are set directly,
164 # because some very obscure BIOSes supply insane values.
166 #ifdef CONFIG_VIDEO_SELECT
167 cmpb $0, graphic_mode
170 movb $0x03, %ah # Read cursor position
173 movw %dx, %fs:(PARAM_CURSOR_POS)
174 movb $0x0f, %ah # Read page/mode/width
176 movw %bx, %fs:(PARAM_VIDEO_PAGE)
177 movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
178 cmpb $0x7, %al # MDA/HGA => segment differs
181 movw $0xb000, video_segment
182 mopar0: movw %gs:(0x485), %ax # Font size
183 movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
184 movw force_size, %ax # Forced size?
188 movb %ah, %fs:(PARAM_VIDEO_COLS)
189 movb %al, %fs:(PARAM_VIDEO_LINES)
192 mopar1: movb $25, %al
193 cmpb $0, adapter # If we are on CGA/MDA/HGA, the
194 jz mopar2 # screen must have 25 lines.
196 movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
197 incb %al # location of max lines.
198 mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
201 #ifdef CONFIG_VIDEO_SELECT
202 # Fetching of VESA frame buffer parameters
204 leaw modelist+1024, %di
205 movb $0x23, %fs:(PARAM_HAVE_VGA)
207 movw %ax, %fs:(PARAM_LFB_LINELENGTH)
209 movw %ax, %fs:(PARAM_LFB_WIDTH)
211 movw %ax, %fs:(PARAM_LFB_HEIGHT)
214 movw %ax, %fs:(PARAM_LFB_DEPTH)
217 movw %ax, %fs:(PARAM_LFB_PAGES)
219 movl %eax, %fs:(PARAM_LFB_BASE)
221 movl %eax, %fs:(PARAM_LFB_COLORS)
223 movl %eax, %fs:(PARAM_LFB_COLORS+4)
225 movw %ax, %fs:(PARAM_VESA_ATTRIB)
228 leaw modelist+1024, %di
233 movl %eax, %fs:(PARAM_LFB_SIZE)
235 # store mode capabilities
237 movl %eax, %fs:(PARAM_CAPABILITIES)
239 # switching the DAC to 8-bit is for <= 8 bpp only
240 movw %fs:(PARAM_LFB_DEPTH), %ax
244 # get DAC switching capability
250 # attempt to switch DAC to 8-bit
256 movb %bh, dac_size # store actual DAC size
259 # set color size to DAC size
261 movb %al, %fs:(PARAM_LFB_COLORS+0)
262 movb %al, %fs:(PARAM_LFB_COLORS+2)
263 movb %al, %fs:(PARAM_LFB_COLORS+4)
264 movb %al, %fs:(PARAM_LFB_COLORS+6)
266 # set color offsets to 0
267 movb $0, %fs:(PARAM_LFB_COLORS+1)
268 movb $0, %fs:(PARAM_LFB_COLORS+3)
269 movb $0, %fs:(PARAM_LFB_COLORS+5)
270 movb $0, %fs:(PARAM_LFB_COLORS+7)
273 # get protected mode interface informations
281 movw %es, %fs:(PARAM_VESAPM_SEG)
282 movw %di, %fs:(PARAM_VESAPM_OFF)
285 # The video mode menu
287 leaw keymsg, %si # "Return/Space/Timeout" message
292 cmpb $0x0d, %al # ENTER ?
293 je listm # yes - manual mode selection
295 cmpb $0x20, %al # SPACE ?
296 je defmd1 # no - repeat
301 defmd1: ret # No mode chosen? Default 80x25
303 listm: call mode_table # List mode table
304 listm0: leaw name_bann, %si # Print adapter name
325 leaw listhdr, %si # Table header
327 movb $0x30, %dl # DL holds mode number
329 lm1: cmpw $ASK_VGA, (%si) # End?
332 movb %dl, %al # Menu selection number
340 movb $0x78, %al # the letter 'x'
343 call prtdec # Columns
344 movb $0x0d, %al # New line
348 incb %dl # Next character
355 lm2: leaw prompt, %si # Mode prompt
357 leaw edit_buf, %di # Editor buffer
359 cmpb $0x0d, %al # Enter?
362 cmpb $0x08, %al # Backspace?
365 cmpb $0x20, %al # Printable?
368 cmpw $edit_buf+4, %di # Enough space?
375 lmbs: cmpw $edit_buf, %di # Backspace
386 lment: movb $0, (%di)
390 cmpb $0, (%si) # Empty string = default mode
393 cmpb $0, 1(%si) # One character = menu selection
396 cmpw $0x6373, (%si) # "scan" => mode scanning
402 lmhx: xorw %bx, %bx # Else => mode ID in hex
425 lmuse1: movw %bx, %ax
428 mnusel: lodsb # Menu selection
439 subb $0x61-0x30-10, %al
446 lmbad: leaw unknt, %si
449 lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
452 movw $0, mt_end # Scanning of modes is
453 movb $1, scanning # done as new autodetection.
458 # Additional parts of mode_set... (relative jumps, you know)
459 setv7: # Video7 extended modes
461 subb $VIDEO_FIRST_V7>>8, %bh
467 _setrec: jmp setrec # Ugly...
468 _set_80x25: jmp set_80x25
470 # Aliases for backward compatibility.
472 movw $VIDEO_80x25, %ax
476 movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
478 jnz setbad # Fall-through!
480 # Setting of user mode (AX=mode ID) => CF=success
482 movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
487 testb $VIDEO_RECALC>>8, %ah
490 cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
493 cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
496 cmpb $VIDEO_FIRST_V7>>8, %ah
500 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 #ifdef CONFIG_FIRMWARE_EDID
577 leaw modelist+1024, %di
584 movw %ax, vbe_version
586 leaw modelist+1024, %di
587 subb $VIDEO_FIRST_VESA>>8, %bh
588 movw %bx, %cx # Get mode information structure
591 addb $VIDEO_FIRST_VESA>>8, %bh
595 movb (%di), %al # Check capabilities.
598 jz setvesa # This is a text mode
600 movb (%di), %al # Check capabilities.
603 jnz _setbad # Doh! No linear frame buffer.
605 subb $VIDEO_FIRST_VESA>>8, %bh
606 orw $0x4000, %bx # Use linear frame buffer
607 movw $0x4f02, %ax # VESA BIOS mode set call
609 cmpw $0x004f, %ax # AL=4f if implemented
610 jnz _setbad # AH=0 if OK
612 movb $1, graphic_mode # flag graphic mode
613 movb $0, do_restore # no screen restore
617 _setbad: jmp setbad # Ugly...
619 # Recalculate vertical display end registers -- this fixes various
620 # inconsistencies of extended modes on many adapters. Called when
621 # the VIDEO_RECALC flag is set in the mode ID.
623 setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
627 movw %gs:(0x485), %ax # Font size in pixels
628 movb %gs:(0x484), %bl # Number of rows
630 mulb %bl # Number of visible
631 decw %ax # scan lines - 1
634 movb $0x12, %al # Lower 8 bits
637 movb $0x07, %al # Bits 8 and 9 in the overflow register
647 rct2: movb $0x07, %al
652 # Table of routines for setting of the special modes.
664 # Set the 80x25 mode. If already set, do nothing.
666 movw $0x5019, force_size # Override possibly broken BIOS
668 #ifdef CONFIG_VIDEO_400_HACK
669 movw $0x1202, %ax # Force 400 scan lines
673 movb $0x0f, %ah # Get current mode ID
675 cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
676 jz st80 # on CGA/MDA/HGA and is also available on EGAM
678 cmpw $0x5003, %ax # Unknown mode, force 80x25 color
681 st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
684 movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
685 orb %al, %al # Some buggy BIOS'es set 0 rows
688 cmpb $24, %al # It's hopefully correct
690 #endif /* CONFIG_VIDEO_400_HACK */
692 movw $0x0003, %ax # Forced set
697 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
700 call use_80x25 # The base is 80x25
702 movw $0x1112, %ax # Use 8x8 font
705 movw $0x1200, %ax # Use alternate print screen
708 movw $0x1201, %ax # Turn off cursor emulation
711 movb $0x01, %ah # Define cursor scan lines 6-7
718 # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
719 # 80x25 mode with 14-point fonts instead of 16-point.
722 call use_80x25 # The base is 80x25
723 set14: movw $0x1111, %ax # Use 9x14 font
726 movb $0x01, %ah # Define cursor scan lines 11-12
732 # Set the 80x43 mode. This mode is works on all VGA's.
733 # It's a 350-scanline mode with 8-pixel font.
736 movw $0x1201, %ax # Set 350 scans
739 movw $0x0003, %ax # Reset video mode
741 jmp set_8pt # Use 8-pixel font
743 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
745 call use_80x25 # Start with real 80x25
747 movw $0x3cc, %dx # Get CRTC port
750 rorb %al # Mono or color?
754 set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
756 movw $0x0b06, %ax # Vertical total
758 movw $0x3e07, %ax # (Vertical) overflow
760 movw $0xea10, %ax # Vertical sync start
762 movw $0xdf12, %ax # Vertical display end
764 movw $0xe715, %ax # Vertical blank start
766 movw $0x0416, %ax # Vertical blank end
769 movb $0xcc, %dl # Misc output register (read)
771 movb $0xc2, %dl # (write)
772 andb $0x0d, %al # Preserve clock select bits and color bit
773 orb $0xe2, %al # Set correct sync polarity
776 movw $0x501e, force_size
780 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
782 call set_80x30 # Set 480 scans
783 call set14 # And 14-pt font
784 movw $0xdb12, %ax # VGA vertical display end
785 movw $0x5022, force_size
790 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
792 call set_80x30 # Set 480 scans
793 call set_8pt # And 8-pt font
794 movw $0xdf12, %ax # VGA vertical display end
795 movw $0x503c, force_size
798 # Special hack for ThinkPad graphics
800 #ifdef CONFIG_VIDEO_GFX_HACK
801 movw $VIDEO_GFX_BIOS_AX, %ax
802 movw $VIDEO_GFX_BIOS_BX, %bx
804 movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
809 #ifdef CONFIG_VIDEO_RETAIN
811 # Store screen contents to temporary buffer.
813 cmpb $0, do_restore # Already stored?
816 testb $CAN_USE_HEAP, loadflags # Have we space for storing?
821 pushw force_size # Don't force specific size
823 call mode_params # Obtain params of current mode
825 movb %fs:(PARAM_VIDEO_LINES), %ah
826 movb %fs:(PARAM_VIDEO_COLS), %al
827 movw %ax, %bx # BX=dimensions
829 movw %ax, %cx # CX=number of characters
830 addw %ax, %ax # Calculate image size
831 addw $modelist+1024+4, %ax
832 cmpw heap_end_ptr, %ax
833 jnc sts1 # Unfortunately, out of memory
835 movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
836 leaw modelist+1024, %di
840 pushw %ds # Store the screen
841 movw video_segment, %ds
846 incb do_restore # Screen will be restored later
851 # Restore screen contents from temporary buffer.
853 cmpb $0, do_restore # Has the screen been stored?
856 call mode_params # Get parameters of current mode
857 movb %fs:(PARAM_VIDEO_LINES), %cl
858 movb %fs:(PARAM_VIDEO_COLS), %ch
859 leaw modelist+1024, %si # Screen buffer
860 lodsw # Set cursor position
872 res3: movb $0x02, %ah
876 movb %ah, %dl # DL=number of lines
877 movb $0, %ah # BX=phys. length of orig. line
879 cmpb %cl, %dl # Too many?
890 res4: cmpb %ch, %al # Too wide?
893 movb %ch, %al # AX=width of src. line
896 movw %cx, %bp # BP=width of dest. line
898 movw video_segment, %es
899 xorw %di, %di # Move the data
900 addw %bx, %bx # Convert BX and BP to _bytes_
916 #endif /* CONFIG_VIDEO_RETAIN */
918 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
919 outidx: outb %al, %dx
928 # Build the table of video modes (stored after the setup.S code at the
929 # `modelist' label. Each video mode record looks like:
930 # .word MODE-ID (our special mode ID (see above))
931 # .byte rows (number of rows)
932 # .byte columns (number of columns)
933 # Returns address of the end of the table in DI, the end is marked
936 movw mt_end, %di # Already filled?
940 leaw modelist, %di # Store standard modes:
941 movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
943 movb adapter, %al # CGA/MDA/HGA -- no more modes
950 movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
956 mtabv: leaw vga_modes, %si # All modes for std VGA
957 movw $vga_modes_end-vga_modes, %cx
958 rep # I'm unable to use movsw as I don't know how to store a half
959 movsb # of the expression above to cx without using explicit shr.
961 cmpb $0, scanning # Mode scan requested?
967 #ifdef CONFIG_VIDEO_LOCAL
969 #endif /* CONFIG_VIDEO_LOCAL */
971 #ifdef CONFIG_VIDEO_VESA
972 call vesa_modes # Detect VESA VGA modes
973 #endif /* CONFIG_VIDEO_VESA */
975 #ifdef CONFIG_VIDEO_SVGA
976 cmpb $0, scanning # Bypass when scanning
979 call svga_modes # Detect SVGA cards & modes
981 #endif /* CONFIG_VIDEO_SVGA */
985 #ifdef CONFIG_VIDEO_COMPACT
989 cmt1: cmpw %dx, %si # Scan all modes
992 leaw modelist, %bx # Find in previous entries
997 cmpw 2(%bx), %cx # Found => don't copy this entry
1003 cmt4: movsl # Copy entry
1006 cmt5: addw $4, %si # Skip entry
1010 #endif /* CONFIG_VIDEO_COMPACT */
1012 movw $ASK_VGA, (%di) # End marker
1014 mtab1: leaw modelist, %si # SI=mode list, DI=list end
1017 # Modes usable on all standard VGAs
1020 .word 0x5032 # 80x50
1022 .word 0x502b # 80x43
1024 .word 0x501c # 80x28
1026 .word 0x501e # 80x30
1028 .word 0x5022 # 80x34
1030 .word 0x503c # 80x60
1031 #ifdef CONFIG_VIDEO_GFX_HACK
1032 .word VIDEO_GFX_HACK
1033 .word VIDEO_GFX_DUMMY_RESOLUTION
1037 # Detect VESA modes.
1039 #ifdef CONFIG_VIDEO_VESA
1041 cmpb $2, adapter # VGA only
1044 movw %di, %bp # BP=original mode table end
1045 addw $0x200, %di # Buffer space
1046 movw $0x4f00, %ax # VESA Get card info call
1049 cmpw $0x004f, %ax # Successful?
1052 cmpw $0x4556, 0x200(%di)
1055 cmpw $0x4153, 0x202(%di)
1058 movw $vesa_name, card_name # Set name to "VESA VGA"
1060 lgsw 0x20e(%di), %si # GS:SI=mode list
1061 movw $128, %cx # Iteration limit
1063 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
1064 # XXX: lodsw %gs:(%si), %ax # Get next mode in the list
1066 cmpw $0xffff, %ax # End of the table?
1069 cmpw $0x0080, %ax # Check validity of mode ID
1072 orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
1073 jz vesan # Certain BIOSes report 0x80-0xff!
1079 movw %ax, %cx # Get mode information structure
1082 movw %cx, %bx # BX=mode number
1083 addb $VIDEO_FIRST_VESA>>8, %bh
1086 jnz vesan # Don't report errors (buggy BIOSES)
1088 movb (%di), %al # Check capabilities. We require
1089 andb $0x19, %al # a color text mode.
1093 cmpw $0xb800, 8(%di) # Standard video memory address required
1096 testb $2, (%di) # Mode characteristics supplied?
1097 movw %bx, (%di) # Store mode number
1101 movw 0x12(%di), %bx # Width
1106 movw 0x14(%di), %ax # Height
1112 cmpw $8193, %ax # Small enough for Linux console driver?
1117 vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
1118 jc vesan # so it must be a standard VESA mode.
1123 movw vesa_text_mode_table(%bx), %ax
1125 vesaok: addw $4, %di # The mode is valid. Store it.
1126 vesan: loop vesa1 # Next mode. Limit exceeded => error
1127 vesae: leaw vesaer, %si
1129 movw %bp, %di # Discard already found modes.
1133 # Dimensions of standard VESA text modes
1134 vesa_text_mode_table:
1136 .byte 25, 132 # 0109
1137 .byte 43, 132 # 010A
1138 .byte 50, 132 # 010B
1139 .byte 60, 132 # 010C
1140 #endif /* CONFIG_VIDEO_VESA */
1142 # Scan for video modes. A bit dirty, but should work.
1144 movw $0x0100, %cx # Start with mode 0
1145 scm1: movb $0, %ah # Test the mode
1151 jnz scm2 # Mode not set
1153 movw $0x3c0, %dx # Test if it's a text mode
1154 movb $0x10, %al # Mode bits
1159 movb $0xce, %dl # Another set of mode bits
1165 movb $0xd4, %dl # Cursor location
1171 movw %cx, %ax # Ok, store the mode
1173 movb %gs:(0x484), %al # Number of rows
1176 movw %gs:(0x44a), %ax # Number of columns
1181 movw $0x0003, %ax # Return back to mode 3
1185 tstidx: outw %ax, %dx # OUT DX,AX and inidx
1186 inidx: outb %al, %dx # Read from indexed VGA register
1187 incw %dx # AL=index, DX=index reg port -> AL=data
1192 # Try to detect type of SVGA card and supply (usually approximate) video
1193 # mode table for it.
1195 #ifdef CONFIG_VIDEO_SVGA
1197 leaw svga_table, %si # Test all known SVGA adapters
1199 movw %ax, %bp # Default mode table
1203 lodsw # Pointer to test routine
1209 call *%ax # Call test routine
1216 movw %bp, %si # Found, copy the modes
1217 movb svga_prefix, %ah
1226 didsv: movw %si, card_name # Store pointer to card name
1229 # Table of all known SVGA cards. For each card, we store a pointer to
1230 # a table of video modes supported by the card and a pointer to a routine
1231 # used for testing of presence of the card. The video mode table is always
1232 # followed by the name of the card or the chipset.
1234 .word ati_md, ati_test
1235 .word oak_md, oak_test
1236 .word paradise_md, paradise_test
1237 .word realtek_md, realtek_test
1238 .word s3_md, s3_test
1239 .word chips_md, chips_test
1240 .word video7_md, video7_test
1241 .word cirrus5_md, cirrus5_test
1242 .word cirrus6_md, cirrus6_test
1243 .word cirrus1_md, cirrus1_test
1244 .word ahead_md, ahead_test
1245 .word everex_md, everex_test
1246 .word genoa_md, genoa_test
1247 .word trident_md, trident_test
1248 .word tseng_md, tseng_test
1251 # Test routines and mode tables:
1253 # S3 - The test algorithm was taken from the SuperProbe package
1254 # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
1256 movw $0x0f35, %cx # we store some constants in cl/ch
1260 movb %al, %bh # store current CRT-register 0x38
1262 call outidx # disable writing to special regs
1263 movb %cl, %al # check whether we can write special reg 0x35
1265 movb %al, %bl # save the current value of CRT reg 0x35
1266 andb $0xf0, %al # clear bits 0-3
1268 movb %cl, %al # and write it to CRT reg 0x35
1270 call inidx # now read it back
1271 andb %ch, %al # clear the upper 4 bits
1272 jz s3_2 # the first test failed. But we have a
1274 movb %bl, %ah # second chance
1277 jmp s3_1 # do the other tests
1279 s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
1280 orb %bl, %ah # set the upper 4 bits of ah with the orig value
1281 call outidx # write ...
1282 call inidx # ... and reread
1283 andb %cl, %al # turn off the upper 4 bits
1285 movb %bl, %ah # restore old value in register 0x35
1289 cmpb %ch, %al # setting lower 4 bits was successful => bad
1290 je no_s3 # writing is allowed => this is not an S3
1292 s3_1: movw $0x4838, %ax # allow writing to special regs by putting
1293 call outidx # magic number into CRT-register 0x38
1294 movb %cl, %al # check whether we can write special reg 0x35
1303 jnz no_s3 # no, we can't write => no S3
1311 movb %bl, %ah # restore old value in register 0x35
1316 jne no_s31 # writing not possible => no S3
1318 call inidx # now get the S3 id ...
1329 no_s3: movb $0x35, %al # restore CRT register 0x35
1332 no_s31: xorw %bp, %bp # Detection failed
1333 s3rest: movb %bh, %ah
1334 movb $0x38, %al # restore old value of CRT register 0x38
1337 idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
1338 .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
1340 s3_md: .byte 0x54, 0x2b, 0x84
1341 .byte 0x55, 0x19, 0x84
1358 idati: .ascii "761295520"
1360 ati_md: .byte 0x23, 0x19, 0x84
1361 .byte 0x33, 0x2c, 0x84
1362 .byte 0x22, 0x1e, 0x64
1363 .byte 0x21, 0x19, 0x64
1364 .byte 0x58, 0x21, 0x50
1365 .byte 0x5b, 0x1e, 0x50
1387 .byte 0x22, 0x2c, 0x84
1388 .byte 0x23, 0x19, 0x84
1389 .byte 0x24, 0x1c, 0x84
1390 .byte 0x2f, 0x32, 0xa0
1391 .byte 0x32, 0x22, 0x50
1392 .byte 0x34, 0x42, 0x50
1417 .byte 0x60, 0x19, 0x84
1418 .byte 0x61, 0x32, 0x84
1420 .ascii "Chips & Technologies"
1461 nocirr: xorw %bp, %bp
1462 iscirr: movw $0x3d4, %dx
1471 .byte 0x1f, 0x19, 0x84
1472 .byte 0x20, 0x2c, 0x84
1473 .byte 0x22, 0x1e, 0x84
1474 .byte 0x31, 0x25, 0x64
1476 .ascii "Cirrus Logic 5X0"
1484 movb %al, %bl # BL=backup
1518 c5fail: xorw %bp, %bp
1519 c5done: movb $6, %al
1525 .byte 0x14, 0x19, 0x84
1526 .byte 0x54, 0x2b, 0x84
1528 .ascii "Cirrus Logic 54XX"
1531 # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
1532 # it's misidentified by the Ahead test.
1537 movb %al, %bl # BL=backup
1549 call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
1563 c2fail: xorw %bp, %bp
1564 c6done: movb $0x0a, %al
1571 .ascii "Cirrus Logic 64XX"
1589 evtrid: leaw trident_md, %bp
1592 noevrx: xorw %bp, %bp
1596 .byte 0x03, 0x22, 0x50
1597 .byte 0x04, 0x3c, 0x50
1598 .byte 0x07, 0x2b, 0x64
1599 .byte 0x08, 0x4b, 0x64
1600 .byte 0x0a, 0x19, 0x84
1601 .byte 0x0b, 0x2c, 0x84
1602 .byte 0x16, 0x1e, 0x50
1603 .byte 0x18, 0x1b, 0x64
1604 .byte 0x21, 0x40, 0xa0
1605 .byte 0x40, 0x1e, 0x84
1607 .ascii "Everex/Trident"
1612 leaw idgenoa, %si # Check Genoa 'clues'
1614 movb %es:(0x37), %al
1633 idgenoa: .byte 0x77, 0x00, 0x99, 0x66
1636 .byte 0x58, 0x20, 0x50
1637 .byte 0x5a, 0x2a, 0x64
1638 .byte 0x60, 0x19, 0x84
1639 .byte 0x61, 0x1d, 0x84
1640 .byte 0x62, 0x20, 0x84
1641 .byte 0x63, 0x2c, 0x84
1642 .byte 0x64, 0x3c, 0x84
1643 .byte 0x6b, 0x4f, 0x64
1644 .byte 0x72, 0x3c, 0x50
1645 .byte 0x74, 0x42, 0x50
1646 .byte 0x78, 0x4b, 0x64
1663 idoakvga: .ascii "OAK VGA "
1665 oak_md: .byte 0x4e, 0x3c, 0x50
1666 .byte 0x4f, 0x3c, 0x84
1667 .byte 0x50, 0x19, 0x84
1668 .byte 0x51, 0x2b, 0x84
1675 leaw idparadise, %si
1685 idparadise: .ascii "VGA="
1688 .byte 0x41, 0x22, 0x50
1689 .byte 0x47, 0x1c, 0x84
1690 .byte 0x55, 0x19, 0x84
1691 .byte 0x54, 0x2c, 0x84
1708 movb %al, %bl # Strange thing ... in the book this wasn't
1709 andb $0x02, %bl # necessary but it worked on my card which
1710 jz setb2 # is a trident. Without it the screen goes
1715 setb2: orb $0x02, %al
1716 clrb2: outb %al, %dx
1725 .byte 0x50, 0x1e, 0x50
1726 .byte 0x51, 0x2b, 0x50
1727 .byte 0x52, 0x3c, 0x50
1728 .byte 0x57, 0x19, 0x84
1729 .byte 0x58, 0x1e, 0x84
1730 .byte 0x59, 0x2b, 0x84
1731 .byte 0x5a, 0x3c, 0x84
1739 inb %dx, %al # Could things be this simple ! :-)
1750 isnot: xorw %bp, %bp
1754 .byte 0x26, 0x3c, 0x50
1755 .byte 0x2a, 0x28, 0x64
1756 .byte 0x23, 0x19, 0x84
1757 .byte 0x24, 0x1c, 0x84
1758 .byte 0x22, 0x2c, 0x84
1759 .byte 0x21, 0x3c, 0x84
1773 even7: movb $0x0c, %al
1798 movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
1802 .byte 0x40, 0x2b, 0x50
1803 .byte 0x43, 0x3c, 0x50
1804 .byte 0x44, 0x3c, 0x64
1805 .byte 0x41, 0x19, 0x84
1806 .byte 0x42, 0x2c, 0x84
1807 .byte 0x45, 0x1c, 0x84
1824 idrtvga: .ascii "REALTEK VGA"
1827 .byte 0x1a, 0x3c, 0x50
1828 .byte 0x1b, 0x19, 0x84
1829 .byte 0x1c, 0x1e, 0x84
1830 .byte 0x1d, 0x2b, 0x84
1831 .byte 0x1e, 0x3c, 0x84
1836 #endif /* CONFIG_VIDEO_SVGA */
1838 # User-defined local mode table (VGA only)
1839 #ifdef CONFIG_VIDEO_LOCAL
1841 leaw local_mode_table, %si
1852 # This is the table of local video modes which can be supplied manually
1853 # by the user. Each entry consists of mode ID (word) and dimensions
1854 # (byte for column count and another byte for row count). These modes
1855 # are placed before all SVGA and VESA modes and override them if table
1856 # compacting is enabled. The table must end with a zero word followed
1857 # by NUL-terminated video adapter name.
1859 .word 0x0100 # Example: 40x25
1864 #endif /* CONFIG_VIDEO_LOCAL */
1866 # Read a key and return the ASCII code in al, scan code in ah
1867 getkey: xorb %ah, %ah
1871 # Read a key with a timeout of 30 seconds.
1872 # The hardware clock is used to get the time.
1874 addb $30, %al # Wait 30 seconds
1881 again: movb $0x01, %ah
1883 jnz getkey # key pressed, so get it
1889 movb $0x20, %al # timeout, return `space'
1892 # Flush the keyboard buffer
1893 flush: movb $0x01, %ah
1903 # Print hexadecimal number.
1913 prthn: cmpb $0x0a, %al
1917 prth1: addb $0x30, %al
1920 # Print decimal number in al
1932 lt100: addb $0x30, %al
1934 skip10: movb %ah, %al
1942 #ifdef CONFIG_FIRMWARE_EDID
1943 pushw %es # just save all registers
1953 movl $0x13131313, %eax # memset block with 0x13
1960 cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0
1964 xorw %di, %di # Report Capability
1966 popw %es # ES:DI must be 0:0
1971 popw %es # restore ES
1973 cmpb $0x00, %ah # call successful
1976 cmpb $0x4f, %al # function supported
1979 movw $0x4f15, %ax # do VBE/DDC
1987 popw %di # restore all registers
1996 # VIDEO_SELECT-only variables
1997 mt_end: .word 0 # End of video mode table if built
1998 edit_buf: .space 6 # Line editor buffer
1999 card_name: .word 0 # Pointer to adapter name
2000 scanning: .byte 0 # Performing mode scan
2001 do_restore: .byte 0 # Screen contents altered during mode change
2002 svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
2003 graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
2004 dac_size: .byte 6 # DAC bit depth
2005 vbe_version: .word 0 # VBE bios version
2008 keymsg: .ascii "Press <RETURN> to see video modes available, "
2009 .ascii "<SPACE> to continue or wait 30 secs"
2012 listhdr: .byte 0x0d, 0x0a
2013 .ascii "Mode: COLSxROWS:"
2015 crlft: .byte 0x0d, 0x0a, 0
2017 prompt: .byte 0x0d, 0x0a
2018 .asciz "Enter mode number or `scan': "
2020 unknt: .asciz "Unknown mode ID. Try again."
2022 badmdt: .ascii "You passed an undefined mode number."
2025 vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
2026 .ascii "report to <mj@ucw.cz>."
2029 old_name: .asciz "CGA/MDA/HGA"
2031 ega_name: .asciz "EGA"
2033 svga_name: .ascii " "
2035 vga_name: .asciz "VGA"
2037 vesa_name: .asciz "VESA"
2039 name_bann: .asciz "Video adapter: "
2040 #endif /* CONFIG_VIDEO_SELECT */
2043 adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
2044 video_segment: .word 0xb800 # Video memory segment
2045 force_size: .word 0 # Use this size instead of the one in BIOS vars