#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vbe.h" #include "vesamode.h" #include "lrmi.h" #ident "$Id: ddcprobe.c,v 1.1.1.1 2002/05/29 20:17:14 csieh Exp $" char *snip(char *string) { int i; /* This is always a 13 character buffer */ /* and it's not always terminated. */ string[12] = '\0'; 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); } if (strcasestr(vbe_info->oem_name.string, "intel") && strstr(vbe_info->oem_name.string, "810")) { printf("Intel 810 VESA video memory = %d * 64k blocks = %dkb. Use 4MB video memory.\n", vbe_info->memory_size, vbe_info->memory_size * 64); printf("Memory installed = 64 * 64k blocks = 4096kb\n"); } else 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); } if ((edid_info->version == 0xff && edid_info->revision == 0xff) || (edid_info->version == 0 && edid_info->revision == 0)) { printf("EDID read failed, returned empty data\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: %04x\n", edid_info->product_code); printf("EISA ID: %s%04x\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; }