Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/boot/video-mode.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/* -*- linux-c -*- ------------------------------------------------------- *
3
*
4
* Copyright (C) 1991, 1992 Linus Torvalds
5
* Copyright 2007-2008 rPath, Inc. - All Rights Reserved
6
*
7
* ----------------------------------------------------------------------- */
8
9
/*
10
* arch/i386/boot/video-mode.c
11
*
12
* Set the video mode. This is separated out into a different
13
* file in order to be shared with the ACPI wakeup code.
14
*/
15
16
#include "boot.h"
17
#include "video.h"
18
#include "vesa.h"
19
20
#include <uapi/asm/boot.h>
21
22
/*
23
* Common variables
24
*/
25
int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
26
int force_x, force_y; /* Don't query the BIOS for cols/rows */
27
int do_restore; /* Screen contents changed during mode flip */
28
int graphic_mode; /* Graphic mode with linear frame buffer */
29
30
/* Probe the video drivers and have them generate their mode lists. */
31
void probe_cards(int unsafe)
32
{
33
struct card_info *card;
34
static u8 probed[2];
35
36
if (probed[unsafe])
37
return;
38
39
probed[unsafe] = 1;
40
41
for (card = video_cards; card < video_cards_end; card++) {
42
if (card->unsafe == unsafe) {
43
if (card->probe)
44
card->nmodes = card->probe();
45
else
46
card->nmodes = 0;
47
}
48
}
49
}
50
51
/* Test if a mode is defined */
52
int mode_defined(u16 mode)
53
{
54
struct card_info *card;
55
struct mode_info *mi;
56
int i;
57
58
for (card = video_cards; card < video_cards_end; card++) {
59
mi = card->modes;
60
for (i = 0; i < card->nmodes; i++, mi++) {
61
if (mi->mode == mode)
62
return 1;
63
}
64
}
65
66
return 0;
67
}
68
69
/* Set mode (without recalc) */
70
static int raw_set_mode(u16 mode, u16 *real_mode)
71
{
72
int nmode, i;
73
struct card_info *card;
74
struct mode_info *mi;
75
76
/* Drop the recalc bit if set */
77
mode &= ~VIDEO_RECALC;
78
79
/* Scan for mode based on fixed ID, position, or resolution */
80
nmode = 0;
81
for (card = video_cards; card < video_cards_end; card++) {
82
mi = card->modes;
83
for (i = 0; i < card->nmodes; i++, mi++) {
84
int visible = mi->x || mi->y;
85
86
if ((mode == nmode && visible) ||
87
mode == mi->mode ||
88
mode == (mi->y << 8)+mi->x) {
89
*real_mode = mi->mode;
90
return card->set_mode(mi);
91
}
92
93
if (visible)
94
nmode++;
95
}
96
}
97
98
/* Nothing found? Is it an "exceptional" (unprobed) mode? */
99
for (card = video_cards; card < video_cards_end; card++) {
100
if (mode >= card->xmode_first &&
101
mode < card->xmode_first+card->xmode_n) {
102
struct mode_info mix;
103
*real_mode = mix.mode = mode;
104
mix.x = mix.y = 0;
105
return card->set_mode(&mix);
106
}
107
}
108
109
/* Otherwise, failure... */
110
return -1;
111
}
112
113
/*
114
* Recalculate the vertical video cutoff (hack!)
115
*/
116
static void vga_recalc_vertical(void)
117
{
118
unsigned int font_size, rows;
119
u16 crtc;
120
u8 pt, ov;
121
122
set_fs(0);
123
font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
124
rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
125
126
rows *= font_size; /* Visible scan lines */
127
rows--; /* ... minus one */
128
129
crtc = vga_crtc();
130
131
pt = in_idx(crtc, 0x11);
132
pt &= ~0x80; /* Unlock CR0-7 */
133
out_idx(pt, crtc, 0x11);
134
135
out_idx((u8)rows, crtc, 0x12); /* Lower height register */
136
137
ov = in_idx(crtc, 0x07); /* Overflow register */
138
ov &= 0xbd;
139
ov |= (rows >> (8-1)) & 0x02;
140
ov |= (rows >> (9-6)) & 0x40;
141
out_idx(ov, crtc, 0x07);
142
}
143
144
/* Set mode (with recalc if specified) */
145
int set_mode(u16 mode)
146
{
147
int rv;
148
u16 real_mode;
149
150
/* Very special mode numbers... */
151
if (mode == VIDEO_CURRENT_MODE)
152
return 0; /* Nothing to do... */
153
else if (mode == NORMAL_VGA)
154
mode = VIDEO_80x25;
155
else if (mode == EXTENDED_VGA)
156
mode = VIDEO_8POINT;
157
158
rv = raw_set_mode(mode, &real_mode);
159
if (rv)
160
return rv;
161
162
if (mode & VIDEO_RECALC)
163
vga_recalc_vertical();
164
165
/* Save the canonical mode number for the kernel, not
166
an alias, size specification or menu position */
167
#ifndef _WAKEUP
168
boot_params.hdr.vid_mode = real_mode;
169
#endif
170
return 0;
171
}
172
173