ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / i386 / boot / video.S
1 /*      video.S
2  *
3  *      Display adapter & video mode setup, version 2.13 (14-May-99)
4  *
5  *      Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
6  *      Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
7  *
8  *      Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
9  *
10  *      For further information, look at Documentation/svga.txt.
11  *
12  */
13
14 #include <linux/config.h> /* for CONFIG_VIDEO_* */
15
16 /* Enable autodetection of SVGA adapters and modes. */
17 #undef CONFIG_VIDEO_SVGA
18
19 /* Enable autodetection of VESA modes */
20 #define CONFIG_VIDEO_VESA
21
22 /* Enable compacting of mode table */
23 #define CONFIG_VIDEO_COMPACT
24
25 /* Retain screen contents when switching modes */
26 #define CONFIG_VIDEO_RETAIN
27
28 /* Enable local mode list */
29 #undef CONFIG_VIDEO_LOCAL
30
31 /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
32 #undef CONFIG_VIDEO_400_HACK
33
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 */
39
40 /* This code uses an extended set of video mode numbers. These include:
41  * Aliases for standard modes
42  *      NORMAL_VGA (-1)
43  *      EXTENDED_VGA (-2)
44  *      ASK_VGA (-3)
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.
47  */
48 #define VIDEO_FIRST_MENU 0x0000
49
50 /* Standard BIOS video modes (BIOS number + 0x0100) */
51 #define VIDEO_FIRST_BIOS 0x0100
52
53 /* VESA BIOS video modes (VESA number + 0x0200) */
54 #define VIDEO_FIRST_VESA 0x0200
55
56 /* Video7 special modes (BIOS number + 0x0900) */
57 #define VIDEO_FIRST_V7 0x0900
58
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
71
72 /* Video modes given by resolution */
73 #define VIDEO_FIRST_RESOLUTION 0x1000
74
75 /* The "recalculate timings" flag */
76 #define VIDEO_RECALC 0x8000
77
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
88
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
101 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
102 #ifdef CONFIG_VIDEO_RETAIN
103 #define DO_STORE call store_screen
104 #else
105 #define DO_STORE
106 #endif /* CONFIG_VIDEO_RETAIN */
107
108 # This is the main entry point called by setup.S
109 # %ds *must* be pointing to the bootsector
110 video:  pushw   %ds             # We use different segments
111         pushw   %ds             # FS contains original DS
112         popw    %fs
113         pushw   %cs             # DS is equal to CS
114         popw    %ds
115         pushw   %cs             # ES is equal to CS
116         popw    %es
117         xorw    %ax, %ax
118         movw    %ax, %gs        # GS is zero
119         cld
120         call    basic_detect    # Basic adapter type testing (EGA/VGA/MDA/CGA)
121 #ifdef CONFIG_VIDEO_SELECT
122         movw    %fs:(0x01fa), %ax               # User selected video mode
123         cmpw    $ASK_VGA, %ax                   # Bring up the menu
124         jz      vid2
125
126         call    mode_set                        # Set the mode
127         jc      vid1
128
129         leaw    badmdt, %si                     # Invalid mode ID
130         call    prtstr
131 vid2:   call    mode_menu
132 vid1:
133 #ifdef CONFIG_VIDEO_RETAIN
134         call    restore_screen                  # Restore screen contents
135 #endif /* CONFIG_VIDEO_RETAIN */
136         call    store_edid
137 #endif /* CONFIG_VIDEO_SELECT */
138         call    mode_params                     # Store mode parameters
139         popw    %ds                             # Restore original DS
140         ret
141
142 # Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
143 basic_detect:
144         movb    $0, %fs:(PARAM_HAVE_VGA)
145         movb    $0x12, %ah      # Check EGA/VGA
146         movb    $0x10, %bl
147         int     $0x10
148         movw    %bx, %fs:(PARAM_VIDEO_EGA_BX)   # Identifies EGA to the kernel
149         cmpb    $0x10, %bl                      # No, it's a CGA/MDA/HGA card.
150         je      basret
151
152         incb    adapter
153         movw    $0x1a00, %ax                    # Check EGA or VGA?
154         int     $0x10
155         cmpb    $0x1a, %al                      # 1a means VGA...
156         jne     basret                          # anything else is EGA.
157         
158         incb    %fs:(PARAM_HAVE_VGA)            # We've detected a VGA
159         incb    adapter
160 basret: ret
161
162 # Store the video mode parameters for later usage by the kernel.
163 # This is done by asking the BIOS except for the rows/columns
164 # parameters in the default 80x25 mode -- these are set directly,
165 # because some very obscure BIOSes supply insane values.
166 mode_params:
167 #ifdef CONFIG_VIDEO_SELECT
168         cmpb    $0, graphic_mode
169         jnz     mopar_gr
170 #endif
171         movb    $0x03, %ah                      # Read cursor position
172         xorb    %bh, %bh
173         int     $0x10
174         movw    %dx, %fs:(PARAM_CURSOR_POS)
175         movb    $0x0f, %ah                      # Read page/mode/width
176         int     $0x10
177         movw    %bx, %fs:(PARAM_VIDEO_PAGE)
178         movw    %ax, %fs:(PARAM_VIDEO_MODE)     # Video mode and screen width
179         cmpb    $0x7, %al                       # MDA/HGA => segment differs
180         jnz     mopar0
181
182         movw    $0xb000, video_segment
183 mopar0: movw    %gs:(0x485), %ax                # Font size
184         movw    %ax, %fs:(PARAM_FONT_POINTS)    # (valid only on EGA/VGA)
185         movw    force_size, %ax                 # Forced size?
186         orw     %ax, %ax
187         jz      mopar1
188
189         movb    %ah, %fs:(PARAM_VIDEO_COLS)
190         movb    %al, %fs:(PARAM_VIDEO_LINES)
191         ret
192
193 mopar1: movb    $25, %al
194         cmpb    $0, adapter                     # If we are on CGA/MDA/HGA, the
195         jz      mopar2                          # screen must have 25 lines.
196
197         movb    %gs:(0x484), %al                # On EGA/VGA, use the EGA+ BIOS
198         incb    %al                             # location of max lines.
199 mopar2: movb    %al, %fs:(PARAM_VIDEO_LINES)
200         ret
201
202 #ifdef CONFIG_VIDEO_SELECT
203 # Fetching of VESA frame buffer parameters
204 mopar_gr:
205         leaw    modelist+1024, %di
206         movb    $0x23, %fs:(PARAM_HAVE_VGA)
207         movw    16(%di), %ax
208         movw    %ax, %fs:(PARAM_LFB_LINELENGTH)
209         movw    18(%di), %ax
210         movw    %ax, %fs:(PARAM_LFB_WIDTH)
211         movw    20(%di), %ax
212         movw    %ax, %fs:(PARAM_LFB_HEIGHT)
213         movb    25(%di), %al
214         movb    $0, %ah
215         movw    %ax, %fs:(PARAM_LFB_DEPTH)
216         movb    29(%di), %al    
217         movb    $0, %ah
218         movw    %ax, %fs:(PARAM_LFB_PAGES)
219         movl    40(%di), %eax
220         movl    %eax, %fs:(PARAM_LFB_BASE)
221         movl    31(%di), %eax
222         movl    %eax, %fs:(PARAM_LFB_COLORS)
223         movl    35(%di), %eax
224         movl    %eax, %fs:(PARAM_LFB_COLORS+4)
225         movw    0(%di), %ax
226         movw    %ax, %fs:(PARAM_VESA_ATTRIB)
227
228 # get video mem size
229         leaw    modelist+1024, %di
230         movw    $0x4f00, %ax
231         int     $0x10
232         xorl    %eax, %eax
233         movw    18(%di), %ax
234         movl    %eax, %fs:(PARAM_LFB_SIZE)
235 # get protected mode interface informations
236         movw    $0x4f0a, %ax
237         xorw    %bx, %bx
238         xorw    %di, %di
239         int     $0x10
240         cmp     $0x004f, %ax
241         jnz     no_pm
242
243         movw    %es, %fs:(PARAM_VESAPM_SEG)
244         movw    %di, %fs:(PARAM_VESAPM_OFF)
245 no_pm:  ret
246
247 # The video mode menu
248 mode_menu:
249         leaw    keymsg, %si                     # "Return/Space/Timeout" message
250         call    prtstr
251         call    flush
252 nokey:  call    getkt
253
254         cmpb    $0x0d, %al                      # ENTER ?
255         je      listm                           # yes - manual mode selection
256
257         cmpb    $0x20, %al                      # SPACE ?
258         je      defmd1                          # no - repeat
259
260         call    beep
261         jmp     nokey
262
263 defmd1: ret                                     # No mode chosen? Default 80x25
264
265 listm:  call    mode_table                      # List mode table
266 listm0: leaw    name_bann, %si                  # Print adapter name
267         call    prtstr
268         movw    card_name, %si
269         orw     %si, %si
270         jnz     an2
271
272         movb    adapter, %al
273         leaw    old_name, %si
274         orb     %al, %al
275         jz      an1
276
277         leaw    ega_name, %si
278         decb    %al
279         jz      an1
280
281         leaw    vga_name, %si
282         jmp     an1
283
284 an2:    call    prtstr
285         leaw    svga_name, %si
286 an1:    call    prtstr
287         leaw    listhdr, %si                    # Table header
288         call    prtstr
289         movb    $0x30, %dl                      # DL holds mode number
290         leaw    modelist, %si
291 lm1:    cmpw    $ASK_VGA, (%si)                 # End?
292         jz      lm2
293
294         movb    %dl, %al                        # Menu selection number
295         call    prtchr
296         call    prtsp2
297         lodsw
298         call    prthw                           # Mode ID
299         call    prtsp2
300         movb    0x1(%si), %al
301         call    prtdec                          # Rows
302         movb    $0x78, %al                      # the letter 'x'
303         call    prtchr
304         lodsw
305         call    prtdec                          # Columns
306         movb    $0x0d, %al                      # New line
307         call    prtchr
308         movb    $0x0a, %al
309         call    prtchr
310         incb    %dl                             # Next character
311         cmpb    $0x3a, %dl
312         jnz     lm1
313
314         movb    $0x61, %dl
315         jmp     lm1
316
317 lm2:    leaw    prompt, %si                     # Mode prompt
318         call    prtstr
319         leaw    edit_buf, %di                   # Editor buffer
320 lm3:    call    getkey
321         cmpb    $0x0d, %al                      # Enter?
322         jz      lment
323
324         cmpb    $0x08, %al                      # Backspace?
325         jz      lmbs
326
327         cmpb    $0x20, %al                      # Printable?
328         jc      lm3
329
330         cmpw    $edit_buf+4, %di                # Enough space?
331         jz      lm3
332
333         stosb
334         call    prtchr
335         jmp     lm3
336
337 lmbs:   cmpw    $edit_buf, %di                  # Backspace
338         jz      lm3
339
340         decw    %di
341         movb    $0x08, %al
342         call    prtchr
343         call    prtspc
344         movb    $0x08, %al
345         call    prtchr
346         jmp     lm3
347         
348 lment:  movb    $0, (%di)
349         leaw    crlft, %si
350         call    prtstr
351         leaw    edit_buf, %si
352         cmpb    $0, (%si)                       # Empty string = default mode
353         jz      lmdef
354
355         cmpb    $0, 1(%si)                      # One character = menu selection
356         jz      mnusel
357
358         cmpw    $0x6373, (%si)                  # "scan" => mode scanning
359         jnz     lmhx
360
361         cmpw    $0x6e61, 2(%si)
362         jz      lmscan
363
364 lmhx:   xorw    %bx, %bx                        # Else => mode ID in hex
365 lmhex:  lodsb
366         orb     %al, %al
367         jz      lmuse1
368
369         subb    $0x30, %al
370         jc      lmbad
371
372         cmpb    $10, %al
373         jc      lmhx1
374
375         subb    $7, %al
376         andb    $0xdf, %al
377         cmpb    $10, %al
378         jc      lmbad
379
380         cmpb    $16, %al
381         jnc     lmbad
382
383 lmhx1:  shlw    $4, %bx
384         orb     %al, %bl
385         jmp     lmhex
386
387 lmuse1: movw    %bx, %ax
388         jmp     lmuse
389
390 mnusel: lodsb                                   # Menu selection
391         xorb    %ah, %ah
392         subb    $0x30, %al
393         jc      lmbad
394
395         cmpb    $10, %al
396         jc      lmuse
397         
398         cmpb    $0x61-0x30, %al
399         jc      lmbad
400         
401         subb    $0x61-0x30-10, %al
402         cmpb    $36, %al
403         jnc     lmbad
404
405 lmuse:  call    mode_set
406         jc      lmdef
407
408 lmbad:  leaw    unknt, %si
409         call    prtstr
410         jmp     lm2
411 lmscan: cmpb    $0, adapter                     # Scanning only on EGA/VGA
412         jz      lmbad
413
414         movw    $0, mt_end                      # Scanning of modes is
415         movb    $1, scanning                    # done as new autodetection.
416         call    mode_table
417         jmp     listm0
418 lmdef:  ret
419
420 # Additional parts of mode_set... (relative jumps, you know)
421 setv7:                                          # Video7 extended modes
422         DO_STORE
423         subb    $VIDEO_FIRST_V7>>8, %bh
424         movw    $0x6f05, %ax
425         int     $0x10
426         stc
427         ret
428
429 _setrec:        jmp     setrec                  # Ugly...
430 _set_80x25:     jmp     set_80x25
431
432 # Aliases for backward compatibility.
433 setalias:
434         movw    $VIDEO_80x25, %ax
435         incw    %bx
436         jz      mode_set
437
438         movb    $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
439         incw    %bx
440         jnz     setbad                          # Fall-through!
441
442 # Setting of user mode (AX=mode ID) => CF=success
443 mode_set:
444         movw    %ax, %fs:(0x01fa)               # Store mode for use in acpi_wakeup.S
445         movw    %ax, %bx
446         cmpb    $0xff, %ah
447         jz      setalias
448
449         testb   $VIDEO_RECALC>>8, %ah
450         jnz     _setrec
451
452         cmpb    $VIDEO_FIRST_RESOLUTION>>8, %ah
453         jnc     setres
454         
455         cmpb    $VIDEO_FIRST_SPECIAL>>8, %ah
456         jz      setspc
457         
458         cmpb    $VIDEO_FIRST_V7>>8, %ah
459         jz      setv7
460         
461         cmpb    $VIDEO_FIRST_VESA>>8, %ah
462         jnc     check_vesa
463         
464         orb     %ah, %ah
465         jz      setmenu
466         
467         decb    %ah
468         jz      setbios
469
470 setbad: clc
471         movb    $0, do_restore                  # The screen needn't be restored
472         ret
473
474 setvesa:
475         DO_STORE
476         subb    $VIDEO_FIRST_VESA>>8, %bh
477         movw    $0x4f02, %ax                    # VESA BIOS mode set call
478         int     $0x10
479         cmpw    $0x004f, %ax                    # AL=4f if implemented
480         jnz     setbad                          # AH=0 if OK
481
482         stc
483         ret
484
485 setbios:
486         DO_STORE
487         int     $0x10                           # Standard BIOS mode set call
488         pushw   %bx
489         movb    $0x0f, %ah                      # Check if really set
490         int     $0x10
491         popw    %bx
492         cmpb    %bl, %al
493         jnz     setbad
494         
495         stc
496         ret
497
498 setspc: xorb    %bh, %bh                        # Set special mode
499         cmpb    $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
500         jnc     setbad
501         
502         addw    %bx, %bx
503         jmp     *spec_inits(%bx)
504
505 setmenu:
506         orb     %al, %al                        # 80x25 is an exception
507         jz      _set_80x25
508         
509         pushw   %bx                             # Set mode chosen from menu
510         call    mode_table                      # Build the mode table
511         popw    %ax
512         shlw    $2, %ax
513         addw    %ax, %si
514         cmpw    %di, %si
515         jnc     setbad
516         
517         movw    (%si), %ax                      # Fetch mode ID
518 _m_s:   jmp     mode_set
519
520 setres: pushw   %bx                             # Set mode chosen by resolution
521         call    mode_table
522         popw    %bx
523         xchgb   %bl, %bh
524 setr1:  lodsw
525         cmpw    $ASK_VGA, %ax                   # End of the list?
526         jz      setbad
527         
528         lodsw
529         cmpw    %bx, %ax
530         jnz     setr1
531         
532         movw    -4(%si), %ax                    # Fetch mode ID
533         jmp     _m_s
534
535 check_vesa:
536         leaw    modelist+1024, %di
537         subb    $VIDEO_FIRST_VESA>>8, %bh
538         movw    %bx, %cx                        # Get mode information structure
539         movw    $0x4f01, %ax
540         int     $0x10
541         addb    $VIDEO_FIRST_VESA>>8, %bh
542         cmpw    $0x004f, %ax
543         jnz     setbad
544
545         movb    (%di), %al                      # Check capabilities.
546         andb    $0x19, %al
547         cmpb    $0x09, %al
548         jz      setvesa                         # This is a text mode
549
550         movb    (%di), %al                      # Check capabilities.
551         andb    $0x99, %al
552         cmpb    $0x99, %al
553         jnz     _setbad                         # Doh! No linear frame buffer.
554
555         subb    $VIDEO_FIRST_VESA>>8, %bh
556         orw     $0x4000, %bx                    # Use linear frame buffer
557         movw    $0x4f02, %ax                    # VESA BIOS mode set call
558         int     $0x10
559         cmpw    $0x004f, %ax                    # AL=4f if implemented
560         jnz     _setbad                         # AH=0 if OK
561
562         movb    $1, graphic_mode                # flag graphic mode
563         movb    $0, do_restore                  # no screen restore
564         stc
565         ret
566
567 _setbad:        jmp     setbad                  # Ugly...
568
569 # Recalculate vertical display end registers -- this fixes various
570 # inconsistencies of extended modes on many adapters. Called when
571 # the VIDEO_RECALC flag is set in the mode ID.
572
573 setrec: subb    $VIDEO_RECALC>>8, %ah           # Set the base mode
574         call    mode_set
575         jnc     rct3
576
577         movw    %gs:(0x485), %ax                # Font size in pixels
578         movb    %gs:(0x484), %bl                # Number of rows
579         incb    %bl
580         mulb    %bl                             # Number of visible
581         decw    %ax                             # scan lines - 1
582         movw    $0x3d4, %dx
583         movw    %ax, %bx
584         movb    $0x12, %al                      # Lower 8 bits
585         movb    %bl, %ah
586         outw    %ax, %dx
587         movb    $0x07, %al              # Bits 8 and 9 in the overflow register
588         call    inidx
589         xchgb   %al, %ah
590         andb    $0xbd, %ah
591         shrb    %bh
592         jnc     rct1
593         orb     $0x02, %ah
594 rct1:   shrb    %bh
595         jnc     rct2
596         orb     $0x40, %ah
597 rct2:   movb    $0x07, %al
598         outw    %ax, %dx
599         stc
600 rct3:   ret
601
602 # Table of routines for setting of the special modes.
603 spec_inits:
604         .word   set_80x25
605         .word   set_8pixel
606         .word   set_80x43
607         .word   set_80x28
608         .word   set_current
609         .word   set_80x30
610         .word   set_80x34
611         .word   set_80x60
612         .word   set_gfx
613
614 # Set the 80x25 mode. If already set, do nothing.
615 set_80x25:
616         movw    $0x5019, force_size             # Override possibly broken BIOS
617 use_80x25:
618 #ifdef CONFIG_VIDEO_400_HACK
619         movw    $0x1202, %ax                    # Force 400 scan lines
620         movb    $0x30, %bl
621         int     $0x10
622 #else
623         movb    $0x0f, %ah                      # Get current mode ID
624         int     $0x10
625         cmpw    $0x5007, %ax    # Mode 7 (80x25 mono) is the only one available
626         jz      st80            # on CGA/MDA/HGA and is also available on EGAM
627
628         cmpw    $0x5003, %ax    # Unknown mode, force 80x25 color
629         jnz     force3
630
631 st80:   cmpb    $0, adapter     # CGA/MDA/HGA => mode 3/7 is always 80x25
632         jz      set80
633
634         movb    %gs:(0x0484), %al       # This is EGA+ -- beware of 80x50 etc.
635         orb     %al, %al                # Some buggy BIOS'es set 0 rows
636         jz      set80
637         
638         cmpb    $24, %al                # It's hopefully correct
639         jz      set80
640 #endif /* CONFIG_VIDEO_400_HACK */
641 force3: DO_STORE
642         movw    $0x0003, %ax                    # Forced set
643         int     $0x10
644 set80:  stc
645         ret
646
647 # Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
648 set_8pixel:
649         DO_STORE
650         call    use_80x25                       # The base is 80x25
651 set_8pt:
652         movw    $0x1112, %ax                    # Use 8x8 font
653         xorb    %bl, %bl
654         int     $0x10
655         movw    $0x1200, %ax                    # Use alternate print screen
656         movb    $0x20, %bl
657         int     $0x10
658         movw    $0x1201, %ax                    # Turn off cursor emulation
659         movb    $0x34, %bl
660         int     $0x10
661         movb    $0x01, %ah                      # Define cursor scan lines 6-7
662         movw    $0x0607, %cx
663         int     $0x10
664 set_current:
665         stc
666         ret
667
668 # Set the 80x28 mode. This mode works on all VGA's, because it's a standard
669 # 80x25 mode with 14-point fonts instead of 16-point.
670 set_80x28:
671         DO_STORE
672         call    use_80x25                       # The base is 80x25
673 set14:  movw    $0x1111, %ax                    # Use 9x14 font
674         xorb    %bl, %bl
675         int     $0x10
676         movb    $0x01, %ah                      # Define cursor scan lines 11-12
677         movw    $0x0b0c, %cx
678         int     $0x10
679         stc
680         ret
681
682 # Set the 80x43 mode. This mode is works on all VGA's.
683 # It's a 350-scanline mode with 8-pixel font.
684 set_80x43:
685         DO_STORE
686         movw    $0x1201, %ax                    # Set 350 scans
687         movb    $0x30, %bl
688         int     $0x10
689         movw    $0x0003, %ax                    # Reset video mode
690         int     $0x10
691         jmp     set_8pt                         # Use 8-pixel font
692
693 # Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
694 set_80x30:
695         call    use_80x25                       # Start with real 80x25
696         DO_STORE
697         movw    $0x3cc, %dx                     # Get CRTC port
698         inb     %dx, %al
699         movb    $0xd4, %dl
700         rorb    %al                             # Mono or color?
701         jc      set48a
702
703         movb    $0xb4, %dl
704 set48a: movw    $0x0c11, %ax            # Vertical sync end (also unlocks CR0-7)
705         call    outidx
706         movw    $0x0b06, %ax                    # Vertical total
707         call    outidx
708         movw    $0x3e07, %ax                    # (Vertical) overflow
709         call    outidx
710         movw    $0xea10, %ax                    # Vertical sync start
711         call    outidx
712         movw    $0xdf12, %ax                    # Vertical display end
713         call    outidx
714         movw    $0xe715, %ax                    # Vertical blank start
715         call    outidx
716         movw    $0x0416, %ax                    # Vertical blank end
717         call    outidx
718         pushw   %dx
719         movb    $0xcc, %dl                      # Misc output register (read)
720         inb     %dx, %al
721         movb    $0xc2, %dl                      # (write)
722         andb    $0x0d, %al      # Preserve clock select bits and color bit
723         orb     $0xe2, %al                      # Set correct sync polarity
724         outb    %al, %dx
725         popw    %dx
726         movw    $0x501e, force_size
727         stc                                     # That's all.
728         ret
729
730 # Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
731 set_80x34:
732         call    set_80x30                       # Set 480 scans
733         call    set14                           # And 14-pt font
734         movw    $0xdb12, %ax                    # VGA vertical display end
735         movw    $0x5022, force_size
736 setvde: call    outidx
737         stc
738         ret
739
740 # Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
741 set_80x60:
742         call    set_80x30                       # Set 480 scans
743         call    set_8pt                         # And 8-pt font
744         movw    $0xdf12, %ax                    # VGA vertical display end
745         movw    $0x503c, force_size
746         jmp     setvde
747
748 # Special hack for ThinkPad graphics
749 set_gfx:
750 #ifdef CONFIG_VIDEO_GFX_HACK
751         movw    $VIDEO_GFX_BIOS_AX, %ax
752         movw    $VIDEO_GFX_BIOS_BX, %bx
753         int     $0x10
754         movw    $VIDEO_GFX_DUMMY_RESOLUTION, force_size
755         stc
756 #endif
757         ret
758
759 #ifdef CONFIG_VIDEO_RETAIN
760
761 # Store screen contents to temporary buffer.
762 store_screen:
763         cmpb    $0, do_restore                  # Already stored?
764         jnz     stsr
765
766         testb   $CAN_USE_HEAP, loadflags        # Have we space for storing?
767         jz      stsr
768         
769         pushw   %ax
770         pushw   %bx
771         pushw   force_size                      # Don't force specific size
772         movw    $0, force_size
773         call    mode_params                     # Obtain params of current mode
774         popw    force_size
775         movb    %fs:(PARAM_VIDEO_LINES), %ah
776         movb    %fs:(PARAM_VIDEO_COLS), %al
777         movw    %ax, %bx                        # BX=dimensions
778         mulb    %ah
779         movw    %ax, %cx                        # CX=number of characters
780         addw    %ax, %ax                        # Calculate image size
781         addw    $modelist+1024+4, %ax
782         cmpw    heap_end_ptr, %ax
783         jnc     sts1                            # Unfortunately, out of memory
784
785         movw    %fs:(PARAM_CURSOR_POS), %ax     # Store mode params
786         leaw    modelist+1024, %di
787         stosw
788         movw    %bx, %ax
789         stosw
790         pushw   %ds                             # Store the screen
791         movw    video_segment, %ds
792         xorw    %si, %si
793         rep
794         movsw
795         popw    %ds
796         incb    do_restore                      # Screen will be restored later
797 sts1:   popw    %bx
798         popw    %ax
799 stsr:   ret
800
801 # Restore screen contents from temporary buffer.
802 restore_screen:
803         cmpb    $0, do_restore                  # Has the screen been stored?
804         jz      res1
805
806         call    mode_params                     # Get parameters of current mode
807         movb    %fs:(PARAM_VIDEO_LINES), %cl
808         movb    %fs:(PARAM_VIDEO_COLS), %ch
809         leaw    modelist+1024, %si              # Screen buffer
810         lodsw                                   # Set cursor position
811         movw    %ax, %dx
812         cmpb    %cl, %dh
813         jc      res2
814         
815         movb    %cl, %dh
816         decb    %dh
817 res2:   cmpb    %ch, %dl
818         jc      res3
819         
820         movb    %ch, %dl
821         decb    %dl
822 res3:   movb    $0x02, %ah
823         movb    $0x00, %bh
824         int     $0x10
825         lodsw                                   # Display size
826         movb    %ah, %dl                        # DL=number of lines
827         movb    $0, %ah                         # BX=phys. length of orig. line
828         movw    %ax, %bx
829         cmpb    %cl, %dl                        # Too many?
830         jc      res4
831
832         pushw   %ax
833         movb    %dl, %al
834         subb    %cl, %al
835         mulb    %bl
836         addw    %ax, %si
837         addw    %ax, %si
838         popw    %ax
839         movb    %cl, %dl
840 res4:   cmpb    %ch, %al                        # Too wide?
841         jc      res5
842         
843         movb    %ch, %al                        # AX=width of src. line
844 res5:   movb    $0, %cl
845         xchgb   %ch, %cl
846         movw    %cx, %bp                        # BP=width of dest. line
847         pushw   %es
848         movw    video_segment, %es
849         xorw    %di, %di                        # Move the data
850         addw    %bx, %bx                        # Convert BX and BP to _bytes_
851         addw    %bp, %bp
852 res6:   pushw   %si
853         pushw   %di
854         movw    %ax, %cx
855         rep
856         movsw
857         popw    %di
858         popw    %si
859         addw    %bp, %di
860         addw    %bx, %si
861         decb    %dl
862         jnz     res6
863         
864         popw    %es                             # Done
865 res1:   ret
866 #endif /* CONFIG_VIDEO_RETAIN */
867
868 # Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
869 outidx: outb    %al, %dx
870         pushw   %ax
871         movb    %ah, %al
872         incw    %dx
873         outb    %al, %dx
874         decw    %dx
875         popw    %ax
876         ret
877
878 # Build the table of video modes (stored after the setup.S code at the
879 # `modelist' label. Each video mode record looks like:
880 #       .word   MODE-ID         (our special mode ID (see above))
881 #       .byte   rows            (number of rows)
882 #       .byte   columns         (number of columns)
883 # Returns address of the end of the table in DI, the end is marked
884 # with a ASK_VGA ID.
885 mode_table:
886         movw    mt_end, %di                     # Already filled?
887         orw     %di, %di
888         jnz     mtab1x
889         
890         leaw    modelist, %di                   # Store standard modes:
891         movl    $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
892         stosl
893         movb    adapter, %al                    # CGA/MDA/HGA -- no more modes
894         orb     %al, %al
895         jz      mtabe
896         
897         decb    %al
898         jnz     mtabv
899         
900         movl    $VIDEO_8POINT + 0x502b0000, %eax        # The 80x43 EGA mode
901         stosl
902         jmp     mtabe
903
904 mtab1x: jmp     mtab1
905
906 mtabv:  leaw    vga_modes, %si                  # All modes for std VGA
907         movw    $vga_modes_end-vga_modes, %cx
908         rep     # I'm unable to use movsw as I don't know how to store a half
909         movsb   # of the expression above to cx without using explicit shr.
910
911         cmpb    $0, scanning                    # Mode scan requested?
912         jz      mscan1
913         
914         call    mode_scan
915 mscan1:
916
917 #ifdef CONFIG_VIDEO_LOCAL
918         call    local_modes
919 #endif /* CONFIG_VIDEO_LOCAL */
920
921 #ifdef CONFIG_VIDEO_VESA
922         call    vesa_modes                      # Detect VESA VGA modes
923 #endif /* CONFIG_VIDEO_VESA */
924
925 #ifdef CONFIG_VIDEO_SVGA
926         cmpb    $0, scanning                    # Bypass when scanning
927         jnz     mscan2
928         
929         call    svga_modes                      # Detect SVGA cards & modes
930 mscan2:
931 #endif /* CONFIG_VIDEO_SVGA */
932
933 mtabe:
934
935 #ifdef CONFIG_VIDEO_COMPACT
936         leaw    modelist, %si
937         movw    %di, %dx
938         movw    %si, %di
939 cmt1:   cmpw    %dx, %si                        # Scan all modes
940         jz      cmt2
941
942         leaw    modelist, %bx                   # Find in previous entries
943         movw    2(%si), %cx
944 cmt3:   cmpw    %bx, %si
945         jz      cmt4
946
947         cmpw    2(%bx), %cx                     # Found => don't copy this entry
948         jz      cmt5
949
950         addw    $4, %bx
951         jmp     cmt3
952
953 cmt4:   movsl                                   # Copy entry
954         jmp     cmt1
955
956 cmt5:   addw    $4, %si                         # Skip entry
957         jmp     cmt1
958
959 cmt2:
960 #endif  /* CONFIG_VIDEO_COMPACT */
961
962         movw    $ASK_VGA, (%di)                 # End marker
963         movw    %di, mt_end
964 mtab1:  leaw    modelist, %si                   # SI=mode list, DI=list end
965 ret0:   ret
966
967 # Modes usable on all standard VGAs
968 vga_modes:
969         .word   VIDEO_8POINT
970         .word   0x5032                          # 80x50
971         .word   VIDEO_80x43
972         .word   0x502b                          # 80x43
973         .word   VIDEO_80x28
974         .word   0x501c                          # 80x28
975         .word   VIDEO_80x30
976         .word   0x501e                          # 80x30
977         .word   VIDEO_80x34
978         .word   0x5022                          # 80x34
979         .word   VIDEO_80x60
980         .word   0x503c                          # 80x60
981 #ifdef CONFIG_VIDEO_GFX_HACK
982         .word   VIDEO_GFX_HACK
983         .word   VIDEO_GFX_DUMMY_RESOLUTION
984 #endif
985
986 vga_modes_end:
987 # Detect VESA modes.
988
989 #ifdef CONFIG_VIDEO_VESA
990 vesa_modes:
991         cmpb    $2, adapter                     # VGA only
992         jnz     ret0
993
994         movw    %di, %bp                        # BP=original mode table end
995         addw    $0x200, %di                     # Buffer space
996         movw    $0x4f00, %ax                    # VESA Get card info call
997         int     $0x10
998         movw    %bp, %di
999         cmpw    $0x004f, %ax                    # Successful?
1000         jnz     ret0
1001         
1002         cmpw    $0x4556, 0x200(%di)
1003         jnz     ret0
1004         
1005         cmpw    $0x4153, 0x202(%di)
1006         jnz     ret0
1007         
1008         movw    $vesa_name, card_name           # Set name to "VESA VGA"
1009         pushw   %gs
1010         lgsw    0x20e(%di), %si                 # GS:SI=mode list
1011         movw    $128, %cx                       # Iteration limit
1012 vesa1:
1013 # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
1014 # XXX:  lodsw   %gs:(%si), %ax                  # Get next mode in the list
1015         gs; lodsw
1016         cmpw    $0xffff, %ax                    # End of the table?
1017         jz      vesar
1018         
1019         cmpw    $0x0080, %ax                    # Check validity of mode ID
1020         jc      vesa2
1021         
1022         orb     %ah, %ah                # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
1023         jz      vesan                   # Certain BIOSes report 0x80-0xff!
1024
1025         cmpw    $0x0800, %ax
1026         jnc     vesae
1027
1028 vesa2:  pushw   %cx
1029         movw    %ax, %cx                        # Get mode information structure
1030         movw    $0x4f01, %ax
1031         int     $0x10
1032         movw    %cx, %bx                        # BX=mode number
1033         addb    $VIDEO_FIRST_VESA>>8, %bh
1034         popw    %cx
1035         cmpw    $0x004f, %ax
1036         jnz     vesan                   # Don't report errors (buggy BIOSES)
1037
1038         movb    (%di), %al                      # Check capabilities. We require
1039         andb    $0x19, %al                      # a color text mode.
1040         cmpb    $0x09, %al
1041         jnz     vesan
1042         
1043         cmpw    $0xb800, 8(%di)         # Standard video memory address required
1044         jnz     vesan
1045
1046         testb   $2, (%di)                       # Mode characteristics supplied?
1047         movw    %bx, (%di)                      # Store mode number
1048         jz      vesa3
1049         
1050         xorw    %dx, %dx
1051         movw    0x12(%di), %bx                  # Width
1052         orb     %bh, %bh
1053         jnz     vesan
1054         
1055         movb    %bl, 0x3(%di)
1056         movw    0x14(%di), %ax                  # Height
1057         orb     %ah, %ah
1058         jnz     vesan
1059         
1060         movb    %al, 2(%di)
1061         mulb    %bl
1062         cmpw    $8193, %ax              # Small enough for Linux console driver?
1063         jnc     vesan
1064
1065         jmp     vesaok
1066
1067 vesa3:  subw    $0x8108, %bx    # This mode has no detailed info specified,
1068         jc      vesan           # so it must be a standard VESA mode.
1069
1070         cmpw    $5, %bx
1071         jnc     vesan
1072
1073         movw    vesa_text_mode_table(%bx), %ax
1074         movw    %ax, 2(%di)
1075 vesaok: addw    $4, %di                         # The mode is valid. Store it.
1076 vesan:  loop    vesa1                   # Next mode. Limit exceeded => error
1077 vesae:  leaw    vesaer, %si
1078         call    prtstr
1079         movw    %bp, %di                        # Discard already found modes.
1080 vesar:  popw    %gs
1081         ret
1082
1083 # Dimensions of standard VESA text modes
1084 vesa_text_mode_table:
1085         .byte   60, 80                          # 0108
1086         .byte   25, 132                         # 0109
1087         .byte   43, 132                         # 010A
1088         .byte   50, 132                         # 010B
1089         .byte   60, 132                         # 010C
1090 #endif  /* CONFIG_VIDEO_VESA */
1091
1092 # Scan for video modes. A bit dirty, but should work.
1093 mode_scan:
1094         movw    $0x0100, %cx                    # Start with mode 0
1095 scm1:   movb    $0, %ah                         # Test the mode
1096         movb    %cl, %al
1097         int     $0x10
1098         movb    $0x0f, %ah
1099         int     $0x10
1100         cmpb    %cl, %al
1101         jnz     scm2                            # Mode not set
1102
1103         movw    $0x3c0, %dx                     # Test if it's a text mode
1104         movb    $0x10, %al                      # Mode bits
1105         call    inidx
1106         andb    $0x03, %al
1107         jnz     scm2
1108         
1109         movb    $0xce, %dl                      # Another set of mode bits
1110         movb    $0x06, %al
1111         call    inidx
1112         shrb    %al
1113         jc      scm2
1114         
1115         movb    $0xd4, %dl                      # Cursor location
1116         movb    $0x0f, %al
1117         call    inidx
1118         orb     %al, %al
1119         jnz     scm2
1120         
1121         movw    %cx, %ax                        # Ok, store the mode
1122         stosw
1123         movb    %gs:(0x484), %al                # Number of rows
1124         incb    %al
1125         stosb
1126         movw    %gs:(0x44a), %ax                # Number of columns
1127         stosb
1128 scm2:   incb    %cl
1129         jns     scm1
1130         
1131         movw    $0x0003, %ax                    # Return back to mode 3
1132         int     $0x10
1133         ret
1134
1135 tstidx: outw    %ax, %dx                        # OUT DX,AX and inidx
1136 inidx:  outb    %al, %dx                        # Read from indexed VGA register
1137         incw    %dx                     # AL=index, DX=index reg port -> AL=data
1138         inb     %dx, %al
1139         decw    %dx
1140         ret
1141
1142 # Try to detect type of SVGA card and supply (usually approximate) video
1143 # mode table for it.
1144
1145 #ifdef CONFIG_VIDEO_SVGA
1146 svga_modes:
1147         leaw    svga_table, %si                 # Test all known SVGA adapters
1148 dosvga: lodsw
1149         movw    %ax, %bp                        # Default mode table
1150         orw     %ax, %ax
1151         jz      didsv1
1152
1153         lodsw                                   # Pointer to test routine
1154         pushw   %si
1155         pushw   %di
1156         pushw   %es
1157         movw    $0xc000, %bx
1158         movw    %bx, %es
1159         call    *%ax                            # Call test routine
1160         popw    %es
1161         popw    %di
1162         popw    %si
1163         orw     %bp, %bp
1164         jz      dosvga
1165         
1166         movw    %bp, %si                        # Found, copy the modes
1167         movb    svga_prefix, %ah
1168 cpsvga: lodsb
1169         orb     %al, %al
1170         jz      didsv
1171         
1172         stosw
1173         movsw
1174         jmp     cpsvga
1175
1176 didsv:  movw    %si, card_name                  # Store pointer to card name
1177 didsv1: ret
1178
1179 # Table of all known SVGA cards. For each card, we store a pointer to
1180 # a table of video modes supported by the card and a pointer to a routine
1181 # used for testing of presence of the card. The video mode table is always
1182 # followed by the name of the card or the chipset.
1183 svga_table:
1184         .word   ati_md, ati_test
1185         .word   oak_md, oak_test
1186         .word   paradise_md, paradise_test
1187         .word   realtek_md, realtek_test
1188         .word   s3_md, s3_test
1189         .word   chips_md, chips_test
1190         .word   video7_md, video7_test
1191         .word   cirrus5_md, cirrus5_test
1192         .word   cirrus6_md, cirrus6_test
1193         .word   cirrus1_md, cirrus1_test
1194         .word   ahead_md, ahead_test
1195         .word   everex_md, everex_test
1196         .word   genoa_md, genoa_test
1197         .word   trident_md, trident_test
1198         .word   tseng_md, tseng_test
1199         .word   0
1200
1201 # Test routines and mode tables:
1202
1203 # S3 - The test algorithm was taken from the SuperProbe package
1204 # for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
1205 s3_test:
1206         movw    $0x0f35, %cx    # we store some constants in cl/ch
1207         movw    $0x03d4, %dx
1208         movb    $0x38, %al
1209         call    inidx
1210         movb    %al, %bh        # store current CRT-register 0x38
1211         movw    $0x0038, %ax
1212         call    outidx          # disable writing to special regs
1213         movb    %cl, %al        # check whether we can write special reg 0x35
1214         call    inidx
1215         movb    %al, %bl        # save the current value of CRT reg 0x35
1216         andb    $0xf0, %al      # clear bits 0-3
1217         movb    %al, %ah
1218         movb    %cl, %al        # and write it to CRT reg 0x35
1219         call    outidx
1220         call    inidx           # now read it back
1221         andb    %ch, %al        # clear the upper 4 bits
1222         jz      s3_2            # the first test failed. But we have a
1223
1224         movb    %bl, %ah        # second chance
1225         movb    %cl, %al
1226         call    outidx
1227         jmp     s3_1            # do the other tests
1228
1229 s3_2:   movw    %cx, %ax        # load ah with 0xf and al with 0x35
1230         orb     %bl, %ah        # set the upper 4 bits of ah with the orig value
1231         call    outidx          # write ...
1232         call    inidx           # ... and reread 
1233         andb    %cl, %al        # turn off the upper 4 bits
1234         pushw   %ax
1235         movb    %bl, %ah        # restore old value in register 0x35
1236         movb    %cl, %al
1237         call    outidx
1238         popw    %ax
1239         cmpb    %ch, %al        # setting lower 4 bits was successful => bad
1240         je      no_s3           # writing is allowed => this is not an S3
1241
1242 s3_1:   movw    $0x4838, %ax    # allow writing to special regs by putting
1243         call    outidx          # magic number into CRT-register 0x38
1244         movb    %cl, %al        # check whether we can write special reg 0x35
1245         call    inidx
1246         movb    %al, %bl
1247         andb    $0xf0, %al
1248         movb    %al, %ah
1249         movb    %cl, %al
1250         call    outidx
1251         call    inidx
1252         andb    %ch, %al
1253         jnz     no_s3           # no, we can't write => no S3
1254
1255         movw    %cx, %ax
1256         orb     %bl, %ah
1257         call    outidx
1258         call    inidx
1259         andb    %ch, %al
1260         pushw   %ax
1261         movb    %bl, %ah        # restore old value in register 0x35
1262         movb    %cl, %al
1263         call    outidx
1264         popw    %ax
1265         cmpb    %ch, %al
1266         jne     no_s31          # writing not possible => no S3
1267         movb    $0x30, %al
1268         call    inidx           # now get the S3 id ...
1269         leaw    idS3, %di
1270         movw    $0x10, %cx
1271         repne
1272         scasb
1273         je      no_s31
1274
1275         movb    %bh, %ah
1276         movb    $0x38, %al
1277         jmp     s3rest
1278
1279 no_s3:  movb    $0x35, %al      # restore CRT register 0x35
1280         movb    %bl, %ah
1281         call    outidx
1282 no_s31: xorw    %bp, %bp        # Detection failed
1283 s3rest: movb    %bh, %ah
1284         movb    $0x38, %al      # restore old value of CRT register 0x38
1285         jmp     outidx
1286
1287 idS3:   .byte   0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
1288         .byte   0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
1289
1290 s3_md:  .byte   0x54, 0x2b, 0x84
1291         .byte   0x55, 0x19, 0x84
1292         .byte   0
1293         .ascii  "S3"
1294         .byte   0
1295
1296 # ATI cards.
1297 ati_test:
1298         leaw    idati, %si
1299         movw    $0x31, %di
1300         movw    $0x09, %cx
1301         repe
1302         cmpsb
1303         je      atiok
1304
1305         xorw    %bp, %bp
1306 atiok:  ret
1307
1308 idati:  .ascii  "761295520"
1309
1310 ati_md: .byte   0x23, 0x19, 0x84
1311         .byte   0x33, 0x2c, 0x84
1312         .byte   0x22, 0x1e, 0x64
1313         .byte   0x21, 0x19, 0x64
1314         .byte   0x58, 0x21, 0x50
1315         .byte   0x5b, 0x1e, 0x50
1316         .byte   0
1317         .ascii  "ATI"
1318         .byte   0
1319
1320 # AHEAD
1321 ahead_test:
1322         movw    $0x200f, %ax
1323         movw    $0x3ce, %dx
1324         outw    %ax, %dx
1325         incw    %dx
1326         inb     %dx, %al
1327         cmpb    $0x20, %al
1328         je      isahed
1329
1330         cmpb    $0x21, %al
1331         je      isahed
1332         
1333         xorw    %bp, %bp
1334 isahed: ret
1335
1336 ahead_md:
1337         .byte   0x22, 0x2c, 0x84
1338         .byte   0x23, 0x19, 0x84
1339         .byte   0x24, 0x1c, 0x84
1340         .byte   0x2f, 0x32, 0xa0
1341         .byte   0x32, 0x22, 0x50
1342         .byte   0x34, 0x42, 0x50
1343         .byte   0
1344         .ascii  "Ahead"
1345         .byte   0
1346
1347 # Chips & Tech.
1348 chips_test:
1349         movw    $0x3c3, %dx
1350         inb     %dx, %al
1351         orb     $0x10, %al
1352         outb    %al, %dx
1353         movw    $0x104, %dx
1354         inb     %dx, %al
1355         movb    %al, %bl
1356         movw    $0x3c3, %dx
1357         inb     %dx, %al
1358         andb    $0xef, %al
1359         outb    %al, %dx
1360         cmpb    $0xa5, %bl
1361         je      cantok
1362         
1363         xorw    %bp, %bp
1364 cantok: ret
1365
1366 chips_md:
1367         .byte   0x60, 0x19, 0x84
1368         .byte   0x61, 0x32, 0x84
1369         .byte   0
1370         .ascii  "Chips & Technologies"
1371         .byte   0
1372
1373 # Cirrus Logic 5X0
1374 cirrus1_test:
1375         movw    $0x3d4, %dx
1376         movb    $0x0c, %al
1377         outb    %al, %dx
1378         incw    %dx
1379         inb     %dx, %al
1380         movb    %al, %bl
1381         xorb    %al, %al
1382         outb    %al, %dx
1383         decw    %dx
1384         movb    $0x1f, %al
1385         outb    %al, %dx
1386         incw    %dx
1387         inb     %dx, %al
1388         movb    %al, %bh
1389         xorb    %ah, %ah
1390         shlb    $4, %al
1391         movw    %ax, %cx
1392         movb    %bh, %al
1393         shrb    $4, %al
1394         addw    %ax, %cx
1395         shlw    $8, %cx
1396         addw    $6, %cx
1397         movw    %cx, %ax
1398         movw    $0x3c4, %dx
1399         outw    %ax, %dx
1400         incw    %dx
1401         inb     %dx, %al
1402         andb    %al, %al
1403         jnz     nocirr
1404         
1405         movb    %bh, %al
1406         outb    %al, %dx
1407         inb     %dx, %al
1408         cmpb    $0x01, %al
1409         je      iscirr
1410
1411 nocirr: xorw    %bp, %bp
1412 iscirr: movw    $0x3d4, %dx
1413         movb    %bl, %al
1414         xorb    %ah, %ah
1415         shlw    $8, %ax
1416         addw    $0x0c, %ax
1417         outw    %ax, %dx
1418         ret
1419
1420 cirrus1_md:
1421         .byte   0x1f, 0x19, 0x84
1422         .byte   0x20, 0x2c, 0x84
1423         .byte   0x22, 0x1e, 0x84
1424         .byte   0x31, 0x25, 0x64
1425         .byte   0
1426         .ascii  "Cirrus Logic 5X0"
1427         .byte   0
1428
1429 # Cirrus Logic 54XX
1430 cirrus5_test:
1431         movw    $0x3c4, %dx
1432         movb    $6, %al
1433         call    inidx
1434         movb    %al, %bl                        # BL=backup
1435         movw    $6, %ax
1436         call    tstidx
1437         cmpb    $0x0f, %al
1438         jne     c5fail
1439         
1440         movw    $0x1206, %ax
1441         call    tstidx
1442         cmpb    $0x12, %al
1443         jne     c5fail
1444         
1445         movb    $0x1e, %al
1446         call    inidx
1447         movb    %al, %bh
1448         movb    %bh, %ah
1449         andb    $0xc0, %ah
1450         movb    $0x1e, %al
1451         call    tstidx
1452         andb    $0x3f, %al
1453         jne     c5xx
1454         
1455         movb    $0x1e, %al
1456         movb    %bh, %ah
1457         orb     $0x3f, %ah
1458         call    tstidx
1459         xorb    $0x3f, %al
1460         andb    $0x3f, %al
1461 c5xx:   pushf
1462         movb    $0x1e, %al
1463         movb    %bh, %ah
1464         outw    %ax, %dx
1465         popf
1466         je      c5done
1467
1468 c5fail: xorw    %bp, %bp
1469 c5done: movb    $6, %al
1470         movb    %bl, %ah
1471         outw    %ax, %dx
1472         ret
1473
1474 cirrus5_md:
1475         .byte   0x14, 0x19, 0x84
1476         .byte   0x54, 0x2b, 0x84
1477         .byte   0
1478         .ascii  "Cirrus Logic 54XX"
1479         .byte   0
1480
1481 # Cirrus Logic 64XX -- no known extra modes, but must be identified, because
1482 # it's misidentified by the Ahead test.
1483 cirrus6_test:
1484         movw    $0x3ce, %dx
1485         movb    $0x0a, %al
1486         call    inidx
1487         movb    %al, %bl        # BL=backup
1488         movw    $0xce0a, %ax
1489         call    tstidx
1490         orb     %al, %al
1491         jne     c2fail
1492         
1493         movw    $0xec0a, %ax
1494         call    tstidx
1495         cmpb    $0x01, %al
1496         jne     c2fail
1497         
1498         movb    $0xaa, %al
1499         call    inidx           # 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
1500         shrb    $4, %al
1501         subb    $4, %al
1502         jz      c6done
1503         
1504         decb    %al
1505         jz      c6done
1506         
1507         subb    $2, %al
1508         jz      c6done
1509         
1510         decb    %al
1511         jz      c6done
1512         
1513 c2fail: xorw    %bp, %bp
1514 c6done: movb    $0x0a, %al
1515         movb    %bl, %ah
1516         outw    %ax, %dx
1517         ret
1518
1519 cirrus6_md:
1520         .byte   0
1521         .ascii  "Cirrus Logic 64XX"
1522         .byte   0
1523
1524 # Everex / Trident
1525 everex_test:
1526         movw    $0x7000, %ax
1527         xorw    %bx, %bx
1528         int     $0x10
1529         cmpb    $0x70, %al
1530         jne     noevrx
1531         
1532         shrw    $4, %dx
1533         cmpw    $0x678, %dx
1534         je      evtrid
1535         
1536         cmpw    $0x236, %dx
1537         jne     evrxok
1538
1539 evtrid: leaw    trident_md, %bp
1540 evrxok: ret
1541
1542 noevrx: xorw    %bp, %bp
1543         ret
1544
1545 everex_md:
1546         .byte   0x03, 0x22, 0x50
1547         .byte   0x04, 0x3c, 0x50
1548         .byte   0x07, 0x2b, 0x64
1549         .byte   0x08, 0x4b, 0x64
1550         .byte   0x0a, 0x19, 0x84
1551         .byte   0x0b, 0x2c, 0x84
1552         .byte   0x16, 0x1e, 0x50
1553         .byte   0x18, 0x1b, 0x64
1554         .byte   0x21, 0x40, 0xa0
1555         .byte   0x40, 0x1e, 0x84
1556         .byte   0
1557         .ascii  "Everex/Trident"
1558         .byte   0
1559
1560 # Genoa.
1561 genoa_test:
1562         leaw    idgenoa, %si                    # Check Genoa 'clues'
1563         xorw    %ax, %ax
1564         movb    %es:(0x37), %al
1565         movw    %ax, %di
1566         movw    $0x04, %cx
1567         decw    %si
1568         decw    %di
1569 l1:     incw    %si
1570         incw    %di
1571         movb    (%si), %al
1572         testb   %al, %al
1573         jz      l2
1574
1575         cmpb    %es:(%di), %al
1576 l2:     loope   l1
1577         orw     %cx, %cx
1578         je      isgen
1579         
1580         xorw    %bp, %bp
1581 isgen:  ret
1582
1583 idgenoa: .byte  0x77, 0x00, 0x99, 0x66
1584
1585 genoa_md:
1586         .byte   0x58, 0x20, 0x50
1587         .byte   0x5a, 0x2a, 0x64
1588         .byte   0x60, 0x19, 0x84
1589         .byte   0x61, 0x1d, 0x84
1590         .byte   0x62, 0x20, 0x84
1591         .byte   0x63, 0x2c, 0x84
1592         .byte   0x64, 0x3c, 0x84
1593         .byte   0x6b, 0x4f, 0x64
1594         .byte   0x72, 0x3c, 0x50
1595         .byte   0x74, 0x42, 0x50
1596         .byte   0x78, 0x4b, 0x64
1597         .byte   0
1598         .ascii  "Genoa"
1599         .byte   0
1600
1601 # OAK
1602 oak_test:
1603         leaw    idoakvga, %si
1604         movw    $0x08, %di
1605         movw    $0x08, %cx
1606         repe
1607         cmpsb
1608         je      isoak
1609         
1610         xorw    %bp, %bp
1611 isoak:  ret
1612
1613 idoakvga: .ascii  "OAK VGA "
1614
1615 oak_md: .byte   0x4e, 0x3c, 0x50
1616         .byte   0x4f, 0x3c, 0x84
1617         .byte   0x50, 0x19, 0x84
1618         .byte   0x51, 0x2b, 0x84
1619         .byte   0
1620         .ascii  "OAK"
1621         .byte   0
1622
1623 # WD Paradise.
1624 paradise_test:
1625         leaw    idparadise, %si
1626         movw    $0x7d, %di
1627         movw    $0x04, %cx
1628         repe
1629         cmpsb
1630         je      ispara
1631         
1632         xorw    %bp, %bp
1633 ispara: ret
1634
1635 idparadise:     .ascii  "VGA="
1636
1637 paradise_md:
1638         .byte   0x41, 0x22, 0x50
1639         .byte   0x47, 0x1c, 0x84
1640         .byte   0x55, 0x19, 0x84
1641         .byte   0x54, 0x2c, 0x84
1642         .byte   0
1643         .ascii  "Paradise"
1644         .byte   0
1645
1646 # Trident.
1647 trident_test:
1648         movw    $0x3c4, %dx
1649         movb    $0x0e, %al
1650         outb    %al, %dx
1651         incw    %dx
1652         inb     %dx, %al
1653         xchgb   %al, %ah
1654         xorb    %al, %al
1655         outb    %al, %dx
1656         inb     %dx, %al
1657         xchgb   %ah, %al
1658         movb    %al, %bl        # Strange thing ... in the book this wasn't
1659         andb    $0x02, %bl      # necessary but it worked on my card which
1660         jz      setb2           # is a trident. Without it the screen goes
1661                                 # blurred ...
1662         andb    $0xfd, %al
1663         jmp     clrb2           
1664
1665 setb2:  orb     $0x02, %al      
1666 clrb2:  outb    %al, %dx
1667         andb    $0x0f, %ah
1668         cmpb    $0x02, %ah
1669         je      istrid
1670
1671         xorw    %bp, %bp
1672 istrid: ret
1673
1674 trident_md:
1675         .byte   0x50, 0x1e, 0x50
1676         .byte   0x51, 0x2b, 0x50
1677         .byte   0x52, 0x3c, 0x50
1678         .byte   0x57, 0x19, 0x84
1679         .byte   0x58, 0x1e, 0x84
1680         .byte   0x59, 0x2b, 0x84
1681         .byte   0x5a, 0x3c, 0x84
1682         .byte   0
1683         .ascii  "Trident"
1684         .byte   0
1685
1686 # Tseng.
1687 tseng_test:
1688         movw    $0x3cd, %dx
1689         inb     %dx, %al        # Could things be this simple ! :-)
1690         movb    %al, %bl
1691         movb    $0x55, %al
1692         outb    %al, %dx
1693         inb     %dx, %al
1694         movb    %al, %ah
1695         movb    %bl, %al
1696         outb    %al, %dx
1697         cmpb    $0x55, %ah
1698         je      istsen
1699
1700 isnot:  xorw    %bp, %bp
1701 istsen: ret
1702
1703 tseng_md:
1704         .byte   0x26, 0x3c, 0x50
1705         .byte   0x2a, 0x28, 0x64
1706         .byte   0x23, 0x19, 0x84
1707         .byte   0x24, 0x1c, 0x84
1708         .byte   0x22, 0x2c, 0x84
1709         .byte   0x21, 0x3c, 0x84
1710         .byte   0
1711         .ascii  "Tseng"
1712         .byte   0
1713
1714 # Video7.
1715 video7_test:
1716         movw    $0x3cc, %dx
1717         inb     %dx, %al
1718         movw    $0x3b4, %dx
1719         andb    $0x01, %al
1720         jz      even7
1721
1722         movw    $0x3d4, %dx
1723 even7:  movb    $0x0c, %al
1724         outb    %al, %dx
1725         incw    %dx
1726         inb     %dx, %al
1727         movb    %al, %bl
1728         movb    $0x55, %al
1729         outb    %al, %dx
1730         inb     %dx, %al
1731         decw    %dx
1732         movb    $0x1f, %al
1733         outb    %al, %dx
1734         incw    %dx
1735         inb     %dx, %al
1736         movb    %al, %bh
1737         decw    %dx
1738         movb    $0x0c, %al
1739         outb    %al, %dx
1740         incw    %dx
1741         movb    %bl, %al
1742         outb    %al, %dx
1743         movb    $0x55, %al
1744         xorb    $0xea, %al
1745         cmpb    %bh, %al
1746         jne     isnot
1747         
1748         movb    $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
1749         ret
1750
1751 video7_md:
1752         .byte   0x40, 0x2b, 0x50
1753         .byte   0x43, 0x3c, 0x50
1754         .byte   0x44, 0x3c, 0x64
1755         .byte   0x41, 0x19, 0x84
1756         .byte   0x42, 0x2c, 0x84
1757         .byte   0x45, 0x1c, 0x84
1758         .byte   0
1759         .ascii  "Video 7"
1760         .byte   0
1761
1762 # Realtek VGA
1763 realtek_test:
1764         leaw    idrtvga, %si
1765         movw    $0x45, %di
1766         movw    $0x0b, %cx
1767         repe
1768         cmpsb
1769         je      isrt
1770         
1771         xorw    %bp, %bp
1772 isrt:   ret
1773
1774 idrtvga:        .ascii  "REALTEK VGA"
1775
1776 realtek_md:
1777         .byte   0x1a, 0x3c, 0x50
1778         .byte   0x1b, 0x19, 0x84
1779         .byte   0x1c, 0x1e, 0x84
1780         .byte   0x1d, 0x2b, 0x84
1781         .byte   0x1e, 0x3c, 0x84
1782         .byte   0
1783         .ascii  "REALTEK"
1784         .byte   0
1785
1786 #endif  /* CONFIG_VIDEO_SVGA */
1787
1788 # User-defined local mode table (VGA only)
1789 #ifdef CONFIG_VIDEO_LOCAL
1790 local_modes:
1791         leaw    local_mode_table, %si
1792 locm1:  lodsw
1793         orw     %ax, %ax
1794         jz      locm2
1795         
1796         stosw
1797         movsw
1798         jmp     locm1
1799
1800 locm2:  ret
1801
1802 # This is the table of local video modes which can be supplied manually
1803 # by the user. Each entry consists of mode ID (word) and dimensions
1804 # (byte for column count and another byte for row count). These modes
1805 # are placed before all SVGA and VESA modes and override them if table
1806 # compacting is enabled. The table must end with a zero word followed
1807 # by NUL-terminated video adapter name.
1808 local_mode_table:
1809         .word   0x0100                          # Example: 40x25
1810         .byte   25,40
1811         .word   0
1812         .ascii  "Local"
1813         .byte   0
1814 #endif  /* CONFIG_VIDEO_LOCAL */
1815
1816 # Read a key and return the ASCII code in al, scan code in ah
1817 getkey: xorb    %ah, %ah
1818         int     $0x16
1819         ret
1820
1821 # Read a key with a timeout of 30 seconds.
1822 # The hardware clock is used to get the time.
1823 getkt:  call    gettime
1824         addb    $30, %al                        # Wait 30 seconds
1825         cmpb    $60, %al
1826         jl      lminute
1827
1828         subb    $60, %al
1829 lminute:
1830         movb    %al, %cl
1831 again:  movb    $0x01, %ah
1832         int     $0x16
1833         jnz     getkey                          # key pressed, so get it
1834
1835         call    gettime
1836         cmpb    %cl, %al
1837         jne     again
1838
1839         movb    $0x20, %al                      # timeout, return `space'
1840         ret
1841
1842 # Flush the keyboard buffer
1843 flush:  movb    $0x01, %ah
1844         int     $0x16
1845         jz      empty
1846         
1847         xorb    %ah, %ah
1848         int     $0x16
1849         jmp     flush
1850
1851 empty:  ret
1852
1853 # Print hexadecimal number.
1854 prthw:  pushw   %ax
1855         movb    %ah, %al
1856         call    prthb
1857         popw    %ax
1858 prthb:  pushw   %ax
1859         shrb    $4, %al
1860         call    prthn
1861         popw    %ax
1862         andb    $0x0f, %al
1863 prthn:  cmpb    $0x0a, %al
1864         jc      prth1
1865
1866         addb    $0x07, %al
1867 prth1:  addb    $0x30, %al
1868         jmp     prtchr
1869
1870 # Print decimal number in al
1871 prtdec: pushw   %ax
1872         pushw   %cx
1873         xorb    %ah, %ah
1874         movb    $0x0a, %cl
1875         idivb   %cl
1876         cmpb    $0x09, %al
1877         jbe     lt100
1878
1879         call    prtdec
1880         jmp     skip10
1881
1882 lt100:  addb    $0x30, %al
1883         call    prtchr
1884 skip10: movb    %ah, %al
1885         addb    $0x30, %al
1886         call    prtchr  
1887         popw    %cx
1888         popw    %ax
1889         ret
1890
1891 store_edid:
1892         pushw   %es                             # just save all registers 
1893         pushw   %ax                             
1894         pushw   %bx
1895         pushw   %cx
1896         pushw   %dx
1897         pushw   %di
1898
1899         pushw   %fs                             
1900         popw    %es
1901
1902         movl    $0x13131313, %eax               # memset block with 0x13
1903         movw    $32, %cx
1904         movw    $0x440, %di
1905         cld
1906         rep 
1907         stosl  
1908
1909         movw    $0x4f15, %ax                    # do VBE/DDC 
1910         movw    $0x01, %bx
1911         movw    $0x00, %cx
1912         movw    $0x01, %dx
1913         movw    $0x440, %di
1914         int     $0x10   
1915
1916         popw    %di                             # restore all registers        
1917         popw    %dx
1918         popw    %cx
1919         popw    %bx
1920         popw    %ax
1921         popw    %es     
1922         ret
1923
1924 # VIDEO_SELECT-only variables
1925 mt_end:         .word   0       # End of video mode table if built
1926 edit_buf:       .space  6       # Line editor buffer
1927 card_name:      .word   0       # Pointer to adapter name
1928 scanning:       .byte   0       # Performing mode scan
1929 do_restore:     .byte   0       # Screen contents altered during mode change
1930 svga_prefix:    .byte   VIDEO_FIRST_BIOS>>8     # Default prefix for BIOS modes
1931 graphic_mode:   .byte   0       # Graphic mode with a linear frame buffer
1932
1933 # Status messages
1934 keymsg:         .ascii  "Press <RETURN> to see video modes available, "
1935                 .ascii  "<SPACE> to continue or wait 30 secs"
1936                 .byte   0x0d, 0x0a, 0
1937
1938 listhdr:        .byte   0x0d, 0x0a
1939                 .ascii  "Mode:    COLSxROWS:"
1940
1941 crlft:          .byte   0x0d, 0x0a, 0
1942
1943 prompt:         .byte   0x0d, 0x0a
1944                 .asciz  "Enter mode number or `scan': "
1945
1946 unknt:          .asciz  "Unknown mode ID. Try again."
1947
1948 badmdt:         .ascii  "You passed an undefined mode number."
1949                 .byte   0x0d, 0x0a, 0
1950
1951 vesaer:         .ascii  "Error: Scanning of VESA modes failed. Please "
1952                 .ascii  "report to <mj@ucw.cz>."
1953                 .byte   0x0d, 0x0a, 0
1954
1955 old_name:       .asciz  "CGA/MDA/HGA"
1956
1957 ega_name:       .asciz  "EGA"
1958
1959 svga_name:      .ascii  " "
1960
1961 vga_name:       .asciz  "VGA"
1962
1963 vesa_name:      .asciz  "VESA"
1964
1965 name_bann:      .asciz  "Video adapter: "
1966 #endif /* CONFIG_VIDEO_SELECT */
1967
1968 # Other variables:
1969 adapter:        .byte   0       # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
1970 video_segment:  .word   0xb800  # Video memory segment
1971 force_size:     .word   0       # Use this size instead of the one in BIOS vars