2007年9月4日星期二

ACPI问题,DSDT解决

如果你的系统有电源管理方面的问题,比如关机、挂起,笔记本电池等等, 或者是硬件传感器方面的问题,如CPU温度检测,风扇状态控制等,你可以考虑一下 是否是你的ACPI(Advanced Configuration and Power Interface)出了问题。

快速应用

  • 我们需要一个软件来处理dsdt,Intel提供了一个工具叫做 iasl(下载的是较小的 Unix Build Environment):

    sudo apt-get install bison flex-old
    make

    生成的可执行文件iasl,可以拷贝出来单独使用。

  • 得到系统当前使用的dsdt,生成asl文件dsdt.dsl:

    sudo cat /proc/acpi/dsdt > dsdt.dat
    iasl -d dsdt.dat
  • 编译dsdt.dsl文件:

    iasl -sa dsdt.dsl

    根据输出的Error,Warning信息修改dsdt.dsl文件,再次编译,直到 0 Errors, 0 Warnings

  • 使用新的dsdt.aml代替BIOS中的版本:

    cp /boot/initrd.img-2.6.20-16-generic /boot/initrd.img-2.6.20-16-generic-bak
    sudo cp dsdt.aml /etc/initramfs-tools/DSDT.aml
    sudo update-initramfs -u -k all

常见DSDT语法

在实例讲解怎样出错之前,我们先来了解一下DSDT文件的语法

  • Name (SWIT, One)

    One对象有了个新名字SWIT

  • Store (0x02, Local0)

    将0x02存储到Local0标示的一段内存中。

  • Method (INCS, 1, NotSerialized)

    定义一个函数INCS,INCS带1个参数等等。函数名也可以是规范中定义的一个对象名。

  • Multiply (Local0, 0x04, Local1)

    Local0中的数据乘以0x04,结果保存在Local1

  • CreateDWordField (BUF1, Local2, CAPB)

    为标示为BUF1的一段内存中第Local2个字节开始的4个字节(Dword:Double word)命名为CAPB

  • And (CAPB, 0xFFFFFFFC, CAPB)

    将CAPB中的值和0xFFFFFFFC按位与后,保存在CAPB中

DSDT的修改

这是一件令人头痛的事,我所能做的,只是依据编译时的错误(警告)信息,参考 《ACPI规范》 , 做一些语法上的修正。

  • 错误信息:

    dsdt.dsl   323:             Method (_CST, 0, NotSerialized)
    Warning 1086 - ^ Not all control paths return a value (_CST)

    查看323行开始的一段代码:

    Method (_CST, 0, NotSerialized)
    {
    If (CSMD) {}
    Else
    {
    ...
    }
    }

    很明显,意思是说if分句中没有返回值。

  • 错误信息:

    dsdt.dsl 1177: Method (_OSC, 5, NotSerialized)
    Warning 1075 - ^ Reserved method has too many arguments
    (_OSC requires 4)

    很清楚,_OSC的参数是4个,把Method中的5改作4即可。

  • 错误信息:

    dsdt.dsl 1191: CreateDWordField (BUF1, Local2, CAPB)
    Error 4111 - Creating a named object in a While loop ^

    这是个新修正的 bug ,命名对象BUF1不能用在一个while循环里。我用老版本的iasl
    编译并无此错,而可能关键的问题就是这个。我不知道该怎么修复这个问题。

  • 错误信息:

    dsdt.dsl  1193:                             And (CAPB, 0xFFFFFFFC)
    Warning 1104 - ^ Result is not used, operator has no effect

    查阅规范,And还可有第3个参数,用以存放比较后的值,我直接改为:

    And (CAPB, 0xFFFFFFFC, CAPB)

    我完全没把握这个改动是否恰当,因为它改变了内存中CAPB标示的一段内容

  • 错误信息:

    dsdt.dsl 1935: Method (INCS, 1, NotSerialized)
    Warning 1086 - ^ Not all control paths return a value (INCS)

    查看相应的代码:

    Method (INCS, 1, NotSerialized)
    {
    If (...)
    {...}
    ...
    IF (...)
    {...}
    }

    这里的错误是,如果所有If都不满足,Method将没有返回值。因为我不知道前面的If中为什么是那些值,我在最后添加了个Return(Zero),随便返回了个Zero对象,也不知是否会被正确处理。但至少,编译又少了个Warning

  • 许多Error或Warning是相关连的,解决1个往往连带消除好几个。 比如1个Not all control paths return a value类警告的修正, 会连带消除相关的Reserved method must return a valueCalled method may not always return a value警告

其它一些相关的资源

Gentoo论坛上有个非常详细的 教程

而Ubuntu的 HowTo 则参考了上面的教程。

我在 这里 还发现了一个和我一模一样的dsdt。去它的论坛上 了一下。回说论坛刚被黑过,所有附件都丢失了,估计原始帖除了这个附件,也没有什么实质性内容。

BenQ S73U似乎也有类似问题,而且 它的dsdt 和我的很相像。

一个中文 ACPI论坛 ,没什么人气。

Linux2下 ACPI PCI Hot-Plug 的实现 ,一些概念很名词的讲解

ACPI学习笔记 ,看来是干这行的,牛人。

Linux ACPI Howto ,linux下解决acpi问题的相关知识,和本文一样,有dsdt错误解决示范。

Linux-ready Firmware Developer Kit ,检查firmware(bios)Linux兼容性的工具,提供了可启动盘,不过几乎没有机器可以全部通过的,所以如果有项目没通过,并不意味着有问题。另外,它的源代码也可以参考一下。

acpiscoperead-write everythin 是Windows下两个查看提取各个acpi表、bios信息的工具。这里是我收藏的备份。

后记

当然ACPI还有个操作系统的支持问题。事实上,因为我的神舟L205T总是死不瞑目,关机时不能关闭电源,我开始找寻ACPI问题的解决办法,到现在,编译了自己的dsdt,问题依旧,我看Ubuntu的这个 bug报告 ,难兄难弟还真是不少。现在看来,内核的ACPI支持部分出了问题,可能性更大一点,毕竟MS Windows下关机正常。

(2008-11-19修订)

没有评论: