Tag Archives: Ubuntu battery

Fix Toshiba battery issue for Linux

Its been a year since I made my last post and have been thinking about what I could write  to start posting again. I have finally found a perfect one. Yepieeee, Its about vexing Toshiba battery conflict with the kernel.  I have got my battery issue fixed after a long wait. First of all let me thank Steve who proposed the perfect resolution for this issue and many thanks to other people who were also part of this seeking for a resolution.

Here was the scenario.

Laptop Made : Toshiba L650 X5310

OS : Ubuntu, Centos, BackTrack Linux

Issue : None of them detects and show my battery status.

I have tried different versions of Ubutnu, distros, Kernels and none of them helped and hence raised a bug report at https://bugs.launchpad.net/ubuntu/+source/linux/+bug/703302

Surprisingly the thread got replies/responses from many people who were having the same issue and none had a clue about the fix. But reply no:16 by George Moutsopoulos helped me to find the solution.

Old Results :

[bash]efheem@tuxjockey:~$ cat /proc/acpi/battery/BAT1/*
present:                 no
present:                 no
present:                 no
efheem@tuxjockey:~$ dmesg | grep batt
[    1.370268] ACPI: Battery Slot [BAT1] (battery absent)[/bash]

The cause of issue is because Toshiba included two sets of boot data that tell the OS what hardware exists in the machine. Windows reads the correct one whereas Linux doesn’t. We will need to build our own kernel to make this happen. We will need to extract the DSDT (Differentiated System Description Table) from the machine, the ASL modified, and a new AML DSDT can be compiled. The sections below show the way to tell Linux to use this modified DSDT instead of the version that came with the BIOS.

Get the original DSDL of machine:

[bash]# cat /sys/firmware/acpi/tables/DSDT > DSDT.dat[/bash]

Disassemble it

[bash]# iasl -d DSDT.dat[/bash]

Make the changes:

[bash]# vi DSDT.dsl[/bash]

search for line : OperationRegion (EMEM, SystemMemory, 0×FF808001, 0×FF)
and replace it with : OperationRegion (EMEM, EmbeddedControl, 0×00, 0×FF)
save the file.

Build it:

[bash]# iasl -tc DSDT.dsl[/bash]

This will create a file DSDT.hex (This file is used for kernel recompilation)

I received the below two errors during this compilation

N:B :- You can actually ignore these errors, this works even having these error unfixed. But if interested you can work out to get those fixed.  Else directly goto ‘Kernel Recompilation’ section.

———————————-

[bash]DSDT.dsl  2656:                     0×00000000,         // Length
Error    4122 -                              ^ Invalid combination of Length and Min/Max fixed flags

DSDT.dsl  2663:                     0×00000000,         // Length
Error    4122 -                              ^ Invalid combination of Length and Min/Max fixed flags[/bash]

———————————-

Fix : (If you didnt receive any error please skip this part )

open DSDT.dsl file and go to the line where iasl indicated the error. In my case I go to lines 2656 and 2663.

iasl is complaining about the “Length” line “0×00000000″. This is wrong. Look at the “Range Minimum” and “Range Maximum”. Open up your Kcalc or whatever you Gnome people use and change it to Numeral System Mode. Make sure HEX is selected and now we subtract the minimun range from the maximun range and then we add 1. Since the minimum range is 0 (And you can’t subtract 0) I will input  FEAFFFFF and then add 1 which gives me FEB00000  (Don’t get confused, I’m simply omitting “0x”, the calculator doesn’t need this). I change 0×00000000 to 0xFEB00000 by Length. So now it looks like this:

0×00000000,         // Granularity
0×00000000,         // Range Minimum
0xFEAFFFFF,         // Range Maximum
0×00000000,         // Translation Offset
0xFEB00000,         // Length

Line 2663 changed to

0×00000000,    // Granularity
0xFED40000,         // Range Minimum
0xFED44FFF,         // Range Maximum
0×00000000,         // Translation Offset
0×00005000,         // Length

compile again.

Kernel Recompilation :

Install necessary packages:

[bash]apt-get install fakeroot kernel-wedge build-essential makedumpfile kernel-package libncurses5 libncurses5-dev[/bash]
[bash]apt-get build-dep –no-install-recommends linux-image-$(uname -r)[/bash]
[bash]mkdir /root/source

cd /root/source

apt-get source linux-image-$(uname -r)[/bash]

NB: My uname -r was 2.6.38.2-generic

[bash]cd linux-2.6.38[/bash]

(replace this with your kernel version)

copy kernel config file from your current kernel:

[bash]cp -vi /boot/config-`uname -r` .config[/bash]

now copy the DSDT.hex file to the include folder inside kernel source

[bash]cp DSDT.hex /root/source/linux-2.6.38/include[/bash]

open .config file we have just copied

[bash]vi /root/source/linux-2.6.38/.config[/bash]

Make the below changes

[bash]CONFIG_STANDALONE=n
CONFIG_ACPI_CUSTOM_DSDT=y
CONFIG_ACPI_CUSTOM_DSDT_FILE="DSDT.hex"[/bash]

save and quit.

My pwd : /root/source/linux-2.6.38

start compiling the Kernel:

[bash]make menuconfig[/bash]

load the .config file, save the menu file and exit.

We are about to start the compile process . A little trick you can do is to set the CONCURRENCY_LEVEL variable to speed up the compile of the kernel. The number should be the number of processors you have plus one. So in my case I have a Intel Core i5 processor so I will add one with the 4 available.

[bash]cat /proc/cpuinfo | grep -i processor
processor    : 0
processor    : 1
processor    : 2
processor    : 3[/bash]

I have got 4 processors, so concurrency will be 4+1

[bash]# export CONCURRENCY_LEVEL=5[/bash]

Start Building :

Here I named my custom kernel as tuxsage, replace it with the one you wish.

[bash]# make-kpkg clean[/bash]
[bash]# fakeroot make-kpkg –initrd –append-to-version=-tuxsage kernel-image kernel-headers[/bash]

(This will take some time)

Once this is completed you will find the built kernel one directory up from your present directory

[bash]# cd /root/source
# dpkg -i linux-image-2.6.38.(This part will be whatever name you gave it).deb
# dpkg -i linux-headers-2.6.38.(This part will be whatever name you gave it).deb[/bash]

Make initramfs:

[bash]# update-initramfs -c -k 2.6.38+tuxsage (replace tuxsage with correct name)[/bash]

Update Grub :

[bash]#update-grub[/bash]

Reboot to the New Kernel :)

UPDATE : If you are using latest Ubuntu (11.10) with kernel 3.0.0-12-generic then you can get my custom compiled kernel with battery fix downloaded directly from http://www.4shared.com/file/O8CRV1qo/Toshiba-kernel-304-tuxsagetar.html which you can install and use. Have a look at ReadMe.txt for install instructions.

N:B : This post was made very soon after I got this fixed and you may find typos and other errors. Will proofread and fix those soon if any :-)

References :

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/703302

https://bugzilla.kernel.org/show_bug.cgi?id=34532
https://bugzilla.kernel.org/show_bug.cgi?id=15707

http://homeport.org/~bcordes/satellite-l500-install.html

http://www.insanelymac.com/forum/lofiversion/index.php/t189272-100.html

http://en.gentoo-wiki.com/wiki/ACPI/Fix_common_problems

http://www.lesswatts.org/projects/acpi/overridingDSDT.php

http://www.question-defense.com/2010/09/26/how-to-recompile-your-ubuntu-10-10-kernel-for-patching-or-to-add-support-for-a-specific-device