fpi-ssm: Make delayed actions cancellable

Add a GCancellable parameter to fpi_ssm_nex_state_delayed and
fpi_ssm_jump_to_state_delayed() so that it's possible to cancel an action
from the caller and in case the driver wants to cancel a delayed operation
when a device action has been cancelled.
This commit is contained in:
Marco Trevisan (Treviño) 2019-11-28 19:24:55 +01:00
parent bac6382f67
commit ff67bf5a16
8 changed files with 127 additions and 41 deletions

View file

@ -752,7 +752,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
if (self->calib_status == 0x00 && if (self->calib_status == 0x00 &&
self->last_read[0] == 0x01) self->last_read[0] == 0x01)
self->calib_status = 0x01; self->calib_status = 0x01;
fpi_ssm_next_state_delayed (ssm, 50); fpi_ssm_next_state_delayed (ssm, 50, NULL);
} }
break; break;

View file

@ -864,7 +864,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
} }
else else
{ {
fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT); fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL);
} }
break; break;
} }
@ -946,11 +946,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
} }
else if (!self->profile->auth_cr) else if (!self->profile->auth_cr)
{ {
fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10); fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL);
} }
else else
{ {
fpi_ssm_next_state_delayed (ssm, 10); fpi_ssm_next_state_delayed (ssm, 10, NULL);
} }
break; break;

View file

@ -608,7 +608,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
clear_data (self); clear_data (self);
/* Wait for probable vdev->active changing */ /* Wait for probable vdev->active changing */
fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT); fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL);
break; break;
case SSM_NEXT_RECEIVE: case SSM_NEXT_RECEIVE:
@ -627,7 +627,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
case SSM_WAIT_ANOTHER_SCAN: case SSM_WAIT_ANOTHER_SCAN:
/* Orange light is on now */ /* Orange light is on now */
fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT); fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT,
NULL);
break; break;
default: default:

View file

@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_0_SLEEP: case M_LOOP_0_SLEEP:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 50); fpi_ssm_next_state_delayed (ssm, 50, NULL);
break; break;
case M_LOOP_0_GET_STATE: case M_LOOP_0_GET_STATE:
@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
img_extract (ssm, dev); img_extract (ssm, dev);
/* Wait handling image */ /* Wait handling image */
fpi_ssm_next_state_delayed (ssm, 10); fpi_ssm_next_state_delayed (ssm, 10, NULL);
break; break;
case M_LOOP_0_CHECK_ACTION: case M_LOOP_0_CHECK_ACTION:
@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
if (vfs_finger_state (self) == VFS_FINGER_PRESENT) if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
{ {
fpi_image_device_report_finger_status (dev, TRUE); fpi_image_device_report_finger_status (dev, TRUE);
fpi_ssm_next_state_delayed (ssm, 250); fpi_ssm_next_state_delayed (ssm, 250, NULL);
} }
else else
{ {
@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_LOOP_1_SLEEP: case M_LOOP_1_SLEEP:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 10); fpi_ssm_next_state_delayed (ssm, 10, NULL);
break; break;
case M_LOOP_2_ABORT_PRINT: case M_LOOP_2_ABORT_PRINT:
@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait aborting */ /* Wait aborting */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 100); fpi_ssm_next_state_delayed (ssm, 100, NULL);
} }
else else
{ {
@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait aborting */ /* Wait aborting */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 100); fpi_ssm_next_state_delayed (ssm, 100, NULL);
} }
else else
{ {
@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
{ {
/* Wait removing finger */ /* Wait removing finger */
self->counter++; self->counter++;
fpi_ssm_next_state_delayed (ssm, 250); fpi_ssm_next_state_delayed (ssm, 250, NULL);
} }
else else
{ {

View file

@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_WAIT_PRINT: case M_WAIT_PRINT:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200); fpi_ssm_next_state_delayed (ssm, 200, NULL);
break; break;
case M_CHECK_PRINT: case M_CHECK_PRINT:
@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
case M_READ_PRINT_WAIT: case M_READ_PRINT_WAIT:
/* Wait fingerprint scanning */ /* Wait fingerprint scanning */
fpi_ssm_next_state_delayed (ssm, 200); fpi_ssm_next_state_delayed (ssm, 200, NULL);
break; break;
case M_READ_PRINT_POLL: case M_READ_PRINT_POLL:

View file

@ -704,7 +704,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
break; break;
case DEV_ACTIVATE_DATA_COMPLETE: case DEV_ACTIVATE_DATA_COMPLETE:
fpi_ssm_next_state_delayed (ssm, 1); fpi_ssm_next_state_delayed (ssm, 1, NULL);
break; break;
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:

View file

@ -88,6 +88,8 @@ struct _FpiSsm
int cur_state; int cur_state;
gboolean completed; gboolean completed;
GSource *timeout; GSource *timeout;
GCancellable *cancellable;
gulong cancellable_id;
GError *error; GError *error;
FpiSsmCompletedCallback callback; FpiSsmCompletedCallback callback;
FpiSsmHandlerCallback handler; FpiSsmHandlerCallback handler;
@ -155,6 +157,81 @@ fpi_ssm_get_data (FpiSsm *machine)
return machine->ssm_data; return machine->ssm_data;
} }
static void
fpi_ssm_clear_delayed_action (FpiSsm *machine)
{
if (machine->cancellable_id)
{
g_cancellable_disconnect (machine->cancellable, machine->cancellable_id);
machine->cancellable_id = 0;
}
g_clear_object (&machine->cancellable);
g_clear_pointer (&machine->timeout, g_source_destroy);
}
typedef struct _CancelledActionIdleData
{
gulong cancellable_id;
GCancellable *cancellable;
} CancelledActionIdleData;
static gboolean
on_delayed_action_cancelled_idle (gpointer user_data)
{
CancelledActionIdleData *data = user_data;
g_cancellable_disconnect (data->cancellable, data->cancellable_id);
g_object_unref (data->cancellable);
g_free (data);
return G_SOURCE_REMOVE;
}
static void
on_delayed_action_cancelled (GCancellable *cancellable,
FpiSsm *machine)
{
CancelledActionIdleData *data;
g_clear_pointer (&machine->timeout, g_source_destroy);
data = g_new0 (CancelledActionIdleData, 1);
data->cancellable = g_steal_pointer (&machine->cancellable);
data->cancellable_id = machine->cancellable_id;
machine->cancellable_id = 0;
g_idle_add_full (G_PRIORITY_HIGH_IDLE, on_delayed_action_cancelled_idle,
data, NULL);
}
static void
fpi_ssm_set_delayed_action_timeout (FpiSsm *machine,
int delay,
FpTimeoutFunc callback,
GCancellable *cancellable,
gpointer user_data,
GDestroyNotify destroy_func)
{
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
fpi_ssm_clear_delayed_action (machine);
if (cancellable != NULL)
{
g_set_object (&machine->cancellable, cancellable);
machine->cancellable_id =
g_cancellable_connect (machine->cancellable,
G_CALLBACK (on_delayed_action_cancelled),
machine, NULL);
}
machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback,
user_data, destroy_func);
}
/** /**
* fpi_ssm_free: * fpi_ssm_free:
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
@ -173,7 +250,7 @@ fpi_ssm_free (FpiSsm *machine)
if (machine->ssm_data_destroy) if (machine->ssm_data_destroy)
g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy);
g_clear_pointer (&machine->error, g_error_free); g_clear_pointer (&machine->error, g_error_free);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_clear_delayed_action (machine);
g_free (machine); g_free (machine);
} }
@ -254,7 +331,8 @@ fpi_ssm_mark_completed (FpiSsm *machine)
BUG_ON (machine->completed); BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL); BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_clear_delayed_action (machine);
machine->completed = TRUE; machine->completed = TRUE;
if (machine->error) if (machine->error)
@ -309,7 +387,7 @@ fpi_ssm_next_state (FpiSsm *machine)
BUG_ON (machine->completed); BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL); BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_clear_delayed_action (machine);
machine->cur_state++; machine->cur_state++;
if (machine->cur_state == machine->nr_states) if (machine->cur_state == machine->nr_states)
@ -325,7 +403,7 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
BUG_ON (machine->completed); BUG_ON (machine->completed);
BUG_ON (machine->timeout == NULL); BUG_ON (machine->timeout == NULL);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_clear_delayed_action (machine);
} }
static void static void
@ -342,25 +420,26 @@ on_device_timeout_next_state (FpDevice *dev,
* fpi_ssm_next_state_delayed: * fpi_ssm_next_state_delayed:
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* @delay: the milliseconds to wait before switching to the next state * @delay: the milliseconds to wait before switching to the next state
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
* *
* Iterate to next state of a state machine with a delay of @delay ms. If the * Iterate to next state of a state machine with a delay of @delay ms. If the
* current state is the last state, then the state machine will be marked as * current state is the last state, then the state machine will be marked as
* completed, as if calling fpi_ssm_mark_completed(). * completed, as if calling fpi_ssm_mark_completed().
* Passing a valid #GCancellable will cause the action to be cancelled when
* @cancellable is.
*/ */
void void
fpi_ssm_next_state_delayed (FpiSsm *machine, fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay) int delay,
GCancellable *cancellable)
{ {
g_autofree char *source_name = NULL; g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL); g_return_if_fail (machine != NULL);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_set_delayed_action_timeout (machine, delay,
machine->timeout = fpi_device_add_timeout (machine->dev, delay, on_device_timeout_next_state, cancellable,
on_device_timeout_next_state, machine, NULL);
machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d", source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
fp_device_get_device_id (machine->dev), fp_device_get_device_id (machine->dev),
@ -384,7 +463,8 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
BUG_ON (state < 0 || state >= machine->nr_states); BUG_ON (state < 0 || state >= machine->nr_states);
BUG_ON (machine->timeout != NULL); BUG_ON (machine->timeout != NULL);
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_clear_delayed_action (machine);
machine->cur_state = state; machine->cur_state = state;
__ssm_call_handler (machine); __ssm_call_handler (machine);
} }
@ -410,14 +490,18 @@ on_device_timeout_jump_to_state (FpDevice *dev,
* @machine: an #FpiSsm state machine * @machine: an #FpiSsm state machine
* @state: the state to jump to * @state: the state to jump to
* @delay: the milliseconds to wait before switching to @state state * @delay: the milliseconds to wait before switching to @state state
* @cancellable: (nullable): a #GCancellable to cancel the delayed operation
* *
* Jump to the @state state with a delay of @delay milliseconds, bypassing * Jump to the @state state with a delay of @delay milliseconds, bypassing
* intermediary states. * intermediary states.
* Passing a valid #GCancellable will cause the action to be cancelled when
* @cancellable is.
*/ */
void void
fpi_ssm_jump_to_state_delayed (FpiSsm *machine, fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
int state, int state,
int delay) int delay,
GCancellable *cancellable)
{ {
FpiSsmJumpToStateDelayedData *data; FpiSsmJumpToStateDelayedData *data;
g_autofree char *source_name = NULL; g_autofree char *source_name = NULL;
@ -430,10 +514,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
data->machine = machine; data->machine = machine;
data->next_state = state; data->next_state = state;
g_clear_pointer (&machine->timeout, g_source_destroy); fpi_ssm_set_delayed_action_timeout (machine, delay,
machine->timeout = fpi_device_add_timeout (machine->dev, delay, on_device_timeout_jump_to_state,
on_device_timeout_jump_to_state, cancellable, data, g_free);
data, g_free);
source_name = g_strdup_printf ("[%s] ssm %p jump to state %d", source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
fp_device_get_device_id (machine->dev), fp_device_get_device_id (machine->dev),

View file

@ -73,11 +73,13 @@ void fpi_ssm_start_subsm (FpiSsm *parent,
void fpi_ssm_next_state (FpiSsm *machine); void fpi_ssm_next_state (FpiSsm *machine);
void fpi_ssm_jump_to_state (FpiSsm *machine, void fpi_ssm_jump_to_state (FpiSsm *machine,
int state); int state);
void fpi_ssm_next_state_delayed (FpiSsm *machine, void fpi_ssm_next_state_delayed (FpiSsm *machine,
int delay); int delay,
void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, GCancellable *cancellable);
int state, void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
int delay); int state,
int delay,
GCancellable *cancellable);
void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine); void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
void fpi_ssm_mark_completed (FpiSsm *machine); void fpi_ssm_mark_completed (FpiSsm *machine);
void fpi_ssm_mark_failed (FpiSsm *machine, void fpi_ssm_mark_failed (FpiSsm *machine,