29.11.2010

Switchable graphics and power consumption

Update: The switch seems to work reliably for me now. I switched to the ATI card, restarted X, used it, switched back and restarted X again. The procedure worked without problems. If I find time I will probably write a small program to switch the graphics card similar to the one I wrote for screen rotation.

It is completed! Switchable graphics are supported by the Linux kernel!
The usage is pretty simple. You have 2 graphics cards installed in the system. Thus, You need drivers for both of them. For the tm2-1090eg this means You need to make sure that both the radeon and the intel module are loaded after You booted up Your laptop. If one of them does not appear in the output of lsmod, there's something wrong or You blacklisted is. How to cope with that is not covered in this guide.
Starting with some-kernel-version, there is a node in the sysfs, specifically in /sys/kernel/debug/, which is called vgaswitcheroo. This neat little thing gives us the possibility to switch the graphics adapter at runtime and also to turn off the idle one.
(As root) You can write different 3 values into the switch at /sys/kernel/debug/vgaswitcheroo/switch using:
Code:
$ echo <value> > /sys/kernel/debug/vgaswitcheroo/switch
The values are:
  1. OFF - This one is simple. It turns off the video adapter which is currently unused. It is of high value, though. I noticed that upon turning off my ATI card, the battery lifetime actually increased by a factor of 5! Before using this, I could use my laptop for about an hour before the batteries went dry and now I am able to hack on it for around 5 hours without a break. At the end of this article I will present an upstart script to automatically turn off the ATI card on startup (I can't think of a reason to use the ATI card on Linux. According to other people, the drivers don't work well and there is no need for 3D acceleration at all.).
  2. DDIS - Switch to the discrete graphics card (the ATI one). This requires a restart of the X server to take effect and the whole switching is buggy on my system. Every one or two switches, the system completely crashes and I need to hard-reboot my laptop. However, it may work for some people and may work for everyone in the near future, so I included it here as well.
  3. DIGD - Switch to the integrated graphics card (the Intel one). The same restrictions and errors apply as for the previous value.
You can also read the state of the switch:
Code:
$ cat /sys/kernel/debug/vgaswitcheroo/switch
So far so good. Now as I mentioned, the ATI card is practically useless unless You want to play games (and even then I heard it's not really making things look good). If You want to turn it off, You may copy the following script (name it ati-disable.conf and place it in /etc/init as root, of course).
Code:
# ati-disable - Disable ATI graphics card
#
# Disable the dedicated ATI graphics card to save power.

description "Disable ATI graphics card"
author "Frederik Möllers"

start on started gdm

script
    if [ -w /sys/kernel/debug/vgaswitcheroo/switch ]
    then
        echo "OFF" > /sys/kernel/debug/vgaswitcheroo/switch
    fi
end script
Upon reboot, Your ATI card should be turned off. You can check if it is by using the cat command from above.

That's it! You're done!

13.11.2010

Fred.deb

Update: There is a note on bugs at the end of the article.

Yay, I forged my first package! And I got my own PPA (personal package archive) at Launchpad!
The first package I made is based on my article on screen rotation. It contains the script itself (an improved version), the upstart script to map the keycodes and a configuration file (/etc/tablet-mode/tablet-mode.conf) to centrally configure the needed values.
Here's what You need to do if You want to use it (You need root access for most of the tasks):
  1. Add the PPA to Your sources:
    Code:
    add-apt-repository ppa:fredfredfred/ppa
  2. Refresh Your package list:
    Code:
    apt-get update
  3. Install the package:
    Code:
    apt-get install tablet-mode
  4. As told in the message during installation, You need to take a look at the configuration file, /etc/tablet-mode/tablet-mode.conf. Either use the comments from the file or have a look at my first article on this subject to find out the values You need. The values provided in the sample should work on an HP TouchSmart tm2-1090eg notebook, You only have to uncomment the last 2 lines to enable the keycode:scancode mapping upon system start.
  5. Bind the scan codes to rotatescreen tableton and rotatescreen tabletoff, as described in the other article.
That's it! You're done!

Bugs: If You turn the screen, put it down and then hibernate Your laptop, turn the screen back and power it back on, the screen is upside down as is the tablet orientation. I will not fix this, since I cannot. Upon resuming from suspend, there is no way for me to check which position the display is in. Use the console commands rotatescreen tableton and rotatescreen tabletoff to switch between the modes manually (or use the GUI).

07.11.2010

CPU governors and power supply status

Update: As announced, this script collection has been incorporated into my PPA as a package. Check it out here.

As promised, here's an article on CPU governors. As You might know by now, I use Ubuntu on my laptop. Unfortunately, it was kind of useless (until now) if I didn't plug in the power supply, since the battery was drained in less than an our of work (using nothing more than a text editor, kile). The problem source: The system doesn't change the cpu governor when the power cord is plugged out. Thus, the ondemand governor is used instead of the powersave one.
Luckily, there's an easy way to cope with this. The ACPI daemon acpid can be taught to execute arbitrary code upon any ACPI event. That means You can use it to automatically change the CPU governor depending on Your power supply status. Here's how it works:
  1. Create a script to change the CPU governor. You can use mine, too:
    Code:
    #! /bin/bash

    # Note: AC connection is in:
    # /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/AC/online
    # 0 is disconnected, 1 is connected

    # If no arguments are passed, print governors
    if [ -z "$1" ]
    then
       for MYCPU in /sys/devices/system/cpu/cpu[0-9]*
       do :
          echo "$(basename $MYCPU): $(cat ${MYCPU}/cpufreq/scaling_governor)"
       done
       echo "Available (on cpu0): $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors)"
       exit 0
    fi

    # Bring governor in control
    if [ "$UID" -ne "0" ]
    then
       echo "Error: Must be run as root!"
       exit 1
    fi
    echo -n "Handling over control to $1 governor... "
    if [ "$1" == "conservative" -o "$1" == "powersave" -o "$1" == "performance" -o "$1" == "ondemand" ]
    then
       for MYCPU in /sys/devices/system/cpu/cpu[0-9]*
       do :
          echo "$1" > ${MYCPU}/cpufreq/scaling_governor
       done
    # userspace governor needs speed argument
    elif [ "$1" == "userspace" ]
    then
       if [ "$2" -gt "0" ]
       then
          for MYCPU in /sys/devices/system/cpu/cpu[0-9]*
          do :
             echo "$1" > ${MYCPU}/cpufreq/scaling_governor
             echo "$(expr $2 \* 1000)" > ${MYCPU}/cpufreq/scaling_setspeed
          done
       else
          echo "userspace governor needs speed argument > 0!"
       fi
    else
       echo "Unknown governor: '$1'"
       exit 1
    fi
    echo "done"
    Make the script executable and place it somewhere, e.g. in /usr/local/bin. You can also use the script manually from the command line, e.g. with sudo cpufreq performance if You feel like You need everything Your computer got.
  2. Create a script for the acpid and place it in /etc/acpi (the script must be executable). Mine is called powersave.sh and looks like this:
    Code:
    #! /bin/bash

    # Called by /etc/acpi/events/powersave
    # Calls cpufreq script to set cpu governor
    # Author: Frederik Möllers

    if [ "$4" -eq 0 ]
    then
       /usr/local/bin/cpufreq powersave
    else
       /usr/local/bin/cpufreq ondemand
    fi
  3. Create a rule for the acpid and place it in /etc/acpi/events. Mine is called powersave and looks like this:
    Code:
    # /etc/acpi/events/powersave
    # Calls /etc/acpi/powersave to set cpu governor when ac adapter status changes
    # Author: Frederik Möllers

    event=ac_adapter
    action=/etc/acpi/powersave.sh %e
  4. Make acpid reload its configuration (as root):
    Code:
    $ reload acpid
  5. You might think You're done now, but actually You've only finished half of the job yet. When the system boots up, there will be no ACPI event telling acpid the status of Your power supply. Thus, if You boot with the power cord plugged out, Your system will still use the ondemand governor. To deal with that, You can create an upstart script which sets the CPU governor depending on the status of the power supply. Create a file /etc/init/cpufreq.conf (or with any other filename, but keep the .conf extension!) and fill it with something like the following.
    Code:
    # cpufreq
    #
    # Sets CPU governor to ondemand if AC is plugged in and powersave if not
    # Default is performance which is kind of overkill.

    description "CPU frequency scaling"
    author "Frederik Möllers"

    start on (virtual-filesystems and local-filesystems)

    script
       if [ "$(cat /sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/power_supply/AC/online)" -eq 0 ]
       then
          sudo /usr/local/bin/cpufreq powersave
       else
          sudo /usr/local/bin/cpufreq ondemand
       fi
    end script
    WARNING: Depending on Your system, the path (/sys/devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00/) on the /sys filesystem where the status of Your power supply can be found, may differ from the one I use. It shouldn't be miles away, but especially the number following ACPI may be another one on other laptop. You might need to search for the power_supply directory manually and change the path.
  6. You're almost done! Since the default CPU governor is performance which, as I said in my script, is kind of overkill, Ubuntu ships with an init-script to set the governor to ondemand upon startup. This, however, collides with the upstart script You just created, so You need to disable that init-script (as root):
    Code:
    $ update-rc.d ondemand disable
    This will safely disable the ondemand script but will still offer You the chance to turn it back on if You ever want to revert the changes You made.
That's it! You're done!

05.11.2010

Automatic screen rotation on HP touchsmart notebooks

Update 3: Apparently the python script which is advertised on some sites got more attention than it had when I first read about it and has even been set up as a Launchpad project. The huge CPU overhead has been taken care of (it's now event-based) and it supports more than just one laptop model. I haven't tried a new version of the script, but I guess it does the job just as fine as my script does (I can't tell which script is better). Feel free to test out both ways, I'd be happy to hear of some comparisons!

Update 2: There's a new article on this topic. I've managed to build a package out of the stuff I wrote here and made it available in my Launchpad PPA. It should be much easier to just install and configure it than to follow this whole guide. Here's the direct link to the article:
http://linuxquirks.blogspot.com/2010/11/freddeb.html

Update: According to feedback, this solution is not yet guaranteed to work, even for similar laptops. Feel free to test it and report any errors (helps me a lot), though. I will try to create an installable package out of all this, but this will take some time.

As I wrote in an earlier article, I possess an HP touchsmart tm2-1090eg notebook whichcan be turned into a tablet PC. Since the automatic screen rotation is not working out-of-the-box on Ubuntu and since I couldn't get the rotate-screen-button on the right side of the display to work yet, I've been getting by with a hand-written script. I wrote a Tcl/Tk program which uses xrandr and xsetwacom to rotate the screen according to my wishes.
By request of Felix, the first person to write a comment to this blog :), I looked into possibilities to automatically rotate the screen upon turning the display. I thought that since I managed to write an ACPI handler for CPU frequency scaling depending on the status of the power supply (there will be a post on this, too), I might give it a try. And guess what? I did it!
Unfortunately, my first guess was wrong. Turning around the display and putting it on top of the keyboard didn't create any ACPI events. However, I noticed some strange noise on dmesg:
atkbd serio0: Use 'setkeycodes e058 ' to make it known
atkbd serio0: Unknown key pressed (translated set 2, code 0xd9 on isa0060/serio0).
atkbd serio0: Use 'setkeycodes e059 ' to make it known.
atkbd serio0: Unknown key released (translated set 2, code 0xd9 on isa0060/serio0).

Hell yes, dmesg even told me what to do! Here's what I did:
  1. Find out the scan code - turn the display, put it down, pull it back up and inspect the messages:
    Code:
    $ dmesg
    There should be some messages like the ones I received. The first one is the key code from putting down the display, the second one is the code from pulling it back up.
    Note: If You don't get any messages like those, chances are that Your kernel already knows the keys. Try to bind something to them using the GNOME "Keyboard Shortcuts" or see if they generate key events by using xev.
  2. Find out which key code is available for mapping. There's no patented way for doing this. I just tried out some codes and looked what the GNOME "Keyboard Shortcuts" called the code. For me, the codes 220 and 221 worked well, since there is no button issuing these codes.
  3. Create an upstart script to set the keycodes on system startup. Setting the codes is not persistens, so You have to do it after each reboot. Use an upstart script to accomplish the job. As root, create a file /etc/init/tablet-mode.conf and put something like this inside:
    Code:
    # tablet-mode
    #
    # Map key codes to the scan codes emitted by the display when putting it down on
    # the keyboard.

    description "Tablet PC mode"
    author "Frederik Möllers"

    start on local-filesystems

    script
        setkeycodes e058 220
        setkeycodes e059 221
    end script
  4. Create a program to rotate the screen. Basically You just need to use xrandr to rotate the screen and xsetwacom to turn the tablet orientation. You can also use my Tcl/Tk program (requires wish to run, install the package if You want to use it) which also offers a GUI to use manually. Put the following code in a file (e.g. /usr/local/bin/rotatescreen, make it executable and You can call it with rotatescreen tableton and rotatescreen tabletoff. It not only turns the display and the tablet orientation but also disables the touch mode. This prevents the cursor from jumping around when You write with the stylus and touch the display with Your hand. Of course, You can customize the Tcl/Tk program to fit Your wishes. Even if You're not experienced in Tcl or Tk, the syntax should be quite easy. So here's the code:
    Code:
    #! /bin/bash
    #\
    exec wish "$0" "$@"

    proc rotate_0 {} {
       exec xrandr --output LVDS1 --rotate normal
       exec xsetwacom --set 11 rotate NONE
       exec xsetwacom --set 12 rotate NONE
       exec xsetwacom --set 13 rotate NONE
    }

    proc rotate_90 {} {
       exec xrandr --output LVDS1 --rotate left
       exec xsetwacom --set 11 rotate CCW
       exec xsetwacom --set 12 rotate CCW
       exec xsetwacom --set 13 rotate CCW
    }

    proc rotate_180 {} {
       exec xrandr --output LVDS1 --rotate inverted
       exec xsetwacom --set 11 rotate HALF
       exec xsetwacom --set 12 rotate HALF
       exec xsetwacom --set 13 rotate HALF
    }

    proc rotate_270 {} {
       exec xrandr --output LVDS1 --rotate right
       exec xsetwacom --set 11 rotate CW
       exec xsetwacom --set 12 rotate CW
       exec xsetwacom --set 13 rotate CW
    }

    proc touch_on {} {
       exec xsetwacom --set 11 Touch on
    }

    proc touch_off {} {
       exec xsetwacom --set 11 Touch off
    }

    proc quit {} {
       destroy .
       exit
    }

    if {$argc > 0} {
       switch "[lindex $argv 0]" {
          "0" {
             rotate_0
          }
          "90" {
             rotate_90
          }
          "180" {
             rotate_180
          }
          "270" {
             rotate_270
          }
          "tableton" {
             rotate_180
             touch_off
          }
          "tabletoff" {
             rotate_0
             touch_on
          }
          default {
             puts "Cannot rotate [lindex $argv 0] degrees!"
          }
       }
       exit
    }

    wm title . "Screen rotation"
    wm geometry . +605+300
    frame .deg
    button .deg.0 -text "0°" -command "rotate_0; quit"
    button .deg.90 -text "90°" -command "rotate_90; quit"
    button .deg.180 -text "180°" -command "rotate_180; quit"
    button .deg.270 -text "270°" -command "rotate_270; quit"
    pack .deg.0 .deg.90 .deg.180 .deg.270 -in .deg -pady 3 -side top
    frame .touch
    button .touch.ton -text "Touch on" -command "touch_on; quit"
    button .touch.toff -text "Touch off" -command "touch_off; quit"
    pack .touch.ton .touch.toff -in .touch -pady 3 -side top
    button .cancel -text "Cancel" -command "quit"
    pack .deg .touch .cancel -pady 6 -side top
    bind . "rotate_0; quit"
    bind . "rotate_90; quit"
    bind . "rotate_180; quit"
    bind . "rotate_270; quit"
    bind . "quit"
    bind . "quit"
    bind . "quit"
  5. Bind the keys to the program using GNOME "Keyboard Shortcuts" (or the equivalent for Your desktop manager). Create a binding with the command rotatescreen tableton and one with the command rotatescreen tabletoff and set the bindings by turning Your display, putting it down and pulling it back up.

Thanks again to Felix who told me to search for a way. I had already given up on this and didn't think I would find a way to get the screen rotation to work automatically.

That's it! You're done!