0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SoftBank Air ターミナル6はUSB NICになる。

0
Last updated at Posted at 2026-09-04

SoftBank Air ターミナル6はUSB NICになる。Windows/LinuxとUSB直結して1.4Gbpsを確認

TL;DR

SoftBank Air ターミナル6(SBA6D)は、内部のUSBコントローラをDEVICE側へ切り替え、Linux USB GadgetのCDC-NCMを構成すると、Windows/Linux PCとUSB直結できるUSBネットワークアダプタとして動作します。

実機では、

  • T6A側:ncm0
  • Windows側:UsbNcm Host Device
  • Windows標準ドライバ:UsbNcm.sys
  • VID/PID:2C7C:7006

として認識しました。

今回のWindows直結構成は、

T6A      192.168.77.1/24
Windows  192.168.77.2/24

です。

iperf3では、SuperSpeed接続時に、

T6A → Windows:約1.37~1.39 Gbit/s
Windows → T6A:約1.00~1.01 Gbit/s

を安定して確認しました。

重要なのは、T6Aでは単にConfigFSへ ncm.gs8 を追加するだけでは不十分だったことです。

実機で再現できた成功条件は、

USB Host未接続
    ↓
mode=3
    ↓
xHCI ABSENT
    ↓
GPIO322 LOW
    ↓
USB-A VBUS 0V
    ↓
f5 -> ncm.gs8
    ↓
UDC unbind / rebind
    ↓
Windows/Linux Host接続
    ↓
SuperSpeed

です。

さらに今回、GPIO322 がHIGHのままだと同じケーブル・同じWindows USBポートでもUSB 2.0 High-Speedへフォールバックし、実測約333~350Mbpsになりました。

その状態から、

echo 0 > /sys/class/gpio/gpio322/value

でGPIO322をLOWへ戻し、UDCをrebindすると、

current_speed = super-speed

へ復帰し、再び約1.4Gbpsが出ました。

つまりGPIO322は、単なる安全上のVBUS制御だけでなく、この実機でSuperSpeedリンクを成立させるうえでも重要な条件でした。


最初に重要:USB A-Aなら何でもよいわけではない

今回の接続にはUSB 3.xのA-Aケーブルを使用しています。

ここはかなり重要です。

USB-Aオス同士のケーブルには、外観が同じでも配線や用途が異なるものがあります。

特にPCと機器のUSB-Aポート同士を接続する場合、双方の5V VBUSを不用意に直結する構成は避ける必要があります。

今回のT6Aでは、Host接続前に、

GPIO322 = LOW
USB-A VBUS = 0V

を実機で確認してから接続しています。

したがってこの記事の「USB直結」は、

USB-A端子同士を適当なA-Aケーブルでつなげばよい

という意味ではありません。

USB roleとVBUS状態を確認したうえで接続しています。


T6AをUSB NICにするとどう見えるのか

構成はシンプルです。

Windows / Linux PC
        │
        │ USB 3.x
        │ CDC-NCM
        ▼
SoftBank Air ターミナル6
        │
        ▼
      ncm0

普通のUSB NICでは、USB接続した小型アダプタがEthernet NICとして見えます。

今回は、そのUSB NIC役をSoftBank Air ターミナル6自身にやらせます。

Windowsから見ると、

UsbNcm Host Device

という普通のネットワークアダプタとして認識されます。


T6A内部にはUSB Gadget構成がある

SoftBank Air ターミナル6の内部OSはLinuxです。

今回の実機は、

Linux 5.4.238
aarch64

でした。

ConfigFSは、

/config

へmountされています。

USB Gadget本体は、

/config/usb_gadget/g1

です。

functionsを見ると、

functions/acm.gs0
functions/acm.gs1
functions/acm.gs2
functions/ffs.adb
functions/ncm.gs8

などが存在します。

今回使うのは、

functions/ncm.gs8

です。

これがCDC-NCMのネットワークfunctionです。


まずUSBコントローラをDEVICE側へ切り替える

ここが重要です。

T6AにはMediaTek MTU3系のdual-role USBコントローラがあり、Host側とDevice側を切り替えられます。

今回実際にUSB NCMが成功した状態では、

/sys/devices/platform/11201000.usb/mode

が、

3

でした。

実際に使用した操作は、

printf 3 > /sys/devices/platform/11201000.usb/mode

です。

このT6A実機では、

mode=3

がUSB Deviceとして成功した状態です。


一般論からmode番号を推測しない

ここでは一度かなりハマりました。

cold boot後のT6Aは、

mode=2

になっていました。

そこでConfigFSを復元し、

f5 -> ncm.gs8
UDC bind
ncm0生成

まで進めることはできました。

しかし、

UDC state = not attached
current_speed = UNKNOWN
ncm0 = NO-CARRIER

のままで、WindowsからUSB Deviceとして列挙されませんでした。

一次記録を再確認すると、最初に成功した実績では、

printf 3 > /sys/devices/platform/11201000.usb/mode

を使用していました。

そこで mode=3 へ戻すと、

xHCI = ABSENT
UDC configured
ncm0 LOWER_UP

へ復帰しました。

このため、少なくともこのT6Aでは、

一般的なLinuxのmode番号を推測せず、実機で成功した値を使う

ことが重要です。


xHCIが消えたことを確認する

DEVICE側へ切り替えたら、Host controller側のxHCIが消えたことを確認します。

成功状態では、

xHCI: ABSENT

でした。

つまり、

T6AがUSB Hostとして動く

状態ではなく、

T6A自身がUSB Deviceになる

状態になっています。


GPIO322をLOWへする

今回、ここが非常に重要だと分かりました。

T6AではGPIO322がUSB-A側のVBUS制御に関係しており、実機では、

GPIO322 HIGH
→ USB-A VBUS 約5V

GPIO322 LOW
→ USB-A VBUS 0V

となりました。

GPIO状態は、

cat /sys/kernel/debug/gpio | grep -C 2 'gpio-322'

で確認できます。

成功状態は、

gpio-322 ... out lo

です。

GPIO322をLOWへする操作は、

echo 0 > /sys/class/gpio/gpio322/value

です。

確認は、

cat /sys/class/gpio/gpio322/value

で、

0

となればLOWです。

Hostを接続する前に、可能であれば実際にUSB-A側のVBUSが0Vになっていることも確認します。


GPIO322 HIGHだとUSB2へ落ちた

今回、GPIO322の重要性を偶然かなりきれいに確認できました。

同じT6A、同じA-Aケーブル、同じWindows USBポートを使用しているにもかかわらず、

GPIO322 = HIGH

の状態では、

UDC state     = configured
current_speed = high-speed
ncm0          = LOWER_UP

となりました。

ここでいう high-speed はUSB 2.0の480Mbpsモードです。

iperf3の実測も、

T6A → Windows:約350 Mbit/s
Windows → T6A:約333 Mbit/s

でした。

USB NCM自体は正常に通信していますが、SuperSpeedではありません。

そこで、

echo 0 > /sys/class/gpio/gpio322/value

としてGPIO322をLOWへ戻し、

G=/config/usb_gadget/g1

echo > "$G/UDC"
sleep 1
echo 11201000.usb > "$G/UDC"

とUDCをrebindしました。

すると直後に、

current_speed = super-speed

へ復帰しました。

同じケーブル、同じWindowsポートのままです。

したがって少なくとも今回の実機では、

GPIO322 HIGH
        ↓
USB 2.0 High-Speed
        ↓
約350Mbps

GPIO322 LOW
        ↓
UDC rebind
        ↓
USB 3.x SuperSpeed
        ↓
約1.4Gbps

という非常に分かりやすい差が再現しました。

GPIO322 LOWは、単にVBUSを切るためだけではなく、SuperSpeed成立にも重要な条件と考えています。


ConfigFSへNCMを組み込む

NCM functionは、

/config/usb_gadget/g1/functions/ncm.gs8

にあります。

USB configurationは、

/config/usb_gadget/g1/configs/b.1

です。

元の構成には、

f1 -> acm.gs2
f2 -> ffs.adb
f3 -> acm.gs0
f4 -> acm.gs1

が存在していました。

ここへ、

f5 -> ncm.gs8

を追加します。

実機上では、

f5 -> ../../../../usb_gadget/g1/functions/ncm.gs8

のように表示されます。

概念的には、

functions/ncm.gs8
       │
       │ f5
       ▼
configs/b.1
       │
       ▼
USB Gadget configuration

です。


symlink確認には readlink -f を使う

ConfigFSではsymlink表示が相対pathになるため、単純な文字列比較では判定を誤ることがあります。

例えば、

../../../../usb_gadget/g1/functions/ncm.gs8

と、

/config/usb_gadget/g1/functions/ncm.gs8

は文字列としては違います。

実体確認には、

readlink -f

を使います。

test \
  "$(readlink -f "$G/configs/b.1/f5")" = \
  "$(readlink -f "$G/functions/ncm.gs8")"

とすれば、実体path同士で比較できます。


UDCをunbind / rebindする

NCMをconfigurationへ組み込んだら、UDCを再bindします。

今回のUDCは、

11201000.usb

です。

G=/config/usb_gadget/g1

echo > "$G/UDC"
echo 11201000.usb > "$G/UDC"

とします。

Host未接続の時点では、

UDC state = not attached
ncm0 = NO-CARRIER
carrier = 0

で問題ありません。

これはUSB Gadget側の準備が完了し、Host接続を待っている状態です。


ここで初めてWindows/Linuxを接続する

今回再現できた順序をまとめると、

USB Host未接続
        ↓
mode=3
        ↓
xHCI ABSENT
        ↓
GPIO322 LOW
        ↓
VBUS 0V確認
        ↓
f5 -> ncm.gs8
        ↓
UDC unbind / rebind
        ↓
not attached / NO-CARRIER
        ↓
Windows/Linux Host接続
        ↓
SuperSpeed

です。

Host接続後は、

UDC state = configured
current_speed = super-speed
ncm0 = LOWER_UP
carrier = 1

となりました。


Windowsからは標準USB NICとして認識

Windows Pavilionへ接続すると、

UsbNcm Host Device

として認識しました。

ドライバはWindows標準の、

UsbNcm.sys

です。

識別情報は、

VID 2C7C
PID 7006
MI  07

でした。

Windows側では、

イーサネット 3

説明:
UsbNcm Host Device

IPv4:
192.168.77.2

サブネット:
255.255.255.0

として使用しています。

T6A側は、

192.168.77.1/24

です。

したがって、

Windows
192.168.77.2
      │
      │ USB NCM
      │
T6A
192.168.77.1

という普通のIPネットワークになります。


SuperSpeedになっているか必ず確認する

Windowsから認識されたからといって、USB 3.xで接続できているとは限りません。

T6A側では、

cat /sys/class/udc/11201000.usb/state
cat /sys/class/udc/11201000.usb/current_speed
cat /sys/kernel/debug/usb/11201000.usb/link-state

を確認します。

今回の正常状態は、

configured
super-speed
opstate: 0x0, ltssm: 0x11

でした。

current_speed が、

high-speed

ならUSB 2.0です。

この状態でもNCMは普通に動いてしまうため、速度を見るまではSuperSpeed成功とは判定しない方がよいです。


実測速度

SuperSpeedへ復帰したあと、iperf3を複数回測定しました。

T6AからWindows方向は、

1.39 Gbit/s
1.37 Gbit/s
1.38 Gbit/s

でした。

すべてTCP retransmissionは0です。

別の単発測定でも、

1.38 Gbit/s

を確認しました。

したがって現時点のbaselineは、

T6A → Windows:約1.37~1.39 Gbit/s

です。

逆方向は、

1.00 Gbit/s
1.01 Gbit/s
1.00 Gbit/s

でした。

したがって、

Windows → T6A:約1.00~1.01 Gbit/s

です。

USB2 High-Speedへフォールバックしていたときの、

333~350 Mbit/s

と比べると差は明確です。


1GbEを明確に超えた

T6A → Windows方向では、約1.4Gbpsが安定しています。

これは1GbEの実効速度を明確に超えています。

一方、Windows → T6A方向は約1Gbps付近で頭打ちです。

複数TCP streamなども試しましたが、大幅な改善はありませんでした。

現在は、

  • CDC-NCM NTB処理
  • aggregation / deaggregation
  • USB request completion
  • MTU3 QMU / DMA
  • skb allocation / copy
  • request queue depth
  • offload制限

などを候補として調査しています。

さらに、この約1.4Gbpsの壁を越えるため、T6A向けUSB NCMカーネルドライバの改造も進めています。


管理経路はUSBとは完全に分離する

今回かなり重要だった設計です。

T6Aの管理にはUSBを使いません。

raspi2
   │
   │ LAN / SSH
   ▼
T6A

です。

USBはあくまで、

Windows
   │
   │ USB NCM
   ▼
T6A

というデータプレーンです。

全体では、

                    ┌── USB NCM ── Windows
                    │
                  T6A
                    │
                    └── LAN/SSH ── raspi2

です。

T6AへのSSHは例えば、

sudo -u codex -H ssh \
  -i /home/codex/.ssh/terminal6_ed25519 \
  root@192.168.3.2

で行っています。

この構成のおかげで、USB Gadget構成が壊れてもLAN側から復旧できます。

ConfigFS上には ffs.adb も存在しますが、今回のT6A管理にはADBを使用していません。

管理はLAN/SSH、USBはNCMデータプレーン。

この2つを分離しています。


実験中にncm0を消した

性能改善のためUSB Gadget構成やNCM実装を触っている途中で、

f5 消失
ncm0 消失
UDC not attached
Windows NCM不通

という状態になりました。

ただし、

/config/usb_gadget/g1/functions/ncm.gs8

自体は残っていました。

つまり、

NCM functionは存在するが、USB configurationへ接続されていない

状態でした。

管理LANは生きていたため、SSHから復旧できました。


NCM functionがあることとncm0があることは別

cold boot後には、

/config/usb_gadget/g1/functions/ncm.gs8

が存在していても、

ncm0

はありませんでした。

ncm.gs8を作っただけでは足りません。

functions/ncm.gs8
       ↓
configs/b.1/f5
       ↓
UDC bind
       ↓
ncm0

という流れで実際のconfigurationへ参加させる必要があります。

さらに今回分かったのは、

ncm0がある

だけでも足りないことです。

mode=2 の状態では ncm0 を作れても、Hostから列挙されませんでした。

つまり確認すべき段階は、

ncm.gs8存在
      ↓
f5存在
      ↓
ncm0存在
      ↓
carrier
      ↓
UDC configured
      ↓
current_speed=super-speed

まであります。


cold bootすれば全部戻る、ではなかった

途中ではMTU3/DRD側の状態までおかしくなり、

UDC = not attached
current_speed = UNKNOWN
ncm0 = NO-CARRIER

から戻らない状態も経験しました。

cold bootするとUSB controller自体は正常化しました。

しかしその直後は、

mode=2
ncm.gs8 は存在
f5 はない
ncm0 はない

という状態でした。

つまり、

cold bootでUSBコントローラは初期化されても、USB NCMとして使える状態まで自動復旧するわけではない

ということです。

ConfigFSはRAM上なので、手動追加した f5 も消えます。


正しい復旧順序

今回確立した復旧順序は、

USB Hostを外す
        ↓
mode=3
        ↓
xHCI ABSENT
        ↓
GPIO322 LOW
        ↓
VBUS 0V確認
        ↓
ncm.gs8確認
        ↓
f5 -> ncm.gs8
        ↓
UDC unbind / rebind
        ↓
ncm0生成
        ↓
192.168.77.1/24
        ↓
ncm0 UP
        ↓
Windows/Linux Host接続
        ↓
configured
        ↓
current_speed=super-speed
        ↓
iperf3 baseline確認

です。

今回この順序で再現できました。


復旧後の確認

最低限、次を確認します。

G=/config/usb_gadget/g1

echo "mode=$(cat /sys/devices/platform/11201000.usb/mode)"

cat /sys/kernel/debug/gpio | grep -C 2 'gpio-322'

echo "UDC=$(cat "$G/UDC")"
echo "state=$(cat /sys/class/udc/11201000.usb/state)"
echo "speed=$(cat /sys/class/udc/11201000.usb/current_speed)"

readlink -f "$G/configs/b.1/f5"

ip -br addr show ncm0
cat /sys/class/net/ncm0/carrier

正常状態は概ね、

mode=3
gpio-322 ... out lo
UDC=11201000.usb
state=configured
speed=super-speed
f5 -> ncm.gs8
ncm0 LOWER_UP
carrier=1

です。


MAC addressは変わる場合がある

cold boot後には、

dev_addr
host_addr

が再生成される場合がありました。

Windowsから見えるMAC addressも変化します。

そのためWindowsが別のネットワークインターフェースとして扱い、

192.168.77.2/24

という静的IPが外れる可能性があります。

T6A側が正常なのにpingが通らない場合は、Windows側のIP設定も確認します。


今回やらないことにした操作

復旧・再現中は次を禁止しました。

  • ADBを管理に使わない
  • 未検証のUSB role変更を使わない
  • flashを書き換えない
  • 復旧途中に別のcandidate driverを投入しない
  • 管理LANを切らない
  • 過去にT6Aを不安定化させたruntime role切替moduleを再実行しない

特に大事だったのは、

一般的なLinuxの知識からT6A固有のmodeやroleを推測せず、実機で成功した一次記録を優先する

ことでした。


まとめ

SoftBank Air ターミナル6は、USBコントローラをDEVICE側へ切り替え、ConfigFSでCDC-NCMを組み込むことで、

Windows / Linux
       │
       │ USB 3.x NCM
       ▼
      T6A
       │
       ▼
      ncm0

というUSB NICとして利用できます。

今回の実機で再現できた重要条件は、

mode=3
xHCI ABSENT
GPIO322 LOW
VBUS 0V
f5 -> ncm.gs8
UDC rebind
Hostは最後に接続
current_speed=super-speed

です。

Windowsでは標準の UsbNcm.sys で認識し、実測では、

T6A → Windows:約1.37~1.39 Gbit/s
Windows → T6A:約1.00~1.01 Gbit/s

を確認しました。

さらに今回、

GPIO322 HIGH
→ USB 2.0 High-Speed
→ 約333~350Mbps

GPIO322 LOW
→ UDC rebind
→ USB 3.x SuperSpeed
→ 約1.4Gbps

という差まで再現できました。

最初は単に、

「SoftBank Air ターミナル6はUSB NICになる」

という発見でした。

しかし実験を進めるうちに、

「どうすれば再現できるのか」
「なぜUSB2へ落ちるのか」
「壊れたらどう戻すのか」

まで少しずつ分かってきました。

次は、この約1.4Gbpsの壁をT6A側のUSB NCM実装を改造して越えられるか試しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?