1// SPDX-License-Identifier: GPL-2.0-only
2/* -*- linux-c -*- ------------------------------------------------------- *
3 *
4 *   Copyright (C) 1991, 1992 Linus Torvalds
5 *   Copyright 2007 rPath, Inc. - All Rights Reserved
6 *   Copyright 2009 Intel Corporation; author H. Peter Anvin
7 *
8 * ----------------------------------------------------------------------- */
9
10/*
11 * Standard video BIOS modes
12 *
13 * We have two options for this; silent and scanned.
14 */
15
16#include "boot.h"
17#include "video.h"
18
19static __videocard video_bios;
20
21/* Set a conventional BIOS mode */
22static int set_bios_mode(u8 mode);
23
24static int bios_set_mode(struct mode_info *mi)
25{
26	return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
27}
28
29static int set_bios_mode(u8 mode)
30{
31	struct biosregs ireg, oreg;
32	u8 new_mode;
33
34	initregs(&ireg);
35	ireg.al = mode;		/* AH=0x00 Set Video Mode */
36	intcall(0x10, &ireg, NULL);
37
38	ireg.ah = 0x0f;		/* Get Current Video Mode */
39	intcall(0x10, &ireg, &oreg);
40
41	do_restore = 1;		/* Assume video contents were lost */
42
43	/* Not all BIOSes are clean with the top bit */
44	new_mode = oreg.al & 0x7f;
45
46	if (new_mode == mode)
47		return 0;	/* Mode change OK */
48
49#ifndef _WAKEUP
50	if (new_mode != boot_params.screen_info.orig_video_mode) {
51		/* Mode setting failed, but we didn't end up where we
52		   started.  That's bad.  Try to revert to the original
53		   video mode. */
54		ireg.ax = boot_params.screen_info.orig_video_mode;
55		intcall(0x10, &ireg, NULL);
56	}
57#endif
58	return -1;
59}
60
61static int bios_probe(void)
62{
63	u8 mode;
64#ifdef _WAKEUP
65	u8 saved_mode = 0x03;
66#else
67	u8 saved_mode = boot_params.screen_info.orig_video_mode;
68#endif
69	u16 crtc;
70	struct mode_info *mi;
71	int nmodes = 0;
72
73	if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
74		return 0;
75
76	set_fs(0);
77	crtc = vga_crtc();
78
79	video_bios.modes = GET_HEAP(struct mode_info, 0);
80
81	for (mode = 0x14; mode <= 0x7f; mode++) {
82		if (!heap_free(sizeof(struct mode_info)))
83			break;
84
85		if (mode_defined(VIDEO_FIRST_BIOS+mode))
86			continue;
87
88		if (set_bios_mode(mode))
89			continue;
90
91		/* Try to verify that it's a text mode. */
92
93		/* Attribute Controller: make graphics controller disabled */
94		if (in_idx(0x3c0, 0x10) & 0x01)
95			continue;
96
97		/* Graphics Controller: verify Alpha addressing enabled */
98		if (in_idx(0x3ce, 0x06) & 0x01)
99			continue;
100
101		/* CRTC cursor location low should be zero(?) */
102		if (in_idx(crtc, 0x0f))
103			continue;
104
105		mi = GET_HEAP(struct mode_info, 1);
106		mi->mode = VIDEO_FIRST_BIOS+mode;
107		mi->depth = 0;	/* text */
108		mi->x = rdfs16(0x44a);
109		mi->y = rdfs8(0x484)+1;
110		nmodes++;
111	}
112
113	set_bios_mode(saved_mode);
114
115	return nmodes;
116}
117
118static __videocard video_bios =
119{
120	.card_name	= "BIOS",
121	.probe		= bios_probe,
122	.set_mode	= bios_set_mode,
123	.unsafe		= 1,
124	.xmode_first	= VIDEO_FIRST_BIOS,
125	.xmode_n	= 0x80,
126};
127