mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
lib: Major rewrite of the libfprint core and API
This is a rewrite of the core based on GObject and Gio. This commit breaks the build in a lot of ways, but basic functionality will start working again with the next commits.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Functions to assist with asynchronous driver <---> library communications
|
||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -17,13 +18,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "drv"
|
||||
#define FP_COMPONENT "SSM"
|
||||
|
||||
#include "fp_internal.h"
|
||||
#include "drivers_api.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**
|
||||
* SECTION:fpi-ssm
|
||||
@@ -32,7 +31,7 @@
|
||||
*
|
||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
||||
* In most cases, the state machine is entirely linear - you only go to the
|
||||
* next state, you never jump or go backwards. The #fpi_ssm functions help you
|
||||
* next state, you never jump or go backwards. The #FpiSsm functions help you
|
||||
* implement such a machine.
|
||||
*
|
||||
* e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4`
|
||||
@@ -72,20 +71,21 @@
|
||||
* upon success (or fails).
|
||||
*
|
||||
* Your completion callback should examine the return value of
|
||||
* fpi_ssm_get_error() in order to determine whether the #fpi_ssm completed or
|
||||
* fpi_ssm_get_error() in ordater to determine whether the #FpiSsm completed or
|
||||
* failed. An error code of zero indicates successful completion.
|
||||
*/
|
||||
|
||||
struct fpi_ssm {
|
||||
struct fp_dev *dev;
|
||||
fpi_ssm *parentsm;
|
||||
void *user_data;
|
||||
int nr_states;
|
||||
int cur_state;
|
||||
gboolean completed;
|
||||
int error;
|
||||
ssm_completed_fn callback;
|
||||
ssm_handler_fn handler;
|
||||
struct _FpiSsm
|
||||
{
|
||||
FpDevice *dev;
|
||||
FpiSsm *parentsm;
|
||||
void *user_data;
|
||||
int nr_states;
|
||||
int cur_state;
|
||||
gboolean completed;
|
||||
GError *error;
|
||||
FpiSsmCompletedCallback callback;
|
||||
FpiSsmHandlerCallback handler;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -98,28 +98,30 @@ struct fpi_ssm {
|
||||
* Allocate a new ssm, with @nr_states states. The @handler callback
|
||||
* will be called after each state transition.
|
||||
*
|
||||
* Returns: a new #fpi_ssm state machine
|
||||
* Returns: a new #FpiSsm state machine
|
||||
*/
|
||||
fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||
ssm_handler_fn handler,
|
||||
int nr_states,
|
||||
void *user_data)
|
||||
FpiSsm *
|
||||
fpi_ssm_new (FpDevice *dev,
|
||||
FpiSsmHandlerCallback handler,
|
||||
int nr_states,
|
||||
void *user_data)
|
||||
{
|
||||
fpi_ssm *machine;
|
||||
BUG_ON(nr_states < 1);
|
||||
FpiSsm *machine;
|
||||
|
||||
machine = g_malloc0(sizeof(*machine));
|
||||
machine->handler = handler;
|
||||
machine->nr_states = nr_states;
|
||||
machine->dev = dev;
|
||||
machine->completed = TRUE;
|
||||
machine->user_data = user_data;
|
||||
return machine;
|
||||
BUG_ON (nr_states < 1);
|
||||
|
||||
machine = g_malloc0 (sizeof (*machine));
|
||||
machine->handler = handler;
|
||||
machine->nr_states = nr_states;
|
||||
machine->dev = dev;
|
||||
machine->completed = TRUE;
|
||||
machine->user_data = user_data;
|
||||
return machine;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_user_data:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Retrieve the pointer to user data set when fpi_ssm_new()
|
||||
* is called.
|
||||
@@ -127,66 +129,73 @@ fpi_ssm *fpi_ssm_new(struct fp_dev *dev,
|
||||
* Returns: a pointer
|
||||
*/
|
||||
void *
|
||||
fpi_ssm_get_user_data(fpi_ssm *machine)
|
||||
fpi_ssm_get_user_data (FpiSsm *machine)
|
||||
{
|
||||
return machine->user_data;
|
||||
return machine->user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_free:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Frees a state machine. This does not call any error or success
|
||||
* callbacks, so you need to do this yourself.
|
||||
*/
|
||||
void fpi_ssm_free(fpi_ssm *machine)
|
||||
void
|
||||
fpi_ssm_free (FpiSsm *machine)
|
||||
{
|
||||
if (!machine)
|
||||
return;
|
||||
g_free(machine);
|
||||
if (!machine)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&machine->error, g_error_free);
|
||||
g_free (machine);
|
||||
}
|
||||
|
||||
/* Invoke the state handler */
|
||||
static void __ssm_call_handler(fpi_ssm *machine)
|
||||
static void
|
||||
__ssm_call_handler (FpiSsm *machine)
|
||||
{
|
||||
fp_dbg("%p entering state %d", machine, machine->cur_state);
|
||||
machine->handler(machine, machine->dev, machine->user_data);
|
||||
fp_dbg ("%p entering state %d", machine, machine->cur_state);
|
||||
machine->handler (machine, machine->dev, machine->user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_start:
|
||||
* @ssm: an #fpi_ssm state machine
|
||||
* @callback: the #ssm_completed_fn callback to call on completion
|
||||
* @ssm: an #FpiSsm state machine
|
||||
* @callback: the #FpiSsmCompletedCallback callback to call on completion
|
||||
*
|
||||
* Starts a state machine. You can also use this function to restart
|
||||
* a completed or failed state machine. The @callback will be called
|
||||
* on completion.
|
||||
*/
|
||||
void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback)
|
||||
void
|
||||
fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
|
||||
{
|
||||
BUG_ON(!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
ssm->completed = FALSE;
|
||||
ssm->error = 0;
|
||||
__ssm_call_handler(ssm);
|
||||
BUG_ON (!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
ssm->completed = FALSE;
|
||||
ssm->error = NULL;
|
||||
__ssm_call_handler (ssm);
|
||||
}
|
||||
|
||||
static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
static void
|
||||
__subsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error)
|
||||
{
|
||||
fpi_ssm *parent = ssm->parentsm;
|
||||
BUG_ON(!parent);
|
||||
if (ssm->error)
|
||||
fpi_ssm_mark_failed(parent, ssm->error);
|
||||
else
|
||||
fpi_ssm_next_state(parent);
|
||||
fpi_ssm_free(ssm);
|
||||
FpiSsm *parent = ssm->parentsm;
|
||||
|
||||
BUG_ON (!parent);
|
||||
if (error)
|
||||
fpi_ssm_mark_failed (parent, error);
|
||||
else
|
||||
fpi_ssm_next_state (parent);
|
||||
fpi_ssm_free (ssm);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_start_subsm:
|
||||
* @parent: an #fpi_ssm state machine
|
||||
* @child: an #fpi_ssm state machine
|
||||
* @parent: an #FpiSsm state machine
|
||||
* @child: an #FpiSsm state machine
|
||||
*
|
||||
* Starts a state machine as a child of another. if the child completes
|
||||
* successfully, the parent will be advanced to the next state. if the
|
||||
@@ -194,124 +203,185 @@ static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||
*
|
||||
* The child will be automatically freed upon completion or failure.
|
||||
*/
|
||||
void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child)
|
||||
void
|
||||
fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
|
||||
{
|
||||
child->parentsm = parent;
|
||||
fpi_ssm_start(child, __subsm_complete);
|
||||
child->parentsm = parent;
|
||||
fpi_ssm_start (child, __subsm_complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_mark_completed:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Mark a ssm as completed successfully. The callback set when creating
|
||||
* the state machine with fpi_ssm_new() will be called synchronously.
|
||||
*/
|
||||
void fpi_ssm_mark_completed(fpi_ssm *machine)
|
||||
void
|
||||
fpi_ssm_mark_completed (FpiSsm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->completed = TRUE;
|
||||
fp_dbg("%p completed with status %d", machine, machine->error);
|
||||
if (machine->callback)
|
||||
machine->callback(machine, machine->dev, machine->user_data);
|
||||
BUG_ON (machine->completed);
|
||||
machine->completed = TRUE;
|
||||
if (machine->error)
|
||||
fp_dbg ("%p completed with error: %s", machine, machine->error->message);
|
||||
else
|
||||
fp_dbg ("%p completed successfully", machine);
|
||||
if (machine->callback)
|
||||
{
|
||||
GError *error = machine->error ? g_error_copy (machine->error) : NULL;
|
||||
|
||||
machine->callback (machine, machine->dev, machine->user_data, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_mark_failed:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @error: the error code
|
||||
* @machine: an #FpiSsm state machine
|
||||
* @error: a #GError
|
||||
*
|
||||
* Mark a state machine as failed with @error as the error code.
|
||||
*/
|
||||
void fpi_ssm_mark_failed(fpi_ssm *machine, int error)
|
||||
void
|
||||
fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
|
||||
{
|
||||
fp_dbg("error %d from state %d", error, machine->cur_state);
|
||||
BUG_ON(error == 0);
|
||||
machine->error = error;
|
||||
fpi_ssm_mark_completed(machine);
|
||||
g_assert (error);
|
||||
if (machine->error)
|
||||
{
|
||||
fp_warn ("SSM already has an error set, ignoring new error %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message);
|
||||
machine->error = error;
|
||||
fpi_ssm_mark_completed (machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_next_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Iterate to next state of a state machine. If the current state is the
|
||||
* last state, then the state machine will be marked as completed, as
|
||||
* if calling fpi_ssm_mark_completed().
|
||||
*/
|
||||
void fpi_ssm_next_state(fpi_ssm *machine)
|
||||
{
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
BUG_ON(machine->completed);
|
||||
machine->cur_state++;
|
||||
if (machine->cur_state == machine->nr_states) {
|
||||
fpi_ssm_mark_completed(machine);
|
||||
} else {
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_next_state_timeout_cb:
|
||||
* @dev: a struct #fp_dev
|
||||
* @data: a pointer to an #fpi_ssm state machine
|
||||
*
|
||||
* Same as fpi_ssm_next_state(), but to be used as a callback
|
||||
* for an fpi_timeout_add() callback, when the state change needs
|
||||
* to happen after a timeout.
|
||||
*
|
||||
* Make sure to pass the #fpi_ssm as the `user_data` argument
|
||||
* for that fpi_timeout_add() call.
|
||||
*/
|
||||
void
|
||||
fpi_ssm_next_state_timeout_cb(struct fp_dev *dev,
|
||||
void *data)
|
||||
fpi_ssm_next_state (FpiSsm *machine)
|
||||
{
|
||||
g_return_if_fail (dev != NULL);
|
||||
g_return_if_fail (data != NULL);
|
||||
g_return_if_fail (machine != NULL);
|
||||
|
||||
fpi_ssm_next_state(data);
|
||||
BUG_ON (machine->completed);
|
||||
machine->cur_state++;
|
||||
if (machine->cur_state == machine->nr_states)
|
||||
fpi_ssm_mark_completed (machine);
|
||||
else
|
||||
__ssm_call_handler (machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_jump_to_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
* @state: the state to jump to
|
||||
*
|
||||
* Jump to the @state state, bypassing intermediary states.
|
||||
*/
|
||||
void fpi_ssm_jump_to_state(fpi_ssm *machine, int state)
|
||||
void
|
||||
fpi_ssm_jump_to_state (FpiSsm *machine, int state)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
BUG_ON(state >= machine->nr_states);
|
||||
machine->cur_state = state;
|
||||
__ssm_call_handler(machine);
|
||||
BUG_ON (machine->completed);
|
||||
BUG_ON (state >= machine->nr_states);
|
||||
machine->cur_state = state;
|
||||
__ssm_call_handler (machine);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_cur_state:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Returns the value of the current state. Note that states are
|
||||
* 0-indexed, so a value of 0 means “the first state”.
|
||||
*
|
||||
* Returns: the current state.
|
||||
*/
|
||||
int fpi_ssm_get_cur_state(fpi_ssm *machine)
|
||||
int
|
||||
fpi_ssm_get_cur_state (FpiSsm *machine)
|
||||
{
|
||||
return machine->cur_state;
|
||||
return machine->cur_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_get_error:
|
||||
* @machine: an #fpi_ssm state machine
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Returns the error code set by fpi_ssm_mark_failed().
|
||||
*
|
||||
* Returns: a error code
|
||||
* Returns: (transfer none): a error code
|
||||
*/
|
||||
int fpi_ssm_get_error(fpi_ssm *machine)
|
||||
GError *
|
||||
fpi_ssm_get_error (FpiSsm *machine)
|
||||
{
|
||||
return machine->error;
|
||||
return machine->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_dup_error:
|
||||
* @machine: an #FpiSsm state machine
|
||||
*
|
||||
* Returns the error code set by fpi_ssm_mark_failed().
|
||||
*
|
||||
* Returns: (transfer full): a error code
|
||||
*/
|
||||
GError *
|
||||
fpi_ssm_dup_error (FpiSsm *machine)
|
||||
{
|
||||
if (machine->error)
|
||||
return g_error_copy (machine->error);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_next_state_timeout_cb:
|
||||
* @dev: a struct #fp_dev
|
||||
* @data: a pointer to an #FpiSsm state machine
|
||||
*
|
||||
* Same as fpi_ssm_next_state(), but to be used as a callback
|
||||
* for an fpi_timeout_add() callback, when the state change needs
|
||||
* to happen after a timeout.
|
||||
*
|
||||
* Make sure to pass the #FpiSsm as the `user_data` argument
|
||||
* for that fpi_timeout_add() call.
|
||||
*/
|
||||
void
|
||||
fpi_ssm_next_state_timeout_cb (FpDevice *dev,
|
||||
void *data)
|
||||
{
|
||||
g_return_if_fail (dev != NULL);
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
fpi_ssm_next_state (data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_ssm_usb_transfer_cb:
|
||||
* @transfer: a #FpiUsbTransfer
|
||||
* @device: a #FpDevice
|
||||
* @user_data: User data (unused)
|
||||
* @error: The #GError or %NULL
|
||||
*
|
||||
* Can be used in as a #FpiUsbTransfer callback handler to automatically
|
||||
* advance or fail a statemachine on transfer completion.
|
||||
*
|
||||
* Make sure to set the #FpiSsm on the transfer.
|
||||
*/
|
||||
void
|
||||
fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||
gpointer user_data, GError *error)
|
||||
{
|
||||
g_return_if_fail (transfer->ssm);
|
||||
|
||||
if (error)
|
||||
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||
else
|
||||
fpi_ssm_next_state (transfer->ssm);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user