summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornalin <nalin>1999-07-18 06:44:42 +0000
committernalin <nalin>1999-07-18 06:44:42 +0000
commit75d74b8f61de2e50989bf3b601ad414abdeeb964 (patch)
tree90d09bfd8fce323226dca355641a4916a5a86cb3
parent99801f67664b5201f6fe92c4b202ee455ba7707d (diff)
downloadanaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.tar.gz
anaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.tar.xz
anaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.zip
Initial revision
-rw-r--r--ddcprobe/bioscall.c207
-rw-r--r--ddcprobe/ddcprobe.c354
-rw-r--r--ddcprobe/svgamodes.c174
-rw-r--r--ddcprobe/vbe.c113
-rw-r--r--ddcprobe/vesamode.c71
5 files changed, 919 insertions, 0 deletions
diff --git a/ddcprobe/bioscall.c b/ddcprobe/bioscall.c
new file mode 100644
index 000000000..7c9029b89
--- /dev/null
+++ b/ddcprobe/bioscall.c
@@ -0,0 +1,207 @@
+#include <sys/types.h>
+#include <sys/io.h>
+#include <sys/stat.h>
+#include <sys/vm86.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include "bioscall.h"
+#ident "$Id$"
+
+/* Dump some of the interesting parts of a register struct to stdout. */
+void dump_regs(struct vm86_regs *regs)
+{
+ printf("ax = 0x%04lx\n", regs->eax & 0xffff);
+ printf("bx = 0x%04lx\n", regs->ebx & 0xffff);
+ printf("cx = 0x%04lx\n", regs->ecx & 0xffff);
+ printf("dx = 0x%04lx\n", regs->edx & 0xffff);
+ printf("cs = 0x%04x\n", regs->cs & 0xffff);
+ printf("ip = 0x%08lx\n", regs->eip & 0xffffffff);
+ printf("ss = 0x%04x\n", regs->ss & 0xffff);
+ printf("sp = 0x%08lx\n", regs->esp & 0xffffffff);
+ printf("%04x:%08lx = (%ld)\n",
+ regs->cs & 0xffff, regs->eip,
+ regs->cs * 16 + regs->eip);
+}
+
+/* Call vm86, but do I/O that gets trapped. We could skip vm86() altogether,
+ but then I'm not trying to emulate an entire CPU here. Luckily, none of
+ the I/O instructions (or push/pop) affect the flags, so we can leave them
+ alone and just deal with performing the I/O operation that caused a return
+ to 32-bit mode. */
+void do_vm86(struct vm86_struct *vm, char *memory, unsigned stop_eip) {
+ int ret;
+ unsigned start_cs, start_eip;
+ unsigned char *ip = NULL;
+
+ /* Save the starting instruction address. */
+ start_cs = vm->regs.cs;
+ start_eip = vm->regs.eip;
+
+ /* We'll need to pass I/O through. PCI devices have higher addresses
+ than we can get access to with ioperm(). */
+ if(iopl(3) != 0) {
+ return;
+ }
+
+ /* Do it. */
+ ret = syscall(SYS_vm86old, vm);
+ while((vm->regs.cs * 16 + vm->regs.eip) != (start_cs * 16 + stop_eip)) {
+ ip = &memory[vm->regs.cs * 16 + vm->regs.eip];
+#ifdef DEBUG
+ printf("Unexpected return:\n");
+ dump_regs(&vm->regs);
+ printf("Offending instructions: %02x %02x %02x %02x\n",
+ ip[0], ip[1], ip[2], ip[3]);
+#endif
+ switch(ip[0]) {
+ case 0xe4: { /* in al, literal */
+ vm->regs.eax &= 0xffffff00;
+ vm->regs.eax |= inb(ip[1]);
+ vm->regs.eip += 2;
+ break;
+ }
+ case 0xe6: { /* out al, literal */
+ outb(vm->regs.eax & 0xff, ip[1]);
+ vm->regs.eip += 2;
+ break;
+ }
+ case 0xec: { /* in al, dx */
+ vm->regs.eax &= 0xffffff00;
+ vm->regs.eax |= inb(vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ case 0xed: { /* in ax, dx */
+ vm->regs.eax &= 0xffff0000;
+ vm->regs.eax |= inw(vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ case 0xee: { /* out al, dx */
+ outb(vm->regs.eax & 0xff,
+ vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ case 0xef: { /* out ax, dx */
+ outw(vm->regs.eax & 0xffff,
+ vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ case 0x66: {
+ /* 32-bit extension prefix. Valid, even in
+ v86 mode. Weird. */
+ vm->regs.eip++;
+ ip++;
+ switch(ip[0]) {
+ case 0xed: { /* in eax, dx */
+ vm->regs.eax =
+ inl(vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ case 0xef: { /* out eax, dx */
+ outl(vm->regs.eax,
+ vm->regs.edx & 0xffff);
+ vm->regs.eip++;
+ break;
+ }
+ default: {
+ fprintf(stderr, "unhandled "
+ "32-bit opcode\n");
+ exit(1);
+ }
+ }
+ break;
+ }
+ case 0x55: { /* push bp */
+ vm->regs.esp -= 2;
+ *(u_int16_t*) &memory[vm->regs.ss * 16 +
+ vm->regs.esp]
+ = vm->regs.ebp;
+ vm->regs.eip++;
+ break;
+ }
+ case 0x5d: { /* pop bp */
+ vm->regs.ebp = *(u_int16_t*)
+ &memory[vm->regs.ss*16 + vm->regs.esp];
+ vm->regs.esp += 2;
+ vm->regs.eip++;
+ break;
+ }
+ default: {
+ fprintf(stderr, "Unexpected stop!\n");
+ dump_regs(&vm->regs);
+ printf("Offending instructions: %02x %02x %02x %02x\n",
+ ip[0], ip[1], ip[2], ip[3]);
+ exit(1);
+ }
+ }
+ ip = &memory[vm->regs.cs * 16 + vm->regs.eip];
+#ifdef DEBUG
+ printf("Resuming execution:\n");
+ dump_regs(&vm->regs);
+ printf("Offending instructions: %02x %02x %02x %02x\n",
+ ip[0], ip[1], ip[2], ip[3]);
+#endif
+ ret = syscall(SYS_vm86old, vm);
+ }
+#ifdef DEBUG
+ printf("Reached stopping point, returning.\n");
+#endif
+ return;
+}
+
+/* Get a snapshot of the first megabyte of memory for use with vm86. */
+unsigned char *vm86_ram_alloc()
+{
+ unsigned char *memory;
+ int fd;
+
+ /* Grab address 0 for this process. */
+ memory = mmap(0, 0x100000, PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0x00000);
+ if(memory == MAP_FAILED) {
+ perror("error mmap()ing memory for the BIOS");
+ return MAP_FAILED;
+ }
+
+ /* Copy the low megabyte to our mmap()'ed buffer. */
+ fd = open("/dev/mem", O_RDONLY);
+ if(fd == -1) {
+ perror("reading kernel memory");
+ return MAP_FAILED;
+ }
+ read(fd, memory, 0x100000);
+ close(fd);
+
+ return memory;
+}
+
+void vm86_ram_free(unsigned char *ram)
+{
+ munmap(ram, 0x100000);
+}
+
+void bioscall(unsigned char int_no, struct vm86_regs *regs, unsigned char *mem)
+{
+ unsigned char call[] = {0xcd, int_no, 0xcd, 0x09};
+ struct vm86_struct vm;
+ memset(&vm, 0, sizeof(vm));
+ memcpy(&vm.regs, regs, sizeof(vm.regs));
+ vm.regs.cs = BIOSCALL_START_SEG;
+ vm.regs.eip = BIOSCALL_START_OFS;
+ memcpy(&mem[BIOSCALL_START_SEG * 16 + BIOSCALL_START_OFS], call,
+ sizeof(call));
+ do_vm86(&vm, mem, BIOSCALL_START_OFS + sizeof(call));
+ memcpy(regs, &vm.regs, sizeof(vm.regs));
+}
diff --git a/ddcprobe/ddcprobe.c b/ddcprobe/ddcprobe.c
new file mode 100644
index 000000000..8ac2a02c4
--- /dev/null
+++ b/ddcprobe/ddcprobe.c
@@ -0,0 +1,354 @@
+#include <sys/types.h>
+#include <sys/io.h>
+#include <sys/stat.h>
+#include <sys/vm86.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include "vbe.h"
+#include "vesamode.h"
+#include "bioscall.h"
+#ident "$Id$"
+
+int main(int argc, char **argv)
+{
+ struct vm86_struct info;
+ struct vbe_info *vbe_info = NULL;
+ struct edid_info *edid_info = NULL;
+ unsigned char *memory = NULL;
+ u_int16_t *mode_list = NULL;
+ char manufacturer[4];
+ int i;
+
+ /* Get a copy of the low megabyte for use as an address space. */
+ memory = vm86_ram_alloc();
+ if(memory == MAP_FAILED) {
+ printf("Couldn't allocate needed memory!\n");
+ exit(0);
+ }
+
+ /* Set up registers for a real-mode interrupt call. */
+ memset(&info, 0, sizeof(info));
+ info.regs.eax = 0x4f00;
+ info.regs.es = 0x4000;
+ info.regs.edi = 0x0000;
+ info.regs.ss = 0x9000;
+ info.regs.esp = 0x0000;
+ info.flags = 0;
+
+ /* Call the BIOS. */
+ memset(&memory[info.regs.es * 16 + info.regs.edi], 0, 1024);
+ bioscall(0x10, &info.regs, memory);
+
+ /* Interpret results. */
+ vbe_info = (struct vbe_info*) &memory[info.regs.es*16 + info.regs.edi];
+
+ if((info.regs.eax & 0xff) != 0x4f) {
+ printf("VESA BIOS Extensions not detected.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ if((info.regs.eax & 0xffff) != 0x004f) {
+ printf("VESA Get SuperVGA Information request failed.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ /* Signature. */
+ printf("%c%c%c%c %d.%d detected.\n",
+ vbe_info->signature[0], vbe_info->signature[1],
+ vbe_info->signature[2], vbe_info->signature[3],
+ vbe_info->version[1], vbe_info->version[0]);
+
+ /* OEM */
+ printf("OEM Name: %s\n", &memory[vbe_info->oem_name.addr.seg * 16 +
+ vbe_info->oem_name.addr.ofs]);
+
+ /* Memory. */
+ printf("Memory installed = %d * 64k blocks = %dkb\n",
+ vbe_info->memory_size, vbe_info->memory_size * 64);
+
+ /* List supported standard modes. */
+ mode_list = (u_int16_t*) &memory[vbe_info->mode_list.addr.seg * 16 +
+ vbe_info->mode_list.addr.ofs];
+ if(*mode_list != 0xffff) {
+ printf("Supported standard modes:\n");
+ }
+ for(;*mode_list != 0xffff; mode_list++) {
+ int i;
+ for(i = 0; known_vesa_modes[i].x != 0; i++) {
+ if(known_vesa_modes[i].number == *mode_list) {
+ printf("\t%s\n", known_vesa_modes[i].text);
+ }
+ }
+ }
+
+ /* Set up registers for reading the EDID from the BIOS. */
+ memset(&info, 0, sizeof(info));
+ info.regs.eax = 0x4f15;
+ info.regs.ebx = 0x0001;
+ info.regs.es = 0x4000;
+ info.regs.edi = 0x0000;
+ info.regs.ss = 0x9000;
+ info.regs.esp = 0x0000;
+ info.flags = 0;
+
+ /* Call the BIOS again. */
+ memset(&memory[info.regs.es * 16 + info.regs.edi], 0, 1024);
+ bioscall(0x10, &info.regs, memory);
+
+ /* Interpret results. */
+ if((info.regs.eax & 0xff) != 0x4f) {
+ printf("EDID read not supported by hardware.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ if((info.regs.eax & 0xffff) == 0x014f) {
+ printf("EDID read supported by hardware, but failed "
+ "(monitor not DCC-capable?).\n");
+#if 1
+ vm86_ram_free(memory);
+ exit(0);
+#endif
+ }
+
+ if((info.regs.eax & 0xffff) != 0x004f) {
+ printf("Unknown failure reading EDID.\n");
+ dump_regs(&info.regs);
+ } else {
+ printf("EDID read successfully.\n");
+ dump_regs(&info.regs);
+ }
+
+ edid_info = (struct edid_info*) &memory[info.regs.es * 16 +
+ info.regs.edi];
+ printf("EDID ver. %d rev. %d.\n",
+ edid_info->edid_version, edid_info->edid_revision);
+
+ edid_info->manufacturer = ntohs(edid_info->manufacturer);
+ manufacturer[0] = ((edid_info->manufacturer>>10)&0x1f)+ 'A' - 1;
+ manufacturer[1] = ((edid_info->manufacturer>> 5)&0x1f)+ 'A' - 1;
+ manufacturer[2] = ((edid_info->manufacturer>> 0)&0x1f)+ 'A' - 1;
+ manufacturer[3] = 0;
+ printf("Manufacturer: %s\n", manufacturer);
+
+ if(edid_info->serial != 0xffffffff) {
+ if(strcmp(manufacturer, "MAG") == 0) {
+ edid_info->serial -= 0x7000000;
+ }
+ if(strcmp(manufacturer, "OQI") == 0) {
+ edid_info->serial -= 456150000;
+ }
+ if(strcmp(manufacturer, "VSC") == 0) {
+ edid_info->serial -= 640000000;
+ }
+ }
+ printf("Serial number: %d.\n", edid_info->serial);
+
+ printf("Manufactured in week %d of %d.\n",
+ edid_info->week, edid_info->year + 1990);
+
+ printf("Input signal type: %s%s%s%s.\n",
+ edid_info->video_input & 0x01 ? "separate sync, " : "",
+ edid_info->video_input & 0x02 ? "composite sync, " : "",
+ edid_info->video_input & 0x04 ? "sync on green, " : "",
+ edid_info->video_input & 0x80 ?
+ "digital signal" : "analog signal");
+
+ printf("Screen size max %d cm horizontal, %d cm vertical.\n",
+ edid_info->max_size_horizontal,
+ edid_info->max_size_vertical);
+
+ printf("Gamma: %f.\n", edid_info->gamma / 100.0 + 1);
+
+ printf("DPMS flags: %s, %s%s, %s%s, %s%s.\n",
+ edid_info->dpms_flags & 0x08 ? "RGB" : "non-RGB",
+ edid_info->dpms_flags & 0x20 ? "" : "no ", "active off",
+ edid_info->dpms_flags & 0x40 ? "" : "no ", "suspend",
+ edid_info->dpms_flags & 0x80 ? "" : "no ", "standby");
+
+ printf("Established timings:\n");
+ if(edid_info->established_timings1 & 0x01)
+ printf("\t720x400 @ 70 Hz (VGA 640x400, IBM)\n");
+ if(edid_info->established_timings1 & 0x02)
+ printf("\t720x400 @ 88 Hz (XGA2)\n");
+ if(edid_info->established_timings1 & 0x04)
+ printf("\t640x480 @ 60 Hz (VGA)\n");
+ if(edid_info->established_timings1 & 0x08)
+ printf("\t640x480 @ 67 Hz (Mac II, Apple)\n");
+ if(edid_info->established_timings1 & 0x10)
+ printf("\t640x480 @ 72 Hz (VESA)\n");
+ if(edid_info->established_timings1 & 0x20)
+ printf("\t640x480 @ 75 Hz (VESA)\n");
+ if(edid_info->established_timings1 & 0x40)
+ printf("\t800x600 @ 56 Hz (VESA)\n");
+ if(edid_info->established_timings1 & 0x80)
+ printf("\t800x600 @ 60 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x01)
+ printf("\t800x600 @ 72 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x02)
+ printf("\t800x600 @ 75 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x04)
+ printf("\t832x624 @ 75 Hz (Mac II)\n");
+ if(edid_info->established_timings2 & 0x08)
+ printf("\t1024x768 @ 87 Hz Interlaced (8514A)\n");
+ if(edid_info->established_timings2 & 0x10)
+ printf("\t1024x768 @ 60 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x20)
+ printf("\t1024x768 @ 70 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x40)
+ printf("\t1024x768 @ 75 Hz (VESA)\n");
+ if(edid_info->established_timings2 & 0x80)
+ printf("\t1280x1024 @ 75 Hz (VESA)\n");
+
+ /* Standard timings. */
+ for(i = 0; i < 8; i++) {
+ double aspect = 1;
+ unsigned int x, y;
+ unsigned char xres, vfreq;
+ xres = edid_info->standard_timing[i].xresolution;
+ vfreq = edid_info->standard_timing[i].vfreq;
+ if((xres != vfreq) ||
+ ((xres != 0) && (xres != 1)) ||
+ ((vfreq != 0) && (vfreq != 1))) {
+ switch(vfreq >> 6) {
+ case 0: aspect = 1; break; /*undefined*/
+ case 1: aspect = 0.750; break;
+ case 2: aspect = 0.800; break;
+ case 3: aspect = 0.625; break;
+ }
+ x = (xres + 31) * 8;
+ y = x * aspect;
+ printf("Standard timing %d: %d Hz, %dx%d\n", i,
+ (vfreq & 0x3f) + 60, x, y);
+ }
+ }
+
+ /* Detailed timing information. */
+ for(i = 0; i < 4; i++) {
+ unsigned char *timing = NULL;
+ timing = edid_info->detailed_timing[i];
+ if((timing[0] != 0) || (timing[1] != 0) || (timing[0] != 0)) {
+ printf("Detailed timing %d:\n", i);
+ printf("\tHoriz. Sync = %d kHz\n", timing[0]);
+ printf("\tVert. Freq. = %d Hz\n", timing[1]);
+ printf("\tHoriz. Active Time = %d pixels\n",
+ timing[2]);
+ printf("\tHoriz. Blank Interval = %d pixels\n",
+ timing[3]);
+ printf("\tHoriz. Active Time 2 / Blanking "
+ "Interval 2 = %d\n", timing[4]);
+ printf("\tVert. Active Time = %d lines\n",
+ timing[5]);
+ printf("\tVert. Blanking Interval = %d lines\n",
+ timing[6]);
+ printf("\tVert. Active Time 2 / Blanking "
+ "Interval 2 = %d\n", timing[7]);
+ printf("\tHoriz. Sync Offset = %d pixels\n",
+ timing[8]);
+ printf("\tHoriz. Sync Pulsewidth = %d pixels\n",
+ timing[9]);
+ printf("\tVert. Sync Offset / Pulsewidth = %d\n",
+ timing[10]);
+ printf("\tVert. Sync Offset 2 / Pulsewidth 2 = %d\n",
+ timing[11]);
+ printf("\tImage Size = %dx%d mm\n",
+ timing[12], timing[13]);
+ printf("\tHoriz. / Vert. Image Size 2 = %d mm\n",
+ timing[14]);
+ printf("\tHoriz. Border Width = %d pixels\n",
+ timing[15]);
+ printf("\tVert. Border Height = %d pixels\n",
+ timing[16]);
+ printf("\tDisplay type: ");
+ if(timing[17] & 0x80) printf("interlaced, ");
+ switch((timing[17] >> 5) & 0x03) {
+ case 0: {
+ printf("non-stereo, ");
+ break;
+ }
+ case 1: {
+ printf("stereo, right stereo "
+ "sync high, ");
+ break;
+ }
+ case 2: {
+ printf("stereo, left stereo "
+ "sync high, ");
+ break;
+ }
+ case 0x60: {
+ printf("undefined stereo, ");
+ break;
+ }
+ }
+ switch((timing[17] >> 3) & 0x03) {
+ case 0: {
+ printf("sync analog composite");
+ break;
+ }
+ case 1: {
+ printf("sync bipolar analog "
+ "composite");
+ break;
+ }
+ case 2: {
+ printf("sync digital "
+ "composite");
+ break;
+ }
+ case 3: {
+ printf("sync digital separate");
+ break;
+ }
+ }
+ printf(".\n");
+ } else {
+ printf("Text info block %d: ", i);
+ switch(timing[3]) {
+ case 0xff: {
+ printf("serial number: ");
+ break;
+ }
+ case 0xfe: {
+ printf("vendor name: ");
+ break;
+ }
+ case 0xfd: {
+ printf("frequency range: ");
+ break;
+ }
+ case 0xfc: {
+ printf("model name: ");
+ break;
+ }
+ }
+ if(timing[3] != 0xfd) {
+ int j;
+ for(j = 4; j < 18; j++) {
+ if(isprint(timing[j])) {
+ printf("%c", timing[j]);
+ }
+ }
+ } else {
+ printf("hsync = %d-%d kHz, ",
+ timing[5], timing[6]);
+ printf("vsync = %d-%d Hz.",
+ timing[7], timing[8]);
+ }
+ printf("\n");
+ }
+ }
+ vm86_ram_free(memory);
+ return 0;
+}
diff --git a/ddcprobe/svgamodes.c b/ddcprobe/svgamodes.c
new file mode 100644
index 000000000..8ca345848
--- /dev/null
+++ b/ddcprobe/svgamodes.c
@@ -0,0 +1,174 @@
+#include <sys/types.h>
+#include <sys/io.h>
+#include <sys/stat.h>
+#include <sys/vm86.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include "vbe.h"
+#include "vesamode.h"
+#include "bioscall.h"
+#ident "$Id$"
+
+int main(int argc, char **argv)
+{
+ struct vm86_struct info;
+ struct vbe_info *vbe_info = NULL;
+ struct mode_info *mode_info = NULL;
+ unsigned char *memory = NULL;
+ u_int16_t *mode_list = NULL;
+ float vesa_version;
+
+ /* Get a copy of the low megabyte for use as an address space. */
+ memory = vm86_ram_alloc();
+ if(memory == MAP_FAILED) {
+ printf("Couldn't allocate needed memory!\n");
+ exit(0);
+ }
+
+ /* Set up registers for a real-mode interrupt call. */
+ memset(&info, 0, sizeof(info));
+ info.regs.eax = 0x4f00;
+ info.regs.es = 0x4000;
+ info.regs.edi = 0x0000;
+ info.regs.ss = 0x9000;
+ info.regs.esp = 0x0000;
+ info.flags = 0;
+
+ /* Call the BIOS. */
+ memset(&memory[info.regs.es * 16 + info.regs.edi], 0, 1024);
+ bioscall(0x10, &info.regs, memory);
+
+ /* Interpret results. */
+ vbe_info = (struct vbe_info*) &memory[info.regs.es*16 + info.regs.edi];
+
+ if((info.regs.eax & 0xff) != 0x4f) {
+ printf("VESA BIOS Extensions not detected.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ if((info.regs.eax & 0xffff) != 0x004f) {
+ printf("VESA Get SuperVGA Information request failed.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ /* Signature. */
+ printf("%c%c%c%c %d.%d detected.\n",
+ vbe_info->signature[0], vbe_info->signature[1],
+ vbe_info->signature[2], vbe_info->signature[3],
+ vbe_info->version[1], vbe_info->version[0]);
+ vesa_version = (vbe_info->version[1]) + (vbe_info->version[0]) / 10.0;
+
+ /* List supported standard modes. */
+ mode_list = (u_int16_t*) &memory[vbe_info->mode_list.addr.seg * 16 +
+ vbe_info->mode_list.addr.ofs];
+ if(*mode_list != 0xffff) {
+ printf("Supported standard modes:\n");
+ }
+ for(;*mode_list != 0xffff; mode_list++) {
+ int j;
+ printf("0x%03x\t", *mode_list);
+ for(j = 0; known_vesa_modes[j].x != 0; j++) {
+ if(known_vesa_modes[j].number == *mode_list) {
+ printf("%dx%d, %d colors",
+ known_vesa_modes[j].x,
+ known_vesa_modes[j].y,
+ known_vesa_modes[j].colors);
+ }}
+ printf("\n");
+ memset(&info, 0, sizeof(info));
+ info.regs.eax = 0x4f01;
+ info.regs.ecx = *mode_list;
+ info.regs.es = 0x5000;
+ info.regs.edi = 0x0000;
+ info.regs.ss = 0x9000;
+ info.regs.esp = 0x0000;
+ info.flags = 0;
+ memset(&memory[info.regs.es * 16 + info.regs.edi], 0, 1024);
+ bioscall(0x10, &info.regs, memory);
+ mode_info = (struct mode_info*) &memory[info.regs.es * 16 +
+ info.regs.edi];
+ if((info.regs.eax & 0xff) != 0x4f) {
+ printf("Get mode information not supported.\n");
+ vm86_ram_free(memory);
+ exit(0);
+ }
+
+ if((info.regs.eax & 0xffff) == 0x004f) {
+ if(mode_info->w && mode_info->h && mode_info->bpp) {
+ printf("\tBIOS reports %dx%d, %d bpp",
+ mode_info->w, mode_info->h,
+ mode_info->bpp);
+ }
+ if(mode_info->bytes_per_scanline) {
+ printf(", %d bytes per scanline.",
+ mode_info->bytes_per_scanline);
+ }
+ printf("\n");
+ printf("\t%s, ", mode_info->mode_attributes & 0x01 ?
+ "Supported" : "Not supported");
+ printf("%s ", mode_info->mode_attributes & 0x08 ?
+ "Color" : "Monochrome");
+ printf("%s.\n", mode_info->mode_attributes & 0x10 ?
+ "Graphics" : "Text");
+ if(vesa_version >= 2.0) {
+ printf("\tLFB mode %s.\n",
+ mode_info->mode_attributes & 0x80 ?
+ "supported" : "not supported");
+ printf("\t%sVGA compatible.\n",
+ mode_info->mode_attributes & 0x20 ?
+ "" : "Not ");
+ }
+ printf("\tMemory model: ");
+ switch(mode_info->memory_model) {
+ case memory_model_text: {
+ printf("text.\n");
+ break;
+ }
+ case memory_model_cga: {
+ printf("CGA.\n");
+ break;
+ }
+ case memory_model_hgc: {
+ printf("Hercules.\n");
+ break;
+ }
+ case memory_model_ega16: {
+ printf("EGA.\n");
+ break;
+ }
+ case memory_model_packed_pixel: {
+ printf("packed-pixel.\n");
+ break;
+ }
+ case memory_model_sequ256: {
+ printf("sequential 256.\n");
+ break;
+ }
+ case memory_model_direct_color: {
+ printf("direct color (24-bit).\n");
+ break;
+ }
+ case memory_model_yuv: {
+ printf("YUV.\n");
+ break;
+ }
+ default : {
+ printf("unknown/OEM.\n");
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/ddcprobe/vbe.c b/ddcprobe/vbe.c
new file mode 100644
index 000000000..77fd8c02e
--- /dev/null
+++ b/ddcprobe/vbe.c
@@ -0,0 +1,113 @@
+#include <sys/types.h>
+#include <sys/vm86.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bioscall.h"
+#include "vbe.h"
+
+struct mode_info *vbe_get_mode_info(u_int16_t mode)
+{
+ struct vm86_regs regs;
+ unsigned char *ram;
+ struct mode_info *ret = NULL;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.eax = 0x4f01;
+ regs.ecx = mode;
+ regs.es = 0x3000;
+ regs.edi = 0x3000;
+
+ /* Just to be sure... */
+ assert(regs.es != BIOSCALL_START_SEG);
+
+ /* Get memory for the bios call. */
+ ram = vm86_ram_alloc();
+ if(ram == MAP_FAILED) {
+ return NULL;
+ }
+
+ /* Do it. */
+ bioscall(0x10, &regs, ram);
+
+ /* Check for successful return. */
+ if((regs.eax & 0xffff) != 0x004f) {
+ return NULL;
+ }
+
+ /* Get memory for return. */
+ ret = malloc(sizeof(struct mode_info));
+ if(ret == NULL) {
+ return NULL;
+ }
+
+ /* Copy the buffer for return. */
+ memcpy(ret, &ram[regs.es * 16 + regs.edi], sizeof(struct mode_info));
+
+ /* Clean up and return. */
+ vm86_ram_free(ram);
+ return ret;
+}
+
+struct vbe_info *vbe_get_vbe_info()
+{
+ struct vm86_regs regs;
+ unsigned char *ram;
+ struct vbe_info *ret = NULL;
+ u_int16_t *modes;
+ int mode_count = 0;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.eax = 0x4f00;
+ regs.es = 0x3000;
+ regs.edi = 0x3000;
+
+ /* Just to be sure... */
+ assert(regs.es != BIOSCALL_START_SEG);
+
+ /* Get memory for the bios call. */
+ ram = vm86_ram_alloc();
+ if(ram == MAP_FAILED) {
+ return NULL;
+ }
+
+ /* Do it. */
+ bioscall(0x10, &regs, ram);
+
+ /* Check for successful return code. */
+ if((regs.eax & 0xffff) != 0x004f) {
+ return NULL;
+ }
+
+ /* Count the number of supported video modes. */
+ ret = (struct vbe_info*) &ram[regs.es * 16 + regs.edi];
+ modes = (u_int16_t*) &ram[ret->mode_list.addr.seg * 16 +
+ ret->mode_list.addr.ofs];
+ for(mode_count = 0; (*modes != 0xffff); modes++) {
+ mode_count++;
+ }
+ modes = (u_int16_t*) &ram[ret->mode_list.addr.seg * 16 +
+ ret->mode_list.addr.ofs];
+
+ /* Get enough memory to hold the mode list, too. */
+ ret = malloc(sizeof(struct vbe_info) +
+ (mode_count + 1) * sizeof(u_int16_t) +
+ strlen(&ram[ret->oem_name.addr.seg * 16 +
+ ret->oem_name.addr.ofs]));
+ if(ret == NULL) {
+ return NULL;
+ }
+
+ /* Copy the static parts of the buffer out. */
+ memcpy(ret, &ram[regs.es * 16 + regs.edi], sizeof(struct vbe_info));
+
+ /* Copy the modes list and set the pointer to it. */
+ memcpy(ret + 1, modes, (mode_count + 1) * sizeof(u_int16_t));
+ ret->mode_list.list = (u_int16_t*) (ret + 1);
+ memcpy(&ret->mode_list.list[mode_count],
+ &ram[ret->oem_name.addr.seg * 16 + ret->oem_name.addr.ofs],
+ strlen(&ram[ret->oem_name.addr.seg*16+ret->oem_name.addr.ofs]));
+
+ vm86_ram_free(ram);
+ return ret;
+}
diff --git a/ddcprobe/vesamode.c b/ddcprobe/vesamode.c
new file mode 100644
index 000000000..5e8798a5a
--- /dev/null
+++ b/ddcprobe/vesamode.c
@@ -0,0 +1,71 @@
+/* Most of these come from http://www.knowplace.org/timings.html */
+
+#include "vesamode.h"
+#ident "$Id$"
+
+/* Known standard VESA modes. */
+struct vesa_mode_t known_vesa_modes[] = {
+ /* VESA 1.0/1.1 ? */
+ {0x100, 640, 400, 256, "640x400x256"},
+ {0x101, 640, 480, 256, "640x480x256"},
+ {0x102, 800, 600, 16, "800x600x16"},
+ {0x103, 800, 600, 256, "800x600x256"},
+ {0x104, 1024, 768, 16, "1024x768x16"},
+ {0x105, 1024, 768, 256, "1024x768x256"},
+ {0x106, 1280, 1024, 16, "1280x1024x16"},
+ {0x107, 1280, 1024, 256,"1280x1024x256"},
+ {0x108, 80, 60, 0, "80x60 (text)"},
+ {0x109, 132, 25, 0, "132x25 (text)"},
+ {0x10a, 132, 43, 0, "132x43 (text)"},
+ {0x10b, 132, 50, 0, "132x50 (text)"},
+ {0x10c, 132, 60, 0, "132x60 (text)"},
+ /* VESA 1.2 */
+ {0x10d, 320, 200, 32768, "320x200x32k"},
+ {0x10e, 320, 200, 65536, "320x200x64k"},
+ {0x10f, 320, 200, 16777216, "320x200x16m"},
+ {0x110, 640, 480, 32768, "640x480x32k"},
+ {0x111, 640, 480, 65536, "640x480x64k"},
+ {0x112, 640, 480, 16777216, "640x480x16m"},
+ {0x113, 800, 600, 32768, "800x600x32k"},
+ {0x114, 800, 600, 65536, "800x600x64k"},
+ {0x115, 800, 600, 16777216, "800x600x16m"},
+ {0x116, 1024, 768, 32768, "1024x768x32k"},
+ {0x117, 1024, 768, 65536, "1024x768x64k"},
+ {0x118, 1024, 768, 16777216, "1024x768x16m"},
+ {0x119, 1280, 1024, 32768, "1280x1024x32k"},
+ {0x11a, 1280, 1024, 65536, "1280x1024x64k"},
+ {0x11b, 1280, 1024, 16777216, "1280x1024x16m"},
+ /* VESA 2.0 */
+ {0x120, 1600, 1200, 256, "1600x1200x256"},
+ {0x121, 1600, 1200, 32768, "1600x1200x32k"},
+ {0x122, 1600, 1200, 16777216, "1600x1200x64k"},
+ { 0, 0, 0, 0, ""},
+};
+
+struct vesa_timing_t known_vesa_timings[] = {
+ { 640, 480, 75, 31.50, { 640, 16, 64, 120, 480, 1, 3, 16},
+ hsync_neg, vsync_pos},
+ { 640, 480, 85, 36.00, { 640, 56, 56, 80, 480, 1, 3, 25},
+ hsync_neg, vsync_pos},
+ { 800, 600, 75, 49.50, { 800, 16, 80, 160, 600, 1, 3, 21},
+ hsync_pos, vsync_pos},
+ { 800, 600, 85, 56.25, { 800, 32, 64, 132, 600, 1, 3, 27},
+ hsync_pos, vsync_pos},
+ {1024, 768, 75, 78.75, {1024, 16, 96, 176, 768, 1, 3, 28},
+ hsync_pos, vsync_pos},
+ {1024, 768, 85, 94.50, {1024, 48, 96, 208, 768, 1, 3, 36},
+ hsync_pos, vsync_pos},
+ {1152, 864, 75, 108.00, {1152, 64, 128, 256, 864, 1, 3, 32},
+ hsync_pos, vsync_pos},
+ {1152, 864, 85, 121.50, {1152, 64, 128, 224, 864, 1, 3, 43},
+ hsync_pos, vsync_pos},
+ {1280, 1024, 75, 135.00, {1280, 16, 144, 248, 1024, 1, 3, 38},
+ hsync_pos, vsync_pos},
+ {1280, 1024, 85, 157.50, {1280, 64, 160, 224, 1024, 1, 3, 44},
+ hsync_pos, vsync_pos},
+ {1600, 1200, 75, 202.50, {1600, 64, 192, 304, 1200, 1, 3, 46},
+ hsync_pos, vsync_pos},
+ {1600, 1200, 85, 229.50, {1600, 64, 192, 304, 1200, 1, 3, 46},
+ hsync_pos, vsync_pos},
+ { 0, 0, 0, 0.00, { 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0},
+};