PageRenderTime 58ms CodeModel.GetById 11ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 1ms

/arch/x86_64/boot/video.S

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