From 6e1e26474164bcbc6b858b046799ec2744376a74 Mon Sep 17 00:00:00 2001 From: Jeff Shee Date: Sat, 12 Sep 2026 12:50:37 +0900 Subject: [PATCH] feat(hw): add IR emitter quirk for Lenovo ThinkPad P14s Gen 4 (Syntek 174f:11a8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The emitter on this module is off by firmware default, so without a quirk every verify is "no face detected in any captured frame". UVC XU unit 14, selector 6, [1, 3, 3, ...] — the same control as the 04f2-b6d0 and 30c9-0120 entries. The firmware rejects an all-zero off payload with ERANGE, so off_bytes carries the default [1, 3, 1, ...]. The control persists across fd close. Independently found by linux-enable-ir-emitter (byte 2 = 2, which behaves identically). Verified on Fedora 44: enroll, verify, PAM sudo and GDM unlock; negative control by restoring the default returns the frames to ambient level. Co-Authored-By: Claude Fable 5.1 Signed-off-by: Jeff Shee --- contrib/hw/174f-11a8.toml | 13 +++++++++++++ crates/visage-hw/src/quirks.rs | 3 +++ docs/hardware-compatibility.md | 1 + 3 files changed, 17 insertions(+) create mode 100644 contrib/hw/174f-11a8.toml diff --git a/contrib/hw/174f-11a8.toml b/contrib/hw/174f-11a8.toml new file mode 100644 index 0000000..a29d373 --- /dev/null +++ b/contrib/hw/174f-11a8.toml @@ -0,0 +1,13 @@ +[device] +vendor_id = 0x174F +product_id = 0x11A8 +name = "Lenovo ThinkPad P14s Gen 4 IR Camera (Syntek 174f:11a8)" + +[emitter] +# UVC XU unit 14, selector 6, len 9: cur/def=[1,3,1] (off), max=[1,3,3] (on). +# Same control as 04f2-b6d0 / 30c9-0120; also found by linux-enable-ir-emitter. +unit = 14 +selector = 6 +control_bytes = [1, 3, 3, 0, 0, 0, 0, 0, 0] +# Rejects an all-zero "off" payload (ERANGE); the real off/default is [1,3,1,...]. +off_bytes = [1, 3, 1, 0, 0, 0, 0, 0, 0] diff --git a/crates/visage-hw/src/quirks.rs b/crates/visage-hw/src/quirks.rs index e688844..4828a02 100644 --- a/crates/visage-hw/src/quirks.rs +++ b/crates/visage-hw/src/quirks.rs @@ -17,6 +17,8 @@ const QUIRK_174F_2454: &str = include_str!("../../../contrib/hw/174f-2454.toml") const QUIRK_30C9_00C2: &str = include_str!("../../../contrib/hw/30c9-00c2.toml"); /// Compile-time embedded quirk for the HP OmniBook X Flip IR camera (Luxvisions 30c9:0120). const QUIRK_30C9_0120: &str = include_str!("../../../contrib/hw/30c9-0120.toml"); +/// Compile-time embedded quirk for the Lenovo ThinkPad P14s Gen 4 IR camera (Syntek 174f:11a8). +const QUIRK_174F_11A8: &str = include_str!("../../../contrib/hw/174f-11a8.toml"); static QUIRK_DB: OnceLock> = OnceLock::new(); @@ -68,6 +70,7 @@ const QUIRK_SOURCES: &[(&str, &str)] = &[ ("174f-2454.toml", QUIRK_174F_2454), ("30c9-00c2.toml", QUIRK_30C9_00C2), ("30c9-0120.toml", QUIRK_30C9_0120), + ("174f-11a8.toml", QUIRK_174F_11A8), ]; fn quirk_db() -> &'static Vec { diff --git a/docs/hardware-compatibility.md b/docs/hardware-compatibility.md index 98d4df3..a7b8782 100644 --- a/docs/hardware-compatibility.md +++ b/docs/hardware-compatibility.md @@ -107,6 +107,7 @@ VID:PID to the correct control bytes for each known device. | Lenovo ThinkPad X1 Carbon Gen 9 20XW00FPUS | `174f:2454` | ✅ Verified on hardware | | Lenovo ThinkBook 14 MP2PQAZG | `30c9:00c2` | ✅ Verified on hardware | | HP OmniBook X Flip | `30c9:0120` | ✅ Verified on hardware | +| Lenovo ThinkPad P14s Gen 4 21HF | `174f:11a8` | ✅ Verified on hardware | **Known devices with NO quirk entry:**