#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 "lrmi.h"
#ident "$Id: ddcprobe.c,v 1.6 1999/08/30 22:46:20 msw Exp $"
char *snip(char *string)
{
int i;
while(((i = strlen(string)) > 0) &&
(isspace(string[i - 1]) ||
(string[i - 1] == '\n') ||
(string[i - 1] == '\r'))) {
string[i - 1] = '\0';
}
return string;
}
int main(int argc, char **argv)
{
struct vbe_info *vbe_info = NULL;
struct vbe_edid1_info *edid_info = NULL;
u_int16_t *mode_list = NULL;
char manufacturer[4];
int i;
assert(sizeof(struct vbe_info) == 512);
assert(sizeof(struct vbe_edid1_info) == 256);
assert(sizeof(struct vbe_edid_detailed_timing) == 18);
assert(sizeof(struct vbe_edid_monitor_descriptor) == 18);
vbe_info = vbe_get_vbe_info();
if(vbe_info == NULL) {
printf("VESA BIOS Extensions not detected.\n");
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 Strings. */
printf("OEM Name: %s\n", vbe_info->oem_name.string);
if(vbe_info->version[1] >= 3) {
printf("Vendor Name: %s\n",
vbe_info->vendor_name.string);
printf("Product Name: %s\n",
vbe_info->product_name.string);
printf("Product Revision: %s\n",
vbe_info->product_revision.string);
}
/* Memory. */
printf("Memory installed = %d * 64k blocks = %dkb\n",
vbe_info->memory_size, vbe_info->memory_size * 64);
/* List supported standard modes. */
mode_list = vbe_info->mode_list.list;
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);
}
}
}
if(!vbe_get_edid_supported()) {
printf("EDID read not supported by video card.\n");
exit(0);
}
edid_info = vbe_get_edid_info();
/* Interpret results. */
if((edid_info == NULL) || (edid_info->version == 0)) {
printf("EDID read failed. (No DDC-capable monitor attached?)\n");
exit(0);
}
printf("EDID ver. %d rev. %d.\n",
edid_info->version, edid_info->revision);
manufacturer[0] = edid_info->manufacturer_name.char1 + 'A' - 1;
manufacturer[1] = edid_info->manufacturer_name.char2 + 'A' - 1;
manufacturer[2] = edid_info->manufacturer_name.char3 + 'A' - 1;
manufacturer[3] = '\0';
printf("Manufacturer: %s\n", manufacturer);
printf("ID: %d\n", edid_info->product_code);
printf("EISA ID: %s%d\n", manufacturer, edid_info->product_code);
if(edid_info->serial_number != 0xffffffff) {
if(strcmp(manufacturer, "MAG") == 0) {
edid_info->serial_number -= 0x7000000;
}
if(strcmp(manufacturer, "OQI") == 0) {
edid_info->serial_number -= 456150000;
}
if(strcmp(manufacturer, "VSC") == 0) {
edid_info->serial_number -= 640000000;
}
}
printf("Serial number: %08x.\n", edid_info->serial_number);
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_definition.separate_sync ?
"separate sync, " : "",
edid_info->video_input_definition.composite_sync ?
"composite sync, " : "",
edid_info->video_input_definition.sync_on_green ?
"sync on green, " : "",
edid_info->video_input_definition.digital ?
"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->feature_support.rgb ? "RGB" : "non-RGB",
edid_info->feature_support.active_off ? "" : "no ", "active off",
edid_info->feature_support.suspend ? "" : "no ", "suspend",
edid_info->feature_support.standby ? "" : "no ", "standby");
printf("Established timings:\n");
if(edid_info->established_timings.timing_720x400_70)
printf("\t720x400 @ 70 Hz (VGA 640x400, IBM)\n");
if(edid_info->established_timings.timing_720x400_88)
printf("\t720x400 @ 88 Hz (XGA2)\n");
if(edid_info->established_timings.timing_640x480_60)
printf("\t640x480 @ 60 Hz (VGA)\n");
if(edid_info->established_timings.timing_640x480_67)
printf("\t640x480 @ 67 Hz (Mac II, Apple)\n");
if(edid_info->established_timings.timing_640x480_72)
printf("\t640x480 @ 72 Hz (VESA)\n");
if(edid_info->established_timings.timing_640x480_75)
printf("\t640x480 @ 75 Hz (VESA)\n");
if(edid_info->established_timings.timing_800x600_56)
printf("\t800x600 @ 56 Hz (VESA)\n");
if(edid_info->established_timings.timing_800x600_60)
printf("\t800x600 @ 60 Hz (VESA)\n");
if(edid_info->established_timings.timing_800x600_72)
printf("\t800x600 @ 72 Hz (VESA)\n");
if(edid_info->established_timings.timing_800x600_75)
printf("\t800x600 @ 75 Hz (VESA)\n");
if(edid_info->established_timings.timing_832x624_75)
printf("\t832x624 @ 75 Hz (Mac II)\n");
if(edid_info->established_timings.timing_1024x768_87i)
printf("\t1024x768 @ 87 Hz Interlaced (8514A)\n");
if(edid_info->established_timings.timing_1024x768_60)
printf("\t1024x768 @ 60 Hz (VESA)\n");
if(edid_info->established_timings.timing_1024x768_70)
printf("\t1024x768 @ 70 Hz (VESA)\n");
if(edid_info->established_timings.timing_1024x768_75)
printf("\t1024x768 @ 75 Hz (VESA)\n");
if(edid_info->established_timings.timing_1280x1024_75)
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(edid_info->standard_timing[i].aspect) {
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++) {
struct vbe_edid_monitor_descriptor *monitor = NULL;
struct vbe_edid_detailed_timing *timing = NULL;
timing = &edid_info->monitor_details.detailed_timing[i];
monitor = &edid_info->monitor_details.monitor_descriptor[i];
if((monitor->zero_flag_1 != 0) || (monitor->zero_flag_2 != 0)) {
printf("Detailed timing %d:\n", i);
printf("\tPixel clock: %d\n",
VBE_EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing));
printf("\tHorizontal active time (pixel width): %d\n",
VBE_EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing));
printf("\tHorizontal blank time (pixel width): %d\n",
VBE_EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing));
printf("\tVertical active time (pixel height): %d\n",
VBE_EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing));
printf("\tVertical blank time (pixel height): %d\n",
VBE_EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing));
printf("\tHorizontal sync offset: %d\n",
VBE_EDID_DETAILED_TIMING_HSYNC_OFFSET(*timing));
printf("\tHorizontal sync pulse width: %d\n",
VBE_EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(*timing));
printf("\tVertical sync offset: %d\n",
VBE_EDID_DETAILED_TIMING_VSYNC_OFFSET(*timing));
printf("\tVertical sync pulse width: %d\n",
VBE_EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(*timing));
printf("\tDimensions: %dx%d\n",
VBE_EDID_DETAILED_TIMING_HIMAGE_SIZE(*timing),
VBE_EDID_DETAILED_TIMING_VIMAGE_SIZE(*timing));
} else
if(monitor->type == vbe_edid_monitor_descriptor_serial) {
printf("Monitor details %d:\n", i);
printf("\tSerial number: %s\n",
snip(monitor->data.string));
} else
if(monitor->type == vbe_edid_monitor_descriptor_ascii) {
printf("Monitor details %d:\n", i);
printf("\tASCII String: %s:\n",
snip(monitor->data.string));
} else
if(monitor->type == vbe_edid_monitor_descriptor_name) {
printf("Monitor details %d:\n", i);
printf("\tName: %s\n",
snip(monitor->data.string));
} else
if(monitor->type == vbe_edid_monitor_descriptor_range) {
printf("Monitor details %d:\n", i);
printf("\tTiming ranges: "
"horizontal = %d - %d, vertical = %d - %d\n",
monitor->data.range_data.horizontal_min,
monitor->data.range_data.horizontal_max,
monitor->data.range_data.vertical_min,
monitor->data.range_data.vertical_max);
}
}
return 0;
}