summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2017-11-17 16:23:27 +0100
committerchrome-bot <chrome-bot@chromium.org>2017-12-06 14:28:56 -0800
commitd757f9bf3b4799b97c57db50ea56735a5b4bcdd1 (patch)
treee5f84b3b1f1027c740e8fb03cd629f8735921c40 /common
parent67c31eb10bc1ce6e559562aedd2f641de4243bb8 (diff)
downloadchrome-ec-d757f9bf3b4799b97c57db50ea56735a5b4bcdd1.tar.gz
eve_fp: update fingerprint architecture
split the common FP sensor code and use the updated private driver. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=b:69460856 TEST=do a finger capture on Eve EVT. CQ-DEPEND=CL:*520759 Change-Id: I8b46762218eed0773a4c49a02c2ee6c3966cfa60 Reviewed-on: https://chromium-review.googlesource.com/806166 Commit-Ready: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/fpsensor.c306
2 files changed, 307 insertions, 0 deletions
diff --git a/common/build.mk b/common/build.mk
index 70922f95fe..e48a7f2c35 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -122,6 +122,7 @@ common-$(CONFIG_WIRELESS)+=wireless.o
common-$(HAS_TASK_CHIPSET)+=chipset.o
common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o
common-$(CONFIG_CMD_MEM)+=memory_commands.o
+common-$(HAS_TASK_FPSENSOR)+=fpsensor.o
common-$(HAS_TASK_HOSTCMD)+=host_command.o ec_features.o
common-$(HAS_TASK_PDCMD)+=host_command_pd.o
common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o
diff --git a/common/fpsensor.c b/common/fpsensor.c
new file mode 100644
index 0000000000..50057ca3e6
--- /dev/null
+++ b/common/fpsensor.c
@@ -0,0 +1,306 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "atomic.h"
+#include "common.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "fpsensor.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "mkbp_event.h"
+#include "spi.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "watchdog.h"
+#ifdef HAVE_PRIVATE
+#define PRIV_HEADER(header) STRINGIFY(header)
+#include PRIV_HEADER(FP_SENSOR_PRIVATE)
+#else
+#define FP_SENSOR_IMAGE_SIZE 0
+#define FP_SENSOR_RES_X 0
+#define FP_SENSOR_RES_Y 0
+#endif
+
+/* Last acquired frame */
+static uint8_t fp_buffer[FP_SENSOR_IMAGE_SIZE];
+
+#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_FP, format, ## args)
+
+/* Events for the FPSENSOR task */
+#define TASK_EVENT_SENSOR_IRQ TASK_EVENT_CUSTOM(1)
+#define TASK_EVENT_UPDATE_CONFIG TASK_EVENT_CUSTOM(2)
+
+#define FP_MODE_ANY_DETECT_FINGER (FP_MODE_FINGER_DOWN | FP_MODE_FINGER_UP | \
+ FP_MODE_CAPTURE)
+#define FP_MODE_ANY_WAIT_IRQ (FP_MODE_FINGER_DOWN | FP_MODE_CAPTURE)
+
+/* Delay between 2 s of the sensor to detect finger removal */
+#define FINGER_POLLING_DELAY (100*MSEC)
+
+static uint32_t fp_events;
+static uint32_t sensor_mode;
+
+/* Interrupt line from the fingerprint sensor */
+void fps_event(enum gpio_signal signal)
+{
+ task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_SENSOR_IRQ, 0);
+}
+
+static void send_mkbp_event(uint32_t event)
+{
+ atomic_or(&fp_events, event);
+ mkbp_send_event(EC_MKBP_EVENT_FINGERPRINT);
+}
+
+void fp_task(void)
+{
+ int timeout_us = -1;
+
+ /* configure the SPI controller (also ensure that CS_N is high) */
+ gpio_config_module(MODULE_SPI_MASTER, 1);
+ spi_enable(CONFIG_SPI_FP_PORT, 1);
+
+#ifdef HAVE_PRIVATE
+ /* Reset and initialize the sensor IC */
+ fp_sensor_init();
+
+ while (1) {
+ uint32_t evt;
+ enum finger_state st = FINGER_NONE;
+
+ /* Wait for a sensor IRQ or a new mode configuration */
+ evt = task_wait_event(timeout_us);
+
+ if (evt & TASK_EVENT_UPDATE_CONFIG) {
+ gpio_disable_interrupt(GPIO_FPS_INT);
+ if (sensor_mode & FP_MODE_ANY_DETECT_FINGER)
+ /* wait for a finger on the sensor */
+ fp_sensor_configure_detect();
+ if (sensor_mode & FP_MODE_DEEPSLEEP)
+ /* Shutdown the sensor */
+ fp_sensor_low_power();
+ if (sensor_mode & FP_MODE_FINGER_UP)
+ /* Poll the sensor to detect finger removal */
+ timeout_us = FINGER_POLLING_DELAY;
+ else
+ timeout_us = -1;
+ if (sensor_mode & FP_MODE_ANY_WAIT_IRQ)
+ gpio_enable_interrupt(GPIO_FPS_INT);
+ } else if (evt & (TASK_EVENT_SENSOR_IRQ | TASK_EVENT_TIMER)) {
+ gpio_disable_interrupt(GPIO_FPS_INT);
+ if (sensor_mode & FP_MODE_ANY_DETECT_FINGER) {
+ st = fp_sensor_finger_status();
+ if (st == FINGER_PRESENT &&
+ sensor_mode & FP_MODE_FINGER_DOWN) {
+ CPRINTS("Finger!");
+ sensor_mode &= ~FP_MODE_FINGER_DOWN;
+ send_mkbp_event(EC_MKBP_FP_FINGER_DOWN);
+ }
+ if (st == FINGER_NONE &&
+ sensor_mode & FP_MODE_FINGER_UP) {
+ sensor_mode &= ~FP_MODE_FINGER_UP;
+ timeout_us = -1;
+ send_mkbp_event(EC_MKBP_FP_FINGER_UP);
+ }
+ }
+
+ if (st == FINGER_PRESENT &&
+ sensor_mode & FP_MODE_CAPTURE) {
+ int res = fp_sensor_acquire_image(fp_buffer);
+
+ if (!res) {
+ sensor_mode &= ~FP_MODE_CAPTURE;
+ send_mkbp_event(EC_MKBP_FP_IMAGE_READY);
+ }
+ }
+ if (sensor_mode & FP_MODE_ANY_WAIT_IRQ) {
+ fp_sensor_configure_detect();
+ gpio_enable_interrupt(GPIO_FPS_INT);
+ }
+ }
+ }
+#else /* !HAVE_PRIVATE */
+ while (1) {
+ uint32_t evt = task_wait_event(timeout_us);
+
+ send_mkbp_event(evt);
+ }
+#endif /* !HAVE_PRIVATE */
+}
+
+static int fp_get_next_event(uint8_t *out)
+{
+ uint32_t event_out = atomic_read_clear(&fp_events);
+
+ memcpy(out, &event_out, sizeof(event_out));
+
+ return sizeof(event_out);
+}
+DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_FINGERPRINT, fp_get_next_event);
+
+static int fp_command_passthru(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_passthru *params = args->params;
+ void *out = args->response;
+ int rc;
+ int ret = EC_RES_SUCCESS;
+
+ if (system_is_locked())
+ return EC_RES_ACCESS_DENIED;
+
+ if (params->len > args->params_size +
+ offsetof(struct ec_params_fp_passthru, data) ||
+ params->len > args->response_max)
+ return EC_RES_INVALID_PARAM;
+
+ rc = spi_transaction_async(&spi_devices[0], params->data,
+ params->len, out, SPI_READBACK_ALL);
+ if (params->flags & EC_FP_FLAG_NOT_COMPLETE)
+ rc |= spi_transaction_wait(&spi_devices[0]);
+ else
+ rc |= spi_transaction_flush(&spi_devices[0]);
+
+ if (rc == EC_ERROR_TIMEOUT)
+ ret = EC_RES_TIMEOUT;
+ else if (rc)
+ ret = EC_RES_ERROR;
+
+ args->response_size = params->len;
+ return ret;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_PASSTHRU, fp_command_passthru, EC_VER_MASK(0));
+
+static int fp_command_sensor_config(struct host_cmd_handler_args *args)
+{
+ /* const struct ec_params_fp_sensor_config *p = args->params; */
+
+ return EC_RES_UNAVAILABLE;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_SENSOR_CONFIG, fp_command_sensor_config,
+ EC_VER_MASK(0));
+
+static int fp_command_mode(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_mode *p = args->params;
+ struct ec_response_fp_mode *r = args->response;
+
+ if (!(p->mode & FP_MODE_DONT_CHANGE)) {
+ sensor_mode = p->mode;
+ task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG, 0);
+ }
+
+ r->mode = sensor_mode;
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_MODE, fp_command_mode, EC_VER_MASK(0));
+
+static int fp_command_info(struct host_cmd_handler_args *args)
+{
+ struct ec_response_fp_info *r = args->response;
+
+#ifdef HAVE_PRIVATE
+ if (fp_sensor_get_info(r) < 0)
+#endif
+ return EC_RES_UNAVAILABLE;
+
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_INFO, fp_command_info, EC_VER_MASK(0));
+
+static int fp_command_frame(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_frame *params = args->params;
+ void *out = args->response;
+
+ if (params->offset + params->size > sizeof(fp_buffer) ||
+ params->size > args->response_max)
+ return EC_RES_INVALID_PARAM;
+
+ memcpy(out, fp_buffer + params->offset, params->size);
+
+ args->response_size = params->size;
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_FRAME, fp_command_frame, EC_VER_MASK(0));
+
+#ifdef CONFIG_CMD_FPSENSOR_DEBUG
+/* --- Debug console commands --- */
+
+/* raw image offset inside the acquired frame */
+#ifndef FP_SENSOR_IMAGE_OFFSET
+#define FP_SENSOR_IMAGE_OFFSET 0
+#endif
+
+/*
+ * Send the current Fingerprint buffer to the host
+ * it is formatted as an 8-bpp PGM ASCII file.
+ *
+ * In addition, it prepends a short Z-Modem download signature,
+ * which triggers automatically your preferred viewer if you configure it
+ * properly in "File transfer protocols" in the Minicom options menu.
+ * (as triggered by Ctrl-A O)
+ * +--------------------------------------------------------------------------+
+ * | Name Program Name U/D FullScr IO-Red. Multi |
+ * | A zmodem /usr/bin/sz -vv -b Y U N Y Y |
+ * [...]
+ * | L pgm /usr/bin/display_pgm N D N Y N |
+ * | M Zmodem download string activates... L |
+ *
+ * My /usr/bin/display_pgm looks like this:
+ * #!/bin/sh
+ * TMPF=$(mktemp)
+ * ascii-xfr -rdv ${TMPF}
+ * display ${TMPF}
+ */
+static void upload_pgm_image(uint8_t *frame)
+{
+ int x, y;
+ uint8_t *ptr = frame;
+
+ /* fake Z-modem ZRQINIT signature */
+ ccprintf("#IGNORE for ZModem\r**\030B00");
+ msleep(100); /* let the download program start */
+ /* Print 8-bpp PGM ASCII header */
+ ccprintf("P2\n%d %d\n255\n", FP_SENSOR_RES_X, FP_SENSOR_RES_Y);
+
+ for (y = 0; y < FP_SENSOR_RES_Y; y++) {
+ watchdog_reload();
+ for (x = 0; x < FP_SENSOR_RES_X; x++, ptr++)
+ ccprintf("%d ", *ptr);
+ ccputs("\n");
+ cflush();
+ }
+
+ ccprintf("\x04"); /* End Of Transmission */
+}
+
+int command_fptest(int argc, char **argv)
+{
+ int tries = 200;
+
+ ccprintf("Waiting for finger ...\n");
+ sensor_mode = FP_MODE_CAPTURE;
+ task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG, 0);
+
+ while (tries--) {
+ if (!(sensor_mode & FP_MODE_CAPTURE)) {
+ ccprintf("done\n");
+ upload_pgm_image(fp_buffer + FP_SENSOR_IMAGE_OFFSET);
+ return 0;
+ }
+ usleep(100 * MSEC);
+ }
+
+ return EC_ERROR_TIMEOUT;
+}
+DECLARE_CONSOLE_COMMAND(fptest, command_fptest, "", "");
+
+#endif /* CONFIG_CMD_FPSENSOR_DEBUG */