1.概述
雖然Linux可以在任何一台386以上的PC上運作,目前大多數人使用的都是新型的,帶有各種外設的桌面PC或者筆記本電腦,這樣,電源管理功能(PM)就逐漸變得越來越重要。在筆記本電腦上電源管理可以節能,延長電池壽命,而在桌面PC上它可以降低幅射,降溫,延長外設使用壽命。現在的作業系統大都内置了電源管理支援,例如 Windows 和 Linux。
2.PC機實作電源管理的方法
要實作電源管理,最重要的有兩點:第一是需要裝置本身支援節電功能,比如硬碟,可以通過指令暫時關閉;第二是需要作業系統支援電源管理,這樣就可以在空閑一段時間之後調用驅動的電源管理功能關閉裝置。
兩種電源管理标準:APM和ACPI
傳統的APM(Advanced Power Management)是一種基于bios的電源管理标準,目前的最新版本是1.2,它提供了CPU和裝置電源管理的功能,但是由于這種電源管理方式主要是由bios實作,是以有些缺陷,比如對bios的過度依賴,新老bios之間的不相容性,以及無法判斷電源管理指令是由使用者發起的還是由bios發起的,對某些新硬體如USB和1394的不支援性。
為了彌補APM的缺陷,新的電源管理ACPI應運而生,這就是ACPI(Advanced Configuration and Power Interface),它主要是将電源管理的主要執行者由bios轉換成為作業系統,這樣可以提供更大的靈活性以及可擴充性。
目前的PC機主機闆一般同時支援APM和ACPI兩種标準。
3.Linux對電源管理的支援
核心子產品
針對APM和ACPI兩種不同的标準,Linux核心提供了兩個不同的子產品來實作電源管理功能,這就是apm和acpi。需要注意,apm和acpi是互相沖突的兩個子產品,使用者在同一時間内隻能加載其中之一,如果當他們在加載的時候發現二者之一已經加載,就會自動退出。
在官方釋出的核心中APM是較為成熟的電源管理方式,可以完成在Windows下ACPI所能完成的大部分功能。由于官方核心中ACPI的功能比較有限,目前還處于開發版狀态。是以目前的大多數distribution,如紅帽子預設就使用了apm作為電源管理方式。但是值得注意的是Linux中的ACPI實際上是由一個單獨的項目小組子產品進行維護的,目前核心ACPI的版本實際上已經遠遠落後于最新的版本。由于Linux穩定版中對任何新特性的加入都非常謹慎小心,是以我們也許隻能等到2.6.x版本的Linux誕生後才能看到ACPI的穩定全功能版了。不過我們也可以自己對核心打最新的ACPI更新檔來獲得這些功能。
這裡是ACPI的首頁:[url]http://sf.net/projects/acpi/[/url]
下面對電源管理的介紹以APM為主。
使用者态Daemon
為了讓Linux核心中的電源管理功能夠更好的被利用,我們還需要使用者态daemon程式的配合。針對APM和ACPI,分别有apmd和acpid兩個不同軟體。他們實作的功能比較類似,都是允許使用者預先定義某些政策,然後跟蹤電源狀态,執行特定的操作。在apmd軟體包中還有一個工具apm,使用者可以用它使機器主動進入standby和suspend狀态,還可以查詢bios的apm版本号。在使用acpi時直接對proc檔案系統進行操作即可完成同樣的功能。
4.Linux下驅動的電源管理機制
在Linux下不必為驅動分别編寫與APM和ACPI相對應的代碼,Linux與Windows類似,為驅動提供了統一的電源管理接口。驅動隻要實作了這些接口,就可以實作電源管理的功能。作業系統在它認為合适的時候就會通知驅動完成這些操作。
實作裝置電源管理接口主要需要實作以下5點:
1.使用pm_register對裝置的每個執行個體(instance)進行注冊;
2.在對硬體進行操作之前調用pm_access(這樣會保證裝置已被喚醒并且處于ready狀态);
3.使用者自己的pm_callback函數在系統進入suspend狀态(ACPI D1-D3),或者從suspend狀态恢複(ACPI D0)的時候會被調用;
4.當裝置不在被使用的時候調用pm_dev_idle函數,這個操作是可選的,可以增強裝置idle狀态的監測能力;
5.當被unload的時候,使用pm_unregister來取消裝置的注冊。
5.對APM進行程式設計
下面介紹在實模式中和在Linux下使用APM功能的程式設計方法:
由于APM是由bios提供的,我們可以直接在實模式(如DOS下)調用int 15軟中斷來進行電源管理操作。
在實模式下APM的standby、suspend和poweroff功能分别可以通過下面的彙編語言實作:
<code>standby:mov ax, 5307Hmov bx, 1mov cx, 1int 15Hsuspend:改成 mov cx,2poweroff:改成 mov cx,3</code>
需要注意的一件事是在Linux核心中沒有使用和實模式的一樣的方法來調用int 15H中斷,而是直接調用了bios的保護模式接口。是以我們如果修改了bios中的apm相關代碼并且沒有處理好保護模式接口的問題,可以出現這樣的情況:在實模式DOS下使用apm功能一切正常,但是在Linux下調用apm功能發生核心一般保護性錯誤。
在Linux下我們可以通過對apm_bios裝置的操作來完成同樣的功能。
下面的代碼可以實作APM的suspend功能,等價于apm -s
<code>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <asm/fcntl.h>#include <linux/types.h>#include <sys/types.h>#include "apm.h"int main(){ int fd, res; fd = open("/dev/apm_bios", O_RDWR); if (fd < 0) { printf("open /dev/apm_bios error! "); exit(-1); } sync(); res = ioctl(fd, APM_IOC_SUSPEND, NULL); if (res != 0) { printf("ioctl error! "); close(fd); exit(-1); } close(fd); return 0;}</code>
如果我們把上面程式中的SUSPEND改成STANDBY,我們就同樣實作了apm -S的功能。
在Linux下POWEROFF操作有其獨特的流程,最後根據核心中apm或者acpi的存在情況來執行相應不同的流程來關閉電源。請參見Linux核心源碼,我寫的《linux關機重新開機流程分析》中也有一定的介紹。
6.常見問題(FAQ)
1)我的系統不能被suspend,這是怎麼回事呢?
系統在suspend之前會向所有的驅動發消息,如果這個時候某個傲慢的驅動傳回了一個-EBUSY,那麼這次suspend的企圖就被這個驅動否決了,你隻有過一會再試,如果這個驅動總是否決(真是蠻橫,不過它也許有自己的苦衷也說不定),你就永遠都無法suspend了。
2)我按下系統的POWEROFF開關,在ATX的主機闆上,系統就會自動關機了,這個處理流程是什麼樣子的呢?
在核心APM子產品中建立了一個核心态線程不停的監測系統狀态,使用者的關機動作在這裡被截獲後處理。詳細的流程可以參見本人的《linux關機重新開機流程分析》。
3)Linux中電源管理的文檔在哪裡?
在Linux/Documentation目錄下的pm.txt中詳細定義了Linux驅動電源管理接口實作方式,并且有詳細的例子,apm和acpi的實作流程需要參見Linux源碼的實作。
7.總結
Linux中的電源管理是發展中的代碼。從目前的趨勢來看ACPI終将取代APM。現在使用APM則是較為成熟和穩妥的方案。我們如果現在編寫驅動應該嚴格遵守文檔中的pm.txt所規定的接口,這樣可以使我們的驅動有較強電源管理的适應性和穩定性。
參考資源
1.Linux-2.4.20源代碼
2.Linux Device Drivers 2nd Edition本文來自:[url]http://doc.linuxpk.com/74974.html[/url]
發表您的高見!