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