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