linux/arch/i386/boot/video.S
<<
>>
Prefs
   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
 109video:  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
 130vid2:   call    mode_menu
 131vid1:
 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.
 142basic_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
 159basret: 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.
 165mode_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
 182mopar0: 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
 192mopar1: 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.
 198mopar2: movb    %al, %fs:(PARAM_VIDEO_LINES)
 199        ret
 200
 201#ifdef CONFIG_VIDEO_SELECT
 202# Fetching of VESA frame buffer parameters
 203mopar_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
 258dac_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
 272dac_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)
 283no_pm:  ret
 284
 285# The video mode menu
 286mode_menu:
 287        leaw    keymsg, %si                     # "Return/Space/Timeout" message
 288        call    prtstr
 289        call    flush
 290nokey:  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
 301defmd1: ret                                     # No mode chosen? Default 80x25
 302
 303listm:  call    mode_table                      # List mode table
 304listm0: 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
 322an2:    call    prtstr
 323        leaw    svga_name, %si
 324an1:    call    prtstr
 325        leaw    listhdr, %si                    # Table header
 326        call    prtstr
 327        movb    $0x30, %dl                      # DL holds mode number
 328        leaw    modelist, %si
 329lm1:    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
 355lm2:    leaw    prompt, %si                     # Mode prompt
 356        call    prtstr
 357        leaw    edit_buf, %di                   # Editor buffer
 358lm3:    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
 375lmbs:   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        
 386lment:  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
 402lmhx:   xorw    %bx, %bx                        # Else => mode ID in hex
 403lmhex:  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
 421lmhx1:  shlw    $4, %bx
 422        orb     %al, %bl
 423        jmp     lmhex
 424
 425lmuse1: movw    %bx, %ax
 426        jmp     lmuse
 427
 428mnusel: 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
 443lmuse:  call    mode_set
 444        jc      lmdef
 445
 446lmbad:  leaw    unknt, %si
 447        call    prtstr
 448        jmp     lm2
 449lmscan: 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
 456lmdef:  ret
 457
 458# Additional parts of mode_set... (relative jumps, you know)
 459setv7:                                          # 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.
 471setalias:
 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
 481mode_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
 508setbad: clc
 509        movb    $0, do_restore                  # The screen needn't be restored
 510        ret
 511
 512setvesa:
 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
 523setbios:
 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
 536setspc: 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
 543setmenu:
 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
 558setres: pushw   %bx                             # Set mode chosen by resolution
 559        call    mode_table
 560        popw    %bx
 561        xchgb   %bl, %bh
 562setr1:  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
 573check_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
 621setrec: 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
 642rct1:   shrb    %bh
 643        jnc     rct2
 644        orb     $0x40, %ah
 645rct2:   movb    $0x07, %al
 646        outw    %ax, %dx
 647        stc
 648rct3:   ret
 649
 650# Table of routines for setting of the special modes.
 651spec_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.
 663set_80x25:
 664        movw    $0x5019, force_size             # Override possibly broken BIOS
 665use_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
 679st80:   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 */
 689force3: DO_STORE
 690        movw    $0x0003, %ax                    # Forced set
 691        int     $0x10
 692set80:  stc
 693        ret
 694
 695# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
 696set_8pixel:
 697        DO_STORE
 698        call    use_80x25                       # The base is 80x25
 699set_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
 712set_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.
 718set_80x28:
 719        DO_STORE
 720        call    use_80x25                       # The base is 80x25
 721set14:  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.
 732set_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.
 742set_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
 752set48a: 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.
 779set_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
 784setvde: call    outidx
 785        stc
 786        ret
 787
 788# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
 789set_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
 797set_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.
 810store_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
 845sts1:   popw    %bx
 846        popw    %ax
 847stsr:   ret
 848
 849# Restore screen contents from temporary buffer.
 850restore_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
 865res2:   cmpb    %ch, %dl
 866        jc      res3
 867        
 868        movb    %ch, %dl
 869        decb    %dl
 870res3:   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
 888res4:   cmpb    %ch, %al                        # Too wide?
 889        jc      res5
 890        
 891        movb    %ch, %al                        # AX=width of src. line
 892res5:   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
 900res6:   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
 913res1:   ret
 914#endif /* CONFIG_VIDEO_RETAIN */
 915
 916# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
 917outidx: 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.
 933mode_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
 952mtab1x: jmp     mtab1
 953
 954mtabv:  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
 963mscan1:
 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
 978mscan2:
 979#endif /* CONFIG_VIDEO_SVGA */
 980
 981mtabe:
 982
 983#ifdef CONFIG_VIDEO_COMPACT
 984        leaw    modelist, %si
 985        movw    %di, %dx
 986        movw    %si, %di
 987cmt1:   cmpw    %dx, %si                        # Scan all modes
 988        jz      cmt2
 989
 990        leaw    modelist, %bx                   # Find in previous entries
 991        movw    2(%si), %cx
 992cmt3:   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
1001cmt4:   movsl                                   # Copy entry
1002        jmp     cmt1
1003
1004cmt5:   addw    $4, %si                         # Skip entry
1005        jmp     cmt1
1006
1007cmt2:
1008#endif  /* CONFIG_VIDEO_COMPACT */
1009
1010        movw    $ASK_VGA, (%di)                 # End marker
1011        movw    %di, mt_end
1012mtab1:  leaw    modelist, %si                   # SI=mode list, DI=list end
1013ret0:   ret
1014
1015# Modes usable on all standard VGAs
1016vga_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
1034vga_modes_end:
1035# Detect VESA modes.
1036
1037#ifdef CONFIG_VIDEO_VESA
1038vesa_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
1060vesa1:
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
1076vesa2:  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
1115vesa3:  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)
1123vesaok: addw    $4, %di                         # The mode is valid. Store it.
1124vesan:  loop    vesa1                   # Next mode. Limit exceeded => error
1125vesae:  leaw    vesaer, %si
1126        call    prtstr
1127        movw    %bp, %di                        # Discard already found modes.
1128vesar:  popw    %gs
1129        ret
1130
1131# Dimensions of standard VESA text modes
1132vesa_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.
1141mode_scan:
1142        movw    $0x0100, %cx                    # Start with mode 0
1143scm1:   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
1176scm2:   incb    %cl
1177        jns     scm1
1178        
1179        movw    $0x0003, %ax                    # Return back to mode 3
1180        int     $0x10
1181        ret
1182
1183tstidx: outw    %ax, %dx                        # OUT DX,AX and inidx
1184inidx:  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
1194svga_modes:
1195        leaw    svga_table, %si                 # Test all known SVGA adapters
1196dosvga: 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
1216cpsvga: lodsb
1217        orb     %al, %al
1218        jz      didsv
1219        
1220        stosw
1221        movsw
1222        jmp     cpsvga
1223
1224didsv:  movw    %si, card_name                  # Store pointer to card name
1225didsv1: 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.
1231svga_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
1253s3_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
1277s3_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
1290s3_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
1327no_s3:  movb    $0x35, %al      # restore CRT register 0x35
1328        movb    %bl, %ah
1329        call    outidx
1330no_s31: xorw    %bp, %bp        # Detection failed
1331s3rest: movb    %bh, %ah
1332        movb    $0x38, %al      # restore old value of CRT register 0x38
1333        jmp     outidx
1334
1335idS3:   .byte   0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
1336        .byte   0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
1337
1338s3_md:  .byte   0x54, 0x2b, 0x84
1339        .byte   0x55, 0x19, 0x84
1340        .byte   0
1341        .ascii  "S3"
1342        .byte   0
1343
1344# ATI cards.
1345ati_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
1354atiok:  ret
1355
1356idati:  .ascii  "761295520"
1357
1358ati_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
1369ahead_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
1382isahed: ret
1383
1384ahead_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.
1396chips_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
1412cantok: ret
1413
1414chips_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
1422cirrus1_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
1459nocirr: xorw    %bp, %bp
1460iscirr: 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
1468cirrus1_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
1478cirrus5_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
1509c5xx:   pushf
1510        movb    $0x1e, %al
1511        movb    %bh, %ah
1512        outw    %ax, %dx
1513        popf
1514        je      c5done
1515
1516c5fail: xorw    %bp, %bp
1517c5done: movb    $6, %al
1518        movb    %bl, %ah
1519        outw    %ax, %dx
1520        ret
1521
1522cirrus5_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.
1531cirrus6_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        
1561c2fail: xorw    %bp, %bp
1562c6done: movb    $0x0a, %al
1563        movb    %bl, %ah
1564        outw    %ax, %dx
1565        ret
1566
1567cirrus6_md:
1568        .byte   0
1569        .ascii  "Cirrus Logic 64XX"
1570        .byte   0
1571
1572# Everex / Trident
1573everex_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
1587evtrid: leaw    trident_md, %bp
1588evrxok: ret
1589
1590noevrx: xorw    %bp, %bp
1591        ret
1592
1593everex_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.
1609genoa_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
1617l1:     incw    %si
1618        incw    %di
1619        movb    (%si), %al
1620        testb   %al, %al
1621        jz      l2
1622
1623        cmpb    %es:(%di), %al
1624l2:     loope   l1
1625        orw     %cx, %cx
1626        je      isgen
1627        
1628        xorw    %bp, %bp
1629isgen:  ret
1630
1631idgenoa: .byte  0x77, 0x00, 0x99, 0x66
1632
1633genoa_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
1650oak_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
1659isoak:  ret
1660
1661idoakvga: .ascii  "OAK VGA "
1662
1663oak_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.
1672paradise_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
1681ispara: ret
1682
1683idparadise:     .ascii  "VGA="
1684
1685paradise_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.
1695trident_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
1713setb2:  orb     $0x02, %al      
1714clrb2:  outb    %al, %dx
1715        andb    $0x0f, %ah
1716        cmpb    $0x02, %ah
1717        je      istrid
1718
1719        xorw    %bp, %bp
1720istrid: ret
1721
1722trident_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.
1735tseng_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
1748isnot:  xorw    %bp, %bp
1749istsen: ret
1750
1751tseng_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.
1763video7_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
1771even7:  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
1799video7_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
1811realtek_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
1820isrt:   ret
1821
1822idrtvga:        .ascii  "REALTEK VGA"
1823
1824realtek_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
1838local_modes:
1839        leaw    local_mode_table, %si
1840locm1:  lodsw
1841        orw     %ax, %ax
1842        jz      locm2
1843        
1844        stosw
1845        movsw
1846        jmp     locm1
1847
1848locm2:  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.
1856local_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
1865getkey: 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.
1871getkt:  call    gettime
1872        addb    $30, %al                        # Wait 30 seconds
1873        cmpb    $60, %al
1874        jl      lminute
1875
1876        subb    $60, %al
1877lminute:
1878        movb    %al, %cl
1879again:  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
1891flush:  movb    $0x01, %ah
1892        int     $0x16
1893        jz      empty
1894        
1895        xorb    %ah, %ah
1896        int     $0x16
1897        jmp     flush
1898
1899empty:  ret
1900
1901# Print hexadecimal number.
1902prthw:  pushw   %ax
1903        movb    %ah, %al
1904        call    prthb
1905        popw    %ax
1906prthb:  pushw   %ax
1907        shrb    $4, %al
1908        call    prthn
1909        popw    %ax
1910        andb    $0x0f, %al
1911prthn:  cmpb    $0x0a, %al
1912        jc      prth1
1913
1914        addb    $0x07, %al
1915prth1:  addb    $0x30, %al
1916        jmp     prtchr
1917
1918# Print decimal number in al
1919prtdec: 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
1930lt100:  addb    $0x30, %al
1931        call    prtchr
1932skip10: movb    %ah, %al
1933        addb    $0x30, %al
1934        call    prtchr  
1935        popw    %cx
1936        popw    %ax
1937        ret
1938
1939store_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
1984no_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
1995mt_end:         .word   0       # End of video mode table if built
1996edit_buf:       .space  6       # Line editor buffer
1997card_name:      .word   0       # Pointer to adapter name
1998scanning:       .byte   0       # Performing mode scan
1999do_restore:     .byte   0       # Screen contents altered during mode change
2000svga_prefix:    .byte   VIDEO_FIRST_BIOS>>8     # Default prefix for BIOS modes
2001graphic_mode:   .byte   0       # Graphic mode with a linear frame buffer
2002dac_size:       .byte   6       # DAC bit depth
2003vbe_version:    .word   0       # VBE bios version
2004
2005# Status messages
2006keymsg:         .ascii  "Press <RETURN> to see video modes available, "
2007                .ascii  "<SPACE> to continue or wait 30 secs"
2008                .byte   0x0d, 0x0a, 0
2009
2010listhdr:        .byte   0x0d, 0x0a
2011                .ascii  "Mode:    COLSxROWS:"
2012
2013crlft:          .byte   0x0d, 0x0a, 0
2014
2015prompt:         .byte   0x0d, 0x0a
2016                .asciz  "Enter mode number or `scan': "
2017
2018unknt:          .asciz  "Unknown mode ID. Try again."
2019
2020badmdt:         .ascii  "You passed an undefined mode number."
2021                .byte   0x0d, 0x0a, 0
2022
2023vesaer:         .ascii  "Error: Scanning of VESA modes failed. Please "
2024                .ascii  "report to <mj@ucw.cz>."
2025                .byte   0x0d, 0x0a, 0
2026
2027old_name:       .asciz  "CGA/MDA/HGA"
2028
2029ega_name:       .asciz  "EGA"
2030
2031svga_name:      .ascii  " "
2032
2033vga_name:       .asciz  "VGA"
2034
2035vesa_name:      .asciz  "VESA"
2036
2037name_bann:      .asciz  "Video adapter: "
2038#endif /* CONFIG_VIDEO_SELECT */
2039
2040# Other variables:
2041adapter:        .byte   0       # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
2042video_segment:  .word   0xb800  # Video memory segment
2043force_size:     .word   0       # Use this size instead of the one in BIOS vars
2044
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.