BeagleBone Blackは標準では電源ボタンを8秒未満押した場合shutdownするようになっているが、電源ボタンを外部に引き出して用いている場合にこの挙動が好ましくない場合があります。
昔はACPIから呼ばれるスクリプトでshutdownが行われていたので、このファイルを弄ることで、shutdownをdisableにしたり、任意の動作を行わせることが可能でした。(詳細忘れましたが)
昨今のバージョン(4.19.94-ti-r42)ではこの挙動が変更されており、どうやらシェルスクリプトが屋ばれる仕組みではなくなったようなので、shutdownをdisableにする方法について以下の通り調査した。
まず、この機能は、PMICからのIRQ割込みによって実現されている。OS状の割込みの統計情報は/proc/interruptで確認出来る。root@beaglebone:~# cat /proc/interrupts CPU0 16: 1524148 INTC 68 Level gp_timer 18: 0 INTC 3 Level arm-pmu 19: 1 INTC 78 Level wkup_m3_txev 20: 5023 INTC 12 Level 49000000.edma_ccint 22: 51 INTC 14 Level 49000000.edma_ccerrint 26: 0 INTC 96 Level 44e07000.gpio 27: 0 INTC 98 Level 4804c000.gpio 28: 0 INTC 32 Level 481ac000.gpio 29: 0 INTC 62 Level 481ae000.gpio 30: 14 INTC 72 Level 44e09000.serial 35: 6328 INTC 46 Level 481aa000.serial 36: 496 INTC 70 Level 44e0b000.i2c 37: 0 INTC 71 Level 4802a000.i2c 38: 102 INTC 30 Level 4819c000.i2c 39: 673 INTC 64 Level mmc0 40: 16054 INTC 28 Level mmc1 44: 0 INTC 77 Level wkup_m3 50: 0 INTC 75 Level rtc0 51: 0 INTC 76 Level rtc0 52: 0 INTC 65 Level 48030000.spi 53: 0 INTC 125 Level 481a0000.spi 55: 1456 INTC 41 Level 4a100000.ethernet 56: 121623 INTC 42 Level 4a100000.ethernet 59: 0 INTC 109 Level 53100000.sham 61: 0 INTC 111 Level 48310000.rng 134: 0 INTC 79 Level eqep_interrupt 136: 0 INTC 88 Level eqep_interrupt 138: 0 INTC 89 Level eqep_interrupt 139: 0 44e07000.gpio 6 Edge 48060000.mmc cd 140: 0 INTC 18 Level musb-hdrc.0 141: 1 INTC 19 Level musb-hdrc.1 142: 0 INTC 17 Level 47400000.dma-controller 143: 2 INTC 7 Level tps65217-irq 145: 2 tps65217 0 Edge vbus 146: 0 tps65217 2 Edge tps65217_pwr_but <- これ IPI0: 0 CPU wakeup interrupts IPI1: 0 Timer broadcast interrupts IPI2: 0 Rescheduling interrupts IPI3: 0 Function call interrupts IPI4: 0 CPU stop interrupts IPI5: 0 IRQ work interrupts IPI6: 0 completion interrupts
146がIRQ#となっているようだ。
割込みハンドラが登録されているのであれば、その登録を削除すれば良いのではないか。という事で、既存の割込みハンドラがあるか調べた。割込みハンドラはスケジューラーが管理しておらず、登録すると、割込みハンドラのコンテキストがメモリ上に常駐していて、割込みがあると直ちに実行されるという事らしい。kenrnelスレッドととしてpsコマンドで表示する事が可能で、スレッド名は[irq/IRQ#-name]となるとの事。
残念ながら、そのようなkernelスレッドは存在していないようなのでこの方法は断念。
root@beaglebone:~# ps -ef | grep irq root 9 2 0 15:04 ? 00:00:00 [ksoftirqd/0] root 29 2 0 15:04 ? 00:00:00 [irq/37-4802a000] root 30 2 0 15:04 ? 00:00:00 [irq/38-4819c000] root 76 2 0 15:04 ? 00:00:00 [irq/139-4806000] root 109 2 0 15:04 ? 00:00:00 [irq/36-44e0b000] root 110 2 0 15:04 ? 00:00:00 [irq/143-tps6521] root 1285 1115 0 15:46 pts/0 00:00:00 grep irq
Linuxには割込みを特定のCPUにのみ許す設定をする機能がある。
/proc/irc/
BBBではこの方法は不可であった。そもそもファイルへの書き込みが許されていないようだ。
# echo 0 >/proc/irq/146/smp_affinity -bash: echo: write error: Input/output error
ハンドラが起動するだけで、shutdownの動作は上書きされないかもしれないが、試してみた。
先ず次のソースとMakefileを用意する。ビルドにはkernel headersをインストールし、そこに含まれるヘッダファイルをincludeする必要がある。Makefileにあるのが定石的な方法の様だ。
root@beaglebone:/tmp# cat c.c #include#include #include MODULE_LICENSE("GPL"); const static char *name="pwrbut"; const static int irq=146; static irq_handler_t isrPwrBut(int irq, void *dev_id, struct pt_regs *regs) { printk("PWR-BUT is pressed\n"); return (irq_handler_t)IRQ_HANDLED; } int init_module(void) { printk("install '%s' for irq %d\n",name,irq); return request_irq (irq, (irq_handler_t)isrPwrBut, IRQF_TRIGGER_RISING, name, NULL); } void cleanup_module(void) { printk("remove '%s'\n",name); free_irq(irq, NULL); } root@beaglebone:/tmp# cat Makefile obj-m += c.o KDIR := /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KDIR) M=$(shell pwd) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
これで良い筈ですが、insmodでエラーになり実行不可。
デバイスごとに定義されているパラメーターが対応していないという事なんだろう。
root@beaglebone:/tmp# insmod c.ko insmod: ERROR: could not insert module c.ko: Invalid parameters
同様にkernel moudeから、特定のIRQ割込みを禁止にすることが出来る(本来は一時的に割込みを禁止にして排他的なしょりや、タイムクリティカルな処理を行う場合の機能)ので、moduleをロードすると割込みが禁止されたままになるようにしてみた。
# cat disable_pwrbut.c #include#include const static char *devname="disable_pwrbut"; const static int irq=146; int init_module(void) { disable_irq(irq); printk("install '%s' for irq %d\n",devname,irq); return 0; } void cleanup_module(void) { enable_irq(irq); printk("remove '%s'\n",devname); } # cat Makefile obj-m += disable_pwrbut.o KDIR := /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KDIR) M=$(shell pwd) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean # insmod disable_pwrbut.ko
これは上手く動作するようだ。ひとまずこれで事が足りそうだ。
+++ b/src/arm/am335x-bone-common.dtsi @@ -362,7 +362,7 @@ }; pwrbutton { - status = "okay"; + status = "disabled"; }; regulators { diff --git a/src/arm/tps65217.dtsi b/src/arm/tps65217.dtsi index 399baaa..552d6b7 100644 --- a/src/arm/tps65217.dtsi +++ b/src/arm/tps65217.dtsi @@ -24,7 +24,7 @@ }; pwrbutton { - compatible = "ti,tps65217-pwrbutton"; + compatible = "ti,tps65217-pwrbutton-disabled"; interrupts = <2>; status = "disabled"; };実際に試していないが、この方法であれば可能だろう。