-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 I have written a U.are.U driver against Digital Persona's official SDK for their U.are.U devices.
I did this so I could get my DP5160 working. This driver DOES work. Additionally, theoretically it should work for any UareU fingerprint reader, now or future. I first tried making this driver using the image capturing interface on it's own (ie. as a devimg), and I got it working, but not as reliably as I would like. Using the device itself for figuring out minutae and doing the verification of the fingerprint seems to work much better. I somewhat arbitrarily decided that when you register your finger you need to register once and then verify it twice (and the registration process will take the highest quality of the 3 attempts and use that for what gets stored). Additionally I decided that 3 failed attempts to match a single fingerprint during enrollment is a failed enrollment. This DOES NOT contain any intellectual property of Digital Persona, it merely implements against their API. I've attached the patch file for this to work. Feel free to merge it with the mainline. Preston. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJWyjl4AAoJEDQ8ATKJYnQGHPQP/3KaDG4X88sQ3qcEDliy54Aa bqh4r/zAgAfuLiUdrkeWk90oMaik11stRIQ1YMpfZ9M8buT4TTLBjmwnNn1SvS/P yxnJgG0fL1bfENutU+YFS1/2gST1o2qU53JAAsSncs/ecBduQ/aF3c6K8CeAVk4W r4Xxf8wGZ2swhupX1Oz9JwPW1kD5YSp9pozEben0fu3sUxqXHdZcewgkZofP8LLw jsPH49uYRx2u/ceBqvAwlmdIYlBj0ThB4frRKhE+QgiugKLdfcnxWiQVa/1OeUn4 qYmO5QAo5m/bMabmVRm8UH+ZrWOHBqE1xGBsTD9HRi0pU3lPwhmLA2XZqkt/Vzi2 kXVmFB3ba4Bqw7YeHri6Vx+YqHsoOUtODudG8oMU8H1FXgxtz4WfN9gA2Ztp1Lkb qkzq/TewhkjnuRnpA4yE43dV0prXElTT4MrzCDoKbeEuYTQD17H3u/y1Qb9BEjio OGXTsBDxEq1NvsFM76KzBIwBgB8FYAv0OKPfyaJV4lJFYqYhM7xcwyKniFRwyd8e +6shRI0j4OC1Tc13S0che2okR2Vb9RQ/B1Uu7qvYK3ShNeawlKcZWRheu4B+Fyx5 tAyP9DVrgasO8mTDOpsvWC0sENPqWMGUVedLWdZ0sMh9ZpfqKo2aFLeg5QA8tp/o VFEz0ga6iqezHp9K4oTx =mb85 -----END PGP SIGNATURE-----
diff --git a/configure.ac b/configure.ac index 707f587..ed9aaeb 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ AC_SUBST(lt_major) AC_SUBST(lt_revision) AC_SUBST(lt_age) -all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603" +all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603 urusdk" require_imaging='no' require_aeslib='no' @@ -48,6 +48,7 @@ enable_vfs301='no' enable_vfs5011='no' enable_upektc_img='no' enable_etes603='no' +enable_urusdk='no' AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers], [List of drivers to enable])], @@ -150,6 +151,10 @@ for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver]) enable_etes603="yes" ;; + urusdk) + AC_DEFINE([ENABLE_URUSDK], [], [Build U.are.U SDK driver]) + enable_urusdk="yes" + ;; esac done @@ -175,6 +180,7 @@ AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"]) AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"]) AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"]) AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"]) +AM_CONDITIONAL([ENABLE_URUSDK], [test "$enable_urusdk" = "yes"]) PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1]) @@ -224,6 +230,11 @@ if test "$require_imaging" = "yes"; then fi fi +AC_ARG_WITH(urusdk-dir, + AS_HELP_STRING([--with-urusdk-dir=DIR],[Directory where the U.are.U SDK is installed.]), + [CFLAGS="$CFLAGS -I${withval}/Include" + LIBS="$LIBS -L${withval}/Linux/lib/lib -ldpfpdd -ldpfj"]) + AM_CONDITIONAL([REQUIRE_PIXMAN], [test "$pixman_found" = "yes"]) AC_SUBST(IMAGING_CFLAGS) AC_SUBST(IMAGING_LIBS) @@ -396,6 +407,11 @@ if test x$enable_etes603 != xno ; then else AC_MSG_NOTICE([ etes603 driver disabled]) fi +if test x$enable_urusdk != xno ; then + AC_MSG_NOTICE([** urusdk driver enabled]) +else + AC_MSG_NOTICE([ urusdk driver disabled]) +fi if test x$require_aeslib != xno ; then AC_MSG_NOTICE([** aeslib helper functions enabled]) else diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am index ea6e678..7754864 100644 --- a/libfprint/Makefile.am +++ b/libfprint/Makefile.am @@ -21,6 +21,7 @@ VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h dri VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h ETES603_SRC = drivers/etes603.c +URUSDK_SRC = drivers/urusdk.c EXTRA_DIST = \ $(UPEKE2_SRC) \ @@ -42,6 +43,7 @@ EXTRA_DIST = \ $(VFS5011_SRC) \ $(UPEKTC_IMG_SRC) \ $(ETES603_SRC) \ + $(URUSDK_SRC) \ drivers/aesx660.c \ drivers/aesx660.h \ drivers/aes3k.c \ @@ -184,6 +186,10 @@ if ENABLE_ETES603 DRIVER_SRC += $(ETES603_SRC) endif +if ENABLE_URUSDK +DRIVER_SRC += $(URUSDK_SRC) +endif + if REQUIRE_PIXMAN OTHER_SRC += pixman.c libfprint_la_CFLAGS += $(IMAGING_CFLAGS) diff --git a/libfprint/core.c b/libfprint/core.c index 2ae7649..beae7b1 100644 --- a/libfprint/core.c +++ b/libfprint/core.c @@ -346,6 +346,9 @@ static struct fp_driver * const primitive_drivers[] = { #ifdef ENABLE_UPEKE2 &upeke2_driver, #endif +#ifdef ENABLE_URUSDK + &urusdk_driver, +#endif }; static struct fp_img_driver * const img_drivers[] = { @@ -398,6 +401,9 @@ static struct fp_img_driver * const img_drivers[] = { #ifdef ENABLE_ETES603 &etes603_driver, #endif +//#ifdef ENABLE_URUSDK +// &urusdk_driver, +//#endif /*#ifdef ENABLE_FDU2000 &fdu2000_driver, #endif diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h index 4d8414c..cf50277 100644 --- a/libfprint/drivers/driver_ids.h +++ b/libfprint/drivers/driver_ids.h @@ -40,6 +40,7 @@ enum { UPEKTC_IMG_ID = 17, ETES603_ID = 18, VFS5011_ID = 19, + URUSDK_ID = 20, }; #endif diff --git a/libfprint/drivers/urusdk.c b/libfprint/drivers/urusdk.c new file mode 100644 index 0000000..046093e --- /dev/null +++ b/libfprint/drivers/urusdk.c @@ -0,0 +1,652 @@ +/* + * Driver for the U.are.U SDK for libfprint + * Copyright (c) 2016 Preston A. Elder <p...@neuromancy.net> + * + * This uses the SDK, which means that SDK is required. + * While I could capture the images directly, I am instead using + * the native stuff in the U.are.U device for matching. + * The SDK supports multiple devices, so any U.are.U device should + * work with this driver. + */ + +#define FP_COMPONENT "urusdk" + +#include <fp_internal.h> +#include <dpfpdd.h> +#include <dpfj.h> +#include <errno.h> +#include <libusb.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "driver_ids.h" + +#define GENERIC_FAILURE -EIO +#define ENROLL_STAGES 3 // We must have n matching copies of the fingerprint. +#define MAX_FAILURES 3 // This many failures to get an individual match is a permanent failure. +#define MATCH_PROBABILITY DPFJ_PROBABILITY_ONE / 100000 // 1 in 100k + +struct urusdk_dev { + DPFPDD_DEV handle; + + unsigned int stored_size; + unsigned char *stored_data; + unsigned int stored_score; + + unsigned int img_size; + unsigned char *img_data; + unsigned int img_score; + + unsigned int enroll_stage; + unsigned int failures; +}; + +enum { + DP_URU5000, + DP_URU5160 +}; + +static const struct usb_id id_table[] = { + /* dp uru5160 (standalone) */ + { .vendor = 0x05ba, .product = 0x000b, .driver_data = DP_URU5160 }, + { 0, 0, 0, } +}; + +static const char *error_string(int err) { + const char *szError = "Unknown Error."; + switch(err){ + case DPFPDD_E_NOT_IMPLEMENTED: szError = "API call is not implemented."; break; + case DPFPDD_E_FAILURE: szError = "Unspecified failure."; break; + case DPFPDD_E_NO_DATA: szError = "No data is available."; break; + case DPFPDD_E_MORE_DATA: szError = "The memory allocated by the application is not big enough for the data which is expected."; break; + case DPFPDD_E_INVALID_PARAMETER: szError = "One or more parameters passed to the API call are invalid."; break; + case DPFPDD_E_INVALID_DEVICE: szError = "Reader handle is not valid."; break; + case DPFPDD_E_DEVICE_BUSY: szError = "The API call cannot be completed because another call is in progress."; break; + case DPFPDD_E_DEVICE_FAILURE: szError = "The reader is not working properly."; break; + case DPFJ_E_INVALID_FID: szError = "FID is invalid."; break; + case DPFJ_E_TOO_SMALL_AREA: szError = "Image is too small."; break; + case DPFJ_E_INVALID_FMD: szError = "FMD is invalid."; break; + case DPFJ_E_ENROLLMENT_IN_PROGRESS: szError = "Enrollment operation is in progress."; break; + case DPFJ_E_ENROLLMENT_NOT_STARTED: szError = "Enrollment operation has not begun."; break; + case DPFJ_E_ENROLLMENT_NOT_READY: szError = "Not enough in the pool of FMDs to create enrollment FMD."; break; + case DPFJ_E_ENROLLMENT_INVALID_SET: szError = "Unable to create enrollment FMD with the collected set of FMDs."; break; + } + return szError; +} + +static const char *quality_string(int qual, char *buf, size_t sz) { + + memset(buf, 0, sz); + gboolean first = TRUE; + for(unsigned int i = 1; i < 0x80000000; i <<= 1) { + const char *szQuality = NULL; + switch(qual & i){ + case DPFPDD_QUALITY_GOOD: break; + case DPFPDD_QUALITY_TIMED_OUT: szQuality = "timeout expired"; break; + case DPFPDD_QUALITY_CANCELED: szQuality = "capture was canceled"; break; + case DPFPDD_QUALITY_NO_FINGER: szQuality = "not a finger detected"; break; + case DPFPDD_QUALITY_FAKE_FINGER: szQuality = "fake finger detected"; break; + case DPFPDD_QUALITY_FINGER_TOO_LEFT: szQuality = "finger is too far left on the reader"; break; + case DPFPDD_QUALITY_FINGER_TOO_RIGHT: szQuality = "finger is too far right on the reader"; break; + case DPFPDD_QUALITY_FINGER_TOO_HIGH: szQuality = "finger is too high on the reader"; break; + case DPFPDD_QUALITY_FINGER_TOO_LOW: szQuality = "finger is too low in the reader"; break; + case DPFPDD_QUALITY_FINGER_OFF_CENTER: szQuality = "finger is not centered on the reader"; break; + case DPFPDD_QUALITY_SCAN_SKEWED: szQuality = "scan is skewed too much"; break; + case DPFPDD_QUALITY_SCAN_TOO_SHORT: szQuality = "scan is too short"; break; + case DPFPDD_QUALITY_SCAN_TOO_LONG: szQuality = "scan is too long"; break; + case DPFPDD_QUALITY_SCAN_TOO_SLOW: szQuality = "speed of the swipe is too slow"; break; + case DPFPDD_QUALITY_SCAN_TOO_FAST: szQuality = "speed of the swipe is too fast"; break; + case DPFPDD_QUALITY_SCAN_WRONG_DIRECTION: szQuality = "direction of the swipe is wrong"; break; + case DPFPDD_QUALITY_READER_DIRTY: szQuality = "reader needs cleaning"; break; + } + + if (szQuality != NULL) { + size_t len = strlen(szQuality); + if (first) { + if (sz < len) + break; + + first = FALSE; + } else { + if (sz < len + 2) + break; + + strncat(buf, ", ", sz); + sz -= 2; + } + + strncat(buf, szQuality, sz); + sz -= len; + } + } + + return buf; +} + +static int dev_init(struct fp_dev *dev, unsigned long driver_data) { + static gboolean api_initialized = FALSE; + + if (!api_initialized) { + if (dpfpdd_init() != DPFPDD_SUCCESS) { + return GENERIC_FAILURE; + } + api_initialized = TRUE; + } + + unsigned int count = 1; + DPFPDD_DEV_INFO *readers = g_malloc(sizeof(DPFPDD_DEV_INFO) * count); + if (readers == NULL) + return -ENOMEM; + + while (readers != NULL) { + for (size_t i = 0; i < count; ++i) { + readers[i].size = sizeof(DPFPDD_DEV_INFO); + } + + unsigned int new_count = count; + int res = dpfpdd_query_devices(&new_count, readers); + + if (res == DPFPDD_SUCCESS) + break; + + if (res == DPFPDD_E_MORE_DATA) { + DPFPDD_DEV_INFO *new_readers = g_realloc(readers, sizeof(DPFPDD_DEV_INFO) * new_count); + if (new_readers == NULL) { + g_free(readers); + return -ENOMEM; + } + + readers = new_readers; + count = new_count; + continue; + } + + g_free(readers); + return GENERIC_FAILURE; + } + + struct libusb_device_descriptor usbdev; + usbdev.bLength = sizeof(usbdev); + + libusb_get_device_descriptor(libusb_get_device(dev->udev), &usbdev); + char serial[MAX_STR_LENGTH]; + if (libusb_get_string_descriptor_ascii(dev->udev, + usbdev.iSerialNumber, serial, MAX_STR_LENGTH) < 0) { + int res = -errno; + g_free(readers); + return res; + } + + char name[MAX_DEVICE_NAME_LENGTH] = {0}; + for (size_t i = 0; i < count; ++i) { + if (strncmp(readers[i].descr.serial_num, serial, MAX_STR_LENGTH)==0) { + strncpy(name, readers[i].name, MAX_DEVICE_NAME_LENGTH); + } + } + g_free(readers); + + if (!strlen(name)) + return -ENODEV; + + DPFPDD_DEV handle = NULL; + int res = dpfpdd_open(name, &handle); + switch (res) { + case DPFPDD_E_INVALID_PARAMETER: + fp_err("dpfpdd_open(): invalid parameter."); + return -EINVAL; + case DPFPDD_E_DEVICE_BUSY: + fp_warn("dpfpdd_open(): device busy."); + return -EBUSY; + case DPFPDD_E_DEVICE_FAILURE: + fp_err("dpfpdd_open(): device failure."); + return -ENODEV; + case DPFPDD_E_FAILURE: + fp_err("dpfpdd_open() failed."); + return GENERIC_FAILURE; + } + + struct urusdk_dev *urudev = g_malloc0(sizeof(struct urusdk_dev)); + urudev->handle = handle; + dev->priv = urudev; + dev->nr_enroll_stages = ENROLL_STAGES; + + dpfpdd_led_config(handle, DPFPDD_LED_ACCEPT | DPFPDD_LED_REJECT, DPFPDD_LED_CLIENT, NULL); + + fpi_drvcb_open_complete(dev, 0); + + return 0; +} + +static void dev_close(struct fp_dev *dev) { + if (dev->priv) { + struct urusdk_dev *urudev = dev->priv; + if (urudev->img_data != NULL) { + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + } + dpfpdd_close(urudev->handle); + g_free(urudev); + dev->priv = NULL; + } + fpi_drvcb_close_complete(dev); +} + +static void run_capture(struct fpi_ssm *ssm); + +// ---------------------------------------------------------------------------- +// ENROLL +// ---------------------------------------------------------------------------- + +enum capture_stages { + CAPTURE_READ = 0, + CAPTURE_VERIFY, + CAPTURE_STORE, + CAPTURE_NUM_STAGES, +}; + +static void run_enroll_complete(struct fpi_ssm *ssm); + +static int enroll_start(struct fp_dev *dev) { + struct urusdk_dev *urudev = dev->priv; + urudev->enroll_stage = 1; + urudev->failures = 0; + + struct fpi_ssm *ssm = fpi_ssm_new(dev, run_capture, CAPTURE_NUM_STAGES); + ssm->priv = dev; + fpi_ssm_start(ssm, run_enroll_complete); + return 0; +} + +static void run_enroll_complete(struct fpi_ssm *ssm) { + struct fp_dev *dev = ssm->dev; + struct urusdk_dev *urudev = dev->priv; + + int r = ssm->error; + fpi_ssm_free(ssm); + if (r < 0) + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_FAIL, NULL, NULL); + else if (r) + fpi_drvcb_enroll_stage_completed(dev, r, NULL, NULL); + + if (urudev->img_data) { + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + } +} + +static int enroll_stop(struct fp_dev *dev) { + struct urusdk_dev *urudev = dev->priv; + + dpfpdd_cancel(urudev->handle); + fpi_drvcb_enroll_stopped(dev); + + urudev->enroll_stage = 0; + if (urudev->stored_data == urudev->img_data) { + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + } + + if (urudev->img_data) { + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + } + + g_free(urudev->stored_data); + urudev->stored_data = NULL; + urudev->stored_size = 0; + urudev->stored_score = 0; + + return 0; +} + +// ---------------------------------------------------------------------------- +// VERIFY +// ---------------------------------------------------------------------------- + +static void run_verify_complete(struct fpi_ssm *ssm); + +static int verify_start(struct fp_dev *dev) { + struct urusdk_dev *urudev = dev->priv; + urudev->enroll_stage = 0; + urudev->failures = 0; + + struct fp_print_data *print = dev->verify_data; + struct fp_print_data_item *item = print->prints->data; + urudev->stored_data = item->data; + urudev->stored_size = item->length; + + struct fpi_ssm *ssm = fpi_ssm_new(dev, run_capture, CAPTURE_NUM_STAGES); + ssm->priv = dev; + fpi_ssm_start(ssm, run_verify_complete); + return 0; +} + + +static void run_verify_complete(struct fpi_ssm *ssm) { + struct fp_dev *dev = ssm->dev; + struct urusdk_dev *urudev = dev->priv; + + int r = ssm->error; + fpi_ssm_free(ssm); + if (r < 0) + fpi_drvcb_report_verify_result(dev, FP_VERIFY_NO_MATCH, NULL); + else if (r) + fpi_drvcb_report_verify_result(dev, r, NULL); + + if (urudev->img_data) { + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + } + + urudev->stored_data = NULL; + urudev->stored_size = 0; +} + +static int verify_stop(struct fp_dev *dev, gboolean iterating) { + struct urusdk_dev *urudev = dev->priv; + + dpfpdd_cancel(urudev->handle); + fpi_drvcb_verify_stopped(dev); + + if (urudev->img_data) { + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + } + + urudev->stored_data = NULL; + urudev->stored_size = 0; + return 0; +} + +// ---------------------------------------------------------------------------- +// COMMON +// ---------------------------------------------------------------------------- + +static void image_capture_cb(void *ctx, unsigned int reserved, unsigned int data_sz, void *data); + +static void run_capture(struct fpi_ssm *ssm) { + struct fp_dev *dev = ssm->priv; + struct urusdk_dev *urudev = dev->priv; + + switch (ssm->cur_state) { + case CAPTURE_READ: + { + DPFPDD_CAPTURE_PARAM cparam; + cparam.size = sizeof(cparam); + cparam.image_fmt = DPFPDD_IMG_FMT_ISOIEC19794; + cparam.image_proc = DPFPDD_IMG_PROC_NONE; + cparam.image_res = 500; + + int res = dpfpdd_capture_async(urudev->handle, &cparam, ssm, image_capture_cb); + + if (res != DPFPDD_SUCCESS) { + switch (res) { + case DPFPDD_E_FAILURE: + fp_err("dpfpdd_capture() failed."); + case DPFPDD_E_INVALID_DEVICE: + fp_err("dpfpdd_capture(): invalid device."); + case DPFPDD_E_INVALID_PARAMETER: + fp_err("dpfpdd_capture(): invalid parameter."); + case DPFPDD_E_DEVICE_BUSY: + fp_warn("dpfpdd_capture(): device busy."); + case DPFPDD_E_DEVICE_FAILURE: + fp_err("dpfpdd_capture(): device failure."); + } + fpi_ssm_mark_aborted(ssm, -1); + return; + } + + if (urudev->enroll_stage == 1 && urudev->failures == 0) + fpi_drvcb_enroll_started(dev, 0); + else if (!urudev->enroll_stage) + fpi_drvcb_verify_started(dev, 0); + } + break; + + case CAPTURE_VERIFY: + if (urudev->enroll_stage == 1) { + urudev->stored_size = urudev->img_size; + urudev->stored_data = urudev->img_data; + urudev->stored_score = urudev->img_score; + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_ACCEPT | DPFPDD_LED_REJECT, DPFPDD_LED_CMD_ON); + sleep(1); + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_ACCEPT | DPFPDD_LED_REJECT, DPFPDD_LED_CMD_OFF); + fpi_ssm_next_state(ssm); + } else { + unsigned int falsematch_rate = 0; + int res = dpfj_compare(DPFJ_FMD_ISO_19794_2_2005, urudev->stored_data, urudev->stored_size, 0, DPFJ_FMD_ISO_19794_2_2005, urudev->img_data, urudev->img_size, 0, &falsematch_rate); + + if (res == DPFJ_SUCCESS) { + if (falsematch_rate < MATCH_PROBABILITY) { + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_ACCEPT, DPFPDD_LED_CMD_ON); + sleep(1); + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_ACCEPT, DPFPDD_LED_CMD_OFF); + fpi_ssm_next_state(ssm); + } else { + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_REJECT, DPFPDD_LED_CMD_ON); + sleep(1); + dpfpdd_led_ctrl(urudev->handle, DPFPDD_LED_REJECT, DPFPDD_LED_CMD_OFF); + urudev->failures++; + if (urudev->enroll_stage) { + if (urudev->failures >= MAX_FAILURES) + fpi_ssm_mark_aborted(ssm, -1); + else { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY, NULL, NULL); + if (urudev->stored_data != urudev->img_data) + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } + } else + fpi_ssm_mark_aborted(ssm, -2); + } + } else { + fp_err("Compare error: %s", error_string(res)); + fpi_ssm_mark_aborted(ssm, -1); + } + } + break; + + case CAPTURE_STORE: + if (urudev->enroll_stage > 1) { + if (urudev->img_score > urudev->stored_score) { + g_free(urudev->stored_data); + urudev->stored_data = urudev->img_data; + urudev->stored_size = urudev->img_size; + urudev->stored_score = urudev->img_score; + } + } + if (urudev->enroll_stage >= ENROLL_STAGES) { + struct fp_print_data *data = fpi_print_data_new(dev); + struct fp_print_data_item *item = fpi_print_data_item_new(urudev->stored_size); + memcpy(item->data, urudev->stored_data, urudev->stored_size); + data->prints = g_slist_prepend(data->prints, item); + + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_COMPLETE, data, NULL); + + urudev->enroll_stage = 0; + if (urudev->stored_data == urudev->img_data) { + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + } + + g_free(urudev->stored_data); + urudev->stored_data = NULL; + urudev->stored_size = 0; + urudev->stored_score = 0; + + fpi_ssm_mark_completed(ssm); + } else if (urudev->enroll_stage) { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_PASS, NULL, NULL); + if (urudev->stored_data != urudev->img_data) + g_free(urudev->img_data); + urudev->img_data = NULL; + urudev->img_size = 0; + urudev->img_score = 0; + urudev->enroll_stage++; + urudev->failures = 0; + + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } else { + fpi_drvcb_report_verify_result(dev, FP_VERIFY_MATCH, NULL); + fpi_ssm_mark_completed(ssm); + } + break; + } +} + +static void image_capture_cb(void *ctx, unsigned int reserved, unsigned int data_sz, void *data) { + DPFPDD_CAPTURE_CALLBACK_DATA_0 *dpdata = data; + + struct fpi_ssm *ssm = ctx; + struct fp_dev *dev = ssm->priv; + struct urusdk_dev *urudev = dev->priv; + + if (dpdata->error != DPFPDD_SUCCESS) { + switch (dpdata->error) { + case DPFPDD_E_FAILURE: + fp_err("dpfpdd_capture() failed."); + case DPFPDD_E_INVALID_DEVICE: + fp_err("dpfpdd_capture(): invalid device."); + case DPFPDD_E_INVALID_PARAMETER: + fp_err("dpfpdd_capture(): invalid parameter."); + case DPFPDD_E_DEVICE_BUSY: + fp_warn("dpfpdd_capture(): device busy."); + case DPFPDD_E_MORE_DATA: + fp_err("dpfpdd_capture(): buffer overflow."); + case DPFPDD_E_DEVICE_FAILURE: + fp_err("dpfpdd_capture(): device failure."); + } + fpi_ssm_mark_aborted(ssm, -1); + return; + } + + if (!dpdata->capture_result.success) { + char qstr[1024]; + fp_err("dpfpdd_capture(): bad quality: %s.", quality_string(dpdata->capture_result.quality, qstr, 1024)); + + if ((dpdata->capture_result.quality & DPFPDD_QUALITY_FINGER_TOO_LEFT) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_FINGER_TOO_RIGHT) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_FINGER_TOO_HIGH) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_FINGER_TOO_LOW) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_FINGER_OFF_CENTER) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_SKEWED)) { + if (urudev->enroll_stage) { + urudev->failures++; + if (urudev->failures >= MAX_FAILURES) + fpi_ssm_mark_aborted(ssm, -1); + else { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY_CENTER_FINGER, NULL, NULL); + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } + } else + fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY_CENTER_FINGER); + } + + else if ((dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_TOO_SHORT) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_TOO_FAST)) { + if (urudev->enroll_stage) { + urudev->failures++; + if (urudev->failures >= MAX_FAILURES) + fpi_ssm_mark_aborted(ssm, -1); + else { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY_TOO_SHORT, NULL, NULL); + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } + } else + fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY_TOO_SHORT); + } + + else if ((dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_TOO_LONG) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_TOO_SLOW) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_SCAN_WRONG_DIRECTION)) { + if (urudev->enroll_stage) { + urudev->failures++; + if (urudev->failures >= MAX_FAILURES) + fpi_ssm_mark_aborted(ssm, -1); + else { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY_REMOVE_FINGER, NULL, NULL); + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } + } else + fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY_REMOVE_FINGER); + return; + } + + else if ((dpdata->capture_result.quality & DPFPDD_QUALITY_NO_FINGER)) { + if (urudev->enroll_stage) { + urudev->failures++; + if (urudev->failures >= MAX_FAILURES) + fpi_ssm_mark_aborted(ssm, -1); + else { + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY, NULL, NULL); + fpi_ssm_jump_to_state(ssm, CAPTURE_READ); + } + } else + fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY); + return; + + } + + else if ((dpdata->capture_result.quality & DPFPDD_QUALITY_TIMED_OUT) || + (dpdata->capture_result.quality & DPFPDD_QUALITY_CANCELED)) + fpi_ssm_mark_aborted(ssm, -1); + return; + } + + fp_dbg("Image Captured %dx%dx%d, %d DPI, %d bytes.\n", dpdata->capture_result.info.width, dpdata->capture_result.info.height, dpdata->capture_result.info.bpp, dpdata->capture_result.info.res, data_sz); + + unsigned int nFeaturesSize = MAX_FMD_SIZE; + unsigned char* pFeatures = g_malloc(nFeaturesSize); + if(NULL == pFeatures){ + fp_err("Failed to allocate memory!"); + fpi_ssm_mark_aborted(ssm, -1); + return; + } else{ + //create template + int res = dpfj_create_fmd_from_fid(DPFJ_FID_ISO_19794_4_2005, dpdata->image_data, dpdata->image_size, DPFJ_FMD_ISO_19794_2_2005, pFeatures, &nFeaturesSize); + + if(DPFJ_SUCCESS != res){ + fp_err("Failed to obtain FMD from FID"); + g_free(pFeatures); + fpi_ssm_mark_aborted(ssm, -1); + return; + } + + urudev->img_data = pFeatures; + urudev->img_size = nFeaturesSize; + urudev->img_score = dpdata->capture_result.score; + } + + dpfpdd_cancel(urudev->handle); + + fpi_ssm_next_state(ssm); +} + +struct fp_driver urusdk_driver = { + .id = URUSDK_ID, + .name = FP_COMPONENT, + .full_name = "Digital Persona U.are.U 5000/5160", + .id_table = id_table, + .scan_type = FP_SCAN_TYPE_PRESS, + + .open = dev_init, + .close = dev_close, + .enroll_start = enroll_start, + .enroll_stop = enroll_stop, + .verify_start = verify_start, + .verify_stop = verify_stop, +}; diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index 2324b27..12eab53 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -305,6 +305,10 @@ extern struct fp_img_driver upektc_img_driver; #ifdef ENABLE_ETES603 extern struct fp_img_driver etes603_driver; #endif +#ifdef ENABLE_URUSDK +// extern struct fp_img_driver urusdk_driver; +extern struct fp_driver urusdk_driver; +#endif extern libusb_context *fpi_usb_ctx; extern GSList *opened_devices;
_______________________________________________ fprint mailing list fprint@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/fprint