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