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