| #!/usr/bin/perl -w | |
| # | |
| # Copyright (C) 2002-2008 Jean Delvare <jdelvare@suse.de> | |
| # | |
| # This program is free software; you can redistribute it and/or modify | |
| # it under the terms of the GNU General Public License as published by | |
| # the Free Software Foundation; either version 2 of the License, or | |
| # (at your option) any later version. | |
| # | |
| # This program is distributed in the hope that it will be useful, | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| # GNU General Public License for more details. | |
| # | |
| # You should have received a copy of the GNU General Public License | |
| # along with this program; if not, write to the Free Software | |
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
| # MA 02110-1301 USA. | |
| # | |
| # EEPROM data decoding for Sony Vaio laptops. | |
| # | |
| # The eeprom driver must be loaded. For kernels older than 2.6.0, the | |
| # eeprom driver can be found in the lm-sensors package. | |
| # | |
| # Please note that this is a guess-only work. Sony support refused to help | |
| # me, so if someone can provide information, please contact me. | |
| # My knowledge is summarized on this page: | |
| # http://jdelvare.nerim.net/articles/vaio/eeprom.html | |
| # | |
| # It seems that if present, the EEPROM is always at 0x57. | |
| # | |
| # Models tested so far: | |
| # PCG-F403 : No EEPROM | |
| # PCG-F707 : No EEPROM | |
| # PCG-GR114EK : OK | |
| # PCG-GR114SK : OK | |
| # PCG-GR214EP : OK | |
| # PCG-GRT955MP : OK | |
| # PCG-GRX316G : OK | |
| # PCG-GRX570 : OK | |
| # PCG-GRX600K : OK | |
| # PCG-U1 : OK | |
| # PCG-Z600LEK : No EEPROM | |
| # PCG-Z600NE : No EEPROM | |
| # VGN-S260 : OK | |
| # VGN-S4M/S : OK | |
| # VGN-TZ11MN/N : OK | |
| # | |
| # Thanks to Werner Heuser, Carsten Blume, Christian Gennerat, Joe Wreschnig, | |
| # Xavier Roche, Sebastien Lefevre, Lars Heer, Steve Dobson, Kent Hunt, | |
| # Timo Hoenig and others for their precious help. | |
| use strict; | |
| use Fcntl qw(:DEFAULT :seek); | |
| use vars qw($sysfs $found); | |
| use constant VERSION => "1.6"; | |
| use constant ONLYROOT => "Readable only by root"; | |
| sub print_item | |
| { | |
| my ($label,$value) = @_; | |
| printf("\%16s : \%s\n",$label,$value); | |
| } | |
| # Abstract reads so that other functions don't have to care wether | |
| # we need to use procfs or sysfs | |
| sub read_eeprom_bytes | |
| { | |
| my ($bus, $addr, $offset, $length) = @_; | |
| my $filename; | |
| if ($sysfs) | |
| { | |
| $filename = "/sys/bus/i2c/devices/$bus-00$addr/eeprom"; | |
| sysopen(FH, $filename, O_RDONLY) | |
| or die "Can't open $filename"; | |
| sysseek(FH, $offset, SEEK_SET) | |
| or die "Can't seek in $filename"; | |
| my ($r, $bytes); | |
| $bytes = ''; | |
| $offset = 0; | |
| while($length) | |
| { | |
| $r = sysread(FH, $bytes, $length, $offset); | |
| die "Can't read $filename" | |
| unless defined($r); | |
| die "Unexpected EOF in $filename" | |
| unless $r; | |
| $offset += $r; | |
| $length -= $r; | |
| } | |
| close(FH); | |
| return $bytes; | |
| } | |
| else | |
| { | |
| my $base = $offset & 0xf0; | |
| $offset -= $base; | |
| my $values = ''; | |
| my $remains = $length + $offset; | |
| # Get all lines in a single string | |
| while ($remains > 0) | |
| { | |
| $filename = "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/" | |
| . sprintf('%02x', $base); | |
| open(FH, $filename) | |
| or die "Can't open $filename"; | |
| $values .= <FH>; | |
| close(FH); | |
| $remains -= 16; | |
| $base += 16; | |
| } | |
| # Store the useful part in an array | |
| my @bytes = split(/[ \n]/, $values); | |
| @bytes = @bytes[$offset..$offset+$length-1]; | |
| # Back to a binary string | |
| return pack('C*', @bytes); | |
| } | |
| } | |
| sub decode_string | |
| { | |
| my ($bus, $addr, $offset, $length) = @_; | |
| my $string = read_eeprom_bytes($bus, $addr, $offset, $length); | |
| $string =~ s/\x00.*$//; | |
| return($string); | |
| } | |
| sub decode_hexa | |
| { | |
| my ($bus, $addr, $offset, $length) = @_; | |
| my @bytes = unpack('C*', read_eeprom_bytes($bus, $addr, $offset, $length)); | |
| my $string=''; | |
| for(my $i=0;$i<$length;$i++) | |
| { | |
| $string.=sprintf('%02X', shift(@bytes)); | |
| } | |
| return($string); | |
| } | |
| sub decode_uuid | |
| { | |
| my ($bus,$addr,$base) = @_; | |
| my @bytes = unpack('C16', read_eeprom_bytes($bus, $addr, $base, 16)); | |
| my $string=''; | |
| for(my $i=0;$i<16;$i++) | |
| { | |
| $string.=sprintf('%02x',shift(@bytes)); | |
| if(($i==3)||($i==5)||($i==7)||($i==9)) | |
| { | |
| $string.='-'; | |
| } | |
| } | |
| if ($string eq '00000000-0000-0000-0000-000000000000') | |
| { | |
| return(ONLYROOT); | |
| } | |
| else | |
| { | |
| return($string); | |
| } | |
| } | |
| sub vaio_decode | |
| { | |
| my ($bus,$addr) = @_; | |
| my $name = decode_string($bus, $addr, 128, 32); | |
| # Simple heuristic to skip false positives | |
| return 0 unless $name =~ m/^[A-Z-]{4}/; | |
| print_item('Machine Name', $name); | |
| my $serial = decode_string($bus, $addr, 192, 32); | |
| print_item('Serial Number', $serial ? $serial : ONLYROOT); | |
| print_item('UUID', decode_uuid($bus, $addr, 16)); | |
| my $revision = decode_string($bus, $addr, 160, 10); | |
| print_item(length($revision) > 2 ? 'Service Tag' : 'Revision', | |
| $revision); | |
| print_item('Asset Tag', decode_string($bus, $addr, 170, 4). | |
| decode_hexa($bus, $addr, 174, 12)); | |
| print_item('OEM Data', decode_string($bus, $addr, 32, 16)); | |
| print_item('Timestamp', decode_string($bus, $addr, 224, 18)); | |
| return 1; | |
| } | |
| BEGIN | |
| { | |
| print("# Sony Vaio EEPROM Decoder version ".VERSION." by Jean Delvare\n\n"); | |
| } | |
| END | |
| { | |
| print("\n"); | |
| } | |
| for (my $i = 0, $found=0; $i <= 4 && !$found; $i++) | |
| { | |
| if (-r "/sys/bus/i2c/devices/$i-0057/eeprom") | |
| { | |
| $sysfs = 1; | |
| $found += vaio_decode($i, '57'); | |
| } | |
| elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57") | |
| { | |
| if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57/data0-15") | |
| { | |
| print("Deprecated old interface found. Please upgrade to lm_sensors 2.6.3 or greater."); | |
| exit; | |
| } | |
| else | |
| { | |
| $sysfs = 0; | |
| $found += vaio_decode($i, '57'); | |
| } | |
| } | |
| } | |
| if (!$found) | |
| { | |
| print("Vaio EEPROM not found. Please make sure that the eeprom module is loaded.\n"); | |
| } |