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