udevで固有の属性がない全く同じデバイスを識別する[ubuntu]

# はじめに

u-bloxのZED-F9Pを2つUSBでPCに接続していて、ベンダー番号(idVendor)、プロダクト番号(idProduct)、シリアル番号全て同じだったので、udevルールを使ってUSBを挿した場所で区別したかった。

# 環境

OS : ubuntu22.04LTS
Kernel : 6.5.0-15-generic


# 手順

- USBを挿す場所を固定し、KERNELS番号を確認する
- udev rulesファイルを作成する
- 再起動

### lsusbで2つ接続した時の状態を見る

```bash
lsusb
```

```bash
Bus 003 Device 014: ID 1546:01a9 U-Blox AG u-blox GNSS receiver
Bus 003 Device 013: ID 1546:01a9 U-Blox AG u-blox GNSS receiver
```

両方ともidVendorが1546, idProductが01a9と全く同じとなっている。

### USB挿してある場所のKERNELSの確認

ZED-F9Pの場合、先に挿した方が`/dev/ttyACM0`, 後に挿した方が`/dev/ttyACM1`となっているので、udevadm infoコマンドでUSBがささっているKARNELSの番号をそれぞれ確認する。


```bash
udevadm info -a -p $(udevadm info -q path -n /dev/ttyACM0)
```

```bash
udevadm info -a -p $(udevadm info -q path -n /dev/ttyACM1)
```

u-bloxの場所を見て先頭のKERNELSを記憶しておく、この場合KERNELSは"3-2.1"になる。


```bash
  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2.1':
    KERNELS=="3-2.1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{authorized}=="1"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bDeviceClass}=="02"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bMaxPower}=="0mA"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bNumInterfaces}==" 2"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bmAttributes}=="c0"
    ATTRS{busnum}=="3"
    ATTRS{configuration}==""
    ATTRS{devnum}=="13"
    ATTRS{devpath}=="2.1"
    ATTRS{idProduct}=="01a9"
    ATTRS{idVendor}=="1546"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="u-blox AG - www.u-blox.com"
    ATTRS{maxchild}=="0"
    ATTRS{power/active_duration}=="761044"
    ATTRS{power/async}=="enabled"
    ATTRS{power/autosuspend}=="2"
    ATTRS{power/autosuspend_delay_ms}=="2000"
    ATTRS{power/connected_duration}=="761044"
    ATTRS{power/control}=="on"
    ATTRS{power/level}=="on"
    ATTRS{power/persist}=="1"
    ATTRS{power/runtime_active_kids}=="0"
    ATTRS{power/runtime_active_time}=="760862"
    ATTRS{power/runtime_enabled}=="forbidden"
    ATTRS{power/runtime_status}=="active"
    ATTRS{power/runtime_suspended_time}=="0"
    ATTRS{power/runtime_usage}=="1"
    ATTRS{product}=="u-blox GNSS receiver"
    ATTRS{quirks}=="0x0"
    ATTRS{removable}=="unknown"
    ATTRS{rx_lanes}=="1"
    ATTRS{speed}=="12"
    ATTRS{tx_lanes}=="1"
    ATTRS{urbnum}=="9"
    ATTRS{version}==" 1.10"
```






### udev rulesファイルの作成

適当なエディタを開いて適当な名前でrulesファイルを作成する。


```bash
sudo nano /etc/udev/rules.d/99-usb-gnss-receivers.rules
```

KERNELS==に先程確認したKERNELSの番号を書く。
SYMLINK+=に分かりやすい名前のシンボリックリンクを書く。
実行権限を追加する場合は` MODE="0777"`を追加する。

```bash:/etc/udev/rules.d/99-usb-gnss-receivers.rules
ACTION=="add", KERNELS=="3-2.1", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="fp9_1"
ACTION=="add", KERNELS=="3-2.4", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="f9p_2"
```

udevに新しいルールを適応する。

```bash
sudo udevadm control --reload-rules
sudo udevadm trigger
```

再起動

```bash
reboot
```

再起動すると/devに先程書いたシンボリックリンクの名前が追加されているので、`/dev/f9p_1`
の名前で使えるようになっているはず。

```bash
$ ls /dev | grep f9p
f9p_1
f9p_2
```




# おわりに

WindowsみたいにCOMポートで指定できたら楽なのに..


# 参考

https://qiita.com/umebosh/items/0db263bfbfa8b4b85be6

https://qiita.com/kiyonaga/items/182db6b8fc9afb33751c