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