root/morphix/trunk/ddcxinfo/vbe.c

Revision 2, 15.7 kB (checked in by nextime, 2 years ago)

Initial import, branching from morphix svn

Line 
1 #include <sys/types.h>
2 #include <sys/io.h>
3 #include <sys/mman.h>
4 #include <netinet/in.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <assert.h>
9 #include <limits.h>
10 #include <ctype.h>
11 #include "lrmi.h"
12 #include "vesamode.h"
13 #include "vbe.h"
14 #ident "$Id: vbe.c 1815 2005-04-25 08:27:54Z alextreme $"
15
16 /* Return information about a particular video mode. */
17 struct vbe_mode_info *vbe_get_mode_info(u_int16_t mode)
18 {
19         struct LRMI_regs regs;
20         char *mem;
21         struct vbe_mode_info *ret = NULL;
22
23         /* Initialize LRMI. */
24         if(LRMI_init() == 0) {
25                 return NULL;
26         }
27
28         /* Allocate a chunk of memory. */
29         mem = LRMI_alloc_real(sizeof(struct vbe_mode_info));
30         if(mem == NULL) {
31                 return NULL;
32         }
33         memset(mem, 0, sizeof(struct vbe_mode_info));
34
35         memset(&regs, 0, sizeof(regs));
36         regs.eax = 0x4f01;
37         regs.ecx = mode;
38         regs.es = ((u_int32_t)mem) >> 4;
39         regs.edi = ((u_int32_t)mem) & 0x0f;
40
41         /* Do it. */
42         iopl(3);
43         ioperm(0, 0x400, 1);
44
45         if(LRMI_int(0x10, &regs) == 0) {
46                 LRMI_free_real(mem);
47                 return NULL;
48         }
49
50         /* Check for successful return. */
51         if((regs.eax & 0xffff) != 0x004f) {
52                 LRMI_free_real(mem);
53                 return NULL;
54         }
55
56         /* Get memory for return. */
57         ret = malloc(sizeof(struct vbe_mode_info));
58         if(ret == NULL) {
59                 LRMI_free_real(mem);
60                 return NULL;
61         }
62
63         /* Copy the buffer for return. */
64         memcpy(ret, mem, sizeof(struct vbe_mode_info));
65
66         /* Clean up and return. */
67         LRMI_free_real(mem);
68         return ret;
69 }
70
71 /* Get VBE info. */
72 struct vbe_info *vbe_get_vbe_info()
73 {
74         struct LRMI_regs regs;
75         unsigned char *mem;
76         struct vbe_info *ret = NULL;
77         int i;
78
79         /* Initialize LRMI. */
80         if(LRMI_init() == 0) {
81                 return NULL;
82         }
83
84         /* Allocate a chunk of memory. */
85         mem = LRMI_alloc_real(sizeof(struct vbe_mode_info));
86         if(mem == NULL) {
87                 return NULL;
88         }
89         memset(mem, 0, sizeof(struct vbe_mode_info));
90
91         /* Set up registers for the interrupt call. */
92         memset(&regs, 0, sizeof(regs));
93         regs.eax = 0x4f00;
94         regs.es = ((u_int32_t)mem) >> 4;
95         regs.edi = ((u_int32_t)mem) & 0x0f;
96         memcpy(mem, "VBE2", 4);
97
98         /* Do it. */
99         iopl(3);
100         ioperm(0, 0x400, 1);
101
102         if(LRMI_int(0x10, &regs) == 0) {
103                 LRMI_free_real(mem);
104                 return NULL;
105         }
106
107         /* Check for successful return code. */
108         if((regs.eax & 0xffff) != 0x004f) {
109                 LRMI_free_real(mem);
110                 return NULL;
111         }
112
113         /* Get memory to return the information. */
114         ret = malloc(sizeof(struct vbe_info));
115         if(ret == NULL) {
116                 LRMI_free_real(mem);
117                 return NULL;
118         }
119         memcpy(ret, mem, sizeof(struct vbe_info));
120
121         /* Set up pointers to usable memory. */
122         ret->mode_list.list = (u_int16_t*) ((ret->mode_list.addr.seg << 4) +
123                                             (ret->mode_list.addr.ofs));
124         ret->oem_name.string = (char*) ((ret->oem_name.addr.seg << 4) +
125                                         (ret->oem_name.addr.ofs));
126
127         /* Snip, snip. */
128         mem = strdup(ret->oem_name.string); /* leak */
129         while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) {
130                 mem[i - 1] = '\0';
131         }
132         ret->oem_name.string = mem;
133
134         /* Set up pointers for VESA 2.0+ strings. */
135         if(ret->version[1] >= 2) {
136
137                 /* Vendor name. */
138                 ret->vendor_name.string = (char*)
139                          ((ret->vendor_name.addr.seg << 4)
140                         + (ret->vendor_name.addr.ofs));
141
142                 mem = strdup(ret->vendor_name.string); /* leak */
143                 while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) {
144                         mem[i - 1] = '\0';
145                 }
146                 ret->vendor_name.string = mem;
147
148                 /* Product name. */
149                 ret->product_name.string = (char*)
150                          ((ret->product_name.addr.seg << 4)
151                         + (ret->product_name.addr.ofs));
152
153                 mem = strdup(ret->product_name.string); /* leak */
154                 while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) {
155                         mem[i - 1] = '\0';
156                 }
157                 ret->product_name.string = mem;
158
159                 /* Product revision. */
160                 ret->product_revision.string = (char*)
161                          ((ret->product_revision.addr.seg << 4)
162                         + (ret->product_revision.addr.ofs));
163
164                 mem = strdup(ret->product_revision.string); /* leak */
165                 while(((i = strlen(mem)) > 0) && isspace(mem[i - 1])) {
166                         mem[i - 1] = '\0';
167                 }
168                 ret->product_revision.string = mem;
169         }
170
171         /* Cleanup. */
172         LRMI_free_real(mem);
173         return ret;
174 }
175
176 /* Check if EDID queries are suorted. */
177 int vbe_get_edid_supported()
178 {
179         struct LRMI_regs regs;
180         int ret = 0;
181
182         /* Initialize LRMI. */
183         if(LRMI_init() == 0) {
184                 return 0;
185         }
186
187         memset(&regs, 0, sizeof(regs));
188         regs.eax = 0x4f15;
189         regs.ebx = 0x0000;
190         regs.es = 0x3000;
191         regs.edi = 0x3000;
192
193         /* Do it. */
194         iopl(3);
195         ioperm(0, 0x400, 1);
196
197         if(LRMI_int(0x10, &regs) == 0) {
198                 return 0;
199         }
200
201         /* Check for successful return. */
202         if((regs.eax & 0xff) == 0x4f) {
203                 /* Supported. */
204                 ret = 1;
205         } else {
206                 /* Not supported. */
207                 ret = 0;
208         }
209
210         /* Clean up and return. */
211         return ret;
212 }
213
214 /* Get EDID info. */
215 struct vbe_edid1_info *vbe_get_edid_info()
216 {
217         struct LRMI_regs regs;
218         unsigned char *mem;
219         struct vbe_edid1_info *ret = NULL;
220         u_int16_t man;
221
222         /* Initialize LRMI. */
223         if(LRMI_init() == 0) {
224                 return NULL;
225         }
226
227         /* Allocate a chunk of memory. */
228         mem = LRMI_alloc_real(sizeof(struct vbe_edid1_info));
229         if(mem == NULL) {
230                 return NULL;
231         }
232         memset(mem, 0, sizeof(struct vbe_edid1_info));
233
234         memset(&regs, 0, sizeof(regs));
235         regs.eax = 0x4f15;
236         regs.ebx = 0x0001;
237         regs.es = ((u_int32_t)mem) >> 4;
238         regs.edi = ((u_int32_t)mem) & 0x0f;
239
240         /* Do it. */
241         iopl(3);
242         ioperm(0, 0x400, 1);
243
244         if(LRMI_int(0x10, &regs) == 0) {
245                 LRMI_free_real(mem);
246                 return NULL;
247         }
248
249 #if 0
250         /* Check for successful return. */
251         if((regs.eax & 0xffff) != 0x004f) {
252                 LRMI_free_real(mem);
253                 return NULL;
254         }
255 #elseif
256         /* Check for successful return. */
257         if((regs.eax & 0xff) != 0x4f) {
258                 LRMI_free_real(mem);
259                 return NULL;
260         }
261 #endif
262
263         /* Get memory for return. */
264         ret = malloc(sizeof(struct vbe_edid1_info));
265         if(ret == NULL) {
266                 LRMI_free_real(mem);
267                 return NULL;
268         }
269
270         /* Copy the buffer for return. */
271         memcpy(ret, mem, sizeof(struct vbe_edid1_info));
272
273         memcpy(&man, &ret->manufacturer_name, 2);
274         man = ntohs(man);
275         memcpy(&ret->manufacturer_name, &man, 2);
276
277         LRMI_free_real(mem);
278         return ret;
279 }
280
281 /* Figure out what the current video mode is. */
282 int32_t vbe_get_mode()
283 {
284         struct LRMI_regs regs;
285         int32_t ret = -1;
286
287         /* Initialize LRMI. */
288         if(LRMI_init() == 0) {
289                 return -1;
290         }
291
292         memset(&regs, 0, sizeof(regs));
293         regs.eax = 0x4f03;
294
295         /* Do it. */
296         iopl(3);
297         ioperm(0, 0x400, 1);
298
299         if(LRMI_int(0x10, &regs) == 0) {
300                 return -1;
301         }
302
303         /* Save the returned value. */
304         if((regs.eax & 0xffff) == 0x004f) {
305                 ret = regs.ebx & 0xffff;
306         } else {
307                 ret = -1;
308         }
309
310         /* Clean up and return. */
311         return ret;
312 }
313
314 /* Set the video mode. */
315 void vbe_set_mode(u_int16_t mode)
316 {
317         struct LRMI_regs regs;
318
319         /* Initialize LRMI. */
320         if(LRMI_init() == 0) {
321                 return;
322         }
323
324         memset(&regs, 0, sizeof(regs));
325         regs.eax = 0x4f02;
326         regs.ebx = mode;
327
328         /* Do it. */
329         iopl(3);
330         ioperm(0, 0x400, 1);
331         LRMI_int(0x10, &regs);
332
333         /* Return. */
334         return;
335 }
336
337 /* Just read ranges from the EDID. */
338 void vbe_get_edid_ranges(unsigned char *hmin, unsigned char *hmax,
339                          unsigned char *vmin, unsigned char *vmax)
340 {
341         struct vbe_edid1_info *edid;
342         struct vbe_edid_monitor_descriptor *monitor;
343         int i;
344
345         *hmin = *hmax = *vmin = *vmax = 0;
346
347         if((edid = vbe_get_edid_info()) == NULL) {
348                 return;
349         }
350
351         for(i = 0; i < 4; i++) {
352                 monitor = &edid->monitor_details.monitor_descriptor[i];
353                 if(monitor->type == vbe_edid_monitor_descriptor_range) {
354                         *hmin = monitor->data.range_data.horizontal_min;
355                         *hmax = monitor->data.range_data.horizontal_max;
356                         *vmin = monitor->data.range_data.vertical_min;
357                         *vmax = monitor->data.range_data.vertical_max;
358                 }
359         }
360 }
361
362 static int compare_vbe_modelines(const void *m1, const void *m2)
363 {
364         const struct vbe_modeline *M1 = (const struct vbe_modeline*) m1;
365         const struct vbe_modeline *M2 = (const struct vbe_modeline*) m2;
366         if(M1->width < M2->width) return -1;
367         if(M1->width > M2->width) return 1;
368         return 0;
369 }
370
371 struct vbe_modeline *vbe_get_edid_modelines()
372 {
373         struct vbe_edid1_info *edid;
374         struct vbe_modeline *ret;
375         char buf[LINE_MAX];
376         int modeline_count = 0, i, j;
377
378         if((edid = vbe_get_edid_info()) == NULL) {
379                 return NULL;
380         }
381
382         memcpy(buf, &edid->established_timings,
383                sizeof(edid->established_timings));
384         for(i = 0; i < (8 * sizeof(edid->established_timings)); i++) {
385                 if(buf[i / 8] & (1 << (i % 8))) {
386                         modeline_count++;
387                 }
388         }
389
390         /* Count the number of standard timings. */
391         for(i = 0; i < 8; i++) {
392                 int x, v;
393                 x = edid->standard_timing[i].xresolution;
394                 v = edid->standard_timing[i].vfreq;
395                 if(((edid->standard_timing[i].xresolution & 0x01) != x) &&
396                    ((edid->standard_timing[i].vfreq & 0x01) != v)) {
397                         modeline_count++;
398                 }
399         }
400
401         ret = malloc(sizeof(struct vbe_modeline) * (modeline_count + 1));
402         if(ret == NULL) {
403                 return NULL;
404         }
405         memset(ret, 0, sizeof(struct vbe_modeline) * (modeline_count + 1));
406
407         modeline_count = 0;
408
409         /* Fill out established timings. */
410         if(edid->established_timings.timing_720x400_70) {
411                 ret[modeline_count].width = 720;
412                 ret[modeline_count].height = 400;
413                 ret[modeline_count].refresh = 70;
414                 modeline_count++;
415         }
416         if(edid->established_timings.timing_720x400_88) {
417                 ret[modeline_count].width = 720;
418                 ret[modeline_count].height = 400;
419                 ret[modeline_count].refresh = 88;
420                 modeline_count++;
421         }
422         if(edid->established_timings.timing_640x480_60) {
423                 ret[modeline_count].width = 640;
424                 ret[modeline_count].height = 480;
425                 ret[modeline_count].refresh = 60;
426                 modeline_count++;
427         }
428         if(edid->established_timings.timing_640x480_67) {
429                 ret[modeline_count].width = 640;
430                 ret[modeline_count].height = 480;
431                 ret[modeline_count].refresh = 67;
432                 modeline_count++;
433         }
434         if(edid->established_timings.timing_640x480_72) {
435                 ret[modeline_count].width = 640;
436                 ret[modeline_count].height = 480;
437                 ret[modeline_count].refresh = 72;
438                 modeline_count++;
439         }
440         if(edid->established_timings.timing_640x480_75) {
441                 ret[modeline_count].width = 640;
442                 ret[modeline_count].height = 480;
443                 ret[modeline_count].refresh = 75;
444                 modeline_count++;
445         }
446         if(edid->established_timings.timing_800x600_56) {
447                 ret[modeline_count].width = 800;
448                 ret[modeline_count].height = 600;
449                 ret[modeline_count].refresh = 56;
450                 modeline_count++;
451         }
452         if(edid->established_timings.timing_800x600_60) {
453                 ret[modeline_count].width = 800;
454                 ret[modeline_count].height = 600;
455                 ret[modeline_count].refresh = 60;
456                 modeline_count++;
457         }
458         if(edid->established_timings.timing_800x600_72) {
459                 ret[modeline_count].width = 800;
460                 ret[modeline_count].height = 600;
461                 ret[modeline_count].refresh = 72;
462                 modeline_count++;
463         }
464         if(edid->established_timings.timing_800x600_75) {
465                 ret[modeline_count].width = 800;
466                 ret[modeline_count].height = 600;
467                 ret[modeline_count].refresh = 75;
468                 modeline_count++;
469         }
470         if(edid->established_timings.timing_832x624_75) {
471                 ret[modeline_count].width = 832;
472                 ret[modeline_count].height = 624;
473                 ret[modeline_count].refresh = 75;
474                 modeline_count++;
475         }
476         if(edid->established_timings.timing_1024x768_87i) {
477                 ret[modeline_count].width = 1024;
478                 ret[modeline_count].height = 768;
479                 ret[<