git: 319d2bf407b3 - main - atkbc: Better test for old chromebooks

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 29 Jun 2023 14:35:32 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=319d2bf407b3762da6f1c67ffe8dce2fee587aaf

commit 319d2bf407b3762da6f1c67ffe8dce2fee587aaf
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2023-06-29 14:24:55 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-06-29 14:34:47 +0000

    atkbc: Better test for old chromebooks
    
    Older Chromebooks have issues in their embedded controller (EC) firmware
    which need working around in atkbd and atkbdc. On these systems, rather
    than use a standard EC, Google used their own arm-based EC. For a while,
    its firmware incorrectly implemented the i8042, requiring workaroundsd
    in the driver.
    
    Implement a heuristic recommended by MrChromebox <mrchromebox@gmail.com>
    to detect them: If the bios.version starts with Google_, or the maker is
    either Google or GOOGLE, assume that it's a chromebook with the affected
    bios. While this isn't strictly true, the number of updated systems
    without the bug is very small and this will exclude all the non-Google
    coreboot user that use a standard EC. There's no simple way to test the
    hardware to see if it's implemented with the buggy EC.
    
    Sponsored by:           Netflix
    Reviewed by:            jon@thesoo.org, MrChromebox
    Differential Revision:  https://reviews.freebsd.org/D40789
---
 UPDATING                |  6 ++++++
 sys/dev/atkbdc/atkbdc.c | 40 +++++++++++++++++++++++++++++-----------
 2 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/UPDATING b/UPDATING
index 002e30ce2835..3a6255bc6112 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 14.x IS SLOW:
 	world, or to merely disable the most expensive debugging functionality
 	at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20230629:
+	The heuristic for detecting old chromebooks with an EC bug that requires
+	atkbdc driver workarounds has changed. There should be no functional
+	change, but if your old chromebook's keyboard stops working, please
+	file a PR and assign it to imp.
+
 20230623:
 	OpenSSL has been updated to version 3.0, including changes throughout
 	the base system.  It is important to rebuild third-party software
diff --git a/sys/dev/atkbdc/atkbdc.c b/sys/dev/atkbdc/atkbdc.c
index 9a8ab3397706..aa233972335e 100644
--- a/sys/dev/atkbdc/atkbdc.c
+++ b/sys/dev/atkbdc/atkbdc.c
@@ -109,21 +109,37 @@ struct atkbdc_quirks {
     const char *bios_vendor;
     const char *maker;
     const char *product;
+    const char *version;
     int		quirk;
 };
 
+/* Old chromebooks running coreboot with i8042 emulation quirks */
+#define CHROMEBOOK_WORKAROUND \
+	(KBDC_QUIRK_KEEP_ACTIVATED | KBDC_QUIRK_IGNORE_PROBE_RESULT |	\
+	    KBDC_QUIRK_RESET_AFTER_PROBE | KBDC_QUIRK_SETLEDS_ON_INIT)
+
 static struct atkbdc_quirks quirks[] = {
-    {"coreboot", "System76", NULL, 0},
-    {"coreboot", "Purism", NULL, 0},
-    {"coreboot", NULL, NULL,
-	KBDC_QUIRK_KEEP_ACTIVATED | KBDC_QUIRK_IGNORE_PROBE_RESULT |
-	KBDC_QUIRK_RESET_AFTER_PROBE | KBDC_QUIRK_SETLEDS_ON_INIT},
+    /*
+     * Older chromebooks running coreboot have an EC that imperfectly emulates
+     * i8042 w/o fixes to its firmware.  Since we can't probe for the problem,
+     * include all chromebooks by matching 'Google_' in the bios version string
+     * or a maker of either 'Google' or 'GOOGLE'. This is imperfect, but catches
+     * all chromebooks while omitting non-Google systems from System76 and
+     * Purism.
+     */
+    {"coreboot", NULL, NULL, "Google_", CHROMEBOOK_WORKAROUND},
+    {"coreboot", "GOOGLE", NULL, NULL, CHROMEBOOK_WORKAROUND},
+    {"coreboot", "Google", NULL, NULL, CHROMEBOOK_WORKAROUND},
     /* KBDC hangs on Lenovo X120e and X121e after disabling AUX MUX */
-    {NULL, "LENOVO", NULL, KBDC_QUIRK_DISABLE_MUX_PROBE},
+    {NULL, "LENOVO", NULL, NULL, KBDC_QUIRK_DISABLE_MUX_PROBE},
 };
 
-#define QUIRK_STR_MATCH(s1, s2) (s1 == NULL || \
-    (s2 != NULL && !strcmp(s1, s2)))
+#define QUIRK_STR_EQUAL(s1, s2)					\
+	(s1 == NULL ||						\
+	(s2 != NULL && strcmp(s1, s2) == 0))
+#define QUIRK_STR_MATCH(s1, s2)					\
+	(s1 == NULL ||						\
+	(s2 != NULL && strncmp(s1, s2, strlen(s1)) == 0))
 
 static int
 atkbdc_getquirks(void)
@@ -132,11 +148,13 @@ atkbdc_getquirks(void)
     char *bios_vendor = kern_getenv("smbios.bios.vendor");
     char *maker = kern_getenv("smbios.system.maker");
     char *product = kern_getenv("smbios.system.product");
+    char *version = kern_getenv("smbios.bios.version");
 
     for (i = 0; i < nitems(quirks); i++)
-	if (QUIRK_STR_MATCH(quirks[i].bios_vendor, bios_vendor) &&
-	    QUIRK_STR_MATCH(quirks[i].maker, maker) &&
-	    QUIRK_STR_MATCH(quirks[i].product, product))
+	if (QUIRK_STR_EQUAL(quirks[i].bios_vendor, bios_vendor) &&
+	    QUIRK_STR_EQUAL(quirks[i].maker, maker) &&
+	    QUIRK_STR_EQUAL(quirks[i].product, product) &&
+	    QUIRK_STR_MATCH(quirks[i].version, version))
 		return (quirks[i].quirk);
 
     return (0);