| 1 | #!/usr/bin/perl -w |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2002-2007 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 2002-02-06 Jean Delvare <khali@linux-fr.org> |
|---|
| 21 | # Version 0.2 2002-02-16 Jean Delvare <khali@linux-fr.org> |
|---|
| 22 | # Fixed to work with the new, simplified /proc interface names of the eeprom |
|---|
| 23 | # driver (lm_sensors 2.6.3 and greater). |
|---|
| 24 | # Shifted data display by 4 columns left. |
|---|
| 25 | # Version 0.3 2002-02-17 Jean Delvare <khali@linux-fr.org> |
|---|
| 26 | # Added UUID field at 0x10 (added decode_uuid). |
|---|
| 27 | # Merged decode_string and decode_string32. |
|---|
| 28 | # Added unknown field at 0x20. |
|---|
| 29 | # Moved header and footer to BEGIN and END, respectively. |
|---|
| 30 | # Reformated history to match those of the other decode scripts. |
|---|
| 31 | # Deleted decode_char (made useless by decode_string). |
|---|
| 32 | # Reordered field display, changed some labels. |
|---|
| 33 | # Added old /proc interface check. |
|---|
| 34 | # Version 1.0 2002-11-15 Jean Delvare <khali@linux-fr.org> |
|---|
| 35 | # Gave the label "OEM Data" to the field at 0x20. |
|---|
| 36 | # Gave the label "Timestamp" to the field at 0xE0. |
|---|
| 37 | # Renamed "Model Number" to "Model Name". |
|---|
| 38 | # Added some documentation. |
|---|
| 39 | # Version 1.1 2004-01-17 Jean Delvare <khali@linux-fr.org> |
|---|
| 40 | # Added support for Linux 2.5/2.6 (i.e. sysfs). |
|---|
| 41 | # Version 1.2 2004-11-28 Jean Delvare <khali@linux-fr.org> |
|---|
| 42 | # Support bus number 0 to 4 instead of only 0. |
|---|
| 43 | # Version 1.3 2005-01-18 Jean Delvare <khali@linux-fr.org> |
|---|
| 44 | # Revision might be a Service Tag. |
|---|
| 45 | # Version 1.4 2006-09-20 Jean Delvare <khali@linux-fr.org> |
|---|
| 46 | # Detect and skip false positives (e.g. EDID EEPROMs). |
|---|
| 47 | # Version 1.5 2007-11-19 Jean Delvare <khali@linux-fr.org> |
|---|
| 48 | # UUID and serial number might be hidden |
|---|
| 49 | # The model name is actually the first half of the asset tag |
|---|
| 50 | # The timestamp is only 18-byte long |
|---|
| 51 | # |
|---|
| 52 | # EEPROM data decoding for Sony Vaio laptops. |
|---|
| 53 | # |
|---|
| 54 | # The eeprom driver must be loaded. For kernels older than 2.6.0, the |
|---|
| 55 | # eeprom driver can be found in the lm-sensors package. |
|---|
| 56 | # |
|---|
| 57 | # Please note that this is a guess-only work. Sony support refused to help |
|---|
| 58 | # me, so if someone can provide information, please contact me. |
|---|
| 59 | # My knowledge is summarized on this page: |
|---|
| 60 | # http://khali.linux-fr.org/vaio/eeprom.html |
|---|
| 61 | # |
|---|
| 62 | # It seems that if present, the EEPROM is always at 0x57. |
|---|
| 63 | # |
|---|
| 64 | # Models tested so far: |
|---|
| 65 | # PCG-F403 : No EEPROM |
|---|
| 66 | # PCG-F707 : No EEPROM |
|---|
| 67 | # PCG-GR114EK : OK |
|---|
| 68 | # PCG-GR114SK : OK |
|---|
| 69 | # PCG-GR214EP : OK |
|---|
| 70 | # PCG-GRT955MP : OK |
|---|
| 71 | # PCG-GRX316G : OK |
|---|
| 72 | # PCG-GRX570 : OK |
|---|
| 73 | # PCG-GRX600K : OK |
|---|
| 74 | # PCG-U1 : OK |
|---|
| 75 | # PCG-Z600LEK : No EEPROM |
|---|
| 76 | # PCG-Z600NE : No EEPROM |
|---|
| 77 | # VGN-S260 : OK |
|---|
| 78 | # VGN-S4M/S : OK |
|---|
| 79 | # VGN-TZ11MN/N : OK |
|---|
| 80 | # Any feedback appreciated anyway. |
|---|
| 81 | # |
|---|
| 82 | # Thanks to Werner Heuser, Carsten Blume, Christian Gennerat, Joe Wreschnig, |
|---|
| 83 | # Xavier Roche, Sebastien Lefevre, Lars Heer, Steve Dobson, Kent Hunt, |
|---|
| 84 | # Timo Hoenig and others for their precious help. |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | use strict; |
|---|
| 88 | use Fcntl qw(:DEFAULT :seek); |
|---|
| 89 | use vars qw($sysfs $found); |
|---|
| 90 | |
|---|
| 91 | use constant ONLYROOT => "Readable only by root"; |
|---|
| 92 | |
|---|
| 93 | sub print_item |
|---|
| 94 | { |
|---|
| 95 | my ($label,$value) = @_; |
|---|
| 96 | |
|---|
| 97 | printf("\%16s : \%s\n",$label,$value); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | # Abstract reads so that other functions don't have to care wether |
|---|
| 101 | # we need to use procfs or sysfs |
|---|
| 102 | sub read_eeprom_bytes |
|---|
| 103 | { |
|---|
| 104 | my ($bus, $addr, $offset, $length) = @_; |
|---|
| 105 | my $filename; |
|---|
| 106 | |
|---|
| 107 | if ($sysfs) |
|---|
| 108 | { |
|---|
| 109 | $filename = "/sys/bus/i2c/devices/$bus-00$addr/eeprom"; |
|---|
| 110 | sysopen(FH, $filename, O_RDONLY) |
|---|
| 111 | or die "Can't open $filename"; |
|---|
| 112 | sysseek(FH, $offset, SEEK_SET) |
|---|
| 113 | or die "Can't seek in $filename"; |
|---|
| 114 | |
|---|
| 115 | my ($r, $bytes); |
|---|
| 116 | $bytes = ''; |
|---|
| 117 | $offset = 0; |
|---|
| 118 | while($length) |
|---|
| 119 | { |
|---|
| 120 | $r = sysread(FH, $bytes, $length, $offset); |
|---|
| 121 | die "Can't read $filename" |
|---|
| 122 | unless defined($r); |
|---|
| 123 | die "Unexpected EOF in $filename" |
|---|
| 124 | unless $r; |
|---|
| 125 | $offset += $r; |
|---|
| 126 | $length -= $r; |
|---|
| 127 | } |
|---|
| 128 | close(FH); |
|---|
| 129 | |
|---|
| 130 | return $bytes; |
|---|
| 131 | } |
|---|
| 132 | else |
|---|
| 133 | { |
|---|
| 134 | my $base = $offset & 0xf0; |
|---|
| 135 | $offset -= $base; |
|---|
| 136 | my $values = ''; |
|---|
| 137 | my $remains = $length + $offset; |
|---|
| 138 | |
|---|
| 139 | # Get all lines in a single string |
|---|
| 140 | while ($remains > 0) |
|---|
| 141 | { |
|---|
| 142 | $filename = "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/" |
|---|
| 143 | . sprintf('%02x', $base); |
|---|
| 144 | open(FH, $filename) |
|---|
| 145 | or die "Can't open $filename"; |
|---|
| 146 | $values .= <FH>; |
|---|
| 147 | close(FH); |
|---|
| 148 | $remains -= 16; |
|---|
| 149 | $base += 16; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | # Store the useful part in an array |
|---|
| 153 | my @bytes = split(/[ \n]/, $values); |
|---|
| 154 | @bytes = @bytes[$offset..$offset+$length-1]; |
|---|
| 155 | |
|---|
| 156 | # Back to a binary string |
|---|
| 157 | return pack('C*', @bytes); |
|---|
| 158 | } |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | sub decode_string |
|---|
| 162 | { |
|---|
| 163 | my ($bus, $addr, $offset, $length) = @_; |
|---|
| 164 | |
|---|
| 165 | my $string = read_eeprom_bytes($bus, $addr, $offset, $length); |
|---|
| 166 | $string =~ s/\x00.*$//; |
|---|
| 167 | |
|---|
| 168 | return($string); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | sub decode_hexa |
|---|
| 172 | { |
|---|
| 173 | my ($bus, $addr, $offset, $length) = @_; |
|---|
| 174 | |
|---|
| 175 | my @bytes = unpack('C*', read_eeprom_bytes($bus, $addr, $offset, $length)); |
|---|
| 176 | my $string=''; |
|---|
| 177 | |
|---|
| 178 | for(my $i=0;$i<$length;$i++) |
|---|
| 179 | { |
|---|
| 180 | $string.=sprintf('%02X', shift(@bytes)); |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | return($string); |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | sub decode_uuid |
|---|
| 187 | { |
|---|
| 188 | my ($bus,$addr,$base) = @_; |
|---|
| 189 | |
|---|
| 190 | my @bytes = unpack('C16', read_eeprom_bytes($bus, $addr, $base, 16)); |
|---|
| 191 | my $string=''; |
|---|
| 192 | |
|---|
| 193 | for(my $i=0;$i<16;$i++) |
|---|
| 194 | { |
|---|
| 195 | $string.=sprintf('%02x',shift(@bytes)); |
|---|
| 196 | if(($i==3)||($i==5)||($i==7)||($i==9)) |
|---|
| 197 | { |
|---|
| 198 | $string.='-'; |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | if ($string eq '00000000-0000-0000-0000-000000000000') |
|---|
| 203 | { |
|---|
| 204 | return(ONLYROOT); |
|---|
| 205 | } |
|---|
| 206 | else |
|---|
| 207 | { |
|---|
| 208 | return($string); |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | sub vaio_decode |
|---|
| 213 | { |
|---|
| 214 | my ($bus,$addr) = @_; |
|---|
| 215 | |
|---|
| 216 | my $name = decode_string($bus, $addr, 128, 32); |
|---|
| 217 | # Simple heuristic to skip false positives |
|---|
| 218 | return 0 unless $name =~ m/^[A-Z-]{4}/; |
|---|
| 219 | |
|---|
| 220 | print_item('Machine Name', $name); |
|---|
| 221 | my $serial = decode_string($bus, $addr, 192, 32); |
|---|
| 222 | print_item('Serial Number', $serial ? $serial : ONLYROOT); |
|---|
| 223 | print_item('UUID', decode_uuid($bus, $addr, 16)); |
|---|
| 224 | my $revision = decode_string($bus, $addr, 160, 10); |
|---|
| 225 | print_item(length($revision) > 2 ? 'Service Tag' : 'Revision', |
|---|
| 226 | $revision); |
|---|
| 227 | print_item('Asset Tag', decode_string($bus, $addr, 170, 4). |
|---|
| 228 | decode_hexa($bus, $addr, 174, 12)); |
|---|
| 229 | print_item('OEM Data', decode_string($bus, $addr, 32, 16)); |
|---|
| 230 | print_item('Timestamp', decode_string($bus, $addr, 224, 18)); |
|---|
| 231 | return 1; |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | BEGIN |
|---|
| 235 | { |
|---|
| 236 | print("Sony Vaio EEPROM Decoder\n"); |
|---|
| 237 | print("Copyright (C) 2002-2007 Jean Delvare\n"); |
|---|
| 238 | print("Version 1.5\n\n"); |
|---|
| 239 | } |
|---|
| 240 | |
|---|
| 241 | END |
|---|
| 242 | { |
|---|
| 243 | print("\n"); |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | for (my $i = 0, $found=0; $i <= 4 && !$found; $i++) |
|---|
| 247 | { |
|---|
| 248 | if (-r "/sys/bus/i2c/devices/$i-0057/eeprom") |
|---|
| 249 | { |
|---|
| 250 | $sysfs = 1; |
|---|
| 251 | $found += vaio_decode($i, '57'); |
|---|
| 252 | } |
|---|
| 253 | elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57") |
|---|
| 254 | { |
|---|
| 255 | if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57/data0-15") |
|---|
| 256 | { |
|---|
| 257 | print("Deprecated old interface found. Please upgrade to lm_sensors 2.6.3 or greater."); |
|---|
| 258 | exit; |
|---|
| 259 | } |
|---|
| 260 | else |
|---|
| 261 | { |
|---|
| 262 | $sysfs = 0; |
|---|
| 263 | $found += vaio_decode($i, '57'); |
|---|
| 264 | } |
|---|
| 265 | } |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | if (!$found) |
|---|
| 269 | { |
|---|
| 270 | print("Vaio EEPROM not found. Please make sure that the eeprom module is loaded.\n"); |
|---|
| 271 | print("If you believe this is an error, please contact me <khali\@linux-fr.org>\n"); |
|---|
| 272 | print("so that we may see how to fix the problem.\n"); |
|---|
| 273 | } |
|---|