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