# FAQ Tips > Tipps und Tricks >  HP Compaq nx6125 Lüftersteuerung

## Skipper

*Problem*

Viele Linuxuser berichten von einer fehlerhaften Lüftersteuerung auf ihren HP Compaq nx6125 Laptops. Die Lüfter arbeiten zufällig und unregelmäßig oder gar nicht. Das führt unter Last schon nach wenigen Sekunden zur Überhitzung, bis hin zur automatischen Notabschaltung des Rechners. Die Lebensdauer der Hardware dürfte darunter erheblich leiden.

*Ursachen*

Einmal haben auf diesem Modell auch aktuellste Kernel Schwierigkeiten mit der Verarbeitung von ACPI-Ereignissen. Wird eine Temperaturschwelle (Trip Point) überschritten, wird die erforderliche Aktion (Lüfter an) nicht immer ausgeführt.

Außerdem ist das BIOS fehlerhaft, genauer die DSDT (Differentiated System Description Table), so daß selbst bei korrekter Reaktion des Kernels die Lüfter nicht anspringen.

Eine genaue Beschreibung des Problems findet ihr hier.

*Lösung*

Edit 05.05.06: Anscheinend gibt es nun einen Kernelpatch, der das Problem lösen soll. Getestet habe ich den noch nicht. Zu finden ist der ebenfalls hier.

Diese Anleitung beschreibt das Vorgehen unter Linux SuSE 10.0 mit Standard-Distributionskernel. Auf anderen Distributionen oder mit selbstgebautem Kernel sind z.T. noch weitere Schritte notwendig, die hier nur kurz erwähnt werden.

*1. DSDT korrigieren*

Als erstes müssen wir die fehlerhafte DSDT reparieren. Die DSDT ist die Schnittstelle zwischen Kernel und BIOS und beschreibt die ACPI-Funktionen und wie sie angesteuert werden müssen. Sie wird beim Booten aus dem BIOS ausgelesen. Die meisten ACPI-Probleme unter Linux entstehen, wenn der Hersteller die DSDT fehlerhaft implementiert.

Mit Hilfe eines Kernelpatches können wir dem Kernel beim Booten eine korrigierte DSDT unterschieben. Bei SuSE ist der Patch schon integriert, so daß wir nichts am Kernel ändern müssen.

Dann laden wir uns eine korrigierte DSDT runter. Es ist sehr wichtig, die zur BIOS-Version passende zu verwenden:
DSDT für BIOS F.09
DSDT für BIOS F.0D
DSDT für BIOS F.07 siehe Dateianhang

Haben wir eine andere BIOS-Version, müssen wir selber Hand anlegen. Dazu brauchen wir den IASL Compiler aus dem Paket pmtools. Die originale DSDT wird ausgelesen, in einer Datei gesichert und deassembliert:


```
cat /proc/acpi/dsdt > dsdt_orig.aml
iasl -d dsdt_orig.aml > dsdt_orig.asl
```

Das Ergebnis steht in "dsdt_orig.dsl". Diese Datei öffnen wir mit einem Editor und suchen etwa bei Zeile 6350 nach folgendem Abschnitt. Einige Bezeichner und die Zeilenzahl können bei verschiedenen BIOS-Versionen abweichen. Die rot markierten Zeilen löschen wir und die grün markierte ganz am Ende fügen wir hinzu:


```
        PowerResource (C25C, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)
            {
                Return (C255 (0x01, 0x64))
            }

            Method (_ON, 0, NotSerialized)
            {
                If (LNot (LGreater (\C008 (), 0x03)))
                {
                    C256 (0x01, 0x64)
                }
                Else
                {
                    If (LGreater (DerefOf (Index (C252, 0x00)), C258 (C24B, 0x00)))
                    {
                        C256 (0x01, 0x64)
                    }
                }
            }

            Method (_OFF, 0, NotSerialized)
            {
                C257 (0x01, 0x50)
            }
        }

        PowerResource (C25D, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)
            {
                Return (C255 (0x02, 0x50))
            }

            Method (_ON, 0, NotSerialized)
            {
                If (LNot (LGreater (\C008 (), 0x03)))
                {
                    C256 (0x02, 0x50)
                }
                Else
                {
                    If (LGreater (DerefOf (Index (C252, 0x00)), C258 (C24A, 0x00)))
                    {
                        C256 (0x02, 0x50)
                    }
                }
            }

            Method (_OFF, 0, NotSerialized)
            {
                C257 (0x02, 0x41)
            }
        }

        PowerResource (C25E, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)
            {
                Return (C255 (0x04, 0x41))
            }

            Method (_ON, 0, NotSerialized)
            {
                If (LNot (LGreater (\C008 (), 0x03)))
                {
                    C256 (0x04, 0x41)
                }
                Else
                {
                    If (LGreater (DerefOf (Index (C252, 0x00)), C258 (C249, 0x00)))
                    {
                        C256 (0x04, 0x41)
                    }
                }
            }

            Method (_OFF, 0, NotSerialized)
            {
                C257 (0x04, 0x32)
            }
        }

        PowerResource (C25F, 0x00, 0x0000)
        {
            Method (_STA, 0, NotSerialized)
            {
                Return (C255 (0x08, 0x32))
            }

            Method (_ON, 0, NotSerialized)
            {
                If (LNot (LGreater (\C008 (), 0x03)))
                {
                    C256 (0x08, 0x32)
                }
                Else
                {
                    If (LGreater (DerefOf (Index (C252, 0x00)), C258 (C248, 0x00)))
                    {
                        C256 (0x08, 0x32)
                    }
                }
            }

            Method (_OFF, 0, NotSerialized)
            {
                C257 (0x08, 0x00)
            }
        }

        Device (C260)
        {
            Method (_INI, 0, NotSerialized)
            {
                \_TZ.C246 ()
            }

            Name (_HID, EisaId ("PNP0C0B"))
            Name (_UID, 0x00)
            Name (_PR0, Package (0x01)
            {
                C25C
            })
        }

        Device (C261)
        {
            Name (_HID, EisaId ("PNP0C0B"))
            Name (_UID, 0x01)
            Name (_PR0, Package (0x01)
            {
                C25D
            })
        }

        Device (C262)
        {
            Name (_HID, EisaId ("PNP0C0B"))
            Name (_UID, 0x02)
            Name (_PR0, Package (0x01)
            {
                C25E
            })
        }

        Device (C263)
        {
            Name (_HID, EisaId ("PNP0C0B"))
            Name (_UID, 0x03)
            Name (_PR0, Package (0x01)
            {
                C25F
            })
        }

        ThermalZone (TZ1)
        {
            Name (_AL0, Package (0x01)
            {
                C260
            })
            Name (_AL1, Package (0x01)
            {
                C261
            })
            Name (_AL2, Package (0x01)
            {
                C262
            })
            Name (_AL3, Package (0x01)
            {
                C263
            })
            Method (_AC0, 0, NotSerialized)
            {
                Return (C258 (C24B, 0x00))
            }

            Method (_AC1, 0, NotSerialized)
            {
                Return (C258 (C24A, 0x00))
            }

            Method (_AC2, 0, NotSerialized)
            {
                Return (C258 (C249, 0x00))
            }

            Method (_AC3, 0, NotSerialized)
            {
                Return (C258 (C248, 0x00))
            }

            Method (_PSV, 0, NotSerialized)
            {
                Return (C258 (C24C, 0x00))
            }

            Name (_PSL, Package (0x01)
            {
                \_PR.C000
            })
            Method (C264, 1, NotSerialized)
            {
                Store (Arg0, C24E)
                Acquire (C171, 0xFFFF)
                Store (0x07, C172)
                Store (0x01, C24F)
                Release (C171)
                If (LEqual (Arg0, 0x00))
                {
                    Store (0x00, C248)
                    Store (0x01, C249)
                    Store (0x02, C24A)
                    Store (0x03, C24B)
                    Store (0x04, C24C)
                }
                Else
                {
                    Store (0x00, C248)
                    Store (0x01, C24C)
                    Store (0x02, C249)
                    Store (0x03, C24A)
                    Store (0x04, C24B)
                }
            }

            Name (_TSP, 0x64)
            Name (_TC1, 0x01)
            Name (_TC2, 0x02)
            Name (_CRT, 0x0E60)
            Method (_TMP, 0, Serialized)
            {
                Store (C25A (0x00), Local0)
                Return (Local0)
            }

            Name (_TZP, 0x012C)

        }
```

Das Ergebnis speichern wir unter neuem Namen "dsdt_neu.dsl".

Nun muß die heruntergeladene oder selbst geänderte DSDT assembliert werden. Hierbei sollten nur ein paar Warnings, aber keine Errors angezeigt werden. Das Ergebnis steht in "DSDT.aml", die wir nach /etc/acpi verschieben:


```
iasl -tc dsdt_neu.dsl
mv DSDT.aml /etc/acpi
```

Jetzt tragen wir in /etc/sysconfig/kernel folgendes nach (nur SuSE):


```
# The file name of a binary ACPI Differentiated System Description Table
# (DSDT). This table is appended to the initial ram disk (initrd) that
# the mkinitrd script creates. If the kernel finds that its initrd
# contains a DSDT, this table replaces the DSDT of the bios. If the file
# specified in ACPI_DSDT is not found or ACPI_DSDT is empty/not specified,
# no DSDT will be appended to the initrd.
# Example path /etc/acpi/dsdt
#
ACPI_DSDT="/etc/acpi/DSDT.aml"
```

Als nächstes wird die initrd neu gebaut, und die neue DSDT darin integriert. Die alte initrd benennen wir vorher um. Wenn etwas schief geht und die neue nicht funktioniert, können wir die alte wieder reaktivieren. Bei Kernelupdates wird die initrd überschrieben, so daß wir die folgenden Schritte nach jedem Update wiederholen müssen. Die genauen Dateinamen hängen von Kernelversion und Distribution ab und müssen individuell angepasst werden:


```
cd /boot
ln -s System.map-2.6.13-15.7-default System.map
mv initrd-2.6.13-15.7-default initrd-2.6.13-15.7-default.bak
mk_initrd -k vmlinuz-2.6.13-15.7-default -i initrd-2.6.13-15.7-default
rm System.map
```

Bei anderen Distributionen als SuSE muß dem mk_initrd die Option "-a /etc/acpi/DSDT.aml" hinzugefügt werden, je nach Distri evtl. auch noch andere Optionen.

Jetzt kommt der große Augenblick, und wir können den Rechner neu booten. In der Ausgabe von "dmesg" sollte danach etwa folgendes zu sehen sein, wenn alles erfolgreich verlaufen ist:


```
ACPI: Looking for DSDT in initramfs... found /DSDT.aml ... successfully read 27308 bytes from /DSDT.aml
ACPI: Using customized DSDT
    ACPI-0306: *** Info: Table [DSDT] replaced by host OS
```

Jetzt sollten wir die Lüfter testweise ein- und ausschalten können. Die Lüfterbezeichnungen können je nach BIOS-Version abweichen:


```
# Ersten Lüfter einschalten
echo 0 > /proc/acpi/fan/C263/state

# Ersten Lüfter ausschalten
echo 3 > /proc/acpi/fan/C263/state
```


*2. ACPI-Thermal-Events verarbeiten*

Das eingangs beschriebene Problem, daß ACPI-Thermal-Events nicht vom Kernel bearbeitet werden, lässt sich einfach umgehen. Es reicht aus, wenn regelmäßig die Temperaturinformationen per "acpi" ausgelesen werden. Aus unbekanntem Grund werden die Events dann verarbeitet und die Lüftersteuerung funktioniert wie gewünscht. Dazu verwenden wir den "watch" Befehl:


```
watch 'acpi -t' &> /dev/null &
```

Um den Befehl beim Booten automatisch zu starten, tragen wir ihn bei SuSE in "/etc/init.d/boot.local" ein, bei anderen Distributionen gibt es ähnliche Möglichkeiten.

Fertig.

*3. Individuelle Lüftersteuerung per Script (optional)*

Im Dateianhang findet ihr mein Script nx6125-fancontrol, das die Steuerung der Lüfter komplett übernimmt. In Zeile 26 sind die Lüfternamen definiert (können je nach BIOS-Version abweichen), und in den Zeilen 27 und 28 die "Trip Points", bei denen die Lüfter ein- und ausgeschaltet werden. Durch Anpassen dieser Werte läßt sich ein beliebiges Lüfterverhalten programmieren. Es sollte nach acpid und powersaved gestartet werden, da diese offenbar die Trip Points wieder resetten.

Achtung: Das Script ist eine Alphaversion und wenig getestet, Benutzung nur durch Fortgeschrittene und auf eigene Gefahr :-).

------------------------- Ende ------------------------
Edit 16.02.06: Pkt. 2 vereinfacht
Edit 27.02.06: Rechtschreibung

----------

