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