📏

Linuxのudevルールを使ってUSBデバイスを挿入する順番の制約を無くそう

2023/12/30に公開

USBデバイスの挿入順番で困るとき

USBデバイスがたくさんつながるLinuxで動く機器を作る人向けの記事です。ソフトよりの組み込み系エンジニアとかラズパイ(Raspberry Pi)で何か作ったりする人とかを想定しています。

Linuxは、USBデバイスをたくさんつなげると/dev/ttyACM0, /dev/ttyACM1, /dev/ttyACM2 ... みたいな感じで対応するデバイス名が増えていきます。

このときソフトでdev/ttyACM0とかデバイスを指定すると、USBの挿す順番によって動かなくなってしまうので困りますね。

自分もニンジャランタンという趣味ガジェットを作ったとき、諸事情によりSeeedさんのシリアルデバイスに対応する必要があったため、この問題にぶちあたりました。これに限らず昔からよくぶち当たってんたんですけど、仕事関係だったので対応方法とかわざわざネットに書いてなかったのです。

ニンジャランタン

Seeedさんのデバイス(Seeed Studio XIAO ESP32C3)

udevルールを使おう

解決方法は「udevルールを使う」です。これだけ覚えておけば、ネットで調べれば解決方法は色々でてきます。以下記事とか実践的で分かりやすいですね。

https://armadillo.atmark-techno.com/blog/615/4245

自分がラズパイで実際にやった例を書いておきます。Linux OSならIntel系でもラズパイ(Arm系)でも同じようにできます。

まずはlsusbコマンドを使って、デバイスのIDを調べます。

最初にUSBデバイスを抜いた状態で実行します。

pi@raspberrypi:~/ninja-lantern $ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 0853:013f Topre Corporation REALFORCE 108JP
Bus 001 Device 003: ID 056e:0054 Elecom Co., Ltd Black Grast Laser Mouse  
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

次に、USBデバイスを挿入した状態で実行しましょう。

pi@raspberrypi:~/ninja-lantern $ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 0853:013f Topre Corporation REALFORCE 108JP
Bus 001 Device 003: ID 056e:0054 Elecom Co., Ltd Black Grast Laser Mouse  
Bus 001 Device 006: ID 303a:1001 Espressif USB JTAG/serial debug unit
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

差分となる以下が対象のUSBデバイスであることが分かります。

Bus 001 Device 006: ID 303a:1001 Espressif USB JTAG/serial debug unit

会社名を表すベンダーIDが303a、製品名を表すプロダクトIDが1001となります。

あとは/etc/udev/rules.d/99-seeed-serial.rulesといったudevルールのファイルを作成します。

今回の例だと、udevルールのファイルの中身は以下になります。

SUBSYSTEM=="tty", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", SYMLINK+="seeedusbserial", MODE="0666"

SYMLINK+="seeedusbserial"でデバイスファイル名を指定できます。MODE="0666"は、指定すると書き込み権限が付与されるので、わざわざUSBデバイスに対して毎回chmod 666 /dev/xxxと実行する必要がなくなります。

ファイルを作成した後、以下のコマンドを実行すると、設定が反映されます(再起動してもOKです)。

$ sudo udevadm control --reload

この状態で、USBデバイスを挿入すると/dev/seeedusbserialというデバイスファイル名が追加されるようになります。

あとはソフトの方で/dev/seeedusbserialを指定すればUSBデバイスの挿入順番を気にする必要はなくなります。便利ですね!

USBポートで固定

本記事ではとりあつかいませんが、udevルールを使ってUSBポートの場所で固定することもできます。興味ある方は調べてみてください。

まとめ

udevルールの使い方をまとめました。GitHubでソフト公開したりするときは、configディレクトリとかの下に.rulesファイルを入れておいて、セットアップスクリプトでsudo cp config/xxx.rules /etc/udev/rules.d/ みたいな感じのコマンドを追加しておくと親切かなと思います。

以下はニンジャランタンのGitHubです。

https://github.com/karaage0703/ninja-lantern

udevルール追加の際のPRです。
https://github.com/karaage0703/ninja-lantern/pull/4

他、有名どころですと例えばIntelのRealSenseとかもudevルールを使ったりしています。独自のカメラ系を複数使ったりする人は参考になるかなと思います。機種のバリエーションが多くてちょっと複雑ですが、configディレクトリ以下にudevルールズの設定ファイルがあります。

https://github.com/IntelRealSense/librealsense

関連記事

https://zenn.dev/karaage0703/articles/a267aa24a80c44

Discussion