Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH RESEND v2] asha: allow LE 2M PHY on the audio channel
@ 2026-10-29  0:21 Kyle Pepper
  2026-10-29  1:22 ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 2+ messages in thread
From: Kyle Pepper @ 2026-10-29  0:21 UTC (permalink / raw)
  To: linux-bluetooth

Allow LE 2M on the CoC socket to increase available throughput for
capable peers. Retain LE 1M fallback and treat BT_PHY as best effort
for older kernels.

Test the PHY mask and continued startup when the preference is rejected.

Assisted-by: OpenCode:gpt-6.1-sol
---
Resending unchanged v2 after inactivity closure of the prior CI PR
(closure reported October 28). Original source and attribution retained.
Prior v2 CI passed as reported; not independently reverified.
No new hardware or remote CI result is claimed.

Changes since v1: fix sanitizer-retained daemon references with
fail-fast test stubs.
Refreshed to BlueZ 9dc7e40962f11d1d9a5568f8a7633a695288329c.
Strict non-LTO ASan/UBSan build and make check pass; ordinary LTO
build and make check pass. Strict LTO has an unchanged upstream
peripheral/btsensor warning failure, reproduced without this topic.
No new hardware trial or remote functional-lab result is claimed.

Submission review notes (not part of the commit message):
N8/UB500 completes 2M in the downstream stack. N7/1M-only hardware
is unavailable; fallback has focused unit coverage, not new hardware proof.

 .gitignore            |   1 +
 Makefile.am           |   9 ++
 profiles/audio/asha.c |  11 ++
 unit/test-asha-phy.c  | 241 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 262 insertions(+)
 create mode 100644 unit/test-asha-phy.c

diff --git a/.gitignore b/.gitignore
index 06b24735df..d214ba0591 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,6 +112,7 @@ unit/test-lib
 unit/test-mgmt
 unit/test-uhid
 unit/test-hfp
+unit/test-asha-phy
 unit/test-crypto
 unit/test-ecc
 unit/test-hog
diff --git a/Makefile.am b/Makefile.am
index f742458d11..2041ac87db 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -706,6 +706,15 @@ unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
 
 unit_tests += unit/test-hfp
 
+unit_tests += unit/test-asha-phy
+
+unit_test_asha_phy_SOURCES = unit/test-asha-phy.c
+unit_test_asha_phy_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
+	-ffunction-sections -fdata-sections
+unit_test_asha_phy_LDADD = src/libshared-glib.la \
+	lib/libbluetooth-internal.la $(GLIB_LIBS) $(DBUS_LIBS)
+unit_test_asha_phy_LDFLAGS = -Wl,--gc-sections
+
 unit_test_hfp_SOURCES = unit/test-hfp.c
 unit_test_hfp_LDADD = src/libshared-glib.la $(GLIB_LIBS)
 
diff --git a/profiles/audio/asha.c b/profiles/audio/asha.c
index 8e625fdca3..d86224764d 100644
--- a/profiles/audio/asha.c
+++ b/profiles/audio/asha.c
@@ -88,6 +88,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	struct connect_data *conn_data = user_data;
 	struct bt_asha_device *asha_dev = conn_data->asha_dev;
 	GError *gerr = NULL;
+	uint32_t phys;
+	int fd;
 
 	if (err) {
 		error("%s", err->message);
@@ -105,6 +107,15 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 		g_error_free(gerr);
 	}
 
+	/*
+	 * Allow LE 2M with LE 1M fallback. Older kernels may lack BT_PHY.
+	 */
+	phys = BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX |
+			BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX;
+	fd = g_io_channel_unix_get_fd(io);
+	if (setsockopt(fd, SOL_BLUETOOTH, BT_PHY, &phys, sizeof(phys)) < 0)
+		DBG("Could not set LE 2M PHY preference: %s", strerror(errno));
+
 	asha_dev->io = io;
 
 	bt_asha_start(asha_dev->asha, conn_data->cb,
diff --git a/unit/test-asha-phy.c b/unit/test-asha-phy.c
new file mode 100644
index 0000000000..c58101ebfd
--- /dev/null
+++ b/unit/test-asha-phy.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <assert.h>
+#include <stdarg.h>
+#include <sys/socket.h>
+
+int test_setsockopt(int fd, int level, int option, const void *value,
+							socklen_t length);
+
+/* Source-level mocks remain effective with link-time optimization. */
+#define setsockopt test_setsockopt
+#define bt_io_get test_io_get
+#define bt_asha_start test_start
+#include "profiles/audio/asha.c"
+#undef setsockopt
+#undef bt_io_get
+#undef bt_asha_start
+#include "src/shared/tester.h"
+
+static unsigned int preferences, starts;
+static bool mtu_ok;
+static int preference_error, expected_fd;
+
+/* Sanitizers retain the plugin's globals, including unused daemon callbacks. */
+int btd_profile_register(struct btd_profile *profile)
+{
+	assert(false);
+}
+
+void btd_profile_unregister(struct btd_profile *profile)
+{
+	assert(false);
+}
+
+const char *device_get_path(const struct btd_device *device)
+{
+	assert(false);
+}
+
+const bdaddr_t *device_get_address(struct btd_device *device)
+{
+	assert(false);
+}
+
+struct btd_adapter *device_get_adapter(struct btd_device *device)
+{
+	assert(false);
+}
+
+const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter)
+{
+	assert(false);
+}
+
+void btd_device_set_conn_param(struct btd_device *device,
+				uint16_t min_interval, uint16_t max_interval,
+					uint16_t latency, uint16_t timeout)
+{
+	assert(false);
+}
+
+struct gatt_db *btd_device_get_gatt_db(struct btd_device *device)
+{
+	assert(false);
+}
+
+struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device)
+{
+	assert(false);
+}
+
+struct btd_device *btd_service_get_device(const struct btd_service *service)
+{
+	assert(false);
+}
+
+void *btd_service_get_user_data(const struct btd_service *service)
+{
+	assert(false);
+}
+
+void btd_service_set_user_data(struct btd_service *service, void *user_data)
+{
+	assert(false);
+}
+
+void btd_service_connecting_complete(struct btd_service *service, int err)
+{
+	assert(false);
+}
+
+void btd_service_disconnecting_complete(struct btd_service *service, int err)
+{
+	assert(false);
+}
+
+DBusConnection *btd_get_dbus_connection(void)
+{
+	assert(false);
+}
+
+gboolean g_dbus_register_interface(DBusConnection *connection,
+				const char *path, const char *name,
+				const GDBusMethodTable *methods,
+				const GDBusSignalTable *signals,
+				const GDBusPropertyTable *properties,
+				void *user_data, GDBusDestroyFunction destroy)
+{
+	assert(false);
+}
+
+gboolean g_dbus_unregister_interface(DBusConnection *connection,
+					const char *path, const char *name)
+{
+	assert(false);
+}
+
+const struct media_endpoint *media_endpoint_get_asha(void)
+{
+	assert(false);
+}
+
+struct media_transport *media_transport_create(struct btd_device *device,
+				const char *remote_endpoint,
+				uint8_t *configuration, size_t size,
+				void *data, void *stream)
+{
+	assert(false);
+}
+
+void media_transport_destroy(struct media_transport *transport)
+{
+	assert(false);
+}
+
+const char *media_transport_get_path(struct media_transport *transport)
+{
+	assert(false);
+}
+
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+				GDestroyNotify destroy, GError **gerr,
+							BtIOOption opt1, ...)
+{
+	assert(false);
+}
+
+void btd_error(uint16_t index, const char *format, ...)
+{
+}
+
+void btd_debug(uint16_t index, const char *format, ...)
+{
+}
+
+int test_setsockopt(int fd, int level, int option, const void *value,
+							socklen_t length)
+{
+	const uint32_t *phys = value;
+
+	assert(fd == expected_fd && level == SOL_BLUETOOTH && option == BT_PHY);
+	assert(length == sizeof(*phys));
+	assert(*phys == (BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX |
+					BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX));
+	assert(starts == 0);
+	preferences++;
+	errno = preference_error;
+	return preference_error ? -1 : 0;
+}
+
+gboolean test_io_get(GIOChannel *io, GError **error, BtIOOption first, ...)
+{
+	va_list args;
+	uint16_t *imtu, *omtu;
+
+	if (!mtu_ok) {
+		*error = g_error_new(G_IO_CHANNEL_ERROR,
+				G_IO_CHANNEL_ERROR_FAILED, "MTU failure");
+		return FALSE;
+	}
+
+	assert(first == BT_IO_OPT_IMTU);
+	va_start(args, first);
+	imtu = va_arg(args, uint16_t *);
+	assert(va_arg(args, int) == BT_IO_OPT_OMTU);
+	omtu = va_arg(args, uint16_t *);
+	assert(va_arg(args, int) == BT_IO_OPT_INVALID);
+	va_end(args);
+	*imtu = 512;
+	*omtu = 163;
+	return TRUE;
+}
+
+unsigned int test_start(struct bt_asha *asha, bt_asha_cb_t callback, void *data)
+{
+	assert(preferences == 1);
+	starts++;
+	return 0;
+}
+
+static void test_phy(const void *user_data)
+{
+	const int errors[] = { 0, ENOPROTOOPT, EINVAL };
+	unsigned int i;
+	int fds[2];
+	GIOChannel *io;
+	GError *error;
+	struct bt_asha asha = { 0 };
+	struct bt_asha_device device = { .asha = &asha };
+	struct connect_data data = { .asha_dev = &device };
+
+	assert(!pipe(fds));
+	io = g_io_channel_unix_new(fds[0]);
+	expected_fd = fds[0];
+
+	for (i = 0; i < ARRAY_SIZE(errors); i++) {
+		preferences = starts = 0;
+		preference_error = errors[i];
+		mtu_ok = i != 2;
+		connect_cb(io, NULL, &data);
+		assert(preferences == 1 && starts == 1 && device.io == io);
+		assert(device.imtu == 512 && device.omtu == 163);
+	}
+
+	preferences = starts = 0;
+	error = g_error_new(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED,
+							"mock connection failure");
+	connect_cb(io, error, &data);
+	assert(preferences == 0 && starts == 0);
+	g_error_free(error);
+	g_io_channel_unref(io);
+	close(fds[0]);
+	close(fds[1]);
+	tester_test_passed();
+}
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+	tester_add("ASHA/PHY/preference", NULL, NULL, test_phy, NULL);
+	return tester_run();
+}

base-commit: 9dc7e40962f11d1d9a5568f8a7633a695288329c
-- 
2.56.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH RESEND v2] asha: allow LE 2M PHY on the audio channel
  2026-10-29  0:21 [PATCH RESEND v2] asha: allow LE 2M PHY on the audio channel Kyle Pepper
@ 2026-10-29  1:22 ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 2+ messages in thread
From: Luiz Augusto von Dentz @ 2026-10-29  1:22 UTC (permalink / raw)
  To: Kyle Pepper; +Cc: linux-bluetooth

Hi Kyle,

On Wed, Oct 28, 2026 at 8:21 PM Kyle Pepper <cochcoder@proton.me> wrote:
>
> Allow LE 2M on the CoC socket to increase available throughput for
> capable peers. Retain LE 1M fallback and treat BT_PHY as best effort
> for older kernels.
>
> Test the PHY mask and continued startup when the preference is rejected.
>
> Assisted-by: OpenCode:gpt-6.1-sol
> ---
> Resending unchanged v2 after inactivity closure of the prior CI PR
> (closure reported October 28). Original source and attribution retained.
> Prior v2 CI passed as reported; not independently reverified.
> No new hardware or remote CI result is claimed.
>
> Changes since v1: fix sanitizer-retained daemon references with
> fail-fast test stubs.
> Refreshed to BlueZ 9dc7e40962f11d1d9a5568f8a7633a695288329c.
> Strict non-LTO ASan/UBSan build and make check pass; ordinary LTO
> build and make check pass. Strict LTO has an unchanged upstream
> peripheral/btsensor warning failure, reproduced without this topic.
> No new hardware trial or remote functional-lab result is claimed.
>
> Submission review notes (not part of the commit message):
> N8/UB500 completes 2M in the downstream stack. N7/1M-only hardware
> is unavailable; fallback has focused unit coverage, not new hardware proof.
>
>  .gitignore            |   1 +
>  Makefile.am           |   9 ++
>  profiles/audio/asha.c |  11 ++
>  unit/test-asha-phy.c  | 241 ++++++++++++++++++++++++++++++++++++++++++

Don't create new test files, just reuse test-asha.

>  4 files changed, 262 insertions(+)
>  create mode 100644 unit/test-asha-phy.c
>
> diff --git a/.gitignore b/.gitignore
> index 06b24735df..d214ba0591 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -112,6 +112,7 @@ unit/test-lib
>  unit/test-mgmt
>  unit/test-uhid
>  unit/test-hfp
> +unit/test-asha-phy
>  unit/test-crypto
>  unit/test-ecc
>  unit/test-hog
> diff --git a/Makefile.am b/Makefile.am
> index f742458d11..2041ac87db 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -706,6 +706,15 @@ unit_test_avrcp_LDADD = lib/libbluetooth-internal.la \
>
>  unit_tests += unit/test-hfp
>
> +unit_tests += unit/test-asha-phy
> +
> +unit_test_asha_phy_SOURCES = unit/test-asha-phy.c
> +unit_test_asha_phy_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
> +       -ffunction-sections -fdata-sections
> +unit_test_asha_phy_LDADD = src/libshared-glib.la \
> +       lib/libbluetooth-internal.la $(GLIB_LIBS) $(DBUS_LIBS)
> +unit_test_asha_phy_LDFLAGS = -Wl,--gc-sections
> +
>  unit_test_hfp_SOURCES = unit/test-hfp.c
>  unit_test_hfp_LDADD = src/libshared-glib.la $(GLIB_LIBS)
>
> diff --git a/profiles/audio/asha.c b/profiles/audio/asha.c
> index 8e625fdca3..d86224764d 100644
> --- a/profiles/audio/asha.c
> +++ b/profiles/audio/asha.c
> @@ -88,6 +88,8 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
>         struct connect_data *conn_data = user_data;
>         struct bt_asha_device *asha_dev = conn_data->asha_dev;
>         GError *gerr = NULL;
> +       uint32_t phys;
> +       int fd;
>
>         if (err) {
>                 error("%s", err->message);
> @@ -105,6 +107,15 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
>                 g_error_free(gerr);
>         }
>
> +       /*
> +        * Allow LE 2M with LE 1M fallback. Older kernels may lack BT_PHY.
> +        */
> +       phys = BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX |
> +                       BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX;
> +       fd = g_io_channel_unix_get_fd(io);
> +       if (setsockopt(fd, SOL_BLUETOOTH, BT_PHY, &phys, sizeof(phys)) < 0)
> +               DBG("Could not set LE 2M PHY preference: %s", strerror(errno));
> +
>         asha_dev->io = io;
>
>         bt_asha_start(asha_dev->asha, conn_data->cb,
> diff --git a/unit/test-asha-phy.c b/unit/test-asha-phy.c
> new file mode 100644
> index 0000000000..c58101ebfd
> --- /dev/null
> +++ b/unit/test-asha-phy.c
> @@ -0,0 +1,241 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <assert.h>
> +#include <stdarg.h>
> +#include <sys/socket.h>
> +
> +int test_setsockopt(int fd, int level, int option, const void *value,
> +                                                       socklen_t length);
> +
> +/* Source-level mocks remain effective with link-time optimization. */
> +#define setsockopt test_setsockopt
> +#define bt_io_get test_io_get
> +#define bt_asha_start test_start
> +#include "profiles/audio/asha.c"
> +#undef setsockopt
> +#undef bt_io_get
> +#undef bt_asha_start
> +#include "src/shared/tester.h"
> +
> +static unsigned int preferences, starts;
> +static bool mtu_ok;
> +static int preference_error, expected_fd;
> +
> +/* Sanitizers retain the plugin's globals, including unused daemon callbacks. */
> +int btd_profile_register(struct btd_profile *profile)
> +{
> +       assert(false);
> +}
> +
> +void btd_profile_unregister(struct btd_profile *profile)
> +{
> +       assert(false);
> +}
> +
> +const char *device_get_path(const struct btd_device *device)
> +{
> +       assert(false);
> +}
> +
> +const bdaddr_t *device_get_address(struct btd_device *device)
> +{
> +       assert(false);
> +}
> +
> +struct btd_adapter *device_get_adapter(struct btd_device *device)
> +{
> +       assert(false);
> +}
> +
> +const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter)
> +{
> +       assert(false);
> +}
> +
> +void btd_device_set_conn_param(struct btd_device *device,
> +                               uint16_t min_interval, uint16_t max_interval,
> +                                       uint16_t latency, uint16_t timeout)
> +{
> +       assert(false);
> +}
> +
> +struct gatt_db *btd_device_get_gatt_db(struct btd_device *device)
> +{
> +       assert(false);
> +}
> +
> +struct bt_gatt_client *btd_device_get_gatt_client(struct btd_device *device)
> +{
> +       assert(false);
> +}
> +
> +struct btd_device *btd_service_get_device(const struct btd_service *service)
> +{
> +       assert(false);
> +}
> +
> +void *btd_service_get_user_data(const struct btd_service *service)
> +{
> +       assert(false);
> +}
> +
> +void btd_service_set_user_data(struct btd_service *service, void *user_data)
> +{
> +       assert(false);
> +}
> +
> +void btd_service_connecting_complete(struct btd_service *service, int err)
> +{
> +       assert(false);
> +}
> +
> +void btd_service_disconnecting_complete(struct btd_service *service, int err)
> +{
> +       assert(false);
> +}
> +
> +DBusConnection *btd_get_dbus_connection(void)
> +{
> +       assert(false);
> +}
> +
> +gboolean g_dbus_register_interface(DBusConnection *connection,
> +                               const char *path, const char *name,
> +                               const GDBusMethodTable *methods,
> +                               const GDBusSignalTable *signals,
> +                               const GDBusPropertyTable *properties,
> +                               void *user_data, GDBusDestroyFunction destroy)
> +{
> +       assert(false);
> +}
> +
> +gboolean g_dbus_unregister_interface(DBusConnection *connection,
> +                                       const char *path, const char *name)
> +{
> +       assert(false);
> +}
> +
> +const struct media_endpoint *media_endpoint_get_asha(void)
> +{
> +       assert(false);
> +}
> +
> +struct media_transport *media_transport_create(struct btd_device *device,
> +                               const char *remote_endpoint,
> +                               uint8_t *configuration, size_t size,
> +                               void *data, void *stream)
> +{
> +       assert(false);
> +}
> +
> +void media_transport_destroy(struct media_transport *transport)
> +{
> +       assert(false);
> +}
> +
> +const char *media_transport_get_path(struct media_transport *transport)
> +{
> +       assert(false);
> +}
> +
> +GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
> +                               GDestroyNotify destroy, GError **gerr,
> +                                                       BtIOOption opt1, ...)
> +{
> +       assert(false);
> +}
> +
> +void btd_error(uint16_t index, const char *format, ...)
> +{
> +}
> +
> +void btd_debug(uint16_t index, const char *format, ...)
> +{
> +}
> +
> +int test_setsockopt(int fd, int level, int option, const void *value,
> +                                                       socklen_t length)
> +{
> +       const uint32_t *phys = value;
> +
> +       assert(fd == expected_fd && level == SOL_BLUETOOTH && option == BT_PHY);
> +       assert(length == sizeof(*phys));
> +       assert(*phys == (BT_PHY_LE_1M_TX | BT_PHY_LE_1M_RX |
> +                                       BT_PHY_LE_2M_TX | BT_PHY_LE_2M_RX));
> +       assert(starts == 0);
> +       preferences++;
> +       errno = preference_error;
> +       return preference_error ? -1 : 0;
> +}
> +
> +gboolean test_io_get(GIOChannel *io, GError **error, BtIOOption first, ...)
> +{
> +       va_list args;
> +       uint16_t *imtu, *omtu;
> +
> +       if (!mtu_ok) {
> +               *error = g_error_new(G_IO_CHANNEL_ERROR,
> +                               G_IO_CHANNEL_ERROR_FAILED, "MTU failure");
> +               return FALSE;
> +       }
> +
> +       assert(first == BT_IO_OPT_IMTU);
> +       va_start(args, first);
> +       imtu = va_arg(args, uint16_t *);
> +       assert(va_arg(args, int) == BT_IO_OPT_OMTU);
> +       omtu = va_arg(args, uint16_t *);
> +       assert(va_arg(args, int) == BT_IO_OPT_INVALID);
> +       va_end(args);
> +       *imtu = 512;
> +       *omtu = 163;
> +       return TRUE;
> +}
> +
> +unsigned int test_start(struct bt_asha *asha, bt_asha_cb_t callback, void *data)
> +{
> +       assert(preferences == 1);
> +       starts++;
> +       return 0;
> +}
> +
> +static void test_phy(const void *user_data)
> +{
> +       const int errors[] = { 0, ENOPROTOOPT, EINVAL };
> +       unsigned int i;
> +       int fds[2];
> +       GIOChannel *io;
> +       GError *error;
> +       struct bt_asha asha = { 0 };
> +       struct bt_asha_device device = { .asha = &asha };
> +       struct connect_data data = { .asha_dev = &device };
> +
> +       assert(!pipe(fds));
> +       io = g_io_channel_unix_new(fds[0]);
> +       expected_fd = fds[0];
> +
> +       for (i = 0; i < ARRAY_SIZE(errors); i++) {
> +               preferences = starts = 0;
> +               preference_error = errors[i];
> +               mtu_ok = i != 2;
> +               connect_cb(io, NULL, &data);
> +               assert(preferences == 1 && starts == 1 && device.io == io);
> +               assert(device.imtu == 512 && device.omtu == 163);
> +       }
> +
> +       preferences = starts = 0;
> +       error = g_error_new(G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED,
> +                                                       "mock connection failure");
> +       connect_cb(io, error, &data);
> +       assert(preferences == 0 && starts == 0);
> +       g_error_free(error);
> +       g_io_channel_unref(io);
> +       close(fds[0]);
> +       close(fds[1]);
> +       tester_test_passed();
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       tester_init(&argc, &argv);
> +       tester_add("ASHA/PHY/preference", NULL, NULL, test_phy, NULL);
> +       return tester_run();
> +}
>
> base-commit: 9dc7e40962f11d1d9a5568f8a7633a695288329c
> --
> 2.56.0
>
>
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-29  1:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29  0:21 [PATCH RESEND v2] asha: allow LE 2M PHY on the audio channel Kyle Pepper
2026-10-29  1:22 ` Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox