2009年10月4日日曜日

acpiの仕組みとか

S101はネットブックなので、電源管理が上手に出来るようにする仕組みを色々調べてたのでまとめてメモ。サスペンドと無線LAN制御の具体的な部分は別メモの予定。

1.acpid
まず、基本はパッケージ「acpid」
acpiイベントに対応した処理を行う仕組み。
http://wiki.archlinux.org/index.php/Acpid
もしくは、man acpidの方が仕組みはよくわかる。

インストールはパッケージ「acpid」が公式リポジトリ[extra]にあるので
pacmanでインストール。
そして、/etc/rc.confのDAEMONS配列にacpidを追加する。
但し、halを導入していている場合、halが自動的に呼び出すので
/etc/rc.confでacpidを呼び出す必要は無い。


acpidは、Adbanced Configuration and Power Interface evet daemonってことらしい。acpidは、/proc/acpi/eventを監視していて、ここにイベントの行が追加されるとこれを読み込んで、/etc/acpi/eventsディレクトリの中にあるファイルで定義されたイベントに対応する処理を検索して実行する仕組み。

/etc/acpi/eventsディレクトリの中のファイルの書式は、「event=」行と「action=」の二つを定義する。eventで捕まえるイベントを定義して、それに対応するコマンドをactionに定義する。
acpidに付属しているanythingを例にみると

event=.*
action=/etc/acpi/handler.sh %e

となっている。
eventについては、正規表現(manによればsee regcomp(3)となっている)を用いることができるらしい。また、action行にある%eはacpidからの渡されるイベントの文字列に展開されて、上の例ではスクリプトの引数として使われている。

archlinuxのwikiでは、

event=button sleep.*
action=/etc/acpi/actions/sleep-button.sh "%e"

という風に、イベント毎に実行スクリプトを個別に定義する方法も紹介されているが、anythingのようにすべてのイベントをひとつのスクリプトに投げてそこで、場合分けするほうが単純でよさげ?

その他のTipsとしては、次のものがあるらしい。
・acpidの処理を一旦中止させる。
 /var/lock/acpidというファイルが存在すると、acpidはすべてのイベントを
 無視するため、acpidの働きを止めることができる。
・ソケット
 /var/run/acpid.soketを通じてAPCIイベントのテキストを受け取ることが
 できるので、このソケットに繋がるクライアントプログラムを書ける。

さて、acpiイベントとは具体的には、

 電源ボタンを押した
 Sleep/Suspendボタンを押した
 特定のファンクションボタン+ファンクションキーを押した
 ノートパソコンの蓋を閉めた
 ノートパソコンのACアダプタを接続した(外した)

みたいなもの。

もともとは、ノートパソコンの様にバッテリーで動いてたりする場合、出来るだけ電気を使わないようにするための仕組みで、蓋を閉めたり、ACアダプタ接続の状態をシステムが把握して状況に応じて自動で節電しようとする仕組み。キーに対応する処理も出来るのは、特別なキーに対応して、WiFiデバイスの電源を落としたり、ユーザーの意思でサスペンドやハイバネートも出来るようしたりするためかな。S101でもFnキーとファンクションキー(F1とかのキー)の組み合わせでこれらの処理をするようになっていて、ファンクションキーの上にはこれらのイメージが書いてある。

以上がacpidの基本的な仕組み。
システムが発信するacpiイベント、特に何のキーが押された等のイベントは、パソコン毎に違う。eeePCでもモデルによって、特殊なボタンの数も違う。S101では、キーボードの上に銀色のボタンで、左に人が走ってるイメージのボタンと、右には電源ボタンの二つがあるが、他のモデルだともっと他にもあるらしい。

ここで、acpidの活用をするためには、じぶんのパソコンに適した設定をする必要がある。そして、もうひとつの注意は、acpidはイベントに対応した処理を定義するだけの仕組みなので、処理の内容についても、システムのアプリの導入状態によって各パソコン毎に違う。なので、acpid付属のhandler.shやacpi-eeepc-generic付属の定義そのままで動く分けではない。特にサスペンドやハイバネートの処理については、色々な方法がある。そこで、ここらへんは別途、自分のシステムに合うものを検討して、一番よい方法を見つけた後、それをacpidの処理に組み込む事が必要。

2.acpi-eeepc-generic
eeePCシリーズの場合、以上のような状況に対応してくれるのがパッケージ「acpi-eeepc-generic」
但し、eeePCシリーズ汎用であるため、スクリプトは結構複雑になっていると同時に、
S101の場合(S101でもロットによるの?)多少手直しが必要な部分もある。
インストールはパッケージがAURにあるので、yaourt等を使う。

(1)概要
acpi-eeepc-genericの主な仕組みは次の通り。

・acpid用の定義
 /etc/acpi/events/acpi-eeepc-generic-events
acpidパッケージ付属のanythingで定義されている定義に代えて(コメントアウト)、
このファイルで処理の定義(呼び出すスクリプトファイルの指定)をしている。
具体的には、すべてのイベントについて、/etc/acpi/acpi-eeepc-generic-handler.shを呼び出している。

・処理の定義
/etc/acpi/acpi-eeepc-generic-handler.sh
このファイルで、イベントに対する処理の定義を行っている。
実際には汎用的な定義になっており、イベント及び処理はすべて変数が使われていて、その具体的な定義は別ファイルになっている。
また、これらの中で使われているシェル関数の定義も別ファイルに集められ、その他のユティリティ的なプログラムファイルも別に同梱している。
これらの別定義ファイルをまとめると以下の通り。

キーイベントの定義:/etc/acpi/eeepc/models/以下の各モデル名のファイル
処理の具体的なコマンドの定義:/etc/conf.d/acpi-eeepc-generic.conf
シェル関数の定義:/etc/acpi/eeepc/acpi-eeepc-generic-function.sh
その他のユティリティプログラム:/etc/acpi/eeepc/以下の上記以外のもの

これらのファイルを使ってacpi-eeepc-genericは構成されて動いている。
eeePCシリーズでこのパッケージを使う場合には、モデルが自動で決定されて、それに対応するキーイベントが読み込まれて、処理の内容も一般的なものがデフォルトで定義されており、だいたいは使えるようになっている。
カスタマイズは、/etc/conf.d/acpi-eeepc-generic.confファイルのみで一元管理する仕組みになっている。
acpi-eeepc-generic.confでは、変数の値として具体的なコマンド文字列を定義する(配列として複数コマンドもOK)。

(2)キーイベントの修正
キーイベントとキーの対応について、S101の場合、/etc/acpi/eeepc/models/acpi-eeepc-S101-events.confで定義されている。
ここでの定義は、前半と後半の2段階の定義になっている。前半は、コメントされている「Silver buttons」と「Fn+F? conbination」の部分で、実際のボタンが押された場合にシステムから送られてくる文字列(数字)とボタン名の対応の定義、後半は「Match previous to functions」で、このボタン名の変数とボタン名に対応したイベント名の対応の定義になっている。

まずは、前半のボタンとシステムが送ってくる文字列の関係については次のようになっている。先に述べたとおり、acpidは/proc/acpi/eventを監視して、イベントが起こるたびに/etc/acpi/events以下の定義を実行する。acpi-eeepc-genericパッケージを導入すると「/etc/acpi/acpi-eeepc-generic-handler.sh %e」が実行される。この「%e」の部分がイベント文字列に展開され、acpi-eeepc-generic-handler.shはこの文字列を分析して、場合分けを行って処理している。

イベントに対する「%e」の内容を具体的にみてみる。
例えば、以下のようにしてみる。

/etc/acpi/events/acpi-eeepc-generic-eventsのaction行を一旦コメントアウトして、

action=/etc/acpi/test-handler.sh %e

を追加。
以下の内容で、/etc/acpi/test-handler.shファイルを作成して、実行権限をつける。

#!/bin/sh
echo "$1:$2:$3:$4:$5:$6:$7" >>/etc/acpi/test.log

次に、/etc/acpi/test.logを空のファイルとして作成しておく。
以上の準備ができたら、acpidを再起動する。

# /etc/rc.d/acpid restart

これで、イベントが発生するたびに、acpidが渡してくる文字列が/etc/acpi/test.logに記録される。実際にFn+F1を押してみるとlogファイルには次のような行が追加される。

button/sleep:SLPB:00000080:00000001:::

他のキーを押してみたり、蓋を閉じてみたり、ACアダプタを付けたり外したりして試すと
色々なイベントが追加されるので試してみる。テスト用のスクリプトファイルは、検証のために7つ分の文字列を用意したけれど、送られてくる文字列は、4つの部分に分かれた文字列が送られてくることが分かる。また、4番目の要素は、そのイベントが呼ばれるたびに増えたりするらしいこともわかる。

これらのうち、特にS101でキーを押した場合の%eの3つ目までの要素の対応をまとめてみると以下の通り。

fn+F1 button/sleep SLPB 00000080
fn+F2 hotkey ATKD 00000010
fn+F3 hotkey ATKD 00000037
fn+F4 hotkey ATKD 0000001b
fn+F5 hotkey ATKD 0000002* (押すと数字が下がる)
fn+F6 hotkey ATKD 0000002* (押すと数字が上がる)
fn+F7 hotkey ATKD 00000016
fn+F8 hotkey ATKD 00000030
fn+F9 hotkey ATKD 00000012
fn+F10 hotkey  ATKD 00000013
fn+F11 hotkey ATKD 00000014
fn+F12 hotkey ATKD 00000015
fn+space hotkey ATKD 00000039

left_silver hotkey ATKD 00000039
right_silver button/power PWRF 00000080

fn+F5とfn+F6は3つ目の要素が変則的

ここで、acpi-eeepc-S101-events.confと見比べてみると、前半部分の定義は%eの第3要素についての定義をしているのが分かる。そして、定義の内容が多少ずれているのも分かる。また、配列定義になっている部分も、後半部分の定義で第1要素のみを定義しているため不必要っぽい。

そこで、実際に自分で試した結果で前半の定義を書き換えると次のようになる。

#Silver buttons
KEY_SILVER1="00000039"
KEY_SILVER2="00000080"
KEY_SILVER3=NONE
KEY_SILVER4=NONE

#Fn+F? combination
KEY_Fn_F1="00000080"
KEY_Fn_F2="00000010"
KEY_Fn_F3="00000037"
KEY_Fn_F4="0000001b"
KEY_Fn_F5="0000002*"
KEY_Fn_F6="0000002*"
KEY_Fn_F7="00000016"
KEY_Fn_F8="00000030"
KEY_Fn_F9="00000012"
KEY_Fn_F10="00000013"
KEY_Fn_F11="00000014"
KEY_Fn_F12="00000015"
KEY_Fn_Space="00000039"

そして、これに対応して、後半部分も書き換えるが、もともと定義されていない部分、
F3,F4辺りも追加して整理してみると次の通り。

#Match previous to functions
EEEPC_BLANK=$KEY_SILVER1
EEEPC_RESOLUTION=NONE
EEEPC_USER1=$KEY_Fn_F3
EEEPC_USER2=$KEY_Fn_F4
EEEPC_USER3=NONE

EEEPC_SLEEP=$KEY_Fn_F1
EEEPC_WIFI_TOGGLE=$KEY_Fn_F2
EEEPC_WIFI_UP=NONE
EEEPC_WIFI_DOWN=NONE
EEEPC_TOUCHPAD_TOGGLE=NONE
EEEPC_BRIGHTNESS_UP=$KEY_Fn_F5
EEEPC_BRIGHTNESS_DOWN=$KEY_Fn_F6
EEEPC_XRANDR_TOGGLE=$KEY_Fn_F8
EEEPC_XRANDR_TOGGLE_0=NONE
EEEPC_XRANDR_TOGGLE_1=NONE
EEEPC_XRANDR_TOGGLE_2=NONE
EEEPC_TASKMAN=$KEY_Fn_F9
EEEPC_VOL_MUTE=$KEY_Fn_F10
EEEPC_VOL_DOWN=$KEY_Fn_F11
EEEPC_VOL_UP=$KEY_Fn_F12

以上がacpi-eeepc-S101-events.confの修正になるが、注意点がある。
/etc/acpi/acpi-eeepc-generic-handler.shを読み解けば、処理の場合分けの仕組みは、まず、%eの第1要素で大きく分けられている。このうち、acpi-eeepc-S101-events.confの設定は、第1要素が「hotkey」の場合の第3要素の振り分けに用いられている。

つまり、fn+F1と電源ボタンについては、S101の場合ここでの設定は意味が無いことになる。

(3)具体的なコマンドの呼び出し設定。
キーの対応付けが修正できたら、次は/etc/conf.d/acpi-eeepc-generic.confで自分のシステムにあった設定を行うことになる。設定の仕方は、ファイルのコメント部分に記載されている。

・Xアプリの権限 XUSER
XUSERの値として、Xアプリ実行者権限を入れておく。

・お知らせ機能 NOTIFY
NOTIFYの値は、コメント通り
gnome系ならlibnotify
KDE系ならkdialog
汎用のdzenならdzen
特に必要ないなら、NONE

・無線ランドライバ WIFI_DRIVERS
S101の場合、ath9kなので
WIFI_DRIVERS=("ath9k")

・設定完了のしるし EEEPC_CONF_DONE
この変数の値がnoの間、お知らせメッセージに設定未完了の旨の表示がでる。
no以外なら出ないので、設定が終わればこの行をコメントアウトする。

・デバイストグルのリストア
RESTORE_hogehoge変数は、システム起動時に、前のデバイスのオンオフ状態を引き継ぐかどうかのフラグ。1で引継ぎ、0でシステムの初期値

・COMMAND_hogehogeによる、コマンド設定
変数の値は配列も可、コマンドの先頭に@をつけると、ユーザー権限で実行。変数名でおおよその対応イベントが分かるが、詳細な対応は/etc/acpi/acpi-eeepc-generic-handler.shファイルをみて直接確認する。また、実は変数の入れ子や、他のユティリティファイルそのものの変数も混在していて、結構読み解くのはめんどくさい。

デフォルトのままで、画面輝度の調整やボリューム調整はできるとおもう。


3.電力節約術
ACPIは結局のところ、ノートパソコン等で電源を長持ちさせるための仕組みなので、これを実現する幾つかの点に絞ってその設定を検証する。

・サスペンド、ハイバネート
サスペンドはメモリに情報を退避して、休眠状態にする方法
ハイバネートはHDDに情報を退避して、休眠状態にする方法
通常、acpiイベントのsleep/suspendイベントに対応して、処理を行うことになる。
acpi-eeepc-genericでは、sleep/suspendイベントに対応して、COMMANDS_SLEEP変数の値が呼び出される。サスペンド、ハイバネートについては、acpi-eeepc-generic同梱のスクリプトとしてacpi-eeepc-generic-suspend2ram.shがある。

サスペンド、ハイバネートについては、いろいろな方法があるが、pm-utilsを使うことにする。そのあたりは、別文書で記載

・画面表示の電源
Xの場合、画面表示のLED電源を落とすことができる?
未検証

・ワイヤレスデバイスの電源を落とす。
無線ランやブルートゥースデバイスは、よく電気を食うらしいので、これらを使っていないときにデバイスの電源を落とす。特に、無線ランについては、デバイスの制御と共に、ネットワークへの接続も含めてボタンでオンオフ出来るようにすると便利なので、その当りを別文書で検討する。
acpi-eeepc-generic同梱のユティリティスクリプトはacpi-eeepc-generic-toggle-wifi.shだが、そのままではS101の場合上手く働かないように見える。
イベントの対応は、無線ランがCOMMANDS_WIWI_TOGGLE。
ブルートゥースは直接の対応がないので、Fn+F3(上記の設定でCOMMAND_BUTTON_USER1)辺りに割り振る。

0 件のコメント:

コメントを投稿