LinuxでUSBのオートサスペンドを一時的に無効にする方法

# はじめに
　LinuxでUSBデバイスの電源が自動的にサスペンド状態になってしまう機能である「オートサスペンド（autosuspend）」を一時的に無効にする方法を紹介する。USBデバイスを安定的に使いたい場合に有効。

# 動作確認環境
* OS
  * Ubuntu 20.04 arm64
    * NVIDIA Jetson Orin (JetPack 5.1.1)  

# 方法
　USBのオートサスペンドを一時的に無効化する方法を紹介する。

:::note warn
注意
今回紹介する方法は、OSを再起動すると設定が無効化される。永続的に変更したい場合は、別の方法となる。[こちらの記事](https://unix.stackexchange.com/questions/91027/how-to-disable-usb-autosuspend-on-kernel-3-7-10-or-above)など参照。
:::

　USBデバイスのオートサスペンドの設定は、接続されているUSBデバイスごとに、```/sys/bus/usb/devices/{device_id}/power```に格納されている。{device_id}は、BusとPortで構成されるUSBデバイスの接続先である。詳細は[こちらの記事](https://qiita.com/propella/items/66eb1e93cc71ebea3829)を参照。
　オートサスペンドに関わる項目は以下である。ここで、Linuxカーネルバージョンによって設定が変わるので注意する。[公式ドキュメント](https://www.kernel.org/doc/Documentation/usb/power-management.txt)に以下の記載がある。

>> The user interface for controlling dynamic PM is located in the power/
subdirectory of each USB device's sysfs directory, that is, in
/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
relevant attribute files are: wakeup, control, and
autosuspend_delay_ms.  (There may also be a file named "level"; this
file was deprecated as of the 2.6.35 kernel and replaced by the
"control" file.  In 2.6.38 the "autosuspend" file will be deprecated
and replaced by the "autosuspend_delay_ms" file.  The only difference
is that the newer file expresses the delay in milliseconds whereas the
older file uses seconds.  Confusingly, both files are present in 2.6.37
but only "autosuspend" works.)

 Copilotでの翻訳結果が以下になる。カーネル2.6.38以降とそれ以前で設定する項目が違うとの記載がある。

>>動的PMを制御するためのユーザーインターフェースは、各USBデバイスのsysfsディレクトリのpower/サブディレクトリにあります。つまり、/sys/bus/usb/devices/.../power/にあり、「...」はデバイスのIDです。関連する属性ファイルは、wakeup、control、およびautosuspend_delay_msです。（「level」という名前のファイルもあるかもしれません。このファイルは2.6.35カーネルで廃止され、「control」ファイルに置き換えられました。2.6.38では「autosuspend」ファイルが廃止され、「autosuspend_delay_ms」ファイルに置き換えられます。唯一の違いは、新しいファイルが遅延をミリ秒で表すのに対し、古いファイルは秒を使用することです。混乱を招くことに、両方のファイルは2.6.37に存在しますが、「autosuspend」のみが機能します。）

　設定項目を以下にまとめる。

|項目|対応カーネル|説明|デフォルト値|
|:-:|:-:|:-:|:-:|
|power/autosuspend_delay_ms|2.6.38以降|オートサスペンドに移行する時間（ミリ秒）|0|
|power/control|2.6.38以降|電源制御の種類（auto:オートサスペンド、on:オートサスペンド無効）|auto|
|power/autosuspend|2.6.38より前|オートサスペンドに移行する時間（秒）|0|
|power/level|2.6.38より前|電源制御の種類（auto:オートサスペンド、on:オートサスペンド無効）|auto|


## 現状設定を確認

　現状のオートサスペンドの状態を確認する。

例：USBデバイス1-1の場合
```bash
$ cd /sys/bus/usb/devices/1-1/power
$ cat autosuspend_delay_ms 
0
$ cat control 
auto
$ cat autosuspend
0
$ cat level 
auto
```

　今回試した環境は、カーネルは2.6.38以降だが、両方の設定項目が設定されていることを確認できた。

## オートサスペンド無効の設定

　以下のコマンドを実行して接続されている全てのUSBデバイスのオートサスペンドを無効にする。念のため、古いカーネル用の項目も設定変更する。

1. 管理者モードに入る
    ```bash
    $ sudo -i
    ```

2. USBデバイスのオートサスペンドを無効化
    カーネル2.6.38以上の場合
    ```bash:接続されている全てのUSBデバイスのオートサスペンドを無効化
    for i in /sys/bus/usb/devices/*/power/autosuspend_delay_ms; do echo -1000 > $i; done
    for i in /sys/bus/usb/devices/*/power/control; do echo on > $i; done
    ```

    カーネル2.6.38以前の場合
    ```bash:接続されている全てのUSBデバイスのオートサスペンドを無効化
    for i in /sys/bus/usb/devices/*/power/autosuspend; do echo -1 > $i; done
    for i in /sys/bus/usb/devices/*/power/level; do echo on > $i; done
    ```

　上記コマンド実行後に、正しく設定されているか確認する。

```bash
$ cd /sys/bus/usb/devices/1-1/power
$ cat autosuspend_delay_ms 
-1000
$ cat control 
on
$ cat autosuspend
-1
$ cat level 
on
```
　正しく設定されていることが確認できた。今回試した環境は、カーネルは2.6.38以降だが、両方の設定項目が変更されることを確認できた。なお、同様に逆も成り立つことを確認した。つまり、カーネル2.6.38以降で、カーネル2.6.38以前に有効なコマンドを実行しても、新しい項目が変更されていることを確認できた。


# まとめ

　LinuxでUSBデバイスの電源が自動的にサスペンド状態になってしまう機能である「オートサスペンド（autosuspend）」を一時的に無効にする方法を紹介した。USBデバイスを安定的に使いたい場合に有効。

# 参考

https://www.kernel.org/doc/Documentation/usb/power-management.txt

https://qiita.com/Hayashi_Kohei/items/4f9db82a85751cbd30f0

https://stackoverflow.com/questions/4702216/controlling-a-usb-power-supply-on-off-with-linux

https://qiita.com/propella/items/66eb1e93cc71ebea3829