目次 このページのソースコードを表示

WSL2でUSBデバイスを認識させる

公開日: 更新日:

WSL2上でUSBデバイスを認識させるために, VirtualHereを用いた方法を, Linux側でUSB/IPの機能を有効にする方法も含めて, 説明します.

WSL2上でArduino UNO が認識されている
WSL2上でArduino UNO が認識されている

はじめに

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を実行すると, このような設定画面が出ます
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]

これらのフラグ設定は, 以下のサイトを参考にしています.

CAUTION

設定項目が多いので, ここでもう一度正しく設定できているか見直してみましょう. ここを間違うと後の手順で問題が起こる可能性があります.

カーネルとモジュールをビルドします. ビルド時は可能な限り多くのジョブ数を指定します(-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
WARNING

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に関連する, すべてのカーネルモジュールを起動するためのスクリプトを, ホームディレクトリに作成します. 注意点として, usbcoreusb-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アドレスを入力する際に参考になります.

CAUTION

シェルスクリプトの改行コードは, 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"を用意しました.

  1. Windows USB Serverを起動します.

    実行ファイル名は, "vhusbdwin64.exe"です.

    初回起動時は, ファイアウォールの許可や, 依存ライブラリのインストールがあります.

    USB Server が立ち上がる
    USB Server が立ち上がる
  2. WSLとX Server(WSLからのGUIを受け付けるもの)を立ち上げます.
  3. USBに関連するモジュールを読み込みます.
                    ~$ sudo ./startusb.sh
                    172.28.80.1
    
  4. VirtualHere USB Clientを起動します.
                    ~$ sudo ./vhuit64
    
    USB Client が立ち上がる
    USB Client が立ち上がる
  5. Clientをサーバに接続します.

    USB Hubsを右クリック → Specify Hubs をクリック → Hubs タブから Add を選択

    表示されているserver.local:7575server.localの部分を, 手順3で表示されているIPアドレス(本稿の場合, 172.28.80.1)に置き換える. つまり, 172.28.80.1:7575と入力.

    「OK」を押し, サーバに接続

  6. Arduino UNO をPCに接続します.
    COMポートが表示されている
    COMポートが表示されている
  7. Arduino UNO をWSLに接続します.

    USB Client から, 対象デバイスを右クリックし, Use this device をクリック

    対象デバイスを右クリックし, Use this device をクリック
    対象デバイスを右クリックし, Use this device をクリック
    使用中と表示される
    使用中と表示される
  8. 接続確認

    別シェルで, 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 が接続されていることが確認できる.

    WSL2上でArduino UNO が認識されている
    WSL2上で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

参考文献

  1. ^ "WSL 2 の新機能". Microsoft. accessed at 2020-08-13
  2. ^ "WSL 1 と WSL 2 の比較". Microsoft. accessed at 2020-08-13
  3. ^ a b "WSL 2 に関する FAQ". Microsoft. accessed at 2020-08-13
  4. ^ "WSL2: Ubuntu 18.04 Serial devices are no longer mounted properly". GitHub. accessed at 2020-08-13
  5. ^ "Serial Support on the Windows Subsystem for Linux". Microsoft. accessed at 2020-08-13
  6. ^ a b "[WSL 2] Attaching an USB device". GitHub. accessed at 2020-08-13
  7. ^ "USB support to WSL2". Memorandum!. accessed at 2020-08-13
  8. ^ "Adding USB support to WSL 2". GitHub. accessed at 2020-08-13
  9. ^ "Windows Subsystem for Linux に関してよく寄せられる質問". Microsoft. accessed at 2020-08-13
  10. ^ "makeの並列オプションは何を指定するべきか". HatenaBlog. accessed at 2020-08-13
「https://contentsviewer.work/Master/WSL/Tips/WSL2-USB/WSL2-USB」から取得