Re: [PATCH BlueZ 1/3] adapter: Add btd_adapter_may_wake()

Luiz Augusto von Dentz <[email protected]> Mon, 27 Jul 2026 15:58:46 -0400
Newsgroups org.kernel.vger.linux-bluetooth
Message-ID <CABBYNZLaSBPDbbWUVm2r57aTp8eikutNYKTW7csDjQcq1F9Fpg@mail.gmail.com>
Hi Matthew,

On Sat, Jul 25, 2026 at 4:19 PM Matthew Schwartz
<[email protected]> wrote:
>
> The kernel provides no interface for querying whether a controller is
> currently configured to wake the host from suspend. hci_register_dev()
> marks HCI_CONN_FLAG_REMOTE_WAKEUP as supported whenever a driver
> provides a wakeup callback, and btusb always does, so the supported
> flags reported through mgmt say nothing about the runtime setting. The
> value that matters, device_may_wakeup() on the underlying USB device,
> is only evaluated during the suspend flow, and the wakeup callback is
> not a pure query (btmtksdio's variant sends vendor HCI commands), so
> mgmt could not simply re-evaluate it on Get Device Flags without new
> kernel infrastructure.
>
> Add btd_adapter_may_wake(), which reconstructs what btusb reports by
> walking the adapter's sysfs ancestry to the closest USB device and
> reading its power/wakeup attribute. A missing attribute means the
> device cannot generate wake events at all, which is what btusb
> arranges for the fake CSR clones by clearing the USB device's wakeup
> capability. The attribute is read per call so that each query
> reflects the current setting.
>
> Only USB is handled. Controllers on other buses keep the current
> behavior. btmtksdio exposes the same attribute on its SDIO function
> device, but its wakeup callback can also depend on a vendor command.

I guess we should introduce some new mgmt setting that allows us to
detect whether the adapter is capable of waking up the system or not.
The tricky part is this being dynamically enabled/disabled with the
likes of:

echo "disabled" > /sys/bus/usb/devices/usb1/power/wakeup

So this would need to send MGMT_EV_NEW_SETTINGS reflecting the current
value of hdev->wakeup, which I don't know it really is worth the
trouble, or we should really hack together the sysfs entry like this,
or maybe we expose the sysfs entry of the device somehow so it is
known to bluetoothd via some mgmt event or something like that.

> Assisted-by: Claude:claude-fable-5
> ---
>  src/adapter.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/adapter.h |  1 +
>  2 files changed, 71 insertions(+)
>
> diff --git a/src/adapter.c b/src/adapter.c
> index a56eafabe..65b394f82 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -563,6 +563,76 @@ uint8_t btd_adapter_get_address_type(struct btd_adapter *adapter)
>         return adapter->bdaddr_type;
>  }
>
> +static bool sysfs_wakeup_enabled(const char *dir)
> +{
> +       char path[PATH_MAX];
> +       char *contents;
> +       bool enabled;
> +
> +       snprintf(path, sizeof(path), "%s/power/wakeup", dir);
> +
> +       /* A missing attribute means the device cannot wake the host */
> +       if (!g_file_get_contents(path, &contents, NULL, NULL))
> +               return false;
> +
> +       enabled = g_str_has_prefix(contents, "enabled");
> +
> +       g_free(contents);
> +
> +       return enabled;
> +}
> +
> +static bool sysfs_is_usb_device(const char *dir)
> +{
> +       char path[PATH_MAX];
> +
> +       /* USB devices expose idVendor, USB interfaces do not */
> +       snprintf(path, sizeof(path), "%s/idVendor", dir);
> +
> +       return g_file_test(path, G_FILE_TEST_EXISTS);
> +}
> +
> +/*
> + * Whether the controller is currently configured to wake the host from
> + * system suspend. btusb reports this to the kernel with
> + * device_may_wakeup() on the underlying USB device, which userspace
> + * controls through its power/wakeup attribute. Only USB is handled
> + * here. Controllers on other buses are assumed to be able to wake the
> + * host. The attribute is read on every call so that runtime changes
> + * are picked up.
> + */
> +bool btd_adapter_may_wake(struct btd_adapter *adapter)
> +{
> +       char path[PATH_MAX];
> +       char *dir;
> +       char *sep;
> +       bool may_wake = true;
> +
> +       snprintf(path, sizeof(path), "/sys/class/bluetooth/hci%u/device",
> +                                                       adapter->dev_id);
> +
> +       dir = realpath(path, NULL);
> +       if (!dir)
> +               return true;
> +
> +       while (g_str_has_prefix(dir, "/sys/devices/")) {
> +               if (sysfs_is_usb_device(dir)) {
> +                       may_wake = sysfs_wakeup_enabled(dir);
> +                       break;
> +               }
> +
> +               sep = strrchr(dir, '/');
> +               if (!sep)
> +                       break;
> +
> +               *sep = '\0';
> +       }
> +
> +       free(dir);
> +
> +       return may_wake;
> +}
> +
>  static void store_adapter_info(struct btd_adapter *adapter)
>  {
>         GKeyFile *key_file;
> diff --git a/src/adapter.h b/src/adapter.h
> index a9e1bbf66..ae0011ff7 100644
> --- a/src/adapter.h
> +++ b/src/adapter.h
> @@ -107,6 +107,7 @@ const char *adapter_get_path(struct btd_adapter *adapter);
>  const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter);
>  uint8_t btd_adapter_get_address_type(struct btd_adapter *adapter);
>  const char *btd_adapter_get_storage_dir(struct btd_adapter *adapter);
> +bool btd_adapter_may_wake(struct btd_adapter *adapter);
>
>  int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec);
>  void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle);
> --
> 2.55.0
>
>


-- 
Luiz Augusto von Dentz