Public async API implementation
Involved some internal overhaul/reorganisation. Nice side effect is that the synchronous API is now expressed purely in terms of the public async API.
This commit is contained in:
parent
83f9da1b87
commit
88e9f4a5f8
12 changed files with 1054 additions and 872 deletions
|
@ -54,12 +54,14 @@ libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(IMAGEMAGICK_LIBS) $(CRYP
|
||||||
|
|
||||||
libfprint_la_SOURCES = \
|
libfprint_la_SOURCES = \
|
||||||
fp_internal.h \
|
fp_internal.h \
|
||||||
|
async.c \
|
||||||
core.c \
|
core.c \
|
||||||
data.c \
|
data.c \
|
||||||
drv.c \
|
drv.c \
|
||||||
img.c \
|
img.c \
|
||||||
imgdev.c \
|
imgdev.c \
|
||||||
poll.c \
|
poll.c \
|
||||||
|
sync.c \
|
||||||
aeslib.c \
|
aeslib.c \
|
||||||
aeslib.h \
|
aeslib.h \
|
||||||
$(DRIVER_SRC) \
|
$(DRIVER_SRC) \
|
||||||
|
|
414
libfprint/async.c
Normal file
414
libfprint/async.c
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
/*
|
||||||
|
* Asynchronous I/O functionality
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "async"
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "fp_internal.h"
|
||||||
|
|
||||||
|
/* Drivers call this when device initialisation has completed */
|
||||||
|
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
||||||
|
{
|
||||||
|
fp_dbg("status %d", status);
|
||||||
|
BUG_ON(dev->state != DEV_STATE_INITIALIZING);
|
||||||
|
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
|
||||||
|
opened_devices = g_slist_prepend(opened_devices, dev);
|
||||||
|
if (dev->open_cb)
|
||||||
|
dev->open_cb(dev, status, dev->open_cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = ddev->drv;
|
||||||
|
struct fp_dev *dev;
|
||||||
|
libusb_dev_handle *udevh;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
udevh = libusb_open(ddev->udev);
|
||||||
|
if (!udevh) {
|
||||||
|
fp_err("usb_open failed");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = g_malloc0(sizeof(*dev));
|
||||||
|
dev->drv = drv;
|
||||||
|
dev->udev = udevh;
|
||||||
|
dev->__enroll_stage = -1;
|
||||||
|
dev->state = DEV_STATE_INITIALIZING;
|
||||||
|
dev->open_cb = cb;
|
||||||
|
dev->open_cb_data = user_data;
|
||||||
|
|
||||||
|
if (!drv->open) {
|
||||||
|
fpi_drvcb_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->state = DEV_STATE_INITIALIZING;
|
||||||
|
r = drv->open(dev, ddev->driver_data);
|
||||||
|
if (r) {
|
||||||
|
fp_err("device initialisation failed, driver=%s", drv->name);
|
||||||
|
libusb_close(udevh);
|
||||||
|
g_free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when device deinitialisation has completed */
|
||||||
|
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
||||||
|
dev->state = DEV_STATE_DEINITIALIZED;
|
||||||
|
libusb_close(dev->udev);
|
||||||
|
if (dev->close_cb)
|
||||||
|
dev->close_cb(dev, dev->close_cb_data);
|
||||||
|
g_free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
||||||
|
fp_dev_close_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
|
||||||
|
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
||||||
|
fp_err("device %p not in opened list!", dev);
|
||||||
|
opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
|
||||||
|
|
||||||
|
dev->close_cb = callback;
|
||||||
|
dev->close_cb_data = user_data;
|
||||||
|
|
||||||
|
if (!drv->close) {
|
||||||
|
fpi_drvcb_close_complete(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->state = DEV_STATE_DEINITIALIZING;
|
||||||
|
drv->close(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when enrollment has started */
|
||||||
|
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
||||||
|
{
|
||||||
|
fp_dbg("status %d", status);
|
||||||
|
BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
|
||||||
|
if (status) {
|
||||||
|
if (status > 0) {
|
||||||
|
status = -status;
|
||||||
|
fp_dbg("adjusted to %d", status);
|
||||||
|
}
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
if (dev->enroll_stage_cb)
|
||||||
|
dev->enroll_stage_cb(dev, status, NULL, NULL,
|
||||||
|
dev->enroll_stage_cb_data);
|
||||||
|
} else {
|
||||||
|
dev->state = DEV_STATE_ENROLLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
||||||
|
fp_enroll_stage_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
||||||
|
fp_err("driver %s has 0 enroll stages or no enroll func",
|
||||||
|
drv->name);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg("starting enrollment");
|
||||||
|
dev->enroll_stage_cb = callback;
|
||||||
|
dev->enroll_stage_cb_data = user_data;
|
||||||
|
|
||||||
|
dev->state = DEV_STATE_ENROLL_STARTING;
|
||||||
|
r = drv->enroll_start(dev);
|
||||||
|
if (r < 0) {
|
||||||
|
dev->enroll_stage_cb = NULL;
|
||||||
|
fp_err("failed to start enrollment");
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when an enroll stage has completed */
|
||||||
|
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||||
|
struct fp_print_data *data, struct fp_img *img)
|
||||||
|
{
|
||||||
|
BUG_ON(dev->state != DEV_STATE_ENROLLING);
|
||||||
|
fp_dbg("result %d", result);
|
||||||
|
if (!dev->enroll_stage_cb) {
|
||||||
|
fp_dbg("ignoring enroll result as no callback is subscribed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result == FP_ENROLL_COMPLETE && !data) {
|
||||||
|
fp_err("BUG: complete but no data?");
|
||||||
|
result = FP_ENROLL_FAIL;
|
||||||
|
}
|
||||||
|
dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when enrollment has stopped */
|
||||||
|
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
|
if (dev->enroll_stop_cb)
|
||||||
|
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
||||||
|
fp_enroll_stop_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
if (!drv->enroll_start)
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
dev->enroll_stage_cb = NULL;
|
||||||
|
dev->enroll_stop_cb = callback;
|
||||||
|
dev->enroll_stop_cb_data = user_data;
|
||||||
|
dev->state = DEV_STATE_ENROLL_STOPPING;
|
||||||
|
|
||||||
|
if (!drv->enroll_stop) {
|
||||||
|
fpi_drvcb_enroll_stopped(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = drv->enroll_stop(dev);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("failed to stop enrollment");
|
||||||
|
dev->enroll_stop_cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
||||||
|
struct fp_print_data *data, fp_verify_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
if (!drv->verify_start)
|
||||||
|
return -ENOTSUP;
|
||||||
|
|
||||||
|
dev->state = DEV_STATE_VERIFY_STARTING;
|
||||||
|
dev->verify_cb = callback;
|
||||||
|
dev->verify_cb_data = user_data;
|
||||||
|
dev->verify_data = data;
|
||||||
|
|
||||||
|
r = drv->verify_start(dev);
|
||||||
|
if (r < 0) {
|
||||||
|
dev->verify_cb = NULL;
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
fp_err("failed to start verification, error %d", r);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when verification has started */
|
||||||
|
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
||||||
|
if (status) {
|
||||||
|
if (status > 0) {
|
||||||
|
status = -status;
|
||||||
|
fp_dbg("adjusted to %d", status);
|
||||||
|
}
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
if (dev->verify_cb)
|
||||||
|
dev->verify_cb(dev, status, NULL, dev->verify_cb_data);
|
||||||
|
} else {
|
||||||
|
dev->state = DEV_STATE_VERIFYING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this to report a verify result (which might mark completion) */
|
||||||
|
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||||
|
struct fp_img *img)
|
||||||
|
{
|
||||||
|
fp_dbg("result %d", result);
|
||||||
|
BUG_ON(dev->state != DEV_STATE_VERIFYING);
|
||||||
|
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
||||||
|
|| result == FP_VERIFY_MATCH)
|
||||||
|
dev->state = DEV_STATE_VERIFY_DONE;
|
||||||
|
|
||||||
|
if (dev->verify_cb)
|
||||||
|
dev->verify_cb(dev, result, img, dev->verify_cb_data);
|
||||||
|
else
|
||||||
|
fp_dbg("ignoring verify result as no callback is subscribed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when verification has stopped */
|
||||||
|
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
|
if (dev->verify_stop_cb)
|
||||||
|
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
||||||
|
fp_verify_stop_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_ERROR
|
||||||
|
&& dev->state != DEV_STATE_VERIFYING
|
||||||
|
&& dev->state != DEV_STATE_VERIFY_DONE);
|
||||||
|
|
||||||
|
dev->verify_cb = NULL;
|
||||||
|
dev->verify_stop_cb = callback;
|
||||||
|
dev->verify_stop_cb_data = user_data;
|
||||||
|
dev->state = DEV_STATE_VERIFY_STOPPING;
|
||||||
|
|
||||||
|
if (!drv->verify_start)
|
||||||
|
return -ENOTSUP;
|
||||||
|
if (!drv->verify_stop) {
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
|
fpi_drvcb_verify_stopped(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = drv->verify_stop(dev, iterating);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("failed to stop verification");
|
||||||
|
dev->verify_stop_cb = NULL;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
|
||||||
|
struct fp_print_data **gallery, fp_identify_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
if (!drv->identify_start)
|
||||||
|
return -ENOTSUP;
|
||||||
|
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
||||||
|
dev->identify_cb = callback;
|
||||||
|
dev->identify_cb_data = user_data;
|
||||||
|
dev->identify_gallery = gallery;
|
||||||
|
|
||||||
|
r = drv->identify_start(dev);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("identify_start failed with error %d", r);
|
||||||
|
dev->identify_cb = NULL;
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Driver-lib: identification has started, expect results soon */
|
||||||
|
void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
|
||||||
|
{
|
||||||
|
fp_dbg("status %d", status);
|
||||||
|
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
|
||||||
|
if (status) {
|
||||||
|
if (status > 0) {
|
||||||
|
status = -status;
|
||||||
|
fp_dbg("adjusted to %d", status);
|
||||||
|
}
|
||||||
|
dev->state = DEV_STATE_ERROR;
|
||||||
|
if (dev->identify_cb)
|
||||||
|
dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data);
|
||||||
|
} else {
|
||||||
|
dev->state = DEV_STATE_IDENTIFYING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers report an identify result (which might mark completion) */
|
||||||
|
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||||
|
size_t match_offset, struct fp_img *img)
|
||||||
|
{
|
||||||
|
fp_dbg("result %d", result);
|
||||||
|
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
||||||
|
&& dev->state != DEV_STATE_ERROR);
|
||||||
|
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
||||||
|
|| result == FP_VERIFY_MATCH)
|
||||||
|
dev->state = DEV_STATE_IDENTIFY_DONE;
|
||||||
|
|
||||||
|
if (dev->identify_cb)
|
||||||
|
dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data);
|
||||||
|
else
|
||||||
|
fp_dbg("ignoring verify result as no callback is subscribed");
|
||||||
|
}
|
||||||
|
|
||||||
|
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
||||||
|
fp_identify_stop_cb callback, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
||||||
|
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
||||||
|
|
||||||
|
dev->state = DEV_STATE_IDENTIFY_STOPPING;
|
||||||
|
dev->identify_cb = NULL;
|
||||||
|
dev->identify_stop_cb = callback;
|
||||||
|
dev->identify_stop_cb_data = user_data;
|
||||||
|
|
||||||
|
if (!drv->identify_start)
|
||||||
|
return -ENOTSUP;
|
||||||
|
if (!drv->identify_stop) {
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
|
fpi_drvcb_identify_stopped(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = drv->identify_stop(dev, iterating);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("failed to stop identification");
|
||||||
|
dev->identify_stop_cb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drivers call this when identification has stopped */
|
||||||
|
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
||||||
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
|
if (dev->identify_stop_cb)
|
||||||
|
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
||||||
|
}
|
||||||
|
|
545
libfprint/core.c
545
libfprint/core.c
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
|
GSList *opened_devices = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \mainpage libfprint API Reference
|
* \mainpage libfprint API Reference
|
||||||
* libfprint is an open source library to provide access to fingerprint
|
* libfprint is an open source library to provide access to fingerprint
|
||||||
|
@ -273,7 +275,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static GSList *registered_drivers = NULL;
|
static GSList *registered_drivers = NULL;
|
||||||
static GSList *opened_devices = NULL;
|
|
||||||
|
|
||||||
void fpi_log(enum fpi_log_level level, const char *component,
|
void fpi_log(enum fpi_log_level level, const char *component,
|
||||||
const char *function, const char *format, ...)
|
const char *function, const char *format, ...)
|
||||||
|
@ -565,89 +566,6 @@ API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev *
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Opens and initialises a device. This is the function you call in order
|
|
||||||
* to convert a \ref dscv_dev "discovered device" into an actual device handle
|
|
||||||
* that you can perform operations with.
|
|
||||||
* \param ddev the discovered device to open
|
|
||||||
* \returns the opened device handle, or NULL on error
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
|
||||||
{
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_driver *drv = ddev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
libusb_dev_handle *udevh = libusb_open(ddev->udev);
|
|
||||||
if (!udevh) {
|
|
||||||
fp_err("usb_open failed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = g_malloc0(sizeof(*dev));
|
|
||||||
dev->drv = drv;
|
|
||||||
dev->udev = udevh;
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
|
|
||||||
r = fpi_drv_init(dev, ddev->driver_data);
|
|
||||||
if (r) {
|
|
||||||
fp_err("device initialisation failed, driver=%s", drv->name);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (dev->state == DEV_STATE_INITIALIZING)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
goto err_deinit;
|
|
||||||
if (dev->state != DEV_STATE_INITIALIZED)
|
|
||||||
goto err_deinit;
|
|
||||||
|
|
||||||
opened_devices = g_slist_prepend(opened_devices, (gpointer) dev);
|
|
||||||
return dev;
|
|
||||||
|
|
||||||
err_deinit:
|
|
||||||
fpi_drv_deinit(dev);
|
|
||||||
while (dev->state == DEV_STATE_DEINITIALIZING) {
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
err:
|
|
||||||
libusb_close(udevh);
|
|
||||||
g_free(dev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* performs close operation without modifying opened_devices list */
|
|
||||||
static void do_close(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fpi_drv_deinit(dev);
|
|
||||||
while (dev->state == DEV_STATE_DEINITIALIZING)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
libusb_close(dev->udev);
|
|
||||||
g_free(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Close a device. You must call this function when you are finished using
|
|
||||||
* a fingerprint device.
|
|
||||||
* \param dev the device to close. If NULL, function simply returns.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
if (!dev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
|
||||||
fp_err("device %p not in opened list!", dev);
|
|
||||||
opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev);
|
|
||||||
do_close(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
/** \ingroup dev
|
||||||
* Get the \ref drv "driver" for a fingerprint device.
|
* Get the \ref drv "driver" for a fingerprint device.
|
||||||
* \param dev the device
|
* \param dev the device
|
||||||
|
@ -843,448 +761,6 @@ API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
||||||
return fpi_imgdev_get_img_height(imgdev);
|
return fpi_imgdev_get_img_height(imgdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sync_enroll_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_enroll_cb(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct sync_enroll_data *edata = dev->enroll_data;
|
|
||||||
edata->result = result;
|
|
||||||
edata->data = data;
|
|
||||||
edata->img = img;
|
|
||||||
edata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Performs an enroll stage. See \ref enrolling for an explanation of enroll
|
|
||||||
* stages.
|
|
||||||
*
|
|
||||||
* If no enrollment is in process, this kicks of the process and runs the
|
|
||||||
* first stage. If an enrollment is already in progress, calling this
|
|
||||||
* function runs the next stage, which may well be the last.
|
|
||||||
*
|
|
||||||
* A negative error code may be returned from any stage. When this occurs,
|
|
||||||
* further calls to the enroll function will start a new enrollment process,
|
|
||||||
* i.e. a negative error code indicates that the enrollment process has been
|
|
||||||
* aborted. These error codes only ever indicate unexpected internal errors
|
|
||||||
* or I/O problems.
|
|
||||||
*
|
|
||||||
* The RETRY codes from #fp_enroll_result may be returned from any enroll
|
|
||||||
* stage. These codes indicate that the scan was not succesful in that the
|
|
||||||
* user did not position their finger correctly or similar. When a RETRY code
|
|
||||||
* is returned, the enrollment stage is <b>not</b> advanced, so the next call
|
|
||||||
* into this function will retry the current stage again. The current stage may
|
|
||||||
* need to be retried several times.
|
|
||||||
*
|
|
||||||
* The fp_enroll_result#FP_ENROLL_FAIL code may be returned from any enroll
|
|
||||||
* stage. This code indicates that even though the scans themselves have been
|
|
||||||
* acceptable, data processing applied to these scans produces incomprehensible
|
|
||||||
* results. In other words, the user may have been scanning a different finger
|
|
||||||
* for each stage or something like that. Like negative error codes, this
|
|
||||||
* return code indicates that the enrollment process has been aborted.
|
|
||||||
*
|
|
||||||
* The fp_enroll_result#FP_ENROLL_PASS code will only ever be returned for
|
|
||||||
* non-final stages. This return code indicates that the scan was acceptable
|
|
||||||
* and the next call into this function will advance onto the next enroll
|
|
||||||
* stage.
|
|
||||||
*
|
|
||||||
* The fp_enroll_result#FP_ENROLL_COMPLETE code will only ever be returned
|
|
||||||
* from the final enroll stage. It indicates that enrollment completed
|
|
||||||
* successfully, and that print_data has been assigned to point to the
|
|
||||||
* resultant enrollment data. The print_data parameter will not be modified
|
|
||||||
* during any other enrollment stages, hence it is actually legal to pass NULL
|
|
||||||
* as this argument for all but the final stage.
|
|
||||||
*
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when the enroll fails with a RETRY or FAIL code. It is legal
|
|
||||||
* to call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* \param dev the device
|
|
||||||
* \param print_data a location to return the resultant enrollment data from
|
|
||||||
* the final stage. Must be freed with fp_print_data_free() after use.
|
|
||||||
* \param img location to store the scan image. accepts NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use.
|
|
||||||
* \return negative code on error, otherwise a code from #fp_enroll_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_data, struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int stage = dev->__enroll_stage;
|
|
||||||
gboolean final = FALSE;
|
|
||||||
struct sync_enroll_data *edata;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
|
||||||
fp_err("driver %s has 0 enroll stages or no enroll func",
|
|
||||||
drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stage == -1) {
|
|
||||||
fp_dbg("starting enrollment");
|
|
||||||
r = fpi_drv_enroll_start(dev, sync_enroll_cb);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to start enrollment");
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
while (dev->state == DEV_STATE_ENROLL_STARTING) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dev->state != DEV_STATE_ENROLLING) {
|
|
||||||
r = -EIO;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->__enroll_stage = ++stage;
|
|
||||||
dev->enroll_data = g_malloc0(sizeof(struct sync_enroll_data));
|
|
||||||
} else if (stage >= dev->nr_enroll_stages) {
|
|
||||||
fp_err("exceeding number of enroll stages for device claimed by "
|
|
||||||
"driver %s (%d stages)", drv->name, dev->nr_enroll_stages);
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
r = -EINVAL;
|
|
||||||
final = TRUE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
fp_dbg("%s will handle enroll stage %d/%d", drv->name, stage,
|
|
||||||
dev->nr_enroll_stages - 1);
|
|
||||||
|
|
||||||
edata = dev->enroll_data;
|
|
||||||
while (!edata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(edata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
edata->populated = FALSE;
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = edata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(edata->img);
|
|
||||||
|
|
||||||
r = edata->result;
|
|
||||||
switch (r) {
|
|
||||||
case FP_ENROLL_PASS:
|
|
||||||
fp_dbg("enroll stage passed");
|
|
||||||
dev->__enroll_stage = stage + 1;
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_COMPLETE:
|
|
||||||
fp_dbg("enroll complete");
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
*print_data = edata->data;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY:
|
|
||||||
fp_dbg("enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, enroll should retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
case FP_ENROLL_FAIL:
|
|
||||||
fp_err("enroll failed");
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
dev->__enroll_stage = -1;
|
|
||||||
r = -EINVAL;
|
|
||||||
final = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (final) {
|
|
||||||
fp_dbg("ending enrollment");
|
|
||||||
if (fpi_drv_enroll_stop(dev) == 0)
|
|
||||||
while (dev->state == DEV_STATE_ENROLL_STOPPING) {
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_free(dev->enroll_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (fpi_drv_enroll_stop(dev) == 0)
|
|
||||||
while (dev->state == DEV_STATE_ENROLL_STOPPING)
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_verify_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_verify_cb(struct fp_dev *dev, int result, struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct sync_verify_data *vdata = dev->sync_verify_data;
|
|
||||||
vdata->result = result;
|
|
||||||
vdata->img = img;
|
|
||||||
vdata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Performs a new scan and verify it against a previously enrolled print.
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when the verify fails with a RETRY code. It is legal to
|
|
||||||
* call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* \param dev the device to perform the scan.
|
|
||||||
* \param enrolled_print the print to verify against. Must have been previously
|
|
||||||
* enrolled with a device compatible to the device selected to perform the scan.
|
|
||||||
* \param img location to store the scan image. accepts NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use.
|
|
||||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *enrolled_print, struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
struct sync_verify_data *vdata;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!enrolled_print) {
|
|
||||||
fp_err("no print given");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drv->verify_start) {
|
|
||||||
fp_err("driver %s has no verify func", drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fp_dev_supports_print_data(dev, enrolled_print)) {
|
|
||||||
fp_err("print is not compatible with device");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg("to be handled by %s", drv->name);
|
|
||||||
r = fpi_drv_verify_start(dev, sync_verify_cb, enrolled_print);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_dbg("verify_start error %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
while (dev->state == DEV_STATE_VERIFY_STARTING) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (dev->state != DEV_STATE_VERIFYING) {
|
|
||||||
r = -EIO;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->sync_verify_data = g_malloc0(sizeof(struct sync_verify_data));
|
|
||||||
vdata = dev->sync_verify_data;
|
|
||||||
|
|
||||||
while (!vdata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(vdata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = vdata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(vdata->img);
|
|
||||||
|
|
||||||
r = vdata->result;
|
|
||||||
g_free(dev->sync_verify_data);
|
|
||||||
switch (r) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
fp_dbg("result: no match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
fp_dbg("result: match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
fp_dbg("verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
fp_dbg("ending verification");
|
|
||||||
if (fpi_drv_verify_stop(dev) == 0) {
|
|
||||||
while (dev->state == DEV_STATE_VERIFY_STOPPING) {
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sync_identify_data {
|
|
||||||
gboolean populated;
|
|
||||||
int result;
|
|
||||||
size_t match_offset;
|
|
||||||
struct fp_img *img;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void sync_identify_cb(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img)
|
|
||||||
{
|
|
||||||
struct sync_identify_data *idata = dev->sync_identify_data;
|
|
||||||
idata->result = result;
|
|
||||||
idata->match_offset = match_offset;
|
|
||||||
idata->img = img;
|
|
||||||
idata->populated = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Performs a new scan and attempts to identify the scanned finger against
|
|
||||||
* a collection of previously enrolled fingerprints.
|
|
||||||
* If the device is an imaging device, it can also return the image from
|
|
||||||
* the scan, even when identification fails with a RETRY code. It is legal to
|
|
||||||
* call this function even on non-imaging devices, just don't expect them to
|
|
||||||
* provide images.
|
|
||||||
*
|
|
||||||
* This function returns codes from #fp_verify_result. The return code
|
|
||||||
* fp_verify_result#FP_VERIFY_MATCH indicates that the scanned fingerprint
|
|
||||||
* does appear in the print gallery, and the match_offset output parameter
|
|
||||||
* will indicate the index into the print gallery array of the matched print.
|
|
||||||
*
|
|
||||||
* This function will not necessarily examine the whole print gallery, it
|
|
||||||
* will return as soon as it finds a matching print.
|
|
||||||
*
|
|
||||||
* Not all devices support identification. -ENOTSUP will be returned when
|
|
||||||
* this is the case.
|
|
||||||
*
|
|
||||||
* \param dev the device to perform the scan.
|
|
||||||
* \param print_gallery NULL-terminated array of pointers to the prints to
|
|
||||||
* identify against. Each one must have been previously enrolled with a device
|
|
||||||
* compatible to the device selected to perform the scan.
|
|
||||||
* \param match_offset output location to store the array index of the matched
|
|
||||||
* gallery print (if any was found). Only valid if FP_VERIFY_MATCH was
|
|
||||||
* returned.
|
|
||||||
* \param img location to store the scan image. accepts NULL for no image
|
|
||||||
* storage. If an image is returned, it must be freed with fp_img_free() after
|
|
||||||
* use.
|
|
||||||
* \return negative code on error, otherwise a code from #fp_verify_result
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
|
||||||
struct fp_print_data **print_gallery, size_t *match_offset,
|
|
||||||
struct fp_img **img)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
struct sync_identify_data *idata;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!drv->identify_start) {
|
|
||||||
fp_dbg("driver %s has no identify func", drv->name);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
fp_dbg("to be handled by %s", drv->name);
|
|
||||||
|
|
||||||
r = fpi_drv_identify_start(dev, sync_identify_cb, print_gallery);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("identify_start error %d", r);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
while (dev->state == DEV_STATE_IDENTIFY_STARTING) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (dev->state != DEV_STATE_IDENTIFYING) {
|
|
||||||
r = -EIO;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->sync_identify_data = g_malloc0(sizeof(struct sync_identify_data));
|
|
||||||
idata = dev->sync_identify_data;
|
|
||||||
|
|
||||||
while (!idata->populated) {
|
|
||||||
r = fp_handle_events();
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(idata);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (img)
|
|
||||||
*img = idata->img;
|
|
||||||
else
|
|
||||||
fp_img_free(idata->img);
|
|
||||||
|
|
||||||
r = idata->result;
|
|
||||||
switch (r) {
|
|
||||||
case FP_VERIFY_NO_MATCH:
|
|
||||||
fp_dbg("result: no match");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_MATCH:
|
|
||||||
fp_dbg("result: match at offset %zd", match_offset);
|
|
||||||
*match_offset = idata->match_offset;
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY:
|
|
||||||
fp_dbg("verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_TOO_SHORT:
|
|
||||||
fp_dbg("swipe was too short, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_CENTER_FINGER:
|
|
||||||
fp_dbg("finger was not centered, verify should retry");
|
|
||||||
break;
|
|
||||||
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
|
||||||
fp_dbg("scan failed, remove finger and retry");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised return code %d", r);
|
|
||||||
r = -EINVAL;
|
|
||||||
}
|
|
||||||
g_free(dev->sync_identify_data);
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (fpi_drv_identify_stop(dev) == 0) {
|
|
||||||
while (dev->state == DEV_STATE_IDENTIFY_STOPPING) {
|
|
||||||
if (fp_handle_events() < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
/** \ingroup core
|
||||||
* Initialise libfprint. This function must be called before you attempt to
|
* Initialise libfprint. This function must be called before you attempt to
|
||||||
* use the library in any way.
|
* use the library in any way.
|
||||||
|
@ -1310,14 +786,18 @@ API_EXPORTED int fp_init(void)
|
||||||
*/
|
*/
|
||||||
API_EXPORTED void fp_exit(void)
|
API_EXPORTED void fp_exit(void)
|
||||||
{
|
{
|
||||||
GSList *elem = opened_devices;
|
|
||||||
fp_dbg("");
|
fp_dbg("");
|
||||||
|
|
||||||
if (elem != NULL) {
|
if (opened_devices) {
|
||||||
do {
|
GSList *copy = g_slist_copy(opened_devices);
|
||||||
fp_dbg("naughty app left a device open on exit!");
|
GSList *elem = copy;
|
||||||
do_close((struct fp_dev *) elem->data);
|
fp_dbg("naughty app left devices open on exit!");
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
|
do
|
||||||
|
fp_dev_close((struct fp_dev *) elem->data);
|
||||||
|
while ((elem = g_slist_next(elem)));
|
||||||
|
|
||||||
|
g_slist_free(copy);
|
||||||
g_slist_free(opened_devices);
|
g_slist_free(opened_devices);
|
||||||
opened_devices = NULL;
|
opened_devices = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1329,4 +809,3 @@ API_EXPORTED void fp_exit(void)
|
||||||
libusb_exit();
|
libusb_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -907,7 +907,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct aes2501_dev));
|
dev->priv = g_malloc0(sizeof(struct aes2501_dev));
|
||||||
fpi_imgdev_init_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
g_free(dev->priv);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(dev->udev, 0);
|
||||||
fpi_imgdev_deinit_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
|
@ -934,8 +934,8 @@ struct fp_img_driver aes2501_driver = {
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = 192,
|
.img_width = 192,
|
||||||
|
|
||||||
.init = dev_init,
|
.open = dev_init,
|
||||||
.deinit = dev_deinit,
|
.close = dev_deinit,
|
||||||
.activate = dev_activate,
|
.activate = dev_activate,
|
||||||
.deactivate = dev_deactivate,
|
.deactivate = dev_deactivate,
|
||||||
};
|
};
|
||||||
|
|
|
@ -213,7 +213,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
dev->priv = g_malloc0(sizeof(struct aes4k_dev));
|
dev->priv = g_malloc0(sizeof(struct aes4k_dev));
|
||||||
|
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
fpi_imgdev_init_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
g_free(dev->priv);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(dev->udev, 0);
|
||||||
fpi_imgdev_deinit_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
|
@ -245,8 +245,8 @@ struct fp_img_driver aes4000_driver = {
|
||||||
/* temporarily lowered until image quality improves */
|
/* temporarily lowered until image quality improves */
|
||||||
.bz3_threshold = 9,
|
.bz3_threshold = 9,
|
||||||
|
|
||||||
.init = dev_init,
|
.open = dev_init,
|
||||||
.deinit = dev_deinit,
|
.close = dev_deinit,
|
||||||
.activate = dev_activate,
|
.activate = dev_activate,
|
||||||
.deactivate = dev_deactivate,
|
.deactivate = dev_deactivate,
|
||||||
};
|
};
|
||||||
|
|
|
@ -840,7 +840,7 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||||
dev->priv = upekdev;
|
dev->priv = upekdev;
|
||||||
dev->nr_enroll_stages = 3;
|
dev->nr_enroll_stages = 3;
|
||||||
|
|
||||||
fpi_drvcb_init_complete(dev, 0);
|
fpi_drvcb_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,7 +848,7 @@ static void dev_exit(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(dev->udev, 0);
|
||||||
g_free(dev->priv);
|
g_free(dev->priv);
|
||||||
fpi_drvcb_deinit_complete(dev);
|
fpi_drvcb_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char enroll_init[] = {
|
static const unsigned char enroll_init[] = {
|
||||||
|
@ -1415,8 +1415,8 @@ struct fp_driver upekts_driver = {
|
||||||
.name = FP_COMPONENT,
|
.name = FP_COMPONENT,
|
||||||
.full_name = "UPEK TouchStrip",
|
.full_name = "UPEK TouchStrip",
|
||||||
.id_table = id_table,
|
.id_table = id_table,
|
||||||
.init = dev_init,
|
.open = dev_init,
|
||||||
.deinit = dev_exit,
|
.close = dev_exit,
|
||||||
.enroll_start = enroll_start,
|
.enroll_start = enroll_start,
|
||||||
.enroll_stop = enroll_stop,
|
.enroll_stop = enroll_stop,
|
||||||
.verify_start = verify_start,
|
.verify_start = verify_start,
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
urudev->interface = iface_desc->bInterfaceNumber;
|
urudev->interface = iface_desc->bInterfaceNumber;
|
||||||
AES_set_encrypt_key(crkey, 128, &urudev->aeskey);
|
AES_set_encrypt_key(crkey, 128, &urudev->aeskey);
|
||||||
dev->priv = urudev;
|
dev->priv = urudev;
|
||||||
fpi_imgdev_init_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,7 +1105,7 @@ static void dev_deinit(struct fp_img_dev *dev)
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = dev->priv;
|
||||||
libusb_release_interface(dev->udev, urudev->interface);
|
libusb_release_interface(dev->udev, urudev->interface);
|
||||||
g_free(urudev);
|
g_free(urudev);
|
||||||
fpi_imgdev_deinit_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
|
@ -1142,8 +1142,8 @@ struct fp_img_driver uru4000_driver = {
|
||||||
.img_height = 289,
|
.img_height = 289,
|
||||||
.img_width = 384,
|
.img_width = 384,
|
||||||
|
|
||||||
.init = dev_init,
|
.open = dev_init,
|
||||||
.deinit = dev_deinit,
|
.close = dev_deinit,
|
||||||
.activate = dev_activate,
|
.activate = dev_activate,
|
||||||
.deactivate = dev_deactivate,
|
.deactivate = dev_deactivate,
|
||||||
.change_state = dev_change_state,
|
.change_state = dev_change_state,
|
||||||
|
|
268
libfprint/drv.c
268
libfprint/drv.c
|
@ -19,277 +19,11 @@
|
||||||
|
|
||||||
#define FP_COMPONENT "drv"
|
#define FP_COMPONENT "drv"
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
/* Lib-driver: start device initialisation */
|
|
||||||
int fpi_drv_init(struct fp_dev *dev, unsigned long driver_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
if (!drv->init) {
|
|
||||||
fpi_drvcb_init_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
|
||||||
return drv->init(dev, driver_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: device initialisation complete */
|
|
||||||
void fpi_drvcb_init_complete(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_INITIALIZING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: start device deinitialisation */
|
|
||||||
void fpi_drv_deinit(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
if (!drv->deinit) {
|
|
||||||
fpi_drvcb_deinit_complete(dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZING;
|
|
||||||
drv->deinit(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: device deinitialisation complete */
|
|
||||||
void fpi_drvcb_deinit_complete(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: start enrollment */
|
|
||||||
int fpi_drv_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->enroll_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
dev->state = DEV_STATE_ENROLL_STARTING;
|
|
||||||
dev->enroll_cb = callback;
|
|
||||||
r = drv->enroll_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->enroll_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: enrollment has now started, expect results soon */
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("status %d", status);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_ENROLLING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: an enroll stage has completed */
|
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img)
|
|
||||||
{
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLLING);
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
if (!dev->enroll_cb) {
|
|
||||||
fp_dbg("ignoring enroll result as no callback is subscribed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (result == FP_ENROLL_COMPLETE && !data) {
|
|
||||||
fp_err("BUG: complete but no data?");
|
|
||||||
result = FP_ENROLL_FAIL;
|
|
||||||
}
|
|
||||||
dev->enroll_cb(dev, result, data, img);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: stop enrollment */
|
|
||||||
int fpi_drv_enroll_stop(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
fp_dbg("");
|
|
||||||
dev->enroll_cb = NULL;
|
|
||||||
|
|
||||||
if (!drv->enroll_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->enroll_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_ENROLL_STOPPING;
|
|
||||||
return drv->enroll_stop(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: enrollment has stopped */
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: start verification */
|
|
||||||
int fpi_drv_verify_start(struct fp_dev *dev, fp_verify_cb callback,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
dev->state = DEV_STATE_VERIFY_STARTING;
|
|
||||||
dev->verify_cb = callback;
|
|
||||||
dev->verify_data = data;
|
|
||||||
r = drv->verify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: verification has started, expect results soon */
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_VERIFYING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: report a verify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFYING);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH) {
|
|
||||||
dev->state = DEV_STATE_VERIFY_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev->verify_cb) {
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dev->verify_cb(dev, result, img);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: stop verification */
|
|
||||||
int fpi_drv_verify_stop(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
|
||||||
&& dev->state != DEV_STATE_VERIFYING
|
|
||||||
&& dev->state != DEV_STATE_VERIFY_DONE);
|
|
||||||
dev->verify_cb = NULL;
|
|
||||||
|
|
||||||
if (!drv->verify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->verify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_VERIFY_STOPPING;
|
|
||||||
return drv->verify_stop(dev, iterating);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: verification has stopped */
|
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Lib-driver: start identification */
|
|
||||||
int fpi_drv_identify_start(struct fp_dev *dev, fp_identify_cb callback,
|
|
||||||
struct fp_print_data **gallery)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
|
||||||
dev->identify_cb = callback;
|
|
||||||
dev->identify_data = gallery;
|
|
||||||
r = drv->identify_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: identification has started, expect results soon */
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING);
|
|
||||||
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_IDENTIFYING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: report a verify result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_ERROR);
|
|
||||||
if (result < 0 || result == FP_VERIFY_NO_MATCH
|
|
||||||
|| result == FP_VERIFY_MATCH) {
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev->identify_cb) {
|
|
||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dev->identify_cb(dev, result, match_offset, img);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lib-driver: stop identification */
|
|
||||||
int fpi_drv_identify_stop(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv = dev->drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
|
||||||
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
|
||||||
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
|
||||||
dev->identify_cb = NULL;
|
|
||||||
|
|
||||||
if (!drv->identify_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->identify_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_IDENTIFY_STOPPING;
|
|
||||||
return drv->identify_stop(dev, iterating);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Driver-lib: identification has stopped */
|
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SSM: sequential state machine
|
/* SSM: sequential state machine
|
||||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
* 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
|
* In most cases, the state machine is entirely linear - you only go to the
|
||||||
|
|
|
@ -91,15 +91,6 @@ enum fp_dev_state {
|
||||||
DEV_STATE_IDENTIFY_STOPPING,
|
DEV_STATE_IDENTIFY_STOPPING,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img);
|
|
||||||
|
|
||||||
typedef void (*fp_verify_cb)(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img);
|
|
||||||
|
|
||||||
typedef void (*fp_identify_cb)(struct fp_dev *dev, int result,
|
|
||||||
size_t match_offset, struct fp_img *img);
|
|
||||||
|
|
||||||
struct fp_dev {
|
struct fp_dev {
|
||||||
struct fp_driver *drv;
|
struct fp_driver *drv;
|
||||||
libusb_dev_handle *udev;
|
libusb_dev_handle *udev;
|
||||||
|
@ -114,15 +105,29 @@ struct fp_dev {
|
||||||
/* drivers should not mess with any of the below */
|
/* drivers should not mess with any of the below */
|
||||||
enum fp_dev_state state;
|
enum fp_dev_state state;
|
||||||
|
|
||||||
/* FIXME: convert this to generic state operational data mechanism? */
|
|
||||||
int __enroll_stage;
|
int __enroll_stage;
|
||||||
fp_enroll_stage_cb enroll_cb;
|
|
||||||
void *enroll_data;
|
/* async I/O callbacks and data */
|
||||||
void *sync_verify_data;
|
/* FIXME: convert this to generic state operational data mechanism? */
|
||||||
|
fp_dev_open_cb open_cb;
|
||||||
|
void *open_cb_data;
|
||||||
|
fp_dev_close_cb close_cb;
|
||||||
|
void *close_cb_data;
|
||||||
|
fp_enroll_stage_cb enroll_stage_cb;
|
||||||
|
void *enroll_stage_cb_data;
|
||||||
|
fp_enroll_stop_cb enroll_stop_cb;
|
||||||
|
void *enroll_stop_cb_data;
|
||||||
fp_verify_cb verify_cb;
|
fp_verify_cb verify_cb;
|
||||||
void *identify_data;
|
void *verify_cb_data;
|
||||||
void *sync_identify_data;
|
fp_verify_stop_cb verify_stop_cb;
|
||||||
|
void *verify_stop_cb_data;
|
||||||
fp_identify_cb identify_cb;
|
fp_identify_cb identify_cb;
|
||||||
|
void *identify_cb_data;
|
||||||
|
fp_identify_stop_cb identify_stop_cb;
|
||||||
|
void *identify_stop_cb_data;
|
||||||
|
|
||||||
|
/* FIXME: better place to put this? */
|
||||||
|
struct fp_print_data **identify_gallery;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fp_imgdev_state {
|
enum fp_imgdev_state {
|
||||||
|
@ -197,8 +202,8 @@ struct fp_driver {
|
||||||
|
|
||||||
/* Device operations */
|
/* Device operations */
|
||||||
int (*discover)(const struct usb_id *usb_id, uint32_t *devtype);
|
int (*discover)(const struct usb_id *usb_id, uint32_t *devtype);
|
||||||
int (*init)(struct fp_dev *dev, unsigned long driver_data);
|
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
||||||
void (*deinit)(struct fp_dev *dev);
|
void (*close)(struct fp_dev *dev);
|
||||||
int (*enroll_start)(struct fp_dev *dev);
|
int (*enroll_start)(struct fp_dev *dev);
|
||||||
int (*enroll_stop)(struct fp_dev *dev);
|
int (*enroll_stop)(struct fp_dev *dev);
|
||||||
int (*verify_start)(struct fp_dev *dev);
|
int (*verify_start)(struct fp_dev *dev);
|
||||||
|
@ -221,8 +226,8 @@ struct fp_img_driver {
|
||||||
int bz3_threshold;
|
int bz3_threshold;
|
||||||
|
|
||||||
/* Device operations */
|
/* Device operations */
|
||||||
int (*init)(struct fp_img_dev *dev, unsigned long driver_data);
|
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
||||||
void (*deinit)(struct fp_img_dev *dev);
|
void (*close)(struct fp_img_dev *dev);
|
||||||
int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
void (*deactivate)(struct fp_img_dev *dev);
|
void (*deactivate)(struct fp_img_dev *dev);
|
||||||
|
@ -236,6 +241,8 @@ extern struct fp_img_driver aes2501_driver;
|
||||||
extern struct fp_img_driver aes4000_driver;
|
extern struct fp_img_driver aes4000_driver;
|
||||||
extern struct fp_img_driver fdu2000_driver;
|
extern struct fp_img_driver fdu2000_driver;
|
||||||
|
|
||||||
|
extern GSList *opened_devices;
|
||||||
|
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
||||||
|
|
||||||
#define fpi_driver_to_img_driver(drv) \
|
#define fpi_driver_to_img_driver(drv) \
|
||||||
|
@ -363,37 +370,27 @@ void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state);
|
||||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine);
|
void fpi_ssm_mark_completed(struct fpi_ssm *machine);
|
||||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error);
|
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error);
|
||||||
|
|
||||||
int fpi_drv_init(struct fp_dev *dev, unsigned long driver_data);
|
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
||||||
void fpi_drvcb_init_complete(struct fp_dev *dev, int status);
|
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
||||||
void fpi_drv_deinit(struct fp_dev *dev);
|
|
||||||
void fpi_drvcb_deinit_complete(struct fp_dev *dev);
|
|
||||||
|
|
||||||
int fpi_drv_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback);
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||||
struct fp_print_data *data, struct fp_img *img);
|
struct fp_print_data *data, struct fp_img *img);
|
||||||
int fpi_drv_enroll_stop(struct fp_dev *dev);
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
int fpi_drv_verify_start(struct fp_dev *dev, fp_verify_cb callback,
|
|
||||||
struct fp_print_data *data);
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||||
struct fp_img *img);
|
struct fp_img *img);
|
||||||
int fpi_drv_verify_stop(struct fp_dev *dev);
|
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
int fpi_drv_identify_start(struct fp_dev *dev, fp_identify_cb callback,
|
|
||||||
struct fp_print_data **gallery);
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||||
size_t match_offset, struct fp_img *img);
|
size_t match_offset, struct fp_img *img);
|
||||||
int fpi_drv_identify_stop(struct fp_dev *dev);
|
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
/* for image drivers */
|
/* for image drivers */
|
||||||
void fpi_imgdev_init_complete(struct fp_img_dev *imgdev, int status);
|
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
||||||
void fpi_imgdev_deinit_complete(struct fp_img_dev *imgdev);
|
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
||||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
||||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
||||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||||
|
|
|
@ -274,5 +274,42 @@ int fp_handle_events(void);
|
||||||
int fp_init(void);
|
int fp_init(void);
|
||||||
void fp_exit(void);
|
void fp_exit(void);
|
||||||
|
|
||||||
|
/* Asynchronous I/O */
|
||||||
|
|
||||||
|
typedef void (*fp_dev_open_cb)(struct fp_dev *dev, int status, void *user_data);
|
||||||
|
int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_dev_close_cb)(struct fp_dev *dev, void *user_data);
|
||||||
|
void fp_async_dev_close(struct fp_dev *dev, fp_dev_close_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result,
|
||||||
|
struct fp_print_data *print, struct fp_img *img, void *user_data);
|
||||||
|
int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_enroll_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||||
|
int fp_async_enroll_stop(struct fp_dev *dev, fp_enroll_stop_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_verify_cb)(struct fp_dev *dev, int result,
|
||||||
|
struct fp_img *img, void *user_data);
|
||||||
|
int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data,
|
||||||
|
fp_verify_cb callback, void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_verify_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||||
|
int fp_async_verify_stop(struct fp_dev *dev, fp_verify_stop_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_identify_cb)(struct fp_dev *dev, int result,
|
||||||
|
size_t match_offset, struct fp_img *img, void *user_data);
|
||||||
|
int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery,
|
||||||
|
fp_identify_cb callback, void *user_data);
|
||||||
|
|
||||||
|
typedef void (*fp_identify_stop_cb)(struct fp_dev *dev, void *user_data);
|
||||||
|
int fp_async_identify_stop(struct fp_dev *dev, fp_identify_stop_cb callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
#define MIN_ACCEPTABLE_MINUTIAE 10
|
||||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||||
|
|
||||||
static int img_dev_init(struct fp_dev *dev, unsigned long driver_data)
|
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||||
|
@ -40,12 +40,12 @@ static int img_dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||||
/* for consistency in driver code, allow udev access through imgdev */
|
/* for consistency in driver code, allow udev access through imgdev */
|
||||||
imgdev->udev = dev->udev;
|
imgdev->udev = dev->udev;
|
||||||
|
|
||||||
if (imgdrv->init) {
|
if (imgdrv->open) {
|
||||||
r = imgdrv->init(imgdev, driver_data);
|
r = imgdrv->open(imgdev, driver_data);
|
||||||
if (r)
|
if (r)
|
||||||
goto err;
|
goto err;
|
||||||
} else {
|
} else {
|
||||||
fpi_drvcb_init_complete(dev, 0);
|
fpi_drvcb_open_complete(dev, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -54,25 +54,25 @@ err:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpi_imgdev_init_complete(struct fp_img_dev *imgdev, int status)
|
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
|
||||||
{
|
{
|
||||||
fpi_drvcb_init_complete(imgdev->dev, status);
|
fpi_drvcb_open_complete(imgdev->dev, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void img_dev_deinit(struct fp_dev *dev)
|
static void img_dev_close(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->priv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||||
|
|
||||||
if (imgdrv->deinit)
|
if (imgdrv->close)
|
||||||
imgdrv->deinit(imgdev);
|
imgdrv->close(imgdev);
|
||||||
else
|
else
|
||||||
fpi_drvcb_deinit_complete(dev);
|
fpi_drvcb_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpi_imgdev_deinit_complete(struct fp_img_dev *imgdev)
|
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
fpi_drvcb_deinit_complete(imgdev->dev);
|
fpi_drvcb_close_complete(imgdev->dev);
|
||||||
g_free(imgdev);
|
g_free(imgdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +173,9 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||||
gboolean present)
|
gboolean present)
|
||||||
{
|
{
|
||||||
int r = imgdev->action_result;
|
int r = imgdev->action_result;
|
||||||
|
struct fp_print_data *data = imgdev->acquire_data;
|
||||||
|
struct fp_img *img = imgdev->acquire_img;
|
||||||
|
|
||||||
fp_dbg(present ? "finger on sensor" : "finger removed");
|
fp_dbg(present ? "finger on sensor" : "finger removed");
|
||||||
|
|
||||||
if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) {
|
if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) {
|
||||||
|
@ -185,25 +188,29 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* clear these before reporting results to avoid complications with
|
||||||
|
* call cascading in and out of the library */
|
||||||
|
imgdev->acquire_img = NULL;
|
||||||
|
imgdev->acquire_data = NULL;
|
||||||
|
|
||||||
|
/* finger removed, report results */
|
||||||
switch (imgdev->action) {
|
switch (imgdev->action) {
|
||||||
case IMG_ACTION_ENROLL:
|
case IMG_ACTION_ENROLL:
|
||||||
fpi_drvcb_enroll_stage_completed(imgdev->dev, r, imgdev->acquire_data,
|
fp_dbg("reporting enroll result");
|
||||||
imgdev->acquire_img);
|
fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_VERIFY:
|
case IMG_ACTION_VERIFY:
|
||||||
fpi_drvcb_report_verify_result(imgdev->dev, r, imgdev->acquire_img);
|
fpi_drvcb_report_verify_result(imgdev->dev, r, img);
|
||||||
fp_print_data_free(imgdev->acquire_data);
|
fp_print_data_free(data);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_IDENTIFY:
|
case IMG_ACTION_IDENTIFY:
|
||||||
fpi_drvcb_report_identify_result(imgdev->dev, r,
|
fpi_drvcb_report_identify_result(imgdev->dev, r,
|
||||||
imgdev->identify_match_offset, imgdev->acquire_img);
|
imgdev->identify_match_offset, img);
|
||||||
fp_print_data_free(imgdev->acquire_data);
|
fp_print_data_free(data);
|
||||||
default:
|
default:
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
fp_err("unhandled action %d", imgdev->action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
imgdev->acquire_img = NULL;
|
|
||||||
imgdev->acquire_data = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_process_img(struct fp_img_dev *imgdev)
|
static void verify_process_img(struct fp_img_dev *imgdev)
|
||||||
|
@ -237,7 +244,7 @@ static void identify_process_img(struct fp_img_dev *imgdev)
|
||||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
|
|
||||||
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
||||||
imgdev->dev->identify_data, match_score, &match_offset);
|
imgdev->dev->identify_gallery, match_score, &match_offset);
|
||||||
|
|
||||||
imgdev->action_result = r;
|
imgdev->action_result = r;
|
||||||
imgdev->identify_match_offset = match_offset;
|
imgdev->identify_match_offset = match_offset;
|
||||||
|
@ -486,8 +493,8 @@ static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
||||||
{
|
{
|
||||||
idriver->driver.type = DRIVER_IMAGING;
|
idriver->driver.type = DRIVER_IMAGING;
|
||||||
idriver->driver.init = img_dev_init;
|
idriver->driver.open = img_dev_open;
|
||||||
idriver->driver.deinit = img_dev_deinit;
|
idriver->driver.close = img_dev_close;
|
||||||
idriver->driver.enroll_start = img_dev_enroll_start;
|
idriver->driver.enroll_start = img_dev_enroll_start;
|
||||||
idriver->driver.enroll_stop = img_dev_enroll_stop;
|
idriver->driver.enroll_stop = img_dev_enroll_stop;
|
||||||
idriver->driver.verify_start = img_dev_verify_start;
|
idriver->driver.verify_start = img_dev_verify_start;
|
||||||
|
|
512
libfprint/sync.c
Normal file
512
libfprint/sync.c
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
/*
|
||||||
|
* Synchronous I/O functionality
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "sync"
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "fp_internal.h"
|
||||||
|
|
||||||
|
struct sync_open_data {
|
||||||
|
struct fp_dev *dev;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sync_open_cb(struct fp_dev *dev, int status, void *user_data)
|
||||||
|
{
|
||||||
|
struct sync_open_data *odata = user_data;
|
||||||
|
fp_dbg("status %d", status);
|
||||||
|
odata->dev = dev;
|
||||||
|
odata->status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \ingroup dev
|
||||||
|
* Opens and initialises a device. This is the function you call in order
|
||||||
|
* to convert a \ref dscv_dev "discovered device" into an actual device handle
|
||||||
|
* that you can perform operations with.
|
||||||
|
* \param ddev the discovered device to open
|
||||||
|
* \returns the opened device handle, or NULL on error
|
||||||
|
*/
|
||||||
|
API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
||||||
|
{
|
||||||
|
struct fp_dev *dev = NULL;
|
||||||
|
struct sync_open_data *odata = g_malloc0(sizeof(*odata));
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
r = fp_async_dev_open(ddev, sync_open_cb, odata);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (!odata->dev)
|
||||||
|
if (fp_handle_events() < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (odata->status == 0)
|
||||||
|
dev = odata->dev;
|
||||||
|
else
|
||||||
|
fp_dev_close(odata->dev);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free(odata);
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sync_close_cb(struct fp_dev *dev, void *user_data)
|
||||||
|
{
|
||||||
|
fp_dbg("");
|
||||||
|
gboolean *closed = user_data;
|
||||||
|
*closed = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \ingroup dev
|
||||||
|
* Close a device. You must call this function when you are finished using
|
||||||
|
* a fingerprint device.
|
||||||
|
* \param dev the device to close. If NULL, function simply returns.
|
||||||
|
*/
|
||||||
|
API_EXPORTED void fp_dev_close(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
gboolean closed = FALSE;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fp_dbg("");
|
||||||
|
fp_async_dev_close(dev, sync_close_cb, &closed);
|
||||||
|
while (!closed)
|
||||||
|
if (fp_handle_events() < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sync_enroll_data {
|
||||||
|
gboolean populated;
|
||||||
|
int result;
|
||||||
|
struct fp_print_data *data;
|
||||||
|
struct fp_img *img;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sync_enroll_cb(struct fp_dev *dev, int result,
|
||||||
|
struct fp_print_data *data, struct fp_img *img, void *user_data)
|
||||||
|
{
|
||||||
|
struct sync_enroll_data *edata = user_data;
|
||||||
|
fp_dbg("result %d", result);
|
||||||
|
edata->result = result;
|
||||||
|
edata->data = data;
|
||||||
|
edata->img = img;
|
||||||
|
edata->populated = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
|
||||||
|
{
|
||||||
|
gboolean *stopped = user_data;
|
||||||
|
fp_dbg("");
|
||||||
|
*stopped = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \ingroup dev
|
||||||
|
* Performs an enroll stage. See \ref enrolling for an explanation of enroll
|
||||||
|
* stages.
|
||||||
|
*
|
||||||
|
* If no enrollment is in process, this kicks of the process and runs the
|
||||||
|
* first stage. If an enrollment is already in progress, calling this
|
||||||
|
* function runs the next stage, which may well be the last.
|
||||||
|
*
|
||||||
|
* A negative error code may be returned from any stage. When this occurs,
|
||||||
|
* further calls to the enroll function will start a new enrollment process,
|
||||||
|
* i.e. a negative error code indicates that the enrollment process has been
|
||||||
|
* aborted. These error codes only ever indicate unexpected internal errors
|
||||||
|
* or I/O problems.
|
||||||
|
*
|
||||||
|
* The RETRY codes from #fp_enroll_result may be returned from any enroll
|
||||||
|
* stage. These codes indicate that the scan was not succesful in that the
|
||||||
|
* user did not position their finger correctly or similar. When a RETRY code
|
||||||
|
* is returned, the enrollment stage is <b>not</b> advanced, so the next call
|
||||||
|
* into this function will retry the current stage again. The current stage may
|
||||||
|
* need to be retried several times.
|
||||||
|
*
|
||||||
|
* The fp_enroll_result#FP_ENROLL_FAIL code may be returned from any enroll
|
||||||
|
* stage. This code indicates that even though the scans themselves have been
|
||||||
|
* acceptable, data processing applied to these scans produces incomprehensible
|
||||||
|
* results. In other words, the user may have been scanning a different finger
|
||||||
|
* for each stage or something like that. Like negative error codes, this
|
||||||
|
* return code indicates that the enrollment process has been aborted.
|
||||||
|
*
|
||||||
|
* The fp_enroll_result#FP_ENROLL_PASS code will only ever be returned for
|
||||||
|
* non-final stages. This return code indicates that the scan was acceptable
|
||||||
|
* and the next call into this function will advance onto the next enroll
|
||||||
|
* stage.
|
||||||
|
*
|
||||||
|
* The fp_enroll_result#FP_ENROLL_COMPLETE code will only ever be returned
|
||||||
|
* from the final enroll stage. It indicates that enrollment completed
|
||||||
|
* successfully, and that print_data has been assigned to point to the
|
||||||
|
* resultant enrollment data. The print_data parameter will not be modified
|
||||||
|
* during any other enrollment stages, hence it is actually legal to pass NULL
|
||||||
|
* as this argument for all but the final stage.
|
||||||
|
*
|
||||||
|
* If the device is an imaging device, it can also return the image from
|
||||||
|
* the scan, even when the enroll fails with a RETRY or FAIL code. It is legal
|
||||||
|
* to call this function even on non-imaging devices, just don't expect them to
|
||||||
|
* provide images.
|
||||||
|
*
|
||||||
|
* \param dev the device
|
||||||
|
* \param print_data a location to return the resultant enrollment data from
|
||||||
|
* the final stage. Must be freed with fp_print_data_free() after use.
|
||||||
|
* \param img location to store the scan image. accepts NULL for no image
|
||||||
|
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||||
|
* use.
|
||||||
|
* \return negative code on error, otherwise a code from #fp_enroll_result
|
||||||
|
*/
|
||||||
|
API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
||||||
|
struct fp_print_data **print_data, struct fp_img **img)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
int stage = dev->__enroll_stage;
|
||||||
|
gboolean final = FALSE;
|
||||||
|
gboolean stopped = FALSE;
|
||||||
|
struct sync_enroll_data *edata;
|
||||||
|
int r;
|
||||||
|
fp_dbg("");
|
||||||
|
|
||||||
|
/* FIXME __enroll_stage is ugly, can we replace it by some function that
|
||||||
|
* says whether we're enrolling or not, and then put __enroll_stage into
|
||||||
|
* edata? */
|
||||||
|
|
||||||
|
if (stage == -1) {
|
||||||
|
edata = g_malloc0(sizeof(struct sync_enroll_data));
|
||||||
|
r = fp_async_enroll_start(dev, sync_enroll_cb, edata);
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(edata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->__enroll_stage = ++stage;
|
||||||
|
} else if (stage >= dev->nr_enroll_stages) {
|
||||||
|
fp_err("exceeding number of enroll stages for device claimed by "
|
||||||
|
"driver %s (%d stages)", drv->name, dev->nr_enroll_stages);
|
||||||
|
dev->__enroll_stage = -1;
|
||||||
|
r = -EINVAL;
|
||||||
|
final = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
fp_dbg("%s will handle enroll stage %d/%d", drv->name, stage,
|
||||||
|
dev->nr_enroll_stages - 1);
|
||||||
|
|
||||||
|
/* FIXME this isn't very clean */
|
||||||
|
edata = dev->enroll_stage_cb_data;
|
||||||
|
|
||||||
|
while (!edata->populated) {
|
||||||
|
r = fp_handle_events();
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(edata);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edata->populated = FALSE;
|
||||||
|
|
||||||
|
if (img)
|
||||||
|
*img = edata->img;
|
||||||
|
else
|
||||||
|
fp_img_free(edata->img);
|
||||||
|
|
||||||
|
r = edata->result;
|
||||||
|
switch (r) {
|
||||||
|
case FP_ENROLL_PASS:
|
||||||
|
fp_dbg("enroll stage passed");
|
||||||
|
dev->__enroll_stage = stage + 1;
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_COMPLETE:
|
||||||
|
fp_dbg("enroll complete");
|
||||||
|
dev->__enroll_stage = -1;
|
||||||
|
*print_data = edata->data;
|
||||||
|
final = TRUE;
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_RETRY:
|
||||||
|
fp_dbg("enroll should retry");
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_RETRY_TOO_SHORT:
|
||||||
|
fp_dbg("swipe was too short, enroll should retry");
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_RETRY_CENTER_FINGER:
|
||||||
|
fp_dbg("finger was not centered, enroll should retry");
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_RETRY_REMOVE_FINGER:
|
||||||
|
fp_dbg("scan failed, remove finger and retry");
|
||||||
|
break;
|
||||||
|
case FP_ENROLL_FAIL:
|
||||||
|
fp_err("enroll failed");
|
||||||
|
dev->__enroll_stage = -1;
|
||||||
|
final = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fp_err("unrecognised return code %d", r);
|
||||||
|
dev->__enroll_stage = -1;
|
||||||
|
r = -EINVAL;
|
||||||
|
final = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (final) {
|
||||||
|
fp_dbg("ending enrollment");
|
||||||
|
g_free(edata);
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (fp_async_enroll_stop(dev, enroll_stop_cb, &stopped) == 0)
|
||||||
|
while (!stopped)
|
||||||
|
if (fp_handle_events() < 0)
|
||||||
|
break;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sync_verify_data {
|
||||||
|
gboolean populated;
|
||||||
|
int result;
|
||||||
|
struct fp_img *img;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sync_verify_cb(struct fp_dev *dev, int result, struct fp_img *img,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct sync_verify_data *vdata = user_data;
|
||||||
|
vdata->result = result;
|
||||||
|
vdata->img = img;
|
||||||
|
vdata->populated = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void verify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||||
|
{
|
||||||
|
gboolean *stopped = user_data;
|
||||||
|
fp_dbg("");
|
||||||
|
*stopped = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \ingroup dev
|
||||||
|
* Performs a new scan and verify it against a previously enrolled print.
|
||||||
|
* If the device is an imaging device, it can also return the image from
|
||||||
|
* the scan, even when the verify fails with a RETRY code. It is legal to
|
||||||
|
* call this function even on non-imaging devices, just don't expect them to
|
||||||
|
* provide images.
|
||||||
|
*
|
||||||
|
* \param dev the device to perform the scan.
|
||||||
|
* \param enrolled_print the print to verify against. Must have been previously
|
||||||
|
* enrolled with a device compatible to the device selected to perform the scan.
|
||||||
|
* \param img location to store the scan image. accepts NULL for no image
|
||||||
|
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||||
|
* use.
|
||||||
|
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||||
|
*/
|
||||||
|
API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
||||||
|
struct fp_print_data *enrolled_print, struct fp_img **img)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
struct sync_verify_data *vdata;
|
||||||
|
gboolean stopped = FALSE;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!enrolled_print) {
|
||||||
|
fp_err("no print given");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fp_dev_supports_print_data(dev, enrolled_print)) {
|
||||||
|
fp_err("print is not compatible with device");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg("to be handled by %s", drv->name);
|
||||||
|
vdata = g_malloc0(sizeof(struct sync_verify_data));
|
||||||
|
r = fp_async_verify_start(dev, enrolled_print, sync_verify_cb, vdata);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_dbg("verify_start error %d", r);
|
||||||
|
g_free(vdata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!vdata->populated) {
|
||||||
|
r = fp_handle_events();
|
||||||
|
if (r < 0) {
|
||||||
|
g_free(vdata);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img)
|
||||||
|
*img = vdata->img;
|
||||||
|
else
|
||||||
|
fp_img_free(vdata->img);
|
||||||
|
|
||||||
|
r = vdata->result;
|
||||||
|
g_free(vdata);
|
||||||
|
switch (r) {
|
||||||
|
case FP_VERIFY_NO_MATCH:
|
||||||
|
fp_dbg("result: no match");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_MATCH:
|
||||||
|
fp_dbg("result: match");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY:
|
||||||
|
fp_dbg("verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_TOO_SHORT:
|
||||||
|
fp_dbg("swipe was too short, verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_CENTER_FINGER:
|
||||||
|
fp_dbg("finger was not centered, verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
||||||
|
fp_dbg("scan failed, remove finger and retry");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fp_err("unrecognised return code %d", r);
|
||||||
|
r = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
fp_dbg("ending verification");
|
||||||
|
if (fp_async_verify_stop(dev, verify_stop_cb, &stopped) == 0)
|
||||||
|
while (!stopped)
|
||||||
|
if (fp_handle_events() < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sync_identify_data {
|
||||||
|
gboolean populated;
|
||||||
|
int result;
|
||||||
|
size_t match_offset;
|
||||||
|
struct fp_img *img;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void sync_identify_cb(struct fp_dev *dev, int result,
|
||||||
|
size_t match_offset, struct fp_img *img, void *user_data)
|
||||||
|
{
|
||||||
|
struct sync_identify_data *idata = user_data;
|
||||||
|
idata->result = result;
|
||||||
|
idata->match_offset = match_offset;
|
||||||
|
idata->img = img;
|
||||||
|
idata->populated = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void identify_stop_cb(struct fp_dev *dev, void *user_data)
|
||||||
|
{
|
||||||
|
gboolean *stopped = user_data;
|
||||||
|
fp_dbg("");
|
||||||
|
*stopped = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \ingroup dev
|
||||||
|
* Performs a new scan and attempts to identify the scanned finger against
|
||||||
|
* a collection of previously enrolled fingerprints.
|
||||||
|
* If the device is an imaging device, it can also return the image from
|
||||||
|
* the scan, even when identification fails with a RETRY code. It is legal to
|
||||||
|
* call this function even on non-imaging devices, just don't expect them to
|
||||||
|
* provide images.
|
||||||
|
*
|
||||||
|
* This function returns codes from #fp_verify_result. The return code
|
||||||
|
* fp_verify_result#FP_VERIFY_MATCH indicates that the scanned fingerprint
|
||||||
|
* does appear in the print gallery, and the match_offset output parameter
|
||||||
|
* will indicate the index into the print gallery array of the matched print.
|
||||||
|
*
|
||||||
|
* This function will not necessarily examine the whole print gallery, it
|
||||||
|
* will return as soon as it finds a matching print.
|
||||||
|
*
|
||||||
|
* Not all devices support identification. -ENOTSUP will be returned when
|
||||||
|
* this is the case.
|
||||||
|
*
|
||||||
|
* \param dev the device to perform the scan.
|
||||||
|
* \param print_gallery NULL-terminated array of pointers to the prints to
|
||||||
|
* identify against. Each one must have been previously enrolled with a device
|
||||||
|
* compatible to the device selected to perform the scan.
|
||||||
|
* \param match_offset output location to store the array index of the matched
|
||||||
|
* gallery print (if any was found). Only valid if FP_VERIFY_MATCH was
|
||||||
|
* returned.
|
||||||
|
* \param img location to store the scan image. accepts NULL for no image
|
||||||
|
* storage. If an image is returned, it must be freed with fp_img_free() after
|
||||||
|
* use.
|
||||||
|
* \return negative code on error, otherwise a code from #fp_verify_result
|
||||||
|
*/
|
||||||
|
API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
||||||
|
struct fp_print_data **print_gallery, size_t *match_offset,
|
||||||
|
struct fp_img **img)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv = dev->drv;
|
||||||
|
gboolean stopped = FALSE;
|
||||||
|
struct sync_identify_data *idata
|
||||||
|
= g_malloc0(sizeof(struct sync_identify_data));
|
||||||
|
int r;
|
||||||
|
|
||||||
|
fp_dbg("to be handled by %s", drv->name);
|
||||||
|
|
||||||
|
r = fp_async_identify_start(dev, print_gallery, sync_identify_cb, idata);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("identify_start error %d", r);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!idata->populated) {
|
||||||
|
r = fp_handle_events();
|
||||||
|
if (r < 0)
|
||||||
|
goto err_stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img)
|
||||||
|
*img = idata->img;
|
||||||
|
else
|
||||||
|
fp_img_free(idata->img);
|
||||||
|
|
||||||
|
switch (idata->result) {
|
||||||
|
case FP_VERIFY_NO_MATCH:
|
||||||
|
fp_dbg("result: no match");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_MATCH:
|
||||||
|
fp_dbg("result: match at offset %zd", idata->match_offset);
|
||||||
|
*match_offset = idata->match_offset;
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY:
|
||||||
|
fp_dbg("verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_TOO_SHORT:
|
||||||
|
fp_dbg("swipe was too short, verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_CENTER_FINGER:
|
||||||
|
fp_dbg("finger was not centered, verify should retry");
|
||||||
|
break;
|
||||||
|
case FP_VERIFY_RETRY_REMOVE_FINGER:
|
||||||
|
fp_dbg("scan failed, remove finger and retry");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fp_err("unrecognised return code %d", r);
|
||||||
|
r = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_stop:
|
||||||
|
if (fp_async_identify_stop(dev, identify_stop_cb, &stopped) == 0)
|
||||||
|
while (!stopped)
|
||||||
|
if (fp_handle_events() < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
err:
|
||||||
|
g_free(idata);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue