summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2026-06-04 08:37:39 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-06-11 14:24:40 -0400
commitcfb192390bb8e8674b78d750e31fc49a5586596d (patch)
tree6b5016224714122d669011cf20ebffe73e3aa9a9
parent3d93e1bb0fb881fe3ef961d1120556658e9cac4d (diff)
downloadlinux-cfb192390bb8e8674b78d750e31fc49a5586596d.tar.gz
linux-cfb192390bb8e8674b78d750e31fc49a5586596d.zip
Bluetooth: btusb: fix wakeup irq devres lifetime
The OOB wakeup interrupt is device managed but its lifetime is incorrectly tied to the child HCI device rather than the USB interface to which the driver is bound. This should not cause any trouble currently as the interrupt will be disabled when the HCI device is deregistered on disconnect (but this was not always the case, see [1]), and there should be no further references if probe fails before registering it. But it is still technically wrong as the reference counted HCI device could in theory remain after a probe failure. Explicitly free the interrupt on disconnect so that it is guaranteed to be disabled before freeing the (non-managed) driver data (including if disconnected while suspended). [1] 699fb50d9903 ("drivers: base: Free devm resources when unregistering a device") Fixes: fd913ef7ce61 ("Bluetooth: btusb: Add out-of-band wakeup support") Cc: Rajat Jain <rajatja@google.com> Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-rw-r--r--drivers/bluetooth/btusb.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 966e017ac1df..843c649f8053 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3843,8 +3843,7 @@ static int btusb_config_oob_wake(struct hci_dev *hdev)
}
irq_set_status_flags(irq, IRQ_NOAUTOEN);
- ret = devm_request_irq(&hdev->dev, irq, btusb_oob_wake_handler,
- 0, "OOB Wake-on-BT", data);
+ ret = request_irq(irq, btusb_oob_wake_handler, 0, "OOB Wake-on-BT", data);
if (ret) {
bt_dev_err(hdev, "%s: IRQ request failed", __func__);
return ret;
@@ -3853,12 +3852,18 @@ static int btusb_config_oob_wake(struct hci_dev *hdev)
ret = device_init_wakeup(dev, true);
if (ret) {
bt_dev_err(hdev, "%s: failed to init_wakeup", __func__);
- return ret;
+ goto err_free_irq;
}
data->oob_wake_irq = irq;
bt_dev_info(hdev, "OOB Wake-on-BT configured at IRQ %u", irq);
+
return 0;
+
+err_free_irq:
+ free_irq(irq, data);
+
+ return ret;
}
#else
static inline int btusb_config_oob_wake(struct hci_dev *hdev)
@@ -4457,8 +4462,10 @@ err_release_siblings:
err_kill_tx_urbs:
usb_kill_anchored_urbs(&data->tx_anchor);
err_disable_wakeup:
- if (data->oob_wake_irq)
+ if (data->oob_wake_irq) {
device_init_wakeup(&data->udev->dev, false);
+ free_irq(data->oob_wake_irq, data);
+ }
out_free_dev:
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
@@ -4491,8 +4498,11 @@ static void btusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev);
- if (data->oob_wake_irq)
+ if (data->oob_wake_irq) {
device_init_wakeup(&data->udev->dev, false);
+ free_irq(data->oob_wake_irq, data);
+ }
+
if (data->reset_gpio)
gpiod_put(data->reset_gpio);