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