* [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support
@ 2026-03-17 20:26 Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: hadess, luiz.dentz, vi, Martin BTS
Changes v3:
* Simplified config setting approach.
* Added a 2-second timeout for secondary discovery.
* Separated BLE/GATT-to-HID code from Procon 2 code.
* Removed all Switch/Procon 2 overlap with the HID kernel driver.
* Link to v2: https://lore.kernel.org/all/20260308124745.19248-1-martinbts@gmx.net/
v3 blurb:
While the overall motivation for my work is the Procon 2 controller, there
are two things very BlueZ specific:
A) Devices (e.g. the Procon 2) may deviate from the spec and not respond
to service discovery, which currently must result in a failed
connection attempt.
B) (I think) There currently isn't a facility that allows feeding HID
devices BLE/GATT traffic.
* Patches 1 and 2 are two alternatives to resolve problem A.
* Patch 5 attempts to resolve problem B.
* Patches 3-4 are minor cleanups (rename set_alias, add Gaming
appearance class), unchanged from v2.
* Patch 6 is minimalistic support for the Switch 2 controllers so that
HID drivers can take over
Patch 1 uses a configuration setting (v1 feedback), while
Patch 2 uses a new 2-second timeout (v2 feedback).
Both work, but connecting the controller using only Patch 2 is a lot
less reliable. The Procon 2 does only try/wait for a connection for
a few seconds. BLE discovery tends to take so long that together with
the 2 second timeout the controller gives up before the timeout fires.
Patch 1 always worked, when the device showed up in bluetoothctl.
Patch 1 and Patch 2 are both individually suited to solve my
immediate problem. From my point of view it is not necessary to apply
both. I am submitting both for side-by-side comparison and discussion.
Patch 5 is a GATT-UHID bridge that forwards notifications from the
controller to the hid device and hid-device-writes to the
controller. This was previously burried in all the other code that
supported the Procon 2. It can now be used for other input devices that
use only GATT. As far as I can tell, this does not overlap at all with
other Switch 2 support efforts.
Patche 6 is specific to the Switch 2 controllers so that they can be
interacted with through uhid. In contrast to v1 and v2 this is "minimal"
code that makes bluetoothd create a HID device and does the plumbing for
a GATT-HID bridge. There is no overlap to any published Switch 2 driver (that
I am aware of). The result is not usable. One still needs a driver that
"does the right thing". I am keeping my "works on my machine" code here:
https://github.com/martin-bts/hid-switch2-dkms. I will keep using it
until we get proper driver support in the kernel.
Disclaimer (as in v1): I only have a Nintendo Switch 2 Pro Controller
and cannot attest to anything related to any other controller.
Martin BTS (6):
shared/gatt: Add skip_secondary option for GATT client
shared/gatt: Add timeout for secondary service discovery
device: Rename set_alias to btd_device_set_alias()
dbus-common: Add Gaming appearance class (0x2a)
plugins/gatt-uhid: Add generic GATT-to-UHID bridge
plugins/switch2: Add Nintendo Switch 2 Controller plugin
Makefile.plugins | 5 +
peripheral/gatt.c | 3 +-
plugins/gatt-uhid.c | 350 +++++++++++++++++++++++++++++++++++++++
plugins/gatt-uhid.h | 56 +++++++
plugins/switch2.c | 255 ++++++++++++++++++++++++++++
src/dbus-common.c | 2 +
src/device.c | 24 +--
src/device.h | 2 +
src/shared/gatt-client.c | 70 +++++++-
src/shared/gatt-client.h | 3 +-
tools/btgatt-client.c | 2 +-
unit/test-bap.c | 2 +-
unit/test-gatt.c | 2 +-
unit/test-gmap.c | 2 +-
unit/test-mcp.c | 2 +-
unit/test-micp.c | 3 +-
unit/test-tmap.c | 2 +-
17 files changed, 762 insertions(+), 23 deletions(-)
create mode 100644 plugins/gatt-uhid.c
create mode 100644 plugins/gatt-uhid.h
create mode 100644 plugins/switch2.c
--
2.47.3
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
2026-03-17 21:31 ` BLE-HID/Nintendo Switch 2 support bluez.test.bot
2026-03-17 20:26 ` [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery Martin BTS
` (4 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth
Cc: hadess, luiz.dentz, vi, Martin BTS, Claude Opus 4.6 (1M context)
Some BLE devices reject or ignore secondary service discovery requests,
causing ATT timeouts that terminate the connection. Add a skip_secondary
parameter to bt_gatt_client_new() that skips the secondary service
discovery step during GATT client initialization. Add
btd_device_set_skip_secondary() so device-specific plugins can enable
this. All existing callers pass false (no behavior change).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
peripheral/gatt.c | 3 ++-
src/device.c | 9 ++++++++-
src/device.h | 1 +
src/shared/gatt-client.c | 8 ++++++--
src/shared/gatt-client.h | 3 ++-
tools/btgatt-client.c | 2 +-
unit/test-bap.c | 2 +-
unit/test-gatt.c | 2 +-
unit/test-gmap.c | 2 +-
unit/test-mcp.c | 2 +-
unit/test-micp.c | 3 ++-
unit/test-tmap.c | 2 +-
12 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/peripheral/gatt.c b/peripheral/gatt.c
index d1ddf0c97..2af67f24a 100644
--- a/peripheral/gatt.c
+++ b/peripheral/gatt.c
@@ -121,7 +121,8 @@ static struct gatt_conn *gatt_conn_new(int fd)
return NULL;
}
- conn->client = bt_gatt_client_new(gatt_cache, conn->att, mtu, 0);
+ conn->client = bt_gatt_client_new(gatt_cache, conn->att, mtu, 0,
+ false);
if (!conn->gatt) {
fprintf(stderr, "Failed to create GATT client\n");
bt_gatt_server_unref(conn->gatt);
diff --git a/src/device.c b/src/device.c
index 3ea683667..fbe137db7 100644
--- a/src/device.c
+++ b/src/device.c
@@ -213,6 +213,7 @@ struct btd_device {
bool pending_paired; /* "Paired" waiting for SDP */
bool svc_refreshed;
bool refresh_discovery;
+ bool skip_secondary;
/* Manage whether this device can wake the system from suspend.
* - wake_support: Requires a profile that supports wake (i.e. HID)
@@ -6302,7 +6303,8 @@ static void gatt_client_init(struct btd_device *device)
}
device->client = bt_gatt_client_new(device->db, device->att,
- device->att_mtu, features);
+ device->att_mtu, features,
+ device->skip_secondary);
if (!device->client) {
DBG("Failed to initialize");
return;
@@ -8254,6 +8256,11 @@ void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval,
timeout);
}
+void btd_device_set_skip_secondary(struct btd_device *device, bool skip)
+{
+ device->skip_secondary = skip;
+}
+
void btd_device_foreach_service_data(struct btd_device *dev, bt_ad_func_t func,
void *data)
{
diff --git a/src/device.h b/src/device.h
index c7b8b2a16..fe988652d 100644
--- a/src/device.h
+++ b/src/device.h
@@ -231,6 +231,7 @@ void btd_device_foreach_ad(struct btd_device *dev, bt_device_ad_func_t func,
void btd_device_set_conn_param(struct btd_device *device, uint16_t min_interval,
uint16_t max_interval, uint16_t latency,
uint16_t timeout);
+void btd_device_set_skip_secondary(struct btd_device *device, bool skip);
void btd_device_foreach_service_data(struct btd_device *dev,
bt_device_ad_func_t func,
void *data);
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index df1541b88..e1685809f 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -93,6 +93,7 @@ struct bt_gatt_client {
struct queue *notify_chrcs;
int next_reg_id;
unsigned int disc_id, nfy_id, nfy_mult_id, ind_id;
+ bool skip_secondary;
/*
* Handles of the GATT Service and the Service Changed characteristic
@@ -1344,7 +1345,7 @@ secondary:
* functionality of a device and is referenced from at least one
* primary service on the device.
*/
- if (queue_isempty(op->pending_svcs))
+ if (queue_isempty(op->pending_svcs) || client->skip_secondary)
goto done;
/* Discover secondary services */
@@ -2550,7 +2551,8 @@ fail:
struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
struct bt_att *att,
uint16_t mtu,
- uint8_t features)
+ uint8_t features,
+ bool skip_secondary)
{
struct bt_gatt_client *client;
@@ -2561,6 +2563,8 @@ struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
if (!client)
return NULL;
+ client->skip_secondary = skip_secondary;
+
if (!gatt_client_init(client, mtu)) {
bt_gatt_client_free(client);
return NULL;
diff --git a/src/shared/gatt-client.h b/src/shared/gatt-client.h
index 63cf99500..d9655e6f0 100644
--- a/src/shared/gatt-client.h
+++ b/src/shared/gatt-client.h
@@ -19,7 +19,8 @@ struct bt_gatt_client;
struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
struct bt_att *att,
uint16_t mtu,
- uint8_t features);
+ uint8_t features,
+ bool skip_secondary);
struct bt_gatt_client *bt_gatt_client_clone(struct bt_gatt_client *client);
struct bt_gatt_client *bt_gatt_client_ref(struct bt_gatt_client *client);
diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index 667b3d651..58999011a 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -206,7 +206,7 @@ static struct client *client_create(int fd, uint16_t mtu)
return NULL;
}
- cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu, 0);
+ cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu, 0, false);
if (!cli->gatt) {
fprintf(stderr, "Failed to create GATT client\n");
gatt_db_unref(cli->db);
diff --git a/unit/test-bap.c b/unit/test-bap.c
index 3a67e7016..221bbedfb 100644
--- a/unit/test-bap.c
+++ b/unit/test-bap.c
@@ -582,7 +582,7 @@ static void test_setup(const void *user_data)
db = gatt_db_new();
g_assert(db);
- data->client = bt_gatt_client_new(db, att, 64, 0);
+ data->client = bt_gatt_client_new(db, att, 64, 0, false);
g_assert(data->client);
bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 535baafc6..8780cc4f5 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -684,7 +684,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
g_assert(context->client_db);
context->client = bt_gatt_client_new(context->client_db,
- context->att, mtu, 0);
+ context->att, mtu, 0, false);
g_assert(context->client);
bt_gatt_client_set_debug(context->client, print_debug,
diff --git a/unit/test-gmap.c b/unit/test-gmap.c
index 8b37efd18..fbf1529a6 100644
--- a/unit/test-gmap.c
+++ b/unit/test-gmap.c
@@ -323,7 +323,7 @@ static void test_setup(const void *user_data)
db = gatt_db_new();
g_assert(db);
- data->client = bt_gatt_client_new(db, att, 64, 0);
+ data->client = bt_gatt_client_new(db, att, 64, 0, false);
g_assert(data->client);
bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
diff --git a/unit/test-mcp.c b/unit/test-mcp.c
index 7d922bb83..3c5cdaad3 100644
--- a/unit/test-mcp.c
+++ b/unit/test-mcp.c
@@ -509,7 +509,7 @@ static void test_setup(const void *user_data)
db = gatt_db_new();
g_assert(db);
- data->client = bt_gatt_client_new(db, att, 64, 0);
+ data->client = bt_gatt_client_new(db, att, 64, 0, false);
g_assert(data->client);
bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
diff --git a/unit/test-micp.c b/unit/test-micp.c
index ff17300d5..64a248a40 100644
--- a/unit/test-micp.c
+++ b/unit/test-micp.c
@@ -500,7 +500,8 @@ static void test_setup(const void *user_data)
db = gatt_db_new();
g_assert(db);
- data->client = bt_gatt_client_new(db, att, MICP_GATT_CLIENT_MTU, 0);
+ data->client = bt_gatt_client_new(db, att, MICP_GATT_CLIENT_MTU, 0,
+ false);
g_assert(data->client);
bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
diff --git a/unit/test-tmap.c b/unit/test-tmap.c
index e75d62119..44465abf5 100644
--- a/unit/test-tmap.c
+++ b/unit/test-tmap.c
@@ -288,7 +288,7 @@ static void test_setup(const void *user_data)
db = gatt_db_new();
g_assert(db);
- data->client = bt_gatt_client_new(db, att, 64, 0);
+ data->client = bt_gatt_client_new(db, att, 64, 0, false);
g_assert(data->client);
bt_gatt_client_set_debug(data->client, print_debug, "bt_gatt_client:",
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 3/6] device: Rename set_alias to btd_device_set_alias() Martin BTS
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth
Cc: hadess, luiz.dentz, vi, Martin BTS, Claude Opus 4.6 (1M context)
Some BLE devices do not respond to secondary service discovery
requests, causing the 30-second ATT timeout to fire and terminate the
connection. Add a 2-second timeout at the GATT client level that
cancels the pending ATT request and proceeds as if no secondary
services were found. This prevents the ATT timeout from killing the
connection while still giving well-behaved devices enough time to
respond.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
src/shared/gatt-client.c | 62 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index e1685809f..3e1c3e525 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -20,6 +20,7 @@
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-client.h"
+#include "src/shared/timeout.h"
#include <assert.h>
#include <limits.h>
@@ -33,6 +34,8 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
+#define SECONDARY_DISC_TIMEOUT 2000 /* 2 seconds in ms */
+
#define UUID_BYTES (BT_GATT_UUID_SIZE * sizeof(uint8_t))
#define GATT_SVC_UUID 0x1801
@@ -114,6 +117,7 @@ struct bt_gatt_client {
unsigned int next_request_id;
struct bt_gatt_request *discovery_req;
+ unsigned int sec_disc_timeout_id;
unsigned int mtu_req_id;
/* Pending retry operation for DB out of sync handling */
@@ -1231,6 +1235,42 @@ static bool discovery_parse_services(struct discovery_op *op, bool primary,
return true;
}
+struct sec_disc_timeout_data {
+ struct bt_gatt_client *client;
+ struct discovery_op *op;
+};
+
+static bool sec_disc_timeout_cb(void *user_data)
+{
+ struct sec_disc_timeout_data *data = user_data;
+ struct bt_gatt_client *client = data->client;
+ struct discovery_op *op = data->op;
+
+ DBG(client, "Secondary service discovery timed out, proceeding");
+
+ client->sec_disc_timeout_id = 0;
+
+ /* Cancel the pending ATT request before it hits the 30s ATT timeout */
+ if (client->discovery_req) {
+ bt_gatt_request_cancel(client->discovery_req);
+ bt_gatt_request_unref(client->discovery_req);
+ client->discovery_req = NULL;
+ }
+
+ /* Treat as success — no secondary services found */
+ discovery_op_complete(op, true, 0);
+
+ return false;
+}
+
+static void sec_disc_timeout_destroy(void *user_data)
+{
+ struct sec_disc_timeout_data *data = user_data;
+
+ discovery_op_unref(data->op);
+ free(data);
+}
+
static void discover_secondary_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -1242,6 +1282,11 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
discovery_req_clear(client);
+ if (client->sec_disc_timeout_id) {
+ timeout_remove(client->sec_disc_timeout_id);
+ client->sec_disc_timeout_id = 0;
+ }
+
if (!success) {
switch (att_ecode) {
case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
@@ -1354,8 +1399,18 @@ secondary:
discover_secondary_cb,
discovery_op_ref(op),
discovery_op_unref);
- if (client->discovery_req)
+ if (client->discovery_req) {
+ struct sec_disc_timeout_data *td;
+
+ td = new0(struct sec_disc_timeout_data, 1);
+ td->client = client;
+ td->op = discovery_op_ref(op);
+ client->sec_disc_timeout_id = timeout_add(
+ SECONDARY_DISC_TIMEOUT,
+ sec_disc_timeout_cb, td,
+ sec_disc_timeout_destroy);
return;
+ }
DBG(client, "Failed to start secondary service discovery");
@@ -2822,6 +2877,11 @@ bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
queue_remove_all(client->pending_requests, NULL, NULL, cancel_pending);
+ if (client->sec_disc_timeout_id) {
+ timeout_remove(client->sec_disc_timeout_id);
+ client->sec_disc_timeout_id = 0;
+ }
+
if (client->discovery_req) {
bt_gatt_request_cancel(client->discovery_req);
bt_gatt_request_unref(client->discovery_req);
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 3/6] device: Rename set_alias to btd_device_set_alias()
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 4/6] dbus-common: Add Gaming appearance class (0x2a) Martin BTS
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: hadess, luiz.dentz, vi, Martin BTS
Renamed set_alias is exposed, so that plugins and others may set
the device alias progammatically. This is usefule for devices whose
Bluetooth name is generic (e.g. a bare BD addess, or literally
"DeviceName") but whose identity is known to the plugin after
protocol-level interrogation.
The signature was changed. The first parameter,
GDBusPendingPropertySet id was dropped and
g_dbus_pending_property_success moved to dev_property_set_alias().
---
src/device.c | 15 +++++----------
src/device.h | 1 +
2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/src/device.c b/src/device.c
index fbe137db7..0a88b82a2 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1063,17 +1063,12 @@ static gboolean dev_property_get_alias(const GDBusPropertyTable *property,
return TRUE;
}
-static void set_alias(GDBusPendingPropertySet id, const char *alias,
- void *data)
+void btd_device_set_alias(struct btd_device *device, const char *alias)
{
- struct btd_device *device = data;
-
/* No change */
if ((device->alias == NULL && g_str_equal(alias, "")) ||
- g_strcmp0(device->alias, alias) == 0) {
- g_dbus_pending_property_success(id);
+ g_strcmp0(device->alias, alias) == 0)
return;
- }
g_free(device->alias);
device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias);
@@ -1082,8 +1077,6 @@ static void set_alias(GDBusPendingPropertySet id, const char *alias,
g_dbus_emit_property_changed(dbus_conn, device->path,
DEVICE_INTERFACE, "Alias");
-
- g_dbus_pending_property_success(id);
}
static void dev_property_set_alias(const GDBusPropertyTable *property,
@@ -1101,7 +1094,9 @@ static void dev_property_set_alias(const GDBusPropertyTable *property,
dbus_message_iter_get_basic(value, &alias);
- set_alias(id, alias, data);
+ btd_device_set_alias(data, alias);
+
+ g_dbus_pending_property_success(id);
}
static gboolean dev_property_exists_class(const GDBusPropertyTable *property,
diff --git a/src/device.h b/src/device.h
index fe988652d..8c56d416f 100644
--- a/src/device.h
+++ b/src/device.h
@@ -22,6 +22,7 @@ char *btd_device_get_storage_path(struct btd_device *device,
void btd_device_device_set_name(struct btd_device *device, const char *name);
+void btd_device_set_alias(struct btd_device *device, const char *alias);
void device_store_cached_name(struct btd_device *dev, const char *name);
void device_get_name(struct btd_device *device, char *name, size_t len);
bool device_name_known(struct btd_device *device);
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 4/6] dbus-common: Add Gaming appearance class (0x2a)
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
` (2 preceding siblings ...)
2026-03-17 20:26 ` [PATCH BlueZ v3 3/6] device: Rename set_alias to btd_device_set_alias() Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 5/6] plugins/gatt-uhid: Add generic GATT-to-UHID bridge Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 6/6] plugins/switch2: Add Nintendo Switch 2 Controller plugin Martin BTS
5 siblings, 0 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: hadess, luiz.dentz, vi, Martin BTS
Bluetooth 5.0+ defines appearance category 0x2a for gaming devices
(generic gaming, handheld game console, game controller, etc.).
Map it to "input-gaming" so the correct icon is exposed over D-Bus.
---
src/dbus-common.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 5e2c83d52..42539116a 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -144,6 +144,8 @@ const char *gap_appearance_to_icon(uint16_t appearance)
return "scanner";
}
break;
+ case 0x2a: /* Gaming — Assigned Numbers, section 2.6.2 */
+ return "input-gaming";
}
return NULL;
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 5/6] plugins/gatt-uhid: Add generic GATT-to-UHID bridge
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
` (3 preceding siblings ...)
2026-03-17 20:26 ` [PATCH BlueZ v3 4/6] dbus-common: Add Gaming appearance class (0x2a) Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 6/6] plugins/switch2: Add Nintendo Switch 2 Controller plugin Martin BTS
5 siblings, 0 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: hadess, luiz.dentz, vi, Martin BTS
Add a reusable bridge that creates a /dev/uhid device backed by BLE
GATT characteristics. It forwards GATT notifications as HID input
reports (UHID_INPUT2) and HID output reports (UHID_OUTPUT) back as
GATT write-without-response commands.
Report format (both directions):
byte 0: HID report ID (0x01)
byte 1-2: GATT handle, little-endian
byte 3+: payload
The bridge has no device-specific knowledge. It subscribes to all
notify-capable GATT characteristics passed by the caller and generates
a vendor-defined HID descriptor at runtime. A kernel HID driver matched
by vendor/product ID provides all protocol handling.
Input forwarding is gated on CCCD subscription completion: the bridge
suppresses UHID_INPUT2 writes until all GATT notification registrations
are confirmed, ensuring the kernel driver's output path is fully
operational before it receives any input events.
---
plugins/gatt-uhid.c | 350 ++++++++++++++++++++++++++++++++++++++++++++
plugins/gatt-uhid.h | 56 +++++++
2 files changed, 406 insertions(+)
create mode 100644 plugins/gatt-uhid.c
create mode 100644 plugins/gatt-uhid.h
diff --git a/plugins/gatt-uhid.c b/plugins/gatt-uhid.c
new file mode 100644
index 000000000..2f81812fe
--- /dev/null
+++ b/plugins/gatt-uhid.c
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Generic GATT-to-UHID bridge
+ * Bridges a BLE GATT service to the kernel HID subsystem via /dev/uhid.
+ *
+ * Report format (both directions):
+ * byte 0: HID report ID (0x01)
+ * byte 1-2: GATT handle, little-endian
+ * byte 3+: payload
+ *
+ * Input: bridge prepends [report_id][handle_lo][handle_hi] to the raw
+ * GATT notification payload.
+ * Output: bridge reads [report_id][handle_lo][handle_hi] from the HID
+ * output report and writes the remaining payload to that GATT
+ * handle via write-without-response.
+ *
+ * The HID report descriptor uses a vendor-defined usage page with a
+ * single input and output report, each sized for the 2-byte handle
+ * prefix plus the maximum payload.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <linux/uhid.h>
+
+#include <glib.h>
+
+#include "src/log.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/util.h"
+
+#include "plugins/gatt-uhid.h"
+
+#define GATT_UHID_REPORT_ID 0x01
+
+/* Handle prefix overhead added to every report */
+#define GATT_UHID_HANDLE_SIZE 2
+
+/*
+ * The struct representing a GATT_UHID-Bridge.
+ */
+struct gatt_uhid {
+ struct bt_gatt_client *client;
+
+ int fd; /* /dev/uhid file descriptor */
+ guint watch_id; /* GLib I/O watch for UHID_OUTPUT */
+
+ unsigned int *notify_ids; /* registered GATT notify IDs */
+ unsigned int notify_count;
+
+ unsigned int cccd_pending; /* CCCDs not yet confirmed */
+};
+
+
+/*
+ * A prototypical HID report descriptor.
+ *
+ * One input and one output report, each sized for the 2-byte handle
+ * prefix plus the maximum payload. The two Report Count fields
+ * (marked 0x00, 0x00) are patched at runtime.
+ */
+static const uint8_t hid_desc_template[] = {
+ 0x06, 0x00, 0xff, /* Usage Page; Vendor Defined; no hid-generic */
+ 0x09, 0x01, /* Usage; we are a vendor */
+ 0xa1, 0x01, /* Collection; <hid_descriptor> */
+
+ /* Input report */
+ 0x85, GATT_UHID_REPORT_ID,
+ 0x09, 0x01, /* Usage */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x26, 0xff, 0x00, /* Logical Maximum (255) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x96, 0x00, 0x00, /* Put max input size here! */
+ 0x81, 0x02, /* Input (Data, Variable, Absolute) */
+
+ /* Output report */
+ 0x85, GATT_UHID_REPORT_ID,
+ 0x09, 0x02, /* Usage */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x96, 0x00, 0x00, /* Put max output size here! */
+ 0x91, 0x02, /* Output (Data, Variable, Absolute) */
+
+ 0xc0, /* End Collection; </hid_descriptor> */
+};
+
+/* Offsets used to put device max sizes into hid_desc_template */
+#define HID_DESC_MAX_INPUT_OFFSET 19
+#define HID_DESC_MAX_OUTPUT_OFFSET 30
+
+static size_t build_hid_descriptor(uint8_t *buf, uint16_t input_size,
+ uint16_t output_size)
+{
+ uint16_t in_total = GATT_UHID_HANDLE_SIZE + input_size;
+ uint16_t out_total = GATT_UHID_HANDLE_SIZE + output_size;
+
+ memcpy(buf, hid_desc_template, sizeof(hid_desc_template));
+
+ /* little endian! */
+ buf[HID_DESC_MAX_INPUT_OFFSET] = in_total & 0xff;
+ buf[HID_DESC_MAX_INPUT_OFFSET + 1] = (in_total >> 8) & 0xff;
+
+ buf[HID_DESC_MAX_OUTPUT_OFFSET] = out_total & 0xff;
+ buf[HID_DESC_MAX_OUTPUT_OFFSET + 1] = (out_total >> 8) & 0xff;
+
+ return sizeof(hid_desc_template);
+}
+
+/* Create device using params from device specific plugin */
+static int uhid_create(const struct gatt_uhid_params *params)
+{
+ struct uhid_event ev = {};
+ uint8_t hid_desc[128];
+ size_t hid_desc_len;
+ int fd;
+
+ fd = open("/dev/uhid", O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ error("gatt-uhid: open /dev/uhid: %s", strerror(errno));
+ return -1;
+ }
+
+ hid_desc_len = build_hid_descriptor(hid_desc,
+ params->input_size,
+ params->output_size);
+
+ ev.type = UHID_CREATE2;
+ ev.u.create2.bus = BUS_BLUETOOTH;
+ ev.u.create2.vendor = params->vendor;
+ ev.u.create2.product = params->product;
+ ev.u.create2.version = params->version;
+ ev.u.create2.country = 0;
+ ev.u.create2.rd_size = hid_desc_len;
+ strncpy((char *) ev.u.create2.name, params->name, 127);
+ memcpy(ev.u.create2.rd_data, hid_desc, hid_desc_len);
+
+ if (write(fd, &ev, sizeof(ev)) < 0) {
+ error("gatt-uhid: UHID_CREATE2: %s", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ DBG("gatt-uhid: uhid device created (%s)", params->name);
+ return fd;
+}
+
+/*
+ * From HID to BLE device
+ *
+ * UHID_OUTPUT data from the kernel HID driver:
+ * byte 0-1: GATT handle, little-endian
+ * byte 2+: payload to write
+ */
+static gboolean uhid_output_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct gatt_uhid *bridge = user_data;
+ struct uhid_event ev;
+ uint16_t handle;
+ ssize_t n;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ DBG("gatt-uhid: output_cb error/hup/nval cond=0x%x",
+ (int) cond);
+ bridge->watch_id = 0;
+ return FALSE;
+ }
+
+ n = read(bridge->fd, &ev, sizeof(ev)); /* fetch the event */
+ if (n < 0 || (size_t) n < sizeof(ev)) {
+ DBG("gatt-uhid: output_cb read returned %zd", n);
+ return TRUE;
+ }
+
+ DBG("gatt-uhid: output_cb event type=%u size=%u",
+ ev.type, ev.u.output.size);
+
+ if (ev.type != UHID_OUTPUT) {
+ DBG("gatt-uhid: output_cb ignoring event type %u", ev.type);
+ return TRUE;
+ }
+
+ if (!bridge->client) {
+ DBG("gatt-uhid: output_cb no client");
+ return TRUE;
+ }
+
+ /* Need at least the 2-byte handle prefix */
+ if (ev.u.output.size < GATT_UHID_HANDLE_SIZE) {
+ DBG("gatt-uhid: output_cb too short: %u", ev.u.output.size);
+ return TRUE;
+ }
+
+ handle = ev.u.output.data[0] | ((uint16_t) ev.u.output.data[1] << 8);
+
+ if (!handle) {
+ DBG("gatt-uhid: output_cb handle is zero");
+ return TRUE;
+ }
+
+ bt_gatt_client_write_without_response(bridge->client,
+ handle, false,
+ ev.u.output.data + GATT_UHID_HANDLE_SIZE,
+ ev.u.output.size - GATT_UHID_HANDLE_SIZE);
+ return TRUE;
+}
+
+
+/*
+ * From BLE device to HID
+ *
+ * Input report format to kernel HID driver:
+ * byte 0: report ID (0x01)
+ * byte 1-2: GATT handle, little-endian
+ * byte 3+: raw notification payload
+ */
+static void notify_cb(uint16_t value_handle, const uint8_t *value,
+ uint16_t length, void *user_data)
+{
+ struct gatt_uhid *bridge = user_data;
+ struct uhid_event ev = {};
+
+ if (length == 0 || bridge->fd < 0)
+ return;
+
+ /* Don't forward until all CCCDs are confirmed, so we don't have
+ * to deal with **some** available handles. */
+ if (bridge->cccd_pending)
+ return;
+
+ ev.type = UHID_INPUT2;
+ ev.u.input2.size = 1 + GATT_UHID_HANDLE_SIZE + length;
+ ev.u.input2.data[0] = GATT_UHID_REPORT_ID;
+ ev.u.input2.data[1] = value_handle & 0xff;
+ ev.u.input2.data[2] = (value_handle >> 8) & 0xff;
+ memcpy(&ev.u.input2.data[3], value, length);
+
+ if (write(bridge->fd, &ev, sizeof(ev)) < 0)
+ error("gatt-uhid: uhid write: %s", strerror(errno));
+}
+
+/* We can react to every single subscription on_registered */
+static void notify_registered_cb(uint16_t att_ecode, void *user_data)
+{
+ struct gatt_uhid *bridge = user_data;
+
+ if (att_ecode) {
+ error("gatt-uhid: notify registration failed: 0x%04x",
+ att_ecode);
+ }
+
+ if (bridge->cccd_pending > 0)
+ bridge->cccd_pending--;
+
+ if (bridge->cccd_pending == 0)
+ DBG("gatt-uhid: all %u CCCDs confirmed, forwarding input",
+ bridge->notify_count);
+}
+
+/*
+ * Public API
+ */
+
+struct gatt_uhid *gatt_uhid_new(struct bt_gatt_client *client,
+ const struct gatt_uhid_params *params)
+{
+ struct gatt_uhid *bridge;
+ GIOChannel *io;
+ unsigned int c;
+
+ if (!client || !params || !params->notify_count)
+ return NULL;
+
+ /* Create bridge */
+ bridge = g_new0(struct gatt_uhid, 1);
+ bridge->client = client;
+ bridge->notify_count = params->notify_count;
+ bridge->notify_ids = g_new0(unsigned int, params->notify_count);
+
+ bridge->fd = uhid_create(params); /* Create hid device */
+ if (bridge->fd < 0) {
+ g_free(bridge->notify_ids);
+ g_free(bridge);
+ return NULL;
+ }
+
+ /* Watch for UHID_OUTPUT events (commands from kernel HID driver) */
+ io = g_io_channel_unix_new(bridge->fd);
+ g_io_channel_set_encoding(io, NULL, NULL);
+ g_io_channel_set_buffered(io, FALSE);
+ bridge->watch_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP,
+ uhid_output_cb, bridge);
+ g_io_channel_unref(io);
+
+ /* Subscribe to all GATT notification handles. */
+ bridge->cccd_pending = params->notify_count;
+ for (c = 0; c < params->notify_count; c++) {
+ bridge->notify_ids[c] = bt_gatt_client_register_notify(
+ client,
+ params->notify_handles[c],
+ notify_registered_cb,
+ notify_cb,
+ bridge, NULL);
+ if (!bridge->notify_ids[c])
+ error("gatt-uhid: failed to register notify "
+ "for handle 0x%04x", params->notify_handles[c]);
+ }
+
+ return bridge;
+}
+
+void gatt_uhid_free(struct gatt_uhid *bridge)
+{
+ struct uhid_event ev = {};
+ unsigned int c;
+
+ if (!bridge)
+ return;
+
+ for (c = 0; c < bridge->notify_count; c++) {
+ if (bridge->notify_ids[c] && bridge->client)
+ bt_gatt_client_unregister_notify(bridge->client,
+ bridge->notify_ids[c]);
+ }
+
+ if (bridge->watch_id)
+ g_source_remove(bridge->watch_id);
+
+ if (bridge->fd >= 0) {
+ ev.type = UHID_DESTROY;
+ if (write(bridge->fd, &ev, sizeof(ev)) < 0)
+ error("gatt-uhid: UHID_DESTROY: %s", strerror(errno));
+ close(bridge->fd);
+ }
+
+ g_free(bridge->notify_ids);
+ g_free(bridge);
+}
diff --git a/plugins/gatt-uhid.h b/plugins/gatt-uhid.h
new file mode 100644
index 000000000..6b5e65f3b
--- /dev/null
+++ b/plugins/gatt-uhid.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Generic GATT-to-UHID bridge
+ * Bridges a BLE GATT service to the kernel HID subsystem via /dev/uhid.
+ *
+ * GATT notifications are forwarded as HID input reports; ble->bluez->uhid
+ * HID output reports are forwarded back as GATT writes; hid->bluez->ble
+ *
+ * The bridge is device-agnostic — all protocol knowledge lives in the
+ * kernel HID driver that claims the uhid device by vendor/product ID.
+ *
+ * This lets the kernel driver identify which characteristic produced
+ * each input report, and target specific handles for output writes.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct gatt_uhid;
+struct bt_gatt_client;
+
+/*
+ * Device specific plugins provide a gatt_uhid_params to
+ * configure the bridge.
+ *
+ * All GATT handles are value handles (not CCCD handles).
+ */
+struct gatt_uhid_params {
+ const char *name; /* Shown device name */
+ uint16_t vendor; /* Vendor ID like USB VID. Use this to match */
+ uint16_t product; /* Product ID like USB PID. Use this to match */
+ uint16_t version;
+
+ uint16_t *notify_handles; /* array of notification value handles */
+ unsigned int notify_count; /* number of entries in notify_handles */
+
+ /* Max payload sizes (excluding report ID and 2-byte handle prefix).*/
+ uint16_t input_size; /* size of a notification from BLE */
+ uint16_t output_size; /* size of an output from HID */
+};
+
+/*
+ * Create a GATT-UHID bridge. Opens /dev/uhid, creates the device,
+ * and subscribes to the specified GATT notification handles.
+ * Returns NULL on failure.
+ */
+struct gatt_uhid *gatt_uhid_new(struct bt_gatt_client *client,
+ const struct gatt_uhid_params *params);
+
+/*
+ * Destroy the bridge — unsubscribes GATT notifications, sends
+ * UHID_DESTROY, and frees resources.
+ */
+void gatt_uhid_free(struct gatt_uhid *bridge);
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v3 6/6] plugins/switch2: Add Nintendo Switch 2 Controller plugin
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
` (4 preceding siblings ...)
2026-03-17 20:26 ` [PATCH BlueZ v3 5/6] plugins/gatt-uhid: Add generic GATT-to-UHID bridge Martin BTS
@ 2026-03-17 20:26 ` Martin BTS
5 siblings, 0 replies; 8+ messages in thread
From: Martin BTS @ 2026-03-17 20:26 UTC (permalink / raw)
To: linux-bluetooth; +Cc: hadess, luiz.dentz, vi, Martin BTS
Thin device-specific wrapper around the generic GATT-UHID bridge for
Nintendo Switch 2 controllers (Pro Controller 2, Joy-Con 2 L/R,
GameCube Controller).
The plugin handles:
- Profile registration with the Switch 2 GATT service UUID
- Dynamic GATT characteristic discovery (all notify handles)
- Controller type detection from product ID
- Vendor/product IDs and payload sizes for uhid device creation
- Low-latency connection parameters and BT_SECURITY_LOW
- Skip secondary service discovery (controller rejects it)
All protocol knowledge (init handshake, calibration, stick normalization,
button mapping, rumble) is delegated to a matched kernel HID driver.
The plugin itself contains no Nintendo protocol logic.
---
Makefile.plugins | 5 +
plugins/switch2.c | 255 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 260 insertions(+)
create mode 100644 plugins/switch2.c
diff --git a/Makefile.plugins b/Makefile.plugins
index c9efadb45..4c5d10a90 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -1,4 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
+builtin_sources += plugins/gatt-uhid.h plugins/gatt-uhid.c
+
+builtin_modules += switch2
+builtin_sources += plugins/switch2.c
+
builtin_modules += hostname
builtin_sources += plugins/hostname.c
diff --git a/plugins/switch2.c b/plugins/switch2.c
new file mode 100644
index 000000000..0e389cab1
--- /dev/null
+++ b/plugins/switch2.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Nintendo Switch 2 controller BLE plugin
+ *
+ * Thin device-specific wrapper around the generic GATT-UHID bridge.
+ * Provides the GATT service UUID, characteristic discovery, and
+ * vendor/product IDs for uhid device matching.
+ *
+ * This wires the BLE device(s) so that HID drivers can take over.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/uuid.h"
+
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/plugin.h"
+#include "src/log.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/gatt-db.h"
+
+#include "plugins/gatt-uhid.h"
+
+/*
+ * Hard facts about Nintendo and the Switch 2 controllers
+ */
+
+#define SWITCH2_SERVICE_UUID "ab7de9be-89fe-49ad-828f-118f09df7fd0"
+
+#define NS2_VID 0x057e /* Nintendo Vendor ID */
+#define NS2_PID_JOYCON_R 0x2066
+#define NS2_PID_JOYCON_L 0x2067
+#define NS2_PID_PROCON 0x2069
+#define NS2_PID_GCCON 0x2073
+
+#define NS2_INPUT_SIZE 63 /* Max observed on Procon2 in bytes */
+#define NS2_OUTPUT_SIZE 64 /* Max observed on Procon2; no off by one */
+
+#define NS2_MAX_NOTIFY 8 /* Max |notify characteristics in the service| */
+
+struct switch2_ctlr_info {
+ uint16_t pid;
+ const char *alias;
+};
+
+static const struct switch2_ctlr_info ctlr_table[] = {
+ { NS2_PID_PROCON, "Nintendo Switch 2 Pro Controller" },
+ { NS2_PID_JOYCON_L, "Nintendo Switch 2 Joy-Con (L)" },
+ { NS2_PID_JOYCON_R, "Nintendo Switch 2 Joy-Con (R)" },
+ { NS2_PID_GCCON, "Nintendo Switch 2 GameCube Controller" },
+};
+
+/* Struct representing a controller */
+struct switch2_device {
+ struct btd_device *device;
+ struct gatt_uhid *bridge;
+ const struct switch2_ctlr_info *info;
+};
+
+/*
+ * GATT characteristic discovery
+ */
+
+/* We iterate gatt_db_foreach_service->gatt_db_service_foreach_char->inspect.
+ * Collect progress in char_walk_state */
+struct char_walk_state {
+ uint16_t notify_handles[NS2_MAX_NOTIFY];
+ unsigned int notify_count;
+};
+
+static void inspect_char(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct char_walk_state *state = user_data;
+ uint16_t handle, value_handle;
+ uint8_t properties;
+
+ if (!gatt_db_attribute_get_char_data(attr, &handle, &value_handle,
+ &properties, NULL, NULL))
+ return;
+
+ /* Collect every characteristic that supports notification */
+ if ((properties & 0x10) &&
+ state->notify_count < NS2_MAX_NOTIFY) {
+ state->notify_handles[state->notify_count++] = value_handle;
+ }
+}
+
+static void find_chars_in_service(struct gatt_db_attribute *service,
+ void *user_data)
+{
+ gatt_db_service_foreach_char(service, inspect_char, user_data);
+}
+
+/*
+ * Plugin functions
+ */
+
+static int switch2_probe(struct btd_service *service)
+{
+ struct btd_device *device = btd_service_get_device(service);
+ uint16_t pid = btd_device_get_product(device);
+ struct switch2_device *dev;
+ unsigned int c;
+
+ DBG("switch2: probe %s", device_get_path(device));
+
+ dev = g_new0(struct switch2_device, 1);
+ dev->device = btd_device_ref(device);
+ dev->info = &ctlr_table[0]; /* default to Procon 2 */
+
+ for (c = 0; c < G_N_ELEMENTS(ctlr_table); c++) {
+ if (ctlr_table[c].pid == pid) {
+ dev->info = &ctlr_table[c];
+ break;
+ }
+ }
+
+ DBG("switch2: detected %s (pid=0x%04x)", dev->info->alias, pid);
+
+ btd_device_set_alias(device, dev->info->alias);
+ btd_device_set_skip_secondary(device, true);
+
+ btd_service_set_user_data(service, dev);
+
+ return 0;
+}
+
+static void switch2_remove(struct btd_service *service)
+{
+ struct switch2_device *dev = btd_service_get_user_data(service);
+
+ DBG("switch2: remove %s", device_get_path(dev->device));
+
+ btd_device_unref(dev->device);
+ g_free(dev);
+}
+
+static int switch2_accept(struct btd_service *service)
+{
+ struct switch2_device *dev = btd_service_get_user_data(service);
+ struct btd_device *device = btd_service_get_device(service);
+ struct bt_gatt_client *client;
+ struct gatt_db *db;
+ struct char_walk_state state;
+ bt_uuid_t service_uuid;
+ struct gatt_uhid_params params;
+
+ DBG("switch2: accept %s", device_get_path(device));
+
+ client = btd_device_get_gatt_client(device);
+ if (!client) {
+ error("switch2: no GATT client");
+ return -EINVAL;
+ }
+
+ /* NS2 controllers reject pairing; avoid pairing */
+ bt_gatt_client_set_security(client, BT_SECURITY_LOW);
+
+ /* Low-latency connection, otherwise unplayable */
+ btd_device_set_conn_param(device, 6, 6, 0, 200);
+
+ /* Discover GATT characteristics */
+ memset(&state, 0, sizeof(state));
+
+ db = btd_device_get_gatt_db(device);
+ bt_string_to_uuid(&service_uuid, SWITCH2_SERVICE_UUID);
+ gatt_db_foreach_service(db, &service_uuid,
+ find_chars_in_service, &state);
+
+ if (!state.notify_count) {
+ error("switch2: no notify characteristics found");
+ return -ENOENT;
+ }
+
+ /* Set up the GATT-UHID bridge */
+ memset(¶ms, 0, sizeof(params));
+ /* Static info */
+ params.version = 0x0001;
+ params.vendor = NS2_VID;
+ params.input_size = NS2_INPUT_SIZE;
+ params.output_size = NS2_OUTPUT_SIZE;
+ /* Our dev->info override in _probe() */
+ params.name = dev->info->alias;
+ params.product = dev->info->pid;
+ /* Discovered handles at runtime */
+ params.notify_handles = state.notify_handles;
+ params.notify_count = state.notify_count;
+
+ dev->bridge = gatt_uhid_new(client, ¶ms);
+ if (!dev->bridge) {
+ error("switch2: failed to create GATT-UHID bridge");
+ return -EIO;
+ }
+
+ btd_service_connecting_complete(service, 0);
+ return 0;
+}
+
+static int switch2_disconnect(struct btd_service *service)
+{
+ struct switch2_device *dev = btd_service_get_user_data(service);
+
+ DBG("switch2: disconnect %s", device_get_path(dev->device));
+
+ gatt_uhid_free(dev->bridge);
+ dev->bridge = NULL;
+
+ btd_service_disconnecting_complete(service, 0);
+ return 0;
+}
+
+/*
+ * Plug in the plugin
+ */
+
+static struct btd_profile switch2_profile = {
+ .name = "switch2",
+ .bearer = BTD_PROFILE_BEARER_LE,
+ .remote_uuid = SWITCH2_SERVICE_UUID,
+ .device_probe = switch2_probe,
+ .device_remove = switch2_remove,
+ .accept = switch2_accept,
+ .disconnect = switch2_disconnect,
+ .auto_connect = true,
+};
+
+static int switch2_init(void)
+{
+ return btd_profile_register(&switch2_profile);
+}
+
+static void switch2_exit(void)
+{
+ btd_profile_unregister(&switch2_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(switch2, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ switch2_init, switch2_exit)
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* RE: BLE-HID/Nintendo Switch 2 support
2026-03-17 20:26 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
@ 2026-03-17 21:31 ` bluez.test.bot
0 siblings, 0 replies; 8+ messages in thread
From: bluez.test.bot @ 2026-03-17 21:31 UTC (permalink / raw)
To: linux-bluetooth, martinbts
[-- Attachment #1: Type: text/plain, Size: 55171 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1068246
---Test result---
Test Summary:
CheckPatch PENDING 0.33 seconds
GitLint PENDING 0.37 seconds
BuildEll PASS 21.90 seconds
BluezMake FAIL 676.98 seconds
MakeCheck FAIL 25.25 seconds
MakeDistcheck PASS 267.28 seconds
CheckValgrind FAIL 222.15 seconds
CheckSmatch FAIL 364.29 seconds
bluezmakeextell FAIL 184.60 seconds
IncrementalBuild PENDING 0.42 seconds
ScanBuild FAIL 519.28 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:
tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12984:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12984 | int main(int argc, char *argv[])
| ^~~~
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
766 | int main(int argc, char *argv[])
| ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:989:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
989 | int main(int argc, char *argv[])
| ^~~~
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4151: all] Error 2
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make: *** [Makefile:10784: check] Error 2
##############################
Test: CheckValgrind - FAIL
Desc: Run Bluez Make Check with Valgrind
Output:
tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12984:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12984 | int main(int argc, char *argv[])
| ^~~~
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:10784: check] Error 2
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:846:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1339:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1370:23: warning: Variable length array is used.
src/shared/gatt-server.c:278:25: warning: Variable length array is used.
src/shared/gatt-server.c:618:25: warning: Variable length array is used.
src/shared/gatt-server.c:716:25: warning: Variable length array is used.
src/shared/bap.c:312:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:846:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1339:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1370:23: warning: Variable length array is used.
src/shared/gatt-server.c:278:25: warning: Variable length array is used.
src/shared/gatt-server.c:618:25: warning: Variable length array is used.
src/shared/gatt-server.c:716:25: warning: Variable length array is used.
src/shared/bap.c:312:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
tools/mesh-cfgtest.c:1453:17: warning: unknown escape sequence: '\%'
tools/sco-tester.c: note: in included file:
./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures
./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures
tools/bneptest.c:634:39: warning: unknown escape sequence: '\%'
tools/seq2bseq.c:57:26: warning: Variable length array is used.
tools/obex-client-tool.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
client/btpclient/gatt.c: note: in included file:
./src/shared/btp.h:309:42: warning: array of flexible structures
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
unit/avctp.c:505:34: warning: Variable length array is used.
unit/avctp.c:556:34: warning: Variable length array is used.
unit/test-avrcp.c:373:26: warning: Variable length array is used.
unit/test-avrcp.c:398:26: warning: Variable length array is used.
unit/test-avrcp.c:414:24: warning: Variable length array is used.
unit/avrcp-lib.c:1085:34: warning: Variable length array is used.
unit/avrcp-lib.c:1583:34: warning: Variable length array is used.
unit/avrcp-lib.c:1612:34: warning: Variable length array is used.
unit/avrcp-lib.c:1638:34: warning: Variable length array is used.
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
mesh/mesh-io-mgmt.c:525:67: warning: Variable length array is used.
client/display.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272:23: warning: Variable length array is used.
src/shared/gatt-helpers.c:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:846:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1339:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1370:23: warning: Variable length array is used.
src/shared/gatt-server.c:278:25: warning: Variable length array is used.
src/shared/gatt-server.c:618:25: warning: Variable length array is used.
src/shared/gatt-server.c:716:25: warning: Variable length array is used.
src/shared/bap.c:312:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
monitor/packet.c:1993:26: warning: Variable length array is used.
monitor/packet.c: note: in included file:
monitor/bt.h:3866:52: warning: array of flexible structures
monitor/bt.h:3854:40: warning: array of flexible structures
monitor/msft.c: note: in included file:
monitor/msft.h:88:44: warning: array of flexible structures
tools/rctest.c:631:33: warning: non-ANSI function declaration of function 'automated_send_recv'
tools/hex2hcd.c:136:26: warning: Variable length array is used.
tools/meshctl.c:324:33: warning: non-ANSI function declaration of function 'forget_mesh_devices'
tools/mesh-gatt/node.c:456:39: warning: non-ANSI function declaration of function 'node_get_local_node'
tools/mesh-gatt/net.c:1239:30: warning: non-ANSI function declaration of function 'get_next_seq'
tools/mesh-gatt/net.c:2193:29: warning: non-ANSI function declaration of function 'net_get_default_ttl'
tools/mesh-gatt/net.c:2207:26: warning: non-ANSI function declaration of function 'net_get_seq_num'
tools/mesh-gatt/prov.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
tools/mesh-gatt/onoff-model.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
ell/log.c:431:65: warning: non-ANSI function declaration of function 'register_debug_section'
ell/log.c:439:68: warning: non-ANSI function declaration of function 'free_debug_sections'
ell/random.c:60:42: warning: non-ANSI function declaration of function 'l_getrandom_is_supported'
ell/checksum.c:382:28: warning: non-ANSI function declaration of function 'init_supported'
ell/checksum.c:444:47: warning: non-ANSI function declaration of function 'l_checksum_cmac_aes_supported'
ell/cipher.c:660:28: warning: non-ANSI function declaration of function 'init_supported'
ell/cipher.c:519:24: warning: Variable length array is used.
ell/cert-crypto.c:36:33: warning: Variable length array is used.
ell/cert-crypto.c:142:36: warning: Variable length array is used.
ell/cert-crypto.c:198:36: warning: Variable length array is used.
ell/cert-crypto.c:251:31: warning: Variable length array is used.
ell/key.c:550:25: warning: Variable length array is used.
ell/dbus-service.c:548:49: warning: non-ANSI function declaration of function '_dbus_object_tree_new'
ell/dbus-filter.c:233:46: warning: Variable length array is used.
ell/tls.c:45:25: warning: Variable length array is used.
ell/tls.c:86:22: warning: Variable length array is used.
ell/tls.c:86:46: warning: Variable length array is used.
ell/tls.c:1819:26: warning: Variable length array is used.
ell/tls-suites.c:1079:25: warning: Variable length array is used.
ell/tls-suites.c:1081:34: warning: Variable length array is used.
ell/tls-suites.c:1084:41: warning: Variable length array is used.
ell/tls-suites.c:1133:41: warning: Variable length array is used.
emulator/btdev.c:470:29: warning: Variable length array is used.
emulator/bthost.c:703:28: warning: Variable length array is used.
emulator/bthost.c:704:32: warning: Variable length array is used.
emulator/bthost.c:945:28: warning: Variable length array is used.
emulator/bthost.c:979:28: warning: Variable length array is used.
emulator/bthost.c:980:32: warning: Variable length array is used.
attrib/gatttool.c:236:23: warning: Variable length array is used.
attrib/interactive.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
attrib/interactive.c:175:27: warning: non-ANSI function declaration of function 'disconnect_io'
attrib/interactive.c:300:23: warning: Variable length array is used.
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4151: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4151: all] Error 2
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:
src/shared/gatt-client.c:460:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:705:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1005:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1111:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1346:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1421:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1696:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1701:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1757:56: warning: Use of memory after it is freed
notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2210:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2218:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3404:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3426:2: warning: Use of memory after it is freed
request_unref(req);
^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
bap = bt_bap_ref_safe(bap);
^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340:20: warning: Use of memory after it is freed
return queue_find(stream->bap->streams, NULL, stream);
^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/gatt-client.c:460:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:705:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1005:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1111:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1346:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1421:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1696:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1701:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1757:56: warning: Use of memory after it is freed
notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2210:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2218:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3404:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3426:2: warning: Use of memory after it is freed
request_unref(req);
^~~~~~~~~~~~~~~~~~
13 warnings generated.
tools/hciattach.c:817:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 10)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:865:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 4)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:887:8: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 10)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:909:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 4)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:930:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 4)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:974:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
if ((n = read_hci_event(fd, resp, 6)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
bap = bt_bap_ref_safe(bap);
^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340:20: warning: Use of memory after it is freed
return queue_find(stream->bap->streams, NULL, stream);
^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/oui.c:50:2: warning: Value stored to 'hwdb' is never read
hwdb = udev_hwdb_unref(hwdb);
^ ~~~~~~~~~~~~~~~~~~~~~
src/oui.c:53:2: warning: Value stored to 'udev' is never read
udev = udev_unref(udev);
^ ~~~~~~~~~~~~~~~~
2 warnings generated.
tools/rfcomm.c:234:3: warning: Value stored to 'i' is never read
i = execvp(cmdargv[0], cmdargv);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:234:7: warning: Null pointer passed to 1st parameter expecting 'nonnull'
i = execvp(cmdargv[0], cmdargv);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:354:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:497:14: warning: Assigned value is garbage or undefined
req.channel = raddr.rc_channel;
^ ~~~~~~~~~~~~~~~~
tools/rfcomm.c:515:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
tools/ciptool.c:351:7: warning: 5th function call argument is an uninitialized value
sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
3 warnings generated.
tools/sdptool.c:941:26: warning: Result of 'malloc' is converted to a pointer of type 'uint32_t', which is incompatible with sizeof operand type 'int'
uint32_t *value_int = malloc(sizeof(int));
~~~~~~~~~~ ^~~~~~ ~~~~~~~~~~~
tools/sdptool.c:980:4: warning: 1st function call argument is an uninitialized value
free(allocArray[i]);
^~~~~~~~~~~~~~~~~~~
tools/sdptool.c:3777:2: warning: Potential leak of memory pointed to by 'si.name'
return add_service(0, &si);
^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/sdptool.c:4112:4: warning: Potential leak of memory pointed to by 'context.svc'
return -1;
^~~~~~~~~
4 warnings generated.
tools/avtest.c:243:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:253:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 4);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:262:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:276:5: warning: Value stored to 'len' is never read
len = write(sk, buf,
^ ~~~~~~~~~~~~~~
tools/avtest.c:283:5: warning: Value stored to 'len' is never read
len = write(sk, buf,
^ ~~~~~~~~~~~~~~
tools/avtest.c:290:5: warning: Value stored to 'len' is never read
len = write(sk, buf,
^ ~~~~~~~~~~~~~~
tools/avtest.c:297:5: warning: Value stored to 'len' is never read
len = write(sk, buf,
^ ~~~~~~~~~~~~~~
tools/avtest.c:309:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 4);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:313:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:322:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:326:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:335:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:342:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:364:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 4);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:368:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:377:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:381:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:394:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 4);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:398:5: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:405:4: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:415:4: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:580:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:588:3: warning: Value stored to 'len' is never read
len = write(sk, buf, invalid ? 2 : 3);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:602:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 4 + media_transport_size);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:615:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:625:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:637:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:652:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:664:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:673:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 3);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:680:3: warning: Value stored to 'len' is never read
len = write(sk, buf, 2);
^ ~~~~~~~~~~~~~~~~~
tools/avtest.c:716:2: warning: Value stored to 'len' is never read
len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 warnings generated.
tools/btproxy.c:836:15: warning: Null pointer passed to 1st parameter expecting 'nonnull'
tcp_port = atoi(optarg);
^~~~~~~~~~~~
tools/btproxy.c:839:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
^~~~~~~~~~~~~~
2 warnings generated.
tools/create-image.c:76:3: warning: Value stored to 'fd' is never read
fd = -1;
^ ~~
tools/create-image.c:84:3: warning: Value stored to 'fd' is never read
fd = -1;
^ ~~
tools/create-image.c:92:3: warning: Value stored to 'fd' is never read
fd = -1;
^ ~~
tools/create-image.c:105:2: warning: Value stored to 'fd' is never read
fd = -1;
^ ~~
4 warnings generated.
tools/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read
ptr = fgets(result, sizeof(result), fp);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/btgatt-client.c:1822:2: warning: Value stored to 'argv' is never read
argv += optind;
^ ~~~~~~
1 warning generated.
tools/btgatt-server.c:1208:2: warning: Value stored to 'argv' is never read
argv -= optind;
^ ~~~~~~
1 warning generated.
tools/gatt-service.c:294:2: warning: 2nd function call argument is an uninitialized value
chr_write(chr, value, len);
^~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/obex-server-tool.c:133:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
data->fd = open(name, O_WRONLY | O_CREAT | O_NOCTTY, 0600);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/obex-server-tool.c:192:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
data->fd = open(name, O_RDONLY | O_NOCTTY, 0);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
client/btpclient/btpclientctl.c:402:3: warning: Value stored to 'bit' is never read
bit = 0;
^ ~
client/btpclient/btpclientctl.c:1655:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
memcpy(cp->data, ad_data, ad_len);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
(*ctxt)->cb = cb;
~~~~~~~~~~~~^~~~
1 warning generated.
src/sdpd-request.c:211:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
pElem = malloc(sizeof(uint16_t));
^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:239:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
pElem = malloc(sizeof(uint32_t));
^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/gatt-database.c:1175:10: warning: Value stored to 'bits' during its initialization is never read
uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
notify_client_unref(client);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
unit/avrcp-lib.c:1968:3: warning: 1st function call argument is an uninitialized value
g_free(text[i]);
^~~~~~~~~~~~~~~
1 warning generated.
unit/avdtp.c:756:25: warning: Use of memory after it is freed
session->prio_queue = g_slist_remove(session->prio_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unit/avdtp.c:763:24: warning: Use of memory after it is freed
session->req_queue = g_slist_remove(session->req_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
profiles/audio/avdtp.c:895:25: warning: Use of memory after it is freed
session->prio_queue = g_slist_remove(session->prio_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
profiles/audio/avdtp.c:902:24: warning: Use of memory after it is freed
session->req_queue = g_slist_remove(session->req_queue, req);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
profiles/audio/a2dp.c:442:8: warning: Use of memory after it is freed
if (!cb->resume_cb)
^~~~~~~~~~~~~
profiles/audio/a2dp.c:3354:20: warning: Access to field 'starting' results in a dereference of a null pointer (loaded from variable 'stream')
stream->starting = TRUE;
~~~~~~ ^
profiles/audio/a2dp.c:3357:8: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
if (!stream->suspending && stream->suspend_timer) {
^~~~~~~~~~~~~~~~~~
profiles/audio/a2dp.c:3417:22: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
stream->suspending = TRUE;
~~~~~~ ^
4 warnings generated.
profiles/audio/avrcp.c:1961:2: warning: Value stored to 'operands' is never read
operands += sizeof(*pdu);
^ ~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
return prepare_write(long_write);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdpd-request.c:211:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
pElem = malloc(sizeof(uint16_t));
^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:239:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
pElem = malloc(sizeof(uint32_t));
^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined
buf[1] = data[i + 1];
^ ~~~~~~~~~~~
3 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
(*ctxt)->cb = cb;
~~~~~~~~~~~~^~~~
1 warning generated.
src/gatt-database.c:1175:10: warning: Value stored to 'bits' during its initialization is never read
uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
notify_client_unref(client);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
memcpy(to, from, count);
^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
if (!g_slist_find(transfers, transfer))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
mesh/main.c:162:3: warning: Value stored to 'optarg' is never read
optarg += strlen("auto");
^ ~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/hci.c:97:4: warning: Value stored to 'ptr' is never read
ptr += sprintf(ptr, "%s", m->str);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
client/player.c:2363:8: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
if (!strcmp(ep->path, pattern))
^~~~~~~~~~~~~~~~~~~~~~~~~
client/player.c:3640:16: warning: Null pointer passed to 1st parameter expecting 'nonnull'
codec->name = strdup(name);
^~~~~~~~~~~~
2 warnings generated.
gdbus/watch.c:226:3: warning: Attempt to free released memory
g_free(l->data);
^~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/sdp.c:509:17: warning: Dereference of undefined pointer value
uint8_t dtd = *(uint8_t *) dtds[i];
^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:539:17: warning: Dereference of undefined pointer value
uint8_t dtd = *(uint8_t *) dtds[i];
^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1885:26: warning: Potential leak of memory pointed to by 'ap'
for (; pdlist; pdlist = pdlist->next) {
^~~~~~
lib/bluetooth/sdp.c:1899:6: warning: Potential leak of memory pointed to by 'pds'
ap = sdp_list_append(ap, pds);
~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1944:10: warning: Potential leak of memory pointed to by 'u'
*seqp = sdp_list_append(*seqp, u);
~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:2049:4: warning: Potential leak of memory pointed to by 'lang'
sdp_list_free(*langSeq, free);
^~~~~~~~~~~~~
lib/bluetooth/sdp.c:2138:9: warning: Potential leak of memory pointed to by 'profDesc'
return 0;
^
lib/bluetooth/sdp.c:3270:8: warning: Potential leak of memory pointed to by 'pSvcRec'
pSeq = sdp_list_append(pSeq, pSvcRec);
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:3271:9: warning: Potential leak of memory pointed to by 'pSeq'
pdata += sizeof(uint32_t);
~~~~~~^~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:4607:13: warning: Potential leak of memory pointed to by 'rec_list'
} while (scanned < attr_list_len && pdata_len > 0);
^~~~~~~
lib/bluetooth/sdp.c:4903:40: warning: Potential leak of memory pointed to by 'tseq'
for (d = sdpdata->val.dataseq; d; d = d->next) {
^
lib/bluetooth/sdp.c:4939:8: warning: Potential leak of memory pointed to by 'subseq'
tseq = sdp_list_append(tseq, subseq);
~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/gatt-client.c:460:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:705:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1005:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1111:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1346:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1421:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1696:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1701:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1757:56: warning: Use of memory after it is freed
notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2210:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2218:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3404:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3426:2: warning: Use of memory after it is freed
request_unref(req);
^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
bap = bt_bap_ref_safe(bap);
^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340:20: warning: Use of memory after it is freed
return queue_find(stream->bap->streams, NULL, stream);
^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
monitor/l2cap.c:1676:4: warning: Value stored to 'data' is never read
data += len;
^ ~~~
monitor/l2cap.c:1677:4: warning: Value stored to 'size' is never read
size -= len;
^ ~~~
2 warnings generated.
monitor/hwdb.c:59:2: warning: Value stored to 'hwdb' is never read
hwdb = udev_hwdb_unref(hwdb);
^ ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:64:2: warning: Value stored to 'udev' is never read
udev = udev_unref(udev);
^ ~~~~~~~~~~~~~~~~
monitor/hwdb.c:106:2: warning: Value stored to 'hwdb' is never read
hwdb = udev_hwdb_unref(hwdb);
^ ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:111:2: warning: Value stored to 'udev' is never read
udev = udev_unref(udev);
^ ~~~~~~~~~~~~~~~~
4 warnings generated.
tools/bluemoon.c:1102:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
^~~~~~~~~~~~~~
1 warning generated.
tools/meshctl.c:326:19: warning: Access to field 'mesh_devices' results in a dereference of a null pointer (loaded from variable 'default_ctrl')
g_list_free_full(default_ctrl->mesh_devices, g_free);
^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:762:2: warning: 2nd function call argument is an uninitialized value
bt_shell_printf("Attempting to disconnect from %s\n", addr);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:1957:2: warning: Value stored to 'len' is never read
len = len + extra + strlen("local_node.json");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:244:9: warning: 1st function call argument is an uninitialized value
return be32_to_cpu(get_unaligned((const uint32_t *) ptr));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:33:26: note: expanded from macro 'be32_to_cpu'
#define be32_to_cpu(val) bswap_32(val)
^~~~~~~~~~~~~
/usr/include/byteswap.h:34:21: note: expanded from macro 'bswap_32'
#define bswap_32(x) __bswap_32 (x)
^~~~~~~~~~~~~~
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:254:9: warning: 1st function call argument is an uninitialized value
return be64_to_cpu(get_unaligned((const uint64_t *) ptr));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:34:26: note: expanded from macro 'be64_to_cpu'
#define be64_to_cpu(val) bswap_64(val)
^~~~~~~~~~~~~
/usr/include/byteswap.h:37:21: note: expanded from macro 'bswap_64'
#define bswap_64(x) __bswap_64 (x)
^~~~~~~~~~~~~~
2 warnings generated.
ell/util.c:853:8: warning: The left operand of '>' is a garbage value
if (x > UINT8_MAX)
~ ^
ell/util.c:871:8: warning: The left operand of '>' is a garbage value
if (x > UINT16_MAX)
~ ^
2 warnings generated.
ell/pem.c:131:8: warning: Dereference of null pointer (loaded from variable 'eol')
if (*eol == '\r' || *eol == '\n')
^~~~
ell/pem.c:166:18: warning: Dereference of null pointer (loaded from variable 'eol')
if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
^~~~
ell/pem.c:166:34: warning: Dereference of null pointer (loaded from variable 'buf_ptr')
if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
^~~~~~~~
ell/pem.c:304:11: warning: 1st function call argument is an uninitialized value
result = pem_load_buffer(file.data, file.st.st_size,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/pem.c:469:9: warning: 1st function call argument is an uninitialized value
list = l_pem_load_certificate_list_from_data(file.data,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
ell/cert.c:645:41: warning: Access to field 'asn1_len' results in a dereference of a null pointer (loaded from variable 'cert')
key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len);
^~~~~~~~~~~~~~
1 warning generated.
ell/gvariant-util.c:143:18: warning: The left operand of '>' is a garbage value
if (alignment > max_alignment)
~~~~~~~~~ ^
ell/gvariant-util.c:456:5: warning: Dereference of null pointer
!children[0].fixed_size) {
^~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
emulator/serial.c:150:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:150:36: warning: Value stored to 'type' during its initialization is never read
enum btdev_type uninitialized_var(type);
^~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
emulator/serial.c:213:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(dev_type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:213:36: warning: Value stored to 'dev_type' during its initialization is never read
enum btdev_type uninitialized_var(dev_type);
^~~~~~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
4 warnings generated.
ell/ecc-external.c:77:11: warning: Assigned value is garbage or undefined
dest[i] = src[i];
^ ~~~~~~
ell/ecc-external.c:160:18: warning: The right operand of '-' is a garbage value
diff = left[i] - right[i] - borrow;
^ ~~~~~~~~
ell/ecc-external.c:227:14: warning: 2nd function call argument is an uninitialized value
product = mul_64_64(left[i], right[k - i]);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/ecc-external.c:408:9: warning: Assigned value is garbage or undefined
tmp[1] = product[3];
^ ~~~~~~~~~~
ell/ecc-external.c:435:22: warning: The left operand of '&' is a garbage value
tmp[1] = product[3] & 0xffffffff00000000ull;
~~~~~~~~~~ ^
ell/ecc-external.c:483:22: warning: The left operand of '&' is a garbage value
tmp[1] = product[5] & 0xffffffff00000000ull;
~~~~~~~~~~ ^
ell/ecc-external.c:688:28: warning: The left operand of '>>' is a garbage value
tmp[i] = (product[8 + i] >> 9) | (product[9 + i] << 55);
~~~~~~~~~~~~~~ ^
7 warnings generated.
emulator/server.c:209:2: warning: Assigned value is garbage or undefined
enum btdev_type uninitialized_var(type);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/server.c:209:36: warning: Value stored to 'type' during its initialization is never read
enum btdev_type uninitialized_var(type);
^~~~
emulator/server.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
^ ~
2 warnings generated.
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'server_port'
int opt;
^~~~~~~
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'sniffer_port'
int opt;
^~~~~~~
emulator/b1ee.c:289:2: warning: Value stored to 'argc' is never read
argc = argc - optind;
^ ~~~~~~~~~~~~~
3 warnings generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
memcpy(to, from, count);
^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
if (!g_slist_find(transfers, transfer))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
return prepare_write(long_write);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
In file included from plugins/gatt-uhid.c:42:
./src/shared/gatt-client.h:19:50: error: ‘struct gatt_db’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
19 | struct bt_gatt_client *bt_gatt_client_new(struct gatt_db *db,
| ^~~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8474: plugins/bluetoothd-gatt-uhid.o] Error 1
make[1]: *** Waiting for unfinished jobs....
emulator/btdev.c:6620:20: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
le_past_received(acl->link, pa);
^~~~~~~~~
emulator/btdev.c:6720:25: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
le_past_info_received(acl->link, ea);
^~~~~~~~~
2 warnings generated.
make: *** [Makefile:4151: all] Error 2
https://github.com/bluez/bluez/pull/1968/checks
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-03-17 21:31 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
2026-03-17 21:31 ` BLE-HID/Nintendo Switch 2 support bluez.test.bot
2026-03-17 20:26 ` [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 3/6] device: Rename set_alias to btd_device_set_alias() Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 4/6] dbus-common: Add Gaming appearance class (0x2a) Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 5/6] plugins/gatt-uhid: Add generic GATT-to-UHID bridge Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 6/6] plugins/switch2: Add Nintendo Switch 2 Controller plugin Martin BTS
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox