---
parent: ../Tips
title: WSL2でUSBデバイスを認識させる
date: 2020-08-15
tags: WSL, WSL2, USB
---

[この方法は古い可能性があります::WARNING]
====
    2021年12月現在, この記事で紹介している方法は古い可能性があります.
    
    最新の方法について,
    microsoft 公式の以下のページか, 他の最新情報サイトをご覧ください.
    
    * ["Connecting USB devices to WSL". microsoft. accessed at 2021-12-16.](https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/)
====

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

![WSL2上でArduino UNO が認識されている](CURRENT_DIR/Images/lsusb.jpg)

===

# はじめに
    WSL2は, Linuxのディストリビューションと, Windowsとの相互の通信方法が変更された, WSLの新しいバージョンのアーキテクチャです^[wsl2-new].
    WSL1と比較して, WSL2にはシステムコールの完全な互換性を持ち, ファイルIOパフォーマンスが向上しています^[wsl1-wsl2].
    
    WSL2の欠点として, USBシリアルを使えない問題があります^[wsl2-faq]^[wsl-issue-4322]
    (WSL1では, USBシリアルをサポートしています^[wsl1-serial-support]).
    この問題により, パーフォーマンスが改善されたWSL2でも, Arduinoなどのシリアルを必要とする開発ができません.
    
    これまでに, WSL2上でUSBデバイスを認識させる試みがされてきました. 
    WSLのGitHubフォーラム#5158^[wsl2-attach-usb]では, <https://github.com/cezanne/usbip-win> といったUSB/IPツールを用いることを提案されており, 
    実際に試している件^[wsl2-usb-support]^[wsl2-adding-usb-support]がありました. 
    しかしこの方法は, Windows側のUSB/IPのドライバを有効にするために, UEFIのセキュアブートを解除する必要があり, セキュリティの面で安全ではありません.
    また同じGitHubフォーラム#5158^[wsl2-attach-usb]で, さらに簡単な方法として, [VirtualHere](https://www.virtualhere.com)というソフトフェアを用いて, 解決する方法もありました.
    しかし, この方法において, Linux側のUSB/IPの機能を有効にする方法が詳しく書かれていません.
    
    本稿では, WSL2上でUSBデバイスを認識させるために, [VirtualHere](https://www.virtualhere.com)を用いた方法を, 
    Linux側でUSB/IPの機能を有効にする方法も含めて, 説明します.
    
# 準備
    # WSL2をインストールする
        公式のリファレンスに従ってインストールします.
        
        ["Windows 10 用 Windows Subsystem for Linux のインストール ガイド"](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10). Microsoft. accessed at 2020-08-13
        
        本稿では, //Ubuntu 18.04//を選択しています.
        
    # WSL2にGUI環境を構築する
        WSL は, GUI デスクトップやアプリケーション (例: Gnome、KDE など) をサポートすることを目的としていません^[wsl-faq].
        ですが, X Window System によって, WSL上でGUI環境を構築することが可能です.
        「WSL2にGUI環境を構築する方法」は, すでに多くの情報がインターネット上にあるので調べてください.
        
        一応, 筆者が作成した, "shell環境を整えるスクリプト"を公開しているので, そちらも参考にしてみてください.
        
        * [/ShellScript/Setup]

# 方法
    # WSL Linux にUSBの機能を追加する
        Microsoftが述べているように, WSL2はUSBをサポートしていません^[wsl2-faq]. 
        Microsoftが提供するLinux カーネルにUSBの機能が含まれていないので, 各自でUSB機能を追加したカーネルをコンパイルする必要があります.
        幸い, [WSL2 Linuxカーネルはオープンソース](https://github.com/microsoft/WSL2-Linux-Kernel)なので, 
        カーネルのソースコードを入手することができます.
        
        # カーネル名を確認する.
            ```shell
                ~$ uname -v -r
                4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020
            ```
            
            このカーネルは, 2020-02-19に作成されたことがわかります(現在日時: 2020-08-14).
        
        # カーネルのビルド準備
            パッケージを更新する
            
            ```shell
                ~$ sudo apt update
                ~$ sudo apt upgrade
            ```
            
            カーネルのビルドツールのインストール
            
            ```shell
                ~$ 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`になります). 
                * [GitHub/microsoft/WSL2-Linux-Kernel](https://github.com/microsoft/WSL2-Linux-Kernel)
            
            ```shell
                ~$ 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
            ```
            
            各自のカーネルバージョンに合わせて, チェックアウトする.
            
            ```shell
                /usr/src/4.19.104-microsoft-standard$ sudo git checkout v4.19.104
            ```
            
            現在のカーネル設定をコピーする
            
            ```shell
                /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) を選択する.
            
            ```shell
                /usr/src/4.19.104-microsoft-standard$ sudo make menuconfig
            ```
            
            ![`menuconfig`を実行すると, このような設定画面が出ます](CURRENT_DIR/Images/menuconfig.jpg)
            
            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"](https://github.com/rpasek/usbip-wsl2-instructions). GitHub. accessed at 2020-08-13
            * ["USB support to WSL2"](http://ktkr3d.github.io/2020/07/06/USB-support-to-WSL2/). Memorandum!. accessed at 2020-08-13
            
            [::CAUTION]
            ===========
                設定項目が多いので, ここでもう一度正しく設定できているか見直してみましょう.
                ここを間違うと後の手順で問題が起こる可能性があります.
            ===========
            
            カーネルとモジュールをビルドします. ビルド時は可能な限り多くのジョブ数を指定します(-j[number of cores]).
            この処理には, 少し時間がかかります.
            
            ```shell
                sudo make -j 12 && sudo make modules_install -j 12 && sudo make install -j 12
            ```
            
            [`make`コマンドの`j`オプション について]
            ==========
                `j`オプションで, コンパイル時に同時に実行できるジョブ数(並列処理の数)を指定します.
                `-j 2`とすれば, 2つ, `-j 3`とすれば3つ同時に作業します.
                
                最適なジョブ数には様々な言説があります^[make-j]が, 
                ["makeの並列オプションは何を指定するべきか"](http://lpha-z.hatenablog.com/entry/2018/12/30/231500)によると,
                CPUのコア数 + 1" が最適なようです.
            ==========
            
            ビルドが完了すると, どのkernel modules がインストールされたか表示されます.
            
            ```shell
                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 をビルド
            
            ```shell
                /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 が見つけられる場所へ複製する.
            
            ```shell
                /usr/src/4.19.104-microsoft-standard/tools/usb/usbip$ sudo cp libsrc/.libs/libusbip.so.0 /lib/libusbip.so.0
            ```
            
            カーネルをコピー
            
            ```shell
                $ 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を起動し, 以下のコマンドを入力します.
            
            ```shell
                wsl --shutdown
            ```
            
            [::WARNING]
            ===========
                WSLをシャットダウンすると, 現在起動しているwslインスタンスが終了します.
            ===========
        
        # ビルドしたカーネルを起動
            WSLを起動します.
            
            wslカーネル名を確認
            
            ```shell
                ~$ 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`:
                
                ```shell
                    #!/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`に実行権限を与えます.
            
            ```shell
                ~$ sudo chmod +x startusb.sh
            ```
            
            `startusb.sh`を実行し, USBに関するカーネルモジュールを起動します.
            
            ```shell
                ~$ ./startusb.sh
            ```
            
            Errorが出る場合:
                * カーネルモジュールの読み込みができない
                    -> カーネルのビルド設定が合っているか確認する.
                
                * シェルスクリプトの改行コードが`CR + LF`である
                    -> `LF`にする
            
            モジュールが起動できているか確認する.
            
            ```shell
                ~$ 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"](https://virtualhere.com/home)
        
        # VirtualHere USB Client をLinux側にインストール
            * [VirtualHere USB Client](https://virtualhere.com/usb_client_software)
            
            バージョンは, "VirtualHere Client for Linux (amd64)"を選択します.
            
            ```shell
                ~$ wget https://www.virtualhere.com/sites/default/files/usbclient/vhuit64
                ~$ chmod 777 vhuit64
                ~$ sudo ./vhuit64
            ```
        
        # Windows USB Server をインストールする.
            * [Windows USB Server](https://virtualhere.com/windows_server_software)
            
            上記サイトから, "VirtualHere Server"をダウンロードします.
            32bit版, 64bit版があるので適したものをダウンロードしてください.
            
            試用バージョンでは, 一度に一つのデバイスのみ使用することができます.
            たとえば, 二つのArduinoをWSL2には接続できません. 
    
    # 使ってみる
        では, 実際にWSL2でUSBデバイスを認識させてみましょう.
        手元にUSBデバイスを準備します. 本稿では, "Arduino UNO"を用意しました.
        
        1. Windows USB Serverを起動します. 
            実行ファイル名は, "vhusbdwin64.exe"です.
            
            初回起動時は, ファイアウォールの許可や, 依存ライブラリのインストールがあります.
        
            ![USB Server が立ち上がる](CURRENT_DIR/Images/usb-server.jpg)
        
        2. WSLとX Server(WSLからのGUIを受け付けるもの)を立ち上げます.
        
        3. USBに関連するモジュールを読み込みます.
            
            ```shell
                ~$ sudo ./startusb.sh
                172.28.80.1
            ```
        
        4. VirtualHere USB Clientを起動します.
            ```shell
                ~$ sudo ./vhuit64
            ```
            
            ![USB Client が立ち上がる](CURRENT_DIR/Images/usb-client.jpg)
        
        5. Clientをサーバに接続します.
            `USB Hubs`を右クリック -> `Specify Hubs` をクリック -> `Hubs` タブから `Add` を選択
            
            表示されている`server.local:7575`の`server.local`の部分を, 
            手順3で表示されているIPアドレス(本稿の場合, `172.28.80.1`)に置き換える.
            つまり, `172.28.80.1:7575`と入力.
            
            「OK」を押し, サーバに接続
            
        5. Arduino UNO をPCに接続します.
            
            ![COMポートが表示されている](CURRENT_DIR/Images/usb-client-listed.jpg)
        
        6. Arduino UNO をWSLに接続します.
            USB Client から, 対象デバイスを右クリックし, `Use this device` をクリック
            
            ![対象デバイスを右クリックし, `Use this device` をクリック](CURRENT_DIR/Images/usb-client-use.jpg)
            
            ![使用中と表示される](CURRENT_DIR/Images/usb-client-in-use.jpg)
        
        7. 接続確認
            別シェルで, `dmesg`コマンドを実行
            
            ```shell
                ~$ 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`コマンドを実行
            
            ```shell
                ~$ 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 が認識されている](CURRENT_DIR/Images/lsusb.jpg)
            
# 使用例
    # USBシリアル
        Arduinoを`ttyACM0`に接続後
        
        `ttyACM0`に読み書きの権限を与える.
        ```shell
            ~$ sudo chmod 666 /dev/ttyACM0
        ```
        
        あとは, pythonなどで通信
    
    # USBストレージ
        USBストレージを接続後, `dmesg`コマンドで`sdc1`に接続されていることを確認.
        
        USB のマウントポイントを作成
        ```shell
            ~$ sudo mkdir /mnt/usb
        ```
        
        `/mnt/usb` にマウント
        ```shell
            ~$ sudo mount /dev/sdc1 /mnt/usb
        ```
        
        ファイル操作後, アンマウント
        ```shell
            ~$ sudo umount /dev/sdc1
        ```


# 参考文献
    [wsl2-new]: ["WSL 2 の新機能"](https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-index"). \
                Microsoft. accessed at 2020-08-13
                
    [wsl1-wsl2]: ["WSL 1 と WSL 2 の比較"](https://docs.microsoft.com/ja-jp/windows/wsl/compare-versions). \
                 Microsoft. accessed at 2020-08-13
                 
    [wsl2-faq]: ["WSL 2 に関する FAQ"](https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-faq). \
                Microsoft. accessed at 2020-08-13
                
    [wsl-faq]: ["Windows Subsystem for Linux に関してよく寄せられる質問"](https://docs.microsoft.com/ja-jp/windows/wsl/faq). \
                Microsoft. accessed at 2020-08-13
                
    [wsl-issue-4322]: ["WSL2: Ubuntu 18.04 Serial devices are no longer mounted properly"](https://github.com/microsoft/WSL/issues/4322). \
                      GitHub. accessed at 2020-08-13
    
    [wsl1-serial-support]: ["Serial Support on the Windows Subsystem for Linux"](https://docs.microsoft.com/ja-jp/archive/blogs/wsl/serial-support-on-the-windows-subsystem-for-linux). \
                           Microsoft. accessed at 2020-08-13

    [wsl2-attach-usb]: ["[WSL 2] Attaching an USB device"](https://github.com/microsoft/WSL/issues/5158). \
                       GitHub. accessed at 2020-08-13
    
    [wsl2-usb-support]: ["USB support to WSL2"](http://ktkr3d.github.io/2020/07/06/USB-support-to-WSL2/). \
                        Memorandum!. accessed at 2020-08-13
    
    [wsl2-adding-usb-support]: ["Adding USB support to WSL 2"](https://github.com/rpasek/usbip-wsl2-instructions). \
                               GitHub. accessed at 2020-08-13

    [make-j]: ["makeの並列オプションは何を指定するべきか"](http://lpha-z.hatenablog.com/entry/2018/12/30/231500). \
              HatenaBlog. accessed at 2020-08-13