* [PATCH BlueZ 1/1] input: add HID gamepad quirk system for broken SDP records
2026-07-22 8:52 [PATCH BlueZ 0/1] input: " Pakrohk
@ 2026-07-22 8:52 ` Pakrohk
0 siblings, 0 replies; 3+ messages in thread
From: Pakrohk @ 2026-07-22 8:52 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pakrohk
Add a modular quirk system for third-party gamepad controllers that
expose incomplete or malformed HID SDP records over Bluetooth.
When BlueZ fails to parse an SDP record (returns -ENOENT), the quirk
system checks for known gamepads and injects a fallback HID report
descriptor so the kernel HID driver can create an input device.
Currently supported:
- Sony DualShock 4 v2 (CUH-ZCT2x) / VID:054c PID:09cc
The quirk system uses multi-factor matching (VID/PID + device name +
SDP provider) to avoid false positives. It does NOT globally weaken
HID parsing - quirks only activate for specifically matched controllers.
---
profiles/input/quirk.c | 77 +++++++++++
profiles/input/quirk.h | 37 ++++++
profiles/input/quirks/tg170w.c | 232 +++++++++++++++++++++++++++++++++
3 files changed, 346 insertions(+)
create mode 100644 profiles/input/quirk.c
create mode 100644 profiles/input/quirk.h
create mode 100644 profiles/input/quirks/tg170w.c
diff --git a/profiles/input/quirk.c b/profiles/input/quirk.c
new file mode 100644
index 0000000..053f45b
--- /dev/null
+++ b/profiles/input/quirk.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * Dispatcher for gamepad HID quirks. When BlueZ fails to parse an SDP
+ * record for a known gamepad, this layer injects a fallback HID report
+ * descriptor so the kernel HID driver can create an input device.
+ *
+ * This does NOT weaken HID parsing globally — quirks only activate for
+ * specifically matched controllers.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hidp.h"
+
+#include "src/log.h"
+
+#include "quirk.h"
+
+/* Individual quirk declarations */
+extern struct gamepad_quirk tg170w_quirk;
+
+static struct gamepad_quirk *quirks[] = {
+ &tg170w_quirk,
+ NULL
+};
+
+bool gamepad_quirk_match(struct input_device *idev)
+{
+ int i;
+
+ /* Check built-in quirks first */
+ for (i = 0; quirks[i]; i++) {
+ if (quirks[i]->match(idev))
+ return true;
+ }
+
+ /* Then check external (file-based) quirks */
+ if (external_quirk_match(idev))
+ return true;
+
+ return false;
+}
+
+int gamepad_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req)
+{
+ int i;
+
+ /* Try built-in quirks first */
+ for (i = 0; quirks[i]; i++) {
+ if (!quirks[i]->match(idev))
+ continue;
+
+ DBG("Applying HID quirk: %s", quirks[i]->name);
+
+ return quirks[i]->apply(idev, req);
+ }
+
+ /* Try external quirks */
+ if (external_quirk_match(idev)) {
+ return external_quirk_apply(idev, req);
+ }
+
+ return -1;
+}
diff --git a/profiles/input/quirk.h b/profiles/input/quirk.h
new file mode 100644
index 0000000..08e0bce
--- /dev/null
+++ b/profiles/input/quirk.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * Minimal HID fallback for third-party gamepads with broken SDP records.
+ * Only activates for specifically matched devices.
+ */
+
+#ifndef __INPUT_QUIRK_H
+#define __INPUT_QUIRK_H
+
+#include <stdbool.h>
+
+struct input_device;
+struct hidp_connadd_req;
+
+struct gamepad_quirk {
+ const char *name;
+ bool (*match)(struct input_device *idev);
+ int (*apply)(struct input_device *idev,
+ struct hidp_connadd_req *req);
+};
+
+bool gamepad_quirk_match(struct input_device *idev);
+
+int gamepad_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req);
+
+/* External quirk support (quirk-profile.c) */
+bool external_quirk_match(struct input_device *idev);
+int external_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req);
+
+#endif
diff --git a/profiles/input/quirks/tg170w.c b/profiles/input/quirks/tg170w.c
new file mode 100644
index 0000000..d3f37a8
--- /dev/null
+++ b/profiles/input/quirks/tg170w.c
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * DualShock 4 (CUH-ZCT2x) / TG170W gamepad quirk.
+ *
+ * This controller identifies as a DualShock 4 compatible device and
+ * works perfectly via USB. Over Bluetooth it exposes an incomplete
+ * or malformed HID SDP record, causing BlueZ to fail with -ENOENT.
+ *
+ * Windows and Android handle this gracefully; Linux/BlueZ does not.
+ * This quirk injects the correct BT HID report descriptor so the
+ * kernel's hid-playstation driver can create an input device.
+ *
+ * Matching criteria (multi-factor, no single-field matching):
+ * - Bluetooth device name + SDP provider
+ * - Vendor/Product ID from device info
+ *
+ * BT report descriptor constructed from kernel hid-playstation.c:
+ * DS4_INPUT_REPORT_BT = 0x11, size = 78 bytes
+ * DS4_OUTPUT_REPORT_BT = 0x11, size = 78 bytes
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hidp.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+
+#include "src/log.h"
+
+#include "../quirk.h"
+
+/*
+ * DualShock 4 Bluetooth HID Report Descriptor.
+ *
+ * The USB descriptor (report ID 0x01, 64 bytes) does NOT work over
+ * Bluetooth. The DS4 sends 78-byte packets with report ID 0x11 on BT.
+ * The kernel's hid-playstation driver expects exactly this format.
+ *
+ * This descriptor tells the HID core to accept report ID 0x11 packets
+ * and route them to the driver's parse_report callback. The driver
+ * creates input devices programmatically -- it doesn't need field-level
+ * mappings in the descriptor.
+ *
+ * Report layout (from hid-playstation.c):
+ * 0x11 Input: 78 bytes total (1 ID + 77 data)
+ * 0x11 Output: 78 bytes total (1 ID + 77 data, rumble/LED)
+ * 0x05 Feature: 41 bytes (gyro/accel calibration)
+ * 0x12 Feature: 16 bytes (pairing info / MAC address)
+ * 0xa3 Feature: 49 bytes (firmware info)
+ */
+static const uint8_t tg170w_hid_report_descriptor[] = {
+ /* Usage Page (Generic Desktop), Usage (Gamepad), Collection (Application) */
+ 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01,
+
+ /*
+ * Report ID 0x11 -- BT Enhanced Input Report
+ * 78 bytes total = 1 byte ID + 77 bytes payload
+ * Contains: sticks, buttons, gyro, accel, timestamp, touchpad, CRC
+ */
+ 0x85, 0x11, /* Report ID (0x11) */
+ 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined 0xFF00) */
+ 0x09, 0x20, /* Usage (0x20) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x26, 0xff, 0x00, /* Logical Maximum (255) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x4d, /* Report Count (77) */
+ 0x81, 0x02, /* Input (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x11 -- BT Output Report
+ * 78 bytes total = 1 byte ID + 77 bytes payload
+ * Used for: rumble motors, lightbar RGB, player LEDs
+ */
+ 0x85, 0x11, /* Report ID (0x11) */
+ 0x09, 0x21, /* Usage (0x21) */
+ 0x95, 0x4d, /* Report Count (77) */
+ 0x91, 0x02, /* Output (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x05 -- Calibration Feature Report (41 bytes)
+ * Gyroscope and accelerometer calibration data
+ */
+ 0x85, 0x05, /* Report ID (0x05) */
+ 0x09, 0x22, /* Usage (0x22) */
+ 0x95, 0x29, /* Report Count (41) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x12 -- Pairing Info Feature Report (16 bytes)
+ * Contains MAC address for device identification
+ */
+ 0x85, 0x12, /* Report ID (0x12) */
+ 0x09, 0x23, /* Usage (0x23) */
+ 0x95, 0x10, /* Report Count (16) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /*
+ * Report ID 0xa3 -- Firmware Info Feature Report (49 bytes)
+ * Hardware/firmware version information
+ */
+ 0x85, 0xa3, /* Report ID (0xa3) */
+ 0x09, 0x24, /* Usage (0x24) */
+ 0x95, 0x31, /* Report Count (49) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /* End Collection */
+ 0xc0
+};
+
+/* Sony DualShock 4 v2 (CUH-ZCT2x) */
+#define TG170W_VID 0x054c /* Sony */
+#define TG170W_PID 0x09cc /* DualShock 4 v2 */
+
+/* Opaque structs - we don't pull in heavy headers */
+struct input_device;
+struct btd_device;
+struct btd_service;
+
+/* Declarations from src/device.h and src/service.h */
+extern struct btd_service *input_device_get_service(
+ struct input_device *idev);
+extern struct btd_device *btd_service_get_device(
+ const struct btd_service *service);
+extern uint16_t btd_device_get_vendor(struct btd_device *device);
+extern uint16_t btd_device_get_product(struct btd_device *device);
+extern const sdp_record_t *btd_device_get_record(
+ struct btd_device *device,
+ const char *uuid);
+extern bool device_name_known(struct btd_device *device);
+extern void device_get_name(struct btd_device *device,
+ char *name, size_t len);
+
+static bool tg170w_match(struct input_device *idev)
+{
+ struct btd_service *service;
+ struct btd_device *device;
+ char name[248];
+ uint16_t vendor, product;
+ const sdp_record_t *rec;
+ sdp_data_t *pdlist;
+
+ if (!idev)
+ return false;
+
+ service = input_device_get_service(idev);
+ if (!service)
+ return false;
+
+ device = btd_service_get_device(service);
+ if (!device)
+ return false;
+
+ /* Check vendor/product ID from device info */
+ vendor = btd_device_get_vendor(device);
+ product = btd_device_get_product(device);
+
+ /* Match by VID/PID (Sony DS4 v2) */
+ if (vendor == TG170W_VID && product == TG170W_PID) {
+ DBG("TG170W quirk: matched by VID/PID %04x:%04x",
+ vendor, product);
+ return true;
+ }
+
+ /* Match by name + SDP provider */
+ if (!device_name_known(device))
+ return false;
+
+ device_get_name(device, name, sizeof(name));
+
+ if (strcmp(name, "Wireless Controller"))
+ return false;
+
+ /* Additional check: look for Sony in SDP provider */
+ rec = btd_device_get_record(device,
+ "00001124-0000-1000-8000-00805f9b34fb");
+ if (!rec)
+ return false;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY);
+ if (!pdlist || !pdlist->val.str)
+ return false;
+
+ if (!strstr(pdlist->val.str, "Sony"))
+ return false;
+
+ DBG("TG170W quirk: matched by name + provider");
+ return true;
+}
+
+static int tg170w_apply(struct input_device *idev,
+ struct hidp_connadd_req *req)
+{
+ /*
+ * HID parser version 1.11 per Bluetooth HID spec.
+ * The playstation kernel driver doesn't inspect this value,
+ * but it should be valid for proper HID core behavior.
+ */
+ req->parser = 0x0111;
+ req->country = 0;
+ req->subclass = 0;
+
+ /* Inject the Bluetooth HID report descriptor */
+ req->rd_size = sizeof(tg170w_hid_report_descriptor);
+ req->rd_data = malloc(req->rd_size);
+ if (!req->rd_data)
+ return -ENOMEM;
+
+ memcpy(req->rd_data, tg170w_hid_report_descriptor, req->rd_size);
+
+ DBG("TG170W: injected %u byte BT HID descriptor", req->rd_size);
+
+ return 0;
+}
+
+struct gamepad_quirk tg170w_quirk = {
+ .name = "TG170W",
+ .match = tg170w_match,
+ .apply = tg170w_apply,
+};
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH BlueZ 0/1] input: HID gamepad quirk system for broken SDP records
@ 2026-07-22 9:03 Pakrohk
2026-07-22 9:03 ` [PATCH BlueZ 1/1] input: add " Pakrohk
0 siblings, 1 reply; 3+ messages in thread
From: Pakrohk @ 2026-07-22 9:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pakrohk
Some Bluetooth gamepads (like DualShock 4 v2) have incomplete or malformed
HID SDP records, causing BlueZ to fail with -ENOENT. Windows and Android
handle this gracefully; Linux does not.
This patch adds a minimal quirk system that only activates for specifically
matched devices. When extract_hid_record() fails, the dispatcher tries
built-in quirks before giving up. The quirk injects the correct BT HID
report descriptor so the kernel's hid-playstation driver can create an
input device.
The patch includes one quirk (TG170W / DualShock 4 v2) as an example.
The system is modular -- new quirks can be added as separate files in
quirks/.
I previously included an external quirk profile system (JSON + HMAC
signatures) and a crypto extension to bt_crypto. Based on your feedback,
I've stripped those out. The core quirk system works without them.
Questions:
1. Is this approach acceptable for upstream?
2. For external quirk profiles (user-installable via JSON), what crypto
approach does BlueZ prefer? The existing bt_crypto uses AF_ALG which
is being deprecated. Should I wait for an upstream decision, use a
different library, or skip signatures entirely?
Pakrohk (1):
input: add HID gamepad quirk system for broken SDP records
profiles/input/quirk.c | 77 +++++++++++
profiles/input/quirk.h | 37 ++++++
profiles/input/quirks/tg170w.c | 232 +++++++++++++++++++++++++++++++++
3 files changed, 346 insertions(+)
create mode 100644 profiles/input/quirk.c
create mode 100644 profiles/input/quirk.h
create mode 100644 profiles/input/quirks/tg170w.c
--
2.54.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH BlueZ 1/1] input: add HID gamepad quirk system for broken SDP records
2026-07-22 9:03 [PATCH BlueZ 0/1] input: HID gamepad quirk system for broken SDP records Pakrohk
@ 2026-07-22 9:03 ` Pakrohk
0 siblings, 0 replies; 3+ messages in thread
From: Pakrohk @ 2026-07-22 9:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pakrohk
Add a modular quirk system for third-party gamepad controllers that
expose incomplete or malformed HID SDP records over Bluetooth.
When BlueZ fails to parse an SDP record (returns -ENOENT), the quirk
system checks for known gamepads and injects a fallback HID report
descriptor so the kernel HID driver can create an input device.
Currently supported:
- Sony DualShock 4 v2 (CUH-ZCT2x) / VID:054c PID:09cc
The quirk system uses multi-factor matching (VID/PID + device name +
SDP provider) to avoid false positives. It does NOT globally weaken
HID parsing - quirks only activate for specifically matched controllers.
---
profiles/input/quirk.c | 77 +++++++++++
profiles/input/quirk.h | 37 ++++++
profiles/input/quirks/tg170w.c | 232 +++++++++++++++++++++++++++++++++
3 files changed, 346 insertions(+)
create mode 100644 profiles/input/quirk.c
create mode 100644 profiles/input/quirk.h
create mode 100644 profiles/input/quirks/tg170w.c
diff --git a/profiles/input/quirk.c b/profiles/input/quirk.c
new file mode 100644
index 0000000..053f45b
--- /dev/null
+++ b/profiles/input/quirk.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * Dispatcher for gamepad HID quirks. When BlueZ fails to parse an SDP
+ * record for a known gamepad, this layer injects a fallback HID report
+ * descriptor so the kernel HID driver can create an input device.
+ *
+ * This does NOT weaken HID parsing globally — quirks only activate for
+ * specifically matched controllers.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hidp.h"
+
+#include "src/log.h"
+
+#include "quirk.h"
+
+/* Individual quirk declarations */
+extern struct gamepad_quirk tg170w_quirk;
+
+static struct gamepad_quirk *quirks[] = {
+ &tg170w_quirk,
+ NULL
+};
+
+bool gamepad_quirk_match(struct input_device *idev)
+{
+ int i;
+
+ /* Check built-in quirks first */
+ for (i = 0; quirks[i]; i++) {
+ if (quirks[i]->match(idev))
+ return true;
+ }
+
+ /* Then check external (file-based) quirks */
+ if (external_quirk_match(idev))
+ return true;
+
+ return false;
+}
+
+int gamepad_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req)
+{
+ int i;
+
+ /* Try built-in quirks first */
+ for (i = 0; quirks[i]; i++) {
+ if (!quirks[i]->match(idev))
+ continue;
+
+ DBG("Applying HID quirk: %s", quirks[i]->name);
+
+ return quirks[i]->apply(idev, req);
+ }
+
+ /* Try external quirks */
+ if (external_quirk_match(idev)) {
+ return external_quirk_apply(idev, req);
+ }
+
+ return -1;
+}
diff --git a/profiles/input/quirk.h b/profiles/input/quirk.h
new file mode 100644
index 0000000..08e0bce
--- /dev/null
+++ b/profiles/input/quirk.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * Minimal HID fallback for third-party gamepads with broken SDP records.
+ * Only activates for specifically matched devices.
+ */
+
+#ifndef __INPUT_QUIRK_H
+#define __INPUT_QUIRK_H
+
+#include <stdbool.h>
+
+struct input_device;
+struct hidp_connadd_req;
+
+struct gamepad_quirk {
+ const char *name;
+ bool (*match)(struct input_device *idev);
+ int (*apply)(struct input_device *idev,
+ struct hidp_connadd_req *req);
+};
+
+bool gamepad_quirk_match(struct input_device *idev);
+
+int gamepad_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req);
+
+/* External quirk support (quirk-profile.c) */
+bool external_quirk_match(struct input_device *idev);
+int external_quirk_apply(struct input_device *idev,
+ struct hidp_connadd_req *req);
+
+#endif
diff --git a/profiles/input/quirks/tg170w.c b/profiles/input/quirks/tg170w.c
new file mode 100644
index 0000000..d3f37a8
--- /dev/null
+++ b/profiles/input/quirks/tg170w.c
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2026 Gamepad Quirk Support
+ *
+ * DualShock 4 (CUH-ZCT2x) / TG170W gamepad quirk.
+ *
+ * This controller identifies as a DualShock 4 compatible device and
+ * works perfectly via USB. Over Bluetooth it exposes an incomplete
+ * or malformed HID SDP record, causing BlueZ to fail with -ENOENT.
+ *
+ * Windows and Android handle this gracefully; Linux/BlueZ does not.
+ * This quirk injects the correct BT HID report descriptor so the
+ * kernel's hid-playstation driver can create an input device.
+ *
+ * Matching criteria (multi-factor, no single-field matching):
+ * - Bluetooth device name + SDP provider
+ * - Vendor/Product ID from device info
+ *
+ * BT report descriptor constructed from kernel hid-playstation.c:
+ * DS4_INPUT_REPORT_BT = 0x11, size = 78 bytes
+ * DS4_OUTPUT_REPORT_BT = 0x11, size = 78 bytes
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hidp.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+
+#include "src/log.h"
+
+#include "../quirk.h"
+
+/*
+ * DualShock 4 Bluetooth HID Report Descriptor.
+ *
+ * The USB descriptor (report ID 0x01, 64 bytes) does NOT work over
+ * Bluetooth. The DS4 sends 78-byte packets with report ID 0x11 on BT.
+ * The kernel's hid-playstation driver expects exactly this format.
+ *
+ * This descriptor tells the HID core to accept report ID 0x11 packets
+ * and route them to the driver's parse_report callback. The driver
+ * creates input devices programmatically -- it doesn't need field-level
+ * mappings in the descriptor.
+ *
+ * Report layout (from hid-playstation.c):
+ * 0x11 Input: 78 bytes total (1 ID + 77 data)
+ * 0x11 Output: 78 bytes total (1 ID + 77 data, rumble/LED)
+ * 0x05 Feature: 41 bytes (gyro/accel calibration)
+ * 0x12 Feature: 16 bytes (pairing info / MAC address)
+ * 0xa3 Feature: 49 bytes (firmware info)
+ */
+static const uint8_t tg170w_hid_report_descriptor[] = {
+ /* Usage Page (Generic Desktop), Usage (Gamepad), Collection (Application) */
+ 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01,
+
+ /*
+ * Report ID 0x11 -- BT Enhanced Input Report
+ * 78 bytes total = 1 byte ID + 77 bytes payload
+ * Contains: sticks, buttons, gyro, accel, timestamp, touchpad, CRC
+ */
+ 0x85, 0x11, /* Report ID (0x11) */
+ 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined 0xFF00) */
+ 0x09, 0x20, /* Usage (0x20) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x26, 0xff, 0x00, /* Logical Maximum (255) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x95, 0x4d, /* Report Count (77) */
+ 0x81, 0x02, /* Input (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x11 -- BT Output Report
+ * 78 bytes total = 1 byte ID + 77 bytes payload
+ * Used for: rumble motors, lightbar RGB, player LEDs
+ */
+ 0x85, 0x11, /* Report ID (0x11) */
+ 0x09, 0x21, /* Usage (0x21) */
+ 0x95, 0x4d, /* Report Count (77) */
+ 0x91, 0x02, /* Output (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x05 -- Calibration Feature Report (41 bytes)
+ * Gyroscope and accelerometer calibration data
+ */
+ 0x85, 0x05, /* Report ID (0x05) */
+ 0x09, 0x22, /* Usage (0x22) */
+ 0x95, 0x29, /* Report Count (41) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /*
+ * Report ID 0x12 -- Pairing Info Feature Report (16 bytes)
+ * Contains MAC address for device identification
+ */
+ 0x85, 0x12, /* Report ID (0x12) */
+ 0x09, 0x23, /* Usage (0x23) */
+ 0x95, 0x10, /* Report Count (16) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /*
+ * Report ID 0xa3 -- Firmware Info Feature Report (49 bytes)
+ * Hardware/firmware version information
+ */
+ 0x85, 0xa3, /* Report ID (0xa3) */
+ 0x09, 0x24, /* Usage (0x24) */
+ 0x95, 0x31, /* Report Count (49) */
+ 0xb1, 0x02, /* Feature (Data, Var, Abs) */
+
+ /* End Collection */
+ 0xc0
+};
+
+/* Sony DualShock 4 v2 (CUH-ZCT2x) */
+#define TG170W_VID 0x054c /* Sony */
+#define TG170W_PID 0x09cc /* DualShock 4 v2 */
+
+/* Opaque structs - we don't pull in heavy headers */
+struct input_device;
+struct btd_device;
+struct btd_service;
+
+/* Declarations from src/device.h and src/service.h */
+extern struct btd_service *input_device_get_service(
+ struct input_device *idev);
+extern struct btd_device *btd_service_get_device(
+ const struct btd_service *service);
+extern uint16_t btd_device_get_vendor(struct btd_device *device);
+extern uint16_t btd_device_get_product(struct btd_device *device);
+extern const sdp_record_t *btd_device_get_record(
+ struct btd_device *device,
+ const char *uuid);
+extern bool device_name_known(struct btd_device *device);
+extern void device_get_name(struct btd_device *device,
+ char *name, size_t len);
+
+static bool tg170w_match(struct input_device *idev)
+{
+ struct btd_service *service;
+ struct btd_device *device;
+ char name[248];
+ uint16_t vendor, product;
+ const sdp_record_t *rec;
+ sdp_data_t *pdlist;
+
+ if (!idev)
+ return false;
+
+ service = input_device_get_service(idev);
+ if (!service)
+ return false;
+
+ device = btd_service_get_device(service);
+ if (!device)
+ return false;
+
+ /* Check vendor/product ID from device info */
+ vendor = btd_device_get_vendor(device);
+ product = btd_device_get_product(device);
+
+ /* Match by VID/PID (Sony DS4 v2) */
+ if (vendor == TG170W_VID && product == TG170W_PID) {
+ DBG("TG170W quirk: matched by VID/PID %04x:%04x",
+ vendor, product);
+ return true;
+ }
+
+ /* Match by name + SDP provider */
+ if (!device_name_known(device))
+ return false;
+
+ device_get_name(device, name, sizeof(name));
+
+ if (strcmp(name, "Wireless Controller"))
+ return false;
+
+ /* Additional check: look for Sony in SDP provider */
+ rec = btd_device_get_record(device,
+ "00001124-0000-1000-8000-00805f9b34fb");
+ if (!rec)
+ return false;
+
+ pdlist = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY);
+ if (!pdlist || !pdlist->val.str)
+ return false;
+
+ if (!strstr(pdlist->val.str, "Sony"))
+ return false;
+
+ DBG("TG170W quirk: matched by name + provider");
+ return true;
+}
+
+static int tg170w_apply(struct input_device *idev,
+ struct hidp_connadd_req *req)
+{
+ /*
+ * HID parser version 1.11 per Bluetooth HID spec.
+ * The playstation kernel driver doesn't inspect this value,
+ * but it should be valid for proper HID core behavior.
+ */
+ req->parser = 0x0111;
+ req->country = 0;
+ req->subclass = 0;
+
+ /* Inject the Bluetooth HID report descriptor */
+ req->rd_size = sizeof(tg170w_hid_report_descriptor);
+ req->rd_data = malloc(req->rd_size);
+ if (!req->rd_data)
+ return -ENOMEM;
+
+ memcpy(req->rd_data, tg170w_hid_report_descriptor, req->rd_size);
+
+ DBG("TG170W: injected %u byte BT HID descriptor", req->rd_size);
+
+ return 0;
+}
+
+struct gamepad_quirk tg170w_quirk = {
+ .name = "TG170W",
+ .match = tg170w_match,
+ .apply = tg170w_apply,
+};
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-22 9:04 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-22 9:03 [PATCH BlueZ 0/1] input: HID gamepad quirk system for broken SDP records Pakrohk
2026-07-22 9:03 ` [PATCH BlueZ 1/1] input: add " Pakrohk
-- strict thread matches above, loose matches on Subject: below --
2026-07-22 8:52 [PATCH BlueZ 0/1] input: " Pakrohk
2026-07-22 8:52 ` [PATCH BlueZ 1/1] input: add " Pakrohk
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.