少し前のことになるが、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 まで問題なく動作している。
※コメント投稿者のブログIDはブログ作成者のみに通知されます