NetBSD@ThinkPad でのsuspend/resume

(ノートPCで)「べつにサスペンドできなくてもいいや」みたいなことを 書いたばかりだが、翻ってできちゃってわーいな話。

NetBSDユーザとしては、できないのがずっと当たり前だったので、 サスペンドとか別になくてもいいじゃんと思い続けること20年余。 ちょうど、Type-Cが長いこと使えなくても、MicroSDみたいな外部補助記憶が 使えなくても別になんとも思ってこなかったiPhoneユーザに近いか。

サスペンドできた。

sysctl -w hw.acpi.sleep.state=3

でよい。

ThinkPadならできるよ」 と書いてあったので念の為試したらx280ではできちゃった。ポイントがいくつか。

  1. サスペンドできないデバイスが付いてるとできない
  2. raidframeもそのデバイスの一つ
  3. Xの画面が戻らなかったりする問題はやはりあるようだ

1と2のデバイス問題

外付けのUSBデバイスとかあるとカーネルにサスペンドを拒否される。 これは分かるのだが、RAIDframeも該当した。 NetBSDではzpoolデバイスに RAIDframe を指定して使っているので、今回も /dev/raid28d で zpoolを作って使っていたが、サスペンドできない!

NetBSDのZFSだとデバイス名がずれたときに自動認識してくれないので 少し不安だが、デバイス接続順を変えて試したところ zpool import -f プール名 と明示的に指定するとインポートできるようなのでRAIDframe経由せずに 再構築した。

復帰時の工夫

manやWeb情報をみると /etc/apm のしたにスクリプトを作るといいよってのが まだ残っていて騙されてしまったが、もうapmdないものね。powerdですよ。

/etc/powerd/scripts/ を見ると、スクリプトが置いてあるので調整。

  1. powerdを起動しておく(/etc/rc.conf に powerd=yes)
  2. sleep_buttonスクリプトはスリープボタンを物理的に押されたときに発動される

後者について、えっと、「スリープボタンてどこよ?」

ThinkPad X280のキーボードには刻印ないっす。探したら、 「ThinkPadをキーボードでスリープ状態にする」がみつかり、 [Fn]+[4$] で行けるとわかった。そこで sleep_button スクリプトを修正。

--- sleep_button.orig   2017-07-13 22:51:15.000000000 +0900
+++ sleep_button        2024-08-27 12:46:37.806733805 +0900
@@ -11,7 +11,24 @@
 case "${2}" in
 pressed)
        if /sbin/sysctl -q hw.acpi.sleep.state; then
+               ncons=`wsconscfg -g`
+               wsconscfg -s 1
+               sleep 1
                /sbin/sysctl -w hw.acpi.sleep.state=3
+               ###################
+               if=iwm0
+               PATH=/usr/local/bin/DT:$PATH
+               #ifconfig $if down up
+               #/etc/rc.d/wpa_supplicant restart
+               ###     echo "$@" > /tmp/args.powerd
+               repeat=10
+               while [ $((--repeat)) -gt 0 ]; do
+                 sleep 2
+                 ifconfig $if | grep -q 'status: active' && break
+               done
+               wsconscfg -s $ncons
+               svc -t /service/*vpn*
+               ###################
        elif /sbin/sysctl -q machdep.xen.suspend; then
                /sbin/sysctl -w machdep.xen.suspend=1
        else

もともとある hw.acpi.sleep.state=3 の前後に、 仮想コンソールの切り替えと復帰とWi-Fiが戻ったらVPNもつなぎ直すのを入れた。

これでばっちり。

NetBSDでのバッテリ残量表示

おまけ。

OpenBSDではバッテリ情報を sysctl 変数から取る必要があったので いちいち面倒でこんな表示が出るスクリプトを作って使っていた。

battery
AC Offline: Battery remaining  66.0%
Discharging at 7.89(31.61/47.77) - 4h00m to go

NetBSDだと envstat(8) で情報が出るが、逆に情報量多すぎて見づらいし、 残り時間を知りたい。てことで、OpenBSDで使っていたbatteryスクリプトを NetBSDにも対応。コチラどうぞ。

#!/bin/sh

case `uname` in
  OpenBSD)
	getval() {
	  case $1 in
	    lastfull)	fld=acpibat0.watthour0 ;;
	    remain)	fld=acpibat0.watthour3 ;;
	    rate)	fld=acpibat0.power0 ;;
	    power)	fld=acpiac0.indicator0 ;;
	  esac
	  sysctl -n hw.sensors.$fld | cut -d' ' -f1
	}
	;;
  NetBSD)
	curstat=`envstat`
	getval() {
	  case $1 in
	    lastfull)	echo "$curstat"|awk '/last full cap:/{print $4}' ;;
	    remain)	echo "$curstat"|awk '/charge:/{print $2}' ;;
	    rate)	echo "$curstat"|awk '/rate:.*[0-9]/{print $3}' ;;
	    power)	echo "$curstat"|awk '/connected:/{print $2}' ;;
	  esac
	}
  	;;
esac
for v in remain lastfull rate power; do
  eval $v=`getval $v`
done
# echo $remain $lastfull $rate $power
percent=`echo "100*$remain/$lastfull"|bc -l|cut -d. -f1`
case $rate in
  0.0*|"")	rate=0 ;;
esac
case $power in
  Off|FALSE)
	printf "AC Offline: Battery remaining %5.1f%%\n" $percent
	if [ x"$rate" = x"0" ]; then
	  echo Unknown lifetime
	else
  	  life=`echo "$remain/$rate"|bc -l`
	  hour=${life%.*} dmin=${life#*.}
	  min=`echo "0.$dmin * 60" | bc -l | cut -d. -f1`
	  printf "Discharging at %.2f(%.2f/%.2f) - ${hour:-0}h%02dm to go\n" $rate $remain $lastfull $min
	fi
	;;
  On|TRUE)
	printf "AC ONline: Battery remaining %5.1f%%\n" $percent
	if [ x"$rate" = x"0" ]; then
	  echo "Last full capacity: ${lastfull}Wh"
	else
	  tf=`echo "$lastfull - $remain"|bc -l`
  	  tofull=`echo "$tf/$rate"|bc -l`
	  hour=${tofull%.*} dmin=${tofull#*.}
	  min=`echo "0.$dmin * 60" | bc -l | cut -d. -f1`
	  printf "Rate $rate to $tf ($remain/$lastfull) - "
	  printf "${hour:-0}h%02dm to full\n" $min
	fi
	;;
esac

# hw.sensors.acpibat0.volt0=11.40 VDC (voltage)
# hw.sensors.acpibat0.volt1=11.75 VDC (current voltage)
# hw.sensors.acpibat0.power0=6.59 W (rate)
# hw.sensors.acpibat0.watthour0=46.74 Wh (last full capacity)
# hw.sensors.acpibat0.watthour1=2.34 Wh (warning capacity)
# hw.sensors.acpibat0.watthour2=0.20 Wh (low capacity)
# hw.sensors.acpibat0.watthour3=30.78 Wh (remaining capacity), OK
# hw.sensors.acpibat0.watthour4=48.10 Wh (design capacity)
# hw.sensors.acpibat0.raw0=1 (battery discharging), OK
# hw.sensors.acpibat0.raw1=24 (discharge cycles)

電源をつないだときの表示はこんな感じ。

battery
AC ONline: Battery remaining  63.0%
Rate 40.926 to 17.220 (30.550/47.770) - 0h25m to full