summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/eve_fp/board.c33
-rw-r--r--driver/fpc1140.c139
-rw-r--r--include/ec_commands.h73
-rw-r--r--util/ectool.c113
4 files changed, 324 insertions, 34 deletions
diff --git a/board/eve_fp/board.c b/board/eve_fp/board.c
index 94ae0daade..21b1c2668b 100644
--- a/board/eve_fp/board.c
+++ b/board/eve_fp/board.c
@@ -7,7 +7,6 @@
#include "console.h"
#include "gpio.h"
#include "hooks.h"
-#include "host_command.h"
#include "spi.h"
#include "system.h"
#include "task.h"
@@ -57,35 +56,3 @@ static void board_init(void)
hook_call_deferred(&ap_deferred_data, 0);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
-
-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));
diff --git a/driver/fpc1140.c b/driver/fpc1140.c
index edeeb6bd36..05094eb713 100644
--- a/driver/fpc1140.c
+++ b/driver/fpc1140.c
@@ -9,11 +9,18 @@
#include "ec_commands.h"
#include "endian.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"
+#ifdef HAVE_PRIVATE
+#include "fpc1145_private.h"
+
+uint8_t fp_buffer[FPC_IMAGE_SIZE];
+#endif
#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args)
#define CPRINTS(format, args...) cprints(CC_FP, format, ## args)
@@ -36,6 +43,13 @@ enum fpc_cmd {
#endif
static uint32_t fp_events;
+static uint32_t sensor_mode;
+
+/* Opaque sensor configuration registers settings */
+static union {
+ struct ec_params_fp_sensor_config sensor_config;
+ uint8_t data[0x220];
+} u;
static int fpc_send_cmd(const uint8_t cmd)
{
@@ -86,6 +100,9 @@ static uint8_t fpc_read_int(void)
/* Reset and initialize the sensor IC */
static int fpc_init(void)
{
+#ifdef HAVE_PRIVATE
+ memcpy(&u.sensor_config, &fpc1145_config, fpc1145_config_size);
+#endif
/* 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);
@@ -149,3 +166,125 @@ static int fp_get_next_event(uint8_t *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;
+ int i, index;
+ unsigned limit = args->params_size
+ - offsetof(struct ec_params_fp_sensor_config, data);
+
+ /* Validate the content size */
+ if (p->count > EC_FP_SENSOR_CONFIG_MAX_REGS ||
+ args->params_size > sizeof(u))
+ return EC_RES_INVALID_PARAM;
+ for (i = 0, index = 0; i < p->count; i++) {
+ if (index + p->len[i] > limit)
+ return EC_RES_INVALID_PARAM;
+ index += p->len[i];
+ }
+
+ memcpy(&u.sensor_config, p, args->params_size);
+
+ return EC_RES_SUCCESS;
+}
+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;
+ if (p->mode & FP_MODE_DEEPSLEEP) {
+ /* TBD fpc_send_cmd(FPC_CMD_DEEPSLEEP) */;
+ } else {
+ if (p->mode & FP_MODE_FINGER_DOWN)
+ /* TBD: fp_prepare_capture()*/;
+ if (p->mode & FP_MODE_FINGER_UP)
+ /* TBD */;
+ }
+ }
+
+ 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;
+ int rc;
+ const uint8_t cmd = FPC_CMD_HW_ID;
+ uint16_t id;
+ int ret = EC_RES_SUCCESS;
+
+#ifdef HAVE_PRIVATE
+ memcpy(r, &fpc1145_info, sizeof(*r));
+#else
+ return EC_RES_UNAVAILABLE;
+#endif
+ rc = spi_transaction(SPI_FPC_DEVICE, &cmd, 1, (void *)&id, sizeof(id));
+ if (rc)
+ return EC_RES_ERROR;
+ r->model_id = be16toh(id);
+
+ args->response_size = sizeof(*r);
+ return ret;
+}
+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)
+{
+#ifdef HAVE_PRIVATE
+ 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;
+#else
+ return EC_RES_UNAVAILABLE;
+#endif
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_FRAME, fp_command_frame, EC_VER_MASK(0));
diff --git a/include/ec_commands.h b/include/ec_commands.h
index abc71517bd..4ef579af65 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2881,6 +2881,12 @@ struct __ec_align2 ec_response_keyboard_factory_test {
uint16_t shorted; /* Keyboard pins are shorted */
};
+/* Fingerprint events in 'fp_events' for EC_MKBP_EVENT_FINGERPRINT */
+#define EC_MKBP_FP_RAW_EVENT(fp_events) ((fp_events) & 0x00FFFFFF)
+#define EC_MKBP_FP_FINGER_DOWN (1 << 29)
+#define EC_MKBP_FP_FINGER_UP (1 << 30)
+#define EC_MKBP_FP_IMAGE_READY (1 << 31)
+
/*****************************************************************************/
/* Temperature sensor commands */
@@ -4104,7 +4110,7 @@ struct __ec_align4 ec_params_rwsig_action {
/*****************************************************************************/
/* Fingerprint MCU commands: range 0x0400-0x040x */
-/* Fingerprint SPI sensor passthru command */
+/* Fingerprint SPI sensor passthru command: prototyping ONLY */
#define EC_CMD_FP_PASSTHRU 0x0400
#define EC_FP_FLAG_NOT_COMPLETE 0x1
@@ -4115,6 +4121,71 @@ struct __ec_align2 ec_params_fp_passthru {
uint8_t data[]; /* Data to send */
};
+/* Fingerprint sensor configuration command: prototyping ONLY */
+#define EC_CMD_FP_SENSOR_CONFIG 0x0401
+
+#define EC_FP_SENSOR_CONFIG_MAX_REGS 16
+
+struct __ec_align2 ec_params_fp_sensor_config {
+ uint8_t count; /* Number of setup registers */
+ /*
+ * the value to send to each of the 'count' setup registers
+ * is stored in the 'data' array for 'len' bytes just after
+ * the previous one.
+ */
+ uint8_t len[EC_FP_SENSOR_CONFIG_MAX_REGS];
+ uint8_t data[];
+};
+
+/* Configure the Fingerprint MCU behavior */
+#define EC_CMD_FP_MODE 0x0402
+
+/* Put the sensor in its lowest power mode */
+#define FP_MODE_DEEPSLEEP (1<<0)
+/* Wait to see a finger on the sensor */
+#define FP_MODE_FINGER_DOWN (1<<1)
+/* Poll until the finger has left the sensor */
+#define FP_MODE_FINGER_UP (1<<2)
+/* Capture the current finger image */
+#define FP_MODE_CAPTURE (1<<3)
+/* special value: don't change anything just read back current mode */
+#define FP_MODE_DONT_CHANGE (1<<31)
+
+struct __ec_align4 ec_params_fp_mode {
+ uint32_t mode; /* as defined by FP_MODE_ constants */
+ /* TBD */
+};
+
+struct __ec_align4 ec_response_fp_mode {
+ uint32_t mode; /* as defined by FP_MODE_ constants */
+ /* TBD */
+};
+
+/* Retrieve Fingerprint sensor information */
+#define EC_CMD_FP_INFO 0x0403
+
+struct __ec_align2 ec_response_fp_info {
+ /* Sensor identification */
+ uint32_t vendor_id;
+ uint32_t product_id;
+ uint32_t model_id;
+ uint32_t version;
+ /* Image frame characteristics */
+ uint32_t frame_size;
+ uint32_t pixel_format; /* using V4L2_PIX_FMT_ */
+ uint16_t width;
+ uint16_t height;
+ uint16_t bpp;
+};
+
+/* Get the last captured finger frame: TODO: will be AES-encrypted */
+#define EC_CMD_FP_FRAME 0x0404
+
+struct __ec_align4 ec_params_fp_frame {
+ uint32_t offset;
+ uint32_t size;
+};
+
/*****************************************************************************/
/*
* Reserve a range of host commands for board-specific, experimental, or
diff --git a/util/ectool.c b/util/ectool.c
index 6a8441f172..039ddcb9d9 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -112,6 +112,12 @@ const char help_str[] =
" Reads from EC flash to a file\n"
" flashwrite <offset> <infile>\n"
" Writes to EC flash from a file\n"
+ " fpframe\n"
+ " Retrieve the finger image as a PGM image\n"
+ " fpinfo\n"
+ " Prints information about the Fingerprint sensor\n"
+ " fpmode [capture|deepsleep|fingerdown|fingerup]\n"
+ " Configure/Read the fingerprint sensor current mode\n"
" forcelidopen <enable>\n"
" Forces the lid switch to open position\n"
" gpioget <GPIO name>\n"
@@ -1059,6 +1065,110 @@ int cmd_rwsig_action(int argc, char *argv[])
return ec_command(EC_CMD_RWSIG_ACTION, 0, &req, sizeof(req), NULL, 0);
}
+int cmd_fp_mode(int argc, char *argv[])
+{
+ struct ec_params_fp_mode p;
+ struct ec_response_fp_mode r;
+ uint32_t mode = 0;
+ int i, rv;
+
+ if (argc == 1)
+ mode = FP_MODE_DONT_CHANGE;
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "deepsleep", 9))
+ mode |= FP_MODE_DEEPSLEEP;
+ else if (!strncmp(argv[i], "fingerdown", 10))
+ mode |= FP_MODE_FINGER_DOWN;
+ else if (!strncmp(argv[i], "fingerup", 8))
+ mode |= FP_MODE_FINGER_UP;
+ else if (!strncmp(argv[i], "capture", 7))
+ mode |= FP_MODE_CAPTURE;
+ }
+
+ p.mode = mode;
+ rv = ec_command(EC_CMD_FP_MODE, 0, &p, sizeof(p), &r, sizeof(r));
+ if (rv < 0)
+ return rv;
+
+ printf("FP mode: (0x%x) ", r.mode);
+ if (r.mode & FP_MODE_DEEPSLEEP)
+ printf("deepsleep ");
+ if (r.mode & FP_MODE_FINGER_DOWN)
+ printf("finger-down ");
+ if (r.mode & FP_MODE_FINGER_UP)
+ printf("finger-up ");
+ if (r.mode & FP_MODE_CAPTURE)
+ printf("capture ");
+ printf("\n");
+ return rv;
+}
+
+int cmd_fp_info(int argc, char *argv[])
+{
+ struct ec_response_fp_info r;
+ int rv;
+
+ rv = ec_command(EC_CMD_FP_INFO, 0, NULL, 0, &r, sizeof(r));
+ if (rv < 0)
+ return rv;
+
+ printf("Fingerprint sensor: vendor %x product %x model %x version %x\n",
+ r.vendor_id, r.product_id, r.model_id, r.version);
+ printf("Image: size %dx%d %d bpp\n", r.width, r.height, r.bpp);
+
+ return 0;
+}
+
+int cmd_fp_frame(int argc, char *argv[])
+{
+ struct ec_response_fp_info r;
+ struct ec_params_fp_frame p;
+ int rv = 0;
+ size_t stride, size;
+ uint8_t *buffer8 = ec_inbuf;
+
+ rv = ec_command(EC_CMD_FP_INFO, 0, NULL, 0, &r, sizeof(r));
+ if (rv < 0)
+ return rv;
+
+ stride = (size_t)r.width * r.bpp/8;
+ if (stride > ec_max_insize) {
+ fprintf(stderr, "Not implemented for line size %zu B "
+ "(%u pixels) > EC transfer size %d\n",
+ stride, r.width, ec_max_insize);
+ return -1;
+ }
+ if (r.bpp != 8) {
+ fprintf(stderr, "Not implemented for BPP = %d != 8\n", r.bpp);
+ return -1;
+ }
+
+ size = stride * r.height;
+
+ /* Print 8-bpp PGM ASCII header */
+ printf("P2\n%d %d\n%d\n", r.width, r.height, (1 << r.bpp) - 1);
+
+ p.offset = 0;
+ p.size = stride;
+ while (size) {
+ int x;
+
+ rv = ec_command(EC_CMD_FP_FRAME, 0, &p, sizeof(p),
+ ec_inbuf, stride);
+ if (rv < 0)
+ return rv;
+ p.offset += stride;
+ size -= stride;
+
+ for (x = 0; x < stride; x++)
+ printf("%d ", buffer8[x]);
+ printf("\n");
+ }
+ printf("# END OF FILE\n");
+
+ return 0;
+}
+
/**
* determine if in GFU mode or not.
*
@@ -7064,6 +7174,9 @@ const struct command commands[] = {
{"flashspiinfo", cmd_flash_spi_info},
{"flashpd", cmd_flash_pd},
{"forcelidopen", cmd_force_lid_open},
+ {"fpframe", cmd_fp_frame},
+ {"fpinfo", cmd_fp_info},
+ {"fpmode", cmd_fp_mode},
{"gpioget", cmd_gpio_get},
{"gpioset", cmd_gpio_set},
{"hangdetect", cmd_hang_detect},