WSL2でUSBデバイスを認識させる
2021年12月現在, この記事で紹介している方法は古い可能性があります.
最新の方法について, microsoft 公式の以下のページか, 他の最新情報サイトをご覧ください.
WSL2上でUSBデバイスを認識させるために, VirtualHereを用いた方法を, Linux側でUSB/IPの機能を有効にする方法も含めて, 説明します.
はじめに
WSL2は, Linuxのディストリビューションと, Windowsとの相互の通信方法が変更された, WSLの新しいバージョンのアーキテクチャです[1]. WSL1と比較して, WSL2にはシステムコールの完全な互換性を持ち, ファイルIOパフォーマンスが向上しています[2].
WSL2の欠点として, USBシリアルを使えない問題があります[3][4] (WSL1では, USBシリアルをサポートしています[5]). この問題により, パーフォーマンスが改善されたWSL2でも, Arduinoなどのシリアルを必要とする開発ができません.
これまでに, WSL2上でUSBデバイスを認識させる試みがされてきました. WSLのGitHubフォーラム#5158[6]では, https://github.com/cezanne/usbip-win といったUSB/IPツールを用いることを提案されており, 実際に試している件[7][8]がありました. しかしこの方法は, Windows側のUSB/IPのドライバを有効にするために, UEFIのセキュアブートを解除する必要があり, セキュリティの面で安全ではありません. また同じGitHubフォーラム#5158[6]で, さらに簡単な方法として, VirtualHereというソフトフェアを用いて, 解決する方法もありました. しかし, この方法において, Linux側のUSB/IPの機能を有効にする方法が詳しく書かれていません.
本稿では, WSL2上でUSBデバイスを認識させるために, VirtualHereを用いた方法を, Linux側でUSB/IPの機能を有効にする方法も含めて, 説明します.
準備
WSL2をインストールする
公式のリファレンスに従ってインストールします.
"Windows 10 用 Windows Subsystem for Linux のインストール ガイド". Microsoft. accessed at 2020-08-13
本稿では, Ubuntu 18.04を選択しています.
WSL2にGUI環境を構築する
WSL は, GUI デスクトップやアプリケーション (例: Gnome、KDE など) をサポートすることを目的としていません[9]. ですが, X Window System によって, WSL上でGUI環境を構築することが可能です. 「WSL2にGUI環境を構築する方法」は, すでに多くの情報がインターネット上にあるので調べてください.
一応, 筆者が作成した, "shell環境を整えるスクリプト"を公開しているので, そちらも参考にしてみてください.
方法
WSL Linux にUSBの機能を追加する
Microsoftが述べているように, WSL2はUSBをサポートしていません[3]. Microsoftが提供するLinux カーネルにUSBの機能が含まれていないので, 各自でUSB機能を追加したカーネルをコンパイルする必要があります. 幸い, WSL2 Linuxカーネルはオープンソースなので, カーネルのソースコードを入手することができます.
カーネル名を確認する.
~$ uname -v -r 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020
このカーネルは, 2020-02-19に作成されたことがわかります(現在日時: 2020-08-14).
カーネルのビルド準備
パッケージを更新する
~$ sudo apt update ~$ sudo apt upgrade
カーネルのビルドツールのインストール
~$ sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses-dev autoconf libudev-dev libtool
カーネルのビルド
WSL2 Kernel を/usr/src/[kernel_name]
にクローンする(本稿では, 4.19.104-microsoft-standard
になります).
~$ sudo git clone https://github.com/microsoft/WSL2-Linux-Kernel.git /usr/src/4.19.104-microsoft-standard ~$ cd /usr/src/4.19.104-microsoft-standard
各自のカーネルバージョンに合わせて, チェックアウトする.
/usr/src/4.19.104-microsoft-standard$ sudo git checkout v4.19.104
現在のカーネル設定をコピーする
/usr/src/4.19.104-microsoft-standard$ sudo cp /proc/config.gz config.gz /usr/src/4.19.104-microsoft-standard$ sudo gunzip config.gz /usr/src/4.19.104-microsoft-standard$ sudo mv config .config
menuconfig
を実行し, 追加したいカーネルモジュール(kernel modules) を選択する.
/usr/src/4.19.104-microsoft-standard$ sudo make menuconfig
menuconfig を操作し, USB kernel modules を選択します. 以下のようにフラグを設定していきます.
Device Drivers->USB support[*] Device Drivers->USB support->Support for Host-side USB[M] Device Drivers->USB support->Enable USB persist by default[*] Device Drivers->USB support->USB Modem (CDC ACM) support[M] Device Drivers->USB support->USB Mass Storage support[M] Device Drivers->USB support->USB/IP support[M] Device Drivers->USB support->VHCI hcd[M] Device Drivers->USB support->VHCI hcd->Number of ports per USB/IP virtual host controller(8) Device Drivers->USB support->Number of USB/IP virtual host controllers(1) Device Drivers->USB support->USB Serial Converter support[M] Device Drivers->USB support->USB Serial Converter support->USB FTDI Single Port Serial Driver[M] Device Drivers->USB support->USB Physical Layer drivers->NOP USB Transceiver Driver[M] Device Drivers->Network device support->USB Network Adapters[M] Device Drivers->Network device support->USB Network Adapters->[Deselect everything you don't care about] Device Drivers->Network device support->USB Network Adapters->Multi-purpose USB Networking Framework[M] Device Drivers->Network device support->USB Network Adapters->CDC Ethernet support (smart devices such as cable modems)[M] Device Drivers->Network device support->USB Network Adapters->Multi-purpose USB Networking Framework->Host for RNDIS and ActiveSync devices[M]
これらのフラグ設定は, 以下のサイトを参考にしています.
- "Adding USB support to WSL 2". GitHub. accessed at 2020-08-13
- "USB support to WSL2". Memorandum!. accessed at 2020-08-13
設定項目が多いので, ここでもう一度正しく設定できているか見直してみましょう. ここを間違うと後の手順で問題が起こる可能性があります.
カーネルとモジュールをビルドします. ビルド時は可能な限り多くのジョブ数を指定します(-j[number of cores]). この処理には, 少し時間がかかります.
sudo make -j 12 && sudo make modules_install -j 12 && sudo make install -j 12
make
コマンドのj
オプション についてj
オプションで, コンパイル時に同時に実行できるジョブ数(並列処理の数)を指定します. -j 2
とすれば, 2つ, -j 3
とすれば3つ同時に作業します.
最適なジョブ数には様々な言説があります[10]が, "makeの並列オプションは何を指定するべきか"によると, CPUのコア数 + 1" が最適なようです.
ビルドが完了すると, どのkernel modules がインストールされたか表示されます.
INSTALL drivers/hid/hid-generic.ko INSTALL drivers/hid/hid.ko INSTALL drivers/hid/usbhid/usbhid.ko INSTALL drivers/net/mii.ko INSTALL drivers/net/usb/cdc_ether.ko INSTALL drivers/net/usb/rndis_host.ko INSTALL drivers/net/usb/usbnet.ko INSTALL drivers/usb/class/cdc-acm.ko INSTALL drivers/usb/common/usb-common.ko INSTALL drivers/usb/core/usbcore.ko INSTALL drivers/usb/serial/ftdi_sio.ko INSTALL drivers/usb/phy/phy-generic.ko INSTALL drivers/usb/serial/usbserial.ko INSTALL drivers/usb/storage/usb-storage.ko INSTALL drivers/usb/usbip/usbip-core.ko INSTALL drivers/usb/usbip/vhci-hcd.ko DEPMOD 4.19.43-microsoft-standard
USBIP tools をビルド
/usr/src/4.19.104-microsoft-standard$ cd tools/usb/usbip/ /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo ./autogen.sh /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo ./configure /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo sed 's/-Werror//g' -i Makefile /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo sed 's/-Werror//g' -i src/Makefile /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo sed 's/-Werror//g' -i libsrc/Makefile /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo make install -j 12
USBIP tools ライブラリを, USBIP が見つけられる場所へ複製する.
/usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo cp libsrc/.libs/libusbip.so.0 /lib/libusbip.so.0
カーネルをコピー
$ sudo cp /usr/src/4.19.104-microsoft-standard/vmlinux /mnt/c/Users/<username>/
WSLの設定ファイルの作成
ビルドされたカーネルを指定するための, 設定ファイルを作成します.
C:\Users\{ユーザ名}\
内に以下の内容の設定ファイル.wslconfig
を作成します.
[WSL2] kernel=C:\\Users\\<username>\\vmlinux
設定を反映するために, 一度WSLをシャットダウンします. PoweShellを起動し, 以下のコマンドを入力します.
wsl --shutdown
WSLをシャットダウンすると, 現在起動しているwslインスタンスが終了します.
ビルドしたカーネルを起動
WSLを起動します.
wslカーネル名を確認
~$ uname -r -v 4.19.104-microsoft-standard #2 SMP Fri Aug 14 22:38:30 JST 2020
ビルド日時が, 2020-08-14であることが確認でき, 自身がビルドしたものであることが分かります.
USBに関連するカーネルモジュールの起動
USBに関連する, すべてのカーネルモジュールを起動するためのスクリプトを, ホームディレクトリに作成します. 注意点として, usbcore
とusb-common
をはじめに読み込みます. スクリプト名はstartusb.sh
とします.
startusb.sh
#!/bin/bash sudo modprobe usbcore sudo modprobe usb-common sudo modprobe hid-generic sudo modprobe hid sudo modprobe usbnet sudo modprobe cdc_ether sudo modprobe rndis_host sudo modprobe usbserial sudo modprobe usb-storage sudo modprobe cdc-acm sudo modprobe ftdi_sio sudo modprobe usbip-core sudo modprobe vhci-hcd echo $(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
最終行の処理で表示されるIPアドレスは, Windows host のIPアドレスになります. USB/IPのクライアントでホストのIPアドレスを入力する際に参考になります.
シェルスクリプトの改行コードは, CR + LF
ではなく, LF
にする必要があります.
startusb.sh
に実行権限を与えます.
~$ sudo chmod +x startusb.sh
startusb.sh
を実行し, USBに関するカーネルモジュールを起動します.
~$ ./startusb.sh
- Errorが出る場合
- カーネルモジュールの読み込みができない
→ カーネルのビルド設定が合っているか確認する.
- シェルスクリプトの改行コードが
CR + LF
である→
LF
にする
- カーネルモジュールの読み込みができない
モジュールが起動できているか確認する.
~$ lsmod Module Size Used by vhci_hcd 32768 0 usbip_core 16384 1 vhci_hcd ftdi_sio 49152 0 cdc_acm 32768 0 usb_storage 61440 0 usbserial 36864 1 ftdi_sio rndis_host 16384 0 cdc_ether 16384 1 rndis_host usbnet 36864 2 rndis_host,cdc_ether mii 16384 1 usbnet hid_generic 16384 0 hid 102400 1 hid_generic usbcore 200704 8 ftdi_sio,usbserial,usbnet,cdc_acm,usb_storage,rndis_host,cdc_ether,vhci_hcd usb_common 16384 2 usbcore,vhci_hcd
VirtualHere のインストール
VirtualHere は, USB/IPを簡単に使えるソフトウェアです.
VirtualHere USB Client をLinux側にインストール
バージョンは, "VirtualHere Client for Linux (amd64)"を選択します.
~$ wget https://www.virtualhere.com/sites/default/files/usbclient/vhuit64 ~$ chmod 777 vhuit64 ~$ sudo ./vhuit64
Windows USB Server をインストールする.
上記サイトから, "VirtualHere Server"をダウンロードします. 32bit版, 64bit版があるので適したものをダウンロードしてください.
試用バージョンでは, 一度に一つのデバイスのみ使用することができます. たとえば, 二つのArduinoをWSL2には接続できません.
使ってみる
では, 実際にWSL2でUSBデバイスを認識させてみましょう. 手元にUSBデバイスを準備します. 本稿では, "Arduino UNO"を用意しました.
- Windows USB Serverを起動します.
実行ファイル名は, "vhusbdwin64.exe"です.
初回起動時は, ファイアウォールの許可や, 依存ライブラリのインストールがあります.
- WSLとX Server(WSLからのGUIを受け付けるもの)を立ち上げます.
- USBに関連するモジュールを読み込みます.
~$ sudo ./startusb.sh 172.28.80.1
- VirtualHere USB Clientを起動します.
~$ sudo ./vhuit64
- Clientをサーバに接続します.
USB Hubs
を右クリック →Specify Hubs
をクリック →Hubs
タブからAdd
を選択表示されている
server.local:7575
のserver.local
の部分を, 手順3で表示されているIPアドレス(本稿の場合,172.28.80.1
)に置き換える. つまり,172.28.80.1:7575
と入力.「OK」を押し, サーバに接続
- Arduino UNO をPCに接続します.
- Arduino UNO をWSLに接続します.
USB Client から, 対象デバイスを右クリックし,
Use this device
をクリック - 接続確認
別シェルで,
dmesg
コマンドを実行~$ dmesg [ 6033.084345] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(12) [ 6033.084348] vhci_hcd vhci_hcd.0: devid(4) speed(2) speed_str(full-speed) [ 6033.362648] vhci_hcd: vhci_device speed not set [ 6033.432601] usb 1-1: new full-speed USB device number 5 using vhci_hcd [ 6033.512607] vhci_hcd: vhci_device speed not set [ 6033.582600] usb 1-1: SetAddress Request (5) to port 0 [ 6033.633611] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
ttyACM0
に接続されていることが確認できる.lsusb
コマンドを実行~$ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 005: ID 2341:0043 Arduino SA Uno R3 (CDC ACM) Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Arduino UNO が接続されていることが確認できる.
使用例
USBシリアル
ArduinoをttyACM0
に接続後
ttyACM0
に読み書きの権限を与える.
~$ sudo chmod 666 /dev/ttyACM0
あとは, pythonなどで通信
USBストレージ
USBストレージを接続後, dmesg
コマンドでsdc1
に接続されていることを確認.
USB のマウントポイントを作成
~$ sudo mkdir /mnt/usb
/mnt/usb
にマウント
~$ sudo mount /dev/sdc1 /mnt/usb
ファイル操作後, アンマウント
~$ sudo umount /dev/sdc1
参考文献
- ^ "WSL 2 の新機能". Microsoft. accessed at 2020-08-13
- ^ "WSL 1 と WSL 2 の比較". Microsoft. accessed at 2020-08-13
- ^ a b "WSL 2 に関する FAQ". Microsoft. accessed at 2020-08-13
- ^ "WSL2: Ubuntu 18.04 Serial devices are no longer mounted properly". GitHub. accessed at 2020-08-13
- ^ "Serial Support on the Windows Subsystem for Linux". Microsoft. accessed at 2020-08-13
- ^ a b "[WSL 2] Attaching an USB device". GitHub. accessed at 2020-08-13
- ^ "USB support to WSL2". Memorandum!. accessed at 2020-08-13
- ^ "Adding USB support to WSL 2". GitHub. accessed at 2020-08-13
- ^ "Windows Subsystem for Linux に関してよく寄せられる質問". Microsoft. accessed at 2020-08-13
- ^ "makeの並列オプションは何を指定するべきか". HatenaBlog. accessed at 2020-08-13