最近安価で手に入るようになった Bluetooth 5.x の USB ドングルを Linux で使う手順です。
これらのドングルには大抵 Realtek の RTL8761B (フルネームはRTL8761BUV) というチップが使われており、Linux 2.6.32 以降に対応しています。
更新履歴
- 2023/11/23 Bluetooth 5.3 のファームウェアが非常に不安定なため削除
- 2023/10/24 Bluetooth 5.3 対応のファームウェアにアップグレードする手順を加筆
- 2021/02/20 Realtek 製ドライバを使う手順に書き直し
- 2020/10/27 Google Home、AirPods とペアリングできたので記事を修正
準備
カーネルに最初から入っている btusb
には、デバイスをスキャンすると音がブツ切りになるという問題があったので、問題のなかった Realtek 謹製のドライバをビルドします。
ドライバをビルドする際にカーネルのソースコードとビルドツールが必要になるので事前に入れておきます。
$ sudo apt install linux-headers build-essential
カーネルの再構築 (※読み飛ばしてもOK)
カーネルを自分でビルドしている人向けです。
Realtek 製ドライバが btusb
を置き換える形になるため、カーネルが btusb
を組み込まずにビルドされているか、モジュールとしてビルドされている必要があります。
modinfo btusb
の出力に (builtin)
が含まれていなければ、この手順は必要ありません。
btusb
をモジュールとしてビルドするには
# scripts/config -m BT_HCIBTUSB
を実行してからいつも通り make
すれば OK です。
ドライバのインストール
ASUS が販売しているドングル USB-BT500 の Linux 版ドライバとして、 Realtek 製ドライバのソースコード一式が配布されているのでこれを利用します。
ASUS の公式サイトからダウンロードできます。現時点での最新版は v0202 (2020/12/08) でした。
以下のコマンドを実行するとドライバとファームウェアがインストールされます。
wget https://dlcdnets.asus.com/pub/ASUS/wireless/USB-BT500/20200909_LINUX_BT_DRIVER_KERNEL_5.7_COEX_v0202.zip
unzip 20200909_LINUX_BT_DRIVER_KERNEL_5.7_COEX_v0202.zip
cd 20200806_LINUX_BT_DRIVER_RTL8761B_COEX_v0202/20200806_LINUX_BT_DRIVER_RTL8761B_COEX_v0202
# デバッグ出力がうるさいので消す
sed -i '/define RTKBT_DBG/c\#define RTKBT_DBG(fmt, arg...)' usb/bluetooth_usb_driver/rtk_coex.c
sudo make install INTERFACE=usb
このコマンドは実行中のカーネルに対して行われるため、作業前にカーネルをアップデートした際は再起動してから行ってください。
ドングルの認識
ドライバをロードします。
$ sudo modprobe rtk_btusb
$ hciconfig -a
hci0: Type: Primary Bus: USB
BD Address: XX:XX:XX:XX:XX:XX ACL MTU: 1021:6 SCO MTU: 255:12
UP RUNNING PSCAN
RX bytes:854270 acl:21692 sco:0 events:66232 errors:0
TX bytes:44662651 acl:65989 sco:0 commands:226 errors:0
Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy: RSWITCH HOLD SNIFF PARK
Link mode: PERIPHERAL ACCEPT
Name: 'XXXX'
Class: 0x7c0104
Service Classes: Rendering, Capturing, Object Transfer, Audio, Telephony
Device Class: Computer, Desktop workstation
HCI Version: 5.1 (0xa) Revision: 0xdfc6
LMP Version: 5.1 (0xa) Subversion: 0xd922
Manufacturer: Realtek Semiconductor Corporation (93)
HCI Version: 5.1
(Bluetooth 5.1) のコントローラーとして認識されました。
トラブルシューティング
頻繁に切断される、音が切れる
2.4 GHz 帯との干渉が原因の可能性が高いです。
USB 2.0 ポートに差すか、USB 2.0 の延長ケーブルを使って PC 本体から少し離れたところにドングルを設置することをおすすめします。
私の場合は延長ケーブルで接続性が劇的に改善されました。
Linux 5.9 でドングルが認識されない
この問題は Linux 5.10.6 で修正されました。
Bluetooth: Fix attempting to set RPA timeout when unsupported · torvalds/linux@a31489d
私の環境 (Linux 5.9.1) ではカーネルはドングルを認識するのですが、bluetoothctl がドングルを全く認識しませんでした。GNOME の設定画面でも Bluetooth ドングルが繋がっていないと表示されます。
btmon で通信内容を見てみると、通信自体は問題なくできているようですがこのようなエラーが出ています。
< HCI Command: LE Set Resolvable P.. (0x08|0x002e) plen 2 #235 [hci0] 8.037958
Timeout: 900 seconds
> HCI Event: Command Complete (0x0e) plen 4 #236 [hci0] 8.038849
LE Set Resolvable Private Address Timeout (0x08|0x002e) ncmd 2
Status: Unsupported Remote Feature / Unsupported LMP Feature (0x1a)
= Close Index: XX:XX:XX:XX:XX:XX [hci0] 8.038893
LE Set Resolvable Private Address Timeout という対応していないコマンドを発行して怒られているようです。
カーネルのコミットログを調べたところ、このコミットが怪しい感じがします。
Linux 5.9 で追加されたコードなので、それ以前のカーネルではこのドングルも正常に動作していたのかもしれません。
あまり他に影響しなさそうなコードなので丸ごと削除してみます。
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c8e67042a3b1..74740a103c6f 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1649,8 +1649,6 @@ struct hci_rp_le_read_resolv_list_size {
#define HCI_OP_LE_SET_ADDR_RESOLV_ENABLE 0x202d
-#define HCI_OP_LE_SET_RPA_TIMEOUT 0x202e
-
#define HCI_OP_LE_READ_MAX_DATA_LEN 0x202f
struct hci_rp_le_read_max_data_len {
__u8 status;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 502552d6e9af..e0872ba36aa1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -763,14 +763,6 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
hci_req_add(req, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL);
}
- if (hdev->commands[35] & 0x40) {
- __le16 rpa_timeout = cpu_to_le16(hdev->rpa_timeout);
-
- /* Set RPA timeout */
- hci_req_add(req, HCI_OP_LE_SET_RPA_TIMEOUT, 2,
- &rpa_timeout);
- }
-
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
/* Read LE Maximum Data Length */
hci_req_add(req, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL);
カーネルを再構築して再起動すると、それまで全く光らなかったドングルが青く発光し、 bluetoothctl からもコントローラーとして正しく認識されました。