Raspberry PiでWDC-433DU2H2-Bを動かす

# はじめに
　ELECOM製の **WDC-433DU2H2-B** をRaspberry Pi4 Model Bで使用するために必要なカーネルモジュールのビルドについて解説します。

<details><summary>WDC-433DU2H2-B と RTL8821AU </summary>
　WDC-433DU2H2-B は WDC-433DU2HBK に次いで発売された大型アンテナがついたWiFiドングル。Realtek製のWiFiコントローラーチップ RTL8811AU を採用しているようだが、RTL8821AU用のカーネルモジュールにて動作させることが可能。
</details>

### 実行環境
実機: Raspberry Pi 4 Model B
OS: Rasbian Buster Light
Kernel version: 4.19.97

別にRPi4でなくても大丈夫だが、カーネルのバージョンが古くなると下記の方法ではうまくいかない可能性が出てくる。

### 作業のサマリ
1. カーネルソースをDLして、make modules_prepareを実行
2. GitHubよりdiederikdehaas/rtl8812AU (https://github.com/diederikdehaas/rtl8812AU) の **ブランチ driver-4.3.22-beta** をclone
3. rtl8812AU/os_dep/linux/usb_intf.c の 8821 セクションに WDC-433DU2H2-B のVID&PIDを書き加える。
4. コンパイルとインストール 



# カーネルソースのダウンロード、コンパイル
詳細は、例えばこちらの小生の記事を参照されたし。
https://qiita.com/newtypehiro919/items/336e09340e728a94a9f7


# カーネルモジュールのコンパイル
### ソースのダウンロード
diederikdehaas/rtl8812AU を利用する。
(https://github.com/diederikdehaas/rtl8812AU/tree/driver-4.3.20)

番号が8812なのは間違いではない。8812用と8821用のカーネルモジュールが同時提供されていることはよくある。

ブランチ `driver-4.3.22-beta` を clone する。**デフォルトのブランチをcloneしてもうまくいかない!**　デフォルトの `driver-4.3.20`には、目的としているrtl8821auのコードが含まれていない。

```shell_session:
git clone -b driver-4.3.22-beta https://github.com/diederikdehaas/rtl8812AU.git 
```

### ソースの編集
カーネルモジュールが WDC-433DU2H2-B を認識できるように、Vender ID と Product ID をソースファイル中に書き込む必要がある。なお、WDC-433DU2H2-B の Vender ID は`0x056E`、Product ID は`0x4010`である。

```c:os_dep/linux/usb_intf.c&nbsp;180行目あたり
#ifdef CONFIG_RTL8821A
        /*=== Realtek demoboard ===*/
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0811),.driver_info = RTL8821},/* Default ID */
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0821),.driver_info = RTL8821},/* Default ID */
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8822),.driver_info = RTL8821},/* Default ID */
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xA811) , .driver_info = RTL8821},/* Default ID */
        {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0820,0xff,0xff,0xff),.driver_info = RTL8821}, /* 8821AU */
        {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0823,0xff,0xff,0xff),.driver_info = RTL8821}, /* 8821AU */
        /*=== Customer ID ===*/
        {USB_DEVICE(0x0411, 0x0242),.driver_info = RTL8821}, /* BUFFALO - Edimax */
        {USB_DEVICE(0x04BB, 0x0953),.driver_info = RTL8821}, /* I-O DATA - Edimax */
        {USB_DEVICE(0x056E, 0x400E),.driver_info = RTL8821}, /* ELECOM -  ELECOM */
        {USB_DEVICE(0x056E, 0x400F),.driver_info = RTL8821}, /* ELECOM -  ELECOM */
        {USB_DEVICE(0x0846, 0x9052),.driver_info = RTL8821}, /* Netgear - A6100 */
        {USB_DEVICE(0x0E66, 0x0023),.driver_info = RTL8821}, /* HAWKING - Edimax */
        {USB_DEVICE(0x2001, 0x3314),.driver_info = RTL8821}, /* D-Link - Cameo */
        {USB_DEVICE(0x2001, 0x3318),.driver_info = RTL8821}, /* D-Link - Cameo */
        {USB_DEVICE(0x2019, 0xAB32),.driver_info = RTL8821}, /* Planex - GW-450S */
        {USB_DEVICE(0x3823, 0x6249),.driver_info = RTL8821}, /* Obihai - OBiWiFi */
        {USB_DEVICE(0x7392, 0xA811),.driver_info = RTL8821}, /* Edimax - Edimax */
        {USB_DEVICE(0x7392, 0xA812),.driver_info = RTL8821}, /* Edimax - EW-7811UTC */
        {USB_DEVICE(0x7392, 0xA813),.driver_info = RTL8821}, /* Edimax - EW-7811UAC */
/* この下の1行を追加。WDC-433DU2H2-B の VID & PID  */
        {USB_DEVICE(0x056E, 0x4010),.driver_info = RTL8821}, 

#endif
```
`#ifdef CONFIG_RTL8821A ` のセクションに `{USB_DEVICE(0x056E, 0x4010),.driver_info = RTL8821},` の1行を書き加える。なお、コンマで終わっているが、間違いではない。


### Makefileの編集

ラズパイ用のカーネルモジュールをコンパイルするので、`CONFIG_PLATFORM_I386` を `n` にして、`CONFIG_PLATFORM_ARM_RPI` を `y` に書き換える。

```makefile:Makefile&nbsp;80行目あたり
CONFIG_RTW_SDIO_PM_KEEP_POWER = y
###################### Platform Related #######################
CONFIG_PLATFORM_I386_PC = n     /* y から n に変更する */
CONFIG_PLATFORM_ARM_RPI = y     /* n から y に変更する */
CONFIG_PLATFORM_ARM64 = n
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_ANDROID_INTEL_X86 = n
```

### コンパイル
make コマンドを実行する。`-j4` オプションを付けた方が少しコンパイルが早くなる。
ところどころで Warning が出るが、コンパイルはできる。

```shell_session:
raspberrypi:/usr/src/rtl8812AU# make -j4
make ARCH=arm CROSS_COMPILE= -C /lib/modules/4.19.97-v7l+/build M=/usr/src/rtl8812AU  modules
make[1]: Entering directory '/usr/src/linux-43857965e5f526b9df807e543102a11fac1c0bcc'
  CC [M]  /usr/src/rtl8812AU/core/rtw_cmd.o
  CC [M]  /usr/src/rtl8812AU/core/rtw_security.o
  CC [M]  /usr/src/rtl8812AU/core/rtw_debug.o
  CC [M]  /usr/src/rtl8812AU/core/rtw_io.o
　　　
（中略）

  CC [M]  /usr/src/rtl8812AU/hal/led/hal_usb_led.o
  CC [M]  /usr/src/rtl8812AU/hal/HalPwrSeqCmd.o
/usr/src/rtl8812AU/hal/hal_hci/hal_usb.c: In function ‘usb_init_recv_priv’:
/usr/src/rtl8812AU/hal/hal_hci/hal_usb.c:38:3: warning: cast between incompatible function types from ‘void (*)(void *)’ to ‘void (*)(long unsigned int)’ [-Wcast-function-type]
   (void(*)(unsigned long))usb_recv_tasklet,
   ^
  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/Hal8812PwrSeq.o
  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/Hal8821APwrSeq.o
  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/rtl8812a_xmit.o
  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/rtl8812a_sreset.o

（中略）

  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/usb/rtl8812au_recv.o
  CC [M]  /usr/src/rtl8812AU/hal/rtl8812a/usb/usb_ops_linux.o
  CC [M]  /usr/src/rtl8812AU/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.o
/usr/src/rtl8812AU/hal/rtl8812a/usb/rtl8812au_xmit.c: In function ‘rtl8812au_init_xmit_priv’:
/usr/src/rtl8812AU/hal/rtl8812a/usb/rtl8812au_xmit.c:33:7: warning: cast between incompatible function types from ‘void (*)(void *)’ to ‘void (*)(long unsigned int)’ [-Wcast-function-type]
       (void(*)(unsigned long))rtl8812au_xmit_tasklet,
       ^
  CC [M]  /usr/src/rtl8812AU/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.o
  CC [M]  /usr/src/rtl8812AU/hal/phydm/phydm_debug.o
  CC [M]  /usr/src/rtl8812AU/hal/phydm/phydm_antdiv.o

（中略）

  CC [M]  /usr/src/rtl8812AU/core/rtw_mp_ioctl.o
  CC [M]  /usr/src/rtl8812AU/core/rtw_bt_mp.o
/usr/src/rtl8812AU/hal/phydm/rtl8821a/phydm_iqk_8821a_ce.c: In function ‘_IQK_Tx_8821A’:
/usr/src/rtl8812AU/hal/phydm/rtl8821a/phydm_iqk_8821a_ce.c:646:174: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
     ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("RX_X0[1][%d] = %x ;; RX_Y0[1][%d] = %x\n", i, (RX_X0[1][i])>>21&0x000007ff, i, (RX_Y0[1][i])>>21&0x000007ff));
                                                                                                                                                                              ^
  LD [M]  /usr/src/rtl8812AU/8812au.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /usr/src/rtl8812AU/8812au.mod.o
  LD [M]  /usr/src/rtl8812AU/8812au.ko
make[1]: Leaving directory '/usr/src/linux-43857965e5f526b9df807e543102a11fac1c0bcc'
raspberrypi:/usr/src/rtl8812AU#
```
この下から3行目にある `8812au.ko` が求めるカーネルモジュール。

ただし、kernel version 4.19.97 でのみ有効なモジュール。後に `apt upgrade` など実行してカーネルのバージョンが変わってしまうと、カーネルソースの取得からカーネルモジュールのコンパイルまで、全部やり直さないといけなくなるので注意が必要。


# カーネルモジュールのインストール
コンパイル終了後に下記コードを実行すれば終了。

```shell_session:
make install
```

modinfo コマンドで確認してみる。カーネルモジュール名は`8812au`

```shell_session:
raspberrypi:/usr/src/rtl8812AU# modinfo 8812au
filename:       /lib/modules/4.19.97-v7l+/kernel/drivers/net/wireless/8812au.ko
version:        v4.3.22-beta
author:         Realtek Semiconductor Corp.
description:    Realtek Wireless Lan Driver
license:        GPL
srcversion:     CB90FC4561203545235BE0B
alias:          usb:v7392pA813d*dc*dsc*dp*ic*isc*ip*in*
alias:          usb:v7392pA812d*dc*dsc*dp*ic*isc*ip*in*
alias:          usb:v7392pA811d*dc*dsc*dp*ic*isc*ip*in*

（以下、省略）
```

再起動してWiFiドングルが認識されれば成功！

### 検証済みのこと
とりあえず、子機として動く（アクセスポイントに接続して通信できる）。
APモードでも動く。ただし、自分が hostapd の設定に明るくないので、フルスペックが引き出せているかは不明。パフォーマンステストまではしてない。


# 余談

<details><summary>どの rtl8821au 用カーネルモジュールを使うか？</summary>
　GitHub上では、多くの作者がrtl8821au用のカーネルモジュールを公開している。ただ、みんなゼロからコードを書いているのではなく、大元となるコードがあるようで、掲げているバージョンが同じならコードもほぼ一緒。デバイスのリストに新たな製品が加えられていたり、細かなbug fixがされていたり、新たなOSをターゲットにしたMakefileの編集がなされているなど、それぞれ微妙に異なっている。
　これら多くのrtl8821au用カーネルモジュールのうち、Raspbean上でのコンパイルに対応している（Makefileがそれ用に編集されている）ものはあまりない。メジャー所（星の数が多い）は abperiasamy (https://github.com/abperiasamy/rtl8812AU_8821AU_linux) や diederikdehaas (https://github.com/diederikdehaas/rtl8812AU) で、これらはいずれもRasbean対応を謳っている。
　先代の WDC-433DU2HBK は abperiasamy/rtl8812AU_8821AU_linux でコンパイルも成功するし、基本的には問題なく動作した。ところが、WDC-433DU2H2-B は認識こそすれど、APへの接続時に何らかの原因で認証が失敗して接続できなかった。diederikdehaas/rtl8812AU もデフォルト(driver-4.3.20)ではコンパイルエラーになるが、ブランチを変えるとうまく行った。ここにたどり着くまでに半年もかかった、、、
</details>