diff options
-rw-r--r-- | board/eve_fp/board.c | 33 | ||||
-rw-r--r-- | driver/fpc1140.c | 139 | ||||
-rw-r--r-- | include/ec_commands.h | 73 | ||||
-rw-r--r-- | util/ectool.c | 113 |
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}, |