root/i2c-tools/trunk/eeprom/decode-edid

Revision 5164, 6.0 kB (checked in by khali, 8 months ago)

Update the FSF address.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
4 #
5 #    This program is free software; you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published by
7 #    the Free Software Foundation; either version 2 of the License, or
8 #    (at your option) any later version.
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program; if not, write to the Free Software
17 #    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 #    MA 02110-1301 USA.
19 #
20 # Version 0.1  2003-07-17  Jean Delvare <khali@linux-fr.org>
21 # Version 0.2  2003-07-22  Jean Delvare <khali@linux-fr.org>
22 #  Use print instead of syswrite.
23 # Version 0.3  2003-08-24  Jean Delvare <khali@linux-fr.org>
24 #  Fix data block length (128 bytes instead of 256).
25 # Version 1.0  2004-02-08  Jean Delvare <khali@linux-fr.org>
26 #  Added support for Linux 2.5/2.6 (i.e. sysfs).
27 # Version 1.1  2006-09-01  Jean Delvare <khali@linux-fr.org>
28 #  Append /usr/sbin or /usr/local/sbin to $PATH if needed.
29 #
30 # EEPROM data decoding for EDID. EDID (Extended Display Identification
31 # Data) is a VESA standard which allows storing (on manufacturer's side)
32 # and retrieving (on user's side) of configuration information about
33 # displays, such as manufacturer, serial number, physical dimensions and
34 # allowed horizontal and vertical refresh rates.
35 #
36 # Using the eeprom kernel driver, you have two possibilities to
37 # make use of these data:
38 #  1* The ddcmon script.
39 #  2* This script.
40 # Both solutions will return a different kind of information. The first
41 # method will report user-interesting information, such as the model number
42 # or the year of manufacturing. The second method will report video-card-
43 # interesting information, such as video modes and refresh rates.
44 #
45 # Note that this script does almost nothing by itself. It simply converts
46 # what it finds in /proc to binary data to feed the parse-edid program.
47 # The parse-edid program was written by John Fremlin and is available at
48 # the following address:
49 #   http://john.fremlin.de/programs/linux/read-edid/
50
51 use strict;
52 use Fcntl qw(:DEFAULT :seek);
53 use vars qw($bus $address);
54 use constant PROCFS => 1;
55 use constant SYSFS  => 2;
56
57 # parse-edid will typically be installed in /usr/sbin or /usr/local/sbin
58 # even though regular users can run it
59 $ENV{PATH} .= ':/usr/local/sbin'
60         if $ENV{PATH} !~ m,(^|:)/usr/local/sbin/?(:|$),
61         && -x '/usr/local/sbin/parse-edid';
62 $ENV{PATH} .= ':/usr/sbin'
63         if $ENV{PATH} !~ m,(^|:)/usr/sbin/?(:|$),
64         && -x '/usr/sbin/parse-edid';
65
66 sub edid_valid_procfs
67 {
68         my ($bus, $addr) = @_;
69
70         open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/00";
71         my $line = <EEDATA>;
72         close EEDATA;
73         return 1
74                 if $line =~ m/^0 255 255 255 255 255 255 0 /;
75         return 0;
76 }
77
78 # Only used for sysfs
79 sub rawread
80 {
81         my ($filename, $length, $offset) = @_;
82         my $bytes = '';
83        
84         sysopen(FH, $filename, O_RDONLY)
85                 or die "Can't open $filename";
86         if ($offset)
87         {
88                 sysseek(FH, $offset, SEEK_SET)
89                         or die "Can't seek in $filename";
90         }
91
92         $offset = 0;
93         while ($length)
94         {
95                 my $r = sysread(FH, $bytes, $length, $offset);
96                 die "Can't read $filename"
97                         unless defined($r);
98                 die "Unexpected EOF in $filename"
99                         unless $r;
100                 $offset += $r;
101                 $length -= $r;
102         }
103         close(FH);
104
105         return $bytes;
106 }
107
108 sub edid_valid_sysfs
109 {
110         my ($bus, $addr) = @_;
111         my $bytes = rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 8, 0);
112
113         return 1
114                 if $bytes eq "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00";
115         return 0;
116 }
117
118 sub bus_detect
119 {
120         my $max = shift;
121
122         for (my $i=0; $i<$max; $i++)
123         {
124                 if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-50/00")
125                 {
126                         if (edid_valid_procfs($i, '50'))
127                         {
128                                 print STDERR
129                                         "decode-edid: using bus $i (autodetected)\n";
130                                 return $i;
131                         }
132                 }
133                 elsif (-r "/sys/bus/i2c/devices/$i-0050/eeprom")
134                 {
135                         if (edid_valid_sysfs($i, '50'))
136                         {
137                                 print STDERR
138                                         "decode-edid: using bus $i (autodetected)\n";
139                                 return $i;
140                         }
141                 }       
142         }
143        
144         return; # default
145 }
146
147 sub edid_decode
148 {
149         my ($bus, $addr, $mode) = @_;
150
151         # Make sure it is an EDID EEPROM.
152
153         unless (($mode == PROCFS && edid_valid_procfs ($bus, $addr))
154              || ($mode == SYSFS  && edid_valid_sysfs  ($bus, $addr)))
155         {
156                 print STDERR
157                         "decode-edid: not an EDID EEPROM at $bus-$addr\n";
158                 return;
159         }
160
161         $SIG{__WARN__} = sub { };
162         open PIPE, "| parse-edid"
163                 or die "Can't open parse-edid. Please install read-edid.\n";
164         delete $SIG{__WARN__};
165         binmode PIPE;
166        
167         if ($mode == PROCFS)
168         {
169                 for (my $i=0; $i<=0x70; $i+=0x10)
170                 {
171                         my $file = sprintf '%02x', $i;
172                         my $output = '';
173                         open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file"
174                                 or die "Can't read /proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file";
175                         while(<EEDATA>)
176                         {
177                                 foreach my $item (split)
178                                 {
179                                         $output .= pack "C", $item;
180                                 }
181                         }
182                         close EEDATA;
183                         print PIPE $output;
184                 }
185         }
186         elsif ($mode == SYSFS)
187         {
188                 print PIPE rawread("/sys/bus/i2c/devices/$bus-00$address/eeprom", 128, 0);
189         }
190
191         close PIPE;
192 }
193
194 # Get the address. Default to 0x50 if not given.
195 $address = $ARGV[1] || 0x50;
196 # Convert to decimal, whatever the value.
197 $address = oct $address if $address =~ m/^0/;
198 # Convert to an hexadecimal string.
199 $address = sprintf '%02x', $address;
200
201 # Get the bus. Try to autodetect if not given.
202 $bus = $ARGV[0] if defined $ARGV[0];
203 $bus = bus_detect(8) unless defined $bus;
204
205 if(defined $bus)
206 {
207         print STDERR
208                 "decode-edid: decode-edid version 1.1\n";
209         if (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address")
210         {
211                 edid_decode ($bus, $address, PROCFS);
212                 exit 0;
213         }
214         elsif (-r "/sys/bus/i2c/devices/$bus-00$address")
215         {
216                 edid_decode ($bus, $address, SYSFS);
217                 exit 0;
218         }
219 }
220
221 print STDERR
222         "EDID EEPROM not found.  Please make sure that the eeprom module is loaded.\n";
223 print STDERR
224         "Maybe your EDID EEPROM is on another bus.  Try \"decode-edid ".($bus+1)."\".\n"
225         if defined $bus;
Note: See TracBrowser for help on using the browser.