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