crossystem: Add quirk reading wpsw_cur

As GPIO numbering has changed with kernel 4.16, so we have to change the finall
offset when reading wpsw_cur. Before there was a gap (3.18):

0: INT33FF:02 GPIOS [373 - 384] PINS [0 - 11] and
12: INT33FF:02 GPIOS [385 - 396] PINS [15 - 26]a

with 4.19 it looks like below:
0: INT33FF:02 GPIOS [314 - 325] PINS [0 - 11] and
12: INT33FF:02 GPIOS [329 - 340] PINS [15 - 26]

BUG=b:143174998
BRANCH=none
TEST=crossystem wpsw_cur (on Kefka)
1. with wp present it should return 1
2. without present wp it should return 0

Change-Id: I7c8ead83717b7be35ce68026768f6f0f5b0ff91c
Signed-off-by: Lukasz Majczak <lma@semihalf.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2153155
Reviewed-by: Brian Norris <briannorris@chromium.org>
Commit-Queue: Brian Norris <briannorris@chromium.org>
(cherry picked from commit 5859c78660a9c8faf26b21210116c9d569c35b24)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2169734
Commit-Queue: Alex Levin <levinale@chromium.org>
Tested-by: Alex Levin <levinale@chromium.org>
Auto-Submit: Alex Levin <levinale@chromium.org>
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
index eba9661..a9fa623 100644
--- a/host/arch/x86/lib/crossystem_arch.c
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/nvram.h>
+#include <linux/version.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -15,6 +16,7 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include "crossystem_arch.h"
@@ -623,6 +625,10 @@
 static int BraswellFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
 				      const char *name)
 {
+	int ret;
+	struct utsname host;
+	unsigned int maj, min;
+	int gpe = 0;
 	static Basemapping data[]={
 		{0x20000, 0},
 		{0x18000, 4},
@@ -630,7 +636,46 @@
 		{0x08000, 2},
 		{0x00000, 1}};
 
-	return FindGpioChipOffsetByNumber(gpio_num, offset, data);
+	/*
+	 * This quirk addresses b:143174998 and is required on kernels >= 4.16
+	 * when GPIO numbering has changed with an upstream commit:
+	 * 03c4749dd6c7ff948a0ce59a44a1b97c015353c2
+	 * "gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation".
+	 * With that change gpio ACPI/Linux kernel 1:1 mapping was introduced which
+	 * made mismatch for gpio number and backward compatibility for user-space.
+	 * Details on review commit review
+	 * https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2153155
+	 */
+
+	/*
+	 * Here we are addressing particular wpsw_cur pin which is connected to
+	 * East Community GPIO chip (uid == 3, base == 0x10000). In this case there
+	 * is only one gap between 11 and 15 (0..11 15..26). For now crosssystem
+	 * is not checking pins in other gpio banks, but it is worth to mention that
+	 * there are gaps as well.
+	 */
+	if (*gpio_num >=  0x10000 && *gpio_num < 0x18000)
+		gpe = 1;
+
+	ret = FindGpioChipOffsetByNumber(gpio_num, offset, data);
+	if (!ret || !gpe)
+		return ret;
+
+	if (uname(&host) == 0) {
+		if (sscanf(host.release, "%u.%u.", &maj, &min) == 2) {
+			if (KERNEL_VERSION(maj, min, 0) >= KERNEL_VERSION(4, 16, 0) &&
+			    *offset > 11)
+				*offset += 3;
+		} else {
+			printf("Couldn't retrieve kernel version!\n");
+			ret = 0;
+		}
+	} else {
+		perror("uname");
+		ret = 0;
+	}
+
+	return ret;
 }
 
 /* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes