pn80t gpio: wire up the gpio toggle

This change connects the interface targeted
APDU:
    0xff 0xe0 0x00 0x00
to the nq-nci platform to allow the inBootloader
gpio to be toggled (cleared).

Test: works with the new kernel
      echo -e 'ffe00000 9000' | strace -e ioctl ese-replay nq-nci # shows ioctl
      applet or kernel state not toggling.
Bug: 37159008

Change-Id: I4526be8901b512bd289ddf10c6cda26f9ecdf506
diff --git a/libese-hw/nxp/include/ese/hw/nxp/pn80t/platform.h b/libese-hw/nxp/include/ese/hw/nxp/pn80t/platform.h
index 8dad425..9596cba 100644
--- a/libese-hw/nxp/include/ese/hw/nxp/pn80t/platform.h
+++ b/libese-hw/nxp/include/ese/hw/nxp/pn80t/platform.h
@@ -42,6 +42,8 @@
   pn80t_platform_toggle_t *const toggle_ven;  /* NFC_VEN */
   /* Optional: enables eSE power control via |toggle_reset|. 1 = on, 0 = off */
   pn80t_platform_toggle_t *const toggle_power_req;  /* SVDD_PWR_REQ */
+  /* Optional: toggles the in bootloader gpio */
+  pn80t_platform_toggle_t *const toggle_bootloader;  /* CLEAR_N */
   /* Required: provides a usleep() equivalent. */
   pn80t_platform_wait_t *const wait;
 };
diff --git a/libese-hw/nxp/pn80t/common.c b/libese-hw/nxp/pn80t/common.c
index 5ea20a1..9a52454 100644
--- a/libese-hw/nxp/pn80t/common.c
+++ b/libese-hw/nxp/pn80t/common.c
@@ -213,17 +213,20 @@
                                          struct EseSgBuffer *rx_buf,
                                          uint32_t rx_len) {
   /* Catch proprietary, host-targeted calls FF XX 00 00 */
+  const struct Pn80tPlatform *platform = ese->ops->opts;
   static const uint32_t kCommandLength = 4;
   static const uint8_t kResetCommand = 0x01;
   static const uint8_t kGpioToggleCommand = 0xe0;
   static const uint8_t kCooldownCommand = 0xe1;
   uint8_t buf[kCommandLength + 1];
   uint8_t ok[2] = {0x90, 0x00};
+  struct NxpState *ns = NXP_PN80T_STATE(ese);
   /* Over-copy by one to make sure the command length matches. */
   if (ese_sg_to_buf(tx_buf, tx_len, 0, sizeof(buf), buf) != kCommandLength) {
     return 0;
   }
-  if (buf[0] != 0xff || buf[2] != 0x00 || buf[3] != 0x00) {
+  /* Let 3 change as an argument. */
+  if (buf[0] != 0xff || buf[2] != 0x00) {
     return 0;
   }
   switch (buf[1]) {
@@ -236,8 +239,19 @@
     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
   case kGpioToggleCommand:
     ALOGI("interface command received: gpio toggle");
-    /* TODO - need kernel support first. */
-    return 0;
+    if (platform->toggle_bootloader) {
+      int ret = platform->toggle_bootloader(ns->handle, buf[3]);
+      if (ret) {
+        /* Grab the bottom two bytes. */
+        ok[0] = (ret >> 8) & 0xff;
+        ok[1] = ret & 0xff;
+      }
+    } else {
+      /* Not found. */
+      ok[0] = 0x6a;
+      ok[1] = 0x82;
+    }
+    return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
   case kCooldownCommand:
     ALOGI("interface command received: cooldown");
     uint8_t reply[6] = {0, 0, 0, 0, 0x90, 0x00};
diff --git a/libese-hw/nxp/pn80t/linux_spidev.c b/libese-hw/nxp/pn80t/linux_spidev.c
index d4ac386..8b3c502 100644
--- a/libese-hw/nxp/pn80t/linux_spidev.c
+++ b/libese-hw/nxp/pn80t/linux_spidev.c
@@ -239,6 +239,7 @@
     .toggle_reset = &platform_toggle_reset,
     .toggle_ven = &platform_toggle_ven,
     .toggle_power_req = &platform_toggle_power_req,
+    .toggle_bootloader = NULL,
     .wait = &platform_wait,
 };
 
diff --git a/libese-hw/nxp/pn80t/nq_nci.c b/libese-hw/nxp/pn80t/nq_nci.c
index 58a1777..60b7464 100644
--- a/libese-hw/nxp/pn80t/nq_nci.c
+++ b/libese-hw/nxp/pn80t/nq_nci.c
@@ -53,6 +53,7 @@
 /* From kernel/drivers/nfc/nq-nci.h */
 #define ESE_SET_PWR _IOW(0xE9, 0x02, unsigned int)
 #define ESE_GET_PWR _IOR(0xE9, 0x03, unsigned int)
+#define ESE_CLEAR_GPIO _IOW(0xE9, 0x11, unsigned int)
 
 static const char kDevicePath[] = "/dev/pn81a";
 
@@ -60,6 +61,11 @@
   int fd;
 };
 
+int platform_toggle_bootloader(void *blob, int val) {
+  const struct PlatformHandle *handle = blob;
+  return ioctl(handle->fd, ESE_CLEAR_GPIO, val);
+}
+
 int platform_toggle_reset(void *blob, int val) {
   const struct PlatformHandle *handle = blob;
   /* 0=power and 1=no power in the kernel. */
@@ -171,6 +177,7 @@
     .toggle_reset = &platform_toggle_reset,
     .toggle_ven = NULL,
     .toggle_power_req = NULL,
+    .toggle_bootloader = &platform_toggle_bootloader,
     .wait = &platform_wait,
 };