From nobody Sun Jun 14 08:16:31 2026 Received: from mail-pj1-f54.google.com (mail-pj1-f54.google.com [209.85.216.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6120C38E113 for ; Sat, 13 Jun 2026 22:58:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781391524; cv=none; b=LA+/fmDoufMbMIQR0N59s8YhpIINYLn5ZassBAKz6SctgFAO3sho9g/ngZ9HdMkyiV8PhnUxI0VP8beWmV/nxmBp+dRg11QpDIKTfqyIKlN+c+mSjqiiffWR2iF5/76qgaOgWEP0qKowsUBwq+gj1NfUuebjhOXLHX309B/KAG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781391524; c=relaxed/simple; bh=/A741uDlGFD2WkGc46FuBg1F/gZV5dKz7KCPBbu/JpE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=Sgkg3g7o8m9GZmiCpry18QCUnX8Gj52Z8spxMoiCEntgZi2CT1cAhY07gDaUJv7cln/Xs88xln93Fy+lfHgMFCzxRA6KsozUxUMPHnTGzi7t72/MfXUf2MIvGxbHg1bXvjOAzFTH+raztNrbZlo6Y4pVGKoleMQJmzSLB0cPQtM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CbEiqYM5; arc=none smtp.client-ip=209.85.216.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CbEiqYM5" Received: by mail-pj1-f54.google.com with SMTP id 98e67ed59e1d1-36ba706ab46so1295483a91.1 for ; Sat, 13 Jun 2026 15:58:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781391519; x=1781996319; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=IjIDujvFdMaBCuNW6n4kM+LVX7mOvVximLwIuH8gZ8c=; b=CbEiqYM560wT7hzkPQ6lE4lKFlksPUtrDyuHVLMz9EBbS3Xtpe87RimXaj6xVM9tbg RTqOZ2pYwSqjUVI+x3VsrsLMS9g6qR3WLmms4CACaG2GetXrW5gFQ2bf0Me3UIlXrBOF 6LgmZgOzH9+nAKe6u2ijszJqFhvMK4GK8cBUyUBjsOdZfTT4T4WLxYFf20bxDZgEQoeY O1VZD/7ezuF/nVwG/IZ8BEdiEQsbIauA/R53h+A+R7eD5E3Kcl7lm0zDkh9F3oYkKk/a TwtKCJv4GYzNrZyTTRRPZH35/EaFZfGuzItFfI81ayC54ob5VLhnWe0QUs7DPZ4jMNpd k9pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781391519; x=1781996319; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=IjIDujvFdMaBCuNW6n4kM+LVX7mOvVximLwIuH8gZ8c=; b=mj/NZNKdw1icWP/11pWdt9f1VkA7i1EaQLDQ6ULdec7pLe9+dalx1O5Zy84tBfUU8Q kDd8VjKJrs85gZANC+8W9XlZu29uXc6o4WnLuy/zutWtQs4szOT8zr7BmkmZxqj38w4d J0JGqJYxjQQEVLhzTD2YiDZfFVJTmemuKWstOqgUOlF7pUsiMTlZulR6gVHQsHPa3/PD klpTY4FwozKB2+W3dz7U5/DDV/5OnlZ870dEGhJgfU0bm1PTLTGXL1yUmWTa01/aWLA3 MUrhpvFyEQDNM228wXNVK3uL7GfbeHVRLC1YG4/Lt3XQnBbRURk7DWqRJKN0AO4SsIIJ R+Ow== X-Gm-Message-State: AOJu0Yw76WCRi+8f9H5XoSVibm6zV9RFs9lo+QL8B4kkQKgDvwxRAiQo dY4r1xuiZpnKh0577hjnYLaVGeqZ1+N+ukF08zgxMK/M4XUgTeXi0RXV62EDc1q73I8= X-Gm-Gg: Acq92OENAyt2vCw2bhvQQcI/tmVZ6ETwR4radWw6U97Pb9XksVjqYH7Nhkicf8sDKo1 IkvWxtHOUpbAAOHeDLr2gaKQv+7gFEwIrqreQWi6UsrRaYAcKhNSFqsmNyt+VHXi9CVI8nMoV1Z I7Cow0DsFJHKVUWoWSIsygGqtDWqa9E+eLt+BAQeJqHGklvElL5p/tF9Hyc2ToDO9XtkXL0CX2j jVy9tKe61dhVjNz9A2OjvkSYxVoEZ7jmhCczYhdzXJGvAkOPamJB125eS+6O9yACDaUbdWif6/5 oq4Rm2RUVCiO4CCiM5WocukIS1QT5ccarls7ji8UI6lLkx8Z4iNE8QsigovdlXeWv4xM3Ptxtz3 zfQJ7mV+8t16SlnaB4cFYCG4L/GSU+c/Ljjf0Lph0NsTqDF9eoNlol0JkSWvCkKAtVBQcOJy1oR YqNmd2AXRIvZ72Vg0tUX22wIKkBJW/Kd5NVf8YwDfg2FfymILM X-Received: by 2002:a17:90b:56c4:b0:368:147f:bd2b with SMTP id 98e67ed59e1d1-37a03bd1880mr8650897a91.23.1781391518445; Sat, 13 Jun 2026 15:58:38 -0700 (PDT) Received: from c12-ThinkPad-X1-Carbon-Gen-12 ([2400:2410:5f2b:700:f4db:34e:97b1:ad63]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-37a212ab0dcsm6252292a91.15.2026.06.13.15.58.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 13 Jun 2026 15:58:37 -0700 (PDT) From: Vishnu Sankar To: mpearson-lenovo@squebb.ca, skhan@linuxfoundation.org, corbet@lwn.net, hmh@hmh.eng.br, hansg@kernel.org, derekjohn.clark@gmail.com, ilpo.jarvinen@linux.intel.com Cc: linux-kernel@vger.kernel.org, ibm-acpi-devel@lists.sourceforge.net, linux-doc@vger.kernel.org, platform-driver-x86@vger.kernel.org, vsankar@lenovo.com, Vishnu Sankar Subject: [PATCH v3] platform/x86: thinkpad_acpi: Add USB-C Security (USCS) support Date: Sun, 14 Jun 2026 07:57:36 +0900 Message-ID: <20260613225736.30906-1-vishnuocv@gmail.com> X-Mailer: git-send-email 2.51.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Newer ThinkPad systems expose a USB-C Security (Restricted Mode) feature. When active, USB-C data connections are disabled while power delivery is preserved. This is useful for kiosk and physically-secured deployments. Hardware interface: The HKEY device exposes a read-only ACPI method USCS(): Return value bit layout: Bit 16 : Capability flag (1 =3D feature present on this SKU) Bit 0 : Current state (0 =3D security OFF, 1 =3D security ON) The sysfs attribute is read-only. The Fn+U followed by Fn+S hotkey chord is the only way to toggle the hardware state. Hotkey: Fn+U followed by Fn+S generates HKEY event 0x131e. sysfs interface: /sys/devices/platform/thinkpad_acpi/usb_c_security (read-only) "enabled\n" -- data connections are currently blocked "disabled\n" -- data connections are currently allowed The attribute is hidden on SKUs where the USCS capability bit (bit 16) is not set, so there is no ABI impact on unsupported hardware. Suggested-by: Mark Pearson Signed-off-by: Vishnu Sankar --- Changes since v2: - Move usbc_security_enabled out of tp_features bitfield to a bool member of tp_features to avoid unsafe concurrent bitfield RMW; usbc_security_supported remains a bitfield as it is init-only. - Pass &tp_features.usbc_security_enabled directly to usbc_security_query() removing the local bool intermediary in both init and hotkey paths. - Remove extra blank line before */ in block comment. - Fix kerneldoc Returns: syntax and rewrite return value description to match the int return type. - Split ternary return into two separate if statements for clarity Changes since v1: - Use guard(mutex) from cleanup.h instead of manual mutex_lock/unlock - Revert usbc_security_query() to return int (-EIO/-ENODEV/0) instead of bool to avoid uninitialized *enabled bug on unsupported platforms - Remove !! when assigning to bool in usbc_security_query() - Remove dead tp_features.usbc_security_supported check in show() since is_visible() already gates the attribute on unsupported SKUs - Use str_enabled_disabled() from string_choices.h in show() - Fix uninitialized *enabled bug in tpacpi_usbc_security_init() by only assigning usbc_security_enabled after a successful query --- .../admin-guide/laptops/thinkpad-acpi.rst | 24 ++++ drivers/platform/x86/lenovo/thinkpad_acpi.c | 116 ++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Document= ation/admin-guide/laptops/thinkpad-acpi.rst index f874db31801d..db4588af0278 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -1543,6 +1543,30 @@ Values: =20 This setting can also be toggled via the Fn+doubletap hotkey. =20 +USB-C Security +-------------- + +sysfs: usb_c_security + +Reports the current state of the USB-C Security (Restricted Mode) feature +on supported ThinkPad systems. When enabled, USB-C data connections are +disabled while power delivery is preserved. + +The available command is:: + + cat /sys/devices/platform/thinkpad_acpi/usb_c_security + +Values: + + * ``enabled`` - USB-C data connections are currently blocked + * ``disabled`` - USB-C data connections are currently allowed + +The attribute is read-only. The USB-C Security state can only be toggled +via the Fn+U followed by Fn+S hotkey chord. + +The sysfs attribute is not created on platforms that do not support this +feature. + Auxmac ------ =20 diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform= /x86/lenovo/thinkpad_acpi.c index e1cee42a1683..59b485a57ffe 100644 --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -185,6 +187,7 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_AMT_TOGGLE =3D 0x131a, /* Toggle AMT on/off */ TP_HKEY_EV_CAMERASHUTTER_TOGGLE =3D 0x131b, /* Toggle Camera Shutter */ TP_HKEY_EV_DOUBLETAP_TOGGLE =3D 0x131c, /* Toggle trackpoint doubletap on= /off */ + TP_HKEY_EV_USB_C_SECURITY =3D 0x131e, /* USB C Security (Fn+U, Fn+S) */ TP_HKEY_EV_PROFILE_TOGGLE =3D 0x131f, /* Toggle platform profile in 2024 = systems */ TP_HKEY_EV_PROFILE_TOGGLE2 =3D 0x1401, /* Toggle platform profile in 2025= + systems */ =20 @@ -373,6 +376,8 @@ static struct { u32 has_adaptive_kbd:1; u32 kbd_lang:1; u32 trackpoint_doubletap_enable:1; + u32 usbc_security_supported:1; + bool usbc_security_enabled; struct quirk_entry *quirks; } tp_features; =20 @@ -11265,6 +11270,110 @@ static struct ibm_struct hwdd_driver_data =3D { .name =3D "hwdd", }; =20 +/************************************************************************* + * USB-C Security subdriver + * + * HKEY.USCS(0) is a read-only ACPI method; its argument is ignored. + * It always returns: + * bit 16 - USB-C security capability present on this SKU or not + * bit 0 - USB-C Security state (enable or disable) + * + * Hotkey + * ------ + * 0x131e (Fn+U, Fn+S): firmware toggles USBS before firing the event. + * The driver reads back the new state and notifies the sysfs attribute. + */ + +/* USCS() return word bit layout */ +#define USCS_CAP_BIT BIT(16) /* capability: feature present on SKU */ +#define USCS_STATUS_BIT BIT(0) /* current security state */ + +static DEFINE_MUTEX(usbc_security_mutex); + +/** + * usbc_security_query - read current USB-C security state via USCS() + * @enabled: out - true when security is ON (data connections blocked) + * + * Returns: + * 0 success, @enabled contains the current state + * -EIO ACPI evaluation failed + * -ENODEV capability bit absent; feature not present on this SKU* + */ +static int usbc_security_query(bool *enabled) +{ + int status; + + guard(mutex)(&usbc_security_mutex); + if (!acpi_evalf(hkey_handle, &status, "USCS", "dd", 0)) + return -EIO; + + if (!(status & USCS_CAP_BIT)) { + pr_debug("USCS cap bit absent (raw=3D0x%x)\n", status); + return -ENODEV; + } + + *enabled =3D status & USCS_STATUS_BIT; + return 0; +} + +/* sysfs: /sys/devices/platform/thinkpad_acpi/usb_c_security ---------- */ +static ssize_t usb_c_security_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", + str_enabled_disabled(tp_features.usbc_security_enabled)); +} + +static DEVICE_ATTR_RO(usb_c_security); + +static struct attribute *usbc_security_attributes[] =3D { + &dev_attr_usb_c_security.attr, + NULL, +}; + +static umode_t usbc_security_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return tp_features.usbc_security_supported ? attr->mode : 0; +} + +static const struct attribute_group usbc_security_attr_group =3D { + .is_visible =3D usbc_security_attr_is_visible, + .attrs =3D usbc_security_attributes, +}; + +static int tpacpi_usbc_security_init(struct ibm_init_struct *iibm) +{ + int err; + + err =3D usbc_security_query(&tp_features.usbc_security_enabled); + if (err =3D=3D -ENODEV) + return 0; + if (err) + return err; + + tp_features.usbc_security_supported =3D true; + return 0; +} + +/* tpacpi_usbc_security_hotkey - handle Fn+U Fn+S hotkey (0x131e) */ +static bool tpacpi_usbc_security_hotkey(void) +{ + if (!tp_features.usbc_security_supported) + return false; + + if (usbc_security_query(&tp_features.usbc_security_enabled)) + return false; + + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "usb_c_security"); + return true; +} + +static struct ibm_struct usbc_security_driver_data =3D { + .name =3D "usbc_security", +}; + /* --------------------------------------------------------------------- */ =20 static struct attribute *tpacpi_driver_attributes[] =3D { @@ -11325,6 +11434,7 @@ static const struct attribute_group *tpacpi_groups[= ] =3D { &dprc_attr_group, &auxmac_attr_group, &hwdd_attr_group, + &usbc_security_attr_group, NULL, }; =20 @@ -11479,6 +11589,8 @@ static bool tpacpi_driver_event(const unsigned int = hkey_event) case TP_HKEY_EV_PROFILE_TOGGLE2: platform_profile_cycle(); return true; + case TP_HKEY_EV_USB_C_SECURITY: + return tpacpi_usbc_security_hotkey(); } =20 return false; @@ -11930,6 +12042,10 @@ static struct ibm_init_struct ibms_init[] __initda= ta =3D { .init =3D tpacpi_hwdd_init, .data =3D &hwdd_driver_data, }, + { + .init =3D tpacpi_usbc_security_init, + .data =3D &usbc_security_driver_data, + }, }; =20 static int __init set_ibm_param(const char *val, const struct kernel_param= *kp) --=20 2.51.0