diff options
author | nalin <nalin> | 1999-07-18 06:44:42 +0000 |
---|---|---|
committer | nalin <nalin> | 1999-07-18 06:44:42 +0000 |
commit | 75d74b8f61de2e50989bf3b601ad414abdeeb964 (patch) | |
tree | 90d09bfd8fce323226dca355641a4916a5a86cb3 | |
parent | 99801f67664b5201f6fe92c4b202ee455ba7707d (diff) | |
download | anaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.tar.gz anaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.tar.xz anaconda-75d74b8f61de2e50989bf3b601ad414abdeeb964.zip |
Initial revision
-rw-r--r-- | ddcprobe/bioscall.c | 207 | ||||
-rw-r--r-- | ddcprobe/ddcprobe.c | 354 | ||||
-rw-r--r-- | ddcprobe/svgamodes.c | 174 | ||||
-rw-r--r-- | ddcprobe/vbe.c | 113 | ||||
-rw-r--r-- | ddcprobe/vesamode.c | 71 |
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(®s, 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, ®s, 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(®s, 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, ®s, 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}, +}; |