diff options
Diffstat (limited to 'common/fpsensor/fpsensor.c')
-rw-r--r-- | common/fpsensor/fpsensor.c | 887 |
1 files changed, 0 insertions, 887 deletions
diff --git a/common/fpsensor/fpsensor.c b/common/fpsensor/fpsensor.c deleted file mode 100644 index 25010c7db8..0000000000 --- a/common/fpsensor/fpsensor.c +++ /dev/null @@ -1,887 +0,0 @@ -/* 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 "clock.h" -#include "common.h" -#include "console.h" -#include "cryptoc/util.h" -#include "ec_commands.h" -#include "fpsensor.h" -#include "fpsensor_crypto.h" -#include "fpsensor_detect.h" -#include "fpsensor_private.h" -#include "fpsensor_state.h" -#include "gpio.h" -#include "host_command.h" -#include "link_defs.h" -#include "mkbp_event.h" -#include "overflow.h" -#include "spi.h" -#include "system.h" -#include "task.h" -#include "trng.h" -#include "util.h" -#include "watchdog.h" - -#if !defined(CONFIG_RNG) -#error "fpsensor requires RNG" -#endif - -#if defined(SECTION_IS_RO) -#error "fpsensor code should not be in RO image." -#endif - -/* Ready to encrypt a template. */ -static timestamp_t encryption_deadline; - -/* raw image offset inside the acquired frame */ -#ifndef FP_SENSOR_IMAGE_OFFSET -#define FP_SENSOR_IMAGE_OFFSET 0 -#endif - -#define FP_MODE_ANY_CAPTURE (FP_MODE_CAPTURE | FP_MODE_ENROLL_IMAGE | \ - FP_MODE_MATCH) -#define FP_MODE_ANY_DETECT_FINGER (FP_MODE_FINGER_DOWN | FP_MODE_FINGER_UP | \ - FP_MODE_ANY_CAPTURE) -#define FP_MODE_ANY_WAIT_IRQ (FP_MODE_FINGER_DOWN | FP_MODE_ANY_CAPTURE) - -/* Delay between 2 s of the sensor to detect finger removal */ -#define FINGER_POLLING_DELAY (100*MSEC) - -/* Timing statistics. */ -static uint32_t capture_time_us; -static uint32_t matching_time_us; -static uint32_t overall_time_us; -static timestamp_t overall_t0; -static uint8_t timestamps_invalid; - -BUILD_ASSERT(sizeof(struct ec_fp_template_encryption_metadata) % 4 == 0); - -/* Interrupt line from the fingerprint sensor */ -void fps_event(enum gpio_signal signal) -{ - task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_SENSOR_IRQ); -} - -static void send_mkbp_event(uint32_t event) -{ - atomic_or(&fp_events, event); - mkbp_send_event(EC_MKBP_EVENT_FINGERPRINT); -} - -static inline int is_raw_capture(uint32_t mode) -{ - int capture_type = FP_CAPTURE_TYPE(mode); - - return (capture_type == FP_CAPTURE_VENDOR_FORMAT - || capture_type == FP_CAPTURE_QUALITY_TEST); -} - -#ifdef HAVE_FP_PRIVATE_DRIVER -static inline int is_test_capture(uint32_t mode) -{ - int capture_type = FP_CAPTURE_TYPE(mode); - - return (mode & FP_MODE_CAPTURE) - && (capture_type == FP_CAPTURE_PATTERN0 - || capture_type == FP_CAPTURE_PATTERN1 - || capture_type == FP_CAPTURE_RESET_TEST); -} - -/* - * contains the bit FP_MODE_ENROLL_SESSION if a finger enrollment is on-going. - * It is used to detect the ENROLL_SESSION transition when sensor_mode is - * updated by the host. - */ -static uint32_t enroll_session; - -static uint32_t fp_process_enroll(void) -{ - int percent = 0; - int res; - - if (template_newly_enrolled != FP_NO_SUCH_TEMPLATE) - CPRINTS("Warning: previously enrolled template has not been " - "read yet."); - - /* begin/continue enrollment */ - CPRINTS("[%d]Enrolling ...", templ_valid); - res = fp_finger_enroll(fp_buffer, &percent); - CPRINTS("[%d]Enroll =>%d (%d%%)", templ_valid, res, percent); - if (res < 0) - return EC_MKBP_FP_ENROLL - | EC_MKBP_FP_ERRCODE(EC_MKBP_FP_ERR_ENROLL_INTERNAL); - templ_dirty |= BIT(templ_valid); - if (percent == 100) { - res = fp_enrollment_finish(fp_template[templ_valid]); - if (res) { - res = EC_MKBP_FP_ERR_ENROLL_INTERNAL; - } else { - template_newly_enrolled = templ_valid; - fp_enable_positive_match_secret(templ_valid, - &positive_match_secret_state); - templ_valid++; - } - sensor_mode &= ~FP_MODE_ENROLL_SESSION; - enroll_session &= ~FP_MODE_ENROLL_SESSION; - } - return EC_MKBP_FP_ENROLL | EC_MKBP_FP_ERRCODE(res) - | (percent << EC_MKBP_FP_ENROLL_PROGRESS_OFFSET); -} - -static bool fp_match_success(int match_result) -{ - if (match_result == EC_MKBP_FP_ERR_MATCH_YES || - match_result == EC_MKBP_FP_ERR_MATCH_YES_UPDATED || - match_result == EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED) { - return true; - } - - return false; -} - -static uint32_t fp_process_match(void) -{ - timestamp_t t0 = get_time(); - int res = -1; - uint32_t updated = 0; - int32_t fgr = FP_NO_SUCH_TEMPLATE; - - /* match finger against current templates */ - fp_disable_positive_match_secret(&positive_match_secret_state); - CPRINTS("Matching/%d ...", templ_valid); - if (templ_valid) { - res = fp_finger_match(fp_template[0], templ_valid, fp_buffer, - &fgr, &updated); - CPRINTS("Match =>%d (finger %d)", res, fgr); - - if (fp_match_success(res)) { - /* - * Match succeded! Let's check if template number - * is valid. If it is not valid, overwrite result - * with EC_MKBP_FP_ERR_MATCH_NO_INTERNAL. - */ - if (fgr >= 0 && fgr < FP_MAX_FINGER_COUNT) { - fp_enable_positive_match_secret(fgr, - &positive_match_secret_state); - } else { - res = EC_MKBP_FP_ERR_MATCH_NO_INTERNAL; - } - } else if (res < 0) { - /* - * Negative result means that there is a problem with - * code responsible for matching. Overwrite it with - * MATCH_NO_INTERNAL to let upper layers know what - * happened. - */ - res = EC_MKBP_FP_ERR_MATCH_NO_INTERNAL; - } - - if (res == EC_MKBP_FP_ERR_MATCH_YES_UPDATED) - templ_dirty |= updated; - } else { - CPRINTS("No enrolled templates"); - res = EC_MKBP_FP_ERR_MATCH_NO_TEMPLATES; - } - - if (!fp_match_success(res)) - timestamps_invalid |= FPSTATS_MATCHING_INV; - - matching_time_us = time_since32(t0); - return EC_MKBP_FP_MATCH | EC_MKBP_FP_ERRCODE(res) - | ((fgr << EC_MKBP_FP_MATCH_IDX_OFFSET) & EC_MKBP_FP_MATCH_IDX_MASK); -} - -static void fp_process_finger(void) -{ - timestamp_t t0 = get_time(); - int res = fp_sensor_acquire_image_with_mode(fp_buffer, - FP_CAPTURE_TYPE(sensor_mode)); - capture_time_us = time_since32(t0); - if (!res) { - uint32_t evt = EC_MKBP_FP_IMAGE_READY; - - /* Clean up SPI before clocking up to avoid hang on the dsb - * in dma_go. Ignore the return value to let the WDT reboot - * the MCU (and avoid getting trapped in the loop). - * b/112781659 */ - res = spi_transaction_flush(&spi_devices[0]); - if (res) - CPRINTS("Failed to flush SPI: 0x%x", res); - /* we need CPU power to do the computations */ - clock_enable_module(MODULE_FAST_CPU, 1); - - if (sensor_mode & FP_MODE_ENROLL_IMAGE) - evt = fp_process_enroll(); - else if (sensor_mode & FP_MODE_MATCH) - evt = fp_process_match(); - - sensor_mode &= ~FP_MODE_ANY_CAPTURE; - overall_time_us = time_since32(overall_t0); - send_mkbp_event(evt); - - /* go back to lower power mode */ - clock_enable_module(MODULE_FAST_CPU, 0); - } else { - timestamps_invalid |= FPSTATS_CAPTURE_INV; - } -} -#endif /* HAVE_FP_PRIVATE_DRIVER */ - -void fp_task(void) -{ - int timeout_us = -1; - - CPRINTS("FP_SENSOR_SEL: %s", - fp_sensor_type_to_str(get_fp_sensor_type())); - -#ifdef HAVE_FP_PRIVATE_DRIVER - /* 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) { - uint32_t mode = sensor_mode; - - gpio_disable_interrupt(GPIO_FPS_INT); - if ((mode ^ enroll_session) & FP_MODE_ENROLL_SESSION) { - if (mode & FP_MODE_ENROLL_SESSION) { - if (fp_enrollment_begin()) - sensor_mode &= - ~FP_MODE_ENROLL_SESSION; - } else { - fp_enrollment_finish(NULL); - } - enroll_session = - sensor_mode & FP_MODE_ENROLL_SESSION; - } - if (is_test_capture(mode)) { - fp_sensor_acquire_image_with_mode(fp_buffer, - FP_CAPTURE_TYPE(mode)); - sensor_mode &= ~FP_MODE_CAPTURE; - send_mkbp_event(EC_MKBP_FP_IMAGE_READY); - continue; - } else 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 (mode & FP_MODE_ANY_WAIT_IRQ) { - gpio_enable_interrupt(GPIO_FPS_INT); - } else if (mode & FP_MODE_RESET_SENSOR) { - fp_reset_and_clear_context(); - sensor_mode &= ~FP_MODE_RESET_SENSOR; - } else if (mode & FP_MODE_SENSOR_MAINTENANCE) { - fp_maintenance(); - sensor_mode &= ~FP_MODE_SENSOR_MAINTENANCE; - } else { - fp_sensor_low_power(); - } - } else if (evt & (TASK_EVENT_SENSOR_IRQ | TASK_EVENT_TIMER)) { - overall_t0 = get_time(); - timestamps_invalid = 0; - 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_ANY_CAPTURE) - fp_process_finger(); - - if (sensor_mode & FP_MODE_ANY_WAIT_IRQ) { - fp_sensor_configure_detect(); - gpio_enable_interrupt(GPIO_FPS_INT); - } else { - fp_sensor_low_power(); - } - } - } -#else /* !HAVE_FP_PRIVATE_DRIVER */ - while (1) { - uint32_t evt = task_wait_event(timeout_us); - - send_mkbp_event(evt); - } -#endif /* !HAVE_FP_PRIVATE_DRIVER */ -} - -static enum ec_status 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 enum ec_status fp_command_info(struct host_cmd_handler_args *args) -{ - struct ec_response_fp_info *r = args->response; - -#ifdef HAVE_FP_PRIVATE_DRIVER - if (fp_sensor_get_info(r) < 0) -#endif - return EC_RES_UNAVAILABLE; - - r->template_size = FP_ALGORITHM_ENCRYPTED_TEMPLATE_SIZE; - r->template_max = FP_MAX_FINGER_COUNT; - r->template_valid = templ_valid; - r->template_dirty = templ_dirty; - r->template_version = FP_TEMPLATE_FORMAT_VERSION; - - /* V1 is identical to V0 with more information appended */ - args->response_size = args->version ? sizeof(*r) : - sizeof(struct ec_response_fp_info_v0); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_FP_INFO, fp_command_info, - EC_VER_MASK(0) | EC_VER_MASK(1)); - -BUILD_ASSERT(FP_CONTEXT_NONCE_BYTES == 12); - -int validate_fp_buffer_offset(const uint32_t buffer_size, const uint32_t offset, - const uint32_t size) -{ - uint32_t bytes_requested; - - if (check_add_overflow(size, offset, &bytes_requested)) - return EC_ERROR_OVERFLOW; - - if (bytes_requested > buffer_size) - return EC_ERROR_INVAL; - - return EC_SUCCESS; -} - -static enum ec_status fp_command_frame(struct host_cmd_handler_args *args) -{ - const struct ec_params_fp_frame *params = args->params; - void *out = args->response; - uint32_t idx = FP_FRAME_GET_BUFFER_INDEX(params->offset); - uint32_t offset = params->offset & FP_FRAME_OFFSET_MASK; - uint32_t size = params->size; - uint32_t fgr; - uint8_t key[SBP_ENC_KEY_LEN]; - struct ec_fp_template_encryption_metadata *enc_info; - int ret; - - if (size > args->response_max) - return EC_RES_INVALID_PARAM; - - if (idx == FP_FRAME_INDEX_RAW_IMAGE) { - /* The host requested a frame. */ - if (system_is_locked()) - return EC_RES_ACCESS_DENIED; - if (!is_raw_capture(sensor_mode)) - offset += FP_SENSOR_IMAGE_OFFSET; - - ret = validate_fp_buffer_offset(sizeof(fp_buffer), offset, - size); - if (ret != EC_SUCCESS) - return EC_RES_INVALID_PARAM; - - memcpy(out, fp_buffer + offset, size); - args->response_size = size; - return EC_RES_SUCCESS; - } - - /* The host requested a template. */ - - /* Templates are numbered from 1 in this host request. */ - fgr = idx - FP_FRAME_INDEX_TEMPLATE; - - if (fgr >= FP_MAX_FINGER_COUNT) - return EC_RES_INVALID_PARAM; - if (fgr >= templ_valid) - return EC_RES_UNAVAILABLE; - ret = validate_fp_buffer_offset(sizeof(fp_enc_buffer), offset, size); - if (ret != EC_SUCCESS) - return EC_RES_INVALID_PARAM; - - if (!offset) { - /* Host has requested the first chunk, do the encryption. */ - timestamp_t now = get_time(); - /* Encrypted template is after the metadata. */ - uint8_t *encrypted_template = fp_enc_buffer + sizeof(*enc_info); - /* Positive match salt is after the template. */ - uint8_t *positive_match_salt = - encrypted_template + sizeof(fp_template[0]); - size_t encrypted_blob_size = sizeof(fp_template[0]) + - sizeof(fp_positive_match_salt[0]); - - /* b/114160734: Not more than 1 encrypted message per second. */ - if (!timestamp_expired(encryption_deadline, &now)) - return EC_RES_BUSY; - encryption_deadline.val = now.val + (1 * SECOND); - - memset(fp_enc_buffer, 0, sizeof(fp_enc_buffer)); - /* - * The beginning of the buffer contains nonce, encryption_salt - * and tag. - */ - enc_info = (void *)fp_enc_buffer; - enc_info->struct_version = FP_TEMPLATE_FORMAT_VERSION; - init_trng(); - rand_bytes(enc_info->nonce, FP_CONTEXT_NONCE_BYTES); - rand_bytes(enc_info->encryption_salt, - FP_CONTEXT_ENCRYPTION_SALT_BYTES); - exit_trng(); - - if (fgr == template_newly_enrolled) { - /* - * Newly enrolled templates need new positive match - * salt, new positive match secret and new validation - * value. - */ - template_newly_enrolled = FP_NO_SUCH_TEMPLATE; - init_trng(); - rand_bytes(fp_positive_match_salt[fgr], - FP_POSITIVE_MATCH_SALT_BYTES); - exit_trng(); - } - - ret = derive_encryption_key(key, enc_info->encryption_salt); - if (ret != EC_SUCCESS) { - CPRINTS("fgr%d: Failed to derive key", fgr); - return EC_RES_UNAVAILABLE; - } - - /* - * Copy the payload to |fp_enc_buffer| where it will be - * encrypted in-place. - */ - memcpy(encrypted_template, fp_template[fgr], - sizeof(fp_template[0])); - memcpy(positive_match_salt, fp_positive_match_salt[fgr], - sizeof(fp_positive_match_salt[0])); - - /* Encrypt the secret blob in-place. */ - ret = aes_gcm_encrypt(key, SBP_ENC_KEY_LEN, encrypted_template, - encrypted_template, - encrypted_blob_size, - enc_info->nonce, FP_CONTEXT_NONCE_BYTES, - enc_info->tag, FP_CONTEXT_TAG_BYTES); - always_memset(key, 0, sizeof(key)); - if (ret != EC_SUCCESS) { - CPRINTS("fgr%d: Failed to encrypt template", fgr); - return EC_RES_UNAVAILABLE; - } - templ_dirty &= ~BIT(fgr); - } - memcpy(out, fp_enc_buffer + offset, size); - args->response_size = size; - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_FP_FRAME, fp_command_frame, EC_VER_MASK(0)); - -static enum ec_status fp_command_stats(struct host_cmd_handler_args *args) -{ - struct ec_response_fp_stats *r = args->response; - - r->capture_time_us = capture_time_us; - r->matching_time_us = matching_time_us; - r->overall_time_us = overall_time_us; - r->overall_t0.lo = overall_t0.le.lo; - r->overall_t0.hi = overall_t0.le.hi; - r->timestamps_invalid = timestamps_invalid; - /* - * Note that this is set to FP_NO_SUCH_TEMPLATE when positive match - * secret is read/disabled, and we are not using this field in biod. - */ - r->template_matched = positive_match_secret_state.template_matched; - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_FP_STATS, fp_command_stats, EC_VER_MASK(0)); - -static bool template_needs_validation_value( - struct ec_fp_template_encryption_metadata *enc_info) -{ - return enc_info->struct_version == 3 - && FP_TEMPLATE_FORMAT_VERSION == 4; -} - -static int validate_template_format( - struct ec_fp_template_encryption_metadata *enc_info) -{ - if (template_needs_validation_value(enc_info)) - /* The host requested migration to v4. */ - return EC_RES_SUCCESS; - - if (enc_info->struct_version != FP_TEMPLATE_FORMAT_VERSION) { - CPRINTS("Invalid template format %d", enc_info->struct_version); - return EC_RES_INVALID_PARAM; - } - return EC_RES_SUCCESS; -} - -static enum ec_status fp_command_template(struct host_cmd_handler_args *args) -{ - const struct ec_params_fp_template *params = args->params; - uint32_t size = params->size & ~FP_TEMPLATE_COMMIT; - int xfer_complete = params->size & FP_TEMPLATE_COMMIT; - uint32_t offset = params->offset; - uint32_t idx = templ_valid; - uint8_t key[SBP_ENC_KEY_LEN]; - struct ec_fp_template_encryption_metadata *enc_info; - int ret; - - /* Can we store one more template ? */ - if (idx >= FP_MAX_FINGER_COUNT) - return EC_RES_OVERFLOW; - - if (args->params_size != - size + offsetof(struct ec_params_fp_template, data)) - return EC_RES_INVALID_PARAM; - ret = validate_fp_buffer_offset(sizeof(fp_enc_buffer), offset, size); - if (ret != EC_SUCCESS) - return EC_RES_INVALID_PARAM; - - memcpy(&fp_enc_buffer[offset], params->data, size); - - if (xfer_complete) { - /* Encrypted template is after the metadata. */ - uint8_t *encrypted_template = fp_enc_buffer + sizeof(*enc_info); - /* Positive match salt is after the template. */ - uint8_t *positive_match_salt = - encrypted_template + sizeof(fp_template[0]); - size_t encrypted_blob_size; - - /* - * The complete encrypted template has been received, start - * decryption. - */ - fp_clear_finger_context(idx); - /* - * The beginning of the buffer contains nonce, encryption_salt - * and tag. - */ - enc_info = (void *)fp_enc_buffer; - ret = validate_template_format(enc_info); - if (ret != EC_RES_SUCCESS) { - CPRINTS("fgr%d: Template format not supported", idx); - return EC_RES_INVALID_PARAM; - } - - if (enc_info->struct_version <= 3) { - encrypted_blob_size = sizeof(fp_template[0]); - } else { - encrypted_blob_size = - sizeof(fp_template[0]) + - sizeof(fp_positive_match_salt[0]); - } - - ret = derive_encryption_key(key, enc_info->encryption_salt); - if (ret != EC_SUCCESS) { - CPRINTS("fgr%d: Failed to derive key", idx); - return EC_RES_UNAVAILABLE; - } - - /* Decrypt the secret blob in-place. */ - ret = aes_gcm_decrypt(key, SBP_ENC_KEY_LEN, encrypted_template, - encrypted_template, - encrypted_blob_size, - enc_info->nonce, FP_CONTEXT_NONCE_BYTES, - enc_info->tag, FP_CONTEXT_TAG_BYTES); - always_memset(key, 0, sizeof(key)); - if (ret != EC_SUCCESS) { - CPRINTS("fgr%d: Failed to decipher template", idx); - /* Don't leave bad data in the template buffer */ - fp_clear_finger_context(idx); - return EC_RES_UNAVAILABLE; - } - memcpy(fp_template[idx], encrypted_template, - sizeof(fp_template[0])); - if (template_needs_validation_value(enc_info)) { - CPRINTS("fgr%d: Generating positive match salt.", idx); - init_trng(); - rand_bytes(positive_match_salt, - FP_POSITIVE_MATCH_SALT_BYTES); - exit_trng(); - } - if (bytes_are_trivial(positive_match_salt, - sizeof(fp_positive_match_salt[0]))) { - CPRINTS("fgr%d: Trivial positive match salt.", idx); - always_memset(fp_template[idx], 0, - sizeof(fp_template[0])); - return EC_RES_INVALID_PARAM; - } - memcpy(fp_positive_match_salt[idx], positive_match_salt, - sizeof(fp_positive_match_salt[0])); - - templ_valid++; - } - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_FP_TEMPLATE, fp_command_template, EC_VER_MASK(0)); - -#ifdef CONFIG_CMD_FPSENSOR_DEBUG -/* --- Debug console commands --- */ - -/* - * 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} - * - * Alternative (if you're using screen as your terminal): - * - * From *outside* the chroot: - * - * Install ascii-xfr: sudo apt-get install minicom - * Install imagemagick: sudo apt-get install imagemagick - * - * Add the following to your ${HOME}/.screenrc: - * - * zmodem catch - * zmodem recvcmd '!!! bash -c "ascii-xfr -rdv /tmp/finger.pgm && display /tmp/finger.pgm"' - * - * From *outside the chroot*, use screen to connect to UART console: - * - * sudo screen -c ${HOME}/.screenrc /dev/pts/NN 115200 - * - */ -static void upload_pgm_image(uint8_t *frame) -{ - int x, y; - uint8_t *ptr = frame; - - /* fake Z-modem ZRQINIT signature */ - CPRINTF("#IGNORE for ZModem\r**\030B00"); - msleep(2000); /* let the download program start */ - /* Print 8-bpp PGM ASCII header */ - CPRINTF("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++) - CPRINTF("%d ", *ptr); - CPRINTF("\n"); - cflush(); - } - - CPRINTF("\x04"); /* End Of Transmission */ -} - -static enum ec_error_list fp_console_action(uint32_t mode) -{ - int tries = 200; - uint32_t mode_output = 0; - int rc = 0; - - if (!(sensor_mode & FP_MODE_RESET_SENSOR)) - CPRINTS("Waiting for finger ..."); - - rc = fp_set_sensor_mode(mode, &mode_output); - - if (rc != EC_RES_SUCCESS) { - /* - * EC host command errors do not directly map to console command - * errors. - */ - return EC_ERROR_UNKNOWN; - } - - while (tries--) { - if (!(sensor_mode & FP_MODE_ANY_CAPTURE)) { - CPRINTS("done (events:%x)", fp_events); - return 0; - } - usleep(100 * MSEC); - } - return EC_ERROR_TIMEOUT; -} - -int command_fpcapture(int argc, char **argv) -{ - int capture_type = FP_CAPTURE_SIMPLE_IMAGE; - uint32_t mode; - enum ec_error_list rc; - - /* - * TODO(b/142944002): Remove this redundant check for system_is_locked - * once we have unit-tests/integration-tests in place. - */ - if (system_is_locked()) - return EC_ERROR_ACCESS_DENIED; - - if (argc >= 2) { - char *e; - - capture_type = strtoi(argv[1], &e, 0); - if (*e || capture_type < 0) - return EC_ERROR_PARAM1; - } - mode = FP_MODE_CAPTURE | ((capture_type << FP_MODE_CAPTURE_TYPE_SHIFT) - & FP_MODE_CAPTURE_TYPE_MASK); - - rc = fp_console_action(mode); - if (rc == EC_SUCCESS) - upload_pgm_image(fp_buffer + FP_SENSOR_IMAGE_OFFSET); - - return rc; -} -DECLARE_CONSOLE_COMMAND_FLAGS(fpcapture, command_fpcapture, NULL, - "Capture fingerprint in PGM format", - CMD_FLAG_RESTRICTED); - -int command_fpenroll(int argc, char **argv) -{ - enum ec_error_list rc; - int percent = 0; - uint32_t event; - static const char * const enroll_str[] = {"OK", "Low Quality", - "Immobile", "Low Coverage"}; - - /* - * TODO(b/142944002): Remove this redundant check for system_is_locked - * once we have unit-tests/integration-tests in place. - */ - if (system_is_locked()) - return EC_ERROR_ACCESS_DENIED; - - do { - int tries = 1000; - - rc = fp_console_action(FP_MODE_ENROLL_SESSION | - FP_MODE_ENROLL_IMAGE); - if (rc != EC_SUCCESS) - break; - event = atomic_clear(&fp_events); - percent = EC_MKBP_FP_ENROLL_PROGRESS(event); - CPRINTS("Enroll capture: %s (%d%%)", - enroll_str[EC_MKBP_FP_ERRCODE(event) & 3], percent); - /* wait for finger release between captures */ - sensor_mode = FP_MODE_ENROLL_SESSION | FP_MODE_FINGER_UP; - task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG); - while (tries-- && sensor_mode & FP_MODE_FINGER_UP) - usleep(20 * MSEC); - } while (percent < 100); - sensor_mode = 0; /* reset FP_MODE_ENROLL_SESSION */ - task_set_event(TASK_ID_FPSENSOR, TASK_EVENT_UPDATE_CONFIG); - - return rc; -} -DECLARE_CONSOLE_COMMAND_FLAGS(fpenroll, command_fpenroll, NULL, - "Enroll a new fingerprint", - CMD_FLAG_RESTRICTED); - - -int command_fpmatch(int argc, char **argv) -{ - enum ec_error_list rc = fp_console_action(FP_MODE_MATCH); - uint32_t event = atomic_clear(&fp_events); - - if (rc == EC_SUCCESS && event & EC_MKBP_FP_MATCH) { - uint32_t errcode = EC_MKBP_FP_ERRCODE(event); - - CPRINTS("Match: %s (%d)", - errcode & EC_MKBP_FP_ERR_MATCH_YES ? "YES" : "NO", - errcode); - } - - return rc; -} -DECLARE_CONSOLE_COMMAND(fpmatch, command_fpmatch, NULL, - "Run match algorithm against finger"); - -int command_fpclear(int argc, char **argv) -{ - /* - * We intentionally run this on the fp_task so that we use the - * same code path as host commands. - */ - enum ec_error_list rc = fp_console_action(FP_MODE_RESET_SENSOR); - - if (rc < 0) - CPRINTS("Failed to clear fingerprint context: %d", rc); - - atomic_clear(&fp_events); - - return rc; -} -DECLARE_CONSOLE_COMMAND(fpclear, command_fpclear, NULL, - "Clear fingerprint sensor context"); - -int command_fpmaintenance(int argc, char **argv) -{ -#ifdef HAVE_FP_PRIVATE_DRIVER - return fp_maintenance(); -#else - return EC_SUCCESS; -#endif /* #ifdef HAVE_FP_PRIVATE_DRIVER */ -} -DECLARE_CONSOLE_COMMAND(fpmaintenance, command_fpmaintenance, NULL, - "Run fingerprint sensor maintenance"); - -#endif /* CONFIG_CMD_FPSENSOR_DEBUG */ |