Raspberry PI ZeroのUSB OTGで遊んだ
Raspberry PI Zeroのセットアップで、電源供給用じゃない方のマイクロUSBポートとホストPCを繋いで仮想ネットワーク経由で接続する云々の情報をみて、どういう仕組みでやっているんだろうと調べてみたら、Raspberry PI ZeroではUSB OTG(On-The-Go)が使えるということを知った。
USB OTG (On-The-Go)
USB OTGはAndroidのUSBポートにマウスとかキーボード繋げばマウスやキーボードとして動くけど、同じポートでPCに繋いだ時はPC側でストレージとして見えるみたいなアレっぽい。
USB On-The-Go(略してUSB OTG)は、USB機器どうしを直接接続するインタフェース規格である。パソコン等をホストとせずに、動作時にホスト機器を動的に切り替える機能を拡張したもの。 IEEE 1394のように直接接続できるので、いろいろな機器に応用できる。
調べてみたら手持ちのRaspberry PI B系では構造上できないようなので、Raspberry PI Zero WHを買ってみた。送料とか色々考えてとりあえずAmazonでポチリ。
Raspberry Pi Zero WH GPIOピンヘッダー ハンダ付け済み Wi-Fi & Bluetooth&ヒートシンク付
- 出版社/メーカー: Raspberrypi
- メディア: エレクトロニクス
- この商品を含むブログを見る
シリアル通信したり、ネットワークにしたり、キーボードにしたりと色々できるみたいだけど、とりあえず今回はストレージとして使う方法を試してみた。
USB OTGでマスストレージ
環境は以前に作成したRaspbian Stretch Liteの2019-04-08バージョンのパーティションをいじって、bootとrootfsの他にextrafsを追加したもの。今出ているBusterの2019-06-20バージョンはとりあえず保留。
環境準備
まずはUSB OTGを利用するために,/boot/config.txt
に次のUSB OTGの有効化を追加する。
dtoverlay=dwc2
反映するためにOSを再起動する。
続いて、ストレージとして利用するためのパーティションを作成する。イメージファイルとかでも良いらしいけど、今回は専用パーティションを作って行う。
現状のパーティションが次のとおり。
$ sudo fdisk -l /dev/mmcblk0 Disk /dev/mmcblk0: 7.4 GiB, 7932477440 bytes, 15493120 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xc1dc39e5 Device Boot Start End Sectors Size Id Type /dev/mmcblk0p1 8192 96042 87851 42.9M c W95 FAT32 (LBA) /dev/mmcblk0p2 98304 6389759 6291456 3G 83 Linux /dev/mmcblk0p3 6389760 8388607 1998848 976M 83 Linux
これに1GBのFAT32パーティションを追加して次の様にした。
$ sudo fdisk -l /dev/mmcblk0 Disk /dev/mmcblk0: 7.4 GiB, 7932477440 bytes, 15493120 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xc1dc39e5 Device Boot Start End Sectors Size Id Type /dev/mmcblk0p1 8192 96042 87851 42.9M c W95 FAT32 (LBA) /dev/mmcblk0p2 98304 6389759 6291456 3G 83 Linux /dev/mmcblk0p3 6389760 8388607 1998848 976M 83 Linux /dev/mmcblk0p4 8388608 10485759 2097152 1G b W95 FAT32
パーティションを切った後にOSを再起動して、vfatでフォーマットする。
$ sudo mkfs -t vfat /dev/mmcblk0p4
これでパーティションの準備は完了。
マスストレージの有効化と解除
環境を準備して次のコマンドを実行すると接続しているホストPC側にUSBストレージとして認識させることができる。 パラメータのオプションは linux/mass-storage.txt at master · torvalds/linux · GitHub を参考にした。
色々試していたらWindowsでUSBストレージとして認識させるにはremovable=y
が必要だった。
$ sudo modprobe g_mass_storage file=/dev/mmcblk0p4 removable=y
lsmodで確認すると次の様に表示される。
$ lsmod | grep g_mass_storage g_mass_storage 4651 0 usb_f_mass_storage 38658 2 g_mass_storage libcomposite 49673 2 g_mass_storage,usb_f_mass_storage
dmesgを確認すると次のようなログが確認できる。
[ 46.534849] Mass Storage Function, version: 2009/09/11 [ 46.534873] LUN: removable file: (no medium) [ 46.535068] LUN: removable file: /dev/mmcblk0p4 [ 46.535077] Number of LUNs=1 [ 46.537657] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11 [ 46.537675] g_mass_storage gadget: userspace failed to provide iSerialNumber [ 46.537681] g_mass_storage gadget: g_mass_storage ready [ 46.537695] dwc2 20980000.usb: bound driver g_mass_storage [ 46.654687] dwc2 20980000.usb: new device is high-speed [ 47.346817] dwc2 20980000.usb: new device is high-speed [ 47.414698] dwc2 20980000.usb: new device is high-speed [ 47.632787] dwc2 20980000.usb: new address 1 [ 47.657761] g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage
マスストレージを解除するには次のコマンドを実行する。
$ sudo modprobe -r g_mass_storage
OS起動時にマスストレージを有効にしてみる
準備が整ったので、OS起動時に自動的にマスストレージを有効にできるようにしてみる。
最初に思いつくのは単純な方法で/etc/rc.local
に起動コマンドを書いておくというもの。
/etc/rc.local
を使った方法
/etc/rc.local
を次の様に編集する。
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi # for MASS Storage modprobe g_mass_storage file=/dev/mmcblk0p4 removable=y exit 0
これで再起動して動作確認。
dmesgでマスストレージが有効化されたタイミングを見てみる。
[ 25.047610] Mass Storage Function, version: 2009/09/11 [ 25.047631] LUN: removable file: (no medium) [ 25.047818] LUN: removable file: /dev/mmcblk0p4 [ 25.047827] Number of LUNs=1 [ 25.061717] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11 [ 25.061738] g_mass_storage gadget: userspace failed to provide iSerialNumber [ 25.061744] g_mass_storage gadget: g_mass_storage ready [ 25.061758] dwc2 20980000.usb: bound driver g_mass_storage [ 25.179253] dwc2 20980000.usb: new device is high-speed [ 25.558496] dwc2 20980000.usb: new device is high-speed [ 25.684040] dwc2 20980000.usb: new device is high-speed [ 25.761661] dwc2 20980000.usb: new address 1 [ 25.785904] g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage
/etc/rc.local
だとOS起動の最後のほうで動くので、25秒くらいかかってるのがわかる。
これだと、ホストPC側に繋いでからUSBストレージとして認識されるまでが結構待たされる気がする。
systemdでサービス化する方法
次にsystemdでoneshotなサービスを作って実行する方法でやってみる。
/etc/rc.local
は元に戻しておいて、/lib/systemd/system/storage.service
を次の様に作る。
[Unit] Description = MASS Storage Service After = local-fs.target [Service] ExecStart = /sbin/modprobe g_mass_storage file=/dev/mmcblk0p4 Type = oneshot [Install] WantedBy = multi-user.target
作ったサービスを有効化して、再起動する。
$ sudo systemctl enable storage.service
再びdmesgでマスストレージが有効化されたタイミングを見てみる。
[ 15.075042] Mass Storage Function, version: 2009/09/11 [ 15.075070] LUN: removable file: (no medium) [ 15.075312] LUN: file: /dev/mmcblk0p4 [ 15.075326] Number of LUNs=1 [ 15.083453] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11 [ 15.083479] g_mass_storage gadget: userspace failed to provide iSerialNumber [ 15.083488] g_mass_storage gadget: g_mass_storage ready [ 15.083507] dwc2 20980000.usb: bound driver g_mass_storage [ 15.203126] dwc2 20980000.usb: new device is high-speed [ 15.225530] uart-pl011 20201000.serial: no DMA platform data [ 15.582358] dwc2 20980000.usb: new device is high-speed [ 15.707818] dwc2 20980000.usb: new device is high-speed [ 15.785478] dwc2 20980000.usb: new address 1 [ 15.809602] g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage
これだと15秒くらいで有効化されている。だいたい10秒くらい縮まったか。
initramfsで有効化する方法
そもそもSDカードのパーティションへのアクセスとmodprobeが使えるタイミングなら良いわけで、initramfsでやってしまえば良いのでは...?と思ったのでやってみる。
systemdのサービスは無効化しておく。
$ sudo systemctl disable storage.service
そして、/etc/initramfs-tools/hooks/usbstorage
を作る。
#!/bin/sh . /usr/share/initramfs-tools/scripts/functions . /usr/share/initramfs-tools/hook-functions manual_add_modules g_mass_storage
作った/etc/initramfs-tools/hooks/usbstorage
に実行権限を与えて、オーナーを変えておく。
$ sudo chmod +x /etc/initramfs-tools/hooks/usbstorage $ sudo chown root.root /etc/initramfs-tools/hooks/usbstorage
次に/etc/initramfs-tools/scripts/local-bottom/usbstorage
を作る。
#!/bin/sh PREREQ="" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac . /scripts/functions log_begin_msg "Setting up usbstorage:" modprobe g_mass_storage file=/dev/mmcblk0p4 removable=y log_end_msg "Done..." exit 0
こちらも実行権限を与えて、オーナーを変えておく。
$ sudo chmod +x /etc/initramfs-tools/scripts/local-bottom/usbstorage $ sudo chown root.root /etc/initramfs-tools/scripts/local-bottom/usbstorage
これらを使ってinitramfsを作る。
$ sudo mkinitramfs -o /boot/initrd.gz
/boot/config.txt
を編集し、末尾に次のinitramfs有効化を追加する。
# enable initramfs initramfs initrd.gz
改めて再起動して動作を確認する。
dmesgを見ると,
[ 4.672923] Mass Storage Function, version: 2009/09/11 [ 4.672945] LUN: removable file: (no medium) [ 4.673187] LUN: removable file: /dev/mmcblk0p4 [ 4.673318] Number of LUNs=1 [ 4.679278] g_mass_storage gadget: Mass Storage Gadget, version: 2009/09/11 [ 4.679300] g_mass_storage gadget: userspace failed to provide iSerialNumber [ 4.679308] g_mass_storage gadget: g_mass_storage ready [ 4.679328] dwc2 20980000.usb: bound driver g_mass_storage [ 4.795750] dwc2 20980000.usb: new device is high-speed [ 5.172263] dwc2 20980000.usb: new device is high-speed [ 5.250174] dwc2 20980000.usb: new address 1 [ 5.274662] g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage
起動してから5秒くらいで有効化されるようになった。30秒近く待たされるより速くなったと思う。