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