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