From nobody Tue Sep 29 02:34:10 2026 Received: from mail-pj1-f44.google.com (mail-pj1-f44.google.com [209.85.216.44]) (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 DA99B33C194 for ; Thu, 13 Aug 2026 02:57:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589856; cv=none; b=N++Obkjncv3EoXn+0Dvvkjl9fB2YXhw9oY/7j1bq/XFimcGnesFC4tLEdpwkvpOR5jf0rWsfXhipPsnTBL6AQ9DJaNxwxbN6rZxMwhqPgTbIaYlHCqXo6u9icQsPV0xmZGK7SsyAHY3H5LYIkxSR/sZp+Ui4M4Pu37DICj8kJsA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589856; c=relaxed/simple; bh=cRQfdbLZ3ICmfv+Fc5dWwLKI4CXtVAZc0TRfydSnF+8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RChjW4tGwuE+IjJPS0lrXxf9xABYFt+wf2qLmk29wgZ0lrA3jS0EQ2aWCGyb/Rf90H0aSwSvhGuup94I0XBCVoUPg1j8zwyhDiXmaBCWuWYvEXi+NRAxaLWXP/s3ENFuOgnaRRb6QE8eq7x6L0W3wgpXYduNUe98OWKST4nFcwo= 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=D1XzdeH4; arc=none smtp.client-ip=209.85.216.44 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="D1XzdeH4" Received: by mail-pj1-f44.google.com with SMTP id 98e67ed59e1d1-38dc69c74b8so350160a91.0 for ; Wed, 12 Aug 2026 19:57:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786589854; x=1787194654; 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=zhNKXXTZhX7lAIpUNXsVTvjOGLIK85dFzIC2xWkANms=; b=D1XzdeH41XE9LC7RsBjHAiMesIPXDpolir/W0WmBQ2S/SmWj4jeujhvwI9B+QsiirS jvW+/4kx1P6okhragJrPHsa5nj/gTJdaN7WquJ+XSt3PIihQX2L9O+W9elV6k+UdYaU3 cZbSaLbxolvekQ2Rf3f1uVbJEvPaoPwz5gFNaFoD6Eq1KDA5iYzu0W6lalpqp7IHqHjV 2lLRnRCuajtHMwTAip0/pRYWhpC0uv7er1X/Gn/EFOneeEZdwMzhQMrVkfVXPKaMdqEU +yM6WvsFgSIUk+V3S6z8ifT9Si9Nq/7ednvbPKEPjQwv4q7xesdAqzhA2ocGu/adEJMT FPXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786589854; x=1787194654; 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=zhNKXXTZhX7lAIpUNXsVTvjOGLIK85dFzIC2xWkANms=; b=fQ9Mu2o8ROSsBopXzBreNRyw6h7Nt+d3CLbe/ccKthgwslKjEpK+Quxe5clm+KPBaj S4RQ0yFviUzkHB+dczIrTgLPJCNIcjNk1SMpQjJ85vwLfJrsHAJE6nnLXUKKXHyTS5K+ AW+6E0lxjDJG9k3SO5k7tMNBqoZ0pztLMcyOmoyVLdT1h2uHRicgXjOS+Dw1q6xeos0h gd5qbNPBWpEw5QgDUbjJWOdLkr8hrejsh+NIeShC2GCAA7MaUXZIUHYumNY1aFXMM5xl TDMjW92yyJROb73qHYu5VKinPKbmexTdebRWeaP4vyqPEdXGxIW+Szad+Eyyg4Slbhor TfXQ== X-Forwarded-Encrypted: i=1; AHgh+Rpseul4bcN2vSmIKxO8fDJeXV8rbp3RAud0ZzCoB60RC33cUQPP1t1IU9Bhbjv30IVEFO4+YTvqK6tdeDA=@vger.kernel.org X-Gm-Message-State: AOJu0YwH3d6nHQVjG4xMMWq0sTrpNRfIVxU0r3m+NZ9QXWSediUf4ZL4 cAcf6DAuc1ScHv0ZsJuMKayX7v+8LIwOotBODsD0DfotBzen0LbatQU0 X-Gm-Gg: AR+sD13B/Buq3axr0ZXt5zKGoDYPmk4V5OKpyj5FLire8ONkli6lPUDxzGBNCiz3OW4 cXR8DxgO+f/foZ55viOpFsXFRAz3lFgeHjLU7Yd542lh7K7khPFOcPT2vzzc8rG8WdM098/4uj9 NBwu1ciEL+oWhs3tkt9xhhOoRODiud1ZIBJ1Ivc95iU7THbuoByPznJNnvlvGEDpAZjz5U2Zkij CUjuNSWXFGsQO4s73NAOxun/kEHd8uSQ6Pvt9W+s+BfhLTk+XsEZUCjJ/7O/cc8pzoLqqoeP3Pu Z/x/OBLAydwwbuVKWYm8q2OMSCIz3WPGtOQAMPLirCgT9gtvtbuXP+iy786N9EpxHcfdXE1LtgV yRb4Lxwfss8zK8ja4Nm/dqQCRrT3M6t8GOIin8S3t30lKDj9UYoCnjVjveRt+O1JlM5SeIjW7ri aaXXbm9u1FqfqbNPLaSC1OE2YsxgAco8u3BAqobjdmShO94MzFW+vwxT1m4q5KRCwzSGbjCcz+D xppZNKv9Ql2NnorKVc= X-Received: by 2002:a17:90b:540c:b0:390:b41a:b92f with SMTP id 98e67ed59e1d1-3931e31bd38mr3055871a91.18.1786589853993; Wed, 12 Aug 2026 19:57:33 -0700 (PDT) Received: from sonic ([177.181.237.62]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebcf66340sm2097470eec.13.2026.08.12.19.57.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Aug 2026 19:57:33 -0700 (PDT) From: Hilgad Montelo To: Kenneth Chan , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH 1/3] platform/x86: panasonic-laptop: Handle CF-33 rotation-lock button Date: Wed, 12 Aug 2026 23:56:23 -0300 Message-ID: <20260813025626.24266-2-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813025626.24266-1-hilgad.montelo@gmail.com> References: <20260813025626.24266-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 --- drivers/platform/x86/panasonic-laptop.c | 75 ++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86= /panasonic-laptop.c index 719add7..730d7cb 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,9 @@ 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 */ + rstate =3D ROT_WAIT_65; + return true; default: /* * Report the previously filtered e0 before continuing @@ -944,6 +1014,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 +1163,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 Tue Sep 29 02:34:10 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.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 620EB328B5E for ; Thu, 13 Aug 2026 02:57:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589861; cv=none; b=JhJ5Sfwvtd9CP2qAnWWsMtrYHsAtDPMaVovThVEeeV7Q/9KiApUnz4DeitttzvhjGseGsma9KPKvZEp9KNHBYbbPytasFVSBpX0JjvuOhSdxBfpPBFGAY/ziXwXyTyr1lloIwYF2eiZKwUXUffv9khtBR6ECsE1z3coA4MPA5oc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589861; c=relaxed/simple; bh=+DG+ErOqL3MI1/uxM3oZ4HOBVJ5ceUMjv64DI0XGTqE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YdwI/gIuNPsrk92TvqwquPMqNK9GIb7aU6dp/2Wd8MJ1EPmz+lBTdJEYOF63E+e5sFLL4jvGJLZb1R9IIf6djqlF8QoXoW6NgnFodJ2HfVQwIY0TU8im8Iro28Cx2U/k+kjDm1T1vjEoHx1muIKKSAUBdkAJCoSWJ1PMImybqyM= 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=VomJEbsc; arc=none smtp.client-ip=209.85.214.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="VomJEbsc" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2cc891373e0so3869365ad.2 for ; Wed, 12 Aug 2026 19:57:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786589860; x=1787194660; 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=WPSVRVpAe9dkfC7tbQ9eQpuysvjIMyLxryqJQ4l+Z84=; b=VomJEbscW3B/BCk5ZJBKdbZNkEMJexNybVOx2+t36/pCieHlquw9zrpmXc0wbUkT18 nxFrv6C1SuyAEBtmN4VA6hHrbd2mzxSsfTylsiKfbwN90SOhbxcXJJud2KUIe3g/RGmA fq07NovImW8FxTGB6e8bJxkP3fPI+EEwCL3Xxzf/OM7NRCWpUmXBUVj8DqsKo1j4Wkin QYZcD9q6646PkJ4/hzFIhrSbLGVcNdtNqMhQ2mkc43oBPjO0rkzo1Ooyvh6SVJFr1/bi 0qX8jOYMXEC4bRfpihCeziRIKKwieytVie32FzUumXUDd/RAE8gUODh2XvpWSaZvTZVI l5Og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786589860; x=1787194660; 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=WPSVRVpAe9dkfC7tbQ9eQpuysvjIMyLxryqJQ4l+Z84=; b=qEIaeH1TCRoSAAdu9gKzCGqnaQJnOdDrFhmMcJ/RQT1auNfmO2XdoAtXH51+fCyl4p tTuxSakfmHfiIUPK6NILZeNYdI1csIB5sl32Dc3Qpbu6d5Qaj659uFojTOKMrCBc8OqR 6XCC3/UZ/+oY9MqZW/zZU7vP1zUFRcpC7fm24IBjSmjiE0z5VhEI4wZ1ruo5OZdsxI/D XSTx03OWiCZlEWtF1WALnDVjTwXpl3CIDOkCCrHs6j800J0l0+iTHsL+0hkHgf0THXu6 30KT/C+OStYwSlndiMMebhnfb9XIoyN5hWBHUJ844lPSn+O6FDoRo48oC0/uTaLrIhxT +Ycg== X-Forwarded-Encrypted: i=1; AHgh+RoR0qI+eBSGdpS5RQ4OrdYyWxD1oBtk1vjgs3DZpao6gdrThY/oVrV301AmPuVN9cP+um5SEhWqziraHgY=@vger.kernel.org X-Gm-Message-State: AOJu0YwhP5eCSJTKfXzgWWGxC+AqPNBDtZ8ghs9fTGdzV5dFpZb1yGVj gHYsS32qaiBM0my+Mb6DOOHt5d9fSyvETgRBquFRmFrEr1oCauTGEp1crqlp9zBmtDY= X-Gm-Gg: AR+sD10SbSaBS/MsH1jwJMVAq/KFnL3QSz/TvDp5MRw/Sp6iglW+asf1hdR5Z98ofPa 9pT3FIMxsahWh79GBIUE+4Y1jHztmISs2vBVhRlhwbPfe2NLB+2qmZNq51CQzTc61H9QAqEx3ta OfPHNEnS+rFJdPFsMO8Pz73O8M8LCsSxT+SRTy5NNzYYkX4Lbk4zlSmUJ0yo1nsu46U5rzi0lI9 +MI0azplmC67MZ85TLniALCZU40y8pFUwiI9Vg3xac8RqddO+c6TSW9/aZRg5TOXYKn/h8eIVDe cxS7HxF0u3JWjCAKsPrU0l0kwMBahsFv/Tyk4/9JkFex8p6jr74HvE5itutLkrpIfXeDGQdCWRr 38RqARUDOFhC7u6IO2NK6YDRpMucybyBf4NsyWOZI62WdXEkxWpYmf4iREinW3OkbmEy4qq9z5i 2p0LEILf9XWcaNTYjp+LdU5nRp/XDYDqb+aFNTbOuJwCo6wRRRpA736B54lTGGZljSA0XzlyKx4 n1M9Ux36+ZPRasO1Ds3 X-Received: by 2002:a05:6a21:7111:b0:3c3:af85:85e7 with SMTP id adf61e73a8af0-3cc55423424mr3821623637.34.1786589859561; Wed, 12 Aug 2026 19:57:39 -0700 (PDT) Received: from sonic ([177.181.237.62]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebcf66340sm2097470eec.13.2026.08.12.19.57.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Aug 2026 19:57:38 -0700 (PDT) From: Hilgad Montelo To: Kenneth Chan , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH 2/3] platform/x86: panasonic-laptop: Add driver for CF-33 A1/A2 buttons (TBTN) Date: Wed, 12 Aug 2026 23:56:24 -0300 Message-ID: <20260813025626.24266-3-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813025626.24266-1-hilgad.montelo@gmail.com> References: <20260813025626.24266-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 730d7cb..0afd6b8 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 @@ -951,6 +987,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) @@ -1211,4 +1353,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 Tue Sep 29 02:34:10 2026 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (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 7C3BA33B96B for ; Thu, 13 Aug 2026 02:57:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589877; cv=none; b=SI0/vvYqAh58fBYyP6z+g5nEvvPy2VpGjZbgMWJwFhlT/Sp9UndpG1d+rUQd1E35uC8+tbrs06ZCKuLfCxrAM+IveKYNCMm4kxjwPUwNxmVab8Qu2C559a1I+XinZLAh1icUK/OY7dccd6vsBgBj4IOS7N4v1X9uOV1iod4ey4A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786589877; c=relaxed/simple; bh=MRVZLhqECN/6bq7hUPFuPgmN1e8vpRmFgF1p+CAfNPQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f7HzVerMymvjGqgohbGbN0eo+WAAcwax+dZ5prRrd61y+cu1y7CCEU7cDnm26Sa4AmgVzFkA/aCPJhQLhk1Os2+Bu2sWgTR7YgMFkUO3ZV4amoFRD+ws/TpgnmEw8GzJnc8gRF1mLpiLY4ntppJ1G5IG/QrZaKpWISc+YPO62Is= 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=ifFiW1xH; arc=none smtp.client-ip=209.85.214.170 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="ifFiW1xH" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-2cf50c6f235so24175355ad.0 for ; Wed, 12 Aug 2026 19:57:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786589876; x=1787194676; 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=1+GWENBjDWrJEgL5CdDa2/cfWBjrCiB4j8gWnZOgbQY=; b=ifFiW1xH/Hqw9yPHXjx7ViShdIMP6Hzbsenk/OoMDEORDsn1sVwrojOJzhyT1dMBgc 0QRNRckq4Sj1ov3Hu7YPDkEvfadziQTvvJG6wa9L1HO2lL/8nxTWO48ISyc2vDQLF1rT Y8d9gx0fJivswTTR0uqAJ67z97++nXx8UFChqTT/zk9k1hGWGGehZUpxMIoT2j5J3zIO JpdcESzM+p84Ve7/t8JL0Ys0aygpG614ZDzP58Yon/C2O7+2pi6P1Z7IAeCa5QvuvXqB 7SoAxLhY4HFmJqzfNt45R/GOB/KwO+QY7lfGIamK2sAcnnjkIYZ725dEe+hySRL4QblE 9Ssw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786589876; x=1787194676; 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=1+GWENBjDWrJEgL5CdDa2/cfWBjrCiB4j8gWnZOgbQY=; b=m4svxy1o1bc10/ph+SRCo6M6Mg26O7HBIShThpSclTT51XgOf78JHr1KjBel9c3iCq i+x6WvJ2nO2h9T453QR+vMB3ZO4kX54tgxMxHtiwNSpirybM3YhQAeFNz4/wc/7m9Whx qKo6v2z2ayAPXN+/79RIrm3Uma+eFh62XHx28qd39aQjLmN5992mU46vROBUIpBfztby ewx+gDZi7Rt70BCxfpl12OuTw6+PeeVoAzqiPa8Nfhri/MI9PB7pkoSVZSzNuQCoiB+C YEIEsZE8rz6cP0rR/6wuebSPEl7UKNbTigo0GMrC3VHl7+5BECjnZyUHqkHpNtpy264Z oy8A== X-Forwarded-Encrypted: i=1; AHgh+RqqZeAoL7kGBAjHgh1nf8bt/tdCg+VUmD1j4Rs6LOb1rzT85an01767XNGxu+ZiObfs9LZAuOtXUmXEuVA=@vger.kernel.org X-Gm-Message-State: AOJu0YzzNF2rXJK8Tj0a7q8I5M1BqyvQB+8wZPINkyBE3XxvbJBVn5/x bUVsje0wtxH10ik1dw6JGdBhXcM4le7nOK3RcRqUX1dJI4z7UDcNPaKy X-Gm-Gg: AR+sD10I3ZWPZmfb99vK17HhdXWy6FHFG5ZVGid5WuYEfhZjzZHmb592hIOIOUwFIqr 10hRX/PzoBRQNfAsCf04CTcG5urn+0Na/VEgY/qhaagzApwKLX0FG3GElpOBiVYgyFXv/Mm8pSN apbC/sSxDLAaQrCj/m3E65JyMXQ4DtXDN58bKyiTdkev/6U4BwmAsxX/ij+1ZiqVV75BJzY2PEh oG21xvU4e3WwREGcKygt+FxDg0fZQ/ffQS2uYx7n0oOjzD+MRzpSY4qNQYp53R/bgWfOJfYUV9y P0JtosBzh1xWDKjBqD0C4zd4yeyE/PYFRLeSF9IuVpg9SSZCTf8B4iSHw76nDER/a66aPSNu1la 5ZSzFzlyscJTVwFSrubbRoQ2GORvTQHUWm4cAWoqynITo6e+Zlz/6PnDJWE0gFjJ82FQxgxjhlc Nl7iQADuUDMDS6JU6O8NetjEuKETTneJlZJJArP0Q80EUgkVKTacP3WSm3gvMx20jDWRpeOGzfE ziKJxUzqqZb7PC4DRM= X-Received: by 2002:a05:6a21:7002:b0:3cb:eca6:ce5 with SMTP id adf61e73a8af0-3cc5539af60mr3916877637.24.1786589875490; Wed, 12 Aug 2026 19:57:55 -0700 (PDT) Received: from sonic ([177.181.237.62]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31ebcf66340sm2097470eec.13.2026.08.12.19.57.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Aug 2026 19:57:55 -0700 (PDT) From: Hilgad Montelo To: Kenneth Chan , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Hilgad Montelo Subject: [PATCH 3/3] platform/x86: panasonic-laptop: Fix sentinel write past pcc->sinf[] Date: Wed, 12 Aug 2026 23:56:25 -0300 Message-ID: <20260813025626.24266-4-hilgad.montelo@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813025626.24266-1-hilgad.montelo@gmail.com> References: <20260813025626.24266-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 0afd6b8..cb79ddb 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -466,7 +466,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