Add function to delete data in sensor.

Add example test app to test delete function.
  Remove sync database function in Synaptics driver.
This commit is contained in:
Vincent Huang 2019-04-25 13:54:26 +08:00 committed by Benjamin Berg
parent e513848871
commit 65483d51b7
13 changed files with 358 additions and 200 deletions

115
examples/delete.c Normal file
View file

@ -0,0 +1,115 @@
/*
* Example fingerprint delete finger program, which delete the right index
* finger which has been previously enrolled to disk.
* Copyright (C) 2019 Synaptics Inc
*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. Loading previously enrolled right index finger "
"data...\n");
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
if (r != 0) {
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
fprintf(stderr, "Did you remember to enroll your right index finger "
"first?\n");
goto out_close;
}
printf("Print loaded. delete data in sensor.\n");
if(!fp_dev_supports_data_in_sensor(dev))
{
printf("This driver doesn't support to store data in sensor.\n");
goto out_close;
}
r = fp_delete_finger(dev, data);
fp_print_data_free(data);
if (r) {
printf("delete finger failed with error %d :(\n", r);
}
else
{
printf("sensor data deleted. now delete host data");
r = fp_print_data_delete(dev, RIGHT_INDEX);
if (r < 0) {
printf("Delete sensor data successfully but delete host data failed. %d :(\n", r);
}
}
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
}

View file

@ -1,5 +1,5 @@
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ]
foreach example: examples
executable(example,
example + '.c',

View file

@ -43,6 +43,7 @@ typedef enum syna_state
SYNA_STATE_IDENTIFY_DELAY_RESULT ,
SYNA_STATE_VERIFY ,
SYNA_STATE_VERIFY_DELAY_RESULT ,
SYNA_STATE_DELETE ,
} syna_state_t;
typedef struct synaptics_dev_s
@ -57,11 +58,6 @@ typedef struct synaptics_dev_s
struct syna_enroll_resp_data enroll_resp_data;
gboolean isFingerOnSensor;
syna_state_t state;
pthread_mutex_t op_mutex;
pthread_cond_t op_cond;
int op_finished;
GSList* file_gslist;
GSList* sensor_gslist;
}synaptics_dev;
#endif //__synaptics_h__

View file

@ -190,9 +190,6 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
return -1;
}
sdev->usb_config->product_id = dsc.idProduct;
pthread_mutex_init(&sdev->op_mutex, NULL);
pthread_cond_init(&sdev->op_cond, NULL);
result = bmkt_init(&(sdev->ctx));
if (result != BMKT_SUCCESS)
@ -263,18 +260,6 @@ static void dev_exit(struct fp_dev *dev)
}
bmkt_exit(sdev->ctx);
ret = pthread_mutex_destroy(&sdev->op_mutex);
if (ret)
{
fp_err("failed to destroy mutex");
}
ret = pthread_cond_destroy(&sdev->op_cond);
if (ret)
{
fp_err("failed to destroy cond ");
}
g_free(sdev);
fpi_drvcb_close_complete(dev);
@ -299,121 +284,6 @@ static gboolean rand_string(char *str, size_t size)
#define TEMPLATE_ID_SIZE 20
void get_file_data(struct fp_dev *dev, const char *basepath)
{
char path[PATH_MAX];
struct dirent *dp;
DIR *dir = opendir(basepath);
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
if(!dir)
return;
while( (dp = readdir(dir)) != NULL)
{
if(strcmp(dp->d_name, ".")!=0 && strcmp(dp->d_name,"..")!=0)
{
strcpy(path,basepath);
strcat(path,"/");
strcat(path,dp->d_name);
fp_info("%s type is %d ",dp->d_name,dp->d_type);
if(dp->d_type == DT_REG)
{
gsize length;
gchar *contents;
GError *err = NULL;
struct fp_print_data *fdata;
fp_info(" load file %s ", path);
g_file_get_contents(path, &contents, &length, &err);
if (err) {
fp_err("load file failed ");
}
else
{
fdata = fp_print_data_from_data(contents, length);
struct fp_print_data_item *item = fdata->prints->data;
struct syna_mis_print_data *print_data =(struct syna_mis_print_data *) item -> data;
char *data_node=(char *)g_malloc0(strlen(print_data->user_id) + 1);
memcpy(data_node, print_data->user_id, strlen(print_data->user_id) + 1);
sdev->file_gslist = g_slist_append(sdev->file_gslist, data_node);
g_free(contents);
}
}
else
get_file_data(dev, path);
}
}
}
static int get_enrolled_users_resp(bmkt_response_t *resp, void *ctx)
{
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
struct fp_dev *dev=(struct fp_dev *)ctx;
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
switch (resp->response_id)
{
case BMKT_RSP_QUERY_FAIL:
fp_info("Failed to query enrolled users: %d", resp->result);
pthread_mutex_lock(&sdev->op_mutex);
sdev->op_finished = 1;
pthread_cond_signal(&sdev->op_cond);
pthread_mutex_unlock(&sdev->op_mutex);
break;
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
pthread_mutex_lock(&sdev->op_mutex);
sdev->op_finished = 1;
pthread_cond_signal(&sdev->op_cond);
pthread_mutex_unlock(&sdev->op_mutex);
fp_info("Query complete!");
break;
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
if (get_enroll_templates_resp->templates[n].user_id_len == 0)
continue;
fp_info("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d",
get_enroll_templates_resp->query_sequence,
get_enroll_templates_resp->total_query_messages,
n,
get_enroll_templates_resp->templates[n].template_status,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
char *data_node = (char *)g_malloc0(strlen(get_enroll_templates_resp->templates[n].user_id) + 1);
memcpy(data_node, get_enroll_templates_resp->templates[n].user_id,
strlen(get_enroll_templates_resp->templates[n].user_id) + 1 );
sdev->sensor_gslist = g_slist_prepend(sdev->sensor_gslist, data_node);
}
break;
}
return 0;
}
void get_sensor_data(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result;
sdev->op_finished = 0;
result = bmkt_get_enrolled_users(sdev->sensor, get_enrolled_users_resp, dev);
if (result != BMKT_SUCCESS)
{
fp_err("Failed to get enrolled users: %d", result);
}
else
{
fp_info("get enrolled data started.");
}
pthread_mutex_lock(&sdev->op_mutex);
if(sdev->op_finished == 0)
{
pthread_cond_wait(&sdev->op_cond, &sdev->op_mutex);
}
pthread_mutex_unlock(&sdev->op_mutex);
}
static int del_enrolled_user_resp(bmkt_response_t *resp, void *ctx)
{
bmkt_del_user_resp_t *del_user_resp = &resp->response.del_user_resp;
@ -428,84 +298,33 @@ static int del_enrolled_user_resp(bmkt_response_t *resp, void *ctx)
break;
case BMKT_RSP_DEL_USER_FP_FAIL:
fp_info("Failed to delete enrolled user: %d", resp->result);
pthread_mutex_lock(&sdev->op_mutex);
sdev->op_finished = 1;
pthread_cond_signal(&sdev->op_cond);
pthread_mutex_unlock(&sdev->op_mutex);
if(sdev->state == SYNA_STATE_DELETE)
{
/* Return result complete when record doesn't exist, otherwise host data
won't be deleted. */
if(resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
fpi_drvcb_delete_complete(dev, FP_DELETE_COMPLETE);
else
fpi_drvcb_delete_complete(dev, FP_DELETE_FAIL);
}
break;
case BMKT_RSP_DEL_USER_FP_OK:
fp_info("Successfully deleted enrolled user");
pthread_mutex_lock(&sdev->op_mutex);
sdev->op_finished = 1;
pthread_cond_signal(&sdev->op_cond);
pthread_mutex_unlock(&sdev->op_mutex);
if(sdev->state == SYNA_STATE_DELETE)
{
fpi_drvcb_delete_complete(dev, FP_DELETE_COMPLETE);
}
break;
}
return 0;
}
const char FPRINTD_DATAPATH[]="/usr/local/var/lib/fprint";
/*
* Delete the data which doesn't exist in fprintd folder from sensor database,
* otherwise, new finger may have problem to be recognized if it
* already exists in sensor.
*/
void sync_database(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result = 0;
int sindex, findex;
GSList* snode;
GSList* fnode;
get_file_data(dev, FPRINTD_DATAPATH);
get_sensor_data(dev);
for(sindex = 0; (snode = g_slist_nth(sdev->sensor_gslist, sindex)); sindex++)
{
for(findex = 0; (fnode = g_slist_nth(sdev->file_gslist, findex)); findex++)
{
if(strlen(snode->data) == strlen(fnode->data) &&
strncmp(snode->data, fnode->data, strlen(snode->data)) == 0)
{
break;
}
}
if(!fnode)
{
sdev->op_finished = 0;
result = bmkt_delete_enrolled_user(sdev->sensor, 1, snode->data,
strlen(snode->data), del_enrolled_user_resp, dev);
if (result != BMKT_SUCCESS)
{
fp_err("Failed to delete enrolled user: %d", result);
}
else
{
pthread_mutex_lock(&sdev->op_mutex);
if(sdev->op_finished == 0)
{
pthread_cond_wait(&sdev->op_cond, &sdev->op_mutex);
}
pthread_mutex_unlock(&sdev->op_mutex);
}
}
}
g_slist_free(sdev->file_gslist);
g_slist_free(sdev->sensor_gslist);
}
static int enroll_start(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result = 0;
char userid[TEMPLATE_ID_SIZE + 1];
sync_database(dev);
fp_info("enroll_start");
@ -587,7 +406,49 @@ static int verify_response(bmkt_response_t *resp, void *ctx)
return 0;
}
static int delete_finger(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result = 0;
struct fp_print_data *print = fpi_dev_get_delete_data(dev);;
struct fp_print_data_item *item = print->prints->data;
struct syna_mis_print_data *print_data;
bmkt_user_id_t user;
if(item->length != sizeof(struct syna_mis_print_data))
{
fp_err("print data is incorrect !");
goto cleanup;
}
print_data = (struct syna_mis_print_data *)item->data;
memset(&user, 0, sizeof(bmkt_user_id_t));
memcpy(user.user_id, print_data->user_id, sizeof(print_data->user_id));
fp_info("delete finger !");
user.user_id_len = strlen(user.user_id);
if (user.user_id_len <= 0 || user.user_id[0] == ' ')
{
fp_err("Invalid user name.");
goto cleanup;
}
sdev->state = SYNA_STATE_DELETE;
result = bmkt_delete_enrolled_user(sdev->sensor, 1, print_data->user_id,
user.user_id_len, del_enrolled_user_resp, dev);
if (result != BMKT_SUCCESS)
{
fp_err("Failed to delete enrolled user: %d", result);
goto cleanup;
}
return 0;
cleanup:
return -1;
}
static int verify_start(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
@ -658,6 +519,7 @@ struct fp_driver synaptics_driver = {
.enroll_stop = enroll_stop,
.verify_start = verify_start,
.verify_stop = verify_stop,
.delete_finger = delete_finger,
};

View file

@ -77,6 +77,9 @@ enum fp_dev_state {
DEV_STATE_CAPTURING,
DEV_STATE_CAPTURE_DONE,
DEV_STATE_CAPTURE_STOPPING,
DEV_STATE_DELETING,
DEV_STATE_DELETE_DONE,
DEV_STATE_DELETE_STOPPING,
};
struct fp_dev {
@ -96,6 +99,9 @@ struct fp_dev {
/* read-only to drivers */
struct fp_print_data *verify_data;
struct fp_print_data *delete_data;
/* drivers should not mess with any of the below */
enum fp_dev_state state;
int __enroll_stage;
@ -123,6 +129,8 @@ struct fp_dev {
void *capture_cb_data;
fp_operation_stop_cb capture_stop_cb;
void *capture_stop_cb_data;
fp_delete_cb delete_cb;
void *delete_cb_data;
/* FIXME: better place to put this? */
struct fp_print_data **identify_gallery;

View file

@ -680,3 +680,58 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
}
return r;
}
/**
* fp_async_delete_finger:
* @dev: the struct #fp_dev device
* @data: data to delete. Must have been previously enrolled.
* @callback: the callback to call when data deleted.
* @user_data: user data to pass to the callback
*
* Request to delete data in sensor.
*
* Returns: 0 on success, non-zero on error
*/
API_EXPORTED int fp_async_delete_finger(struct fp_dev *dev,
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
g_return_val_if_fail (callback != NULL, -EINVAL);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->delete_finger)
return -ENOTSUP;
dev->state = DEV_STATE_DELETING;
dev->delete_cb = callback;
dev->delete_cb_data = user_data;
dev->delete_data = data;
r = drv->delete_finger(dev);
if (r < 0) {
dev->delete_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to delete data, error %d", r);
}
return r;
}
/* Drivers call this when delete done */
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_DELETING);
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_DELETE_DONE;
if (dev->delete_cb)
dev->delete_cb(dev, status, dev->delete_cb_data);
}

View file

@ -36,4 +36,7 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
struct fp_img *img);
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status);
#endif

View file

@ -703,6 +703,21 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
return dev->drv->identify_start != NULL;
}
/**
* fp_dev_supports_data_in_sensor:
* @dev: the struct #fp_dev device
*
* Determines if a device is capable of storing print data in sensor.
* Not all devices support this functionality.
*
* Returns: 1 if the device is capable of storing data in sensor, 0 otherwise.
*/
API_EXPORTED int fp_dev_supports_data_in_sensor(struct fp_dev *dev)
{
return dev->drv->delete_finger != NULL;
}
/**
* fp_dev_get_img_width:
* @dev: the struct #fp_dev device

View file

@ -87,6 +87,7 @@ struct fp_driver {
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
int (*capture_start)(struct fp_dev *dev);
int (*capture_stop)(struct fp_dev *dev);
int (*delete_finger)(struct fp_dev *dev);
};
/**

View file

@ -148,3 +148,17 @@ fpi_dev_get_verify_data(struct fp_dev *dev)
{
return dev->verify_data;
}
/**
* fpi_dev_get_delete_data:
* @dev: a struct #fp_dev
*
* Returns the delete data associated with @dev.
* Returns: a struct #fp_print_data pointer or %NULL
*/
struct fp_print_data *
fpi_dev_get_delete_data(struct fp_dev *dev)
{
return dev->delete_data;
}

View file

@ -43,5 +43,7 @@ libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
int nr_enroll_stages);
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
struct fp_print_data *fpi_dev_get_delete_data(struct fp_dev *dev);
#endif

View file

@ -441,6 +441,72 @@ API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
return fp_verify_finger_img(dev, enrolled_print, NULL);
}
struct sync_delete_data {
gboolean populated;
int result;
};
static void sync_delete_cb(struct fp_dev *dev, int result, void *user_data)
{
struct sync_delete_data *ddata = user_data;
ddata->result = result;
ddata->populated = TRUE;
}
/**
* fp_delete_finger:
* @dev: the struct #fp_dev device to perform the operation.
* @enrolled_data: the id need to delete on sensor. This id is
* returned in previously enrolled with a MIS device.
*
* Perform a delete data operation on sensor. When print data is stored on sensor,
* this function is needed when host deletes enrolled finger.
*
* Returns: negative code on error, otherwise a code from #fp_delete_result
*/
API_EXPORTED int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_data)
{
struct sync_delete_data *ddata;
gboolean stopped = FALSE;
int r;
if (!enrolled_data) {
fp_err("no print given");
return -EINVAL;
}
if (!fp_dev_supports_print_data(dev, enrolled_data)) {
fp_err("print is not compatible with device");
return -EINVAL;
}
fp_dbg("to be handled by %s", dev->drv->name);
ddata = g_malloc0(sizeof(struct sync_delete_data));
r = fp_async_delete_finger(dev, enrolled_data, sync_delete_cb, ddata);
if (r < 0) {
fp_dbg("delete_finger error %d", r);
g_free(ddata);
return r;
}
while (!ddata->populated) {
r = fp_handle_events();
if (r < 0)
goto out;
}
r = ddata->result;
fp_dbg("delete_finger result %d", r);
out:
g_free(ddata);
return r;
}
struct sync_identify_data {
gboolean populated;
int result;

View file

@ -267,12 +267,17 @@ int fp_verify_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print);
int fp_dev_supports_identification(struct fp_dev *dev);
int fp_dev_supports_data_in_sensor(struct fp_dev *dev);
int fp_identify_finger_img(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset,
struct fp_img **img);
int fp_identify_finger(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset);
int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print);
/* Data handling */
int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger,
struct fp_print_data **data) LIBFPRINT_DEPRECATED;
@ -451,6 +456,22 @@ int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operati
int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data);
/**
* fp_delete_result:
* @FP_DELETE_COMPLETE: Delete completed successfully.
* @FP_DELETE_FAIL: Delete failed
*
*/
enum fp_delete_result {
FP_DELETE_COMPLETE = 0,
FP_DELETE_FAIL = 1,
};
typedef void (*fp_delete_cb)(struct fp_dev *dev, int status, void *user_data);
int fp_async_delete_finger(struct fp_dev *dev, struct fp_print_data *data, fp_img_operation_cb callback, void *user_data);
#ifdef __cplusplus
}
#endif