Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/boot/video-vga.c
10817 views
1
/* -*- linux-c -*- ------------------------------------------------------- *
2
*
3
* Copyright (C) 1991, 1992 Linus Torvalds
4
* Copyright 2007 rPath, Inc. - All Rights Reserved
5
* Copyright 2009 Intel Corporation; author H. Peter Anvin
6
*
7
* This file is part of the Linux kernel, and is made available under
8
* the terms of the GNU General Public License version 2.
9
*
10
* ----------------------------------------------------------------------- */
11
12
/*
13
* Common all-VGA modes
14
*/
15
16
#include "boot.h"
17
#include "video.h"
18
19
static struct mode_info vga_modes[] = {
20
{ VIDEO_80x25, 80, 25, 0 },
21
{ VIDEO_8POINT, 80, 50, 0 },
22
{ VIDEO_80x43, 80, 43, 0 },
23
{ VIDEO_80x28, 80, 28, 0 },
24
{ VIDEO_80x30, 80, 30, 0 },
25
{ VIDEO_80x34, 80, 34, 0 },
26
{ VIDEO_80x60, 80, 60, 0 },
27
};
28
29
static struct mode_info ega_modes[] = {
30
{ VIDEO_80x25, 80, 25, 0 },
31
{ VIDEO_8POINT, 80, 43, 0 },
32
};
33
34
static struct mode_info cga_modes[] = {
35
{ VIDEO_80x25, 80, 25, 0 },
36
};
37
38
static __videocard video_vga;
39
40
/* Set basic 80x25 mode */
41
static u8 vga_set_basic_mode(void)
42
{
43
struct biosregs ireg, oreg;
44
u8 mode;
45
46
initregs(&ireg);
47
48
/* Query current mode */
49
ireg.ax = 0x0f00;
50
intcall(0x10, &ireg, &oreg);
51
mode = oreg.al;
52
53
if (mode != 3 && mode != 7)
54
mode = 3;
55
56
/* Set the mode */
57
ireg.ax = mode; /* AH=0: set mode */
58
intcall(0x10, &ireg, NULL);
59
do_restore = 1;
60
return mode;
61
}
62
63
static void vga_set_8font(void)
64
{
65
/* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
66
struct biosregs ireg;
67
68
initregs(&ireg);
69
70
/* Set 8x8 font */
71
ireg.ax = 0x1112;
72
/* ireg.bl = 0; */
73
intcall(0x10, &ireg, NULL);
74
75
/* Use alternate print screen */
76
ireg.ax = 0x1200;
77
ireg.bl = 0x20;
78
intcall(0x10, &ireg, NULL);
79
80
/* Turn off cursor emulation */
81
ireg.ax = 0x1201;
82
ireg.bl = 0x34;
83
intcall(0x10, &ireg, NULL);
84
85
/* Cursor is scan lines 6-7 */
86
ireg.ax = 0x0100;
87
ireg.cx = 0x0607;
88
intcall(0x10, &ireg, NULL);
89
}
90
91
static void vga_set_14font(void)
92
{
93
/* Set 9x14 font - 80x28 on VGA */
94
struct biosregs ireg;
95
96
initregs(&ireg);
97
98
/* Set 9x14 font */
99
ireg.ax = 0x1111;
100
/* ireg.bl = 0; */
101
intcall(0x10, &ireg, NULL);
102
103
/* Turn off cursor emulation */
104
ireg.ax = 0x1201;
105
ireg.bl = 0x34;
106
intcall(0x10, &ireg, NULL);
107
108
/* Cursor is scan lines 11-12 */
109
ireg.ax = 0x0100;
110
ireg.cx = 0x0b0c;
111
intcall(0x10, &ireg, NULL);
112
}
113
114
static void vga_set_80x43(void)
115
{
116
/* Set 80x43 mode on VGA (not EGA) */
117
struct biosregs ireg;
118
119
initregs(&ireg);
120
121
/* Set 350 scans */
122
ireg.ax = 0x1201;
123
ireg.bl = 0x30;
124
intcall(0x10, &ireg, NULL);
125
126
/* Reset video mode */
127
ireg.ax = 0x0003;
128
intcall(0x10, &ireg, NULL);
129
130
vga_set_8font();
131
}
132
133
/* I/O address of the VGA CRTC */
134
u16 vga_crtc(void)
135
{
136
return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
137
}
138
139
static void vga_set_480_scanlines(void)
140
{
141
u16 crtc; /* CRTC base address */
142
u8 csel; /* CRTC miscellaneous output register */
143
144
crtc = vga_crtc();
145
146
out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
147
out_idx(0x0b, crtc, 0x06); /* Vertical total */
148
out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
149
out_idx(0xea, crtc, 0x10); /* Vertical sync start */
150
out_idx(0xdf, crtc, 0x12); /* Vertical display end */
151
out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
152
out_idx(0x04, crtc, 0x16); /* Vertical blank end */
153
csel = inb(0x3cc);
154
csel &= 0x0d;
155
csel |= 0xe2;
156
outb(csel, 0x3c2);
157
}
158
159
static void vga_set_vertical_end(int lines)
160
{
161
u16 crtc; /* CRTC base address */
162
u8 ovfw; /* CRTC overflow register */
163
int end = lines-1;
164
165
crtc = vga_crtc();
166
167
ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40);
168
169
out_idx(ovfw, crtc, 0x07); /* Vertical overflow */
170
out_idx(end, crtc, 0x12); /* Vertical display end */
171
}
172
173
static void vga_set_80x30(void)
174
{
175
vga_set_480_scanlines();
176
vga_set_vertical_end(30*16);
177
}
178
179
static void vga_set_80x34(void)
180
{
181
vga_set_480_scanlines();
182
vga_set_14font();
183
vga_set_vertical_end(34*14);
184
}
185
186
static void vga_set_80x60(void)
187
{
188
vga_set_480_scanlines();
189
vga_set_8font();
190
vga_set_vertical_end(60*8);
191
}
192
193
static int vga_set_mode(struct mode_info *mode)
194
{
195
/* Set the basic mode */
196
vga_set_basic_mode();
197
198
/* Override a possibly broken BIOS */
199
force_x = mode->x;
200
force_y = mode->y;
201
202
switch (mode->mode) {
203
case VIDEO_80x25:
204
break;
205
case VIDEO_8POINT:
206
vga_set_8font();
207
break;
208
case VIDEO_80x43:
209
vga_set_80x43();
210
break;
211
case VIDEO_80x28:
212
vga_set_14font();
213
break;
214
case VIDEO_80x30:
215
vga_set_80x30();
216
break;
217
case VIDEO_80x34:
218
vga_set_80x34();
219
break;
220
case VIDEO_80x60:
221
vga_set_80x60();
222
break;
223
}
224
225
return 0;
226
}
227
228
/*
229
* Note: this probe includes basic information required by all
230
* systems. It should be executed first, by making sure
231
* video-vga.c is listed first in the Makefile.
232
*/
233
static int vga_probe(void)
234
{
235
static const char *card_name[] = {
236
"CGA/MDA/HGC", "EGA", "VGA"
237
};
238
static struct mode_info *mode_lists[] = {
239
cga_modes,
240
ega_modes,
241
vga_modes,
242
};
243
static int mode_count[] = {
244
sizeof(cga_modes)/sizeof(struct mode_info),
245
sizeof(ega_modes)/sizeof(struct mode_info),
246
sizeof(vga_modes)/sizeof(struct mode_info),
247
};
248
249
struct biosregs ireg, oreg;
250
251
initregs(&ireg);
252
253
ireg.ax = 0x1200;
254
ireg.bl = 0x10; /* Check EGA/VGA */
255
intcall(0x10, &ireg, &oreg);
256
257
#ifndef _WAKEUP
258
boot_params.screen_info.orig_video_ega_bx = oreg.bx;
259
#endif
260
261
/* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
262
if (oreg.bl != 0x10) {
263
/* EGA/VGA */
264
ireg.ax = 0x1a00;
265
intcall(0x10, &ireg, &oreg);
266
267
if (oreg.al == 0x1a) {
268
adapter = ADAPTER_VGA;
269
#ifndef _WAKEUP
270
boot_params.screen_info.orig_video_isVGA = 1;
271
#endif
272
} else {
273
adapter = ADAPTER_EGA;
274
}
275
} else {
276
adapter = ADAPTER_CGA;
277
}
278
279
video_vga.modes = mode_lists[adapter];
280
video_vga.card_name = card_name[adapter];
281
return mode_count[adapter];
282
}
283
284
static __videocard video_vga = {
285
.card_name = "VGA",
286
.probe = vga_probe,
287
.set_mode = vga_set_mode,
288
};
289
290