summaryrefslogtreecommitdiff
path: root/host
diff options
context:
space:
mode:
authorBrian Norris <briannorris@chromium.org>2018-10-24 10:48:00 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-26 17:18:59 -0700
commit4b5879805ac75dea9ea74a338f0f8a5d7f5edca1 (patch)
tree4ac797d0587647dc3180b545f003eea0d8b48cac /host
parent5c904692b5c3279b3258deaf98a65336f62d1df8 (diff)
downloadvboot-4b5879805ac75dea9ea74a338f0f8a5d7f5edca1.tar.gz
crossystem: replace 'chromeos_arm' device with new GPIO chardev API
Upstream Linux supports a new ioctl API for GPIO chips, via new /dev/gpiochip* device nodes. This new API supports name lookups, which is a much nicer way than the index-based stuff in /sys/class/gpio/. We can finally use this instead of our custom, downstream "chromeos_arm" driver. GPIO line names are defined in a 'gpio-line-names' property in the Device Tree. For now, we have exactly one board using this, and we're calling it 'AP_FLASH_WP_L'. We will need to ensure future devices use this same naming. Per others' suggestions, I'm avoiding using libgpiod, because it's a relatively new library (with breaking changes in v1.0 as recently as this year), and vboot_reference is used by plenty of other projects. And it wasn't that hard to hand-roll the ioctls. Side note: the chromeos_arm device is not guaranteed to be found at /sys/devices/platform/chromeos_arm any more (especially on kernel >=4.14), so this is a handy excuse to just kill use of the driver entirely. BRANCH=none BUG=chromium:897992 TEST=`crossystem wpsw_cur` on 4.14 kernels (with this API) and older kernels (without this API) Change-Id: I7553801fb0e97c8a0aa6f4341d297ad0071c3dac Signed-off-by: Brian Norris <briannorris@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1298274 Reviewed-by: Douglas Anderson <dianders@chromium.org>
Diffstat (limited to 'host')
-rw-r--r--host/arch/arm/lib/crossystem_arch.c145
1 files changed, 142 insertions, 3 deletions
diff --git a/host/arch/arm/lib/crossystem_arch.c b/host/arch/arm/lib/crossystem_arch.c
index d56f4e2e..2702f8ef 100644
--- a/host/arch/arm/lib/crossystem_arch.c
+++ b/host/arch/arm/lib/crossystem_arch.c
@@ -3,18 +3,21 @@
* found in the LICENSE file.
*/
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#ifndef HAVE_MACOS
#include <linux/fs.h>
+#include <linux/gpio.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
+#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
@@ -29,8 +32,10 @@
#define FDT_BASE_PATH "/proc/device-tree/firmware/chromeos"
/* Path to compatible FDT entry */
#define FDT_COMPATIBLE_PATH "/proc/device-tree/compatible"
-/* Path to the chromeos_arm platform device */
+/* Path to the chromeos_arm platform device (deprecated) */
#define PLATFORM_DEV_PATH "/sys/devices/platform/chromeos_arm"
+/* This should match the Linux GPIO name (i.e., 'gpio-line-names'). */
+#define GPIO_NAME_WP_L "AP_FLASH_WP_L"
/* Device for NVCTX write */
#define NVCTX_PATH "/dev/mmcblk%d"
/* Base name for GPIO files */
@@ -244,6 +249,137 @@ out:
return ret;
}
+#ifndef HAVE_MACOS
+static int gpioline_read_value(int chip_fd, int idx, bool active_low)
+{
+ struct gpiohandle_request request = {
+ .lineoffsets = { idx },
+ .flags = GPIOHANDLE_REQUEST_INPUT | \
+ (active_low ? GPIOHANDLE_REQUEST_ACTIVE_LOW : 0),
+ .lines = 1,
+ };
+ struct gpiohandle_data data;
+ int ret;
+
+ ret = ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request);
+ if (ret < 0) {
+ perror("GPIO_GET_LINEHANDLE_IOCTL");
+ return -1;
+ }
+ if (request.fd < 0) {
+ fprintf(stderr, "bad LINEHANDLE fd %d\n", request.fd);
+ return -1;
+ }
+
+ ret = ioctl(request.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
+ if (ret < 0) {
+ perror("GPIOHANDLE_GET_LINE_VALUES_IOCTL");
+ close(request.fd);
+ return -1;
+ }
+ close(request.fd);
+ return data.values[0];
+}
+
+/* Return 1 if @idx line matches name; 0 if no match; negative if error. */
+static int gpioline_name_match(int chip_fd, int idx, const char *name)
+{
+ struct gpioline_info info = {
+ .line_offset = idx,
+ };
+ int ret;
+
+ ret = ioctl(chip_fd, GPIO_GET_LINEINFO_IOCTL, &info);
+ if (ret < 0) {
+ perror("GPIO_GET_LINEINFO_IOCTL");
+ return -1;
+ }
+
+ return strncmp(info.name, name, sizeof(info.name)) == 0;
+}
+
+/* Return value of gpio, if found. Negative for error codes. */
+static int gpiochip_read_value(int chip_fd, const char *name, bool active_low)
+{
+ struct gpiochip_info info;
+ int i, ret;
+
+ ret = ioctl(chip_fd, GPIO_GET_CHIPINFO_IOCTL, &info);
+ if (ret < 0) {
+ perror("GPIO_GET_CHIPINFO_IOCTL");
+ return -1;
+ }
+
+ for (i = 0; i < info.lines; i++) {
+ if (gpioline_name_match(chip_fd, i, name) != 1)
+ continue;
+ return gpioline_read_value(chip_fd, i, active_low);
+ }
+
+ return -1;
+}
+
+/* Return nonzero for entries with a 'gpiochip'-prefixed name. */
+static int gpiochip_scan_filter(const struct dirent *d)
+{
+ const char prefix[] = "gpiochip";
+ return !strncmp(prefix, d->d_name, strlen(prefix));
+}
+
+/*
+ * Read a named GPIO via the Linux /dev/gpiochip* API, supported in recent
+ * kernels (e.g., ChromeOS kernel 4.14+). This method is preferred over the
+ * downstream chromeos_arm driver.
+ *
+ * Returns -1 for errors (e.g., API not supported, or @name not found); 1 for
+ * active; 0 for inactive.
+ */
+static int gpiod_read(const char *name, bool active_low)
+{
+ struct dirent **list;
+ int i, max, ret;
+
+ ret = scandir("/dev", &list, gpiochip_scan_filter, alphasort);
+ if (ret < 0) {
+ perror("scandir");
+ return -1;
+ }
+ max = ret;
+ /* No /dev/gpiochip* -- API not supported. */
+ if (!max)
+ return -1;
+
+ for (i = 0; i < max; i++) {
+ char buf[30];
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/dev/%s", list[i]->d_name);
+ ret = open(buf, O_RDWR);
+ if (ret < 0) {
+ perror("open");
+ break;
+ }
+ fd = ret;
+
+ ret = gpiochip_read_value(fd, name, active_low);
+ close(fd);
+ if (ret >= 0)
+ break;
+ }
+
+ for (i = 0; i < max; i++)
+ free(list[i]);
+ free(list);
+
+ return ret >= 0 ? ret : -1;
+}
+#else
+static int gpiod_read(const char *name, bool active_low)
+{
+ return -1;
+}
+#endif /* HAVE_MACOS */
+
static int vb2_read_nv_storage_disk(struct vb2_context *ctx)
{
int nvctx_fd = -1;
@@ -418,8 +554,11 @@ int VbGetArchPropertyInt(const char* name)
return VbGetVarGpio("recovery-switch");
} else if (!strcasecmp(name, "wpsw_cur")) {
int value;
- /* Try finding the GPIO through the chromeos_arm platform
- * device first. */
+ /* Try GPIO chardev API first. */
+ value = gpiod_read(GPIO_NAME_WP_L, true);
+ if (value != -1)
+ return value;
+ /* Try the deprecated chromeos_arm platform device next. */
value = VbGetPlatformGpioStatus("write-protect");
if (value != -1)
return value;