From nobody Wed Sep 30 02:57:43 2026 Received: from mail-pj1-f45.google.com (mail-pj1-f45.google.com [209.85.216.45]) (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 7408C3E1686 for ; Thu, 13 Aug 2026 22:17:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659476; cv=none; b=SOMOxKTDykzydQRXYvp1suZ1ovqPCZG3DjfE94K/hFoZ9RBFkRlEWbg9wvqYzojrdKVruowrCax+2Hc92uuv6Lrvw2w/wnKjukWu0KWrXvmEbi9n4+eex3fkBBj+Utp8N7BW522fNzG03x91NYIT72GH0uuBWE8+bCowaNBM3wE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659476; c=relaxed/simple; bh=5cPTCnPJa6O937ZZQIFK/lzfkFCIFcrM09a2SqAhsCw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qdSM9IZx5276ddic/is751q6ih29UkyCT/zqwYELNq5KtFI3GzFWSPNfgRV5s4IXJSLO4j/qYnlax7zzUadQyD1grQfpEaTz/wLa0WFi+MV8IMRZCvz00zLzcfCDg6GW7m4ELzbsLwghQOF5kfQ7k5KwDZ5R56VQBVM+vK0So9M= 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=fRvebYl7; arc=none smtp.client-ip=209.85.216.45 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="fRvebYl7" Received: by mail-pj1-f45.google.com with SMTP id 98e67ed59e1d1-38f620399a0so307935a91.2 for ; Thu, 13 Aug 2026 15:17:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786659474; x=1787264274; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=GDWpzRdkpQScqquzbwd+Qr1uIGmT0mrL4KFJepX9iCw=; b=fRvebYl7+/xUmaauyPrE6SOAbdgQzDPfB2s5BA6XhRRdtSMBz1Op5MjOdrKGIDBGmz X8mlyM8Wnb5UaQWmsUf5TqWyjjmBi44AHPFSMdav8kiOyhU/5AOVldczV/u4FYv2xHMl PHw2g2x9XFgXqXlD1HwHX0BdpiqssxxTcgaF8xOuWrdBoU5KJN+25kylRBj2KXbrq53p oV+J1UZT0ycav/r7P/+t1rC2GptE8YwezDIM2VwHlWdFWqhQFuwT0NSdZslkllpoU0z+ 2Gb/vTAqt4V7UVIIvJmUvwExF9W+UcTCToGu/q2gLfjbNLtd69uQRvgP2ufgsiZgYFJl M6Iw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786659474; x=1787264274; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=GDWpzRdkpQScqquzbwd+Qr1uIGmT0mrL4KFJepX9iCw=; b=FaRJ7l6AvthQy2dfptui5eiY0/pxKlWWdXar3lRM2zs4Q4uO7RmcslXTz+7pd00yIz m+fcJeDX+6588twn9pxKPAOTml28idDyvHImkxCxx/UsInQiu5+HFOxeedmRfSWkYc5k wd7y9HjRPhKgp2CiVMxZJDDVmREtRCd9kmXd2xOyF7Bza5so+7W42d8g4gEWzR0Kv7Vl ioxUo8cYQSid8TkIACqZRObudA9IHwLBZToCGs3W7/tbKQFwYbOyi0uJvGb3GuA9eLRU dyex4x9Yn7mjsZmA1de3OHg1h70tXOyZMSXk0M/rT/oJH2sQup1BgQm0QQ4EVVASpN5z 5Fbg== X-Forwarded-Encrypted: i=1; AHgh+Rq7/uJJYNJj0o2Deewx/UHS0m4X6jrwhI4X4TYphCBh6q9lkk8eFgm9O3Tmljop1bD9/SKiICHWjt+DX+8=@vger.kernel.org X-Gm-Message-State: AOJu0YylDe17Ji70K8CDm8QsxEeHBx445crpeVlWaJQj5A9uNZtNoj5b v8dYIkpOfva2pOStwb5WmRTnsKr54HSXlEeRR/CRTzezGrNg+9efleLNfmMWcxmS X-Gm-Gg: AR+sD11Ka5h3C/zdNVi+5inI8ZoHgSn1augGtHabnNE5H5BW2Pcho36E9QVI3YR1usS IgPgt9xSB4H1AMEp50+MHKgz06Pwq0Wl6pJf/FM9JR6xPQivWAie9WIvKW8vQbCa2BBA5Y+9tSC hUqmP5ZKxDTQFL6hCU/wNRy1p9sWKI+/w2ELr6vdmlhxEO2vggDBauW1olliJlYldkB0Ypwd2ZL KmF5UOuv57gJ7X3getDylq0byKMgc61Y6eLagJqATDp6DmzJGvvWQfZNWlGvdVkMtUR8Ha0lBr2 ffNKiwjNX3qonEw+0BjUIuWRE3ERQH6Nb7S6B7fW8wUhj4lSmPO9RfI93UfaSKd6AJ8E1mjIzJY pQb9B77DXfE9UP/0zxuOBQby8YA/mgLoryk38n2LVPyZRKcBgykDf3hiCYpH0HYTF2h1BjZgktT VDy174uKRaQKJr/xtnuRSiaS3lU2o1FpdT5awghGFU7Pfyt4I1XdM4czP8z1U2z9sqJuCcze8DX l228+xMRos9S/t24LI= X-Received: by 2002:a17:90b:4c8f:b0:38d:dfd1:7c1 with SMTP id 98e67ed59e1d1-3933b77fff8mr1008035a91.2.1786659473561; Thu, 13 Aug 2026 15:17:53 -0700 (PDT) Received: from sonic ([2804:18:167:9e8c:e6b5:fa0:d068:30e3]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebc667bfesm11463318eec.2.2026.08.13.15.17.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 15:17:53 -0700 (PDT) From: Hilgad Montelo To: kenneth.t.chan@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH v2 1/3] platform/x86: panasonic-laptop: Handle CF-33 rotation-lock button Date: Thu, 13 Aug 2026 19:17:42 -0300 Message-ID: <20260813221744.25668-2-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813221744.25668-1-hilgad.montelo@gmail.com> References: <20260813221744.25668-1-hilgad.montelo@gmail.com> 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" On the Panasonic Toughbook CF-33 the bezel "Rotation Lock" button does not signal via ACPI notify like the other hotkeys. Instead the embedded controller injects raw i8042/PS2 scancodes that alias the real Left-GUI/Meta key: press: e0 5b 65 release: e5 e0 db e0 5b / e0 db are the standard AT scancode for the physical Left-GUI key. The bare 65 / e5 bytes interleaved with them are not valid codes for any real key and only ever appear as part of this vendor signal (confirmed by tracing raw bytes crossing the i8042 port on the actual hardware). Left unfiltered, this shows up as a spurious KEY_LEFTMETA + KEY_F14 combo, which does nothing useful and can trigger desktop environment Meta-key bindings on every press. This driver already installs an i8042 filter (panasonic_i8042_filter) to de-duplicate volume key events. Extend it with a small state machine that recognizes and swallows the exact e0 5b 65 ... e5 e0 db sequence, and emits a single debounced KEY_ROTATE_LOCK_TOGGLE event instead. The 600ms debounce is needed because the EC repeats the make/break unit every ~280-400ms for as long as the button is physically held, which would otherwise fire multiple toggles for one tap. If a byte sequence starts the same way but doesn't complete the pattern, the buffered e0 5b bytes are replayed unfiltered, so a genuine Left-GUI keypress is unaffected. Verified on a CF-33 Mk1: each button press now produces exactly one KEY_ROTATE_LOCK_TOGGLE pair, the plain keyboard device stays silent during presses (no more stray LEFTMETA/F14), and GNOME's auto-rotate lock correctly engages/disengages. Brightness and volume hotkeys are unaffected. Signed-off-by: Hilgad Montelo Reviewed-by: Ilpo J=C3=A4rvinen --- drivers/platform/x86/panasonic-laptop.c | 85 ++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86= /panasonic-laptop.c index 719add7..0c0e4a6 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -127,6 +127,7 @@ #include #include #include +#include #include #include #include @@ -256,15 +257,81 @@ struct pcc_acpi { /* * On some Panasonic models the volume up / down / mute keys send duplicate * keypress events over the PS/2 kbd interface, filter these out. + * + * On the CF-33 the bezel "Rotation Lock" button also signals over this sa= me + * interface, instead of via an ACPI notify like the other hotkeys. It does + * so by injecting scancodes that alias the real Left-GUI/Meta key + * (e0 5b make / e0 db break), interleaved with a bare byte (0x65 / 0xe5) + * that no physical key on this keyboard uses. Left unfiltered this shows = up + * as a bogus LEFTMETA+F14 combo. We recognize and swallow the whole + * sequence and emit a single debounced KEY_ROTATE_LOCK_TOGGLE instead; any + * byte that breaks the expected pattern is treated as a genuine key and + * replayed unfiltered. */ +enum rot_lock_state { + ROT_IDLE, + ROT_WAIT_65, + ROT_WAIT_E5, + ROT_WAIT_E0B, + ROT_WAIT_DB, +}; + static bool panasonic_i8042_filter(unsigned char data, unsigned char str, struct serio *port, void *context) { + struct pcc_acpi *pcc =3D context; static bool extended; + static enum rot_lock_state rstate =3D ROT_IDLE; + static unsigned long last_toggle; + const unsigned long debounce =3D msecs_to_jiffies(600); =20 if (str & I8042_STR_AUXDATA) return false; =20 + switch (rstate) { + case ROT_WAIT_65: + if (data =3D=3D 0x65) { + rstate =3D ROT_WAIT_E5; + if (pcc && pcc->input_dev && + time_after(jiffies, last_toggle + debounce)) { + input_report_key(pcc->input_dev, + KEY_ROTATE_LOCK_TOGGLE, 1); + input_sync(pcc->input_dev); + input_report_key(pcc->input_dev, + KEY_ROTATE_LOCK_TOGGLE, 0); + input_sync(pcc->input_dev); + last_toggle =3D jiffies; + } + return true; + } + /* Not our sequence: replay the buffered genuine Left-GUI make. */ + rstate =3D ROT_IDLE; + serio_interrupt(port, 0xe0, 0); + serio_interrupt(port, 0x5b, 0); + break; + case ROT_WAIT_E5: + if (data =3D=3D 0xe5) { + rstate =3D ROT_WAIT_E0B; + return true; + } + rstate =3D ROT_IDLE; + break; + case ROT_WAIT_E0B: + if (data =3D=3D 0xe0) { + rstate =3D ROT_WAIT_DB; + return true; + } + rstate =3D ROT_IDLE; + break; + case ROT_WAIT_DB: + rstate =3D ROT_IDLE; + if (data =3D=3D 0xdb) + return true; + break; + case ROT_IDLE: + break; + } + if (data =3D=3D 0xe0) { extended =3D true; return true; @@ -276,6 +343,19 @@ static bool panasonic_i8042_filter(unsigned char data,= unsigned char str, case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */ case 0x30: /* e0 30 / e0 b0, Volume Up press / release */ return true; + case 0x5b: /* e0 5b, possible start of rotate-lock sequence */ + if (data =3D=3D 0x5b) { + rstate =3D ROT_WAIT_65; + return true; + } + /* + * data =3D=3D 0xdb: genuine Left-GUI/Meta break code. + * The rotate-lock sequence only ever begins with + * the make code, so this is a real key release, + * not our sequence; the code below replays it + * untouched. + */ + fallthrough; default: /* * Report the previously filtered e0 before continuing @@ -944,6 +1024,9 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) goto err_free_dev; } =20 + /* Synthesized by panasonic_i8042_filter(), not part of the ACPI keymap. = */ + input_set_capability(input_dev, EV_KEY, KEY_ROTATE_LOCK_TOGGLE); + error =3D input_register_device(input_dev); if (error) { pr_err("Unable to register input device\n"); @@ -1090,7 +1173,7 @@ static int acpi_pcc_hotkey_probe(struct platform_devi= ce *pdev) pcc->platform =3D NULL; } =20 - i8042_install_filter(panasonic_i8042_filter, NULL); + i8042_install_filter(panasonic_i8042_filter, pcc); return 0; =20 out_platform: --=20 2.53.0 From nobody Wed Sep 30 02:57:43 2026 Received: from mail-pg1-f178.google.com (mail-pg1-f178.google.com [209.85.215.178]) (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 7E66B36A03F for ; Thu, 13 Aug 2026 22:17:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659479; cv=none; b=iS1x6OitU82eyMwZYQjx3agwKalPND6xKnAp1Df3kmnguoSw0s2qy4i6iNwZgSFPX2up85n+dy6/drMMv2Pm2seHz+ECbiT3L3Da+JrPVlXgkswQtJDLA00TymUOltyd+wYCFRr+d0uImyOUoF74rNyORpIwQtDTXcx6v2K6MtU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659479; c=relaxed/simple; bh=xsQDYjfQm1eCxXVjzDCszXGmvYXCzlN4tkF8rFLYnPw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZJb6+AqBLlLFY0WwQFfD94cqaXatFF7x2PkmjddIRuB6An/ZpfrfwFbm/zJ9BnbR8k0UUir5zBijpiExVCIrN/edOrNwvLRWXZacJ8oXznPMp2w++sr/FRR74ffWurRToowrAAo3E80XwpZ7G/3D2uooO2JfZDSWwPAUJRF43Xg= 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=AOlcwfBQ; arc=none smtp.client-ip=209.85.215.178 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="AOlcwfBQ" Received: by mail-pg1-f178.google.com with SMTP id 41be03b00d2f7-c9eefcf9175so284910a12.3 for ; Thu, 13 Aug 2026 15:17:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786659477; x=1787264277; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=W0RUKgI78wtLWKhEVRZgKOfPx5UGL6e83+wjMlqNKno=; b=AOlcwfBQW6aX0650cgruInboaYXd6v4L/IKYfTJ6B1VuVEAFAUlokI5154CfjCE914 LfLnVgZj3FvCQMFJH8sUW3EZAqa3aYdLC0JLWtaIDVAaMwH5gNcsYdGB7O4y9mQ1AKMB 7eG86HW+bMvuHHOtKVnEqUmtpnrCgqIaMBFl9/rLlrTNh8K1DVRnaLL++0aQpW59JBcR 80JX8N4+dm78s+7HncqRwo46CPnCicgkjQP3CiSaiY5CkSAgbzauEvJBlTfGUNmr0NrJ VhZU6lG1fc1cMCHLK4jMk7L7xq0GpiTPgtvhISd+o3jyJjZpuRHKa1Rr4ASsn15jJJTV dHcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786659477; x=1787264277; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=W0RUKgI78wtLWKhEVRZgKOfPx5UGL6e83+wjMlqNKno=; b=W0BdADIDhAoCFATJIWMoM32ZoY6YM/pcasNN6lb+bjZKBV6QRbCu6xgDPBGp63LMTf qAERQACOk2X7yEnesvnmtbKOQz9H0+NUcR02OvEM5eMZmb+gKfqJrvFcVCBuiFYxaSk0 672xqNxEjEHDe+TUtJVb40bA73onGheQn1BwSf+chUxFIT0z8cUstpzHAzFlJ37Oq8iZ ZGxAz9wrF9Ekj+Wa5FvzMGoO61BOKYKfr5fh4cfjwqabeaqQ2XHA19A9EcfI6yGSwbhY JR0izLcyiVCoMYh9NQhT71M2fCadxPZ/vHd6YHMCgOEHGwAT8kjhcLjaSla/Y8mecIqC saJA== X-Forwarded-Encrypted: i=1; AHgh+RqCk6aLAlHbTfSZoptW7RHVoV3B5l6y3URxEaiIwdmAaLERpWCXG7jIE2NNdCCVW6XYc42nSqMMVn4kKrI=@vger.kernel.org X-Gm-Message-State: AOJu0YwQ0jKEt37UbGmhp/B6+rPvVQw8TUg6A3c3DNaAiU5fwibssv1r gJrq1bVIqPcbxpbZNLoVbIPJ12FfwUN7i8Eps+kXC9pRoadbShd1zNtw X-Gm-Gg: AR+sD11I3JCBosz4EhGswiROR0uIeNN8GC0/L3IjwHDwMrAs35B/Dgx5ODjTfhleDpe XQrRF8J4BY/OE0D0Osk0QDfo+Rm78RAsXCq4ntrkrtTx5cJKwdqUikEvovMaNb5iakPIvPphYSZ 2NBZcEljDyX4KvLuKLb93rXp2bKOr7Om1sBCRwvYMVzvwHA374SB84g0XVYaqCipYQ25nqchINo WlkWdETqKILc9A81QS7uMrLXyVAR51SGpC1UHRHwNlW1noe4SAvMCg/lLtztSPpq6FLsn7MtayU KtE+qKwZNc//3j7X8T2x7L0+AlumvxZ7JI3qyt+4Tx54bDAnyQNp3bl0z36v65bqUmXRJRr7e4g tjwYfTatWfYdw+i5Wj2ZXYebY+C2rV5ct74Br8XsNOf4k9yrqLFb0g/wT1qNl+VodP/5i0KfYov UDbcch6KSLT4/4YdVT0JOmMJeGkfPSUh0r7I6SI4luYJRJTBTz+BioVaWHfUxF6gS+J2sm98ukb kcMDO1HMkklDjGjfcs= X-Received: by 2002:a05:6a20:7d9f:b0:3cc:3d08:da39 with SMTP id adf61e73a8af0-3cc714e62bbmr1286185637.0.1786659476717; Thu, 13 Aug 2026 15:17:56 -0700 (PDT) Received: from sonic ([2804:18:167:9e8c:e6b5:fa0:d068:30e3]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebc667bfesm11463318eec.2.2026.08.13.15.17.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 15:17:56 -0700 (PDT) From: Hilgad Montelo To: kenneth.t.chan@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH v2 2/3] platform/x86: panasonic-laptop: Add driver for CF-33 A1/A2 buttons (TBTN) Date: Thu, 13 Aug 2026 19:17:43 -0300 Message-ID: <20260813221744.25668-3-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813221744.25668-1-hilgad.montelo@gmail.com> References: <20260813221744.25668-1-hilgad.montelo@gmail.com> 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" On the Panasonic Toughbook CF-33 the bezel A1/A2 buttons are wired to a separate ACPI device, MAT003C (ACPI path \_SB.TBTN), rather than the main Hotkey device (MAT0019/HKEY) this driver already talks to. MAT003C was present in the ACPI namespace but had no driver bound to it, so A1/A2 produced no signal through any channel: no evdev events, no ACPI notify (nothing logged), no WMI device, and no correlated ACPI GPE interrupt activity. Found by dumping and disassembling the platform's ACPI tables (acpidump -b + iasl -d) and searching for EC _Qxx query handlers that push scancodes into a hotkey queue. TBTN turned out to implement its own HINF/HIND/SQTY/SINF method quartet, structurally a clone of HKEY's: _Qxx handlers call TBTN.HIND(code) then Notify(TBTN, 0x80); HINF() dequeues one scancode from a small EC-side FIFO. Confirmed scancodes: 0x38/0x39 =3D A1 press/release, 0x42/0x43 =3D A2 press/release. Unlike HKEY, TBTN's codes never set the high bit -- press and release are distinct scancodes rather than one code plus an up/down flag. TBTN.SQTY returns 1 (it has no brightness/battery data, just a button-availability flag), so it cannot be probed via the existing acpi_pcc_hotkey_probe(), which requires num_sifr > SINF_DC_CUR_BRIGHT (assumes every device has the full brightness/eco-mode/battery SINF block). Add a second, minimal platform_driver bound to MAT003C instead, with its own small input device reporting KEY_PROG2 (A1) and KEY_PROG3 (A2) -- both already carry standard XKB keysym mappings (XF86Launch2/XF86Launch3), so no udev/hwdb work is needed for desktop environments to bind them to actions. Verified on a CF-33 Mk1: evtest shows clean KEY_PROG2/KEY_PROG3 press/release pairs with real physical timing; confirmed bindable as GNOME custom shortcuts and launching applications correctly. Signed-off-by: Hilgad Montelo --- drivers/platform/x86/panasonic-laptop.c | 168 +++++++++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86= /panasonic-laptop.c index 0c0e4a6..93e6511 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -197,6 +197,42 @@ static const struct acpi_device_id pcc_device_ids[] = =3D { }; MODULE_DEVICE_TABLE(acpi, pcc_device_ids); =20 +/* + * On the CF-33 the bezel A1/A2 buttons are wired to a separate ACPI device + * (MAT003C, ACPI path \_SB.TBTN) rather than the main Hotkey (MAT0019/HKE= Y) + * device the rest of this driver talks to. TBTN implements its own + * HINF/HIND/SQTY/SINF method quartet, structurally a clone of HKEY's, but + * SQTY only reports a single SIFR element (a button-availability flag) -- + * it has none of HKEY's brightness/battery/backlight state, so it can't be + * probed via acpi_pcc_hotkey_probe(), which requires the full SINF block. + * Register a second, minimal platform_driver for it instead. + */ +#define METHOD_TBTN_QUERY "HINF" +#define TBTN_NOTIFY 0x80 + +static const struct acpi_device_id tbtn_device_ids[] =3D { + { "MAT003C", 0}, + { "", 0}, +}; +MODULE_DEVICE_TABLE(acpi, tbtn_device_ids); + +struct tbtn_acpi { + acpi_handle handle; + struct input_dev *input_dev; +}; + +static int tbtn_probe(struct platform_device *pdev); +static void tbtn_remove(struct platform_device *pdev); + +static struct platform_driver acpi_tbtn_driver =3D { + .probe =3D tbtn_probe, + .remove =3D tbtn_remove, + .driver =3D { + .name =3D "Panasonic Tablet Buttons", + .acpi_match_table =3D tbtn_device_ids, + }, +}; + #ifdef CONFIG_PM_SLEEP static int acpi_pcc_hotkey_resume(struct device *dev); #endif @@ -961,6 +997,112 @@ static void acpi_pcc_hotkey_notify(acpi_handle handle= , u32 event, void *data) } } =20 +/* + * TBTN's HINF dequeues one raw scancode from a small EC-side FIFO (0 if + * empty) and re-Notify()s itself if more than one entry was pending, so a + * single evaluate-and-report per notification is sufficient here -- unlike + * HKEY, TBTN's codes never set the high bit, since press and release are + * distinct scancodes rather than one code plus an up/down flag. + */ +static void tbtn_report_key(struct tbtn_acpi *tbtn, unsigned int code) +{ + static const struct { + unsigned int code; + unsigned int keycode; + bool down; + } keymap[] =3D { + { 0x38, KEY_PROG2, true }, /* A1 press */ + { 0x39, KEY_PROG2, false }, /* A1 release */ + { 0x42, KEY_PROG3, true }, /* A2 press */ + { 0x43, KEY_PROG3, false }, /* A2 release */ + }; + int i; + + for (i =3D 0; i < ARRAY_SIZE(keymap); i++) { + if (keymap[i].code !=3D code) + continue; + input_report_key(tbtn->input_dev, keymap[i].keycode, keymap[i].down); + input_sync(tbtn->input_dev); + return; + } + + pr_info("Unknown TBTN hotkey event: 0x%02x\n", code); +} + +static void tbtn_notify(acpi_handle handle, u32 event, void *data) +{ + struct tbtn_acpi *tbtn =3D data; + unsigned long long result; + acpi_status status; + + if (event !=3D TBTN_NOTIFY) + return; + + status =3D acpi_evaluate_integer(tbtn->handle, METHOD_TBTN_QUERY, + NULL, &result); + if (ACPI_FAILURE(status)) { + pr_err("TBTN: error getting hotkey status\n"); + return; + } + + if (result) + tbtn_report_key(tbtn, result); +} + +static int tbtn_probe(struct platform_device *pdev) +{ + struct acpi_device *device =3D ACPI_COMPANION(&pdev->dev); + struct tbtn_acpi *tbtn; + struct input_dev *input_dev; + int error; + + if (!device) + return -ENODEV; + + tbtn =3D devm_kzalloc(&pdev->dev, sizeof(*tbtn), GFP_KERNEL); + if (!tbtn) + return -ENOMEM; + + tbtn->handle =3D device->handle; + device->driver_data =3D tbtn; + + input_dev =3D devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + input_dev->name =3D "Panasonic Tablet Buttons"; + input_dev->phys =3D "panasonic/tbtn0"; + input_dev->id.bustype =3D BUS_HOST; + input_dev->id.vendor =3D 0x0001; + input_dev->id.product =3D 0x0002; + input_dev->id.version =3D 0x0100; + input_set_capability(input_dev, EV_KEY, KEY_PROG2); + input_set_capability(input_dev, EV_KEY, KEY_PROG3); + + error =3D input_register_device(input_dev); + if (error) { + pr_err("TBTN: unable to register input device\n"); + return error; + } + + tbtn->input_dev =3D input_dev; + + error =3D acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + tbtn_notify, tbtn); + if (error) + return error; + + return 0; +} + +static void tbtn_remove(struct platform_device *pdev) +{ + struct acpi_device *device =3D ACPI_COMPANION(&pdev->dev); + + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, tbtn_notify); + device->driver_data =3D NULL; +} + static void pcc_optd_notify(acpi_handle handle, u32 event, void *data) { if (event !=3D ACPI_NOTIFY_EJECT_REQUEST) @@ -1221,4 +1363,28 @@ static void acpi_pcc_hotkey_remove(struct platform_d= evice *pdev) kfree(pcc); } =20 -module_platform_driver(acpi_pcc_driver); +static int __init panasonic_module_init(void) +{ + int error; + + error =3D platform_driver_register(&acpi_pcc_driver); + if (error) + return error; + + error =3D platform_driver_register(&acpi_tbtn_driver); + if (error) { + platform_driver_unregister(&acpi_pcc_driver); + return error; + } + + return 0; +} + +static void __exit panasonic_module_exit(void) +{ + platform_driver_unregister(&acpi_tbtn_driver); + platform_driver_unregister(&acpi_pcc_driver); +} + +module_init(panasonic_module_init); +module_exit(panasonic_module_exit); --=20 2.53.0 From nobody Wed Sep 30 02:57:43 2026 Received: from mail-pl1-f182.google.com (mail-pl1-f182.google.com [209.85.214.182]) (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 997FB3E7BCA for ; Thu, 13 Aug 2026 22:18:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659481; cv=none; b=tg+J8soLhWAwj6Lth7ZMyAewUfZqtmkhGe8PW1iDLDvXcX2RFOclZFbFBuhsEZmOOZc9UlpJD+pQUUKO+IbioETxKWAsF7P6iuiyTVK7cKJFLJ6xf7H2Ana9l0xir9OJb7fIqvQk8UhTJg8xCeqUE5btkLXSiYEHoozq9upJKiM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786659481; c=relaxed/simple; bh=Fx11ZzcEMDx+XWvgLsyL/NzaNa77kctud5tY5T/YvMU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BATk2FqVFW1tLSlvuH5NXUpoaTvbgT7NbFqvAlfUo0VTOftmKo5j31Knb0AIV0VQv5mjpRHZzzG+G5t7m+twpsNRAaA5iPVsSRRNpFfTMPKRg+x9nePW7+Bfx+AimX02Hfup2yQFrpeePwAzJ9EUoFj9M6erMZ5JkfbM/w1oR0U= 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=DgyAGMgu; arc=none smtp.client-ip=209.85.214.182 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="DgyAGMgu" Received: by mail-pl1-f182.google.com with SMTP id d9443c01a7336-2cacf197759so6905605ad.2 for ; Thu, 13 Aug 2026 15:18:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786659480; x=1787264280; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=6kwzuj7mx25GPpnRY6pHNhOgcyjHMHZYoHK7gFZt5W0=; b=DgyAGMgucPEotkq2lpIAYvp06ZAK2t16lOcL+r2uXDhrKPpabmI5d68w3+t0D4iXbj /F95tQUB33RAhm7vhszOYNNfpf0uX0cLNn7UwgP2X/mUFWFZknSVQztEyzMJAPNlEYLE o4JuheHbQNRxJxFEUB83uVFK3YWttT+ypyX/sVSBJtke7CB28j1bUIvi6i4Gh09lqMSK pOrDwHpsgnWY/Nz7im306L/YZlqGalki3gu8NXaSA/btw8ONv+Pgp86fPgu7wklJp2Cy 117pwgPycO/zWWQuoG0fr7ReEOWRAEr7aov/MIJ+xWWyRQzTmkl4SJaCgPpxWJ7XU59s F8XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786659480; x=1787264280; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=6kwzuj7mx25GPpnRY6pHNhOgcyjHMHZYoHK7gFZt5W0=; b=Gs2vdGvh+4n8xiSF7e5R4HxreBtoTyRQDLCeXigSf0jGIw21eVDOy5mJ+ZhTLMHkNT wGukrN0tNadp2X8ckBGyYZQC6tRfs9FC07ZmwQCsXMmSO3xKhBxbr+FuGKIIC58lph5v bB0tJK2ncfoN70lYru/SBcrAsks2dWUagAW/1Nr7zrpEQwyYe4k2eNTZH0bmvX5HjVy0 O0wwJmP8ZfvjxvWcZdrbBFHLqdkTRj8OLt/kHhvWEeTG6dndHyA3R8WtxuaCxAFiQiZG +FxAHsBvwgrWJVTXFMYbLs1H/ZovKrn3vMTr6BysKVxr4a0/jeceroMTGtdTYD3O7avG 5bXQ== X-Forwarded-Encrypted: i=1; AHgh+RqQ9tDXEvvcMOCr/UnIBomnPKFTsAIN0fOq9g2+qmbBAKI0WV/DYR99fseFLDqLiacjR1Fay1pJHMwopJc=@vger.kernel.org X-Gm-Message-State: AOJu0YzjOXw3O2MIqhqzyDREzqtXcP1nWSRt7W/zaDcaqy/bxPuW1ZIU j6bRwzl6in8cnCD59Zor0cMvzSs/0QwrFbDEPy5sxY8m8Pq6kdTIzjaE X-Gm-Gg: AR+sD103/IHUmWNLNja7u4dru4LWX9yRZe2YTWhGyb+oK40a8hrdunGQPFg1ud7hoNM 9m461W0hKpKxILHjk9GMl13PbVlEotp0tbzAJIxKhIj0Mm6yTI8SOM1fqY+YbtoXta3N6Lwbv4t AINmHe84aN4ijVEC+kKU0dXQY/qr2Yu9w64dBcea5XycvEn+gwT4nD8tNuJ3ScsleDclP4ixVKI TfLRer0u344+pQhNG9sYKrfiWANnY1jp3xGlKMQVYJHDGTVeidjDzUgdopOjiCdt/8cDm4x7Y1l Vs6CCfkaCvA5XYXgjQhLpeZnHG94zzi40vAhuZy35LpuUestSSeAxfm2B7dRnTXim9OeVxWvU4i EluGNguntW8hiziixW+5R7iGRuKtRRAjmApLCcPqq2SUhYtY4EBYuMqmv2wa1NYccfzoTMJAmZs qj4Z+8hOLzuZTum0cs4GVqxm3meA97WjzwUkxmH1FZEXLHSiqIhJ/VeK5lcMI7YKaZVLIVIfsLW KgQMK7UHvRBvk1wNS4= X-Received: by 2002:a05:6a21:2d4b:b0:3b2:a809:ffe with SMTP id adf61e73a8af0-3cc71a2d522mr1308747637.14.1786659479811; Thu, 13 Aug 2026 15:17:59 -0700 (PDT) Received: from sonic ([2804:18:167:9e8c:e6b5:fa0:d068:30e3]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebc667bfesm11463318eec.2.2026.08.13.15.17.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 15:17:59 -0700 (PDT) From: Hilgad Montelo To: kenneth.t.chan@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH v2 3/3] platform/x86: panasonic-laptop: Fix sentinel write past pcc->sinf[] Date: Thu, 13 Aug 2026 19:17:44 -0300 Message-ID: <20260813221744.25668-4-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813221744.25668-1-hilgad.montelo@gmail.com> References: <20260813221744.25668-1-hilgad.montelo@gmail.com> 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" acpi_pcc_retrieve_biosdata() rejects SINF packages only when pcc->num_sifr is strictly less than hkey->package.count, then unconditionally writes a trailing sentinel at pcc->sinf[hkey->package.count]. But pcc->sinf[] is allocated with exactly pcc->num_sifr elements (valid indices 0..num_sifr-1), so that write needs num_sifr strictly greater than package.count to stay in bounds -- num_sifr =3D=3D package.count passes the existing check but still overflows by one element. This is exactly the case probe()'s existing num_sifr++ workaround ("Some DSDT-s have an off-by-one bug where the SINF package count is one higher than the SQTY reported value") is written to accommodate: when a DSDT's SINF package count equals SQTY+1, the workaround makes num_sifr equal to package.count, which is precisely the boundary that overflows here. Found via UBSan (array-index-out-of-bounds) on hardware where HKEY.SQTY returns 37 and HKEY.SINF()'s package has 38 elements: num_sifr becomes 38 after the +=3D 1 workaround, the loop correctly fills indices 0..37, and the sentinel write then targets index 38, one past the end -- a silent 4-byte heap overflow on kernels without CONFIG_UBSAN. Tightening the rejection check to num_sifr <=3D package.count would avoid the overflow but breaks probe() entirely on exactly this hardware, since num_sifr =3D=3D package.count is the case the off-by-one workaround exists to support. Nothing else in the driver reads this sentinel value back, so simply skip the write when there is no room for it instead. Signed-off-by: Hilgad Montelo --- drivers/platform/x86/panasonic-laptop.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86= /panasonic-laptop.c index 93e6511..9511440 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -476,7 +476,16 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi = *pcc) } else pr_err("Invalid HKEY.SINF data\n"); } - pcc->sinf[hkey->package.count] =3D -1; + /* + * pcc->sinf[] has pcc->num_sifr elements (valid indices + * 0..num_sifr-1). On DSDTs where SINF's package count equals + * num_sifr exactly -- the off-by-one case probe()'s num_sifr++ + * already allocates a spare element for -- there is no room left + * for this trailing sentinel; nothing reads it back, so just skip + * the write rather than running one element past the flex array. + */ + if (hkey->package.count < pcc->num_sifr) + pcc->sinf[hkey->package.count] =3D -1; =20 end: kfree(buffer.pointer); --=20 2.53.0