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