From c690719e9067f6bb1c4321c471a8f300d5f88a93 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sat, 2 Jan 2010 10:20:09 +0000 Subject: monitor-parse-edid: add support for Detailed Timing Descriptors in CEA EDID Timing Extension --- NEWS | 2 ++ monitor-parse-edid | 69 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 193e5ab..3134111 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ - monitor-parse-edid: o print EDID version and the number of EDID extension blocks o accept EDID data with multiple extension blocks + o add support for Detailed Timing Descriptors in CEA EDID Timing + Extension Version 2.5 - 18 October 2009, by Anssi Hannula diff --git a/monitor-parse-edid b/monitor-parse-edid index 68fb32b..b8f3515 100755 --- a/monitor-parse-edid +++ b/monitor-parse-edid @@ -153,6 +153,16 @@ my %subfields = ( 8 => 'vertical_blanking_max', 8 => 'module_revision', ) ], + + cea_data_block_collection => [ group_by2( + 3 => 'type', + 5 => 'size', + ) ], + + cea_video_data_block => [ group_by2( + 1 => 'native', + 7 => 'mode', + ) ], ); sub within_limit { @@ -190,11 +200,26 @@ sub check_parsed_edid { ''; } +sub build_detailed_timing { + my ($pixel_clock, $vv) = @_; + + my $h = get_many_bits($vv, 'detailed_timing'); + $h->{pixel_clock} = $pixel_clock / 100; # to have it in MHz + my %detailed_timing_field_size = map { $_->[1], $_->[0] } @{$subfields{detailed_timing}}; + foreach my $field (keys %detailed_timing_field_size) { + $field =~ s/_hi$// or next; + my $hi = delete($h->{$field . '_hi'}); + $h->{$field} += $hi << $detailed_timing_field_size{$field}; + } + $h; +} + sub parse_edid { my ($raw_edid, $verbose) = @_; my %edid; - my @vals = unpack(join('', map { $_->[0] } @edid_info), $raw_edid); + my ($main_edid, @eedid_blocks) = unpack("a128" x (length($raw_edid) / 128), $raw_edid); + my @vals = unpack(join('', map { $_->[0] } @edid_info), $main_edid); my $i; foreach (@edid_info) { my ($field, $v) = ($_->[1], $vals[$i++]); @@ -237,15 +262,7 @@ sub parse_edid { if ($pixel_clock) { # detailed timing - my $h = get_many_bits($vv, 'detailed_timing'); - $h->{pixel_clock} = $pixel_clock / 100; # to have it in MHz - - my %detailed_timing_field_size = map { $_->[1], $_->[0] } @{$subfields{detailed_timing}}; - foreach my $field (keys %detailed_timing_field_size) { - $field =~ s/_hi$// or next; - my $hi = delete($h->{$field . '_hi'}); - $h->{$field} += $hi << $detailed_timing_field_size{$field}; - } + my $h = build_detailed_timing($pixel_clock, $vv); push @{$edid{detailed_timings}}, $h if $h->{horizontal_active} > 0 && $h->{vertical_active} > 0; } else { @@ -307,6 +324,38 @@ sub parse_edid { $edid{$field} = $v if $field && $field !~ /^_/; } + foreach (@eedid_blocks) { + my ($tag, $v) = unpack("C a*", $_); + + if ($tag == 0x02) { # CEA EDID + my $dtd_offset; + ($dtd_offset, $v) = unpack("x C x a*", $v); + + next if $dtd_offset < 4; + $dtd_offset -= 4; + + while ($dtd_offset > 0) { + my $h = get_many_bits($v, 'cea_data_block_collection'); + $dtd_offset -= $h->{size} + 1; + + $v = unpack("x x$h->{size} a*", $v); + if ($h->{type} == 0x02) { # Video Data Block + $verbose && warn "video data block not handled\n"; + } + } + + while (length($v) >= 18) { + (my $pixel_clock, my $vv, $v) = unpack("v a16 a*", $v); + last if !$pixel_clock; + my $h = build_detailed_timing($pixel_clock, $vv); + push @{$edid{detailed_timings}}, $h + if $h->{horizontal_active} > 0 && $h->{vertical_active} > 0; + } + } else { + $verbose && warn "parse_edid: unknown tag $tag\n"; + } + } + $edid{max_size_precision} = 'cm'; $edid{EISA_ID} = $edid{manufacturer_name} . sprintf('%04x', $edid{product_code}) if $edid{product_code}; -- cgit v1.2.1