After some more hacking in DSDT, I found that fan control is located in ACPI EC (embedded controller) address space : VTMP acpi byte in acpi EC bit field, at offest 0x5E.
If found some similar concerns on some acer laptops (having the same WMI related acpi methods, located in device AMW0), with a perl script that I was able to modify in order to setup a constant fan speed...
Here is the script, for 8.04 to 10.04 LTS users that found this issue and that have not already burned their GPU:
file: tosh_p100_ec.pl
***
#!/usr/bin/perl -w
# Version 1.0 (2010-05-27)
#
# *************************************************
# ** Toshiba P100 series GPU fan setup for Linux **
# ** Must be called in init/resume scripts **
# ** This bypass the need for custom ACPI kernel **
# ** no more possible in latest distros... **
# *************************************************
#
# Machines used for test (successful users, please update):
# - p100-114, PSPA3E, bios 4.80
# - ...
#
# Copyright (C) 2010 YL ; adapted from acer_ec.pl (0.6.1) by these authors:
#
# Copyright (C) 2007 Michael Kurz michi.kurz (at) googlemail.com
# Copyright (C) 2007 Petr Tomasek tomasek (#) etf,cuni,cz
# Copyright (C) 2007 Carlos Corbacho cathectic (at) gmail.com
#
# 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 3
# 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.
require 5.004;
use strict;
use Fcntl;
use POSIX;
use File::Basename;
sub initialize_ioports
{
sysopen (IOPORTS, "/dev/port", O_RDWR)
or die "/dev/port: $!\n";
binmode IOPORTS;
}
sub close_ioports
{
close (IOPORTS)
or print "Warning: $!\n";
}
sub inb
{
my ($res,$nrchars);
sysseek IOPORTS, $_[0], 0 or return -1;
$nrchars = sysread IOPORTS, $res, 1;
return -1 if not defined $nrchars or $nrchars != 1;
$res = unpack "C",$res ;
return $res;
}
# $_[0]: value to write
# $_[1]: port to write
# Returns: -1 on failure, 0 on success.
sub outb
{
if ($_[0] > 0xff)
{
my ($package, $filename, $line, $sub) = caller(1);
print "\n*** Called outb with value=$_[1] from line $line\n",
"*** (in $sub). PLEASE REPORT!\n",
"*** Terminating.\n";
exit(-1);
}
my $towrite = pack "C", $_[0];
sysseek IOPORTS, $_[1], 0 or return -1;
my $nrchars = syswrite IOPORTS, $towrite, 1;
return -1 if not defined $nrchars or $nrchars != 1;
return 0;
}
sub wait_write
{
my $i = 0;
while ((inb($_[0]) & 0x02) && ($i < 10000)) {
sleep(0.01);
$i++;
}
return -($i == 10000);
}
sub wait_read
{
my $i = 0;
while (!(inb($_[0]) & 0x01) && ($i < 10000)) {
sleep(0.01);
$i++;
}
return -($i == 10000);
}
sub wait_write_ec
{
wait_write(0x66);
}
sub wait_read_ec
{
wait_read(0x66);
}
sub send_ec
{
if (!wait_write_ec()) { outb($_[0], 0x66); }
if (!wait_write_ec()) { outb($_[1], 0x62); }
}
sub write_ec
{
if (!wait_write_ec()) { outb(0x81, 0x66 ); }
if (!wait_write_ec()) { outb($_[0], 0x62); }
if (!wait_write_ec()) { outb($_[1], 0x62); }
}
sub read_ec
{
if (!wait_write_ec()) { outb(0x80, 0x66 ); }
if (!wait_write_ec()) { outb($_[0], 0x62); }
if (!wait_read_ec()) { inb(0x62); }
}
sub print_regs
{
initialize_ioports();
my @arr = ("00","10","20","30","40","50","60","70","80","90","A0","B0","C0","D0","E0","F0", "");
if (!$ARGV[0]){
print "wrong arguments!\n";
print "usage:\n";
print "\'tosh_p100_ec regs\' \t\t\t\tdumps all ec registers\n";
print "\'tosh_p100_ec set_gpu_fan_med\' \t\t\tinit GPU fan medium speed\n";
print "\'tosh_p100_ec set_gpu_fan_hig\' \t\t\tinit GPU fan high speed\n";
} elsif ($ARGV[0] eq "regs") {
print_regs();
} elsif ($ARGV[0] eq "set_gpu_fan_med") {
# Set VTMP for GPU fan, medium speed : Bios 2.4 pre-Vista hack value
initialize_ioports();
write_ec(0x5e, 0x3c);
close_ioports();
} elsif ($ARGV[0] eq "set_gpu_fan_hig") {
# Set VTMP for GPU fan, highest speed (some higher values seems not always reversible)
initialize_ioports();
write_ec(0x5e, 0x4c);
close_ioports();
} else {
print "wrong arguments!\n";
}
***
Just save this file, make it executable (chmod +x tosh_p100_ec.pl) and try:
sudo ./tosh_p100_ec.pl set_gpu_fan_med
sudo ./tosh_p100_ec.pl set_gpu_fan_hig
sudo ./tosh_p100_ec.pl set_gpu_fan_med
You should hear fan speed variations...
Setup this script for init/resume, I could not do so because I'm currently trying openSuse after this DSDT patch issue...
After some more hacking in DSDT, I found that fan control is located in ACPI EC (embedded controller) address space : VTMP acpi byte in acpi EC bit field, at offest 0x5E.
If found some similar concerns on some acer laptops (having the same WMI related acpi methods, located in device AMW0), with a perl script that I was able to modify in order to setup a constant fan speed...
Here is the script, for 8.04 to 10.04 LTS users that found this issue and that have not already burned their GPU:
file: tosh_p100_ec.pl
***
#!/usr/bin/perl -w
# Version 1.0 (2010-05-27) ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******
#
# *******
# ** Toshiba P100 series GPU fan setup for Linux **
# ** Must be called in init/resume scripts **
# ** This bypass the need for custom ACPI kernel **
# ** no more possible in latest distros... **
# *******
#
# Machines used for test (successful users, please update):
# - p100-114, PSPA3E, bios 4.80
# - ...
#
# Copyright (C) 2010 YL ; adapted from acer_ec.pl (0.6.1) by these authors:
#
# Copyright (C) 2007 Michael Kurz michi.kurz (at) googlemail.com
# Copyright (C) 2007 Petr Tomasek tomasek (#) etf,cuni,cz
# Copyright (C) 2007 Carlos Corbacho cathectic (at) gmail.com
#
# 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 3
# 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.
require 5.004;
use strict;
use Fcntl;
use POSIX;
use File::Basename;
sub initialize_ioports
{
sysopen (IOPORTS, "/dev/port", O_RDWR)
or die "/dev/port: $!\n";
binmode IOPORTS;
}
sub close_ioports
{
close (IOPORTS)
or print "Warning: $!\n";
}
sub inb
{
my ($res,$nrchars);
sysseek IOPORTS, $_[0], 0 or return -1;
$nrchars = sysread IOPORTS, $res, 1;
return -1 if not defined $nrchars or $nrchars != 1;
$res = unpack "C",$res ;
return $res;
}
# $_[0]: value to write
# $_[1]: port to write
# Returns: -1 on failure, 0 on success.
sub outb
{
if ($_[0] > 0xff)
{
my ($package, $filename, $line, $sub) = caller(1);
print "\n*** Called outb with value=$_[1] from line $line\n",
"*** (in $sub). PLEASE REPORT!\n",
"*** Terminating.\n";
exit(-1);
}
my $towrite = pack "C", $_[0];
sysseek IOPORTS, $_[1], 0 or return -1;
my $nrchars = syswrite IOPORTS, $towrite, 1;
return -1 if not defined $nrchars or $nrchars != 1;
return 0;
}
sub wait_write
{
my $i = 0;
while ((inb($_[0]) & 0x02) && ($i < 10000)) {
sleep(0.01);
$i++;
}
return -($i == 10000);
}
sub wait_read
{
my $i = 0;
while (!(inb($_[0]) & 0x01) && ($i < 10000)) {
sleep(0.01);
$i++;
}
return -($i == 10000);
}
sub wait_write_ec
{
wait_write(0x66);
}
sub wait_read_ec
{
wait_read(0x66);
}
sub send_ec
{
if (!wait_write_ec()) { outb($_[0], 0x66); }
if (!wait_write_ec()) { outb($_[1], 0x62); }
}
sub write_ec
{
if (!wait_write_ec()) { outb(0x81, 0x66 ); }
if (!wait_write_ec()) { outb($_[0], 0x62); }
if (!wait_write_ec()) { outb($_[1], 0x62); }
}
sub read_ec
{
if (!wait_write_ec()) { outb(0x80, 0x66 ); }
if (!wait_write_ec()) { outb($_[0], 0x62); }
if (!wait_read_ec()) { inb(0x62); }
}
sub print_regs ioports( );
{
initialize_
my @arr = ("00"," 10","20" ,"30"," 40","50" ,"60"," 70","80" ,"90"," A0","B0" ,"C0"," D0","E0" ,"F0", "");
my $i = 0; t02\t03\ t04\t05\ t06\t07\ t|\t08\ t09\t0A\ t0B\t0C\ t0D\t0E\ t0F\n"; _\t__\t_ _\t__\t_ _\t__\t_ _\t|\t_ _\t__\t_ _\t__\t_ _\t__\t_ _\t__\n" ;
my $t = 0;
print "\n \t00\t01\
print " \t__\t_
print "00 |\t";
for ($i = 0; $i < 256; $i++)
{
$t = read_ec($i);
print $t;
print "\t";
if ((($i + 1) % 8) == 0){
if ((($i + 1) % 16) == 0) {
if ($i != 255) { print "\n$arr[(($i-(($i + 1) % 16)) / 16) + 1] |\t"; }
} else {
print "|\t";
}
}
}
print "\n";
close_ioports();
}
if (!$ARGV[0]){ ioports( ); ioports( );
print "wrong arguments!\n";
print "usage:\n";
print "\'tosh_p100_ec regs\' \t\t\t\tdumps all ec registers\n";
print "\'tosh_p100_ec set_gpu_fan_med\' \t\t\tinit GPU fan medium speed\n";
print "\'tosh_p100_ec set_gpu_fan_hig\' \t\t\tinit GPU fan high speed\n";
} elsif ($ARGV[0] eq "regs") {
print_regs();
} elsif ($ARGV[0] eq "set_gpu_fan_med") {
# Set VTMP for GPU fan, medium speed : Bios 2.4 pre-Vista hack value
initialize_
write_ec(0x5e, 0x3c);
close_ioports();
} elsif ($ARGV[0] eq "set_gpu_fan_hig") {
# Set VTMP for GPU fan, highest speed (some higher values seems not always reversible)
initialize_
write_ec(0x5e, 0x4c);
close_ioports();
} else {
print "wrong arguments!\n";
}
***
Just save this file, make it executable (chmod +x tosh_p100_ec.pl) and try:
sudo ./tosh_p100_ec.pl set_gpu_fan_med
sudo ./tosh_p100_ec.pl set_gpu_fan_hig
sudo ./tosh_p100_ec.pl set_gpu_fan_med
You should hear fan speed variations...
Setup this script for init/resume, I could not do so because I'm currently trying openSuse after this DSDT patch issue...