博主头像
Kurfuerst

ワクワク

手柄蓝牙唤醒Steamos

背景

心血来潮把xsx卖了,用闲置的硬盘和内存装了一台steamos。想要用diy设备cos主机,第一步就是解决手柄唤醒的问题。

研究了一下发现通过2.4g接收器唤醒的难度较大,usb设备唤醒依赖于其自身固件的实现。linux在枚举设备的时候会遍历每个设备的描述符,设备声明自己支持remote wakeup才会通过SET_FEATURE(DEVICE_REMOTE_WAKEUP)请求使用USB设备的远程唤醒功能。而大多数手柄的接收器都没有实现这个功能,只好退而求其次通过蓝牙唤醒。

设置蓝牙唤醒

蓝牙手柄的唤醒链路大致是:

蓝牙手柄
   ↓
Bluetooth 无线连接
   ↓
Intel Bluetooth Controller
   ↓
USB Remote Wakeup
   ↓
USB / xHCI
   ↓
SteamOS Resume

因此完整条件实际上是:

手柄 WakeAllowed = yes
             ↓
蓝牙 USB Controller power/wakeup = enabled
             ↓
USB/xHCI 支持 wake
             ↓
SteamOS 可以被唤醒

最初的现象

最开始的现象是:

蓝牙手柄       → 无法唤醒 SteamOS
USB 键盘接收器 → 可以唤醒 SteamOS

因为 USB 键盘仍然能唤醒,意味着xHCI/usb唤醒没问题

找到 Bluetooth HCI 对应的 USB 设备

Linux 蓝牙子系统看到的是:

/sys/class/bluetooth/hci0

但蓝牙控制器本身实际上通常挂在 USB 总线上。

所以先获取 hci0 的真实设备路径:

HCI=$(readlink -f /sys/class/bluetooth/hci0/device)

echo "$HCI"

在本机得到类似:

/sys/devices/pci0000:00/0000:00:14.0/usb1/1-14/1-14:1.0

注意这里:

1-14:1.0

是 USB Interface,而不是整个 USB Device。

我们真正需要的是它的父级:

1-14

所以向父目录逐层查找,直到找到:

idVendor
idProduct

完整命令:

HCI=$(readlink -f /sys/class/bluetooth/hci0/device)

USB="$HCI"

while [ "$USB" != "/" ]; do
    if [ -f "$USB/idVendor" ] &&
       [ -f "$USB/idProduct" ]; then
        break
    fi

    USB=$(dirname "$USB")
done

echo "Bluetooth HCI:"
echo "$HCI"

echo
echo "Bluetooth USB device:"
echo "$USB"

echo
echo "VID:PID"
cat "$USB/idVendor"
cat "$USB/idProduct"

echo
echo "Wakeup:"
cat "$USB/power/wakeup"

echo
echo "Power control:"
cat "$USB/power/control"

实际结果:

Bluetooth HCI:
/sys/devices/.../usb1/1-14/1-14:1.0

Bluetooth USB device:
/sys/devices/.../usb1/1-14

VID:PID
8087
0033

Wakeup:
disabled

Power control:
auto

于是问题基本定位:

Intel Bluetooth Controller
VID:PID = 8087:0033

power/wakeup = disabled

蓝牙唤醒的过程实际上是:

手柄按键
   ↓
蓝牙无线事件
   ↓
8087:0033 蓝牙控制器收到事件
   ↓
蓝牙控制器通过 USB Remote Wakeup
通知 xHCI
   ↓
系统恢复

但是 Linux 给这个 USB Device 设置了 power/wakeup = disabled

相当于告诉内核:

系统进入 suspend 后,不允许这个 USB 设备成为系统唤醒源。

所以手柄按键不会产生系统 Resume

临时开启蓝牙 USB Wakeup

直接执行:

echo enabled | sudo tee "$USB/power/wakeup"

然后确认:

cat "$USB/power/wakeup"

应该变成:

enabled

此时进行验证,手柄成功唤醒steamos

检查 BlueZ 的 WakeAllowed

虽然已经可以成功唤醒了,但以防万一还是看了下bluez

Linux USB wakeup 只是底层的一层。BlueZ 对每一个蓝牙设备还存在一个更高层的控制: WakeAllowed ,需要wkeallowed和linux的power/wakeup都开启。

先列出已经配对的设备:

bluetoothctl devices

例如:

Device AA:BB:CC:DD:EE:FF Wireless Controller

然后看一下wakeAllowed的状态:

bluetoothctl info AA:BB:CC:DD:EE:FF |
grep -E 'Name|Paired|Bonded|Trusted|WakeAllowed'

理想状态:

Paired: yes
Bonded: yes
Trusted: yes
WakeAllowed: yes

如果看到:

WakeAllowed: no

可以执行:

bluetoothctl wake AA:BB:CC:DD:EE:FF on

然后再次检查。

如果当前版本的 bluetoothctl 不识别 wake 命令,可以先:

bluetoothctl help

确认当前 BlueZ 是否提供该子命令。

持久化

直接执行:

echo enabled > /sys/.../power/wakeup

只修改当前内核中的运行时状态。

/sys 并不是普通磁盘目录,而是内核根据当前设备动态创建sysfs,之前手动写进去的规则不会永久存在,因此需要 udev 持久化规则。

创建:

sudo mkdir -p /etc/udev/rules.d

然后:

sudo tee /etc/udev/rules.d/99-bluetooth-wakeup.rules >/dev/null <<'EOF'
ACTION=="add|change", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="8087", ATTR{idProduct}=="0033", TEST=="power/wakeup", ATTR{power/wakeup}="enabled"
EOF

加载:

sudo udevadm control --reload-rules

可以重新触发对应设备:

sudo udevadm trigger \
  --action=change \
  --subsystem-match=usb \
  --attr-match=idVendor=8087 \
  --attr-match=idProduct=0033

然后重新定位 Bluetooth Controller:

HCI=$(readlink -f /sys/class/bluetooth/hci0/device)

USB="$HCI"

while [ "$USB" != "/" ]; do
    if [ -f "$USB/idVendor" ] &&
       [ -f "$USB/idProduct" ]; then
        break
    fi

    USB=$(dirname "$USB")
done

检查:

cat "$USB/power/wakeup"

应该返回enable。重启后再次验证,同样返回enable,且手柄顺利唤醒。

SteamOS 原子更新导致配置丢失

后来想试试测试版的steamos,切换了分支。更新之后蓝牙唤醒失效。

重新检查:

cat /etc/udev/rules.d/99-bluetooth-wakeup.rules

返回 没有那个文件或目录

与此同时:

cat "$USB/power/wakeup"

再次是disabled

steamos原子更新会删除白名单外的全部配置

为 SteamOS 原子更新增加保留配置

于是增加:

sudo mkdir -p /etc/atomic-update.conf.d

j然后:

sudo tee /etc/atomic-update.conf.d/bluetooth-wakeup.conf >/dev/null <<'EOF'
/etc/udev/rules.d/99-bluetooth-wakeup.rules
/etc/atomic-update.conf.d/bluetooth-wakeup.conf
EOF

将所需配置加入白名单,这样steamos在原子化更新时会迁移这些配置文件。

最终蓝牙唤醒配置结构

最后与蓝牙相关的两个文件是:

/etc/
├── udev/
│   └── rules.d/
│       └── 99-bluetooth-wakeup.rules
│
└── atomic-update.conf.d/
    └── bluetooth-wakeup.conf

99-bluetooth-wakeup.rules:

ACTION=="add|change", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="8087", ATTR{idProduct}=="0033", TEST=="power/wakeup", ATTR{power/wakeup}="enabled"

bluetooth-wakeup.conf:

/etc/udev/rules.d/99-bluetooth-wakeup.rules
/etc/atomic-update.conf.d/bluetooth-wakeup.conf
手柄蓝牙唤醒Steamos
http://blog.kurfuerst.online/index.php/archives/53/
本文作者 Großer Kurfürst
发布时间 2026-09-19
许可协议 CC BY-NC-SA 4.0
发表新评论