落穂拾い

Gleanings in my life

【Gentoo】Lavie Z (2012年版) の acpi

2014年01月15日 22時51分30秒 | Linux
少し前のことになるが、kernel が 3.8 から 3.10.7 に上がったらバッテリーが認識されなくなった。 dmesg で確認すると
[    1.633496] ACPI Warning: For \_SB_.PCI0.LPCB.EC__.BAT1._BIX: Return Package is too small - found 19 elements, expected 20 (20130328/nsprepkg-341)
[    1.633505] battery: probe of PNP0C0A:00 failed with error -14
といった感じである。kernel を 3.10.11 に上げても変化なし。 3.10.6 から 3.10.7 になるときに acpi/battery.c に変更が入ったのが影響しているようだ。 しかし、もとはといえば上記のエラーの1行目が問題である(これは 3.8 まででも出ていたwarningである)。 そこで、LaVie Z の ACPI を調査してみる。まず、tool をインストールする。
emerge -av iasl pmtools
これらのツールを用いて調査する。今回は acpi という作業ディレクトリに acpi 情報を読み出すこととする。
mkdir acpi
cd acpi
これで準備オッケー。 acpi 情報を dump する。
acpidump --binary -t DSDT > dsdt.aml
iasl -d dsdt.aml
上記コマンドは acpi 情報を binary で dump するものであるが、同時に逆アセンブルしてテキスト形式になったものが dsdt.dsl というファイルで生成される。 そこで dsdt.dsl を見る(テキストファイルなので lv とか less で見る)。この中から BAT1 を探すと
            Device (BAT1)
            {
                Name (_HID, EisaId ("PNP0C0A"))
                Name (_UID, One)
                Name (_PCL, Package (0x01)
                {
                    _SB
                })
                Method (_STA, 0, NotSerialized)
                {
                    If (MYEC)
                    {
                        If (MBTS)
                        {
                            Return (0x1F)
                        }
                        Else
                        {
                            Return (0x0F)
                        }
                    }
                    Else
                    {
                        Return (0x0F)
                    }
                }

                Method (_BIF, 0, NotSerialized)
                {
                    If (MYEC)
                    {
                        UPBI ()
                    }
                    Else
                    {
                        IVBI ()
                        Store (0x99, DBG8)
                        Sleep (0x03E8)
                    }

                    Return (BIF0)
                }

                Method (_BIX, 0, NotSerialized)
                {
                    If (MYEC)
                    {
                        UPBX ()
                    }
                    Else
                    {
                        IVBX ()
                        Store (0x99, DBG8)
                        Sleep (0x03E8)
                    }

                    Return (BIX0)
                }

                Method (_BST, 0, NotSerialized)
                {
                    If (MYEC)
                    {
                        UPBS ()
                    }
                    Else
                    {
                        IVBS ()
                    }

                    Return (STAT)
                }

                Method (IVBI, 0, NotSerialized)
                {
                    Store (0xFFFFFFFF, Index (BIF0, One))
                    Store (0xFFFFFFFF, Index (BIF0, 0x02))
                    Store (0xFFFFFFFF, Index (BIF0, 0x04))
                    Store ("Wrong", Index (BIF0, 0x09))
                    Store (" ", Index (BIF0, 0x0A))
                    Store ("Wrong", Index (BIF0, 0x0B))
                    Store ("Wrong", Index (BIF0, 0x0C))
                }

                Method (IVBX, 0, NotSerialized)
                {
                    Store (0xFFFFFFFF, Index (BIX0, One))
                    Store (0xFFFFFFFF, Index (BIX0, 0x02))
                    Store (0xFFFFFFFF, Index (BIX0, 0x04))
                    Store ("Wrong", Index (BIX0, 0x09))
                    Store (" ", Index (BIX0, 0x0A))
                    Store ("Wrong", Index (BIX0, 0x0B))
                    Store ("Wrong", Index (BIX0, 0x0C))
                }

                Method (IVBS, 0, NotSerialized)
                {
                    Store (Zero, Index (STAT, Zero))
                    Store (0xFFFFFFFF, Index (STAT, One))
                    Store (0xFFFFFFFF, Index (STAT, 0x02))
                    Store (0x2710, Index (STAT, 0x03))
                }

                Method (UPBI, 0, NotSerialized)
                {
                    Store (Zero, Local0)
                    Store (Zero, Local1)
                    Store (Zero, Local2)
                    Store (Zero, Local3)
                    Store (MDCH, Local0)
                    Store (MDCL, Local1)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local1, Local0)
                    Store (Local0, Index (BIF0, One))
                    Store ("PC-VP-BP86/OP-570-77009", Index (BIF0, 0x09))
                    Store (MFCH, Local0)
                    Store (MFCL, Local1)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local1, Local1)
                    Store (Local1, Index (BIF0, 0x02))
                    Store (Divide (Local1, 0x0A, ), Local0)
                    Store (Local0, Index (BIF0, 0x05))
                    Store (Divide (Local1, 0x14, ), Local0)
                    Store (Local0, Index (BIF0, 0x06))
                    Store (MDVH, Local0)
                    Store (MDVL, Local2)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local2, Local2)
                    Store (Local2, Index (BIF0, 0x04))
                    Store ("", Index (BIF0, 0x0A))
                    Store ("Lipo", Index (BIF0, 0x0B))
                    Store (CTID, Local0)
                    If (LEqual (Local0, Zero))
                    {
                        Store ("NEC", Index (BIF0, 0x0C))
                    }
                    Else
                    {
                        Store ("NEC", Index (BIF0, 0x0C))
                    }
                }

                Method (UPBX, 0, NotSerialized)
                {
                    Store (Zero, Local0)
                    Store (Zero, Local1)
                    Store (Zero, Local2)
                    Store (Zero, Local3)
                    Store (MDCH, Local0)
                    Store (MDCL, Local1)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local1, Local0)
                    Store (Local0, Index (BIX0, One))
                    Store ("PC-VP-BP86/OP-570-77009", Index (BIX0, 0x0F))
                    Store (MFCH, Local0)
                    Store (MFCL, Local1)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local1, Local1)
                    Store (Local1, Index (BIX0, 0x02))
                    Store (Divide (Local1, 0x0A, ), Local0)
                    Store (Local0, Index (BIX0, 0x05))
                    Store (Divide (Local1, 0x14, ), Local0)
                    Store (Local0, Index (BIX0, 0x06))
                    Store (MDVH, Local0)
                    Store (MDVL, Local2)
                    ShiftLeft (Local0, 0x08, Local0)
                    Or (Local0, Local2, Local2)
                    Store (Local2, Index (BIX0, 0x04))
                    Store ("Lipo", Index (BIX0, 0x11))
                    Store (CTID, Local0)
                    If (LEqual (Local0, Zero))
                    {
                        Store ("NEC", Index (BIX0, 0x12))
                    }
                    Else
                    {
                        Store ("NEC", Index (BIX0, 0x12))
                    }

                    Store (0x16, SMAD)
                    Store (0x17, SMCM)
                    Store (0x02, SMAA)
                    Store (0x09, SMPR)
                    Sleep (0x01F4)
                    Store (SMD1, Index (BIX0, 0x07))
                    Store (0x16, SMAD)
                    Store (0x1C, SMCM)
                    Store (0x02, SMAA)
                    Store (0x09, SMPR)
                    Sleep (0x01F4)
                    Store (SMD1, Index (BIX0, 0x10))
                }

                Method (UPBS, 0, NotSerialized)
                {
                    Store (Zero, Local0)
                    Store (Zero, Local1)
                    Store (Zero, Local2)
                    Store (Zero, Local3)
                    Store (Zero, Local4)
                    Store (Zero, Local7)
                    Store (MBTS, Local0)
                    If (LEqual (Local0, One))
                    {
                        Store (POWS, Local0)
                        If (LEqual (Local0, One))
                        {
                            Store (MBCS, Local1)
                            If (LEqual (Local1, One))
                            {
                                Or (Local4, 0x02, Local4)
                            }
                        }
                        Else
                        {
                            Or (Local4, One, Local4)
                            Store (MBLS, Local0)
                            If (LEqual (Local0, One))
                            {
                                Or (Local4, 0x04, Local4)
                            }
                        }

                        Store (POWS, Local0)
                        If (LEqual (Local0, One))
                        {
                            Store (MBCS, Local0)
                            If (LEqual (Local0, One))
                            {
                                Store (MCUH, Local0)
                                Store (MCUL, Local1)
                                ShiftLeft (Local0, 0x08, Local0)
                                Or (Local0, Local1, Local1)
                                If (LEqual (Local1, 0xFFFF))
                                {
                                    Store (0xFFFFFFFF, Local1)
                                }

                                Store (Local1, Index (STAT, One))
                            }
                            Else
                            {
                                Store (Zero, Index (STAT, One))
                            }
                        }
                        Else
                        {
                            Store (MCUH, Local0)
                            Store (MCUL, Local1)
                            ShiftLeft (Local0, 0x08, Local0)
                            Or (Local0, Local1, Local1)
                            XOr (Local1, 0xFFFF, Local1)
                            If (LEqual (Local1, Zero))
                            {
                                Store (0xFFFFFFFF, Local1)
                            }

                            Store (Local1, Index (STAT, One))
                        }

                        Store (MRCH, Local0)
                        Store (MRCL, Local2)
                        ShiftLeft (Local0, 0x08, Local0)
                        Or (Local0, Local2, Local2)
                        Store (Local2, Index (STAT, 0x02))
                        Store (MVOH, Local0)
                        Store (MVOL, Local3)
                        ShiftLeft (Local0, 0x08, Local0)
                        Or (Local0, Local3, Local3)
                        Store (Local3, Index (STAT, 0x03))
                        Store (Local4, Index (STAT, Zero))
                        Sleep (0x64)
                    }
                    Else
                    {
                        IVBS ()
                    }
                }
            }
となっている。電池だ。型番もあってる。 しかし詳細を見てみるとおかしなところがある。 BIX0 のエントリーが 19個 (0x13) しかないのだ。20個 (0x14) あるべきなのに (ACPIの仕様上)。
            Name (BIX0, Package (0x13)
            {
                One, 
                0x1130, 
                0x1130, 
                One, 
                0x39D0, 
                Zero, 
                Zero, 
                0xFFFFFFFF, 
                0x00013880, 
                0x07D0, 
                0x07D0, 
                0x0BB8, 
                0x03E8, 
                One, 
                One, 
                "CRB Battery 0", 
                "Battery 0", 
                "Lipo", 
                "-Virtual Battery 0-"
            })
ACPIの仕様にあわせて、Linux kernel 3.10.7 から、この構造体に revision が最初のメンバーとして加わったのだが、LaVie Z の BIOS の ACPI 情報は、仕様から逸脱しているということのようだ。 そこで、これを仕様に合わせることにする。具体的には、上記の dsdt.dsl ファイルを編集し、メンバー数を 0x14 (20個) に変更し、最初のメンバーに 0x0 (revision は 0ということにする) を追加する。これを binary に変換 (assemble) するには、
iasl -tc dsdt.dsl
とする。エラーが出るが、なんとか dsdt.hx ができる。これを正しい ACPI 情報として kernel に読み込ませればよい。 これは kernel の config で、BIOS から acpi 情報を読み込む変わりにファイルから acpi 情報を読み込ませるように設定するだけだ。 というわけで、この対策で現状、3.10.25 まで問題なく動作している。

コメントを投稿