| /* Copyright 2024 The ChromiumOS Authors |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "mock_fingerprint_algorithm.h" |
| |
| #include <zephyr/device.h> |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/emul.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/drivers/gpio/gpio_emul.h> |
| #include <zephyr/fff.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/ztest.h> |
| #include <zephyr/ztest_assert.h> |
| |
| #include <drivers/fingerprint.h> |
| #include <drivers/fingerprint_sim.h> |
| #include <ec_commands.h> |
| #include <ec_tasks.h> |
| #include <fpsensor/fpsensor_state.h> |
| #include <host_command.h> |
| |
| DEFINE_FFF_GLOBALS; |
| |
| FAKE_VALUE_FUNC(int, mkbp_send_event, uint8_t); |
| |
| #define fp_sim DEVICE_DT_GET(DT_CHOSEN(cros_fp_fingerprint_sensor)) |
| |
| static const size_t test_info_buffer_size = |
| sizeof(struct ec_response_fp_info_v3) + |
| sizeof(struct fp_image_frame_params_v2) * FP_MAX_CAPTURE_TYPES; |
| static uint8_t buffer[test_info_buffer_size]; |
| static struct ec_response_fp_info_v3 *test_info_buffer = |
| (struct ec_response_fp_info_v3 *)buffer; |
| |
| ZTEST_USER(fpsensor_init, test_tpm_seed_init) |
| { |
| struct ec_response_fp_encryption_status status; |
| struct ec_params_fp_seed params = { |
| .struct_version = 4, |
| .reserved = 0, |
| .seed = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, |
| }; |
| |
| /* Get FP encryption flags. */ |
| zassert_ok(ec_cmd_fp_encryption_status(NULL, &status)); |
| |
| /* Confirm TPM seed is not set */ |
| zassert_true(status.valid_flags & FP_ENC_STATUS_SEED_SET); |
| zassert_false(status.status & FP_ENC_STATUS_SEED_SET); |
| |
| /* Set TPM seed. */ |
| zassert_ok(ec_cmd_fp_seed(NULL, ¶ms)); |
| |
| /* Get FP encryption flags. */ |
| zassert_ok(ec_cmd_fp_encryption_status(NULL, &status)); |
| |
| /* Confirm that FP_ENC_STATUS_SEED_SET is set. */ |
| zassert_true(status.valid_flags & FP_ENC_STATUS_SEED_SET); |
| zassert_true(status.status & FP_ENC_STATUS_SEED_SET); |
| |
| /* Try to set TPM seed once again (should fail). */ |
| zassert_equal(EC_RES_ACCESS_DENIED, ec_cmd_fp_seed(NULL, ¶ms)); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_tpm_seed_invalid) |
| { |
| struct ec_params_fp_seed params = { |
| /* 0 is not a valid structure version. */ |
| .struct_version = 0, |
| .reserved = 0, |
| .seed = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
| 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, |
| }; |
| |
| /* Try to set TPM seed (should fail). */ |
| zassert_equal(EC_RES_INVALID_PARAM, ec_cmd_fp_seed(NULL, ¶ms)); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_set_fp_context) |
| { |
| struct ec_params_fp_context_v1 params = { |
| .action = FP_CONTEXT_ASYNC, |
| .userid = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 }, |
| }; |
| struct ec_response_fp_encryption_status status; |
| |
| /* Set context (asynchronously). */ |
| zassert_ok(ec_cmd_fp_context_v1(NULL, ¶ms)); |
| |
| /* Now any attempt to set context should return EC_RES_BUSY. */ |
| zassert_equal(EC_RES_BUSY, ec_cmd_fp_context_v1(NULL, ¶ms)); |
| |
| /* Now any attempt to get command result should return EC_RES_BUSY. */ |
| params.action = FP_CONTEXT_GET_RESULT; |
| zassert_equal(EC_RES_BUSY, ec_cmd_fp_context_v1(NULL, ¶ms)); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Get command result. */ |
| zassert_ok(ec_cmd_fp_context_v1(NULL, ¶ms)); |
| |
| /* Get FP encryption flags. */ |
| zassert_ok(ec_cmd_fp_encryption_status(NULL, &status)); |
| |
| /* Confirm that FP_CONTEXT_USER_ID_SET is set. */ |
| zassert_true(status.status & FP_CONTEXT_USER_ID_SET); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_maintenance_mode_dead_pixel_3) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_SENSOR_MAINTENANCE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| const int dead_pixels = 3; |
| |
| /* Confirm that number of dead pixels is unknown. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal( |
| FP_ERROR_DEAD_PIXELS(test_info_buffer->sensor_info.errors), |
| FP_ERROR_DEAD_PIXELS_UNKNOWN); |
| |
| fingerprint_get_state(fp_sim, &state); |
| state.bad_pixels = dead_pixels; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Change fingerprint mode to maintenance. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Check that maintenance was run. */ |
| fingerprint_get_state(fp_sim, &state); |
| zassert_true(state.maintenance_ran); |
| |
| /* Confirm that number of dead pixels is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal( |
| FP_ERROR_DEAD_PIXELS(test_info_buffer->sensor_info.errors), |
| dead_pixels); |
| |
| /* |
| * Confirm that maintenance flag is not set after the maintenance |
| * operation is finished. |
| */ |
| params.mode = FP_MODE_DONT_CHANGE; |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_false(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_maintenance_mode_dead_pixel_max_plus_2) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_SENSOR_MAINTENANCE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| fingerprint_get_state(fp_sim, &state); |
| state.bad_pixels = FP_ERROR_DEAD_PIXELS_MAX + 2; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Change fingerprint mode to maintenance. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Check that maintenance was run. */ |
| fingerprint_get_state(fp_sim, &state); |
| zassert_true(state.maintenance_ran); |
| |
| /* Confirm that number of dead pixels is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal( |
| FP_ERROR_DEAD_PIXELS(test_info_buffer->sensor_info.errors), |
| FP_ERROR_DEAD_PIXELS_MAX); |
| |
| /* |
| * Confirm that maintenance flag is not set after the maintenance |
| * operation is finished. |
| */ |
| params.mode = FP_MODE_DONT_CHANGE; |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_false(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_maintenance_mode_dead_pixel_max) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_SENSOR_MAINTENANCE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| fingerprint_get_state(fp_sim, &state); |
| state.bad_pixels = FP_ERROR_DEAD_PIXELS_MAX; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Change fingerprint mode to maintenance. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Check that maintenance was run. */ |
| fingerprint_get_state(fp_sim, &state); |
| zassert_true(state.maintenance_ran); |
| |
| /* Confirm that number of dead pixels is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal( |
| FP_ERROR_DEAD_PIXELS(test_info_buffer->sensor_info.errors), |
| FP_ERROR_DEAD_PIXELS_MAX); |
| |
| /* |
| * Confirm that maintenance flag is not set after the maintenance |
| * operation is finished. |
| */ |
| params.mode = FP_MODE_DONT_CHANGE; |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_false(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| } |
| |
| ZTEST_USER(fpsensor_init, test_maintenance_mode_dead_pixel_max_minus_1) |
| { |
| struct ec_params_fp_mode params = { |
| .mode = FP_MODE_SENSOR_MAINTENANCE, |
| }; |
| struct ec_response_fp_mode response; |
| struct fingerprint_sensor_state state; |
| |
| fingerprint_get_state(fp_sim, &state); |
| state.bad_pixels = FP_ERROR_DEAD_PIXELS_MAX - 1; |
| fingerprint_set_state(fp_sim, &state); |
| |
| /* Change fingerprint mode to maintenance. */ |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_true(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| /* Check that maintenance was run. */ |
| fingerprint_get_state(fp_sim, &state); |
| zassert_true(state.maintenance_ran); |
| |
| /* Confirm that number of dead pixels is correct. */ |
| zassert_ok(ec_cmd_fp_info_v3(NULL, test_info_buffer, |
| test_info_buffer_size)); |
| zassert_equal( |
| FP_ERROR_DEAD_PIXELS(test_info_buffer->sensor_info.errors), |
| FP_ERROR_DEAD_PIXELS_MAX - 1); |
| |
| /* |
| * Confirm that maintenance flag is not set after the maintenance |
| * operation is finished. |
| */ |
| params.mode = FP_MODE_DONT_CHANGE; |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_false(response.mode & FP_MODE_SENSOR_MAINTENANCE); |
| } |
| |
| static void *fpsensor_setup(void) |
| { |
| /* Start shimmed tasks. */ |
| start_ec_tasks(); |
| k_msleep(100); |
| |
| return NULL; |
| } |
| |
| static void fpsensor_before(void *f) |
| { |
| struct fingerprint_sensor_state state = { |
| .bad_pixels = 0, |
| .maintenance_ran = false, |
| .detect_mode = false, |
| .low_power_mode = false, |
| .finger_state = FINGERPRINT_FINGER_STATE_NONE, |
| .init_result = 0, |
| .deinit_result = 0, |
| .config_result = 0, |
| .get_info_result = 0, |
| .acquire_image_result = FINGERPRINT_SENSOR_SCAN_GOOD, |
| .last_acquire_image_mode = -1, |
| }; |
| struct ec_params_fp_mode params = { |
| .mode = 0, |
| }; |
| struct ec_response_fp_mode response; |
| |
| zassert_ok(ec_cmd_fp_mode(NULL, ¶ms, &response)); |
| zassert_equal(response.mode, 0); |
| |
| /* Give opportunity for fpsensor task to change mode. */ |
| k_msleep(1); |
| |
| fingerprint_set_state(fp_sim, &state); |
| RESET_FAKE(mkbp_send_event); |
| } |
| |
| ZTEST_SUITE(fpsensor_init, NULL, fpsensor_setup, fpsensor_before, NULL, NULL); |