diff options
22 files changed, 1802 insertions, 34 deletions
diff --git a/common/fpsensor/build.mk b/common/fpsensor/build.mk index 03bc80f2ef..a1eeaa9932 100644 --- a/common/fpsensor/build.mk +++ b/common/fpsensor/build.mk @@ -10,7 +10,3 @@ _fpsensor_dir:=$(dir $(lastword $(MAKEFILE_LIST))) all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)fpsensor_state.o all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)fpsensor_crypto.o all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)fpsensor.o - -ifeq ($(HAS_MOCK_FP_SENSOR),) -all-obj-$(HAS_TASK_FPSENSOR)+=$(_fpsensor_dir)fpsensor_stubs.o -endif diff --git a/common/fpsensor/fpsensor_stubs.c b/common/fpsensor/fpsensor_stubs.c deleted file mode 100644 index 3acaa689f5..0000000000 --- a/common/fpsensor/fpsensor_stubs.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2019 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 "common.h" -#include "fpsensor_state.h" -#include "panic.h" - -/* - * These are built when we don't have the private driver files. - * The definitions are intentionally kept separate from the mock - * implementations so that we don't accidentally compile mocks into a release. - */ - -#if !defined(HAVE_FP_PRIVATE_DRIVER) - -int fp_sensor_init(void) -{ - panic("fp_sensor_init stub should never be called\n"); - return EC_ERROR_UNKNOWN; -} - -int fp_sensor_deinit(void) -{ - panic("fp_sensor_deinit stub should never be called\n"); - return EC_ERROR_UNKNOWN; -} - -#endif /* !HAVE_FP_PRIVATE_DRIVER */ diff --git a/driver/build.mk b/driver/build.mk index aa962fca95..4a22432ded 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -6,6 +6,9 @@ # Drivers for off-chip devices # +# Note that this variable includes the trailing "/" +_driver_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) + # Accelerometers driver-$(CONFIG_ACCEL_BMA255)+=accel_bma2x2.o driver-$(CONFIG_ACCEL_KXCJ9)+=accel_kionix.o @@ -72,6 +75,9 @@ driver-$(CONFIG_CHARGER_RT9466)+=charger/rt946x.o driver-$(CONFIG_CHARGER_RT9467)+=charger/rt946x.o driver-$(CONFIG_CHARGER_SY21612)+=charger/sy21612.o +# Fingerprint Sensors +include $(_driver_cur_dir)fingerprint/build.mk + # I/O expander driver-$(CONFIG_IO_EXPANDER_PCA9534)+=ioexpander_pca9534.o driver-$(CONFIG_IO_EXPANDER_NCT38XX)+=ioexpander_nct38xx.o diff --git a/driver/fingerprint/build.mk b/driver/fingerprint/build.mk new file mode 100644 index 0000000000..862fa29914 --- /dev/null +++ b/driver/fingerprint/build.mk @@ -0,0 +1,10 @@ +# Copyright 2019 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. + +# Build fingerprint drivers + +# Note that this variable includes the trailing "/" +_fingerprint_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) + +include $(_fingerprint_cur_dir)fpc/build.mk diff --git a/driver/fingerprint/fpc/bep/build.mk b/driver/fingerprint/fpc/bep/build.mk new file mode 100644 index 0000000000..fc704e172a --- /dev/null +++ b/driver/fingerprint/fpc/bep/build.mk @@ -0,0 +1,23 @@ +# Copyright 2019 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. + +# FPC BEP source files build + +# Note that this variable includes the trailing "/" +_bep_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) + +# Make sure output directory is created (in build directory) +dirs-y+="$(_bep_cur_dir)" + +sensor-$(CONFIG_FP_SENSOR_FPC1025)=fpc1025 +sensor-$(CONFIG_FP_SENSOR_FPC1035)=fpc1035 + +# Only build for these objects for the RW image +all-obj-rw+=$(_bep_cur_dir)fpc_misc.o \ + $(_bep_cur_dir)fpc_private.o \ + $(_bep_cur_dir)fpc_sensor_spi.o \ + $(_bep_cur_dir)fpc_timebase.o +fp_sensor_header-rw=$(_bep_cur_dir)$(sensor-rw)_private.h + +CPPFLAGS+=-DFP_SENSOR_PRIVATE=$(fp_sensor_header-rw) diff --git a/driver/fingerprint/fpc/bep/fpc1025_private.h b/driver/fingerprint/fpc/bep/fpc1025_private.h new file mode 100644 index 0000000000..eddb435d4a --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc1025_private.h @@ -0,0 +1,52 @@ +/* Copyright 2019 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. + */ + +#ifndef __CROS_EC_FPC1025_PRIVATE_H +#define __CROS_EC_FPC1025_PRIVATE_H + +/* Define sensor type */ +#define FP_SENSOR_CONFIG_FPC1025 + +/* The 16-bit hardware ID is 0x021y */ +#define FP_SENSOR_HWID 0x021 + +/* Sensor type name */ +#define FP_SENSOR_NAME "FPC1025" + +/* Sensor pixel resolution */ +#define FP_SENSOR_RES_X (160) /**< Sensor width */ +#define FP_SENSOR_RES_Y (160) /**< Sensor height */ +#define FP_SENSOR_RES_BPP (8) /**< Resolution bits per pixel */ + +/* + * Sensor image size + * + * Value from fpc_bep_image_get_buffer_size(): (160*160)+660 + */ +#define FP_SENSOR_IMAGE_SIZE (26260) +#define FP_SENSOR_REAL_IMAGE_SIZE (FP_SENSOR_RES_X * FP_SENSOR_RES_Y) +/* Offset of image data in fp_buffer */ +#define FP_SENSOR_IMAGE_OFFSET (400) + +/* + * Constant value for the enrollment data size + * + * Size of private fp_bio_enrollment_t + */ +#define FP_ALGORITHM_ENROLLMENT_SIZE (4) + +/* + * Constant value corresponding to the maximum template size + * for FPC1025 sensor. Client template memory allocation must + * have this size. This includes extra memory for template update. + * + * Template size + alignment padding + size of template size variable + */ +#define FP_ALGORITHM_TEMPLATE_SIZE (5088 + 0 + 4) + +/* Max number of templates stored / matched against */ +#define FP_MAX_FINGER_COUNT (5) + +#endif /* __CROS_EC_FPC1025_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/bep/fpc1035_private.h b/driver/fingerprint/fpc/bep/fpc1035_private.h new file mode 100644 index 0000000000..61c423c6b8 --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc1035_private.h @@ -0,0 +1,52 @@ +/* Copyright 2019 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. + */ + +#ifndef __CROS_EC_FPC1035_PRIVATE_H +#define __CROS_EC_FPC1035_PRIVATE_H + +/* Define sensor type */ +#define FP_SENSOR_CONFIG_FPC1035 + +/* The 16-bit hardware ID is 0x011y */ +#define FP_SENSOR_HWID 0x011 + +/* Sensor type name */ +#define FP_SENSOR_NAME "FPC1035" + +/* Sensor pixel resolution */ +#define FP_SENSOR_RES_X (112) /**< Sensor width */ +#define FP_SENSOR_RES_Y (88) /**< Sensor height */ +#define FP_SENSOR_RES_BPP (8) /**< Resolution bits per pixel */ + +/* + * Sensor image size + * + * Value from fpc_bep_image_get_buffer_size(): (112*88)+660 + */ +#define FP_SENSOR_IMAGE_SIZE (10516) +#define FP_SENSOR_REAL_IMAGE_SIZE (FP_SENSOR_RES_X * FP_SENSOR_RES_Y) +/* Offset of image data in fp_buffer */ +#define FP_SENSOR_IMAGE_OFFSET (400) + +/* + * Constant value for the enrollment data size + * + * Size of private fp_bio_enrollment_t + */ +#define FP_ALGORITHM_ENROLLMENT_SIZE (4) + +/* + * Constant value corresponding to the maximum template size + * for FPC1035 sensor. Client template memory allocation must + * have this size. This includes extra memory for template update. + * + * Template size + alignment padding + size of template size variable + */ +#define FP_ALGORITHM_TEMPLATE_SIZE (14373 + 3 + 4) + +/* Max number of templates stored / matched against */ +#define FP_MAX_FINGER_COUNT (5) + +#endif /* __CROS_EC_FPC1035_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h b/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h new file mode 100644 index 0000000000..1bf598a3ee --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h @@ -0,0 +1,136 @@ +/* Copyright 2019 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. + */ + +#ifndef __CROS_EC_FPC_BIO_ALGORITHM_H +#define __CROS_EC_FPC_BIO_ALGORITHM_H + +#include <stdint.h> + +/* + * An opaque pointer representing an image (scan). + */ +typedef void *bio_image_t; +/* + * An opaque pointer representing/uniquely identifying an (serialized) enrolled + * template. + */ +typedef void *bio_template_t; +/* + * An opaque pointer representing/uniquely identifying enrollment attempt. + */ +typedef void *bio_enrollment_t; +/* + * An opaque struct representing algorithm. + */ +typedef struct fpc_bep_algorithm fpc_bep_algorithm_t; +/* + * Struct with biometric algorithm information. + */ +typedef struct { + const fpc_bep_algorithm_t *algorithm; + uint32_t template_size; +} fpc_bio_info_t; +/* + * Initializes biometric algorithm library. Should be the very first function + * to be invoked by the biometric daemon. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_algorithm_init(void); +/* + * Instructs the biometric library to release all resources in preparation + * for the process termination (or unloading the library). Regardless of + * the returned error code the action is considered unrecoverable. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_algorithm_exit(void); +/* + * Compares given biometric image against a list of enrolled template(s). + * In case the image match a template the match_index will indicate which + * template in the list that matched. + * The algorithm library can update templates with additional biometric data + * from the image, if it chooses to do so. The updated template(s) will be + * indicated by the out parameter 'updated_templates', a bit-field where + * updated template(s) indicated by the corresponding bit being set + * Returns: + * - negative value on error + * - BIO_TEMPLATE_NO_MATCH on non-match + * - BIO_TEMPLATE_MATCH for match when template was not updated with new data + * - BIO_TEMPLATE_MATCH_UPDATED for match when template was updated + * - BIO_TEMPLATE_MATCH_UPDATE_FAILED match, but update failed (do not save) + * - BIO_TEMPLATE_LOW_QUALITY when matching could not be performed due to low + * image quality + * - BIO_TEMPLATE_LOW_COVERAGE when matching could not be performed due to + * finger covering too little area of the sensor + */ +#define BIO_TEMPLATE_NO_MATCH 0 +#define BIO_TEMPLATE_MATCH 1 +#define BIO_TEMPLATE_MATCH_UPDATED 3 +#define BIO_TEMPLATE_MATCH_UPDATE_FAILED 5 +#define BIO_TEMPLATE_LOW_QUALITY 2 +#define BIO_TEMPLATE_LOW_COVERAGE 4 + +int bio_template_image_match_list(bio_template_t templ, uint32_t num_templ, + bio_image_t image, int32_t *match_index, + uint32_t *updated_templ); +/* + * Initiates biometric data enrollment process. Algorithm library returns + * 'enrollment handle' that is used for all subsequent enrollment operations. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_enrollment_begin(bio_enrollment_t *enrollment); +/* + * Adds fingerprint image to an enrollment. + * + * The library should expect to copy any relevant data from the “image” + * as it is likely to be destroyed (via bio_image_destroy() call) shortly after + * this call completes. + * + * Returns: + * - negative value on error + * - BIO_ENROLLMENT_OK when image was successfully enrolled + * - BIO_ENROLLMENT_LOW_QUALITY when image could not be used due to low + * image quality + * - BIO_ENROLLMENT_IMMOBILE when image added, but user should be advised + * to move finger + * - BIO_ENROLLMENT_LOW_COVERAGE when image could not be used due to + * finger covering too little area of the sensor + * - BIO_ENROLLMENT_INTERNAL_ERROR when an internal error occurred + */ +#define BIO_ENROLLMENT_OK 0 +#define BIO_ENROLLMENT_LOW_QUALITY 1 +#define BIO_ENROLLMENT_IMMOBILE 2 +#define BIO_ENROLLMENT_LOW_COVERAGE 3 +#define BIO_ENROLLMENT_INTERNAL_ERROR 5 + +/* Can be used to detect if image was usable for enrollment or not. */ +#define BIO_ENROLLMENT_PROBLEM_MASK 1 +int bio_enrollment_add_image(bio_enrollment_t enrollment, bio_image_t image); +/* + * Returns percent of coverage accumulated during enrollment process. + * Optional method. Regardless of value returned by this call user should call + * bio_enrollment_is_complete() to check if algorithm library accumulated enough + * data to create a template. + * + * Returns value in the range 0..100, or negative error (such as -EINVAL); + */ +int bio_enrollment_get_percent_complete(bio_enrollment_t enrollment); +/* + * Indicates that given enrollment process is complete, and algorithm library + * should generate an active template that can be used in subsequent calls + * to bio_image_match() and bio_template_serialize() from enrollment data. + * After the template is created the library should release all resources + * associated with this enrollment. + * + * Argument 'templ' is optional and can be set to NULL if caller wishes to + * abort enrollment process. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_enrollment_finish(bio_enrollment_t enrollment, bio_template_t *templ); + +#endif /* __CROS_EC_FPC_BIO_ALGORITHM_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_misc.c b/driver/fingerprint/fpc/bep/fpc_misc.c new file mode 100644 index 0000000000..c4c779b702 --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_misc.c @@ -0,0 +1,51 @@ +/* Copyright 2019 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. + */ + +/* FPC Platform Abstraction Layer */ + +#include <stdint.h> +#include <stddef.h> + +#include "shared_mem.h" +#include "uart.h" + +void __unused *fpc_malloc(uint32_t size) +{ + char *data; + int rc; + + rc = shared_mem_acquire(size, (char **)&data); + + if (rc == 0) + return data; + else + return NULL; +} + +void __unused fpc_free(void *data) +{ + shared_mem_release(data); +} + +/* Not in release */ +void __unused fpc_assert_fail(const char *file, uint32_t line, const char *func, + const char *expr) +{ +} + +void __unused fpc_log_var(const char *source, uint8_t level, const char *format, + ...) +{ + va_list args; + + va_start(args, format); + uart_vprintf(format, args); + va_end(args); +} + +uint32_t abs(int32_t a) +{ + return (a < 0) ? (uint32_t)(-a) : (uint32_t)a; +} diff --git a/driver/fingerprint/fpc/bep/fpc_private.c b/driver/fingerprint/fpc/bep/fpc_private.c new file mode 100644 index 0000000000..f69cffb0ce --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_private.c @@ -0,0 +1,260 @@ +/* Copyright 2019 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 <stdint.h> +#include <stddef.h> + +#include "fpc_bio_algorithm.h" +#include "fpsensor.h" +#include "spi.h" +#include "system.h" +#include "util.h" + +#include STRINGIFY(FP_SENSOR_PRIVATE) + +/* Console output macros */ +#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) +#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) + +static uint8_t enroll_ctx[FP_ALGORITHM_ENROLLMENT_SIZE] = {0}; + +/* Recorded error flags */ +static uint16_t errors; + +/* FPC specific initialization and de-initialization functions */ +int fp_sensor_open(void); +int fp_sensor_close(void); + +/* Get FPC library version code.*/ +const char *fp_sensor_get_version(void); + +/* Get FPC library build info.*/ +const char *fp_sensor_get_build_info(void); + +/* Sensor description */ +static struct ec_response_fp_info ec_fp_sensor_info = { + /* Sensor identification */ + .vendor_id = FOURCC('F', 'P', 'C', ' '), + .product_id = 9, + .model_id = 1, + .version = 1, + /* Image frame characteristics */ + .frame_size = FP_SENSOR_IMAGE_SIZE, + .pixel_format = V4L2_PIX_FMT_GREY, + .width = FP_SENSOR_RES_X, + .height = FP_SENSOR_RES_Y, + .bpp = FP_SENSOR_RES_BPP, +}; + +typedef struct fpc_bep_sensor fpc_bep_sensor_t; + +typedef struct { + const fpc_bep_sensor_t *sensor; + uint32_t image_buffer_size; +} fpc_sensor_info_t; + +#if defined(FP_SENSOR_CONFIG_FPC1025) + +extern const fpc_bep_sensor_t fpc_bep_sensor_1025; +extern const fpc_bep_algorithm_t fpc_bep_algorithm_pfe_1025; + +const fpc_sensor_info_t fpc_sensor_info = { + .sensor = &fpc_bep_sensor_1025, + .image_buffer_size = FP_SENSOR_IMAGE_SIZE, +}; + +const fpc_bio_info_t fpc_bio_info = { + .algorithm = &fpc_bep_algorithm_pfe_1025, + .template_size = FP_ALGORITHM_TEMPLATE_SIZE, +}; + +#elif defined(FP_SENSOR_CONFIG_FPC1035) + +extern const fpc_bep_sensor_t fpc_bep_sensor_1035; +extern const fpc_bep_algorithm_t fpc_bep_algorithm_pfe_1035; + +const fpc_sensor_info_t fpc_sensor_info = { + .sensor = &fpc_bep_sensor_1035, + .image_buffer_size = FP_SENSOR_IMAGE_SIZE, +}; + +const fpc_bio_info_t fpc_bio_info = { + .algorithm = &fpc_bep_algorithm_pfe_1035, + .template_size = FP_ALGORITHM_TEMPLATE_SIZE, +}; +#else +#error "Sensor type not defined!" +#endif + +/* Sensor IC commands */ +enum fpc_cmd { + FPC_CMD_DEEPSLEEP = 0x2C, + FPC_CMD_HW_ID = 0xFC, +}; + +/* Maximum size of a sensor command SPI transfer */ +#define MAX_CMD_SPI_TRANSFER_SIZE 3 + +/* Memory for the SPI transfer buffer */ +static uint8_t spi_buf[MAX_CMD_SPI_TRANSFER_SIZE]; + +static int fpc_send_cmd(const uint8_t cmd) +{ + spi_buf[0] = cmd; + + return spi_transaction(SPI_FP_DEVICE, spi_buf, 1, spi_buf, + SPI_READBACK_ALL); +} + +void fp_sensor_low_power(void) +{ + fpc_send_cmd(FPC_CMD_DEEPSLEEP); +} + +static int fpc_check_hwid(void) +{ + uint16_t id; + int rc; + + spi_buf[0] = FPC_CMD_HW_ID; + + rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, + SPI_READBACK_ALL); + if (rc) { + CPRINTS("FPC HW ID read failed %d", rc); + return FP_ERROR_SPI_COMM; + } + + id = (spi_buf[1] << 8) | spi_buf[2]; + if ((id >> 4) != FP_SENSOR_HWID) { + CPRINTS("FPC unknown silicon 0x%04x", id); + return FP_ERROR_BAD_HWID; + } + CPRINTS(FP_SENSOR_NAME " id 0x%04x", id); + + return EC_SUCCESS; +} + +/* Reset and initialize the sensor IC */ +int fp_sensor_init(void) +{ + int rc; + + /* Print the binary libfpbep.a library version */ + CPRINTS("FPC libfpbep.a %s", fp_sensor_get_version()); + + /* Print the BEP version and build time of the library */ + CPRINTS("Build information - %s", fp_sensor_get_build_info()); + + rc = fp_sensor_open(); + if (rc) { + errors |= FP_ERROR_INIT_FAIL; + CPRINTS("Error: fp_sensor_open() failed, result=%d", rc); + } + + errors |= fpc_check_hwid(); + + rc = bio_algorithm_init(); + if (rc < 0) { + errors |= FP_ERROR_INIT_FAIL; + CPRINTS("Error: bio_algorithm_init() failed, result=%d", rc); + } + + /* Go back to low power */ + fp_sensor_low_power(); + + return EC_SUCCESS; +} + +/* Deinitialize the sensor IC */ +int fp_sensor_deinit(void) +{ + int rc; + + rc = bio_algorithm_exit(); + if (rc < 0) + CPRINTS("Error: bio_algorithm_exit() failed, result=%d", rc); + + rc = fp_sensor_close(); + if (rc < 0) + CPRINTS("Error: fp_sensor_close() failed, result=%d", rc); + + return rc; +} + +int fp_sensor_get_info(struct ec_response_fp_info *resp) +{ + int rc; + + spi_buf[0] = FPC_CMD_HW_ID; + + memcpy(resp, &ec_fp_sensor_info, sizeof(struct ec_response_fp_info)); + + rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, + SPI_READBACK_ALL); + if (rc) + return EC_RES_ERROR; + + resp->model_id = (spi_buf[1] << 8) | spi_buf[2]; + resp->errors = errors; + + return EC_SUCCESS; +} + +int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image, + int32_t *match_index, uint32_t *update_bitmap) +{ + int rc; + + rc = bio_template_image_match_list(templ, templ_count, image, + match_index, update_bitmap); + if (rc < 0) + CPRINTS("Error: bio_template_image_match_list() failed, result=%d", + rc); + + return rc; +} + +int fp_enrollment_begin(void) +{ + int rc; + bio_enrollment_t bio_enroll = enroll_ctx; + + rc = bio_enrollment_begin(&bio_enroll); + if (rc < 0) + CPRINTS("Error: bio_enrollment_begin() failed, result=%d", rc); + + return rc; +} + +int fp_enrollment_finish(void *templ) +{ + int rc; + bio_enrollment_t bio_enroll = enroll_ctx; + bio_template_t bio_templ = templ; + + rc = bio_enrollment_finish(bio_enroll, templ ? &bio_templ : NULL); + if (rc < 0) + CPRINTS("Error: bio_enrollment_finish() failed, result=%d", rc); + + return rc; +} + +int fp_finger_enroll(uint8_t *image, int *completion) +{ + int rc; + bio_enrollment_t bio_enroll = enroll_ctx; + + rc = bio_enrollment_add_image(bio_enroll, image); + if (rc < 0) { + CPRINTS("Error: bio_enrollment_add_image() failed, result=%d", + rc); + return rc; + } + + *completion = bio_enrollment_get_percent_complete(bio_enroll); + + return rc; +} diff --git a/driver/fingerprint/fpc/bep/fpc_sensor_spi.c b/driver/fingerprint/fpc/bep/fpc_sensor_spi.c new file mode 100644 index 0000000000..3db3713702 --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_sensor_spi.c @@ -0,0 +1,94 @@ +/* Copyright 2019 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. + */ + +/* FPC Platform Abstraction Layer */ + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +#include "console.h" +#include "fpsensor.h" +#include "fpc_sensor_spi.h" +#include "gpio.h" +#include "spi.h" +#include "util.h" + +#include STRINGIFY(FP_SENSOR_PRIVATE) + +/* Console output macros */ +#define CPRINTF(format, args...) cprintf(CC_FP, format, ##args) +#define CPRINTS(format, args...) cprints(CC_FP, format, ##args) + +#define SPI_BUF_SIZE (1024) + +#define FPC_RESULT_OK (0) +#define FPC_RESULT_IO_ERROR (-8) + +static uint8_t spi_buf[SPI_BUF_SIZE] FP_FRAME_SECTION __aligned(4); + +int __unused fpc_sensor_spi_write_read(uint8_t *write, uint8_t *read, + size_t size, bool leave_cs_asserted) +{ + int rc = 0; + + if (size == FP_SENSOR_REAL_IMAGE_SIZE) { + rc |= spi_transaction(SPI_FP_DEVICE, write, size, read, + SPI_READBACK_ALL); + spi_transaction_flush(SPI_FP_DEVICE); + } else if (size <= SPI_BUF_SIZE) { + memcpy(spi_buf, write, size); + rc |= spi_transaction_async(SPI_FP_DEVICE, spi_buf, size, + spi_buf, SPI_READBACK_ALL); + + /* De-asserting the sensor chip-select will clear the sensor + * internal command state. To run multiple sensor transactions + * in the same command state (typically image capture), leave + * chip-select asserted. Make sure chip-select is de-asserted + * when all transactions are finished. + */ + if (!leave_cs_asserted) + spi_transaction_flush(SPI_FP_DEVICE); + else + spi_transaction_wait(SPI_FP_DEVICE); + + memcpy(read, spi_buf, size); + } else { + rc = -1; + } + + if (rc == 0) { + return FPC_RESULT_OK; + } else { + CPRINTS("Error: spi_transaction()/spi_transaction_async() failed, result=%d", + rc); + return FPC_RESULT_IO_ERROR; + } +} + +bool __unused fpc_sensor_spi_check_irq(void) +{ + return (gpio_get_level(GPIO_FPS_INT) == 1); +} + +bool __unused fpc_sensor_spi_read_irq(void) +{ + return (gpio_get_level(GPIO_FPS_INT) == 1); +} + +void __unused fpc_sensor_spi_reset(bool state) +{ + gpio_set_level(GPIO_FP_RST_ODL, state ? 0 : 1); +} + +void __unused fpc_sensor_spi_init(uint32_t speed_hz) +{ +} + +int __unused fpc_sensor_wfi(uint16_t timeout_ms, fpc_wfi_check_t enter_wfi, + bool enter_wfi_mode) +{ + return FPC_RESULT_OK; +} diff --git a/driver/fingerprint/fpc/bep/fpc_sensor_spi.h b/driver/fingerprint/fpc/bep/fpc_sensor_spi.h new file mode 100644 index 0000000000..4b9bcd63a8 --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_sensor_spi.h @@ -0,0 +1,98 @@ +/* Copyright 2019 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. + */ + +#ifndef __CROS_EC_FPC_SENSOR_SPI_H +#define __CROS_EC_FPC_SENSOR_SPI_H + +/** + * @file fpc_sensor_spi.h + * @brief Driver for SPI master. + * + * Driver for SPI master. Intended for communication with fingerprint sensor. + */ + +#include <stdint.h> +#include <stdbool.h> + +typedef bool (*fpc_wfi_check_t)(void); + +/** + * @brief Writes and reads SPI data. + * + * Writes data to SPI interface and reads data from SPI interface, with chip + * select control. The caller is blocked until the operation is complete. By use + * of the chip select control parameter a single SPI transaction can be split in + * several calls. + * + * @param[in] write Data to write. Must not be NULL if size > 0. + * @param[in,out] read Receive data buffer. The caller is responsible for + * allocating buffer. NULL => response is thrown away. + * @param[in] size Number of bytes to write (same as bytes received). + * 0 => Only chip select control. + * @param[in] leave_cs_asserted True => chip select is left in asserted + * state. + * False => chip select is de-asserted before + * return. + * @return ::fpc_bep_result_t + */ +int __unused fpc_sensor_spi_write_read(uint8_t *write, uint8_t *read, + size_t size, bool leave_cs_asserted); + +/** + * @brief Read sensor IRQ status. + * + * Returns status of the sensor IRQ. + * + * @return true if the sensor IRQ is currently active, otherwise false. + */ +bool __unused fpc_sensor_spi_check_irq(void); + +/** + * @brief Read sensor IRQ status and then set status to false. + * + * Returns status of the sensor IRQ and sets the status to false. + * + * @return true if the sensor IRQ has been active, otherwise false. + */ +bool __unused fpc_sensor_spi_read_irq(void); + +/** + * @brief Set sensor reset state. + * + * Set sensor reset state. + * + * @param[in] state Reset state. + * true => reset sensor, i.e. low GPIO state + * false => normal operation, i.e. high GPIO state + */ +void __unused fpc_sensor_spi_reset(bool state); + +/** + * @brief Initializes SPI master. + * + * @param[in] speed_hz Maximum SPI clock speed according to sensor HW spec + * (unit Hz). + * + */ +void __unused fpc_sensor_spi_init(uint32_t speed_hz); + +/** + * @brief Set system in WFI mode while waiting sensor IRQ. + * + * @note This mode only requires the system to be able to wake up from Sensor + * IRQ pin, all other peripheral can be turned off. + * + * @note The system time must be adjusted upon WFI return. + * + * @param[in] timeout_ms Time in ms before waking up, 0 if no timeout. + * @param[in] enter_wfi Function pointer to check WFI entry. + * @param[in] enter_wfi_mode Bool that is used when comparing the value returned + * by enter_wfi. + * @return FPC_RESULT_OK, FPC_RESULT_TIMEOUT + */ +int __unused fpc_sensor_wfi(uint16_t timeout_ms, fpc_wfi_check_t enter_wfi, + bool enter_wfi_mode); + +#endif /* __CROS_EC_FPC_SENSOR_SPI_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_timebase.c b/driver/fingerprint/fpc/bep/fpc_timebase.c new file mode 100644 index 0000000000..113e150ed9 --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_timebase.c @@ -0,0 +1,29 @@ +/* Copyright 2019 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. + */ + +/* FPC Platform Abstraction Layer */ + +#include <stdint.h> + +#include "fpc_timebase.h" +#include "timer.h" + +uint32_t __unused fpc_timebase_get_tick(void) +{ + clock_t time; + + time = clock(); + + return (uint32_t)time; +} + +void __unused fpc_timebase_busy_wait(uint32_t ms) +{ + udelay(ms * 1000); +} + +void __unused fpc_timebase_init(void) +{ +} diff --git a/driver/fingerprint/fpc/bep/fpc_timebase.h b/driver/fingerprint/fpc/bep/fpc_timebase.h new file mode 100644 index 0000000000..388d13293e --- /dev/null +++ b/driver/fingerprint/fpc/bep/fpc_timebase.h @@ -0,0 +1,48 @@ +/* Copyright 2019 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. + */ + +#ifndef __CROS_EC_FPC_TIMEBASE_H +#define __CROS_EC_FPC_TIMEBASE_H + +/** + * @file fpc_timebase.h + * @brief Timebase based on a system tick. + * + * Supplies tick counter and wait operation(s). + */ + +#include <stdint.h> + +#include "common.h" + +/** + * @brief Reads the system tick counter. + * + * @details To handle tick counter wrap around when checking for timeout, make + * sure to do the calculation in the following manner: + * "if ((current_tick - old_tick) > timeout) {" + * Example: current time (uint32_t) = 10 ticks + * old time (uint32_t) = 30 ticks before overflow of uint32_t + * current_time - old_time = 10 - (2**32 - 30) -> wraps around to 40 + * + * @return Tick count since fpc_timebase_init() call. [ms] + */ +uint32_t __unused fpc_timebase_get_tick(void); + +/** + * @brief Busy wait. + * + * @param[in] ms Time to wait [ms]. + * 0 => return immediately + * 1 => wait at least 1ms etc. + */ +void __unused fpc_timebase_busy_wait(uint32_t ms); + +/** + * @brief Initializes timebase. Starts system tick counter. + */ +void __unused fpc_timebase_init(void); + +#endif /* __CROS_EC_FPC_TIMEBASE_H */ diff --git a/driver/fingerprint/fpc/build.mk b/driver/fingerprint/fpc/build.mk new file mode 100644 index 0000000000..ab6a6a4b9c --- /dev/null +++ b/driver/fingerprint/fpc/build.mk @@ -0,0 +1,16 @@ +# Copyright 2019 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. + +# Build for FPC fingerprint drivers + +# Note that this variable includes the trailing "/" +_fpc_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) + +ifeq ($(CONFIG_FP_SENSOR_FPC1145),rw) +include $(_fpc_cur_dir)libfp/build.mk +else ifeq ($(CONFIG_FP_SENSOR_FPC1025),rw) +include $(_fpc_cur_dir)bep/build.mk +else ifeq ($(CONFIG_FP_SENSOR_FPC1035),rw) +include $(_fpc_cur_dir)bep/build.mk +endif diff --git a/driver/fingerprint/fpc/libfp/build.mk b/driver/fingerprint/fpc/libfp/build.mk new file mode 100644 index 0000000000..8e745f728a --- /dev/null +++ b/driver/fingerprint/fpc/libfp/build.mk @@ -0,0 +1,21 @@ +# Copyright 2019 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. + +# FPC libfp source files build + +# Note that this variable includes the trailing "/" +libfp_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) + +# Make sure output directory is created (in build directory) +dirs-y+="$(libfp_cur_dir)" + +sensor-$(CONFIG_FP_SENSOR_FPC1145)=fpc1145 + +# Only build for these objects for the RW image +all-obj-rw+=$(libfp_cur_dir)fpc_sensor_pal.o \ + $(libfp_cur_dir)fpc_private.o +fp_sensor_header-rw=$(libfp_cur_dir)$(sensor-rw)_private.h + +CPPFLAGS+=-DFP_SENSOR_PRIVATE=$(fp_sensor_header-rw) +CPPFLAGS+=-DFP_SENSOR_CONFIG=$(call uppercase,$(sensor-rw)) diff --git a/driver/fingerprint/fpc/libfp/fpc1145_private.h b/driver/fingerprint/fpc/libfp/fpc1145_private.h new file mode 100644 index 0000000000..ad1e824942 --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc1145_private.h @@ -0,0 +1,42 @@ +/* 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. + */ + +#ifndef __CROS_EC_FPC1145_PRIVATE_H +#define __CROS_EC_FPC1145_PRIVATE_H + +#include <stdint.h> + +/* The 16-bit hardware ID is 0x140y */ +#define FP_SENSOR_HWID 0x140 + +/* Sensor pixel resolution */ +#define FP_SENSOR_RES_Y 192 +#define FP_SENSOR_RES_X 56 +#define FP_SENSOR_RES_BPP 8 + +/* Acquired finger frame definitions */ +#define FP_SENSOR_IMAGE_SIZE_MODE_VENDOR (35460) +#define FP_SENSOR_IMAGE_SIZE_MODE_SIMPLE (13356) +/* + * Size of the captured image in MQT mode. If you this is modified the + * corresponding value in the MQT tool fputils.py must be changed too. + * See b/111443750 for context. + */ +#define FP_SENSOR_IMAGE_SIZE_MODE_QUAL (24408) + +#define FP_SENSOR_IMAGE_SIZE FP_SENSOR_IMAGE_SIZE_MODE_VENDOR +#define FP_SENSOR_IMAGE_OFFSET 2340 + +/* Opaque FPC context */ +#define FP_SENSOR_CONTEXT_SIZE 4944 + +/* Algorithm buffer sizes */ +#define FP_ALGORITHM_ENROLLMENT_SIZE 28 +#define FP_ALGORITHM_TEMPLATE_SIZE 47552 + +/* Max number of templates stored / matched against */ +#define FP_MAX_FINGER_COUNT 5 + +#endif /* __CROS_EC_FPC1145_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h b/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h new file mode 100644 index 0000000000..9c00b14640 --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h @@ -0,0 +1,265 @@ +/* Copyright 2016 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. + */ +#ifndef BIOD_BIO_ALGORITHM_H_ +#define BIOD_BIO_ALGORITHM_H_ + +#include <stdint.h> + +enum bio_algorithm_type { + BIO_ALGORITHM_FINGERPRINT, + BIO_ALGORITHM_IRIS, +}; +/* + * An opaque pointer representing/uniquely identifying a sensor. + */ +typedef void *bio_sensor_t; +/* + * An opaque pointer representing an image (scan). + */ +typedef void *bio_image_t; +/* + * An opaque pointer representing/uniquely identifying an (serialized) enrolled + * template. + */ +typedef void *bio_template_t; +/* + * An opaque pointer representing/uniquely identifying enrollment attempt. + */ +typedef void *bio_enrollment_t; +/* + * Initializes biometric algorithm library. Should be the very first function + * to be invoked by the biometric daemon. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_algorithm_init(void); +/* + * Instructs the biometric library to release all resources in preparation + * for the process termination (or unloading the library). Regardless of + * the returned error code the action is considered unrecoverable. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_algorithm_exit(void); +/* + * Used to retrieve type of the algorithm library. Might be used by + * configuration processor module to match sensors and algorithm libraries. + */ +enum bio_algorithm_type bio_algorithm_get_type(void); +/* + * Used to retrieve name of the algorithm library, to be used in diagnostics. + * Also might be used by configuration processor module to match sensors and + * algorithm libraries. + */ +const char *bio_algorithm_get_name(void); +/* + * Used to retrieve version of the algorithm library, to be used in diagnostics. + */ +const char *bio_algorithm_get_version(void); +/* + * Used to retrieve additional information from the algorithm library, to be + * used in diagnostics. + */ +const char *bio_algorithm_get_banner(void); +/* + * Initializes a new sensor structure and returns its handle that will be used + * in other calls to identify the sensor involved in the operation. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_sensor_create(bio_sensor_t *sensor); +/* + * Releases all resources held by the library in conjunction with given sensor. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_sensor_destroy(bio_sensor_t sensor); +/* + * Communicates particulars of a given sensor so that algorithm library can + * adjust its behavior as needed. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_sensor_set_model(bio_sensor_t sensor, uint32_t vendor_id, + uint32_t product_id, uint32_t model_id, + uint32_t version); +/* + * Communicates format of data used by given sensor to the algorithm library. + * This is a fourcc value defined by V4L2 API. + * Could be a new define for biometric sensors or V4L2_PIX_FMT_GREY. + * Algorithm library will return error if it can not work with given format. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_sensor_set_format(bio_sensor_t sensor, uint32_t pixel_format); +/* + * Communicates dimensions of given sensor to the algorithm library. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_sensor_set_size(bio_sensor_t sensor, uint32_t width, uint32_t height); +/* + * Instructs the algorithm library to initialize a new structure to hold + * biometric image of given dimensions acquired from given sensor. + * It will return image handle that will be used in other calls to identify + * the image involved in the operation. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_image_create(bio_sensor_t sensor, uint32_t width, uint32_t height, + bio_image_t *image); +/* + * Communicates dimensions of image to the algorithm library. + * Can be used if image is less than full sensor resolution. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_image_set_size(bio_image_t image, uint32_t width, uint32_t height); +/* + * Attaches data from biometric sensor to image structure. The caller must + * ensure that there is enough of data for given image dimensions for given + * format used by the sensor. + * + * It is assumes that the data pointer stays valid until bio_image_destroy() + * is called. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_image_set_data(bio_image_t image, const uint8_t *data, size_t size); +/* + * Releases all resources held by the library in conjunction with given image. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_image_destroy(bio_image_t image); + +/* + * Compares given biometric image against a list of enrolled template(s). + * In case the image match a template the match_index will indicate which + * template in the list that matched. + * The algorithm library can update templates with additional biometric data + * from the image, if it chooses to do so. The updated template(s) will be + * indicated by the out parameter 'updated_templates', a bit-field where + * updated template(s) indicated by the corresponding bit being set + * Returns: + * - negative value on error + * - BIO_TEMPLATE_NO_MATCH on non-match + * - BIO_TEMPLATE_MATCH for match when template was not updated with new data + * - BIO_TEMPLATE_MATCH_UPDATED for match when template was updated + * - BIO_TEMPLATE_MATCH_UPDATE_FAILED match, but update failed (do not save) + * - BIO_TEMPLATE_LOW_QUALITY when matching could not be performed due to low + * image quality + * - BIO_TEMPLATE_LOW_COVERAGE when matching could not be performed due to + * finger covering too little area of the sensor + */ +int bio_template_image_match_list(bio_template_t tmpl, uint32_t num_templates, + bio_image_t image, int32_t *match_index, + uint32_t *updated_templates); +int bio_template_image_match(bio_template_t tmpl, bio_image_t image); +/* + * Returns size of template data in serialized form. + * + * Returns negative error code (such as -EINVAL) on failure, or size of the + * serialized form in bytes. + */ +ssize_t bio_template_get_serialized_size(bio_template_t tmpl); +/* + * Releases all resources held by the library in conjunction with given + * template. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_template_destroy(bio_template_t tmpl); +/* + * Initiates biometric data enrollment process. Algorithm library returns + * 'enrollment handle' that is used for all subsequent enrollment operations. + * + * Returns 0 on success, negative error code (such as -ENOMEM) on failure. + */ +int bio_enrollment_begin(bio_sensor_t sensor, bio_enrollment_t *enrollment); +/* + * Adds fingerprint image to an enrollment. + * + * The library should expect to copy any relevant data from the “image” + * as it is likely to be destroyed (via bio_image_destroy() call) shortly after + * this call completes. + * + * Returns: + * - negative value on error + * - BIO_ENROLLMENT_OK when image was successfully enrolled + * - BIO_ENROLLMENT_IMMOBILE when image added, but user should be advised + * to move finger + * - BIO_ENROLLMENT_LOW_QUALITY when image could not be used due to low + * image quality + * - BIO_ENROLLMENT_LOW_COVERAGE when image could not be used due to + * finger covering too little area of the sensor + */ +#define BIO_ENROLLMENT_OK 0 +#define BIO_ENROLLMENT_IMMOBILE 2 +#define BIO_ENROLLMENT_LOW_QUALITY 1 +#define BIO_ENROLLMENT_LOW_COVERAGE 3 +/* Can be used to detect if image was usable for enrollment or not. */ +#define BIO_ENROLLMENT_PROBLEM_MASK 1 +int bio_enrollment_add_image(bio_enrollment_t enrollment, bio_image_t image); +/* + * Indicates whether there is enough data in the enrollment for it to be + * converted into a template to be used for identification. + * + * Returns 0 for if enrollment does not have enough data yet, 1 if enrollment + * is complete, or negative error code (such as -EINVAL) on failure. + * + */ +int bio_enrollment_is_complete(bio_enrollment_t enrollment); +/* + * Returns percent of coverage accumulated during enrollment process. + * Optional method. Regardless of value returned by this call user should call + * bio_enrollment_is_complete() to check if algorithm library accumulated enough + * data to create a template. + * + * Returns value in the range 0..100, or negative error (such as -EINVAL); + */ +int bio_enrollment_get_percent_complete(bio_enrollment_t enrollment); +/* + * Indicates that given enrollment process is complete, and algorithm library + * should generate an active template that can be used in subsequent calls + * to bio_image_match() and bio_template_serialize() from enrollment data. + * After the template is created the library should release all resources + * associated with this enrollment. + * + * Argument 'tmpl' is optional and can be set to NULL if caller wishes to + * abort enrollment process. + * + * Returns 0 on success, negative error code (such as -EINVAL) on failure. + */ +int bio_enrollment_finish(bio_enrollment_t enrollment, bio_template_t *tmpl); + +typedef struct { + int32_t coverage; /* Sensor coverage in range [0..100] */ + int32_t quality; /* Image quality in range [0..100] */ + int32_t min_coverage; /* Minimum coverage accepted by enroll */ + int32_t min_quality; /* Minimum image quality accepted by enroll */ +} bio_image_status_t; + +/* + * Get the image quality and threshold values for a bio_image_t + * + * @param[in] image Image data as acquired by + * fp_sensor_acquire_image_with_mode + * @param[out] image_status Populated structure with quality/coverage values + * and corresponding threshold values + * + * @note This function will alter the internal states of the bio algorithm + * library and must not be used during an enroll sequence. The typical + * use case for this function is to qualify images during image + * collection. + * + * @return negative on error. + * @return 0 if the quality and coverage threshold values aren't reached. + * @return 1 if the quality and coverage threshold values are reached. + */ +int bio_sensor_get_image_status(bio_image_t image, + bio_image_status_t *image_status); + +#endif /* BIOD_BIO_ALGORITHM_H_ */ diff --git a/driver/fingerprint/fpc/libfp/fpc_private.c b/driver/fingerprint/fpc/libfp/fpc_private.c new file mode 100644 index 0000000000..1ee7f29a79 --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc_private.c @@ -0,0 +1,317 @@ +/* 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 <stddef.h> +#include "common.h" +#include "console.h" +#include "endian.h" +#include "fpc_bio_algorithm.h" +#include "fpc_private.h" +#include "fpsensor.h" +#include "gpio.h" +#include "link_defs.h" +#include "spi.h" +#include "system.h" +#include "timer.h" +#include "util.h" + +#include STRINGIFY(FP_SENSOR_PRIVATE) + +#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) +#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) + +#define FP_SENSOR_NAME STRINGIFY(FP_SENSOR_CONFIG) + +/* Minimum reset duration */ +#define FP_SENSOR_RESET_DURATION_US (10 * MSEC) +/* Maximum delay for the interrupt to be asserted after the sensor is reset */ +#define FP_SENSOR_IRQ_MAX_DELAY_US (5 * MSEC) +/* Maximum number of attempts to initialise the sensor */ +#define FP_SENSOR_MAX_INIT_ATTEMPTS 10 +/* Delay between failed attempts of fp_sensor_open() */ +#define FP_SENSOR_OPEN_DELAY_US (500 * MSEC) + +/* Decode internal error codes from FPC's sensor library */ +#define FPC_GET_INTERNAL_CODE(res) (((res) & 0x000fc000) >> 14) +/* There was a finger on the sensor when calibrating finger detect */ +#define FPC_INTERNAL_FINGER_DFD FPC_ERROR_INTERNAL_38 + +/* + * The sensor context is uncached as it contains the SPI buffers, + * the binary library assumes that it is aligned. + */ +static uint8_t ctx[FP_SENSOR_CONTEXT_SIZE] __uncached __aligned(4); +static bio_sensor_t bio_sensor; +static uint8_t enroll_ctx[FP_ALGORITHM_ENROLLMENT_SIZE]; + +/* recorded error flags */ +static uint16_t errors; + +/* Sensor description */ +static struct ec_response_fp_info fpc1145_info = { + /* Sensor identification */ + .vendor_id = FOURCC('F', 'P', 'C', ' '), + .product_id = 9, + .model_id = 1, + .version = 1, + /* Image frame characteristics */ + .frame_size = FP_SENSOR_IMAGE_SIZE, + .pixel_format = V4L2_PIX_FMT_GREY, + .width = FP_SENSOR_RES_X, + .height = FP_SENSOR_RES_Y, + .bpp = FP_SENSOR_RES_BPP, +}; + +/* Sensor IC commands */ +enum fpc_cmd { + FPC_CMD_STATUS = 0x14, + FPC_CMD_INT_STS = 0x18, + FPC_CMD_INT_CLR = 0x1C, + FPC_CMD_FINGER_QUERY = 0x20, + FPC_CMD_SLEEP = 0x28, + FPC_CMD_DEEPSLEEP = 0x2C, + FPC_CMD_SOFT_RESET = 0xF8, + FPC_CMD_HW_ID = 0xFC, +}; + +/* Maximum size of a sensor command SPI transfer */ +#define MAX_CMD_SPI_TRANSFER_SIZE 3 + +/* Uncached memory for the SPI transfer buffer */ +static uint8_t spi_buf[MAX_CMD_SPI_TRANSFER_SIZE] __uncached; + +static int fpc_send_cmd(const uint8_t cmd) +{ + spi_buf[0] = cmd; + return spi_transaction(SPI_FP_DEVICE, spi_buf, 1, spi_buf, + SPI_READBACK_ALL); +} + +void fp_sensor_low_power(void) +{ + /* + * TODO(b/117620462): verify that sleep mode is WAI (no increased + * latency, expected power consumption). + */ + if (0) + fpc_send_cmd(FPC_CMD_SLEEP); +} + +static int fpc_check_hwid(void) +{ + uint16_t id; + int rc; + + /* Clear previous occurences of relevant |errors| flags. */ + errors &= (~FP_ERROR_SPI_COMM & ~FP_ERROR_BAD_HWID); + + spi_buf[0] = FPC_CMD_HW_ID; + rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, + SPI_READBACK_ALL); + if (rc) { + CPRINTS("FPC ID read failed %d", rc); + errors |= FP_ERROR_SPI_COMM; + return EC_ERROR_HW_INTERNAL; + } + id = (spi_buf[1] << 8) | spi_buf[2]; + if ((id >> 4) != FP_SENSOR_HWID) { + CPRINTS("FPC unknown silicon 0x%04x", id); + errors |= FP_ERROR_BAD_HWID; + return EC_ERROR_HW_INTERNAL; + } + CPRINTS(FP_SENSOR_NAME " id 0x%04x", id); + + return EC_SUCCESS; +} + +static uint8_t fpc_read_clear_int(void) +{ + spi_buf[0] = FPC_CMD_INT_CLR; + spi_buf[1] = 0xff; + if (spi_transaction(SPI_FP_DEVICE, spi_buf, 2, spi_buf, + SPI_READBACK_ALL)) + return 0xff; + return spi_buf[1]; +} + +/* + * Toggle the h/w reset pins and clear any pending IRQs before initializing the + * sensor contexts. + * Returns: + * - EC_SUCCESS on success. + * - EC_ERROR_HW_INTERNAL on failure (and |errors| variable is updated where + * appropriate). + */ +static int fpc_pulse_hw_reset(void) +{ + int ret; + int rc = EC_SUCCESS; + /* Clear previous occurrence of possible error flags. */ + errors &= ~FP_ERROR_NO_IRQ; + + /* Ensure we pulse reset low to initiate the startup */ + gpio_set_level(GPIO_FP_RST_ODL, 0); + usleep(FP_SENSOR_RESET_DURATION_US); + gpio_set_level(GPIO_FP_RST_ODL, 1); + /* the IRQ line should be set high by the sensor */ + usleep(FP_SENSOR_IRQ_MAX_DELAY_US); + if (!gpio_get_level(GPIO_FPS_INT)) { + CPRINTS("Sensor IRQ not ready"); + errors |= FP_ERROR_NO_IRQ; + rc = EC_ERROR_HW_INTERNAL; + } + + /* Check the Hardware ID */ + ret = fpc_check_hwid(); + if (ret != EC_SUCCESS) { + CPRINTS("Failed to verify HW ID"); + rc = EC_ERROR_HW_INTERNAL; + } + + /* clear the pending 'ready' IRQ before enabling interrupts */ + fpc_read_clear_int(); + + return rc; +} + +/* Reset and initialize the sensor IC */ +int fp_sensor_init(void) +{ + int res; + int attempt; + + errors = FP_ERROR_DEAD_PIXELS_UNKNOWN; + + /* Release any previously held resources from earlier iterations */ + res = bio_sensor_destroy(bio_sensor); + if (res) + CPRINTS("FPC Sensor resources release failed: %d", res); + bio_sensor = NULL; + + res = bio_algorithm_exit(); + if (res) + CPRINTS("FPC Algorithm resources release failed: %d", res); + + /* Print the binary libfpsensor.a library version */ + CPRINTF("FPC libfpsensor.a v%s\n", fp_sensor_get_version()); + cflush(); + + attempt = 0; + do { + attempt++; + + res = fpc_pulse_hw_reset(); + if (res != EC_SUCCESS) { + /* In case of failure, retry after a delay. */ + CPRINTS("H/W sensor reset failed, error flags: 0x%x", + errors); + cflush(); + usleep(FP_SENSOR_OPEN_DELAY_US); + continue; + } + + /* + * Ensure that any previous context data is obliterated in case + * of a sensor reset. + */ + memset(ctx, 0, FP_SENSOR_CONTEXT_SIZE); + + res = fp_sensor_open(ctx, FP_SENSOR_CONTEXT_SIZE); + /* Flush messages from the PAL if any */ + cflush(); + CPRINTS("Sensor init (attempt %d): 0x%x", attempt, res); + /* + * Retry on failure. This typically happens if the user has left + * their finger on the sensor after powering up the device, DFD + * will fail in that case. We've seen other error modes in the + * field, retry in all cases to be more resilient. + */ + if (!res) + break; + usleep(FP_SENSOR_OPEN_DELAY_US); + } while (attempt < FP_SENSOR_MAX_INIT_ATTEMPTS); + if (res) + errors |= FP_ERROR_INIT_FAIL; + + res = bio_algorithm_init(); + /* the PAL might have spewed a lot of traces, ensure they are visible */ + cflush(); + CPRINTS("Algorithm init: 0x%x", res); + if (res < 0) + errors |= FP_ERROR_INIT_FAIL; + res = bio_sensor_create(&bio_sensor); + CPRINTS("Sensor create: 0x%x", res); + if (res < 0) + errors |= FP_ERROR_INIT_FAIL; + + /* Go back to low power */ + fp_sensor_low_power(); + + return EC_SUCCESS; +} + +/* Deinitialize the sensor IC */ +int fp_sensor_deinit(void) +{ + /* + * TODO(tomhughes): libfp doesn't have fp_sensor_close like BEP does. + * We'll need FPC to either add it or verify that we don't have the same + * problem with the libfp library as described in: + * b/124773209#comment46 + */ + return EC_SUCCESS; +} + +int fp_sensor_get_info(struct ec_response_fp_info *resp) +{ + int rc; + + memcpy(resp, &fpc1145_info, sizeof(*resp)); + + spi_buf[0] = FPC_CMD_HW_ID; + rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, + SPI_READBACK_ALL); + if (rc) + return EC_RES_ERROR; + resp->model_id = (spi_buf[1] << 8) | spi_buf[2]; + resp->errors = errors; + + return EC_SUCCESS; +} + +int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image, + int32_t *match_index, uint32_t *update_bitmap) +{ + return bio_template_image_match_list(templ, templ_count, image, + match_index, update_bitmap); +} + +int fp_enrollment_begin(void) +{ + int rc; + bio_enrollment_t p = enroll_ctx; + + rc = bio_enrollment_begin(bio_sensor, &p); + if (rc < 0) + CPRINTS("begin failed %d", rc); + return rc; +} + +int fp_enrollment_finish(void *templ) +{ + bio_template_t pt = templ; + + return bio_enrollment_finish(enroll_ctx, templ ? &pt : NULL); +} + +int fp_finger_enroll(uint8_t *image, int *completion) +{ + int rc = bio_enrollment_add_image(enroll_ctx, image); + + if (rc < 0) + return rc; + *completion = bio_enrollment_get_percent_complete(enroll_ctx); + return rc; +} diff --git a/driver/fingerprint/fpc/libfp/fpc_private.h b/driver/fingerprint/fpc/libfp/fpc_private.h new file mode 100644 index 0000000000..6ec09ee0ee --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc_private.h @@ -0,0 +1,104 @@ +/* Copyright 2018 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. + */ + +/* Private sensor interface */ + +#ifndef __CROS_EC_FPC_PRIVATE_H +#define __CROS_EC_FPC_PRIVATE_H + +/* External error codes from FPC's sensor library */ +enum fpc_error_code_external { + FPC_ERROR_NONE = 0, + FPC_ERROR_NOT_FOUND = 1, + FPC_ERROR_CAN_BE_USED_2 = 2, + FPC_ERROR_CAN_BE_USED_3 = 3, + FPC_ERROR_CAN_BE_USED_4 = 4, + FPC_ERROR_PAL = 5, + FPC_ERROR_IO = 6, + FPC_ERROR_CANCELLED = 7, + FPC_ERROR_UNKNOWN = 8, + FPC_ERROR_MEMORY = 9, + FPC_ERROR_PARAMETER = 10, + FPC_ERROR_TEST_FAILED = 11, + FPC_ERROR_TIMEDOUT = 12, + FPC_ERROR_SENSOR = 13, + FPC_ERROR_SPI = 14, + FPC_ERROR_NOT_SUPPORTED = 15, + FPC_ERROR_OTP = 16, + FPC_ERROR_STATE = 17, + FPC_ERROR_PN = 18, + FPC_ERROR_DEAD_PIXELS = 19, + FPC_ERROR_TEMPLATE_CORRUPTED = 20, + FPC_ERROR_CRC = 21, + FPC_ERROR_STORAGE = 22, /**< Errors related to storage **/ + FPC_ERROR_MAXIMUM_REACHED = 23, /**< The allowed maximum has been reached **/ + FPC_ERROR_MINIMUM_NOT_REACHED = 24, /**< The required minimum was not reached **/ + FPC_ERROR_SENSOR_LOW_COVERAGE = 25, /**< Minimum sensor coverage was not reached **/ + FPC_ERROR_SENSOR_LOW_QUALITY = 26, /**< Sensor image is considered low quality **/ + FPC_ERROR_SENSOR_FINGER_NOT_STABLE = 27, /**< Finger was not stable during image capture **/ +}; + +/* Internal error codes from FPC's sensor library */ +enum fpc_error_code_internal { + FPC_ERROR_INTERNAL_0 = 0, /* Indicates that no internal code was set. */ + FPC_ERROR_INTERNAL_1 = 1, /* Not supported by sensor. */ + FPC_ERROR_INTERNAL_2 = 2, /* Sensor got a NULL response (from other module). */ + FPC_ERROR_INTERNAL_3 = 3, /* Runtime config not supported by firmware. */ + FPC_ERROR_INTERNAL_4 = 4, /* CAC has not been created. */ + FPC_ERROR_INTERNAL_5 = 5, /* CAC returned an error to the sensor. */ + FPC_ERROR_INTERNAL_6 = 6, /* CAC fasttap image capture failed. */ + FPC_ERROR_INTERNAL_7 = 7, /* CAC fasttap image capture failed. */ + FPC_ERROR_INTERNAL_8 = 8, /* CAC Simple image capture failed. */ + FPC_ERROR_INTERNAL_9 = 9, /* CAC custom image capture failed. */ + FPC_ERROR_INTERNAL_10 = 10, /* CAC MQT image capture failed. */ + FPC_ERROR_INTERNAL_11 = 11, /* CAC PN image capture failed. */ + FPC_ERROR_INTERNAL_12 = 12, /* Reading CAC context size. */ + FPC_ERROR_INTERNAL_13 = 13, /* Reading CAC context size. */ + FPC_ERROR_INTERNAL_14 = 14, /* Sensor context invalid. */ + FPC_ERROR_INTERNAL_15 = 15, /* Buffer reference is invalid. */ + FPC_ERROR_INTERNAL_16 = 16, /* Buffer size reference is invalid. */ + FPC_ERROR_INTERNAL_17 = 17, /* Image data reference is invalid. */ + FPC_ERROR_INTERNAL_18 = 18, /* Capture type specified is invalid. */ + FPC_ERROR_INTERNAL_19 = 19, /* Capture config specified is invalid. */ + FPC_ERROR_INTERNAL_20 = 20, /* Sensor type in hw desc could not be extracted. */ + FPC_ERROR_INTERNAL_21 = 21, /* Failed to create BNC component. */ + FPC_ERROR_INTERNAL_22 = 22, /* BN calibration failed. */ + FPC_ERROR_INTERNAL_23 = 23, /* BN memory allocation failed. */ + FPC_ERROR_INTERNAL_24 = 24, /* Companion type in hw desc could not be extracted. */ + FPC_ERROR_INTERNAL_25 = 25, /* Coating type in hw desc could not be extracted. */ + FPC_ERROR_INTERNAL_26 = 26, /* Sensor mode type is invalid. */ + FPC_ERROR_INTERNAL_27 = 27, /* Wrong Sensor state in OTP read. */ + FPC_ERROR_INTERNAL_28 = 28, /* Mismatch of register size in overlay vs rrs. */ + FPC_ERROR_INTERNAL_29 = 29, /* Checkerboard capture failed. */ + FPC_ERROR_INTERNAL_30 = 30, /* Error converting to fpc_image in dp calibration. */ + FPC_ERROR_INTERNAL_31 = 31, /* Failed to capture reset pixel image. */ + FPC_ERROR_INTERNAL_32 = 32, /* API level not support in dp calibration. */ + FPC_ERROR_INTERNAL_33 = 33, /* The image data in parameter is invalid. */ + FPC_ERROR_INTERNAL_34 = 34, /* PAL delay function has failed. */ + FPC_ERROR_INTERNAL_35 = 35, /* AFD sensor commad did not complete. */ + FPC_ERROR_INTERNAL_36 = 36, /* AFD wrong runlevel detected after calibration. */ + FPC_ERROR_INTERNAL_37 = 37, /* Wrong rrs size. */ + FPC_ERROR_INTERNAL_38 = 38, /* There was a finger on the sensor when calibrating finger detect. */ + FPC_ERROR_INTERNAL_39 = 39, /* The calculated calibration value is larger than max. */ + FPC_ERROR_INTERNAL_40 = 40, /* The sensor fifo always underflows */ + FPC_ERROR_INTERNAL_41 = 41, /* The oscillator calibration resulted in a too high or low value */ + FPC_ERROR_INTERNAL_42 = 42, /* Sensor driver was opened with NULL configuration */ + FPC_ERROR_INTERNAL_43 = 43, /* Sensor driver as opened with NULL hw descriptor */ + FPC_ERROR_INTERNAL_44 = 44, /* Error occured during image drive test */ +}; + +/* FPC specific initialization function to fill their context */ +int fp_sensor_open(void *ctx, uint32_t ctx_size); + +/* + * Get library version code. + * version code contains three digits. x.y.z + * x - major version + * y - minor version + * z - build index + */ +const char *fp_sensor_get_version(void); + +#endif /* __CROS_EC_FPC_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c new file mode 100644 index 0000000000..35c07b464a --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c @@ -0,0 +1,60 @@ +/* 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. + */ +/* FPC Platform Abstraction Layer callbacks */ + +#include "common.h" +#include "console.h" +#include "fpsensor.h" +#include "fpc_sensor_pal.h" +#include "shared_mem.h" +#include "spi.h" +#include "timer.h" +#include "uart.h" +#include "util.h" + +#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) +#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) + +void fpc_pal_log_entry(const char *tag, int log_level, const char *format, ...) +{ + va_list args; + + va_start(args, format); + uart_puts(tag); + uart_vprintf(format, args); + va_end(args); +} + +int fpc_pal_delay_us(uint64_t us) +{ + if (us > 250) + usleep(us); + else + udelay(us); + return 0; +} + +int fpc_pal_spi_writeread(fpc_device_t device, uint8_t *tx_buf, uint8_t *rx_buf, + uint32_t size) +{ + return spi_transaction(SPI_FP_DEVICE, tx_buf, size, rx_buf, + SPI_READBACK_ALL); +} + +int fpc_pal_wait_irq(fpc_device_t device, fpc_pal_irq_t irq_type) +{ + /* TODO: b/72360575 */ + return EC_SUCCESS; /* just lie about it, libfpsensor prefers... */ +} + +int32_t FpcMalloc(void **data, size_t size) +{ + return shared_mem_acquire(size, (char **)data); +} + +void FpcFree(void **data) +{ + shared_mem_release(*data); +} diff --git a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h new file mode 100644 index 0000000000..78376863f1 --- /dev/null +++ b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h @@ -0,0 +1,118 @@ +/* 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. + */ + +#ifndef FPC_PAL_SENSOR_H_ +#define FPC_PAL_SENSOR_H_ + +#include <stdint.h> + +typedef void *fpc_device_t; + +/** + * @brief Used to describe an interrupt + */ +typedef enum { + IRQ_INT_TRIG = 0x01, /**< Internally triggered by sensor (fast interrupt) **/ + IRQ_EXT_TRIG = 0x02 /**< Externally triggered by event outside sensor (may take long time) **/ +} fpc_pal_irq_t; + +/** + * @brief Write sensor access buffer to SPI interface + * + * @param[in] device Client's device handle. + * @param[in] access_buffer Buffer holding data to write. + * @param[in] access_buffer_size Size of the access buffer. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_spi_write(fpc_device_t device, uint8_t *access_buffer, + uint32_t access_buffer_size); + +/** + * @brief Write and read sensor access buffer to SPI interface + * + * SPI transfers always write the same number of bytes as they read, + * hence the size of tx_buffer and rx_buffer must be the same. + * + * @param[in] device Client's device handle. + * @param[in] tx_buffer Buffer holding data to write. + * @param[in] rx_buffer Buffer where read data will be stored. + * @param[in] size Size of tx and rx buffer. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_spi_writeread(fpc_device_t device, uint8_t *tx_buffer, + uint8_t *rx_buffer, uint32_t size); + +/** + * @brief Wait for IRQ + * + * @param[in] device Client's device handle. + * @param[in] irq_type The expected IRQ type. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_wait_irq(fpc_device_t device, fpc_pal_irq_t irq_type); + +/** + * @brief Get time + * + * @param[out] time_us Timestamp in microseconds. + * + * Not all platforms have microsecond resolution. These should + * return time in terms of hole milliseconds. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_get_time(uint64_t *time_us); + +/** + * @brief Delay function + * + * @param[in] us Delay in microseconds. + * + * Not all platforms have microsecond resolution. These should + * delay in terms of hole milliseconds. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_delay_us(uint64_t us); + +/** + * @brief Get platform SPI clock frequency + * + * @param[in] device Client's device handle. + * @param[out] speed_hz SPI frequency in hertz. + * + * Required by platform for adaptive SPI calculations. + * + * @return 0 on success. + * negative value on error. + */ +int fpc_pal_spi_get_speed_hz(fpc_device_t device, uint32_t *speed_hz); + +/** + * @brief Print SDK log strings + * + * @param[in] tag sensor sdk log prefix + * @param[in] log_level FPC_SENSOR_SDK_LOG_LEVEL_DEBUG - debug print + * FPC_SENSOR_SDK_LOG_LEVEL_INFO - information print + * FPC_SENSOR_SDK_LOG_LEVEL_ERROR - error print + * @param[in] format the format specifier. + * @param[in] ... additional arguments. + * + */ +#define FPC_SENSOR_SDK_LOG_LEVEL_DEBUG (1) +#define FPC_SENSOR_SDK_LOG_LEVEL_INFO (2) +#define FPC_SENSOR_SDK_LOG_LEVEL_ERROR (3) +#define FPC_SENSOR_SDK_LOG_LEVEL_DISABLED (4) +void fpc_pal_log_entry(const char *tag, int log_level, const char *format, ...); + +#endif // FPC_PAL_SENSOR_H_ |