/*
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
* fbc_predid - Display EDID data
*/
#include <ctype.h> /* isprint() */
#include <stdio.h> /* printf(), putchar(), sprintf() */
#include <string.h> /* strlen() */
#include "sun_edid.h" /* EDID data parsing */
#include "fbc.h" /* Common fbconf_xorg(1M) definitions */
#include "fbc_predid.h" /* Display EDID data */
#include "fbc_predid_ceaext.h" /* Display EDID CEA-EXT data */
#include "fbc_predid_diext.h" /* Display EDID DI-EXT data */
#include "fbc_predid_vtbext.h" /* Display EDID VTB-EXT data */
/*
* Conversions from EDID flag bit value to output text string
*/
/*
* fbc_predid_dump_bytes()
*
* Dump the specified bytes of the EDID data block in hexadecimal.
*
* Byte addresses as well as data bytes are displayed using two hex
* digits. Each line can contain 16 bytes. The data is such that an
* ASCII display wouldn't be useful.
*/
void
{
size_t i; /* Loop counter / array index */
/*
* Provide Spaces for undisplayed bytes that precede the start address
*/
hex_buf[0] = '\0';
}
/*
* Display each 16-byte wide line of the dump
*/
for (;
byte_addr += 1) {
}
hex_buf[0] = '\0';
}
} /* fbc_predid_dump_bytes() */
/*
* fbc_predid_tagged_string()
*
* Given a string tag number, a table of tagged strings with a
* final NULL entry, and a default string, return the text string
* with the matching tag, else return the default text string.
*/
const char *
unsigned int tag, /* String tag number */
const char *const default_text) /* Default string text */
{
int i; /* Loop counter / arrax index */
}
}
return (default_text);
} /* fbc_predid_tagged_string() */
/*
* Parsed EDID data display function type
*/
typedef void (parsed_fn_t)(
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr); /* Ending byte address */
/*
* EDID data block format descriptor
*/
typedef struct {
enum {
};
/*
* fbc_predid_vendor()
*
* Decode and display Vendor & Product Identification from an EDID
* Base block:
* * ID Manufacturer
* * ID Product Code
* * ID Serial Number (Zero = Not used)
* * Week of Manufacture
* (0x00 = Not used, 1..54 = Week, 0xFF = Model year flag (EDID 1.4))
* * Year of Manufacture or Model Year
*/
static
void
unsigned int start_addr, /* Starting byte address (0x08) */
unsigned int end_addr) /* Ending byte address (0x11) */
{
} else {
}
if (week == 0xFF) {
} else {
}
} /* fbc_predid_vendor() */
/*
* fbc_predid_version()
*
* Decode and display the EDID Structure and Revision from an EDID
* Base block:
* * ID Manufacturer
* * ID Product Code
* * ID Serial Number (Zero = Not used)
* * Week of Manufacture (0x00 = Not used, 1..54 = Week,
* 0xFF = Model year flag (EDID 1.4))
* * Year of Manufacture or Model Year
*/
static
void
unsigned int start_addr, /* Starting byte address (0x12) */
unsigned int end_addr) /* Ending byte address (0x13) */
{
printf("\t EDID Version: %u.%u\n",
} /* fbc_predid_version() */
/*
* fbc_predid_disp_params()
*
* Decode and display the Basic Display Parameters & Features section
* of an EDID Base block:
* * Video Input Definition
* * Horizontal & Vertical Screen Size or Aspect Ratio
* * Vertical Screen Size or Aspect Ratio
* * Display Transfer Characteristic (Gamma)
* * Feature Support
*/
static
void
unsigned int start_addr, /* Starting byte address (0x14) */
unsigned int end_addr) /* Ending byte address (0x18) */
{
/*
* Video Input Definition
*/
/*
* Input is an Analog Video Signal Interface
*/
printf("\t Signal Level Std (Video+Sync=Total): "
" %5.3f + %5.3f = %5.3f\n",
printf("\t Video Setup: %s\n",
"Blank-to-Black setup or pedestal" :
"Blank Level = Black Level");
printf("\t Separate Sync H & V Signals: %s\n",
printf("\t Composite Sync Signal on Horizontal: %s\n",
printf("\t Composite Sync Signal on Green Video: %s\n",
printf("\t Serration on the Vertical Sync: %s\n",
} else {
const char *dvi_std[] = {
"Not defined",
"DVI",
"HDMI-a",
"HDMI-b",
"MDDI",
"DisplayPort"
};
/*
* Input is a Digital Video Signal Interface
*/
printf("\t Color Bit Depth: ");
printf("Undefined\n");
} else
} else {
printf("Reserved\n");
}
printf("\t Digital Video Interface Standard: %s\n",
"Reserved");
}
/*
* Horizontal & Vertical Screen Size or Aspect Ratio
*
* The returned aspect ratio value (introduced in EDID 1.4)
* is only valid iff positive. Aspect ratios are rounded to
* the hundredth decimal place.
*/
if ((horizontal != 0) && (vertical != 0)) {
printf("\t Screen Size (HxV): %dx%d cm\n",
} else
if (aspect > 0.0) {
if (horizontal != 0) {
"\t Aspect ratio (Landscape): %4.2f:1\n",
aspect);
} else {
printf("\t Aspect ratio (Portrait): %4.2f:1\n",
aspect);
}
}
/*
* Display Transfer Characteristic (Gamma)
*/
printf("\t Gamma: ");
if (gamma > 0.0) {
} else {
printf("Undefined\n");
}
/*
* Feature Support
*/
printf("\t Standby Mode: %s\n",
printf("\t Suspend Mode: %s\n",
printf("\t Active Off: %s\n",
"Monochrome or Grayscale",
"RGB color",
"Non-RGB color",
"Undefined"
};
printf("\t Display Color Type: %s\n",
} else {
"RGB 4:4:4",
"RGB 4:4:4 & YCrCb 4:4:4",
"RGB 4:4:4 & YCrCb 4:2:2",
"RGB 4:4:4 & YCrCb 4:4:4 & YCrCb 4:2:2"
};
printf("\t Color Encoding Format(s): %s\n",
}
printf("\t sRGB Standard is default color space: %s\n",
printf("\t Preferred Timing Mode inclusions: %s\n",
printf("\t Display is continuous frequency: %s\n",
} /* fbc_predid_disp_params() */
/*
* fbc_predid_color_chars()
*
* Decode and display the Color Characteristics section of an EDID
* Base block.
*/
static
void
unsigned int start_addr, /* Starting byte address (0x19) */
unsigned int end_addr) /* Ending byte address (0x22) */
{
printf("\t Red x,y: %9.7f %9.7f\n",
printf("\t Green x,y: %9.7f %9.7f\n",
printf("\t Blue x,y: %9.7f %9.7f\n",
printf("\t White x,y: %9.7f %9.7f\n",
} /* fbc_predid_color_chars() */
/*
* fbc_predid_est_timings()
*
* Decode and display the sense of an Established Timings bit array.
*/
static
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
for (bit_off = 0;
bit_off += 1) {
printf("\t %2d: %4d x %4d @ %3d\n",
}
}
} /* fbc_predid_est_timings() */
/*
* fbc_predid_std_timing()
*
* Decode and display a Standard Timing Descriptor.
*/
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
index = 0;
printf("\t %2d: %4d x %4d @ %3d\n",
}
index += 1;
}
} /* fbc_predid_std_timings() */
/*
* fbc_predid_det_timing()
*
* Decode and display a Detailed Timing Descriptor.
*/
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
/*
* Detailed Timing Definition -- Part 1
*/
/* Note 18 for Table 3.21 */
printf("\t Image Aspect Ratio: %d:%d\n",
} else {
printf("\t H Addr Video Image: %d mm\n",
printf("\t V Addr Video Image: %d mm\n",
}
/*
* Detailed Timing Definition -- Part 2 (Flags)
*/
printf("\t Signal Interface Type: %s\n",
{
"Normal Display - No Stereo",
"Normal Display - No Stereo",
"Field sequential, right when sync = 1",
"2-way interleaved, right on even lines",
"Field sequential, left when sync = 1",
"2-way interleaved, left on even lines",
"4-way interleaved stereo",
"Side-by-Side interleaved stereo"
};
printf("\t Stereo Viewing Support: %s\n",
}
printf("\t Analog Sync Signal Definitions:\n");
printf("\t\tBipolar Analog Composite Sync: %s\n",
printf("\t\tSerrations: %s\n",
printf("\t\tSync On: %s\n",
} else {
printf("\t Digital Sync Signal Definitions:\n");
printf("\t Digital Composite Sync:\n");
printf("\t\t Serrations: %s\n",
} else {
printf("\t Digital Separate Sync:\n");
printf("\t\t Vertical Sync: %s\n",
? "Positive" : "Negative");
}
printf("\t Horizontal Sync: %s\n",
}
}
} /* fbc_predid_det_timing() */
static
void
{
printf("\t Display Range Limits\n");
printf("\t Vertical Rate: %u - %u Hz\n",
printf("\t Horizontal Rate: %u - %u kHz\n",
printf("\t Maximum Pixel Clock: %u MHz\n",
switch (edid_data[10]) {
case 0x00:
/* Note that this bit must be set: (edid_data[0x18] & 0x01) */
printf("\t Default GTF supported\n");
break;
case 0x01:
printf("\t Range Limits only\n");
break;
case 0x02: /* Generalized Timing Formula (deprecated) */
/* Note that this bit must be set: (edid_data[0x18] & 0x01) */
printf("\t GTF Secondary Curve\n");
"\t\tStart break frequency for secondary curve: %u kHz\n",
break;
case 0x04:
/* Note that this bit must be set: (edid_data[0x18] & 0x01) */
printf("\t CVT Support Information\n");
printf("\t\tCVT Standard Version: %u.%u\n",
printf("\t\tMaximum Pixel Clock: %u.%02u MHz\n",
printf("\t\tMaximum Active Pixels per Line: ");
if (range_limits->cvt_hactive_max == 0) {
printf("No limit\n");
} else {
}
{
const char *aspect_ratio[] = {
"4:3",
"16:9",
"16:10",
"5:4",
"15:9",
"Reserved",
"Reserved",
"Reserved",
};
int bit_off;
char *comma;
printf("\t\tSupported Aspect Ratios: ");
comma = "";
for (bit_off = 0;
bit_off += 1) {
if (sun_edid_bit_set(
printf("%s%s",
comma = ", ";
}
}
printf("\n");
printf("\t\tPreferred Aspect Ratio: %s\n",
}
printf("\t\tStandard CVT Blanking: %s\n",
printf("\t\tReduced CVT Blanking: %s\n",
{
const char *display_scaling[] = {
"Horizontal Shrink",
"Horizontal Stretch",
"Vertical Shrink",
"Vertical Stretch",
};
int bit_off;
printf("\t\tSupported Display Scaling:\n");
for (bit_off = 0;
bit_off += 1) {
if (sun_edid_bit_set(
printf("\t\t %s\n",
}
}
}
break;
}
} /* fbc_predid_range_limits() */
/*
* fbc_predid_18_byte_data()
*
* Decode and display an 18-Byte Data Block.
*/
static
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
/*
* Determine what kind of 18-Byte Data Block this is
*/
/*
* Display the Detailed Timing Descriptor
*/
} else
/* if (edid_base[start_addr+2] == 0) */ { /* Reserved */
/*
* Display the Display Descriptor
*
* Display Descriptor tag numbers are (as of EDID 1.4):
* 0xFF Display Product Serial Number
* 0xFE Alphanumeric Data String (ASCII)
* 0xFD Display Range Limits
* 0xFC Display Product Name
* 0xFB Color Point Data
* 0xFA Standard Timing Identifications
* 0xF9 Display Color Management (DCM) Data
* 0xF8 CVT 3 Byte Timing Codes
* 0xF7 Established Timings III
* 0x11..0xF6 Reserved
* 0x10 Dummy Descriptor
* 0x00..0x0F Manufacturer Specified Display Descriptors
*/
switch (tag) {
case 0xFF:
printf("\t Display Product Serial Number: %s\n",
break;
case 0xFE:
printf("\t Alphanumeric Data String: %s\n",
break;
case 0xFD:
{
/* Display Range Limits */
&range_limits);
&range_limits);
}
break;
case 0xFC:
printf("\t Display Product Name: %s\n",
break;
case 0xFB:
printf("\t Color Point Data\n");
break;
case 0xFA:
printf("\t Standard Timing Identifications\n");
break;
case 0xF9:
printf("\t Display Color Management (DCM) Data\n");
break;
case 0xF8:
printf("\t CVT 3 Byte Timing Codes\n");
break;
case 0xF7:
printf("\t Established Timings III\n");
break;
case 0x10:
printf("\t Dummy Descriptor\n");
break;
default:
"\t Reserved Display Descriptor (tag = 0x%02X)\n",
tag);
break;
}
if (tag <= 0x0F) {
"\t Manufacturer Specified Display Descriptor (tag = 0x%02X)\n",
tag);
break;
}
break;
}
}
} /* fbc_predid_18_byte_data() */
/*
* fbc_predid_ext_blk_cnt()
*
* Display the Extension Block Count N of an EDID Base block.
*/
static
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
} /* fbc_predid_ext_blk_cnt() */
/*
* fbc_predid_checksum()
*
* Display the checksum byte of an EDID data block and complain when
* it's not correct.
*/
static
void
unsigned int start_addr, /* Starting byte address */
unsigned int end_addr) /* Ending byte address */
{
if (sum != 0) {
"\t Sum of bytes (0x%02X) in EDID block is non-zero\n",
sum);
}
} /* fbc_predid_checksum() */
/*
* fbc_predid_ext_revision()
*
* EDID Extension Block revision number.
*/
static
void
unsigned int start_addr, /* Starting byte address (0x01) */
unsigned int end_addr) /* Ending byte address (0x01) */
{
} /* fbc_predid_ext_revision() */
/* Base Block common strings (referenced at least twice) */
static const char bb_det_timing_2_etc[] =
" Detailed Timing #2 or Display Descriptor";
static const char bb_det_timing_3_etc[] =
" Detailed Timing #3 or Display Descriptor";
static const char bb_det_timing_4_etc[] =
" Detailed Timing #4 or Display Descriptor";
/* Base Block format, EDID 1.0 */
};
/* Base Block format, EDID 1.1 & 1.2 */
{ 0x36, 0x47, " Detailed Timing #1 or Display Descriptor",
};
/* Base Block format, EDID 1.3 & 1.4 */
};
/* Extension Block common strings (referenced at least twice) */
/* CEA-EXT (Tag 0x02): CEA 861 Series Extension Block */
"CEA 861 Series Extension (CEA-EXT) Block", NULL },
{ 0x02, 0x02, "Detailed Timing Descriptor Start Address",
};
/* VTB-EXT (Tag 0x10): Video Timing Block Extension Block */
"Video Timing Block Extension (VTB-EXT) Block", NULL },
};
/* DI-EXT (Tag 0x40): Display Information Extension Block */
"Display Information Extension (DI-EXT) Block", NULL },
{ 0x02, 0x0D, "Digital Interface section",
{ 0x0E, 0x13, "Display Device section",
{ 0x14, 0x36, "Display Capabilities & Feature Support Set",
{ 0x51, 0x7E, "Display Transfer Characteristic - Gamma",
};
/* LS-EXT (Tag 0x50): Localized String Extension Block */
"Localized String Extension (LS-EXT) Block", NULL },
};
/* DPVL-EXT (Tag 0x60): Digital Packet Video Link (DPVL-EXT) Extension */
"Digital Packet Video Link Extension (DPVL-EXT) Block", NULL },
};
/* Extension Block Map 1 format (Tag 0xF0 at Block 1) */
{ 0x01, 0x7E,
"Extension Block Tags for Extension Blocks 2 to 127", NULL },
};
/* Extension Block Map 2 format (Tag 0xF0 at Block 128) */
{ 0x01, 0x7E,
"Extension Block Tags for Extension Blocks 129 to 254", NULL },
};
/* Extensions defined by the display manufacturer (Tag 0xFF) */
"Extensions defined by the display manufacturer", NULL },
};
/* Unknown Extension block (This might be passed to fbc_predid_dump_block()) */
};
/* Unknown EDID block (This won't be passed to fbc_predid_dump_block()) */
};
/*
* fbc_predid_dump_block()
*
* Display this EDID data block according to the provided format
* descriptors (as from edid_1_3_base_fmt[], etc.).
*/
static
void
int predid_raw) /* TRUE => Display raw EDID data */
{
/*
* Repeat for each EDID structure format descriptor
*
* The EDID data block heading (block_fmt[0].heading) has
* been displayed already.
*/
blk_fmt += 1) {
/*
* Display a line describing the data that follows
*/
}
/*
* If the function exisis, display the EDID data in parsed form
*
* There typically wouldn't be a parser function for:
* * Heading text lines
* * EDID Base block header bytes
* * Raw, opaque, or enigmatic data bytes
* * Reserved bytes (zeroes)
* * etc.
*/
if (parsed) {
}
/*
* Display the EDID data as raw hexadecimal bytes
*
* Skip this if this fbc_edid_fmt_t descriptor is for
* a header line, and not for data bytes (NO_DATA).
*
* Otherwise, display the raw data if either is true:
* * There is no parsed EDID data display function
* * The "-predid ... raw ..." option is specified
*/
(predid_raw || !parsed)) {
}
}
} /* fbc_predid_dump_block() */
/*
* fbc_predid()
*
* Dump the E-EDID (Enhanced Extended Display Identification Data)
* data blocks. The contiguous EDID data bytes are pointed to by
* edid_data. The byte length is specified by edid_length.
*
* human-readable text (predid_parsed). If only raw data is wanted,
* the hex values will appear in a 16x8 grid. Parsed output will
* include subheadings, text labels, numeric or textual values, etc.
* If both raw and parsed form are wanted, raw hex for each
* subheading will appear after the parsed output, as an aligned
* fragment of a 16x8 grid.
*/
void
int predid_raw, /* TRUE => Display raw EDID data */
int predid_parsed) /* TRUE => Display parsed EDID data */
{
#if defined(FBC_EDID_TEST_DATA)
#include "fbc_edid_test_data.h" /* EDID test data */
#endif
/*
* Make sure there's at least some EDID data to display
*/
"EDID Data: EDID Base block is not available\n");
return;
}
/*
* EDID version and revision
*/
/*
* Display each EDID data block
*/
block_num = 0;
for (block_addr = 0x00;
block_addr += 0x80) {
/*
* Figure out what kind of EDID block this might be
*/
block_fmt = &edid_unknown_fmt[0];
block_len = 0x80;
/*
* Incomplete EDID data block
*/
} else
if (block_num == 0) {
/*
* EDID Base Block
*/
block_fmt = &edid_1_0_base_fmt[0];
if (edid_version >= EDID_1_1) {
block_fmt = &edid_1_1_base_fmt[0];
}
if (edid_version >= EDID_1_3) {
block_fmt = &edid_1_3_base_fmt[0];
}
} else
if (block_num <= 255) {
/*
* EDID Extension Block
*
* There's not much solid documentation on
* Extension Blocks until the EDID 1.4 spec.
* The EDID 1.3 spec is kind of runny.
*
* If block #255 is found to be out of range,
* retain &edid_unknown_fmt[0] as the value
* of block_fmt.
*/
if (edid_version < EDID_1_3) {
block_fmt = &edid_unknown_ext_fmt[0];
} else
if (edid_version == EDID_1_3) {
if (block_num < 255) {
block_fmt = &edid_unknown_ext_fmt[0];
ext_block_tag = tag;
}
}
} else
if (edid_version >= EDID_1_4) {
ext_block_tag = tag;
}
}
switch (ext_block_tag) {
default: /* Bad blk #, bad tag, no documentation */
break;
case 0x02: /* CEA-EXT: CEA 861 Series Extension */
block_fmt = &edid_cea_ext_fmt[0];
break;
case 0x10: /* VTB-EXT: Video Timing Block Ext */
block_fmt = &edid_vtb_ext_fmt[0];
break;
case 0x40: /* DI-EXT: Display Info Extension */
block_fmt = &edid_di_ext_fmt[0];
break;
case 0x50: /* LS-EXT: Localized String Extension */
block_fmt = &edid_ls_ext_fmt[0];
break;
case 0x60: /* DPVL-EXT: Digital Packet Video Link */
block_fmt = &edid_dpvl_ext_fmt[0];
break;
case 0xF0: /* EXTENSION Block Map 1 or 2 */
if (block_num == 1) {
block_fmt = &edid_map1_ext_fmt[0];
} else
if (block_num == 128) {
block_fmt = &edid_map2_ext_fmt[0];
}
/* Reject Block Maps at other locations */
break;
case 0xFF: /* EXTENSIONS by display manufacturer */
block_fmt = &edid_mfg_ext_fmt[0];
break;
}
}
/*
* Display the EDID data block
*/
if (block_num > 0) {
}
/*
*/
} else {
/*
* Display a valid EDID block parsed or parsed & raw
*/
}
block_num += 1;
}
} /* fbc_predid() */
/* End of fbc_predid.c */