2019年7月28日日曜日

Raspberry Pi の USB 電源を ON/OFF

Raspberry Pi 3 Model B+ の USB 電源をオフにする方法です。手順としては、事前にUSBデバイスを解放、次に電源OFF となります。

1.USBデバイス を unbind する。

単なる電源用のUSBデバイス(USBライト等)でなければ、USBデバイスを解放します。

(※もし USB フラッシュドライブ等なら、その前に umount する)
(※解放せずに下記の電源OFF をしても、モノによっては直後に再認識/電源ON となって、電源が落とせないケースあり。例えば、バッテリーを持っている USB デバイス等を USBポート2 に接続すると発生)

USBのポート番号は以下の図(内部的には、LAN ポートも USB 扱い)


今回は、iPod mini を USBポート2 へ接続している。
pi@raspberrypi:~ $ ls /sys/bus/usb/drivers/usb
1-1 1-1.1 1-1.2 bind uevent unbind usb1


この名称 A-B.C の様式は、
  • A:USBバス
  • B:バスのポート
  • C:USBハブのポート

この状態から、Raspberry Pi 3B+ のハードウェアとしては、こうなっている。
・USB の4ポートは、USBハブとして提供されている
・LANポートが USBハブのポート1 として管理されていた

さらに追加でUSBハブ等を挿していると、この名称も長くなる。追跡するにはカーネルのメッセージなら探しやすい。
pi@raspberrypi:~ $ dmesg | grep usb
[11002.555034] usb 1-1.2: Product: iPod mini
[11002.555042] usb 1-1.2: Manufacturer: Apple


iPod mini は 1-1.2 だと判明


lsusb コマンドでも番号を追跡できるが、確認できるポートは「バスのポート」なのか「ハブのポート」なのか分かりにくい。
pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 05ac:1205 Apple, Inc. iPod Mini 1.Gen/2.Gen
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

pi@raspberrypi:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
        |__ Port 2: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M
状況的に赤字が「ハブのポート」である様子。lsusb と lsusb -t の関係は Device番号 で紐づけできる。これまでの調査から USB デバイスの正体は、
  • usb1:Linux Foundation 2.0 root hub(コネクタは無い)
  • 1-1:Standard Microsystems Corp. SMC9514 Hub(コネクタは無い)
  • 1-1.1:Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
    (有線LAN コネクタ)
  • 1-1.2:Apple iPod mini(Pi 3B+ の USBポート2 へ接続中)

これで操作するデバイスが確認できたら、以下のコマンドで unbind します。
pi@raspberrypi:~ $ echo 1-1.2 | sudo tee /sys/bus/usb/drivers/usb/unbind
※ファイルの変更権は root のみなので、単にリダイレクトするのは無理です。


2.USB コネクタの電源OFF

USBハブのポート毎に電源管理できる製品でないと、ポート毎に電源OFF できない。Raspberry Pi 3B+ 基盤にあるUSBは、完全にはできないタイプなので、USBの4ポートを一括で電源OFFすることになる。(per-port power switching に対応するスマートHub 製品が必要だが、希少)

利用できるツールを2つ挙げる。
  1. 産総研のお偉いさんが提供しているツール(これはコンパイルするだけなのでコンパクト)。個人用のページのうち、「6. Implementation」にある、C もしくは Python 実装

    もしくは githubサイト(簡単なリファレンスあり、上と同じ C のプログラム)
    https://github.com/codazoda/hub-ctrl.c
  2. 上記の派生ツール(これはmake install が必要)
    https://github.com/mvp/uhubctl

今回は、hub-ctrl.c を使用する。github の説明の通りにコンパイルする。
wget https://www.gniibe.org/oitoite/ac-power-control-by-USB-hub/hub-ctrl.c
sudo apt-get install libusb-dev
gcc -o hub-ctrl hub-ctrl.c -lusb

使用方法は github にもあるが、番号のつけ方が分かりにくい。
hub-ctrl -b [Bus Num] -d [Device Num] -P [Port Num] -p [off:0/on:1]
この Port は Bus のポートでなく、USBハブのポート番号が該当する。
pi@raspberrypi:~ $ lsusb
Bus 001 Device 004: ID 05ac:1205 Apple, Inc. iPod Mini 1.Gen/2.Gen
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

pi@raspberrypi:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
        |__ Port 2: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M
USBハブとして機能しているのが、「(Bus 001 Device 002)Standard Microsystems Corp. SMC9514 Hub」なので、このハブのポートの電源を切る操作となる。
  • Bus Num:1
  • Device Num:2
  • Port Num:1~5(USBハブのポート番号)

LANコネクタの電源OFF(ハブのポート1)
pi@raspberrypi:~ $ sudo ./hub-ctrl -b 1 -d 2 -P 1 -p 0
USBコネクタの電源OFF(ハブのポート2)
pi@raspberrypi:~ $ sudo ./hub-ctrl -b 1 -d 2 -P 2 -p 0

※電源管理が完全ではないので、ポート2の電源を切るとUSB全ポートの電源が切れる。ポート3~5 は個別に電源管理できない。


もしくは USBハブの番号を指定して操作する、ハブの番号は hub-ctrl ツールの中で連番を付けているだけなので、そちらで確認する。
pi@raspberrypi:~ $ ./hub-ctrl
Hub #0 at 001:002
INFO: individual power switching.
WARN: Port indicators are NOT supported.
Hub #1 at 001:001
INFO: ganged switching.
WARN: Port indicators are NOT supported.

この様式は、Hub #[Hub Num] at [Bus Num]:[Device Num] となっているので、今回ではUSBハブとの対応はこのようになっている。
  • Hub #0:(Bus 001 Device 002)Standard Microsystems Corp. SMC9514 Hub
  • Hub #1:(Bus 001 Device 001)Linux Foundation 2.0 root hub

上記より、電源を切るのは Hub #0 になる。(Hub #1 を電源OFFしちゃうと、この後の電源管理が全くできないうえ、このハブの再電源ONすらできず、OS再起動することになる。)

LANコネクタの電源OFF(ハブのポート1)
pi@raspberrypi:~ $ sudo ./hub-ctrl -h 0 -P 1 -p 0
USBコネクタの電源OFF(ハブのポート2)
pi@raspberrypi:~ $ sudo ./hub-ctrl -h 0 -P 2 -p 0

※同じく電源管理が完全ではないので、ポート2の電源を切るとUSB全ポートの電源が切れる。