Port primitive driver layer to asynchronous model
This commit is contained in:
parent
69760547df
commit
5b1f6a0df7
4 changed files with 742 additions and 64 deletions
275
libfprint/core.c
275
libfprint/core.c
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Core functions for libfprint
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* 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
|
||||
|
@ -325,7 +325,6 @@ static void register_driver(struct fp_driver *drv)
|
|||
}
|
||||
|
||||
static struct fp_driver * const primitive_drivers[] = {
|
||||
/* &upekts_driver, */
|
||||
};
|
||||
|
||||
static struct fp_img_driver * const img_drivers[] = {
|
||||
|
@ -578,6 +577,7 @@ API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
|||
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");
|
||||
|
@ -588,27 +588,43 @@ API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev)
|
|||
dev->drv = drv;
|
||||
dev->udev = udevh;
|
||||
dev->__enroll_stage = -1;
|
||||
dev->state = DEV_STATE_INITIALIZING;
|
||||
|
||||
if (drv->init) {
|
||||
r = drv->init(dev, ddev->driver_data);
|
||||
if (r) {
|
||||
fp_err("device initialisation failed, driver=%s", drv->name);
|
||||
libusb_close(udevh);
|
||||
g_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
r = fpi_drv_init(dev, ddev->driver_data);
|
||||
if (r) {
|
||||
fp_err("device initialisation failed, driver=%s", drv->name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
fp_dbg("");
|
||||
while (dev->state == DEV_STATE_INITIALIZING)
|
||||
if (libusb_poll() < 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 (libusb_poll() < 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)
|
||||
{
|
||||
if (dev->drv->exit)
|
||||
dev->drv->exit(dev);
|
||||
fpi_drv_deinit(dev);
|
||||
while (dev->state == DEV_STATE_DEINITIALIZING)
|
||||
if (libusb_poll() < 0)
|
||||
break;
|
||||
|
||||
libusb_close(dev->udev);
|
||||
g_free(dev);
|
||||
}
|
||||
|
@ -751,7 +767,7 @@ API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
|||
*/
|
||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
||||
{
|
||||
return dev->drv->identify != NULL;
|
||||
return dev->drv->identify_start != NULL;
|
||||
}
|
||||
|
||||
/** \ingroup dev
|
||||
|
@ -824,6 +840,23 @@ API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
|||
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.
|
||||
|
@ -881,44 +914,66 @@ 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;
|
||||
struct fp_img *_img = NULL;
|
||||
int ret;
|
||||
int stage = dev->__enroll_stage;
|
||||
gboolean initial = FALSE;
|
||||
gboolean final = FALSE;
|
||||
struct sync_enroll_data *edata;
|
||||
int r;
|
||||
|
||||
if (!dev->nr_enroll_stages || !drv->enroll) {
|
||||
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) {
|
||||
initial = TRUE;
|
||||
dev->__enroll_stage = ++stage;
|
||||
}
|
||||
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 = libusb_poll();
|
||||
if (r < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (stage >= dev->nr_enroll_stages) {
|
||||
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;
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
final = TRUE;
|
||||
goto out;
|
||||
}
|
||||
fp_dbg("%s will handle enroll stage %d/%d%s", drv->name, stage,
|
||||
dev->nr_enroll_stages - 1, initial ? " (initial)" : "");
|
||||
fp_dbg("%s will handle enroll stage %d/%d", drv->name, stage,
|
||||
dev->nr_enroll_stages - 1);
|
||||
|
||||
ret = drv->enroll(dev, initial, stage, print_data, &_img);
|
||||
if (ret < 0) {
|
||||
fp_err("enroll failed with code %d", ret);
|
||||
dev->__enroll_stage = -1;
|
||||
return ret;
|
||||
edata = dev->enroll_data;
|
||||
while (!edata->populated) {
|
||||
r = libusb_poll();
|
||||
if (r < 0) {
|
||||
g_free(edata);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
edata->populated = FALSE;
|
||||
|
||||
if (img)
|
||||
*img = _img;
|
||||
*img = edata->img;
|
||||
else
|
||||
fp_img_free(_img);
|
||||
fp_img_free(edata->img);
|
||||
|
||||
switch (ret) {
|
||||
r = edata->result;
|
||||
switch (r) {
|
||||
case FP_ENROLL_PASS:
|
||||
fp_dbg("enroll stage passed");
|
||||
dev->__enroll_stage = stage + 1;
|
||||
|
@ -926,6 +981,8 @@ API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
|||
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");
|
||||
|
@ -942,13 +999,49 @@ API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev,
|
|||
case FP_ENROLL_FAIL:
|
||||
fp_err("enroll failed");
|
||||
dev->__enroll_stage = -1;
|
||||
final = TRUE;
|
||||
break;
|
||||
default:
|
||||
fp_err("unrecognised return code %d", ret);
|
||||
fp_err("unrecognised return code %d", r);
|
||||
dev->__enroll_stage = -1;
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
final = TRUE;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
out:
|
||||
if (final) {
|
||||
fp_dbg("ending enrollment");
|
||||
if (fpi_drv_enroll_stop(dev) == 0)
|
||||
while (dev->state == DEV_STATE_ENROLL_STOPPING) {
|
||||
if (libusb_poll() < 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 (libusb_poll() < 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
|
||||
|
@ -970,7 +1063,7 @@ 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 fp_img *_img = NULL;
|
||||
struct sync_verify_data *vdata;
|
||||
int r;
|
||||
|
||||
if (!enrolled_print) {
|
||||
|
@ -978,9 +1071,9 @@ API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!drv->verify) {
|
||||
if (!drv->verify_start) {
|
||||
fp_err("driver %s has no verify func", drv->name);
|
||||
return -EINVAL;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!fp_dev_supports_print_data(dev, enrolled_print)) {
|
||||
|
@ -989,17 +1082,39 @@ API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
|||
}
|
||||
|
||||
fp_dbg("to be handled by %s", drv->name);
|
||||
r = drv->verify(dev, enrolled_print, &_img);
|
||||
r = fpi_drv_verify_start(dev, sync_verify_cb, enrolled_print);
|
||||
if (r < 0) {
|
||||
fp_dbg("verify error %d", r);
|
||||
fp_dbg("verify_start error %d", r);
|
||||
return r;
|
||||
}
|
||||
while (dev->state == DEV_STATE_VERIFY_STARTING) {
|
||||
r = libusb_poll();
|
||||
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 = libusb_poll();
|
||||
if (r < 0) {
|
||||
g_free(vdata);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (img)
|
||||
*img = _img;
|
||||
*img = vdata->img;
|
||||
else
|
||||
fp_img_free(_img);
|
||||
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");
|
||||
|
@ -1021,12 +1136,38 @@ API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev,
|
|||
break;
|
||||
default:
|
||||
fp_err("unrecognised return code %d", r);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
err:
|
||||
fp_dbg("ending verification");
|
||||
if (fpi_drv_verify_stop(dev) == 0) {
|
||||
while (dev->state == DEV_STATE_VERIFY_STOPPING) {
|
||||
if (libusb_poll() < 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.
|
||||
|
@ -1063,31 +1204,54 @@ API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
|||
struct fp_img **img)
|
||||
{
|
||||
struct fp_driver *drv = dev->drv;
|
||||
struct fp_img *_img;
|
||||
struct sync_identify_data *idata;
|
||||
int r;
|
||||
|
||||
if (!drv->identify) {
|
||||
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 = drv->identify(dev, print_gallery, match_offset, &_img);
|
||||
|
||||
r = fpi_drv_identify_start(dev, sync_identify_cb, print_gallery);
|
||||
if (r < 0) {
|
||||
fp_dbg("identify error %d", r);
|
||||
fp_err("identify_start error %d", r);
|
||||
return r;
|
||||
}
|
||||
while (dev->state == DEV_STATE_IDENTIFY_STARTING) {
|
||||
r = libusb_poll();
|
||||
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 = libusb_poll();
|
||||
if (r < 0) {
|
||||
g_free(idata);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (img)
|
||||
*img = _img;
|
||||
*img = idata->img;
|
||||
else
|
||||
fp_img_free(_img);
|
||||
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");
|
||||
|
@ -1103,7 +1267,16 @@ API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev,
|
|||
break;
|
||||
default:
|
||||
fp_err("unrecognised return code %d", r);
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
}
|
||||
g_free(dev->sync_identify_data);
|
||||
|
||||
err:
|
||||
if (fpi_drv_identify_stop(dev) == 0) {
|
||||
while (dev->state == DEV_STATE_IDENTIFY_STOPPING) {
|
||||
if (libusb_poll() < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
|
|
395
libfprint/drv.c
Normal file
395
libfprint/drv.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Functions to assist with asynchronous driver <---> library communications
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <errno.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;
|
||||
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;
|
||||
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_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);
|
||||
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
|
||||
* 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 SSM functions help you
|
||||
* implement such a machine.
|
||||
*
|
||||
* e.g. S1 --> S2 --> S3 --> S4
|
||||
* S1 is the start state
|
||||
* There is also an implicit error state and an implicit accepting state
|
||||
* (both with implicit edges from every state).
|
||||
*
|
||||
* To create a ssm, you pass a state handler function and the total number of
|
||||
* states (4 in the above example).
|
||||
*
|
||||
* To start a ssm, you pass in a completion callback function which gets
|
||||
* called when the ssm completes (both on error and on failure).
|
||||
*
|
||||
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
||||
* attempt to iterate beyond the final state - this is equivalent to marking
|
||||
* the ssm as successfully completed.
|
||||
*
|
||||
* To mark successful completion of a SSM, either iterate beyond the final
|
||||
* state or call fpi_ssm_mark_completed() from any state.
|
||||
*
|
||||
* To mark failed completion of a SSM, call fpi_ssm_mark_aborted() from any
|
||||
* state. You must pass a non-zero error code.
|
||||
*
|
||||
* Your state handling function looks at ssm->cur_state in order to determine
|
||||
* the current state and hence which operations to perform (a switch statement
|
||||
* is appropriate).
|
||||
* Typically, the state handling function fires off an asynchronous libusb
|
||||
* transfer, and the callback function iterates the machine to the next state
|
||||
* upon success (or aborts the machine on transfer failure).
|
||||
*
|
||||
* Your completion callback should examine ssm->error in order to determine
|
||||
* whether the ssm completed or failed. An error code of zero indicates
|
||||
* successful completion.
|
||||
*/
|
||||
|
||||
/* Allocate a new ssm */
|
||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
||||
int nr_states)
|
||||
{
|
||||
struct fpi_ssm *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;
|
||||
return machine;
|
||||
}
|
||||
|
||||
/* Free a ssm */
|
||||
void fpi_ssm_free(struct fpi_ssm *machine)
|
||||
{
|
||||
if (!machine)
|
||||
return;
|
||||
g_free(machine);
|
||||
}
|
||||
|
||||
/* Invoke the state handler */
|
||||
static void __ssm_call_handler(struct fpi_ssm *machine)
|
||||
{
|
||||
machine->handler(machine);
|
||||
}
|
||||
|
||||
/* Start a ssm. You can also restart a completed or aborted ssm. */
|
||||
void fpi_ssm_start(struct fpi_ssm *ssm, ssm_completed_fn callback)
|
||||
{
|
||||
BUG_ON(!ssm->completed);
|
||||
ssm->callback = callback;
|
||||
ssm->cur_state = 0;
|
||||
ssm->completed = FALSE;
|
||||
ssm->error = 0;
|
||||
__ssm_call_handler(ssm);
|
||||
}
|
||||
|
||||
/* Mark a ssm as completed successfully. */
|
||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->completed = TRUE;
|
||||
if (machine->callback)
|
||||
machine->callback(machine);
|
||||
}
|
||||
|
||||
/* Mark a ssm as aborted with error. */
|
||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error)
|
||||
{
|
||||
fp_dbg("error %d", error);
|
||||
BUG_ON(error == 0);
|
||||
machine->error = error;
|
||||
fpi_ssm_mark_completed(machine);
|
||||
}
|
||||
|
||||
/* Iterate to next state of a ssm */
|
||||
void fpi_ssm_next_state(struct fpi_ssm *machine)
|
||||
{
|
||||
BUG_ON(machine->completed);
|
||||
machine->cur_state++;
|
||||
if (machine->cur_state == machine->nr_states) {
|
||||
fpi_ssm_mark_completed(machine);
|
||||
} else {
|
||||
__ssm_call_handler(machine);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Internal/private definitions for libfprint
|
||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||||
* 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
|
||||
|
@ -62,6 +62,42 @@ void fpi_log(enum fpi_log_level, const char *component, const char *function,
|
|||
#define fp_warn(fmt...) _fpi_log(LOG_LEVEL_WARNING, fmt)
|
||||
#define fp_err(fmt...) _fpi_log(LOG_LEVEL_ERROR, fmt)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define BUG_ON(condition) \
|
||||
if ((condition)) fp_err("BUG at %s:%d", __FILE__, __LINE__)
|
||||
#else
|
||||
#define BUG_ON(condition)
|
||||
#endif
|
||||
|
||||
enum fp_dev_state {
|
||||
DEV_STATE_INITIAL = 0,
|
||||
DEV_STATE_ERROR,
|
||||
DEV_STATE_INITIALIZING,
|
||||
DEV_STATE_INITIALIZED,
|
||||
DEV_STATE_DEINITIALIZING,
|
||||
DEV_STATE_DEINITIALIZED,
|
||||
DEV_STATE_ENROLL_STARTING,
|
||||
DEV_STATE_ENROLLING,
|
||||
DEV_STATE_ENROLL_STOPPING,
|
||||
DEV_STATE_VERIFY_STARTING,
|
||||
DEV_STATE_VERIFYING,
|
||||
DEV_STATE_VERIFY_DONE,
|
||||
DEV_STATE_VERIFY_STOPPING,
|
||||
DEV_STATE_IDENTIFY_STARTING,
|
||||
DEV_STATE_IDENTIFYING,
|
||||
DEV_STATE_IDENTIFY_DONE,
|
||||
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_driver *drv;
|
||||
libusb_dev_handle *udev;
|
||||
|
@ -70,8 +106,21 @@ struct fp_dev {
|
|||
|
||||
int nr_enroll_stages;
|
||||
|
||||
/* drivers should not mess with these */
|
||||
/* read-only to drivers */
|
||||
struct fp_print_data *verify_data;
|
||||
|
||||
/* drivers should not mess with any of the below */
|
||||
enum fp_dev_state state;
|
||||
|
||||
/* FIXME: convert this to generic state operational data mechanism? */
|
||||
int __enroll_stage;
|
||||
fp_enroll_stage_cb enroll_cb;
|
||||
void *enroll_data;
|
||||
void *sync_verify_data;
|
||||
fp_verify_cb verify_cb;
|
||||
void *identify_data;
|
||||
void *sync_identify_data;
|
||||
fp_identify_cb identify_cb;
|
||||
};
|
||||
|
||||
struct fp_img_dev {
|
||||
|
@ -108,13 +157,13 @@ struct fp_driver {
|
|||
/* Device operations */
|
||||
int (*discover)(const struct usb_id *usb_id, uint32_t *devtype);
|
||||
int (*init)(struct fp_dev *dev, unsigned long driver_data);
|
||||
void (*exit)(struct fp_dev *dev);
|
||||
int (*enroll)(struct fp_dev *dev, gboolean initial, int stage,
|
||||
struct fp_print_data **print_data, struct fp_img **img);
|
||||
int (*verify)(struct fp_dev *dev, struct fp_print_data *data,
|
||||
struct fp_img **img);
|
||||
int (*identify)(struct fp_dev *dev, struct fp_print_data **print_gallery,
|
||||
size_t *match_offset, struct fp_img **img);
|
||||
void (*deinit)(struct fp_dev *dev);
|
||||
int (*enroll_start)(struct fp_dev *dev);
|
||||
int (*enroll_stop)(struct fp_dev *dev);
|
||||
int (*verify_start)(struct fp_dev *dev);
|
||||
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
int (*identify_start)(struct fp_dev *dev);
|
||||
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||
};
|
||||
|
||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
||||
|
@ -230,5 +279,66 @@ int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
|||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
||||
struct fp_print_data **gallery, int match_threshold, int *match_offset);
|
||||
|
||||
/* async drv <--> lib comms */
|
||||
|
||||
struct fpi_ssm;
|
||||
typedef void (*ssm_completed_fn)(struct fpi_ssm *ssm);
|
||||
typedef void (*ssm_handler_fn)(struct fpi_ssm *ssm);
|
||||
|
||||
/* sequential state machine: state machine that iterates sequentially over
|
||||
* a predefined series of states. can be aborted by either completion or
|
||||
* abortion error conditions. */
|
||||
struct fpi_ssm {
|
||||
struct fp_dev *dev;
|
||||
void *priv;
|
||||
int nr_states;
|
||||
int cur_state;
|
||||
gboolean completed;
|
||||
int error;
|
||||
ssm_completed_fn callback;
|
||||
ssm_handler_fn handler;
|
||||
};
|
||||
|
||||
|
||||
/* for library and drivers */
|
||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
||||
int nr_states);
|
||||
void fpi_ssm_free(struct fpi_ssm *machine);
|
||||
void fpi_ssm_start(struct fpi_ssm *machine, ssm_completed_fn callback);
|
||||
int fpi_ssm_has_completed(struct fpi_ssm *machine);
|
||||
|
||||
/* for drivers */
|
||||
void fpi_ssm_next_state(struct fpi_ssm *machine);
|
||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine);
|
||||
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_init_complete(struct fp_dev *dev, int status);
|
||||
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_stage_completed(struct fp_dev *dev, int result,
|
||||
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);
|
||||
|
||||
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_report_verify_result(struct fp_dev *dev, int result,
|
||||
struct fp_img *img);
|
||||
int fpi_drv_verify_stop(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_report_identify_result(struct fp_dev *dev, int result,
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -349,9 +349,9 @@ void fpi_img_driver_setup(struct fp_img_driver *idriver)
|
|||
{
|
||||
idriver->driver.type = DRIVER_IMAGING;
|
||||
idriver->driver.init = img_dev_init;
|
||||
idriver->driver.exit = img_dev_exit;
|
||||
idriver->driver.enroll = img_dev_enroll;
|
||||
idriver->driver.verify = img_dev_verify;
|
||||
idriver->driver.identify = img_dev_identify;
|
||||
//idriver->driver.exit = img_dev_exit;
|
||||
//idriver->driver.enroll = img_dev_enroll;
|
||||
//idriver->driver.verify = img_dev_verify;
|
||||
//idriver->driver.identify = img_dev_identify;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue