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