]>
Commit | Line | Data |
---|---|---|
a6316ce4 MT |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <unistd.h> | |
4 | #include <string.h> | |
5 | #include <stdarg.h> | |
6 | ||
7 | #include "vbios.h" | |
8 | ||
9 | #include "hd.h" | |
10 | #include "hd_int.h" | |
11 | #include "bios.h" | |
12 | ||
13 | static unsigned segofs2addr(unsigned char *segofs); | |
14 | static unsigned get_data(unsigned char *buf, unsigned buf_size, unsigned addr); | |
15 | static void read_vbe_info(hd_data_t *hd_data, vbe_info_t *vbe, unsigned char *vbeinfo, unsigned cpuemu); | |
16 | ||
17 | static hd_data_t *log_hd_data; | |
18 | void log_err(char *format, ...) __attribute__ ((format (printf, 1, 2))); | |
19 | ||
20 | void get_vbe_info(hd_data_t *hd_data, vbe_info_t *vbe) | |
21 | { | |
22 | int i; | |
23 | unsigned char vbeinfo[0x200]; | |
24 | int ax, bx, cx; | |
25 | unsigned cpuemu = hd_data->flags.cpuemu; | |
26 | ||
27 | log_hd_data = hd_data; | |
28 | ||
29 | if(InitInt10(hd_data, hd_data->pci_config_type)) { | |
30 | ADD2LOG("VBE: Could not init Int10\n"); | |
31 | return; | |
32 | } | |
33 | ||
34 | memset(vbeinfo, 0, sizeof vbeinfo); | |
35 | strcpy(vbeinfo, "VBE2"); | |
36 | ||
37 | PROGRESS(4, 1, "vbe info"); | |
38 | ||
39 | if(hd_probe_feature(hd_data, pr_cpuemu_debug)) cpuemu |= 2; | |
40 | ||
41 | #ifdef __i386__ | |
42 | if(hd_data->flags.cpuemu) | |
43 | #endif | |
44 | ADD2LOG("vm86: using CPU emulation\n"); | |
45 | ||
46 | ax = 0x4f00; bx = 0; cx = 0; | |
47 | i = CallInt10(&ax, &bx, &cx, vbeinfo, sizeof vbeinfo, cpuemu) & 0xffff; | |
48 | ||
49 | if(i != 0x4f) { | |
50 | ADD2LOG("VBE: Error (0x4f00): 0x%04x\n", i); | |
51 | FreeInt10(); | |
52 | return; | |
53 | } | |
54 | ||
55 | if(hd_probe_feature(hd_data, pr_bios_fb)) { | |
56 | PROGRESS(4, 2, "mode info"); | |
57 | ||
58 | read_vbe_info(hd_data, vbe, vbeinfo, cpuemu); | |
59 | } | |
60 | ||
61 | if(hd_probe_feature(hd_data, pr_bios_ddc)) { | |
62 | PROGRESS(4, 3, "ddc info"); | |
63 | ||
64 | memset(vbeinfo, 0, sizeof vbeinfo); | |
65 | ax = 0x4f15; bx = 1; cx = 0; | |
66 | i = CallInt10(&ax, &bx, &cx, vbeinfo, sizeof vbeinfo, cpuemu) & 0xffff; | |
67 | ||
68 | if(i != 0x4f) { | |
69 | ADD2LOG("Error (0x4f15): 0x%04x\n", i); | |
70 | } else { | |
71 | vbe->ok = 1; | |
72 | memcpy(vbe->ddc, vbeinfo, sizeof vbe->ddc); | |
73 | ||
74 | ADD2LOG("edid record:\n"); | |
75 | for(i = 0; (unsigned) i < sizeof vbe->ddc; i += 0x10) { | |
76 | ADD2LOG(" "); | |
77 | hexdump(&hd_data->log, 1, 0x10, vbe->ddc + i); | |
78 | ADD2LOG("\n"); | |
79 | } | |
80 | } | |
81 | } | |
82 | ||
83 | if(hd_probe_feature(hd_data, pr_bios_mode)) { | |
84 | PROGRESS(4, 4, "gfx mode"); | |
85 | ||
86 | ax = 0x4f03; bx = 0; cx = 0; | |
87 | i = CallInt10(&ax, &bx, &cx, vbeinfo, sizeof vbeinfo, cpuemu) & 0xffff; | |
88 | ||
89 | if(i != 0x4f) { | |
90 | ADD2LOG("Error (0x4f03): 0x%04x\n", i); | |
91 | } else { | |
92 | vbe->current_mode = bx; | |
93 | vbe->ok = 1; | |
94 | } | |
95 | } | |
96 | ||
97 | FreeInt10(); | |
98 | } | |
99 | ||
100 | ||
101 | unsigned segofs2addr(unsigned char *segofs) | |
102 | { | |
103 | return segofs[0] + (segofs[1] << 8) + (segofs[2] << 4)+ (segofs[3] << 12); | |
104 | } | |
105 | ||
106 | ||
107 | unsigned get_data(unsigned char *buf, unsigned buf_size, unsigned addr) | |
108 | { | |
109 | unsigned bufferaddr = 0x7e00; | |
110 | unsigned len; | |
111 | ||
112 | *buf = 0; | |
113 | len = 0; | |
114 | ||
115 | if(addr >= bufferaddr && addr < bufferaddr + 0x200) { | |
116 | len = bufferaddr + 0x200 - addr; | |
117 | if(len >= buf_size) len = buf_size - 1; | |
118 | memcpy(buf, addr + (char *) 0, len); | |
119 | } | |
120 | else if(addr >= 0x0c0000 && addr < 0x100000) { | |
121 | len = 0x100000 - addr; | |
122 | if(len >= buf_size) len = buf_size - 1; | |
123 | memcpy(buf, addr + (char *) 0, len); | |
124 | } | |
125 | ||
126 | buf[len] = 0; | |
127 | ||
128 | return len; | |
129 | } | |
130 | ||
131 | ||
132 | void read_vbe_info(hd_data_t *hd_data, vbe_info_t *vbe, unsigned char *v, unsigned cpuemu) | |
133 | { | |
134 | unsigned char tmp[1024], s[64]; | |
135 | unsigned i, l, u; | |
136 | unsigned modelist[0x100]; | |
137 | unsigned bpp, res_bpp, fb, clock; | |
138 | vbe_mode_info_t *mi; | |
139 | int ax, bx, cx; | |
140 | ||
141 | vbe->ok = 1; | |
142 | ||
143 | vbe->version = v[0x04] + (v[0x05] << 8); | |
144 | vbe->oem_version = v[0x14] + (v[0x15] << 8); | |
145 | vbe->memory = (v[0x12] + (v[0x13] << 8)) << 16; | |
146 | ||
147 | ADD2LOG( | |
148 | "version = %u.%u, oem version = %u.%u\n", | |
149 | vbe->version >> 8, vbe->version & 0xff, vbe->oem_version >> 8, vbe->oem_version & 0xff | |
150 | ); | |
151 | ||
152 | ADD2LOG("memory = %uk\n", vbe->memory >> 10); | |
153 | ||
154 | l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x06)); | |
155 | vbe->oem_name = canon_str(tmp, l); | |
156 | ADD2LOG("oem name [0x%05x] = \"%s\"\n", u, vbe->oem_name); | |
157 | ||
158 | l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x16)); | |
159 | vbe->vendor_name = canon_str(tmp, l); | |
160 | ADD2LOG("vendor name [0x%05x] = \"%s\"\n", u, vbe->vendor_name); | |
161 | ||
162 | l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x1a)); | |
163 | vbe->product_name = canon_str(tmp, l); | |
164 | ADD2LOG("product name [0x%05x] = \"%s\"\n", u, vbe->product_name); | |
165 | ||
166 | l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x1e)); | |
167 | vbe->product_revision = canon_str(tmp, l); | |
168 | ADD2LOG("product revision [0x%05x] = \"%s\"\n", u, vbe->product_revision); | |
169 | ||
170 | l = get_data(tmp, sizeof tmp, u = segofs2addr(v + 0x0e)) >> 1; | |
171 | ||
172 | for(i = vbe->modes = 0; i < l && i < sizeof modelist / sizeof *modelist; i++) { | |
173 | u = tmp[2 * i] + (tmp[2 * i + 1] << 8); | |
174 | if(u != 0xffff) | |
175 | modelist[vbe->modes++] = u; | |
176 | else | |
177 | break; | |
178 | } | |
179 | ||
180 | ADD2LOG("%u video modes:\n", vbe->modes); | |
181 | ||
182 | vbe->mode = new_mem(vbe->modes * sizeof *vbe->mode); | |
183 | ||
184 | if(!vbe->mode) return; | |
185 | ||
186 | for(i = 0; i < vbe->modes; i++) { | |
187 | ||
188 | mi = vbe->mode + i; | |
189 | ||
190 | mi->number = modelist[i]; | |
191 | ||
192 | ax = 0x4f01; bx = 0; cx = modelist[i]; | |
193 | l = CallInt10(&ax, &bx, &cx, tmp, sizeof tmp, cpuemu) & 0xffff; | |
194 | ||
195 | if(l != 0x4f) { | |
196 | ADD2LOG("0x%04x: no mode info\n", modelist[i]); | |
197 | continue; | |
198 | } | |
199 | ||
200 | mi->attributes = tmp[0x00] + (tmp[0x01] << 8); | |
201 | ||
202 | mi->width = tmp[0x12] + (tmp[0x13] << 8); | |
203 | mi->height = tmp[0x14] + (tmp[0x15] << 8); | |
204 | mi->bytes_p_line = tmp[0x10] + (tmp[0x11] << 8); | |
205 | ||
206 | mi->win_A_start = (tmp[0x08] + (tmp[0x09] << 8)) << 4; | |
207 | mi->win_B_start = (tmp[0x0a] + (tmp[0x0b] << 8)) << 4; | |
208 | ||
209 | mi->win_A_attr = tmp[0x02]; | |
210 | mi->win_B_attr = tmp[0x03]; | |
211 | ||
212 | mi->win_gran = (tmp[0x04] + (tmp[0x05] << 8)) << 10; | |
213 | mi->win_size = (tmp[0x06] + (tmp[0x07] << 8)) << 10; | |
214 | ||
215 | bpp = res_bpp = 0; | |
216 | switch(tmp[0x1b]) { | |
217 | case 0: | |
218 | bpp = -1; | |
219 | break; | |
220 | ||
221 | case 1: | |
222 | bpp = 2; | |
223 | break; | |
224 | ||
225 | case 2: | |
226 | bpp = 1; | |
227 | break; | |
228 | ||
229 | case 3: | |
230 | bpp = 4; | |
231 | break; | |
232 | ||
233 | case 4: | |
234 | bpp = 8; | |
235 | break; | |
236 | ||
237 | case 6: | |
238 | bpp = tmp[0x19] - tmp[0x25]; | |
239 | res_bpp = tmp[0x25]; | |
240 | } | |
241 | ||
242 | fb = 0; | |
243 | if(vbe->version >= 0x0200) { | |
244 | mi->fb_start = tmp[0x28] + (tmp[0x29] << 8) + (tmp[0x2a] << 16) + (tmp[0x2b] << 24); | |
245 | } | |
246 | ||
247 | clock = 0; | |
248 | if(vbe->version >= 0x0300) { | |
249 | mi->pixel_clock = tmp[0x3e] + (tmp[0x3f] << 8) + (tmp[0x40] << 16) + (tmp[0x41] << 24); | |
250 | } | |
251 | ||
252 | mi->pixel_size = bpp; | |
253 | ||
254 | if(bpp == -1u) { | |
255 | ADD2LOG(" 0x%04x[%02x]: %ux%u, text\n", mi->number, mi->attributes, mi->width, mi->height); | |
256 | } | |
257 | else { | |
258 | if( | |
259 | (mi->attributes & 1) && /* mode is supported */ | |
260 | mi->fb_start | |
261 | ) { | |
262 | if(!vbe->fb_start) vbe->fb_start = mi->fb_start; | |
263 | } | |
264 | *s = 0; | |
265 | if(res_bpp) sprintf(s, "+%u", res_bpp); | |
266 | ADD2LOG( | |
267 | " 0x%04x[%02x]: %ux%u+%u, %u%s bpp", | |
268 | mi->number, mi->attributes, mi->width, mi->height, mi->bytes_p_line, mi->pixel_size, s | |
269 | ); | |
270 | ||
271 | if(mi->pixel_clock) ADD2LOG(", max. %u MHz", mi->pixel_clock/1000000); | |
272 | ||
273 | if(mi->fb_start) ADD2LOG(", fb: 0x%08x", mi->fb_start); | |
274 | ||
275 | ADD2LOG(", %04x.%x", mi->win_A_start, mi->win_A_attr); | |
276 | ||
277 | if(mi->win_B_start || mi->win_B_attr) ADD2LOG("/%04x.%x", mi->win_B_start, mi->win_B_attr); | |
278 | ||
279 | ADD2LOG(": %uk", mi->win_size >> 10); | |
280 | ||
281 | if(mi->win_gran != mi->win_size) ADD2LOG("/%uk", mi->win_gran >> 10); | |
282 | ||
283 | ADD2LOG("\n"); | |
284 | } | |
285 | } | |
286 | ||
287 | } | |
288 | ||
289 | void log_err(char *format, ...) | |
290 | { | |
291 | va_list args; | |
292 | char buf[1024]; | |
293 | ||
294 | va_start(args, format); | |
295 | vsnprintf(buf, sizeof buf, format, args); | |
296 | str_printf(&log_hd_data->log, -2, "%s", buf); | |
297 | va_end(args); | |
298 | } | |
299 |