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