diff options
Diffstat (limited to 'common/physical_presence.c')
-rw-r--r-- | common/physical_presence.c | 326 |
1 files changed, 0 insertions, 326 deletions
diff --git a/common/physical_presence.c b/common/physical_presence.c deleted file mode 100644 index 5fa97e1218..0000000000 --- a/common/physical_presence.c +++ /dev/null @@ -1,326 +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. - * - * Physical presence detect state machine - */ - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "physical_presence.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_CCD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_CCD, format, ## args) - -#ifdef CONFIG_PHYSICAL_PRESENCE_DEBUG_UNSAFE -/* More lenient physical presence for dev builds */ -#define PP_SHORT_PRESS_COUNT 3 -#define PP_SHORT_PRESS_MIN_INTERVAL_US (100 * MSEC) -#define PP_SHORT_PRESS_MAX_INTERVAL_US (15 * SECOND) -#define PP_LONG_PRESS_COUNT (PP_SHORT_PRESS_COUNT + 2) -#define PP_LONG_PRESS_MIN_INTERVAL_US (2 * SECOND) -#define PP_LONG_PRESS_MAX_INTERVAL_US (300 * SECOND) -#else -/* Stricter physical presence for non-dev builds */ -#define PP_SHORT_PRESS_COUNT 5 -#define PP_SHORT_PRESS_MIN_INTERVAL_US (100 * MSEC) -#define PP_SHORT_PRESS_MAX_INTERVAL_US (5 * SECOND) -#define PP_LONG_PRESS_COUNT (PP_SHORT_PRESS_COUNT + 4) -#define PP_LONG_PRESS_MIN_INTERVAL_US (60 * SECOND) -#define PP_LONG_PRESS_MAX_INTERVAL_US (300 * SECOND) -#endif - -enum pp_detect_state { - PP_DETECT_IDLE = 0, - PP_DETECT_AWAITING_PRESS, - PP_DETECT_BETWEEN_PRESSES, - PP_DETECT_FINISHING, - PP_DETECT_ABORT -}; - -/* Physical presence state machine data */ -static enum pp_detect_state pp_detect_state; -static void (*pp_detect_callback)(void); -static uint8_t pp_press_count; -static uint8_t pp_press_count_needed; -static uint64_t pp_last_press; /* Time of last press */ - -/* - * We need a mutex because physical_detect_start() and physical_detect_abort() - * could be called from multiple threads (TPM or console). And either of those - * could preempt the deferred functions for the state machine which run in the - * hook task. - */ -static struct mutex pp_mutex; - -static int pp_detect_in_progress(void) -{ - return ((pp_detect_state == PP_DETECT_AWAITING_PRESS) || - (pp_detect_state == PP_DETECT_BETWEEN_PRESSES)); -} - -/******************************************************************************/ -/* - * Deferred functions - * - * These are called by the hook task, so can't preempt each other. But they - * could be preempted by calls to physical_presence_start() or - * physical_presence_abort(). - */ - -/** - * Clean up at end of physical detect sequence. - */ -static void physical_detect_done(void) -{ - /* - * Note that calling physical_detect_abort() from another thread after - * the start of physical_detect_done() but before mutex_lock() will - * result in another call to physical_detect_done() being queued up. - * That's harmless, because we go back to PP_DETECT_IDLE at the end of - * this call, so the second call will simply drop through without - * calling pp_detect_callback(). - */ - mutex_lock(&pp_mutex); - - if (!pp_detect_in_progress()) { - CPRINTF("\nPhysical presence check aborted.\n"); - pp_detect_callback = NULL; - } else if (pp_press_count < pp_press_count_needed) { - CPRINTF("\nPhysical presence check timeout.\n"); - pp_detect_callback = NULL; - } - - pp_detect_state = PP_DETECT_FINISHING; - mutex_unlock(&pp_mutex); - - /* No longer care about button presses */ - board_physical_presence_enable(0); - - /* - * Call the callback function. Do this outside the mutex, because the - * callback may take a while. If we kept holding the mutex, then calls - * to physical_detect_abort() or physical_detect_start() during the - * callback would block instead of simply failing. - */ - if (pp_detect_callback) { - CPRINTS("PP callback"); - pp_detect_callback(); - pp_detect_callback = NULL; - } - - /* Now go to idle */ - mutex_lock(&pp_mutex); - pp_detect_state = PP_DETECT_IDLE; - mutex_unlock(&pp_mutex); -} -DECLARE_DEFERRED(physical_detect_done); - -/** - * Print a prompt when we've hit the minimum wait time - */ -static void physical_detect_prompt(void) -{ - pp_detect_state = PP_DETECT_AWAITING_PRESS; - CPRINTF("\n\nPress the physical button now!\n\n"); -} -DECLARE_DEFERRED(physical_detect_prompt); - -/** - * Handle a physical present button press - * - * This is implemented as a deferred function so it can use the mutex. - */ -static void physical_detect_check_press(void) -{ - uint64_t now = get_time().val; - uint64_t dt = now - pp_last_press; - - mutex_lock(&pp_mutex); - - CPRINTS("PP press dt=%.6lld", dt); - - /* If we no longer care about presses, ignore them */ - if (!pp_detect_in_progress()) - goto pdpress_exit; - - /* Ignore extra presses we don't need */ - if (pp_press_count >= pp_press_count_needed) - goto pdpress_exit; - - /* Ignore presses outside the expected interval */ - if (pp_press_count < PP_SHORT_PRESS_COUNT) { - if (dt < PP_SHORT_PRESS_MIN_INTERVAL_US) { - CPRINTS("PP S too soon"); - goto pdpress_exit; - } - if (dt > PP_SHORT_PRESS_MAX_INTERVAL_US) { - CPRINTS("PP S too late"); - goto pdpress_exit; - } - } else { - if (dt < PP_LONG_PRESS_MIN_INTERVAL_US) { - CPRINTS("PP L too soon"); - goto pdpress_exit; - } - if (dt > PP_LONG_PRESS_MAX_INTERVAL_US) { - CPRINTS("PP L too late"); - goto pdpress_exit; - } - } - - /* Ok, we need this press */ - CPRINTS("PP press counted!"); - pp_detect_state = PP_DETECT_BETWEEN_PRESSES; - pp_last_press = now; - pp_press_count++; - - /* Set up call to done handler for timeout or actually done */ - if (pp_press_count == pp_press_count_needed) { - /* Done, so call right away */ - hook_call_deferred(&physical_detect_done_data, 0); - } else if (pp_press_count < PP_SHORT_PRESS_COUNT) { - hook_call_deferred(&physical_detect_prompt_data, - PP_SHORT_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_SHORT_PRESS_MAX_INTERVAL_US); - } else { - CPRINTF("Another press will be required soon.\n"); - dt = PP_LONG_PRESS_MAX_INTERVAL_US; - hook_call_deferred(&physical_detect_prompt_data, - PP_LONG_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_LONG_PRESS_MAX_INTERVAL_US); - } - -pdpress_exit: - mutex_unlock(&pp_mutex); -} -DECLARE_DEFERRED(physical_detect_check_press); - -/******************************************************************************/ -/* Interface */ - -int physical_detect_start(int is_long, void (*callback)(void)) -{ - mutex_lock(&pp_mutex); - - /* Fail if detection is already in progress */ - if (pp_detect_state != PP_DETECT_IDLE) { - mutex_unlock(&pp_mutex); - return EC_ERROR_BUSY; - } - - pp_press_count_needed = is_long ? PP_LONG_PRESS_COUNT : - PP_SHORT_PRESS_COUNT; - pp_press_count = 0; - pp_last_press = get_time().val; - pp_detect_callback = callback; - pp_detect_state = PP_DETECT_BETWEEN_PRESSES; - mutex_unlock(&pp_mutex); - - /* Start capturing button presses */ - hook_call_deferred(&physical_detect_check_press_data, -1); - board_physical_presence_enable(1); - - CPRINTS("PP start %s", is_long ? "long" : "short"); - - /* Initial timeout is for a short press */ - hook_call_deferred(&physical_detect_prompt_data, - PP_SHORT_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_SHORT_PRESS_MAX_INTERVAL_US); - - return EC_SUCCESS; -} - -int physical_detect_busy(void) -{ - return pp_detect_state != PP_DETECT_IDLE; -} - -void physical_detect_abort(void) -{ - mutex_lock(&pp_mutex); - if (pp_detect_in_progress()) { - CPRINTS("PP abort"); - pp_detect_state = PP_DETECT_ABORT; - /* Speed up call to done */ - hook_call_deferred(&physical_detect_prompt_data, -1); - hook_call_deferred(&physical_detect_check_press_data, -1); - hook_call_deferred(&physical_detect_done_data, 0); - } - mutex_unlock(&pp_mutex); -} - -int physical_detect_press(void) -{ - /* Ignore presses if we're idle */ - if (pp_detect_state == PP_DETECT_IDLE) - return EC_ERROR_NOT_HANDLED; - - /* Call the deferred function to do the work */ - hook_call_deferred(&physical_detect_check_press_data, 0); - return EC_SUCCESS; -} - -enum pp_fsm_state physical_presense_fsm_state(void) -{ - switch (pp_detect_state) { - case PP_DETECT_AWAITING_PRESS: - return PP_AWAITING_PRESS; - case PP_DETECT_BETWEEN_PRESSES: - return PP_BETWEEN_PRESSES; - default: - break; - } - - return PP_OTHER; -} - -#ifdef CONFIG_PHYSICAL_PRESENCE_DEBUG_UNSAFE - -/** - * Test callback function - */ -static void pp_test_callback(void) -{ - ccprintf("\nPhysical presence good\n"); -} - -/** - * Test physical presence. - */ -static int command_ppresence(int argc, char **argv) -{ - /* Print current status */ - ccprintf("PP state: %d, %d/%d, dt=%.6lld\n", - pp_detect_state, pp_press_count, pp_press_count_needed, - get_time().val - pp_last_press); - - /* With no args, simulate a button press */ - if (argc < 2) { - physical_detect_press(); - return EC_SUCCESS; - } - - if (!strcasecmp(argv[1], "short")) { - return physical_detect_start(0, pp_test_callback); - } else if (!strcasecmp(argv[1], "long")) { - return physical_detect_start(1, pp_test_callback); - } else if (!strcasecmp(argv[1], "abort")) { - physical_detect_abort(); - return EC_SUCCESS; - } else { - return EC_ERROR_PARAM1; - } -} -DECLARE_SAFE_CONSOLE_COMMAND(ppresence, command_ppresence, - "[short | long | abort]", - "Test physical presence press or sequence"); - -#endif |