All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Schwartz <matthew.schwartz@linux.dev>
To: linux-bluetooth@vger.kernel.org
Cc: Matthew Schwartz <matthew.schwartz@linux.dev>
Subject: [PATCH BlueZ 1/3] adapter: Add btd_adapter_may_wake()
Date: Sat, 25 Jul 2026 13:18:54 -0700	[thread overview]
Message-ID: <20260725201856.2142333-2-matthew.schwartz@linux.dev> (raw)
In-Reply-To: <20260725201856.2142333-1-matthew.schwartz@linux.dev>

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.

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


  reply	other threads:[~2026-07-25 20:19 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-25 20:18 [PATCH BlueZ 0/3] Hide WakeAllowed when the adapter cannot wake the host Matthew Schwartz
2026-07-25 20:18 ` Matthew Schwartz [this message]
2026-07-25 21:19   ` bluez.test.bot
2026-07-25 20:18 ` [PATCH BlueZ 2/3] device: Hide WakeAllowed when adapter cannot wake Matthew Schwartz
2026-07-25 20:18 ` [PATCH BlueZ 3/3] doc: Mark WakeAllowed as optional Matthew Schwartz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260725201856.2142333-2-matthew.schwartz@linux.dev \
    --to=matthew.schwartz@linux.dev \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.