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 | |
19 | static __videocard video_bios; |
20 | |
21 | /* Set a conventional BIOS mode */ |
22 | static int set_bios_mode(u8 mode); |
23 | |
24 | static int bios_set_mode(struct mode_info *mi) |
25 | { |
26 | return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS); |
27 | } |
28 | |
29 | static int set_bios_mode(u8 mode) |
30 | { |
31 | struct biosregs ireg, oreg; |
32 | u8 new_mode; |
33 | |
34 | initregs(regs: &ireg); |
35 | ireg.al = mode; /* AH=0x00 Set Video Mode */ |
36 | intcall(int_no: 0x10, ireg: &ireg, NULL); |
37 | |
38 | ireg.ah = 0x0f; /* Get Current Video Mode */ |
39 | intcall(int_no: 0x10, ireg: &ireg, oreg: &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(int_no: 0x10, ireg: &ireg, NULL); |
56 | } |
57 | #endif |
58 | return -1; |
59 | } |
60 | |
61 | static 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(n: 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(port: 0x3c0, index: 0x10) & 0x01) |
95 | continue; |
96 | |
97 | /* Graphics Controller: verify Alpha addressing enabled */ |
98 | if (in_idx(port: 0x3ce, index: 0x06) & 0x01) |
99 | continue; |
100 | |
101 | /* CRTC cursor location low should be zero(?) */ |
102 | if (in_idx(port: crtc, index: 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(addr: 0x44a); |
109 | mi->y = rdfs8(addr: 0x484)+1; |
110 | nmodes++; |
111 | } |
112 | |
113 | set_bios_mode(saved_mode); |
114 | |
115 | return nmodes; |
116 | } |
117 | |
118 | static __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 | |