Compare commits

..

1 Commits

Author SHA1 Message Date
Benjamin Berg
e1fdc7b01b uru4000: Fix control transfer request type
During porting the request type was accidentally changed from VENDOR to
DEVICE. Change the type back to VENDOR.

Fixes: #205
2019-12-04 13:11:32 +01:00
148 changed files with 3272 additions and 14270 deletions

23
.gitignore vendored
View File

@@ -1,3 +1,24 @@
ltmain.sh
missing
stamp-h1
libtool
*.la
*.lo
*.o
*.swp
_build
Makefile
Makefile.in
config.h*
aclocal.m4
autom4te.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
.deps
.libs
compile
ChangeLog

View File

@@ -1,144 +1,98 @@
include:
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
- remote: 'https://gitlab.gnome.org/GNOME/citemplates/-/raw/master/flatpak/flatpak_ci_initiative.yml'
variables:
extends: .libfprint_common_variables
FDO_DISTRIBUTION_TAG: latest
FDO_DISTRIBUTION_VERSION: rawhide
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
image: fedora:rawhide
stages:
- check-source
- build
- test
- flatpak
- flatpack
image: "$FEDORA_IMAGE"
variables:
DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
gobject-introspection-devel python3-cairo python3-gobject umockdev
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
.build_one_driver_template: &build_one_driver
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
# Build with a driver that doesn't need imaging, or nss
- meson --werror -Ddrivers=$driver . _build
- meson -Ddrivers=$driver . _build
- ninja -C _build
- rm -rf _build/
.build_template: &build
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
# And build with everything
- meson --werror -Ddrivers=all . _build
- meson -Ddrivers=all . _build
- ninja -C _build
- ninja -C _build install
.build_template: &check_abi
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES doxygen libabigail git
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
build:
stage: build
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
variables:
driver: virtual_image
<<: *build_one_driver
<<: *build
# <<: *check_abi
artifacts:
expose_as: "HTML Documentation"
paths:
- _build/doc/html/
expire_in: 1 week
test:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- meson --werror -Ddrivers=all -Db_coverage=true . _build
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage
- cat _build/meson-logs/coverage.txt
artifacts:
paths:
- _build/meson-logs
expire_in: 1 week
coverage: '/^TOTAL.*\s+(\d+\%)$/'
- meson test -C _build --verbose --no-stdsplit
test_valgrind:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES valgrind
- meson -Ddrivers=all . _build
- ninja -C _build
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
test_scan_build:
stage: test
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
script:
- meson -Ddrivers=all . _build
# This is ugly, the wrapper disables the malloc checker
- SCANBUILD=$CI_PROJECT_DIR/.gitlab-ci/scan-build ninja -C _build scan-build
# Check that the directory is empty
- "! ls -A _build/meson-logs/scanbuild | grep -q ."
artifacts:
paths:
- _build/meson-logs
expire_in: 1 week
test_indent:
stage: check-source
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
script:
- scripts/uncrustify.sh
- git diff
- "! git status -s | grep -q ."
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck git uncrustify
- scripts/uncrustify.sh --check
flatpak:
stage: flatpak
extends: .flatpak
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.36
variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
FLATPAK_MODULE: "libfprint"
APP_ID: "org.freedesktop.libfprint.Demo"
rules:
- if: '$CI_PROJECT_PATH != "libfprint/libfprint"'
when: never
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: never
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- if: '$CI_COMMIT_TAG'
when: always
# For any other (commit), allow manual run.
# This excludes MRs which would create a duplicate pipeline
- if: '$CI_COMMIT_BRANCH'
when: manual
allow_failure: true
.flatpak_script_template: &flatpak_script
script:
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
# Make sure to keep this in sync with the Flatpak manifest, all arguments
# are passed except the config-args because we build it ourselves
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
- flatpak build app ninja -C _build install
- flatpak build app rm -rf /app/include/ /app/lib/pkgconfig/
- flatpak-builder --finish-only --repo=repo app ${MANIFEST_PATH}
# Generate a Flatpak bundle
- flatpak build-bundle repo ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${DBUS_ID}
# CONTAINERS creation stage
container_fedora_build:
extends: .fdo.container-build@fedora
only:
.flatpak_artifacts_template: &flatpak_artifacts
artifacts:
paths:
- ${BUNDLE}
when: always
expire_in: 30 days
.flatpak_template: &flatpak
<<: *flatpak_script
<<: *flatpak_artifacts
flatpak master:
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
stage: flatpack
variables:
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
# a list of packages to install
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
# From demo/org.freedesktop.libfprint.Demo.json
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
FLATPAK_MODULE: "libfprint"
DBUS_ID: "org.freedesktop.libfprint.Demo"
<<: *flatpak

View File

@@ -1,27 +0,0 @@
.libfprint_common_variables:
LIBFPRINT_DEPENDENCIES:
doxygen
flatpak-builder
gcc
gcc-c++
gcovr
git
glib2-devel
glibc-devel
gobject-introspection-devel
gtk-doc
gtk3-devel
libabigail
libgusb-devel
libX11-devel
libXv-devel
meson
nss-devel
pixman-devel
python3-cairo
python3-gobject
systemd
umockdev
uncrustify
valgrind
clang-analyzer

View File

@@ -1,4 +0,0 @@
#!/bin/sh
# This wrapper just disables the malloc checker
exec /usr/bin/scan-build -disable-checker unix.Malloc "$@"

View File

@@ -1,13 +0,0 @@
Current maintainers of libfprint are:
* Benjamin Berg <bberg@redhat.com>
* Marco Trevisan (Treviño) <mail@3v1n0.net>
Many drivers are not actively maintained and may not be fully functional.
We are happy to receive contributions, but the support we can give is
limitted unfortunately. For many drivers we may not even have test devices.
Maintained drivers are:
* synaptics:
Contributed and maintained by Synaptics Inc.
Contact: Vincent Huang <vincent.huang@tw.synaptics.com>

64
NEWS
View File

@@ -1,70 +1,6 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
2020-06-08: v1.90.3 release
This release mostly contains support for a number of new match-on-chip
devices. Most notable is the addition of the new goodixmoc driver.
Currently the driver has the small caveat that we have no strategy to
garbage collect old prints yet (a simple strategy could be implemented
in fprintd).
Highlights:
* New goodixmoc driver supporting Goodix USB devices:
27C6:5840
27C6:6496
27C6:60A2
* Newly added support for Synaptics device:
06CB:00E9
06CB:00DF
* Fixed an issue with Synaptics devices sometimes not working at boot
* Fix issue with aes3k driver (#306)
2020-06-08: v1.90.2 release
This release contains a large amount of bug and regression fixes. These
are not listed explicitly, but affect the majority of drivers.
Highlights:
* A patch for nbis required for some sensors was accidentally dropped in
an earlier release. Users of these sensors/drivers (aes1610, aes2501,
aes2550, aes1660, aes2660, elan, upektc_img) need to re-enroll (#142).
2019-11-20: v1.90.1 release
This release fixes a lot of the regressions introduced in 1.90.0. Please note
that both the driver and external APIs have changed, as both the verify and
the identify functions now have early reporting mechanisms.
The soname for the library, as well as a number of file locations have also
changed. While this allows installation in parallel with the 1.0 version of
libfprint, we recommend installing only one, and migrating from version 1.0 to
version 2.0 alongside its main consumer (fprintd).
Only major changes are listed below. A lot of other cleanup work and small
fixes have also been merged.
* Library:
- Add support to run tests in gdb/valgrind
- Allow testing on all architectures
- Avoid image device AWAIT_FINGER_ON to deactivate state transitions
- Fix verify/identify error propagation to library user
- Correctly read image device information from class data
- Continue enroll after an image driver reported a retry error
- Change external API to allow reporting match results early
- A lot of new unit tests and integration tests have been added
* Drivers API
- Support variadic arguments in error functions
- Various re-definitions of ownership handling
- Add convenience API to change state after a timeout
- Add unit tests for all the drivers API
* Drivers:
- elan: Ensure correct deactivation of device
- uru4000: Fix IRQ handler registration and internal state handling
- uru4000: Fix control transfer request type
- synaptics: Ensure errors are only reported after finger removal
2019-11-20: v1.90.0 release
This release updates the core of the library to use GLib routines and Gio

View File

@@ -22,11 +22,9 @@
#include <gtk/gtk.h>
#include <libfprint/fprint.h>
struct _LibfprintDemo
{
GtkApplication parent;
};
G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication)
typedef GtkApplication LibfprintDemo;
typedef GtkApplicationClass LibfprintDemoClass;
G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION)
typedef enum {
@@ -35,7 +33,7 @@ typedef enum {
IMAGE_DISPLAY_BINARY = 1 << 1
} ImageDisplayFlags;
struct _LibfprintDemoWindow
typedef struct
{
GtkApplicationWindow parent_instance;
@@ -54,9 +52,10 @@ struct _LibfprintDemoWindow
FpImage *img;
ImageDisplayFlags img_flags;
};
} LibfprintDemoWindow;
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
G_DECLARE_FINAL_TYPE (LibfprintDemoWindow, libfprint_demo_window, FP, DEMO_WINDOW, GtkApplicationWindow)
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
typedef enum {
@@ -241,8 +240,6 @@ dev_capture_start_cb (FpDevice *dev,
if (error->domain == FP_DEVICE_RETRY ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
libfprint_demo_set_mode (win, RETRY_MODE);
else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
libfprint_demo_set_mode (win, NOIMAGING_MODE);
else
libfprint_demo_set_mode (win, ERROR_MODE);
return;

View File

@@ -9,11 +9,14 @@ datadir = join_paths(prefix, get_option('datadir'))
executable('gtk-libfprint-test',
[ 'gtk-libfprint-test.c', gtk_test_resources ],
dependencies: [
gtk_dep,
libfprint_dep,
dependencies: [ libfprint_dep, gtk_dep ],
include_directories: [
root_inc,
],
c_args: [
common_cflags,
'-DPACKAGE_VERSION="' + meson.project_version() + '"'
],
c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"',
install: true,
install_dir: bindir)

View File

@@ -1,7 +1,7 @@
{
"app-id": "org.freedesktop.libfprint.Demo",
"runtime": "org.gnome.Platform",
"runtime-version": "3.36",
"runtime-version": "3.32",
"sdk": "org.gnome.Sdk",
"command": "gtk-libfprint-test",
"finish-args": [

View File

@@ -26,7 +26,6 @@ FpDeviceError
fp_device_retry_quark
fp_device_error_quark
FpEnrollProgress
FpMatchCb
fp_device_get_driver
fp_device_get_device_id
fp_device_get_name
@@ -130,7 +129,7 @@ fpi_get_driver_types
<FILE>fpi-device</FILE>
FpDeviceClass
FpTimeoutFunc
FpiDeviceAction
FpDeviceAction
FpIdEntry
fpi_device_get_usb_device
fpi_device_get_virtual_env
@@ -160,8 +159,6 @@ fpi_device_identify_complete
fpi_device_capture_complete
fpi_device_delete_complete
fpi_device_enroll_progress
fpi_device_verify_report
fpi_device_identify_report
</SECTION>
<SECTION>
@@ -175,8 +172,8 @@ fpi_image_resize
<SECTION>
<FILE>fpi-image-device</FILE>
<TITLE>Internal FpImageDevice</TITLE>
FpiImageDeviceState
<TITLE>FpImageDevice</TITLE>
FpImageDeviceState
FpImageDeviceClass
fpi_image_device_session_error
fpi_image_device_open_complete
@@ -200,15 +197,13 @@ BUG
<SECTION>
<FILE>fpi-print</FILE>
FpiPrintType
FpPrintType
FpiMatchResult
fpi_print_add_print
fpi_print_set_type
fpi_print_set_device_stored
fpi_print_add_from_image
fpi_print_bz3_match
fpi_print_generate_user_id
fpi_print_fill_from_user_id
</SECTION>
<SECTION>
@@ -216,7 +211,6 @@ fpi_print_fill_from_user_id
FpiSsmCompletedCallback
FpiSsmHandlerCallback
fpi_ssm_new
fpi_ssm_new_full
fpi_ssm_free
fpi_ssm_start
fpi_ssm_start_subsm

View File

@@ -90,7 +90,7 @@ fp_image_get_width
<TITLE>Base class for image devices</TITLE>
FpImageDevice
FpImageDeviceClass
FpiImageDeviceState
FpImageDeviceState
</SECTION>
<SECTION>
@@ -114,3 +114,5 @@ FpUsbTransferCallback
FP_USB_ENDPOINT_IN
FP_USB_ENDPOINT_OUT
</SECTION>

View File

@@ -4,6 +4,7 @@ private_headers = [
'config.h',
'nbis-helpers.h',
'fprint.h',
'fp_internal.h',
# Subdirectories to ignore
'drivers',
@@ -23,13 +24,17 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(versioned_libname,
gnome.gtkdoc('libfprint',
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
dependencies: libfprint_dep,
content_files: content_files,
expand_content_files: expand_content_files,
ignore_headers: private_headers,
scan_args: [
#'--rebuild-sections',
'--ignore-decorators=API_EXPORTED',
'--ignore-headers=' + ' '.join(private_headers),
],
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),

View File

@@ -1,8 +1,8 @@
ent_conf = configuration_data()
ent_conf.set('PACKAGE', versioned_libname)
ent_conf.set('PACKAGE', 'libfprint')
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
ent_conf.set('PACKAGE_NAME', versioned_libname)
ent_conf.set('PACKAGE_STRING', versioned_libname)
ent_conf.set('PACKAGE_NAME', 'libfprint')
ent_conf.set('PACKAGE_STRING', 'libfprint')
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
ent_conf.set('PACKAGE_VERSION', meson.project_version())

View File

@@ -6,10 +6,10 @@
int main (int argc, char **argv)
{
FpContext *ctx;
FpContext *ctx;
ctx = fp_context_new ();
g_object_unref (ctx);
ctx = fp_context_new ();
g_object_unref (ctx);
return 0;
return 0;
}

View File

@@ -1,6 +1,6 @@
/*
* Example fingerprint enrollment program
* Enrolls your chosen finger and saves the print to disk
* Enrolls your choosen finger and saves the print to disk
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
@@ -19,29 +19,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-enroll"
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct _EnrollData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
GMainLoop *loop;
FpFinger finger;
int ret_value;
} EnrollData;
static void
enroll_data_free (EnrollData *enroll_data)
{
g_clear_handle_id (&enroll_data->sigint_handler, g_source_remove);
g_clear_object (&enroll_data->cancellable);
g_main_loop_unref (enroll_data->loop);
g_free (enroll_data);
}
@@ -57,7 +50,7 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_warning ("Failed closing device %s\n", error->message);
g_main_loop_quit (enroll_data->loop);
}
@@ -89,7 +82,7 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
}
else
{
g_warning ("Enroll failed with error %s", error->message);
g_warning ("Enroll failed with error %s\n", error->message);
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
@@ -112,7 +105,7 @@ on_enroll_progress (FpDevice *device,
return;
}
if (print && fp_print_get_image (print) &&
if (fp_device_supports_capture (device) &&
print_image_save (print, "enrolled.pgm"))
printf ("Wrote scanned image to enrolled.pgm\n");
@@ -142,22 +135,11 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
printf ("Scan your finger now.\n");
print_template = print_create_template (dev, enroll_data->finger);
fp_device_enroll (dev, print_template, enroll_data->cancellable,
on_enroll_progress, NULL, NULL,
(GAsyncReadyCallback) on_enroll_completed,
fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL,
NULL, (GAsyncReadyCallback) on_enroll_completed,
enroll_data);
}
static gboolean
sigint_cb (void *user_data)
{
EnrollData *enroll_data = user_data;
g_cancellable_cancel (enroll_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
@@ -204,15 +186,8 @@ main (void)
enroll_data->finger = finger;
enroll_data->ret_value = EXIT_FAILURE;
enroll_data->loop = g_main_loop_new (NULL, FALSE);
enroll_data->cancellable = g_cancellable_new ();
enroll_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
enroll_data,
NULL);
fp_device_open (dev, enroll_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
enroll_data);
g_main_loop_run (enroll_data->loop);

View File

@@ -1,192 +0,0 @@
/*
* Example fingerprint verification program, which verifies the
* finger which has been previously enrolled to disk.
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
* Copyright (C) 2020 Vasily Khoruzhick <anarsoul@gmail.com>
*
* 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 "example-capture"
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct CaptureData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
int ret_value;
const char *filename;
} CaptureData;
static void
capture_data_free (CaptureData *capture_data)
{
g_clear_handle_id (&capture_data->sigint_handler, g_source_remove);
g_clear_object (&capture_data->cancellable);
g_main_loop_unref (capture_data->loop);
g_free (capture_data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC (CaptureData, capture_data_free)
static void
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
{
CaptureData *capture_data = user_data;
g_autoptr(GError) error = NULL;
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_main_loop_quit (capture_data->loop);
}
static void
capture_quit (FpDevice *dev,
CaptureData *capture_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (capture_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, capture_data);
}
static void
dev_capture_cb (FpDevice *dev,
GAsyncResult *res,
void *user_data)
{
g_autoptr(GError) error = NULL;
CaptureData *capture_data = user_data;
FpImage *image = NULL;
g_clear_object (&capture_data->cancellable);
image = fp_device_capture_finish (dev, res, &error);
if (!image)
{
g_warning ("Error capturing data: %s", error->message);
capture_quit (dev, capture_data);
return;
}
save_image_to_pgm (image, capture_data->filename);
capture_quit (dev, capture_data);
}
static void
start_capture (FpDevice *dev, CaptureData *capture_data)
{
fp_device_capture (dev, TRUE, capture_data->cancellable, (GAsyncReadyCallback) dev_capture_cb, capture_data);
}
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
CaptureData *capture_data = user_data;
g_autoptr(GError) error = NULL;
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
capture_quit (dev, capture_data);
return;
}
g_print ("Opened device. ");
start_capture (dev, capture_data);
}
static gboolean
sigint_cb (void *user_data)
{
CaptureData *capture_data = user_data;
g_cancellable_cancel (capture_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (int argc, const char *argv[])
{
g_autoptr(FpContext) ctx = NULL;
g_autoptr(CaptureData) capture_data = NULL;
GPtrArray *devices;
FpDevice *dev;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
ctx = fp_context_new ();
devices = fp_context_get_devices (ctx);
if (!devices)
{
g_warning ("Impossible to get devices");
return EXIT_FAILURE;
}
dev = discover_device (devices);
if (!dev)
{
g_warning ("No devices detected.");
return EXIT_FAILURE;
}
if (!fp_device_supports_capture (dev))
{
g_warning ("Device %s doesn't support capture",
fp_device_get_name (dev));
return EXIT_FAILURE;
}
capture_data = g_new0 (CaptureData, 1);
capture_data->ret_value = EXIT_FAILURE;
capture_data->loop = g_main_loop_new (NULL, FALSE);
capture_data->cancellable = g_cancellable_new ();
capture_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
capture_data,
NULL);
if (argc == 2)
capture_data->filename = argv[1];
else
capture_data->filename = "finger.pgm";
fp_device_open (dev, capture_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
capture_data);
g_main_loop_run (capture_data->loop);
return capture_data->ret_value;
}

View File

@@ -18,8 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-mange-prints"
#include <stdio.h>
#include <libfprint/fprint.h>
@@ -54,7 +52,7 @@ on_device_closed (FpDevice *dev,
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_warning ("Failed closing device %s\n", error->message);
g_main_loop_quit (list_data->loop);
}
@@ -86,7 +84,7 @@ delete_next_print (FpDevice *dev,
g_assert_nonnull (list_data->to_delete);
print = list_data->to_delete->data;
g_debug ("Deleting print %s", fp_print_get_description (print));
g_debug ("Deleting print %s\n", fp_print_get_description (print));
fp_device_delete_print (dev, print, NULL,
(GAsyncReadyCallback) on_print_deleted, list_data);
}
@@ -199,6 +197,9 @@ on_list_completed (FpDevice *dev,
list_data->ret_value = EXIT_SUCCESS;
else
g_warning ("Invalid finger selected");
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
list_data);
}
}

View File

@@ -1,16 +1,19 @@
examples = [ 'enroll', 'verify', 'manage-prints', 'img-capture' ]
examples = [ 'enroll', 'verify', 'manage-prints' ]
foreach example: examples
executable(example,
[ example + '.c', 'storage.c', 'utilities.c' ],
dependencies: [
libfprint_dep,
glib_dep,
dependencies: [ libfprint_dep, glib_dep ],
include_directories: [
root_inc,
],
)
c_args: common_cflags)
endforeach
executable('cpp-test',
'cpp-test.cpp',
dependencies: libfprint_dep,
)
include_directories: [
root_inc,
],
c_args: common_cflags)

View File

@@ -19,11 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h"
#include <errno.h>
#include <stdio.h>
@@ -60,8 +56,8 @@ load_data (void)
{
GVariantDict *res;
GVariant *var;
gchar *contents = NULL;
gsize length = 0;
g_autofree gchar *contents = NULL;
gssize length = 0;
if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL))
{
@@ -69,12 +65,7 @@ load_data (void)
return g_variant_dict_new (NULL);
}
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT,
contents,
length,
FALSE,
g_free,
contents);
var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL);
res = g_variant_dict_new (var);
g_variant_unref (var);
@@ -137,7 +128,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
g_autoptr(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL;
const guchar *stored_data = NULL;
g_autofree guchar *stored_data = NULL;
gsize stored_len;
dict = load_data ();
@@ -148,7 +139,7 @@ print_data_load (FpDevice *dev, FpFinger finger)
FpPrint *print;
g_autoptr(GError) error = NULL;
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
print = fp_print_deserialize (stored_data, stored_len, &error);
if (error)
@@ -164,8 +155,8 @@ FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
{
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL;
GDate *date = NULL;
gint year, month, day;
template = fp_print_new (dev);
@@ -175,12 +166,13 @@ print_create_template (FpDevice *dev, FpFinger finger)
g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year);
fp_print_set_enroll_date (template, date);
g_date_free (date);
return template;
}
gboolean
static gboolean
save_image_to_pgm (FpImage *img, const char *path)
{
FILE *fd = fopen (path, "w");
@@ -220,7 +212,7 @@ save_image_to_pgm (FpImage *img, const char *path)
gboolean
print_image_save (FpPrint *print, const char *path)
{
FpImage *img = NULL;
g_autoptr(FpImage) img = NULL;
g_return_val_if_fail (FP_IS_PRINT (print), FALSE);
g_return_val_if_fail (path != NULL, FALSE);

View File

@@ -18,7 +18,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __STORAGE_H
#define __STORAGE_H
int print_data_save (FpPrint *print,
FpFinger finger);
@@ -28,5 +30,5 @@ FpPrint * print_create_template (FpDevice *dev,
FpFinger finger);
gboolean print_image_save (FpPrint *print,
const char *path);
gboolean save_image_to_pgm (FpImage *img,
const char *path);
#endif /* __STORAGE_H */

View File

@@ -18,8 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h>
#include <stdio.h>
@@ -109,19 +107,29 @@ finger_to_string (FpFinger finger)
FpFinger
finger_chooser (void)
{
int i = FP_FINGER_UNKNOWN;
int i;
const FpFinger all_fingers[] = {
FP_FINGER_LEFT_THUMB,
FP_FINGER_LEFT_INDEX,
FP_FINGER_LEFT_MIDDLE,
FP_FINGER_LEFT_RING,
FP_FINGER_LEFT_LITTLE,
FP_FINGER_RIGHT_THUMB,
FP_FINGER_RIGHT_INDEX,
FP_FINGER_RIGHT_MIDDLE,
FP_FINGER_RIGHT_RING,
FP_FINGER_RIGHT_LITTLE,
};
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i)
g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i));
for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i)
g_print (" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i));
g_print ("> ");
if (!scanf ("%d%*c", &i))
return FP_FINGER_UNKNOWN;
i += FP_FINGER_FIRST;
if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST)
if (i < 0 || i >= G_N_ELEMENTS (all_fingers))
return FP_FINGER_UNKNOWN;
return i;
return all_fingers[i];
}

View File

@@ -18,8 +18,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __UTILITIES_H
#define __UTILITIES_H
FpDevice * discover_device (GPtrArray *devices);
FpFinger finger_chooser (void);
const char * finger_to_string (FpFinger finger);
#endif /* __UTILITIES_H */

View File

@@ -19,29 +19,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-verify"
#include <stdio.h>
#include <libfprint/fprint.h>
#include <glib-unix.h>
#include "storage.h"
#include "utilities.h"
typedef struct _VerifyData
{
GMainLoop *loop;
GCancellable *cancellable;
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
GMainLoop *loop;
FpFinger finger;
int ret_value;
} VerifyData;
static void
verify_data_free (VerifyData *verify_data)
{
g_clear_handle_id (&verify_data->sigint_handler, g_source_remove);
g_clear_object (&verify_data->cancellable);
g_main_loop_unref (verify_data->loop);
g_free (verify_data);
}
@@ -57,24 +50,11 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
fp_device_close_finish (dev, res, &error);
if (error)
g_warning ("Failed closing device %s", error->message);
g_warning ("Failed closing device %s\n", error->message);
g_main_loop_quit (verify_data->loop);
}
static void
verify_quit (FpDevice *dev,
VerifyData *verify_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (verify_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
}
static void start_verification (FpDevice *dev,
VerifyData *verify_data);
@@ -91,65 +71,35 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
{
g_warning ("Failed to verify print: %s", error->message);
verify_data->ret_value = EXIT_FAILURE;
g_main_loop_quit (verify_data->loop);
return;
}
if (error->domain != FP_DEVICE_RETRY)
{
verify_quit (dev, verify_data);
return;
}
if (match)
{
g_print ("MATCH!\n");
if (fp_device_supports_capture (dev) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm");
verify_data->ret_value = EXIT_SUCCESS;
}
else
{
g_print ("NO MATCH!\n");
verify_data->ret_value = EXIT_FAILURE;
}
g_print ("Verify again? [Y/n]? ");
if (fgets (buffer, sizeof (buffer), stdin) &&
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
(buffer[0] == 'Y' || buffer[0] == 'y'))
{
start_verification (dev, verify_data);
return;
}
verify_quit (dev, verify_data);
}
static void
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
gpointer user_data, GError *error)
{
VerifyData *verify_data = user_data;
if (error)
{
g_warning ("Match report: Finger not matched, retry error reported: %s",
error->message);
return;
}
if (print && fp_print_get_image (print) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm\n");
if (match)
{
char date_str[128];
verify_data->ret_value = EXIT_SUCCESS;
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
fp_print_get_enroll_date (match));
g_debug ("Match report: device %s matched finger %s successifully "
"with print %s, enrolled on date %s by user %s",
fp_device_get_name (dev),
finger_to_string (fp_print_get_finger (match)),
fp_print_get_description (match), date_str,
fp_print_get_username (match));
g_print ("MATCH!\n");
}
else
{
g_debug ("Match report: Finger not matched");
g_print ("NO MATCH!\n");
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
verify_data);
}
static void
@@ -193,7 +143,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
{
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
verify_quit (dev, verify_data);
g_main_loop_quit (verify_data->loop);
return;
}
@@ -201,32 +151,28 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
fp_print_get_description (verify_print));
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, verify_data->cancellable,
on_match_cb, verify_data, NULL,
fp_device_verify (dev, verify_print, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
else
{
g_warning ("Loading prints failed with error %s", error->message);
verify_quit (dev, verify_data);
g_main_loop_quit (verify_data->loop);
}
}
static void
start_verification (FpDevice *dev, VerifyData *verify_data)
{
if (verify_data->finger == FP_FINGER_UNKNOWN)
{
g_print ("Choose the finger to verify:\n");
verify_data->finger = finger_chooser ();
}
g_print ("Choose the finger to verify:\n");
verify_data->finger = finger_chooser ();
if (verify_data->finger == FP_FINGER_UNKNOWN)
{
g_warning ("Unknown finger selected");
verify_data->ret_value = EXIT_FAILURE;
verify_quit (dev, verify_data);
g_main_loop_quit (verify_data->loop);
return;
}
@@ -250,13 +196,12 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
g_warning ("Failed to load fingerprint data");
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
verify_quit (dev, verify_data);
g_main_loop_quit (verify_data->loop);
return;
}
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, verify_data->cancellable,
on_match_cb, verify_data, NULL,
fp_device_verify (dev, verify_print, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
@@ -272,7 +217,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
verify_quit (dev, verify_data);
g_main_loop_quit (verify_data->loop);
return;
}
@@ -281,16 +226,6 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
start_verification (dev, verify_data);
}
static gboolean
sigint_cb (void *user_data)
{
VerifyData *verify_data = user_data;
g_cancellable_cancel (verify_data->cancellable);
return G_SOURCE_CONTINUE;
}
int
main (void)
{
@@ -321,14 +256,8 @@ main (void)
verify_data = g_new0 (VerifyData, 1);
verify_data->ret_value = EXIT_FAILURE;
verify_data->loop = g_main_loop_new (NULL, FALSE);
verify_data->cancellable = g_cancellable_new ();
verify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
SIGINT,
sigint_cb,
verify_data,
NULL);
fp_device_open (dev, verify_data->cancellable,
(GAsyncReadyCallback) on_device_opened,
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
verify_data);
g_main_loop_run (verify_data->loop);

View File

@@ -138,7 +138,7 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
unsigned char *data;
data = g_malloc (bytes);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, NULL);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
@@ -614,7 +614,6 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
self->strips = g_slist_reverse (self->strips);
fpi_do_movement_estimation (&assembling_ctx, self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;

View File

@@ -18,7 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AES1660_H
#define __AES1660_H
#define AES1660_FRAME_SIZE 0x244
@@ -1985,3 +1986,5 @@ static const unsigned char aes1660_start_imaging_cmd[] = {
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
};
#endif

View File

@@ -458,7 +458,6 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
fpi_do_movement_estimation (&assembling_ctx, self->strips);
img = fpi_assemble_frames (&assembling_ctx,
self->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;
@@ -687,7 +686,7 @@ enum activate_states {
ACTIVATE_NUM_STATES,
};
static void
void
activate_read_regs_cb (FpImageDevice *dev, GError *error,
unsigned char *regs, void *user_data)
{

View File

@@ -19,7 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AES2501_H
#define __AES2501_H
enum aes2501_regs {
AES2501_REG_CTRL1 = 0x80,
@@ -171,3 +172,5 @@ enum aes2501_sensor_gain2 {
#define AES2501_SUM_HIGH_THRESH 1000
#define AES2501_SUM_LOW_THRESH 700
#endif /* __AES2501_H */

View File

@@ -197,12 +197,12 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
if (data[0] != AES2550_EDATA_MAGIC)
{
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
return FALSE;
}
len = data[1] * 256 + data[2];
if (len != (AES2550_STRIP_SIZE - 3))
fp_dbg ("Bogus frame len: %.4x", len);
fp_dbg ("Bogus frame len: %.4x\n", len);
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
stripe->delta_x = (int8_t) data[6];
stripe->delta_y = -(int8_t) data[7];
@@ -230,7 +230,6 @@ capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
self->strips = g_slist_reverse (self->strips);
img = fpi_assemble_frames (&assembling_ctx, self->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (self->strips, g_free);
self->strips = NULL;
self->strips_len = 0;

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AES2550_H
#define __AES2550_H
/* Registers bits */
@@ -109,3 +110,5 @@ enum aes2550_cmds {
#define AES2550_HEARTBEAT_MAGIC 0xdb
#define AES2550_EP_IN_BUF_SIZE 8192
#endif

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AES2660_H
#define __AES2660_H
#define AES2660_FRAME_SIZE 0x354
@@ -1959,3 +1960,5 @@ static const unsigned char aes2660_start_imaging_cmd[] = {
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
};
#endif

View File

@@ -42,7 +42,8 @@
typedef struct
{
GCancellable *img_trf_cancel;
FpiUsbTransfer *img_trf;
gboolean deactivating;
} FpiDeviceAes3kPrivate;
#define CTRL_TIMEOUT 1000
@@ -83,22 +84,22 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
FpImage *img;
int i;
priv->img_trf = NULL;
if (error)
{
if (g_error_matches (error,
G_IO_ERROR,
G_IO_ERROR_CANCELLED))
{
/* Cancellation implies we are deactivating. */
/* Deactivation was completed. */
g_error_free (error);
g_clear_object (&priv->img_trf_cancel);
fpi_image_device_deactivate_complete (dev, NULL);
if (priv->deactivating)
fpi_image_device_deactivate_complete (dev, NULL);
return;
}
fpi_image_device_session_error (dev, error);
g_clear_object (&priv->img_trf_cancel);
return;
}
fpi_image_device_report_finger_status (dev, TRUE);
@@ -125,37 +126,30 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
* it really has, then restart the capture */
fpi_image_device_report_finger_status (dev, FALSE);
/* Note: We always restart the transfer, it may already be cancelled though. */
do_capture (dev);
}
static void
do_capture (FpImageDevice *dev)
{
g_autoptr(FpiUsbTransfer) img_trf = NULL;
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
img_trf->short_is_error = TRUE;
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
priv->img_trf_cancel,
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
priv->img_trf->short_is_error = TRUE;
fpi_usb_transfer_submit (priv->img_trf, 0,
fpi_device_get_cancellable (FP_DEVICE (dev)),
img_cb, NULL);
}
static void
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (FPI_DEVICE_AES3K (dev));
fpi_image_device_activate_complete (dev, result);
if (!result)
{
priv->img_trf_cancel = g_cancellable_new ();
do_capture (dev);
}
do_capture (dev);
}
static void
@@ -165,7 +159,7 @@ aes3k_dev_activate (FpImageDevice *dev)
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
g_assert (!priv->img_trf_cancel);
priv->deactivating = FALSE;
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
}
@@ -175,11 +169,10 @@ aes3k_dev_deactivate (FpImageDevice *dev)
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
/* Deactivation finishes from the cancellation handler */
if (priv->img_trf_cancel)
g_cancellable_cancel (priv->img_trf_cancel);
else
fpi_image_device_deactivate_complete (dev, NULL);
priv->deactivating = TRUE;
if (priv->img_trf)
return;
fpi_image_device_deactivate_complete (dev, NULL);
}
static void

View File

@@ -19,11 +19,13 @@
#define FP_COMPONENT "aeslib"
#include "drivers_api.h"
#include "fp_internal.h"
#include <errno.h>
#include <string.h>
#include "fpi-usb-transfer.h"
#include "fpi-assembling.h"
#include "aeslib.h"
#define MAX_REGWRITES_PER_REQUEST 16

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __AESLIB_H__
#define __AESLIB_H__
#include <fprint.h>
@@ -44,3 +45,5 @@ unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame,
unsigned int x,
unsigned int y);
#endif

View File

@@ -116,7 +116,7 @@ aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer,
/* Calibrate response was read correctly? */
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
{
fp_dbg ("Bogus calibrate response: %.2x", data[0]);
fp_dbg ("Bogus calibrate response: %.2x\n", data[0]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus calibrate "
@@ -155,14 +155,14 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
if (error)
{
fp_dbg ("Failed to read FD data");
fp_dbg ("Failed to read FD data\n");
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
{
fp_dbg ("Bogus FD response: %.2x", data[0]);
fp_dbg ("Bogus FD response: %.2x\n", data[0]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus FD response %.2x",
@@ -177,7 +177,7 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
}
else
{
fp_dbg ("Wait for finger returned %.2x as result",
fp_dbg ("Wait for finger returned %.2x as result\n",
data[AESX660_FINGER_PRESENT_OFFSET]);
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
}
@@ -331,7 +331,6 @@ capture_set_idle_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device,
priv->strips = g_slist_reverse (priv->strips);
img = fpi_assemble_frames (cls->assembling_ctx, priv->strips);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_foreach (priv->strips, (GFunc) g_free, NULL);
g_slist_free (priv->strips);
priv->strips = NULL;
@@ -405,7 +404,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
g_byte_array_set_size (priv->stripe_packet, 0);
}
fp_dbg ("finger %s", finger_missing ? "missing" : "present");
fp_dbg ("finger %s\n", finger_missing ? "missing" : "present");
if (finger_missing)
fpi_ssm_next_state (transfer->ssm);
@@ -440,7 +439,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case CAPTURE_SET_IDLE:
fp_dbg ("Got %lu frames", priv->strips_len);
fp_dbg ("Got %lu frames\n", priv->strips_len);
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
capture_set_idle_cmd_cb);
break;
@@ -513,19 +512,19 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
{
fp_dbg ("read_id cmd failed");
fp_dbg ("read_id cmd failed\n");
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
/* ID was read correctly */
if (data[0] == 0x07)
{
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x",
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n",
data[4], data[3], data[5], data[6], data[7]);
}
else
{
fp_dbg ("Bogus read ID response: %.2x", data[AESX660_RESPONSE_TYPE_OFFSET]);
fp_dbg ("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus read ID response %.2x",
@@ -553,7 +552,7 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_dbg ("Failed to init device! init status: %.2x", data[7]);
fp_dbg ("Failed to init device! init status: %.2x\n", data[7]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Failed to init device %.2x",
@@ -570,11 +569,11 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
unsigned char *data = transfer->buffer;
fp_dbg ("read_init_cb");
fp_dbg ("read_init_cb\n");
if (error)
{
fp_dbg ("read_init transfer status: %s, actual_len: %d", error->message,
fp_dbg ("read_init transfer status: %s, actual_len: %d\n", error->message,
(gint) transfer->actual_length);
fpi_ssm_mark_failed (transfer->ssm, error);
return;
@@ -582,7 +581,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
/* ID was read correctly */
if (data[0] != 0x42 || data[3] != 0x01)
{
fp_dbg ("Bogus read init response: %.2x %.2x", data[0],
fp_dbg ("Bogus read init response: %.2x %.2x\n", data[0],
data[3]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -614,13 +613,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
{
case ACTIVATE_SET_IDLE:
priv->init_seq_idx = 0;
fp_dbg ("Activate: set idle");
fp_dbg ("Activate: set idle\n");
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
fpi_ssm_usb_transfer_cb);
break;
case ACTIVATE_SEND_READ_ID_CMD:
fp_dbg ("Activate: read ID");
fp_dbg ("Activate: read ID\n");
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
fpi_ssm_usb_transfer_cb);
break;
@@ -630,7 +629,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case ACTIVATE_SEND_INIT_CMD:
fp_dbg ("Activate: send init seq #%d cmd #%d",
fp_dbg ("Activate: send init seq #%d cmd #%d\n",
priv->init_seq_idx,
priv->init_cmd_idx);
aesX660_send_cmd (ssm, _dev,
@@ -640,7 +639,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case ACTIVATE_READ_INIT_RESPONSE:
fp_dbg ("Activate: read init response");
fp_dbg ("Activate: read init response\n");
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
break;

View File

@@ -1,7 +1,6 @@
/*
* FPrint Print handling
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Driver IDs
* Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,29 +17,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "fpi-print.h"
#include "fpi-image.h"
#ifndef __DRIVER_IDS
#define __DRIVER_IDS
#include <nbis.h>
struct _FpPrint
{
GInitiallyUnowned parent_instance;
FpiPrintType type;
gchar *driver;
gchar *device_id;
gboolean device_stored;
FpImage *image;
/* Metadata */
FpFinger finger;
gchar *username;
gchar *description;
GDate *enroll_date;
GVariant *data;
GPtrArray *prints;
enum {
UPEKTS_ID = 1,
URU4000_ID = 2,
AES4000_ID = 3,
AES2501_ID = 4,
UPEKTC_ID = 5,
AES1610_ID = 6,
/* FDU2000_ID = 7, */
VCOM5S_ID = 8,
UPEKSONLY_ID = 9,
VFS101_ID = 10,
VFS301_ID = 11,
AES2550_ID = 12,
/* UPEKE2_ID = 13 */
AES1660_ID = 14,
AES2660_ID = 15,
AES3500_ID = 16,
UPEKTC_IMG_ID = 17,
ETES603_ID = 18,
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
};
#endif

View File

@@ -41,7 +41,7 @@
#include "drivers_api.h"
#include "elan.h"
static unsigned char
unsigned char
elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *frame, unsigned int x,
unsigned int y)
@@ -73,25 +73,25 @@ struct _FpiDeviceElan
/* end commands */
/* state */
gboolean deactivating;
FpiImageDeviceState dev_state;
FpiImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
gboolean deactivating;
FpImageDeviceState dev_state;
FpImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
/* end state */
};
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
static int
int
cmp_short (const void *a, const void *b)
{
return (int) (*(short *) a - *(short *) b);
@@ -207,7 +207,6 @@ elan_save_img_frame (FpiDeviceElan *elandev)
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
unsigned short *frame = g_malloc (frame_size * sizeof (short));
elan_save_frame (elandev, frame);
unsigned int sum = 0;
@@ -245,7 +244,6 @@ elan_process_frame_linear (unsigned short *raw_frame,
G_DEBUG_HERE ();
unsigned short min = 0xffff, max = 0;
for (int i = 0; i < frame_size; i++)
{
if (raw_frame[i] < min)
@@ -257,7 +255,6 @@ elan_process_frame_linear (unsigned short *raw_frame,
g_assert (max != min);
unsigned short px;
for (int i = 0; i < frame_size; i++)
{
px = raw_frame[i];
@@ -281,7 +278,6 @@ elan_process_frame_thirds (unsigned short *raw_frame,
unsigned short lvl0, lvl1, lvl2, lvl3;
unsigned short *sorted = g_malloc (frame_size * sizeof (short));
memcpy (sorted, raw_frame, frame_size * sizeof (short));
qsort (sorted, frame_size, sizeof (short), cmp_short);
lvl0 = sorted[0];
@@ -291,7 +287,6 @@ elan_process_frame_thirds (unsigned short *raw_frame,
g_free (sorted);
unsigned short px;
for (int i = 0; i < frame_size; i++)
{
px = raw_frame[i];
@@ -325,9 +320,6 @@ elan_submit_image (FpImageDevice *dev)
g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
fpi_do_movement_estimation (&assembling_ctx, frames);
img = fpi_assemble_frames (&assembling_ctx, frames);
img->flags |= FPI_IMAGE_PARTIAL;
g_slist_free_full (frames, g_free);
fpi_image_device_image_captured (dev, img);
}
@@ -487,7 +479,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
/* The device is inactive at this point. */
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
if (self->deactivating)
{
@@ -515,7 +507,6 @@ elan_stop_capture (FpDevice *dev)
FpiSsm *ssm =
fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, stop_capture_complete);
}
@@ -545,7 +536,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case CAPTURE_READ_DATA:
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE;
/* 0x55 - finger present
* 0xff - device not calibrated (probably) */
@@ -556,11 +547,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
}
else
{
/* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
fpi_ssm_mark_completed (ssm);
else
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
}
break;
@@ -592,6 +579,8 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
G_DEBUG_HERE ();
/* XXX: cancellation was specially handled by doing nothing! */
/* either max frames captured or timed out waiting for the next frame */
if (!error ||
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
@@ -626,7 +615,6 @@ elan_capture (FpDevice *dev)
elan_dev_reset_state (self);
FpiSsm *ssm =
fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, capture_complete);
}
@@ -741,7 +729,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
fp_dbg ("calibration failed");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Calibration failed!"));
"Callibration failed!"));
}
break;
@@ -783,11 +771,12 @@ calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
{
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE;
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
}
else
{
self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_capture (dev);
}
@@ -805,7 +794,6 @@ elan_calibrate (FpDevice *dev)
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state,
CALIBRATE_NUM_STATES);
fpi_ssm_start (ssm, calibrate_complete);
}
@@ -901,7 +889,6 @@ elan_activate (FpImageDevice *dev)
FpiSsm *ssm =
fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
ACTIVATE_NUM_STATES);
fpi_ssm_start (ssm, activate_complete);
}
@@ -963,7 +950,7 @@ elan_change_state (FpImageDevice *idev)
{
FpDevice *dev = FP_DEVICE (idev);
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
FpiImageDeviceState next_state = self->dev_state_next;
FpImageDeviceState next_state = self->dev_state_next;
if (self->dev_state == next_state)
{
@@ -977,18 +964,17 @@ elan_change_state (FpImageDevice *idev)
switch (next_state)
{
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
/* activation completed or another enroll stage started */
self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_calibrate (dev);
break;
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
case FP_IMAGE_DEVICE_STATE_CAPTURE:
/* not used */
break;
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
elan_stop_capture (dev);
break;
}
@@ -998,12 +984,12 @@ static void
elan_change_state_async (FpDevice *dev,
void *data)
{
fp_dbg ("state change dev: %p", dev);
g_message ("state change dev: %p", dev);
elan_change_state (FP_IMAGE_DEVICE (dev));
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
GSource *timeout;
@@ -1011,20 +997,17 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
G_DEBUG_HERE ();
/* Inactive and await finger off are equivalent for the elan driver. */
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FP_IMAGE_DEVICE_STATE_INACTIVE;
if (self->dev_state_next == state)
{
fp_dbg ("change to state %d already queued", state);
return;
}
fp_dbg ("change to state %d already queued", state);
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
char *name;
/* schedule state change instead of calling it directly to allow all actions
@@ -1041,7 +1024,7 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
break;
}
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
case FP_IMAGE_DEVICE_STATE_CAPTURE:
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
self->dev_state = state;
self->dev_state_next = state;
@@ -1059,7 +1042,7 @@ dev_deactivate (FpImageDevice *dev)
G_DEBUG_HERE ();
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE)
{
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
@@ -1070,7 +1053,7 @@ dev_deactivate (FpImageDevice *dev)
* need to signal back deactivation) and then ensure we will change
* to the inactive state eventually. */
self->deactivating = TRUE;
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE);
}
}

View File

@@ -18,7 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __ELAN_H
#define __ELAN_H
#include <glib.h>
@@ -221,5 +222,7 @@ static void elan_cmd_read (FpiSsm *ssm,
static void elan_calibrate (FpDevice *dev);
static void elan_capture (FpDevice *dev);
static void dev_change_state (FpImageDevice *dev,
FpiImageDeviceState state);
static void dev_change_state (FpImageDevice *dev,
FpImageDeviceState state);
#endif

View File

@@ -36,6 +36,7 @@
#define FP_COMPONENT "etes603"
#include "drivers_api.h"
#include "driver_ids.h"
/* libusb defines */
#define EP_IN 0x81
@@ -859,29 +860,21 @@ m_capture_state (FpiSsm *ssm, FpDevice *dev)
}
else
{
FpImage *img;
unsigned int img_size;
/* Remove empty parts 2 times for the 2 frames */
process_removefpi_end (self);
process_removefpi_end (self);
if (self->fp_height >= FE_WIDTH)
{
FpImage *img = fp_image_new (FE_WIDTH, self->fp_height);
unsigned int img_size = self->fp_height * FE_WIDTH;
/* Images received are white on black, so invert it. */
/* TODO detect sweep direction */
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
img->height = self->fp_height;
process_4to8_bpp (self->fp, img_size / 2, img->data);
fp_dbg ("Sending the raw fingerprint image (%dx%d)",
img->width, img->height);
fpi_image_device_image_captured (idev, img);
}
else
{
fpi_image_device_retry_scan (idev, FP_DEVICE_RETRY_TOO_SHORT);
}
img_size = self->fp_height * FE_WIDTH;
img = fp_image_new (FE_WIDTH, self->fp_height);
/* Images received are white on black, so invert it. */
/* TODO detect sweep direction */
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
img->height = self->fp_height;
process_4to8_bpp (self->fp, img_size / 2, img->data);
fp_dbg ("Sending the raw fingerprint image (%dx%d)",
img->width, img->height);
fpi_image_device_image_captured (idev, img);
fpi_image_device_report_finger_status (idev, FALSE);
fpi_ssm_mark_completed (ssm);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,58 +0,0 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* 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
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
G_DECLARE_FINAL_TYPE (FpiDeviceGoodixMoc, fpi_device_goodixmoc, FPI, DEVICE_GOODIXMOC, FpDevice)
typedef enum {
FP_CMD_SEND = 0,
FP_CMD_GET_ACK,
FP_CMD_GET_DATA,
FP_CMD_NUM_STATES,
} FpCmdState;
typedef enum {
FP_INIT_VERSION = 0,
FP_INIT_CONFIG,
FP_INIT_NUM_STATES,
} FpInitState;
typedef enum {
FP_ENROLL_ENUM = 0,
FP_ENROLL_IDENTIFY,
FP_ENROLL_CREATE,
FP_ENROLL_CAPTURE,
FP_ENROLL_UPDATE,
FP_ENROLL_WAIT_FINGER_UP,
FP_ENROLL_CHECK_DUPLICATE,
FP_ENROLL_COMMIT,
FP_ENROLL_NUM_STATES,
} FpEnrollState;
typedef enum {
FP_VERIFY_CAPTURE = 0,
FP_VERIFY_IDENTIFY,
FP_VERIFY_NUM_STATES,
} FpVerifyState;

View File

@@ -1,422 +0,0 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* 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 <glib.h>
#include "goodix_proto.h"
/*
* Crc functions
*/
#define WIDTH (8 * sizeof (uint32_t))
#define FINAL_XOR_VALUE 0xFFFFFFFF
#define REFLECT_DATA(X) ((uint8_t) reflect ((X), 8))
#define REFLECT_REMAINDER(X) ((unsigned int) reflect ((X), WIDTH))
uint8_t
gx_proto_crc8_calc (uint8_t *lubp_date, uint32_t lui_len)
{
const uint8_t *data = lubp_date;
unsigned int crc = 0;
int i, j;
for (j = lui_len; j; j--, data++)
{
crc ^= (*data << 8);
for (i = 8; i; i--)
{
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
crc >>= 8;
crc = ~crc;
return (uint8_t) crc;
}
typedef struct
{
uint32_t crc;
} gf_crc32_context;
static uint32_t s_crc_table[256] =
{ 0x0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, 0x808d07d, 0xcc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
static uint32_t
reflect (uint32_t data, uint8_t n_bits)
{
unsigned long reflection = 0x00000000;
uint8_t bit;
/*
* Reflect the data about the center bit.
*/
for (bit = 0; bit < n_bits; ++bit)
{
/*
* If the LSB bit is set, set the reflection of it.
*/
if (data & 0x01)
reflection |= (1 << ((n_bits - 1) - bit));
data = (data >> 1);
}
return reflection;
}
static void
crc32_init (gf_crc32_context *ctx)
{
ctx->crc = 0xFFFFFFFF;
}
static void
crc32_update (gf_crc32_context *ctx, const uint8_t *message, uint32_t n_bytes)
{
uint8_t data;
uint32_t byte;
/*
* Divide the message by the polynomial, a byte at a time.
*/
for (byte = 0; byte < n_bytes; ++byte)
{
data = REFLECT_DATA (message[byte]) ^ (ctx->crc >> (WIDTH - 8));
ctx->crc = s_crc_table[data] ^ (ctx->crc << 8);
}
}
static void
crc32_final (gf_crc32_context *ctx, uint8_t *md)
{
ctx->crc = (REFLECT_REMAINDER (ctx->crc) ^ FINAL_XOR_VALUE);
memcpy (md, &ctx->crc, 4);
}
uint8_t
gx_proto_crc32_calc (uint8_t *pchMsg, uint32_t wDataLen, uint8_t *pchMsgDst)
{
gf_crc32_context context = { 0 };
if (!pchMsg)
return 0;
crc32_init (&context);
crc32_update (&context, pchMsg, wDataLen);
crc32_final (&context, pchMsgDst);
return 1;
}
/*
* protocol
*
*/
static uint8_t dump_seq = 0;
static void
init_pack_header (
ppack_header pheader,
uint16_t len,
uint16_t cmd,
uint8_t packagenum
)
{
g_assert (pheader);
memset (pheader, 0, sizeof (*pheader));
pheader->cmd0 = HIBYTE (cmd);
pheader->cmd1 = LOBYTE (cmd);
pheader->packagenum = packagenum;
pheader->reserved = dump_seq++;
pheader->len = len + PACKAGE_CRC_SIZE;
pheader->crc8 = gx_proto_crc8_calc ((uint8_t *) pheader, 6);
pheader->rev_crc8 = ~pheader->crc8;
}
int
gx_proto_build_package (uint8_t *ppackage,
uint32_t *package_len,
uint16_t cmd,
const uint8_t *payload,
uint32_t payload_size)
{
pack_header header;
if (!ppackage || !package_len)
return -1;
if(*package_len < (payload_size + PACKAGE_HEADER_SIZE + PACKAGE_CRC_SIZE))
return -1;
init_pack_header (&header, payload_size, cmd, 0);
memcpy (ppackage, &header, PACKAGE_HEADER_SIZE);
memcpy (ppackage + PACKAGE_HEADER_SIZE, payload, payload_size);
gx_proto_crc32_calc (ppackage, PACKAGE_HEADER_SIZE + payload_size, ppackage + PACKAGE_HEADER_SIZE + payload_size);
return 0;
}
int
gx_proto_parse_header (
uint8_t *buffer,
uint32_t buffer_len,
pack_header *pheader)
{
if (!buffer || !pheader)
return -1;
if (buffer_len < PACKAGE_HEADER_SIZE)
return -1;
memcpy (pheader, buffer, sizeof (pack_header));
pheader->len = GUINT16_FROM_LE (*(buffer + 4));
pheader->len -= PACKAGE_CRC_SIZE;
return 0;
}
static int
gx_proto_parse_fingerid (
uint8_t * fid_buffer,
uint16_t fid_buffer_size,
ptemplate_format_t template
)
{
uint8_t * buffer = NULL;
uint16_t Offset = 0;
if (!template || !fid_buffer)
return -1;
if (fid_buffer_size < 70)
return -1;
buffer = fid_buffer;
Offset = 0;
if (buffer[Offset++] != 67)
return -1;
template->type = buffer[Offset++];
template->finger_index = buffer[Offset++];
Offset++;
memcpy (template->accountid, &buffer[Offset], 32);
Offset += 32;
memcpy (template->tid, &buffer[Offset], 32);
Offset += 32; // Offset == 68
template->payload.size = buffer[Offset++];
memset (template->payload.data, 0, 56);
memcpy (template->payload.data, &buffer[Offset], template->payload.size);
return 0;
}
int
gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint32_t buffer_len, pgxfp_cmd_response_t presp)
{
uint32_t offset = 0;
uint8_t *fingerlist = NULL;
if (!buffer || !presp)
return -1;
if (buffer_len < 1)
return -1;
presp->result = buffer[0];
switch (HIBYTE (cmd))
{
case RESPONSE_PACKAGE_CMD:
{
presp->parse_msg.ack_cmd = buffer[1];
}
break;
case MOC_CMD0_UPDATE_CONFIG:
case MOC_CMD0_COMMITENROLLMENT:
case MOC_CMD0_DELETETEMPLATE:
break;
case MOC_CMD0_GET_VERSION:
memcpy (&presp->version_info, buffer + 1, sizeof (gxfp_version_info_t));
break;
case MOC_CMD0_CAPTURE_DATA:
if (LOBYTE (cmd) == MOC_CMD1_DEFAULT)
{
presp->capture_data_resp.img_quality = buffer[1];
presp->capture_data_resp.img_coverage = buffer[2];
}
break;
case MOC_CMD0_ENROLL_INIT:
if (presp->result == GX_SUCCESS)
memcpy (&presp->enroll_init.tid, &buffer[1], TEMPLATE_ID_SIZE);
break;
case MOC_CMD0_ENROLL:
presp->enroll_update.rollback = (buffer[0] < 0x80) ? false : true;
presp->enroll_update.img_overlay = buffer[1];
presp->enroll_update.img_preoverlay = buffer[2];
break;
case MOC_CMD0_CHECK4DUPLICATE:
presp->check_duplicate_resp.duplicate = (presp->result == 0) ? false : true;
if (presp->check_duplicate_resp.duplicate)
{
uint16_t tid_size = GUINT16_FROM_LE (*(buffer + 1));
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
}
break;
case MOC_CMD0_GETFINGERLIST:
if (presp->result != GX_SUCCESS)
break;
presp->finger_list_resp.finger_num = buffer[1];
if (presp->finger_list_resp.finger_num > FP_MAX_FINGERNUM)
{
presp->finger_list_resp.finger_num = 0;
presp->result = GX_ERROR_NO_AVAILABLE_SPACE;
break;
}
fingerlist = buffer + 2;
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{
uint16_t fingerid_length = GUINT16_FROM_LE (*(fingerlist + offset));
offset += 2;
if (gx_proto_parse_fingerid (fingerlist + offset,
fingerid_length,
&presp->finger_list_resp.finger_list[num]) != 0)
{
g_error ("parse fingerlist error");
presp->finger_list_resp.finger_num = 0;
presp->result = GX_FAILED;
break;
}
offset += fingerid_length;
}
break;
case MOC_CMD0_IDENTIFY:
{
uint32_t score = 0;
uint8_t study = 0;
uint16_t fingerid_size = 0;
presp->verify.match = (buffer[0] == 0) ? true : false;
if (presp->verify.match)
{
offset += 1;
presp->verify.rejectdetail = GUINT16_FROM_LE (*(buffer + offset));
offset += 2;
score = GUINT32_FROM_LE (*(buffer + offset));
offset += 4;
study = GUINT16_FROM_LE (*(buffer + offset));
offset += 1;
fingerid_size = GUINT16_FROM_LE (*(buffer + offset));
offset += 2;
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
{
presp->result = GX_FAILED;
break;
}
g_debug ("match, score: %d, study: %d", score, study);
}
}
break;
case MOC_CMD0_FINGER_MODE:
presp->finger_status.status = buffer[0];
break;
default:
break;
}
return 0;
}
static uint8_t sensor_config[26] = {
0x00, 0x00, 0x64, 0x50, 0x0f, 0x41, 0x08, 0x0a, 0x18, 0x00, 0x00, 0x23, 0x00,
0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x05, 0x05
};
int
gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig)
{
uint32_t crc32_calc = 0;
if (!pconfig)
return -1;
memset (pconfig, 0, sizeof (*pconfig));
//NOTICE: Do not change any value!
memcpy (&pconfig->config, sensor_config, 26);
pconfig->reserved[0] = 1;
gx_proto_crc32_calc ((uint8_t *) pconfig, sizeof (*pconfig) - PACKAGE_CRC_SIZE, (uint8_t *) &crc32_calc);
memcpy (pconfig->crc_value, &crc32_calc, PACKAGE_CRC_SIZE);
return 0;
}

View File

@@ -1,232 +0,0 @@
/*
* Goodix Moc driver for libfprint
* Copyright (C) 2019 Shenzhen Goodix Technology Co., Ltd.
*
* 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
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define PACKAGE_CRC_SIZE (4)
#define PACKAGE_HEADER_SIZE (8)
#define FP_MAX_FINGERNUM (10)
#define TEMPLATE_ID_SIZE (32)
#define GX_VERSION_LEN (8)
/* Type covert */
#define MAKE_CMD_EX(cmd0, cmd1) ((uint16_t) (((cmd0) << 8) | (cmd1)))
#define LOBYTE(value) ((uint8_t) (value))
#define HIBYTE(value) ((uint8_t) (((uint16_t) (value) >> 8) & 0xFF))
/* Error code */
#define GX_SUCCESS 0x00
#define GX_FAILED 0x80
#define GX_ERROR_FINGER_ID_NOEXIST 0x9C
#define GX_ERROR_TEMPLATE_INCOMPLETE 0xB8
#define GX_ERROR_WAIT_FINGER_UP_TIMEOUT 0xC7
#define GX_ERROR_NO_AVAILABLE_SPACE 0x8F
/* Command Type Define */
#define RESPONSE_PACKAGE_CMD 0xAA
#define MOC_CMD0_ENROLL 0xA0
#define MOC_CMD0_ENROLL_INIT 0xA1
#define MOC_CMD0_CAPTURE_DATA 0xA2
#define MOC_CMD0_CHECK4DUPLICATE 0xA3
#define MOC_CMD0_COMMITENROLLMENT 0xA4
#define MOC_CMD0_IDENTIFY 0xA5
#define MOC_CMD0_GETFINGERLIST 0xA6
#define MOC_CMD0_DELETETEMPLATE 0xA7
#define MOC_CMD1_DEFAULT 0x00
#define MOC_CMD1_UNTIL_DOWN 0x00
#define MOC_CMD1_WHEN_DOWN 0x01
#define MOC_CMD1_DELETE_TEMPLATE 0x04
#define MOC_CMD1_DELETE_ALL 0x01
#define MOC_CMD0_GET_VERSION 0xD0
#define MOC_CMD0_UPDATE_CONFIG 0xC0
#define MOC_CMD1_NWRITE_CFG_TO_FLASH 0x00
#define MOC_CMD1_WRITE_CFG_TO_FLASH 0x01
#define MOC_CMD0_FINGER_MODE 0xB0
#define MOC_CMD1_GET_FINGER_MODE 0x00
#define MOC_CMD1_SET_FINGER_DOWN 0x01
#define MOC_CMD1_SET_FINGER_UP 0x02
/* */
typedef struct _gxfp_version_info
{
uint8_t format[2];
uint8_t fwtype[GX_VERSION_LEN];
uint8_t fwversion[GX_VERSION_LEN];
uint8_t customer[GX_VERSION_LEN];
uint8_t mcu[GX_VERSION_LEN];
uint8_t sensor[GX_VERSION_LEN];
uint8_t algversion[GX_VERSION_LEN];
uint8_t interface[GX_VERSION_LEN];
uint8_t protocol[GX_VERSION_LEN];
uint8_t flashVersion[GX_VERSION_LEN];
uint8_t reserved[62];
} gxfp_version_info_t, *pgxfp_version_info_t;
typedef struct _gxfp_parse_msg
{
uint8_t ack_cmd;
bool has_no_config;
} gxfp_parse_msg_t, *pgxfp_parse_msg_t;
typedef struct _gxfp_enroll_init
{
uint8_t tid[TEMPLATE_ID_SIZE];
} gxfp_enroll_init_t, *pgxfp_enroll_init_t;
#pragma pack(push, 1)
typedef struct _template_format
{
uint8_t type;
uint8_t finger_index;
uint8_t accountid[32];
uint8_t tid[32];
struct
{
uint32_t size;
uint8_t data[56];
} payload;
uint8_t reserve[2];
} template_format_t, *ptemplate_format_t;
#pragma pack(pop)
typedef struct _gxfp_verify
{
bool match;
uint32_t rejectdetail;
template_format_t template;
} gxfp_verify_t, *pgxfp_verify_t;
typedef struct _gxfp_capturedata
{
uint8_t img_quality;
uint8_t img_coverage;
} gxfp_capturedata_t, *pgxfp_capturedata_t;
typedef struct _gxfp_check_duplicate
{
bool duplicate;
template_format_t template;
} gxfp_check_duplicate_t, *pgxfp_check_duplicate_t;
typedef struct _gxfp_enroll_update
{
bool rollback;
uint8_t img_overlay;
uint8_t img_preoverlay;
} gxfp_enroll_update_t, *Pgxfp_enroll_update_t;
typedef struct _gxfp_enum_fingerlist
{
uint8_t finger_num;
template_format_t finger_list[FP_MAX_FINGERNUM];
} gxfp_enum_fingerlist_t, *pgxfp_enum_fingerlist_t;
typedef struct _gxfp_enroll_commit
{
uint8_t result;
} gxfp_enroll_commit_t, *pgxfp_enroll_commit_t;
typedef struct _fp_finger_status
{
uint8_t status;
} fp_finger_status_t, *pfp_finger_status_t;
typedef struct _fp_cmd_response
{
uint8_t result;
union
{
gxfp_parse_msg_t parse_msg;
gxfp_verify_t verify;
gxfp_enroll_init_t enroll_init;
gxfp_capturedata_t capture_data_resp;
gxfp_check_duplicate_t check_duplicate_resp;
gxfp_enroll_commit_t enroll_commit;
gxfp_enroll_update_t enroll_update;
gxfp_enum_fingerlist_t finger_list_resp;
gxfp_version_info_t version_info;
fp_finger_status_t finger_status;
};
} gxfp_cmd_response_t, *pgxfp_cmd_response_t;
typedef struct _pack_header
{
uint8_t cmd0;
uint8_t cmd1;
uint8_t packagenum;
uint8_t reserved;
uint16_t len;
uint8_t crc8;
uint8_t rev_crc8;
} pack_header, *ppack_header;
typedef struct _gxfp_sensor_cfg
{
uint8_t config[26];
uint8_t reserved[98];
uint8_t crc_value[4];
} gxfp_sensor_cfg_t, *pgxfp_sensor_cfg_t;
/* */
int gx_proto_build_package (uint8_t *ppackage,
uint32_t *package_len,
uint16_t cmd,
const uint8_t *payload,
uint32_t payload_size);
int gx_proto_parse_header (uint8_t *buffer,
uint32_t buffer_len,
pack_header *pheader);
int gx_proto_parse_body (uint16_t cmd,
uint8_t *buffer,
uint32_t buffer_len,
pgxfp_cmd_response_t presponse);
int gx_proto_init_sensor_config (pgxfp_sensor_cfg_t pconfig);
uint8_t gx_proto_crc8_calc (uint8_t *lubp_date,
uint32_t lui_len);
uint8_t gx_proto_crc32_calc (uint8_t *pchMsg,
uint32_t wDataLen,
uint8_t *pchMsgDst);

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef _BMKT_H_
#define _BMKT_H_
/**< User ID maximum length allowed */
#define BMKT_MAX_USER_ID_LEN 100
@@ -227,3 +228,5 @@ typedef struct bmkt_user_id
#ifdef __cplusplus
}
#endif
#endif /* _BMKT_H_ */

View File

@@ -206,7 +206,6 @@ parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *res
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
int n = 0;
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
{
if (offset >= msg_resp->payload_len)

View File

@@ -16,7 +16,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef BMKT_MESSAGE_H_
#define BMKT_MESSAGE_H_
#define BMKT_MESSAGE_HEADER_ID 0xFE
#define BMKT_MESSAGE_HEADER_LEN (4)
@@ -87,3 +90,4 @@ int bmkt_parse_message_header (uint8_t *resp_buf,
bmkt_msg_resp_t *msg_resp);
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
bmkt_response_t *resp);
#endif /* BMKT_MESSAGE_H_ */

View File

@@ -17,7 +17,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef _BMKT_RESPONSE_H_
#define _BMKT_RESPONSE_H_
#include "bmkt.h"
@@ -316,7 +318,7 @@ typedef struct bmkt_init_resp
*/
typedef struct bmkt_enroll_resp
{
int progress; /**< Shows current progress status [0-100] */
int progress; /**< Shows current progress stutus [0-100] */
uint8_t finger_id; /**< User's finger id [1-10] */
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
} bmkt_enroll_resp_t;
@@ -483,3 +485,5 @@ typedef struct bmkt_response
int complete; /**< Operation completion status 1: complete / 0: not completed */
bmkt_response_data_t response; /**< Operation specific response union */
} bmkt_response_t;
#endif /* _BMKT_RESPONSE_H_ */

View File

@@ -16,7 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef _SENSOR_H_
#define _SENSOR_H_
#include "usb_transport.h"
#define BMKT_MAX_PENDING_SESSIONS 2
@@ -83,3 +84,4 @@ int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
bmkt_msg_resp_t *msg_resp);
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
#endif /* _SENSOR_H_ */

View File

@@ -29,14 +29,13 @@ G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
static void
cmd_receive_cb (FpiUsbTransfer *transfer,
cmd_recieve_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data,
GError *error)
@@ -169,7 +168,7 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
* depending on resp.complete. */
if (self->cmd_pending_transfer)
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING);
else if (!resp.complete || self->cmd_complete_on_removal)
else if (!resp.complete)
fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */
else
fpi_ssm_mark_completed (transfer->ssm);
@@ -235,7 +234,7 @@ synaptics_cmd_run_state (FpiSsm *ssm,
fpi_usb_transfer_submit (transfer,
5000,
NULL,
cmd_receive_cb,
cmd_recieve_cb,
fpi_ssm_get_data (ssm));
break;
@@ -280,10 +279,17 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
self->cmd_ssm = NULL;
/* Notify about the SSM failure from here instead. */
if (error || self->cmd_complete_on_removal)
callback (self, NULL, error);
if (error)
{
callback (self, NULL, error);
}
else if (self->cmd_complete_on_removal)
{
callback (self, NULL, self->cmd_complete_error);
self->cmd_complete_error = NULL;
}
self->cmd_complete_on_removal = FALSE;
g_clear_pointer (&self->cmd_complete_error, g_error_free);
}
static void
@@ -322,7 +328,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self,
g_assert (payload || payload_len == 0);
/* seq_num of 0 means a normal command, -1 means the current commands
* sequence number should not be updated (i.e. second async command which
* sequence number should not be udpated (i.e. second async command which
* may only be a cancellation currently). */
if (seq_num <= 0)
{
@@ -401,7 +407,7 @@ static gboolean
parse_print_data (GVariant *data,
guint8 *finger,
const guint8 **user_id,
gsize *user_id_len)
gssize *user_id_len)
{
g_autoptr(GVariant) user_id_var = NULL;
@@ -500,7 +506,7 @@ list_msg_cb (FpiDeviceSynaptics *self,
get_enroll_templates_resp->templates[n].user_id,
get_enroll_templates_resp->templates[n].finger_id);
userid = (gchar *) get_enroll_templates_resp->templates[n].user_id;
userid = get_enroll_templates_resp->templates[n].user_id;
print = fp_print_new (FP_DEVICE (self));
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
@@ -511,12 +517,45 @@ list_msg_cb (FpiDeviceSynaptics *self,
get_enroll_templates_resp->templates[n].finger_id,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_type (print, FP_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "fp-data", data, NULL);
g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL);
fpi_print_fill_from_user_id (print, userid);
/* The format has 24 bytes at the start and some dashes in the right places */
if (g_str_has_prefix (userid, "FP1-") && strlen (userid) >= 24 &&
userid[12] == '-' && userid[14] == '-' && userid[23] == '-')
{
g_autofree gchar *copy = g_strdup (userid);
gint32 date_ymd;
GDate *date = NULL;
gint32 finger;
gchar *username;
/* Try to parse information from the string. */
copy[12] = '\0';
date_ymd = g_ascii_strtod (copy + 4, NULL);
if (date_ymd > 0)
date = g_date_new_dmy (date_ymd % 100,
(date_ymd / 100) % 100,
date_ymd / 10000);
else
date = g_date_new ();
fp_print_set_enroll_date (print, date);
g_date_free (date);
copy[14] = '\0';
finger = g_ascii_strtoll (copy + 13, NULL, 16);
fp_print_set_finger (print, finger);
/* We ignore the next chunk, it is just random data.
* Then comes the username; nobody is the default if the metadata
* is unknown */
username = copy + 24;
if (strlen (username) > 0 && g_strcmp0 (username, "nobody") != 0)
fp_print_set_username (print, username);
}
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
}
@@ -543,22 +582,6 @@ list (FpDevice *device)
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
}
static void
verify_complete_after_finger_removal (FpiDeviceSynaptics *self)
{
FpDevice *device = FP_DEVICE (self);
if (self->finger_on_sensor)
{
fp_dbg ("delaying verify report until after finger removal!");
self->cmd_complete_on_removal = TRUE;
}
else
{
fpi_device_verify_complete (device, NULL);
}
}
static void
verify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
@@ -569,13 +592,16 @@ verify_msg_cb (FpiDeviceSynaptics *self,
if (error)
{
fpi_device_verify_complete (device, error);
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error);
return;
}
if (resp == NULL && self->cmd_complete_on_removal)
{
fpi_device_verify_complete (device, NULL);
fpi_device_verify_complete (device,
GPOINTER_TO_INT (self->cmd_complete_data),
NULL,
error);
return;
}
@@ -594,40 +620,39 @@ verify_msg_cb (FpiDeviceSynaptics *self,
break;
case BMKT_RSP_VERIFY_FAIL:
if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
if(resp->result == BMKT_SENSOR_STIMULUS_ERROR)
{
fp_info ("Match error occurred");
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
verify_complete_after_finger_removal (self);
fp_dbg ("delaying retry error until after finger removal!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR);
self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
}
else if (resp->result == BMKT_FP_NO_MATCH)
{
fp_info ("Print didn't match");
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
verify_complete_after_finger_removal (self);
fp_dbg ("delaying match failure until after finger removal!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL);
self->cmd_complete_error = NULL;
}
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS)
{
fp_info ("Print is not in database");
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
else
{
fp_warn ("Verify has failed: %d", resp->result);
fpi_device_verify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected result from device %d",
resp->result));
fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL);
}
break;
case BMKT_RSP_VERIFY_OK:
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
fpi_device_verify_complete (device, NULL);
fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL);
break;
}
}
@@ -645,11 +670,13 @@ verify (FpDevice *device)
fpi_device_get_verify_data (device, &print);
g_object_get (print, "fpi-data", &data, NULL);
g_object_get (print, "fp-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
@@ -699,7 +726,7 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
if (enroll_resp->progress < 100)
done_stages = MIN (done_stages, ENROLL_SAMPLES - 1);
/* Emit a retry error if there has been no discernible
/* Emit a retry error if there has been no discernable
* progress. Some firmware revisions report more required
* touches. */
if (self->enroll_stage == done_stages)
@@ -764,6 +791,8 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
}
}
#define TEMPLATE_ID_SIZE 20
static void
enroll (FpDevice *device)
{
@@ -771,21 +800,52 @@ enroll (FpDevice *device)
FpPrint *print = NULL;
GVariant *data = NULL;
GVariant *uid = NULL;
const gchar *username;
guint finger;
g_autofree gchar *user_id = NULL;
gssize user_id_len;
g_autofree guint8 *payload = NULL;
const GDate *date;
gint y, m, d;
gint32 rand_id = 0;
fpi_device_get_enroll_data (device, &print);
G_DEBUG_HERE ();
user_id = fpi_print_generate_user_id (print);
date = fp_print_get_enroll_date (print);
if (date && g_date_valid (date))
{
y = g_date_get_year (date);
m = g_date_get_month (date);
d = g_date_get_day (date);
}
else
{
y = 0;
m = 0;
d = 0;
}
username = fp_print_get_username (print);
if (!username)
username = "nobody";
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
rand_id = 0;
else
rand_id = g_random_int ();
user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s",
y, m, d,
fp_print_get_finger (print),
rand_id,
username);
user_id_len = strlen (user_id);
user_id_len = MIN (BMKT_MAX_USER_ID_LEN, user_id_len);
/* We currently always use finger 1 from the devices point of view */
/* We currently always use finger 1 from the devices piont of view */
finger = 1;
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
@@ -796,9 +856,9 @@ enroll (FpDevice *device)
finger,
uid);
fpi_print_set_type (print, FPI_PRINT_RAW);
fpi_print_set_type (print, FP_PRINT_RAW);
fpi_print_set_device_stored (print, TRUE);
g_object_set (print, "fpi-data", data, NULL);
g_object_set (print, "fp-data", data, NULL);
g_object_set (print, "description", user_id, NULL);
g_debug ("user_id: %s, finger: %d", user_id, finger);
@@ -867,7 +927,7 @@ delete_print (FpDevice *device)
fpi_device_get_delete_data (device, &print);
g_object_get (print, "fpi-data", &data, NULL);
g_object_get (print, "fp-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
@@ -898,7 +958,6 @@ dev_probe (FpDevice *device)
const guint8 *data;
gboolean read_ok = TRUE;
g_autofree gchar *serial = NULL;
gboolean retry = TRUE;
G_DEBUG_HERE ();
@@ -910,49 +969,41 @@ dev_probe (FpDevice *device)
return;
}
if (!g_usb_device_reset (usb_dev, &error))
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
goto err_close;
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
goto err_close;
while(1)
/* TODO: Do not do this synchronous. */
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
transfer->short_is_error = TRUE;
transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
goto err_close;
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
goto err_close;
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
{
/* TODO: Do not do this synchronous. */
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
transfer->short_is_error = TRUE;
transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
goto err_close;
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
transfer = fpi_usb_transfer_new (device);
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
goto err_close;
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
{
g_warning ("Transfer in response to version query was too short");
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto err_close;
}
if (status != 0)
{
g_warning ("Device responded with error: %d retry: %d", status, retry);
if(retry)
{
retry = FALSE;
continue;
}
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto err_close;
}
break;
g_warning ("Transfer in response to version query was too short");
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto err_close;
}
if (status != 0)
{
g_warning ("Device responded with error: %d", status);
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto err_close;
}
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
@@ -974,7 +1025,7 @@ dev_probe (FpDevice *device)
if (!read_ok)
{
g_warning ("Transfer in response to version query was too short");
g_warning ("Transfer in response to verison query was too short");
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
goto err_close;
}

View File

@@ -16,7 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __synaptics_h__
#define __synaptics_h__
#include "fpi-device.h"
#include "fpi-ssm.h"
@@ -110,6 +111,8 @@ struct _FpiDeviceSynaptics
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal;
GError *cmd_complete_error;
void *cmd_complete_data;
bmkt_sensor_version_t mis_version;
@@ -123,3 +126,5 @@ struct _FpiDeviceSynaptics
struct syna_enroll_resp_data enroll_resp_data;
syna_state_t state;
};
#endif //__synaptics_h__

View File

@@ -47,11 +47,17 @@ enum {
enum sonly_kill_transfers_action {
NOT_KILLING = 0,
/* abort a SSM with an error code */
ABORT_SSM,
/* report an image session error */
IMG_SESSION_ERROR,
/* iterate a SSM to the next state */
ITERATE_SSM,
/* call a callback */
EXEC_CALLBACK,
};
enum sonly_fs {
@@ -91,9 +97,13 @@ struct _FpiDeviceUpeksonly
enum sonly_kill_transfers_action killing_transfers;
GError *kill_error;
FpiSsm *kill_ssm;
union
{
FpiSsm *kill_ssm;
void (*kill_cb)(FpImageDevice *dev);
};
struct fpi_line_asmbl_ctx assembling_ctx;
struct fpi_line_asmbl_ctx assembling_ctx;
};
G_DECLARE_FINAL_TYPE (FpiDeviceUpeksonly, fpi_device_upeksonly, FPI,
DEVICE_UPEKSONLY, FpImageDevice);
@@ -166,6 +176,11 @@ last_transfer_killed (FpImageDevice *dev)
switch (self->killing_transfers)
{
case ABORT_SSM:
fp_dbg ("abort ssm error %s", self->kill_error->message);
fpi_ssm_mark_failed (self->kill_ssm, g_steal_pointer (&self->kill_error));
return;
case ITERATE_SSM:
fp_dbg ("iterate ssm");
fpi_ssm_next_state (self->kill_ssm);
@@ -516,14 +531,6 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
return;
}
/* NOTE: The old code assume 4096 bytes are received each time
* but there is no reason we need to enforce that. However, we
* always need full lines. */
if (transfer->actual_length % 64 != 0)
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Data packets need to be multiple of 64 bytes, got %zi bytes",
transfer->actual_length);
if (error)
{
fp_warn ("bad status %s, terminating session", error->message);
@@ -544,7 +551,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
* the first 2 bytes are a sequence number
* then there are 62 bytes for image data
*/
for (i = 0; i + 64 <= transfer->actual_length; i += 64)
for (i = 0; i < 4096; i += 64)
{
if (!is_capturing (self))
return;
@@ -553,7 +560,7 @@ img_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (is_capturing (self))
{
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
fpi_usb_transfer_submit (transfer,
0,
self->img_cancellable,
img_data_cb,
@@ -581,8 +588,6 @@ write_regs_finished (struct write_regs_data *wrdata, GError *error)
fpi_ssm_next_state (wrdata->ssm);
else
fpi_ssm_mark_failed (wrdata->ssm, error);
g_free (wrdata);
}
static void write_regs_iterate (struct write_regs_data *wrdata);
@@ -629,9 +634,9 @@ write_regs_iterate (struct write_regs_data *wrdata)
1);
transfer->short_is_error = TRUE;
transfer->ssm = wrdata->ssm;
transfer->buffer[0] = regwrite->value;
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL);
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, wrdata);
transfer->buffer[0] = regwrite->value;
}
static void
@@ -670,10 +675,10 @@ sm_write_reg (FpiSsm *ssm,
1);
transfer->short_is_error = TRUE;
transfer->ssm = ssm;
transfer->buffer[0] = value;
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
fpi_ssm_usb_transfer_cb, NULL);
transfer->buffer[0] = value;
}
static void
@@ -903,7 +908,7 @@ capsm_fire_bulk (FpiSsm *ssm,
self->img_cancellable = g_cancellable_new ();
for (i = 0; i < self->img_transfers->len; i++)
{
fpi_usb_transfer_submit (fpi_usb_transfer_ref (g_ptr_array_index (self->img_transfers, i)),
fpi_usb_transfer_submit (g_ptr_array_index (self->img_transfers, i),
0,
self->img_cancellable,
img_data_cb,
@@ -1401,12 +1406,8 @@ dev_activate (FpImageDevice *dev)
self->capturing = FALSE;
self->num_flying = 0;
self->img_transfers = g_ptr_array_new_with_free_func ((GFreeFunc) fpi_usb_transfer_unref);
/* This might seem odd, but we do need multiple in-flight URBs so that
* we never stop polling the device for more data.
*/
for (i = 0; i < NUM_BULK_TRANSFERS; i++)
for (i = 0; i < self->img_transfers->len; i++)
{
FpiUsbTransfer *transfer;

View File

@@ -171,7 +171,7 @@ finger_present (unsigned char *img, size_t len, int sum_threshold)
if (img[i] < 160)
sum++;
fp_dbg ("finger_present: sum is %d", sum);
fp_dbg ("finger_present: sum is %d\n", sum);
return sum < sum_threshold ? 0 : 1;
}
@@ -184,7 +184,7 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
{
fp_dbg ("data transfer status %s", error->message);
fp_dbg ("data transfer status %s\n", error->message);
fpi_image_device_session_error (dev, error);
return;
}
@@ -212,7 +212,7 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
if (error)
{
fp_dbg ("req transfer status %s", error->message);
fp_dbg ("req transfer status %s\n", error->message);
fpi_image_device_session_error (dev, error);
return;
}
@@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
break;
default:
fp_err ("Device variant %lu is not known", driver_data);
fp_err ("Device variant %lu is not known\n", driver_data);
g_assert_not_reached ();
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;

View File

@@ -19,7 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __UPEKTC_H
#define __UPEKTC_H
#define UPEKTC_CMD_LEN 0x40
#define IMAGE_WIDTH 208
@@ -1935,3 +1936,5 @@ static const unsigned char scan_cmd[0x40] = {
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
};
#endif

View File

@@ -193,7 +193,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (self->deactivating)
{
fp_dbg ("Deactivate requested");
fp_dbg ("Deactivate requested\n");
fpi_ssm_mark_completed (transfer->ssm);
return;
}
@@ -208,7 +208,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
{
fp_dbg ("Terminating SSM");
fp_dbg ("Terminating SSM\n");
fpi_ssm_mark_completed (transfer->ssm);
return;
}
@@ -219,7 +219,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
response_size += 9; /* 7 bytes for header, 2 for CRC */
if (response_size > transfer->actual_length)
{
fp_dbg ("response_size is %lu, actual_length is %d",
fp_dbg ("response_size is %lu, actual_length is %d\n",
response_size, (gint) transfer->actual_length);
fp_dbg ("Waiting for rest of transfer");
BUG_ON (self->response_rest);
@@ -237,7 +237,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
{
/* No finger */
case 0x28:
fp_dbg ("18th byte is %.2x", data[18]);
fp_dbg ("18th byte is %.2x\n", data[18]);
switch (data[18])
{
case 0x0c:
@@ -254,7 +254,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x1e:
/* short scan */
fp_err ("short scan, aborting");
fp_err ("short scan, aborting\n");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY_TOO_SHORT);
fpi_image_device_report_finger_status (dev,
@@ -265,7 +265,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x1d:
/* too much horisontal movement */
fp_err ("too much horisontal movement, aborting");
fp_err ("too much horisontal movement, aborting\n");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY_CENTER_FINGER);
fpi_image_device_report_finger_status (dev,
@@ -276,7 +276,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
default:
/* some error happened, cancel scan */
fp_err ("something bad happened, stop scan");
fp_err ("something bad happened, stop scan\n");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY);
fpi_image_device_report_finger_status (dev,
@@ -307,10 +307,9 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
upektc_img_process_image_frame (self->image_bits + self->image_size,
data);
BUG_ON (self->image_size != IMAGE_SIZE);
fp_dbg ("Image size is %lu",
fp_dbg ("Image size is %lu\n",
self->image_size);
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
img->flags |= FPI_IMAGE_PARTIAL;
memcpy (img->data, self->image_bits,
IMAGE_SIZE);
fpi_image_device_image_captured (dev, img);
@@ -320,7 +319,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_err ("Unknown response!");
fp_err ("Unknown response!\n");
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
break;
}
@@ -331,7 +330,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_err ("Not handled response!");
fp_err ("Not handled response!\n");
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
}

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __UPEKTC_IMG_H
#define __UPEKTC_IMG_H
static const unsigned char upek2020_init_1[] = {
'C', 'i', 'a', 'o',
@@ -139,3 +140,5 @@ static const unsigned char upek2020_ack_frame[] = {
0x30,
0xac, 0x5b /* CRC */
};
#endif

View File

@@ -35,6 +35,7 @@
#define TIMEOUT 5000
#define MSG_READ_BUF_SIZE 0x40
#define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9)
struct _FpiDeviceUpekts
{
@@ -235,18 +236,12 @@ __handle_incoming_msg (FpDevice *device,
{
GError *error = NULL;
guint8 *buf = udata->buffer;
guint16 len;
guint16 computed_crc;
guint16 msg_crc;
guint16 len = ((buf[5] & 0xf) << 8) | buf[6];
guint16 computed_crc = udf_crc (buf + 4, len + 3);
guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7];
unsigned char *retdata = NULL;
unsigned char code_a, code_b;
g_assert (udata->buflen >= 6);
len = ((buf[5] & 0xf) << 8) | buf[6];
g_assert (udata->buflen >= len + 9);
computed_crc = udf_crc (buf + 4, len + 3);
msg_crc = (buf[len + 8] << 8) | buf[len + 7];
if (computed_crc != msg_crc)
{
fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc);
@@ -272,7 +267,12 @@ __handle_incoming_msg (FpDevice *device,
return;
}
udata->callback (device, READ_MSG_CMD, code_a, 0, buf + 7, len,
if (len > 0)
{
retdata = g_malloc (len);
memcpy (retdata, buf + 7, len);
}
udata->callback (device, READ_MSG_CMD, code_a, 0, retdata, len,
udata->user_data, NULL);
goto done;
}
@@ -309,8 +309,14 @@ __handle_incoming_msg (FpDevice *device,
innerlen = innerlen - 3;
_subcmd = innerbuf[5];
fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen);
if (innerlen > 0)
{
retdata = g_malloc (innerlen);
memcpy (retdata, innerbuf + 6, innerlen);
}
udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd,
innerbuf + 6, innerlen, udata->user_data, NULL);
retdata, innerlen, udata->user_data, NULL);
g_free (retdata);
goto done;
}
else
@@ -352,8 +358,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
struct read_msg_data *udata = user_data;
guint16 payload_len;
gsize packet_len;
guint16 len;
if (error)
{
@@ -370,7 +375,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
goto err;
}
if (strncmp ((char *) udata->buffer, "Ciao", 4) != 0)
if (strncmp (udata->buffer, "Ciao", 4) != 0)
{
fp_err ("no Ciao for you!!");
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -378,15 +383,14 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
goto err;
}
payload_len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
packet_len = payload_len + 9;
len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6];
if (transfer->actual_length != MSG_READ_BUF_SIZE &&
packet_len > transfer->actual_length)
(len + 9) > transfer->actual_length)
{
/* Check that the length claimed inside the message is in line with
* the amount of data that was transferred over USB. */
fp_err ("msg didn't include enough data, expected=%d recv=%d",
(gint) packet_len, (gint) transfer->actual_length);
len + 9, (gint) transfer->actual_length);
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Packet from device didn't include data");
goto err;
@@ -395,14 +399,14 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device,
/* We use a 64 byte buffer for reading messages. However, sometimes
* messages are longer, in which case we have to do another USB bulk read
* to read the remainder. This is handled below. */
if (packet_len > MSG_READ_BUF_SIZE)
if (len > MAX_DATA_IN_READ_BUF)
{
int needed = packet_len - MSG_READ_BUF_SIZE;
int needed = len - MAX_DATA_IN_READ_BUF;
FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device);
fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed);
udata->buffer = g_realloc ((gpointer) udata->buffer, packet_len);
udata->buflen = packet_len;
udata->buffer = g_realloc ((gpointer) udata->buffer, len);
udata->buflen = len;
fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN,
udata->buffer + MSG_READ_BUF_SIZE,
@@ -696,7 +700,7 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case SEND_RESP03:;
transfer = alloc_send_cmdresponse_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
transfer = alloc_send_cmd28_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03));
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL);
@@ -853,15 +857,22 @@ dev_init (FpDevice *dev)
}
static void
dev_exit (FpDevice *dev)
deinitsm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
{
GError *error = NULL;
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, &error);
g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL);
fpi_device_close_complete (dev, error);
}
static void
dev_exit (FpDevice *dev)
{
FpiSsm *ssm;
ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
fpi_ssm_start (ssm, deinitsm_done);
}
static const unsigned char enroll_init[] = {
0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08
};
@@ -891,10 +902,8 @@ enroll_start_sm_cb_msg28 (FpDevice *dev,
FpiSsm *ssm = user_data;
if (error)
{
fpi_ssm_mark_failed (ssm, error);
}
else if (type != READ_MSG_RESPONSE)
fpi_ssm_mark_failed (ssm, error);
if (type != READ_MSG_RESPONSE)
{
fp_err ("expected response, got %d seq=%x", type, seq);
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -972,9 +981,7 @@ enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
fp_warn ("Error deinitializing: %s", error->message);
fpi_device_enroll_complete (dev,
g_steal_pointer (&data->print),
g_steal_pointer (&data->error));
fpi_device_enroll_complete (dev, data->print, data->error);
}
static void
@@ -983,7 +990,7 @@ do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error)
EnrollStopData *data = g_new0 (EnrollStopData, 1);
FpiSsm *ssm = deinitsm_new (dev, data);
data->print = print;
data->print = g_object_ref (print);
data->error = error;
fpi_ssm_start (ssm, enroll_stop_deinit_cb);
@@ -1110,6 +1117,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
else
{
GVariant *fp_data;
print = fp_print_new (dev);
fpi_device_get_enroll_data (dev, &print);
@@ -1118,8 +1126,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data,
data_len - sizeof (scan_comp),
1);
fpi_print_set_type (print, FPI_PRINT_RAW);
g_object_set (print, "fpi-data", fp_data, NULL);
g_object_set (print, "fp-data", fp_data, NULL);
g_object_ref (print);
}
@@ -1218,7 +1225,8 @@ enroll (FpDevice *dev)
typedef struct
{
GError *error;
FpiMatchResult res;
GError *error;
} VerifyStopData;
static void
@@ -1236,12 +1244,7 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
fp_warn ("Error deinitializing: %s", error->message);
if (data->error)
fpi_device_verify_complete (dev, g_steal_pointer (&data->error));
else
fpi_device_verify_complete (dev, g_steal_pointer (&error));
g_clear_error (&error);
fpi_device_verify_complete (dev, data->res, NULL, data->error);
}
static void
@@ -1250,11 +1253,8 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
VerifyStopData *data = g_new0 (VerifyStopData, 1);
FpiSsm *ssm = deinitsm_new (dev, data);
/* Report the error immediately if possible, otherwise delay it. */
if (error && error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (dev, res, NULL, error);
else
data->error = error;
data->res = res;
data->error = error;
fpi_ssm_start (ssm, verify_stop_deinit_cb);
fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free);
@@ -1293,7 +1293,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev)
case VERIFY_INIT:
fpi_device_get_verify_data (dev, &print);
g_object_get (print, "fpi-data", &fp_data, NULL);
g_object_get (dev, "fp-data", &fp_data, NULL);
data = g_variant_get_fixed_array (fp_data, &data_len, 1);

View File

@@ -81,7 +81,7 @@ static const struct uru4k_dev_profile
{
const char *name;
gboolean auth_cr;
gboolean image_not_flipped;
gboolean encryption;
} uru4k_dev_info[] = {
[MS_KBD] = {
.name = "Microsoft Keyboard with Fingerprint Reader",
@@ -106,7 +106,7 @@ static const struct uru4k_dev_profile
[DP_URU4000B] = {
.name = "Digital Persona U.are.U 4000B",
.auth_cr = FALSE,
.image_not_flipped = TRUE, /* See comment in the code where it is used. */
.encryption = TRUE,
},
};
@@ -122,7 +122,7 @@ struct _FpiDeviceUru4000
const struct uru4k_dev_profile *profile;
uint8_t interface;
FpiImageDeviceState activate_state;
FpImageDeviceState activate_state;
unsigned char last_reg_rd[16];
unsigned char last_hwstat;
@@ -332,8 +332,6 @@ irq_handler (FpiUsbTransfer *transfer,
return;
}
start_irq_handler (imgdev);
type = GUINT16_FROM_BE (*((uint16_t *) data));
fp_dbg ("recv irq type %04x", type);
@@ -346,6 +344,8 @@ irq_handler (FpiUsbTransfer *transfer,
urudev->irq_cb (imgdev, NULL, type, urudev->irq_cb_data);
else
fp_dbg ("ignoring interrupt");
start_irq_handler (imgdev);
}
static void
@@ -408,16 +408,16 @@ change_state_write_reg_cb (FpiUsbTransfer *transfer,
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
dev_change_state (FpImageDevice *dev, FpImageDeviceState state)
{
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
case FP_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FP_IMAGE_DEVICE_STATE_CAPTURE:
break;
default:
@@ -680,17 +680,17 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
return;
}
/* Detect whether image is encrypted (by checking how noisy it is) */
dev2 = calc_dev2 (img);
fp_dbg ("dev2: %d", dev2);
if (dev2 < ENC_THRESHOLD)
if (!self->profile->encryption)
{
fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE);
return;
dev2 = calc_dev2 (img);
fp_dbg ("dev2: %d", dev2);
if (dev2 < ENC_THRESHOLD)
{
fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE);
return;
}
fp_info ("image seems to be encrypted");
}
fp_info ("image seems to be encrypted");
buf[0] = img->key_number;
buf[1] = self->img_enc_seed;
buf[2] = self->img_enc_seed >> 8;
@@ -723,7 +723,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
num_lines);
if (flags & BLOCKF_CHANGE_KEY)
{
fp_dbg ("changing encryption keys.");
fp_dbg ("changing encryption keys.\n");
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
img->key_number++;
self->img_enc_seed = rand ();
@@ -769,17 +769,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
}
fpimg->flags = FPI_IMAGE_COLORS_INVERTED;
/* NOTE: For some reason all but U4000B (or rather U4500?) flipped the
* image, we retain this behaviour here, but it is not clear whether it
* is correct.
* It may be that there are different models with the same USB ID that
* behave differently.
*/
if (self->profile->image_not_flipped)
if (!self->profile->encryption)
fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
fpi_image_device_image_captured (dev, fpimg);
if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE)
if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE)
fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE);
else
fpi_ssm_mark_completed (ssm);
@@ -1182,7 +1176,7 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
static void
dev_deactivate (FpImageDevice *dev)
{
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE);
}
static void
@@ -1193,7 +1187,7 @@ execute_state_change (FpImageDevice *dev)
switch (self->activate_state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FP_IMAGE_DEVICE_STATE_INACTIVE:
fp_dbg ("deactivating");
self->irq_cb = NULL;
self->irq_cb_data = NULL;
@@ -1201,7 +1195,7 @@ execute_state_change (FpImageDevice *dev)
deactivate_write_reg_cb, NULL);
break;
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
fp_dbg ("wait finger on");
if (!IRQ_HANDLER_IS_RUNNING (self))
{
@@ -1215,7 +1209,7 @@ execute_state_change (FpImageDevice *dev)
change_state_write_reg_cb, NULL);
break;
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
case FP_IMAGE_DEVICE_STATE_CAPTURE:
fp_dbg ("starting capture");
self->irq_cb = NULL;
@@ -1235,7 +1229,7 @@ execute_state_change (FpImageDevice *dev)
change_state_write_reg_cb, NULL);
break;
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
fp_dbg ("await finger off");
if (!IRQ_HANDLER_IS_RUNNING (self))
{

View File

@@ -117,10 +117,9 @@ async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
int ep = transfer->endpoint;
/* In normal case endpoint is empty */
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
(g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
{
g_clear_error (&error);
g_free (error);
fpi_ssm_next_state (transfer->ssm);
return;
}
@@ -157,8 +156,6 @@ async_abort (FpDevice *dev, FpiSsm *ssm, int ep)
else
fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
async_abort_callback, NULL);
}
@@ -243,7 +240,6 @@ prepare_image (FpDeviceVfs0050 *vdev)
/* Building GSList */
GSList *lines = NULL;
for (int i = height - 1; i >= 0; --i)
lines = g_slist_prepend (lines, vdev->lines_buffer + i);
@@ -403,7 +399,7 @@ interrupt_callback (FpiUsbTransfer *transfer, FpDevice *device,
gpointer user_data, GError *error)
{
FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device);
unsigned char *interrupt = transfer->buffer;
char *interrupt = transfer->buffer;
/* we expect a cancellation error when the device is deactivating
* go into the SSM_CLEAR_EP2 state in that case. */
@@ -468,8 +464,8 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
g_error_free (error);
/* Capture is done when there is no more data to transfer or device timed out */
if (transfer->actual_length <= 0)
/* Check if fingerprint data is over */
if (transfer->actual_length == 0)
{
fpi_ssm_next_state (transfer->ssm);
}
@@ -477,7 +473,7 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
{
self->bytes += transfer->actual_length;
/* Try reading more data */
/* We need more data */
fpi_ssm_jump_to_state (transfer->ssm,
fpi_ssm_get_cur_state (transfer->ssm));
}
@@ -599,7 +595,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
/* Receive chunk of data */
transfer = fpi_usb_transfer_new (dev);
fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
(guint8 *) self->lines_buffer + self->bytes,
(void *) self->lines_buffer + self->bytes,
VFS_USB_BUFFER_SIZE, NULL);
transfer->ssm = ssm;
fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
@@ -671,7 +667,6 @@ dev_activate (FpImageDevice *idev)
self->ssm_active = 1;
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
fpi_ssm_start (ssm, dev_activate_callback);
}
@@ -715,7 +710,6 @@ dev_open (FpImageDevice *idev)
/* Clearing previous device state */
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
fpi_ssm_start (ssm, dev_open_callback);
}

View File

@@ -177,7 +177,6 @@ translate_str (const char **srcL, gssize *len)
src_len += tmp;
}
g_assert (src_len >= 2);
*len = src_len / 2;
res = g_malloc0 (*len);
dst = res;
@@ -438,7 +437,7 @@ img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int l
usb_send (dev, data, len, NULL); \
}
#define RAW_DATA(x) g_memdup (x, sizeof (x)), sizeof (x)
#define RAW_DATA(x) x, sizeof (x)
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))

View File

@@ -190,13 +190,11 @@ usbexchange_loop (FpiSsm *ssm, FpDevice *_dev)
static void
usb_exchange_async (FpiSsm *ssm,
struct usbexchange_data *data,
const char *exchange_name)
struct usbexchange_data *data)
{
FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
usbexchange_loop,
data->stepcount,
exchange_name);
FpiSsm *subsm = fpi_ssm_new (FP_DEVICE (data->device),
usbexchange_loop,
data->stepcount);
fpi_ssm_set_data (subsm, data, NULL);
fpi_ssm_start_subsm (ssm, subsm);
@@ -212,8 +210,8 @@ vfs5011_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *ro
int res = 0, mean = 0, i;
const int size = 64;
buf1 = (unsigned char *) row1->data + 56;
buf2 = (unsigned char *) row2->data + 168;
buf1 = row1->data + 56;
buf2 = row2->data + 168;
for (i = 0; i < size; i++)
mean += (int) buf1[i] + (int) buf2[i];
@@ -234,7 +232,7 @@ vfs5011_get_pixel (struct fpi_line_asmbl_ctx *ctx,
GSList *row,
unsigned x)
{
unsigned char *data = (unsigned char *) row->data + 8;
unsigned char *data = row->data + 8;
return data[x];
}
@@ -381,8 +379,9 @@ submit_image (FpiSsm *ssm,
{
FpImage *img;
if (self->lines_recorded < VFS5011_IMAGE_WIDTH)
if (self->lines_recorded == 0)
{
/* == FP_ENROLL_RETRY_TOO_SHORT */
fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
return;
}
@@ -685,7 +684,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = 1000;
usb_exchange_async (ssm, &self->init_sequence, "ACTIVATE REQUEST");
usb_exchange_async (ssm, &self->init_sequence);
break;
case DEV_ACTIVATE_INIT_COMPLETE:
@@ -717,7 +716,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
usb_exchange_async (ssm, &self->init_sequence, "PREPARE CAPTURE");
usb_exchange_async (ssm, &self->init_sequence);
break;
}
@@ -770,7 +769,7 @@ open_loop (FpiSsm *ssm, FpDevice *_dev)
self->init_sequence.receive_buf =
g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
usb_exchange_async (ssm, &self->init_sequence, "DEVICE OPEN");
usb_exchange_async (ssm, &self->init_sequence);
break;
}
;

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef __VFS5011_PROTO_H
#define __VFS5011_PROTO_H
#define VFS5011_LINE_SIZE 240
#define VFS5011_IMAGE_WIDTH 160
@@ -6181,3 +6182,5 @@ static unsigned char vfs5011_prepare_04[] = { /* 2903 B */
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
};
#endif

View File

@@ -21,7 +21,7 @@
/*
* This is a virtual driver to debug the image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to be sent to this device programmatically.
* prints to be sent to this device programatically.
* Using this it is possible to test libfprint and fprintd.
*/
@@ -47,7 +47,6 @@ struct _FpDeviceVirtualImage
gint socket_fd;
gint client_fd;
gboolean automatic_finger;
FpImage *recv_img;
gint recv_img_hdr[2];
};
@@ -76,9 +75,9 @@ recv_image_img_recv_cb (GObject *source_object,
{
if (!success)
{
g_warning ("Error receiving header for image data: %s", error->message);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
@@ -90,11 +89,9 @@ recv_image_img_recv_cb (GObject *source_object,
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self);
if (self->automatic_finger)
fpi_image_device_report_finger_status (device, TRUE);
fpi_image_device_report_finger_status (device, TRUE);
fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img));
if (self->automatic_finger)
fpi_image_device_report_finger_status (device, FALSE);
fpi_image_device_report_finger_status (device, FALSE);
/* And, listen for more images from the same client. */
recv_image (self, G_INPUT_STREAM (source_object));
@@ -116,10 +113,9 @@ recv_image_hdr_recv_cb (GObject *source_object,
{
if (!success)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ||
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
@@ -151,17 +147,6 @@ recv_image_hdr_recv_cb (GObject *source_object,
fpi_device_error_new (self->recv_img_hdr[1]));
break;
case -3:
/* -3 sets/clears automatic finger detection for images */
self->automatic_finger = !!self->recv_img_hdr[1];
break;
case -4:
/* -4 submits a finger detection report */
fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self),
!!self->recv_img_hdr[1]);
break;
default:
/* disconnect client, it didn't play fair */
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
@@ -228,7 +213,6 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
}
dev->connection = connection;
dev->automatic_finger = TRUE;
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
recv_image (dev, stream);
@@ -252,7 +236,6 @@ dev_init (FpImageDevice *dev)
g_autoptr(GSocketListener) listener = NULL;
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
const char *env;
g_autoptr(GSocketAddress) addr = NULL;
G_DEBUG_HERE ();
@@ -288,8 +271,7 @@ dev_init (FpImageDevice *dev)
start_listen (self);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
fpi_image_device_open_complete (dev, NULL);
}
static void
@@ -304,17 +286,7 @@ dev_deinit (FpImageDevice *dev)
g_clear_object (&self->listener);
g_clear_object (&self->connection);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL);
}
static void
dev_deactivate (FpImageDevice *dev)
{
G_DEBUG_HERE ();
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_deactivate_complete, NULL, NULL);
fpi_image_device_close_complete (dev, NULL);
}
static void
@@ -340,6 +312,4 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->deactivate = dev_deactivate;
}

View File

@@ -2,7 +2,6 @@
* Driver API definitions
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2018 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,14 +18,17 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __DRIVERS_API_H__
#define __DRIVERS_API_H__
#include <config.h>
#include "fp_internal.h"
#include "fpi-compat.h"
#include "fpi-assembling.h"
#include "fpi-device.h"
#include "fpi-image-device.h"
#include "fpi-image.h"
#include "fpi-log.h"
#include "fpi-print.h"
#include "fpi-usb-transfer.h"
#include "fpi-ssm.h"
#include "fpi-assembling.h"
#include "fpi-image-device.h"
#endif

View File

@@ -57,35 +57,6 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0 };
static const char *
get_drivers_whitelist_env (void)
{
return g_getenv ("FP_DRIVERS_WHITELIST");
}
static gboolean
is_driver_allowed (const gchar *driver)
{
g_auto(GStrv) whitelisted_drivers = NULL;
const char *fp_drivers_whitelist_env;
int i;
g_return_val_if_fail (driver, TRUE);
fp_drivers_whitelist_env = get_drivers_whitelist_env ();
if (!fp_drivers_whitelist_env)
return TRUE;
whitelisted_drivers = g_strsplit (fp_drivers_whitelist_env, ":", -1);
for (i = 0; whitelisted_drivers[i]; ++i)
if (g_strcmp0 (driver, whitelisted_drivers[i]) == 0)
return TRUE;
return FALSE;
}
static void
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
@@ -94,21 +65,22 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
FpContext *context;
FpContextPrivate *priv;
device = FP_DEVICE (g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
res, &error));
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
context = FP_CONTEXT (user_data);
priv = fp_context_get_instance_private (context);
priv->pending_devices--;
if (error)
device = (FpDevice *) g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error);
if (!device)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
context = FP_CONTEXT (user_data);
priv = fp_context_get_instance_private (context);
priv->pending_devices--;
g_message ("Ignoring device due to initialization error: %s", error->message);
return;
}
context = FP_CONTEXT (user_data);
priv = fp_context_get_instance_private (context);
priv->pending_devices--;
g_ptr_array_add (priv->devices, device);
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
}
@@ -130,11 +102,14 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB)
continue;
{
g_type_class_unref (cls);
continue;
}
for (entry = cls->id_table; entry->pid; entry++)
{
@@ -154,11 +129,13 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
found_driver = driver;
found_entry = entry;
}
g_type_class_unref (cls);
}
if (found_driver == G_TYPE_NONE)
{
g_debug ("No driver found for USB device %04X:%04X", vid, pid);
g_debug ("No driver found for USB device %04X:%04X", pid, vid);
return;
}
@@ -168,8 +145,8 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
priv->cancellable,
async_device_init_done_cb,
self,
"fpi-usb-device", device,
"fpi-driver-data", found_entry->driver_data,
"fp-usb-device", device,
"fp-driver-data", found_entry->driver_data,
NULL);
}
@@ -210,8 +187,7 @@ fp_context_finalize (GObject *object)
g_clear_object (&priv->cancellable);
g_clear_pointer (&priv->drivers, g_array_unref);
if (priv->usb_ctx)
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
g_object_run_dispose (G_OBJECT (priv->usb_ctx));
g_clear_object (&priv->usb_ctx);
G_OBJECT_CLASS (fp_context_parent_class)->finalize (object);
@@ -266,23 +242,9 @@ fp_context_init (FpContext *self)
{
g_autoptr(GError) error = NULL;
FpContextPrivate *priv = fp_context_get_instance_private (self);
guint i;
priv->drivers = fpi_get_driver_types ();
if (get_drivers_whitelist_env ())
{
for (i = 0; i < priv->drivers->len;)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
if (!is_driver_allowed (cls->id))
g_array_remove_index (priv->drivers, i);
else
++i;
}
}
priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType));
fpi_get_driver_types (priv->drivers);
priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
@@ -290,7 +252,7 @@ fp_context_init (FpContext *self)
priv->usb_ctx = g_usb_context_new (&error);
if (!priv->usb_ctx)
{
g_message ("Could not initialise USB Subsystem: %s", error->message);
fp_warn ("Could not initialise USB Subsystem: %s", error->message);
}
else
{
@@ -343,14 +305,13 @@ fp_context_enumerate (FpContext *context)
priv->enumerated = TRUE;
/* USB devices are handled from callbacks */
if (priv->usb_ctx)
g_usb_context_enumerate (priv->usb_ctx);
g_usb_context_enumerate (priv->usb_ctx);
/* Handle Virtual devices based on environment variables */
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
@@ -371,11 +332,13 @@ fp_context_enumerate (FpContext *context)
priv->cancellable,
async_device_init_done_cb,
context,
"fpi-environ", val,
"fpi-driver-data", entry->driver_data,
"fp-environ", val,
"fp-driver-data", entry->driver_data,
NULL);
g_debug ("created");
}
g_type_class_unref (cls);
}
while (priv->pending_devices)

View File

@@ -1,82 +0,0 @@
/*
* FpDevice - A fingerprint reader device
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
*
* 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
*/
#pragma once
#include "fpi-device.h"
typedef struct
{
FpDeviceType type;
GUsbDevice *usb_device;
const gchar *virtual_env;
gboolean is_open;
gchar *device_id;
gchar *device_name;
FpScanType scan_type;
guint64 driver_data;
gint nr_enroll_stages;
GSList *sources;
/* We always make sure that only one task is run at a time. */
FpiDeviceAction current_action;
GTask *current_task;
GAsyncReadyCallback current_user_cb;
gulong current_cancellable_id;
GSource *current_idle_cancel_source;
GSource *current_task_idle_return_source;
/* State for tasks */
gboolean wait_for_finger;
} FpDevicePrivate;
typedef struct
{
FpPrint *print;
FpEnrollProgress enroll_progress_cb;
gpointer enroll_progress_data;
GDestroyNotify enroll_progress_destroy;
} FpEnrollData;
void enroll_data_free (FpEnrollData *enroll_data);
typedef struct
{
FpPrint *enrolled_print; /* verify */
GPtrArray *gallery; /* identify */
gboolean result_reported;
FpPrint *match;
FpPrint *print;
GError *error;
FpMatchCb match_cb;
gpointer match_data;
GDestroyNotify match_destroy;
} FpMatchData;
void match_data_free (FpMatchData *match_data);

File diff suppressed because it is too large Load Diff

View File

@@ -79,7 +79,7 @@ typedef enum {
/**
* FpDeviceError:
* @FP_DEVICE_ERROR_GENERAL: A general error occurred.
* @FP_DEVICE_ERROR_GENERAL: A general error occured.
* @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested
* operation.
* @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this
@@ -90,7 +90,6 @@ typedef enum {
* @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
*
* Error codes for device operations. More specific errors from other domains
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
@@ -105,7 +104,6 @@ typedef enum {
FP_DEVICE_ERROR_DATA_INVALID,
FP_DEVICE_ERROR_DATA_NOT_FOUND,
FP_DEVICE_ERROR_DATA_FULL,
FP_DEVICE_ERROR_DATA_DUPLICATE,
} FpDeviceError;
GQuark fp_device_retry_quark (void);
@@ -115,7 +113,7 @@ GQuark fp_device_error_quark (void);
* FpEnrollProgress:
* @device: a #FpDevice
* @completed_stages: Number of completed stages
* @print: (nullable) (transfer none): The last scanned print
* @print: (nullable) (transfer none): The last scaned print
* @user_data: (nullable) (transfer none): User provided data
* @error: (nullable) (transfer none): #GError or %NULL
*
@@ -127,48 +125,10 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
gpointer user_data,
GError *error);
/**
* FpMatchCb:
* @device: a #FpDevice
* @match: (nullable) (transfer none): The matching print if any matched @print
* @print: (nullable) (transfer none): The newly scanned print
* @user_data: (nullable) (transfer none): User provided data
* @error: (nullable) (transfer none): #GError or %NULL
*
* Report the result of a match (identify or verify) operation.
*
* If @match is non-%NULL, then it is set to the matching #FpPrint as passed
* to the match operation. In this case @error will always be %NULL.
*
* If @error is not %NULL then its domain is guaranteed to be
* %FP_DEVICE_RETRY. All other error conditions will not be reported using
* this callback. If such an error occurs before a match/no-match decision
* can be made, then this callback will not be called. Should an error
* happen afterwards, then you will get a match report through this callback
* and an error when the operation finishes.
*
* If @match and @error are %NULL, then a finger was presented but it did not
* match any known print.
*
* @print represents the newly scanned print. The driver may or may not
* provide this information. Image based devices will provide it and it
* allows access to the raw data.
*
* This callback exists because it makes sense for drivers to wait e.g. on
* finger removal before completing the match operation. However, the
* success/failure can often be reported at an earlier time, and there is
* no need to make the user wait.
*/
typedef void (*FpMatchCb) (FpDevice *device,
FpPrint *match,
FpPrint *print,
gpointer user_data,
GError *error);
const gchar *fp_device_get_driver (FpDevice *device);
const gchar *fp_device_get_device_id (FpDevice *device);
const gchar *fp_device_get_name (FpDevice *device);
gboolean fp_device_is_open (FpDevice *device);
FpScanType fp_device_get_scan_type (FpDevice *device);
gint fp_device_get_nr_enroll_stages (FpDevice *device);
@@ -199,18 +159,12 @@ void fp_device_enroll (FpDevice *device,
void fp_device_verify (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_identify (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
@@ -276,16 +230,12 @@ FpPrint * fp_device_enroll_sync (FpDevice *device,
gboolean fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match,
FpPrint **print,
GError **error);
gboolean fp_device_identify_sync (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match,
FpPrint **print,
GError **error);

View File

@@ -1,43 +0,0 @@
/*
* FpImageDevice - An image based fingerprint reader device
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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
*/
#pragma once
#include "fpi-image-device.h"
#define IMG_ENROLL_STAGES 5
typedef struct
{
FpiImageDeviceState state;
gboolean active;
gboolean cancelling;
gboolean enroll_await_on_pending;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gint bz3_threshold;
} FpImageDevicePrivate;
void fpi_image_device_activate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device);

View File

@@ -20,9 +20,14 @@
#define FP_COMPONENT "image_device"
#include "fpi-log.h"
#include "fp-image-device-private.h"
#include "fpi-image-device.h"
#include "fpi-enums.h"
#include "fpi-print.h"
#include "fpi-image.h"
#define MIN_ACCEPTABLE_MINUTIAE 10
#define BOZORTH3_DEFAULT_THRESHOLD 40
#define IMG_ENROLL_STAGES 5
/**
* SECTION: fp-image-device
@@ -32,6 +37,28 @@
* This is a helper class for the commonly found image based devices.
*/
/**
* SECTION: fpi-image-device
* @title: Internal FpImageDevice
* @short_description: Internal image device routines
*
* See #FpImageDeviceClass for more details. Also see the public
* #FpImageDevice routines.
*/
typedef struct
{
FpImageDeviceState state;
gboolean active;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gint bz3_threshold;
} FpImageDevicePrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
enum {
@@ -58,38 +85,82 @@ static guint signals[LAST_SIGNAL] = { 0 };
/* Static helper functions */
static void
fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
/* Cannot change to inactive using this function. */
g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE);
/* We might have been waiting for the finger to go OFF to start the
* next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state);
priv->state = state;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->state);
}
static void
fp_image_device_activate (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
g_assert (!priv->active);
/* We don't have a neutral ACTIVE state, but we always will
* go into WAIT_FINGER_ON afterwards. */
priv->state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
/* We might have been waiting for deactivation to finish before
* starting the next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Activating image device\n");
cls->activate (self);
}
static void
fp_image_device_deactivate (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
if (!priv->active)
{
/* XXX: We currently deactivate both from minutiae scan result
* and finger off report. */
fp_dbg ("Already deactivated, ignoring request.");
return;
}
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fp_dbg ("Deactivating image device\n");
cls->deactivate (self);
}
static gboolean
pending_activation_timeout (gpointer user_data)
{
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action = fpi_device_get_current_action (device);
GError *error;
priv->pending_activation_timeout_id = 0;
if (priv->pending_activation_timeout_waiting_finger_off)
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
"Remove finger before requesting another scan operation");
fpi_device_action_error (FP_DEVICE (self),
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
"Remove finger before requesting another scan operation"));
else
error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (device, NULL, NULL, error);
fpi_device_identify_complete (device, NULL);
}
else
{
/* Can this happen for enroll? */
fpi_device_action_error (device, error);
}
fpi_device_action_error (FP_DEVICE (self),
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
return G_SOURCE_REMOVE;
}
@@ -117,35 +188,32 @@ fp_image_device_close (FpDevice *device)
* 1. We are inactive
* -> immediately close
* 2. We are waiting for finger off
* -> immediately deactivate
* -> imediately deactivate
* 3. We are deactivating
* -> handled by deactivate_complete */
if (!priv->active)
cls->img_close (self);
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
fpi_image_device_deactivate (self);
else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE)
fp_image_device_deactivate (device);
}
static void
fp_image_device_cancel_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
FpDeviceAction action;
action = fpi_device_get_current_action (device);
/* We can only cancel capture operations, in that case, deactivate and return
* an error immediately. */
if (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE)
if (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE)
{
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fp_image_device_deactivate (FP_DEVICE (self));
/* XXX: Some nicer way of doing this would be good. */
fpi_device_action_error (FP_DEVICE (self),
@@ -160,14 +228,14 @@ fp_image_device_start_capture_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
FpDeviceAction action;
/* There is just one action that we cannot support out
* of the box, which is a capture without first waiting
* for a finger to be on the device.
*/
action = fpi_device_get_current_action (device);
if (action == FPI_DEVICE_ACTION_CAPTURE)
if (action == FP_DEVICE_ACTION_CAPTURE)
{
gboolean wait_for_finger;
@@ -179,30 +247,29 @@ fp_image_device_start_capture_action (FpDevice *device)
return;
}
}
else if (action == FPI_DEVICE_ACTION_ENROLL)
else if (action == FP_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print = NULL;
fpi_device_get_enroll_data (device, &enroll_print);
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
fpi_print_set_type (enroll_print, FP_PRINT_NBIS);
}
priv->enroll_stage = 0;
priv->enroll_await_on_pending = FALSE;
/* The device might still be deactivating from a previous call.
* In that situation, try to wait for a bit before reporting back an
* error (which will usually say that the user should remove the
* finger).
*/
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
{
g_debug ("Got a new request while the device was still active");
g_assert (priv->pending_activation_timeout_id == 0);
priv->pending_activation_timeout_id =
g_timeout_add (100, pending_activation_timeout, device);
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
if (priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
priv->pending_activation_timeout_waiting_finger_off = TRUE;
else
priv->pending_activation_timeout_waiting_finger_off = FALSE;
@@ -212,7 +279,7 @@ fp_image_device_start_capture_action (FpDevice *device)
/* And activate the device; we rely on fpi_image_device_activate_complete()
* to be called when done (or immediately). */
fpi_image_device_activate (self);
fp_image_device_activate (self);
}
@@ -262,23 +329,6 @@ fp_image_device_get_property (GObject *object,
}
}
static void
fp_image_device_constructed (GObject *obj)
{
FpImageDevice *self = FP_IMAGE_DEVICE (obj);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold;
G_OBJECT_CLASS (fp_image_device_parent_class)->constructed (obj);
}
static void
fp_image_device_class_init (FpImageDeviceClass *klass)
{
@@ -287,7 +337,6 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
object_class->finalize = fp_image_device_finalize;
object_class->get_property = fp_image_device_get_property;
object_class->constructed = fp_image_device_constructed;
fp_device_class->open = fp_image_device_open;
fp_device_class->close = fp_image_device_close;
@@ -302,37 +351,21 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
klass->activate = fp_image_device_default_activate;
klass->deactivate = fp_image_device_default_deactivate;
/**
* FpImageDevice::fpi-image-device-state: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_STATE] =
g_param_spec_enum ("fpi-image-device-state",
g_param_spec_enum ("fp-image-device-state",
"Image Device State",
"Private: The state of the image device",
FPI_TYPE_IMAGE_DEVICE_STATE,
FPI_IMAGE_DEVICE_STATE_INACTIVE,
FP_TYPE_IMAGE_DEVICE_STATE,
FP_IMAGE_DEVICE_STATE_INACTIVE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
/**
* FpImageDevice::fpi-image-device-state-changed: (skip)
* @image_device: A #FpImageDevice
* @new_state: The new state of the device
*
* This signal is only for internal purposes.
*
* Stability: private
*/
signals[FPI_STATE_CHANGED] =
g_signal_new ("fpi-image-device-state-changed",
g_signal_new ("fp-image-device-state-changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
NULL, NULL, NULL,
G_TYPE_NONE, 1, FPI_TYPE_IMAGE_DEVICE_STATE);
G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -340,4 +373,474 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
static void
fp_image_device_init (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
/* Set default values. */
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
if (cls->bz3_threshold > 0)
priv->bz3_threshold = cls->bz3_threshold;
}
static void
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(FpImage) image = FP_IMAGE (source_object);
g_autoptr(FpPrint) print = NULL;
GError *error = NULL;
FpDevice *device = FP_DEVICE (user_data);
FpImageDevicePrivate *priv;
FpDeviceAction action;
/* Note: We rely on the device to not disappear during an operation. */
if (!fp_image_detect_minutiae_finish (image, res, &error))
{
/* Cancel operation . */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
fpi_device_action_error (device, g_steal_pointer (&error));
fp_image_device_deactivate (device);
return;
}
/* Replace error with a retry condition. */
g_warning ("Failed to detect minutiae: %s", error->message);
g_clear_pointer (&error, g_error_free);
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
}
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
action = fpi_device_get_current_action (device);
if (action == FP_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
fp_image_device_deactivate (device);
return;
}
if (!error)
{
print = fp_print_new (device);
fpi_print_set_type (print, FP_PRINT_NBIS);
if (!fpi_print_add_from_image (print, image, &error))
g_clear_object (&print);
}
if (action == FP_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print;
fpi_device_get_enroll_data (device, &enroll_print);
if (print)
{
fpi_print_add_print (enroll_print, print);
priv->enroll_stage += 1;
}
fpi_device_enroll_progress (device, priv->enroll_stage,
g_steal_pointer (&print), error);
if (priv->enroll_stage == IMG_ENROLL_STAGES)
{
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
fp_image_device_deactivate (device);
}
}
else if (action == FP_DEVICE_ACTION_VERIFY)
{
FpPrint *template;
FpiMatchResult result;
fpi_device_get_verify_data (device, &template);
if (print)
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
else
result = FPI_MATCH_ERROR;
fpi_device_verify_complete (device, result, g_steal_pointer (&print), error);
fp_image_device_deactivate (device);
}
else if (action == FP_DEVICE_ACTION_IDENTIFY)
{
gint i;
GPtrArray *templates;
FpPrint *result = NULL;
fpi_device_get_identify_data (device, &templates);
for (i = 0; !error && i < templates->len; i++)
{
FpPrint *template = g_ptr_array_index (templates, i);
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
{
result = g_object_ref (template);
break;
}
}
fpi_device_identify_complete (device, result, g_steal_pointer (&print), error);
fp_image_device_deactivate (device);
}
else
{
/* XXX: This can be hit currently due to a race condition in the enroll code!
* In that case we scan a further image even though the minutiae for the previous
* one have not yet been detected.
* We need to keep track on the pending minutiae detection and the fact that
* it will finish eventually (or we may need to retry on error and activate the
* device again). */
g_assert_not_reached ();
}
}
/*********************************************************/
/* Private API */
/**
* fpi_image_device_set_bz3_threshold:
* @self: a #FpImageDevice imaging fingerprint device
* @bz3_threshold: BZ3 threshold to use
*
* Dynamically adjust the bz3 threshold. This is only needed for drivers
* that support devices with different properties. It should generally be
* called from the probe callback, but is acceptable to call from the open
* callback.
*/
void
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
gint bz3_threshold)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
g_return_if_fail (bz3_threshold > 0);
priv->bz3_threshold = bz3_threshold;
}
/**
* fpi_image_device_report_finger_status:
* @self: a #FpImageDevice imaging fingerprint device
* @present: whether the finger is present on the sensor
*
* Reports from the driver whether the user's finger is on
* the sensor.
*/
void
fpi_image_device_report_finger_status (FpImageDevice *self,
gboolean present)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
{
/* Do we really want to always ignore such reports? We could
* also track the state in case the user had the finger on
* the device at initialisation time and the driver reports
* this early.
*/
g_debug ("Ignoring finger presence report as the device is not active!");
return;
}
action = fpi_device_get_current_action (device);
g_assert (action != FP_DEVICE_ACTION_OPEN);
g_assert (action != FP_DEVICE_ACTION_CLOSE);
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE);
}
else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
/* We need to deactivate or continue to await finger */
/* There are three possible situations:
* 1. We are deactivating the device and the action is still in progress
* (minutiae detection).
* 2. We are still deactivating the device after an action completed
* 3. We were waiting for finger removal to start the new action
* Either way, we always end up deactivating except for the enroll case.
* XXX: This is not quite correct though, as we assume we need another finger
* scan even though we might be processing the last one (successfully).
*/
if (action != FP_DEVICE_ACTION_ENROLL)
fp_image_device_deactivate (device);
else
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
}
/**
* fpi_image_device_image_captured:
* @self: a #FpImageDevice imaging fingerprint device
* @image: whether the finger is present on the sensor
*
* Reports an image capture. Only use this function if the image was
* captured successfully. If there was an issue where the user should
* retry, use fpi_image_device_retry_scan() to report the retry condition.
*
* In the event of a fatal error for the operation use
* fpi_image_device_session_error(). This will abort the entire operation
* including e.g. an enroll operation which captures multiple images during
* one session.
*/
void
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (image != NULL);
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
g_debug ("Image device captured an image");
/* XXX: We also detect minutiae in capture mode, we solely do this
* to normalize the image which will happen as a by-product. */
fp_image_detect_minutiae (image,
fpi_device_get_cancellable (FP_DEVICE (self)),
fpi_image_device_minutiae_detected,
self);
}
/**
* fpi_image_device_retry_scan:
* @self: a #FpImageDevice imaging fingerprint device
* @retry: The #FpDeviceRetry error code to report
*
* Reports a scan failure to the user. This may or may not abort the
* current session. It is the equivalent of fpi_image_device_image_captured()
* in the case of a retryable error condition (e.g. short swipe).
*/
void
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
GError *error;
action = fpi_device_get_current_action (FP_DEVICE (self));
/* We might be waiting for a finger at this point, so just accept
* all but INACTIVE */
g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
error = fpi_device_retry_new (retry);
if (action == FP_DEVICE_ACTION_ENROLL)
{
g_debug ("Reporting retry during enroll");
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
}
else
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
fp_image_device_deactivate (FP_DEVICE (self));
fpi_device_action_error (FP_DEVICE (self), error);
}
}
/**
* fpi_image_device_session_error:
* @self: a #FpImageDevice imaging fingerprint device
* @error: The #GError to report
*
* Report an error while interacting with the device. This effectively
* aborts the current ongoing action.
*/
void
fpi_image_device_session_error (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (self);
if (!error)
{
g_warning ("Driver did not provide an error, generating a generic one");
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
}
if (!priv->active)
{
FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
g_warning ("Driver reported session error, but device is inactive.");
if (action != FP_DEVICE_ACTION_NONE)
{
g_warning ("Translating to activation failure!");
fpi_image_device_activate_complete (self, error);
return;
}
}
else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE)
{
g_warning ("Driver reported session error; translating to deactivation failure.");
fpi_image_device_deactivate_complete (self, error);
return;
}
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
fp_image_device_deactivate (FP_DEVICE (self));
fpi_device_action_error (FP_DEVICE (self), error);
}
/**
* fpi_image_device_activate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device activation.
*/
void
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL ||
action == FP_DEVICE_ACTION_VERIFY ||
action == FP_DEVICE_ACTION_IDENTIFY ||
action == FP_DEVICE_ACTION_CAPTURE);
if (error)
{
g_debug ("Image device activation failed");
fpi_device_action_error (FP_DEVICE (self), error);
return;
}
g_debug ("Image device activation completed");
priv->active = TRUE;
/* We always want to capture at this point, move to AWAIT_FINGER
* state. */
fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
/**
* fpi_image_device_deactivate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device deactivation.
*/
void
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpDeviceAction action;
g_return_if_fail (priv->active == TRUE);
g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE);
g_debug ("Image device deactivation completed");
priv->active = FALSE;
/* Deactivation completed. As we deactivate in the background
* there may already be a new task pending. Check whether we
* need to do anything. */
action = fpi_device_get_current_action (FP_DEVICE (self));
/* Special case, if we should be closing, but didn't due to a running
* deactivation, then do so now. */
if (action == FP_DEVICE_ACTION_CLOSE)
{
cls->img_close (self);
return;
}
/* We might be waiting to be able to activate again. */
if (priv->pending_activation_timeout_id)
{
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
priv->pending_activation_timeout_id =
g_idle_add ((GSourceFunc) fp_image_device_activate, self);
}
}
/**
* fpi_image_device_open_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of open operation.
*/
void
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_OPEN);
g_debug ("Image device open completed");
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fpi_device_open_complete (FP_DEVICE (self), error);
}
/**
* fpi_image_device_close_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of close operation.
*/
void
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_debug ("Image device close completed");
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE);
priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]);
fpi_device_close_complete (FP_DEVICE (self), error);
}

View File

@@ -19,7 +19,7 @@
#pragma once
#include "fp-device.h"
#include <fp-device.h>
G_BEGIN_DECLS

View File

@@ -18,12 +18,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "image"
#include "fpi-image.h"
#include "fpi-log.h"
#include <nbis.h>
#include "nbis/include/lfs.h"
#if HAVE_PIXMAN
#include <pixman.h>
#endif
/**
* SECTION: fp-image
@@ -34,6 +35,15 @@
* this object allows accessing this data.
*/
/**
* SECTION: fpi-image
* @title: Internal FpImage
* @short_description: Internal image handling routines
*
* Internal image handling routines. Also see the public <ulink
* url="libfprint-FpImage.html">FpImage routines</ulink>.
*/
G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
enum {
@@ -184,8 +194,10 @@ fp_image_detect_minutiae_cb (GObject *source_object,
GTask *task = G_TASK (res);
FpImage *image;
DetectMinutiaeData *data = g_task_get_task_data (task);
GCancellable *cancellable;
if (!g_task_had_error (task))
cancellable = g_task_get_cancellable (task);
if (!cancellable || !g_cancellable_is_cancelled (cancellable))
{
gint i;
image = FP_IMAGE (source_object);
@@ -281,7 +293,6 @@ fp_image_detect_minutiae_thread_func (GTask *task,
gint map_w, map_h;
gint bw, bh, bd;
gint r;
g_autofree LFSPARMS *lfsparms;
/* Normalize the image first */
if (data->flags & FPI_IMAGE_H_FLIPPED)
@@ -295,15 +306,12 @@ fp_image_detect_minutiae_thread_func (GTask *task,
data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED);
lfsparms = g_memdup (&g_lfsparms_V2, sizeof (LFSPARMS));
lfsparms->remove_perimeter_pts = data->flags & FPI_IMAGE_PARTIAL ? TRUE : FALSE;
timer = g_timer_new ();
r = get_minutiae (&minutiae, &quality_map, &direction_map,
&low_contrast_map, &low_flow_map, &high_curve_map,
&map_w, &map_h, &bdata, &bw, &bh, &bd,
data->image, data->width, data->height, 8,
data->ppmm, lfsparms);
data->ppmm, &g_lfsparms_V2);
g_timer_stop (timer);
fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL));
@@ -318,14 +326,6 @@ fp_image_detect_minutiae_thread_func (GTask *task,
return;
}
if (!data->minutiae || data->minutiae->num == 0)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
"No minutiae found");
g_object_unref (task);
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
@@ -478,6 +478,78 @@ fp_image_detect_minutiae_finish (FpImage *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
/**
* fpi_std_sq_dev:
* @buf: buffer (usually bitmap, one byte per pixel)
* @size: size of @buffer
*
* Calculates the squared standard deviation of the individual
* pixels in the buffer, as per the following formula:
* |[<!-- -->
* mean = sum (buf[0..size]) / size
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
* ]|
* This function is usually used to determine whether image
* is empty.
*
* Returns: the squared standard deviation for @buffer
*/
gint
fpi_std_sq_dev (const guint8 *buf,
gint size)
{
guint64 res = 0, mean = 0;
gint i;
for (i = 0; i < size; i++)
mean += buf[i];
mean /= size;
for (i = 0; i < size; i++)
{
int dev = (int) buf[i] - mean;
res += dev * dev;
}
return res / size;
}
/**
* fpi_mean_sq_diff_norm:
* @buf1: buffer (usually bitmap, one byte per pixel)
* @buf2: buffer (usually bitmap, one byte per pixel)
* @size: buffer size of smallest buffer
*
* This function calculates the normalized mean square difference of
* two buffers, usually two lines, as per the following formula:
* |[<!-- -->
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
* ]|
*
* This functions is usually used to get numerical difference
* between two images.
*
* Returns: the normalized mean squared difference between @buf1 and @buf2
*/
gint
fpi_mean_sq_diff_norm (const guint8 *buf1,
const guint8 *buf2,
gint size)
{
int res = 0, i;
for (i = 0; i < size; i++)
{
int dev = (int) buf1[i] - (int) buf2[i];
res += dev * dev;
}
return res / size;
}
/**
* fp_minutia_get_coords:
* @min: A #FpMinutia
@@ -495,3 +567,44 @@ fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
if (y)
*y = min->y;
}
#if HAVE_PIXMAN
FpImage *
fpi_image_resize (FpImage *orig_img,
guint w_factor,
guint h_factor)
{
int new_width = orig_img->width * w_factor;
int new_height = orig_img->height * h_factor;
pixman_image_t *orig, *resized;
pixman_transform_t transform;
FpImage *newimg;
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
pixman_transform_init_identity (&transform);
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
pixman_image_set_transform (orig, &transform);
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_composite32 (PIXMAN_OP_SRC,
orig, /* src */
NULL, /* mask */
resized, /* dst */
0, 0, /* src x y */
0, 0, /* mask x y */
0, 0, /* dst x y */
new_width, new_height /* width height */
);
newimg = fp_image_new (new_width, new_height);
newimg->flags = orig_img->flags;
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
pixman_image_unref (orig);
pixman_image_unref (resized);
return newimg;
}
#endif

View File

@@ -18,11 +18,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "print"
#include "fpi-print.h"
#include "fpi-image.h"
#include "fpi-device.h"
#include "fp-print-private.h"
#include "fpi-compat.h"
#include "fpi-log.h"
#include "nbis/include/bozorth.h"
#include "nbis/include/lfs.h"
/**
* SECTION: fp-print
@@ -41,6 +42,28 @@
* #FpPrint routines.
*/
struct _FpPrint
{
GInitiallyUnowned parent_instance;
FpPrintType type;
gchar *driver;
gchar *device_id;
gboolean device_stored;
FpImage *image;
/* Metadata */
FpFinger finger;
gchar *username;
gchar *description;
GDate *enroll_date;
GVariant *data;
GPtrArray *prints;
};
G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED)
enum {
@@ -51,7 +74,7 @@ enum {
PROP_IMAGE,
/* The following is metadata that is stored by default for each print.
* Drivers may make use of these during enrollment (e.g. to additionally store
* Drivers may make use of these during enrollment (e.g. to additionaly store
* the metadata on the device). */
PROP_FINGER,
PROP_USERNAME,
@@ -184,7 +207,7 @@ fp_print_set_property (GObject *object,
break;
case PROP_FPI_DATA:
g_clear_pointer (&self->data, g_variant_unref);
g_clear_pointer (&self->description, g_variant_unref);
self->data = g_value_dup_variant (value);
break;
@@ -269,30 +292,16 @@ fp_print_class_init (FpPrintClass *klass)
G_TYPE_DATE,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
/**
* FpPrint::fpi-type: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_TYPE] =
g_param_spec_enum ("fpi-type",
g_param_spec_enum ("fp-type",
"Type",
"Private: The type of the print data",
FPI_TYPE_PRINT_TYPE,
FPI_PRINT_RAW,
FP_TYPE_PRINT_TYPE,
FP_PRINT_RAW,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
/**
* FpPrint::fpi-data: (skip)
*
* This property is only for internal purposes.
*
* Stability: private
*/
properties[PROP_FPI_DATA] =
g_param_spec_variant ("fpi-data",
g_param_spec_variant ("fp-data",
"Raw Data",
"The raw data for internal use only",
G_VARIANT_TYPE_ANY,
@@ -531,6 +540,223 @@ fp_print_set_enroll_date (FpPrint *print,
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]);
}
/**
* fpi_print_add_print:
* @print: A #FpPrint
* @add: Print to append to @print
*
* Appends the single #FP_PRINT_NBIS print from @add to the collection of
* prints in @print. Both print objects need to be of type #FP_PRINT_NBIS
* for this to work.
*/
void
fpi_print_add_print (FpPrint *print, FpPrint *add)
{
g_return_if_fail (print->type == FP_PRINT_NBIS);
g_return_if_fail (add->type == FP_PRINT_NBIS);
g_assert (add->prints->len == 1);
g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
}
/**
* fpi_print_set_type:
* @print: A #FpPrint
* @type: The newly type of the print data
*
* This function can only be called exactly once. Drivers should
* call it after creating a new print, or to initialize the template
* print passed during enrollment.
*/
void
fpi_print_set_type (FpPrint *print,
FpPrintType type)
{
g_return_if_fail (FP_IS_PRINT (print));
/* We only allow setting this once! */
g_return_if_fail (print->type == FP_PRINT_UNDEFINED);
print->type = type;
if (print->type == FP_PRINT_NBIS)
{
g_assert_null (print->prints);
print->prints = g_ptr_array_new_with_free_func (g_free);
}
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]);
}
/**
* fpi_print_set_device_stored:
* @print: A #FpPrint
* @device_stored: Whether the print is stored on the device or not
*
* Drivers must set this to %TRUE for any print that is really a handle
* for data that is stored on the device itself.
*/
void
fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored)
{
g_return_if_fail (FP_IS_PRINT (print));
print->device_stored = device_stored;
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DEVICE_STORED]);
}
/* XXX: This is the old version, but wouldn't it be smarter to instead
* use the highest quality mintutiae? Possibly just using bz_prune from
* upstream? */
static void
minutiae_to_xyt (struct fp_minutiae *minutiae,
int bwidth,
int bheight,
struct xyt_struct *xyt)
{
int i;
struct fp_minutia *minutia;
struct minutiae_struct c[MAX_FILE_MINUTIAE];
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
for (i = 0; i < nmin; i++)
{
minutia = minutiae->list[i];
lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
minutia, bwidth, bheight);
c[i].col[3] = sround (minutia->reliability * 100.0);
if (c[i].col[2] > 180)
c[i].col[2] -= 360;
}
qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
sort_x_y);
for (i = 0; i < nmin; i++)
{
xyt->xcol[i] = c[i].col[0];
xyt->ycol[i] = c[i].col[1];
xyt->thetacol[i] = c[i].col[2];
}
xyt->nrows = nmin;
}
/**
* fpi_print_add_from_image:
* @print: A #FpPrint
* @image: A #FpImage
* @error: Return location for error
*
* Extracts the minutiae from the given image and adds it to @print of
* type #FP_PRINT_NBIS.
*
* The @image will be kept so that API users can get retrieve it e.g.
* for debugging purposes.
*
* Returns: %TRUE on success
*/
gboolean
fpi_print_add_from_image (FpPrint *print,
FpImage *image,
GError **error)
{
GPtrArray *minutiae;
struct fp_minutiae _minutiae;
struct xyt_struct *xyt;
if (print->type != FP_PRINT_NBIS || !image)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Cannot add print data from image!");
return FALSE;
}
minutiae = fp_image_get_minutiae (image);
if (!minutiae || minutiae->len == 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"No minutiae found in image or not yet detected!");
return FALSE;
}
_minutiae.num = minutiae->len;
_minutiae.list = (struct fp_minutia **) minutiae->pdata;
_minutiae.alloc = minutiae->len;
xyt = g_new0 (struct xyt_struct, 1);
minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
g_ptr_array_add (print->prints, xyt);
g_clear_object (&print->image);
print->image = g_object_ref (image);
g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_IMAGE]);
return TRUE;
}
/**
* fpi_print_bz3_match:
* @template: A #FpPrint containing one or more prints
* @print: A newly scanned #FpPrint to test
* @bz3_threshold: The BZ3 match threshold
* @error: Return location for error
*
* Match the newly scanned @print (containing exactly one print) against the
* prints contained in @template which will have been stored during enrollment.
*
* Both @template and @print need to be of type #FP_PRINT_NBIS for this to
* work.
*
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
*/
FpiMatchResult
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
{
struct xyt_struct *pstruct;
gint probe_len;
gint i;
/* XXX: Use a different error type? */
if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"It is only possible to match NBIS type print data");
return FPI_MATCH_ERROR;
}
if (print->prints->len != 1)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"New print contains more than one print!");
return FPI_MATCH_ERROR;
}
pstruct = g_ptr_array_index (print->prints, 0);
probe_len = bozorth_probe_init (pstruct);
for (i = 0; i < template->prints->len; i++)
{
struct xyt_struct *gstruct;
gint score;
gstruct = g_ptr_array_index (template->prints, i);
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
fp_dbg ("score %d", score);
if (score >= bz3_threshold)
return FPI_MATCH_SUCCESS;
}
return FPI_MATCH_FAIL;
}
/**
* fp_print_compatible:
* @self: A #FpPrint
@@ -570,8 +796,8 @@ fp_print_equal (FpPrint *self, FpPrint *other)
{
g_return_val_if_fail (FP_IS_PRINT (self), FALSE);
g_return_val_if_fail (FP_IS_PRINT (other), FALSE);
g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (self->type != FP_PRINT_UNDEFINED, FALSE);
g_return_val_if_fail (other->type != FP_PRINT_UNDEFINED, FALSE);
if (self->type != other->type)
return FALSE;
@@ -582,13 +808,13 @@ fp_print_equal (FpPrint *self, FpPrint *other)
if (g_strcmp0 (self->device_id, other->device_id))
return FALSE;
if (self->type == FPI_PRINT_RAW)
if (self->type == FP_PRINT_RAW)
{
return g_variant_equal (self->data, other->data);
}
else if (self->type == FPI_PRINT_NBIS)
else if (self->type == FP_PRINT_NBIS)
{
guint i;
gint i;
if (self->prints->len != other->prints->len)
return FALSE;
@@ -610,7 +836,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
}
}
#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
#define FP_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)")
G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4);
@@ -633,7 +859,7 @@ fp_print_serialize (FpPrint *print,
GError **error)
{
g_autoptr(GVariant) result = NULL;
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FPI_PRINT_VARIANT_TYPE);
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FP_PRINT_VARIANT_TYPE);
gsize len;
g_assert (data);
@@ -658,10 +884,10 @@ fp_print_serialize (FpPrint *print,
g_variant_builder_close (&builder);
/* Insert NBIS print data for type NBIS, otherwise the GVariant directly */
if (print->type == FPI_PRINT_NBIS)
if (print->type == FP_PRINT_NBIS)
{
GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))"));
guint i;
gint i;
g_variant_builder_open (&nested, G_VARIANT_TYPE ("a(aiaiai)"));
for (i = 0; i < print->prints->len; i++)
@@ -753,14 +979,14 @@ fp_print_deserialize (const guchar *data,
g_autoptr(GVariant) raw_value = NULL;
g_autoptr(GVariant) value = NULL;
g_autoptr(GVariant) print_data = NULL;
g_autoptr(GDate) date = NULL;
guchar *aligned_data = NULL;
GDate *date = NULL;
guint8 finger_int8;
FpFinger finger;
g_autofree gchar *username = NULL;
g_autofree gchar *description = NULL;
gint julian_date;
FpiPrintType type;
FpPrintType type;
const gchar *driver;
const gchar *device_id;
gboolean device_stored;
@@ -781,7 +1007,7 @@ fp_print_deserialize (const guchar *data,
* longer. */
aligned_data = g_malloc (length - 3);
memcpy (aligned_data, data + 3, length - 3);
raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE,
raw_value = g_variant_new_from_data (FP_PRINT_VARIANT_TYPE,
aligned_data, length - 3,
FALSE, g_free, aligned_data);
@@ -809,20 +1035,20 @@ fp_print_deserialize (const guchar *data,
finger = finger_int8;
/* Assume data is valid at this point if the values are somewhat sane. */
if (type == FPI_PRINT_NBIS)
if (type == FP_PRINT_NBIS)
{
g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0);
guint i;
gint i;
result = g_object_new (FP_TYPE_PRINT,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
NULL);
fpi_print_set_type (result, FPI_PRINT_NBIS);
fpi_print_set_type (result, FP_PRINT_NBIS);
for (i = 0; i < g_variant_n_children (prints); i++)
{
g_autofree struct xyt_struct *xyt = NULL;
g_autofree struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1);
const gint32 *xcol, *ycol, *thetacol;
gsize xlen, ylen, thetalen;
g_autoptr(GVariant) xyt_data = NULL;
@@ -848,7 +1074,6 @@ fp_print_deserialize (const guchar *data,
if (xlen > G_N_ELEMENTS (xyt->xcol))
goto invalid_format;
xyt = g_new0 (struct xyt_struct, 1);
xyt->nrows = xlen;
memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen);
memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen);
@@ -857,16 +1082,16 @@ fp_print_deserialize (const guchar *data,
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
}
}
else if (type == FPI_PRINT_RAW)
else if (type == FP_PRINT_RAW)
{
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
result = g_object_new (FP_TYPE_PRINT,
"fpi-type", type,
"fp-type", type,
"driver", driver,
"device-id", device_id,
"device-stored", device_stored,
"fpi-data", fp_data,
"fp-data", fp_data,
NULL);
}
else
@@ -883,6 +1108,8 @@ fp_print_deserialize (const guchar *data,
"enroll_date", date,
NULL);
g_date_free (date);
return g_steal_pointer (&result);
invalid_format:

View File

@@ -28,9 +28,6 @@ G_BEGIN_DECLS
#define FP_TYPE_PRINT (fp_print_get_type ())
G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
#define FP_FINGER_IS_VALID(finger) \
((finger) >= FP_FINGER_FIRST && (finger) <= FP_FINGER_LAST)
#include "fp-device.h"
/**
@@ -46,8 +43,6 @@ G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned)
* @FP_FINGER_RIGHT_MIDDLE: Right middle finger
* @FP_FINGER_RIGHT_RING: Right ring finger
* @FP_FINGER_RIGHT_LITTLE: Right little finger
* @FP_FINGER_FIRST: The first finger in the fp-print order
* @FP_FINGER_LAST: The last finger in the fp-print order
*/
typedef enum {
FP_FINGER_UNKNOWN = 0,
@@ -61,9 +56,6 @@ typedef enum {
FP_FINGER_RIGHT_MIDDLE,
FP_FINGER_RIGHT_RING,
FP_FINGER_RIGHT_LITTLE,
FP_FINGER_FIRST = FP_FINGER_LEFT_THUMB,
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
} FpFinger;
FpPrint *fp_print_new (FpDevice *device);

View File

@@ -17,7 +17,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __FPRINT_INTERNAL_H__
#define __FPRINT_INTERNAL_H__
#include "fpi-log.h"
#include "nbis-helpers.h"
#include "fpi-image.h"
#include "fpi-image-device.h"
/* fp_minutia structure definition */
struct fp_minutia
@@ -43,3 +49,6 @@ struct fp_minutiae
int num;
struct fp_minutia **list;
};
#endif

View File

@@ -21,8 +21,7 @@
#define FP_COMPONENT "assembling"
#include "fpi-log.h"
#include "fpi-image.h"
#include "fp_internal.h"
#include <string.h>
@@ -52,9 +51,6 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
width = ctx->frame_width - (dx > 0 ? dx : -dx);
height = ctx->frame_height - dy;
if (height == 0 || width == 0)
return INT_MAX;
y1 = 0;
y2 = dy;
i = 0;
@@ -89,6 +85,9 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx,
err *= (ctx->frame_height * ctx->frame_width);
err /= (height * width);
if (err == 0)
return INT_MAX;
return err;
}
@@ -99,8 +98,6 @@ static void
find_overlap (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *first_frame,
struct fpi_frame *second_frame,
int *dx_out,
int *dy_out,
unsigned int *min_error)
{
int dx, dy;
@@ -122,8 +119,8 @@ find_overlap (struct fpi_frame_asmbl_ctx *ctx,
if (err < *min_error)
{
*min_error = err;
*dx_out = -dx;
*dy_out = dy;
second_frame->delta_x = -dx;
second_frame->delta_y = dy;
}
}
}
@@ -135,7 +132,7 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
{
GSList *l;
GTimer *timer;
guint num_frames = 1;
guint num_frames = 0;
struct fpi_frame *prev_stripe;
unsigned int min_error;
/* Max error is width * height * 255, for AES2501 which has the largest
@@ -145,27 +142,20 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx,
unsigned long long total_error = 0;
timer = g_timer_new ();
/* Skip the first frame */
prev_stripe = stripes->data;
for (l = stripes->next; l != NULL; l = l->next, num_frames++)
for (l = stripes; l != NULL; l = l->next, num_frames++)
{
struct fpi_frame *cur_stripe = l->data;
if (reverse)
{
find_overlap (ctx, prev_stripe, cur_stripe,
&cur_stripe->delta_x, &cur_stripe->delta_y,
&min_error);
find_overlap (ctx, prev_stripe, cur_stripe, &min_error);
cur_stripe->delta_y = -cur_stripe->delta_y;
cur_stripe->delta_x = -cur_stripe->delta_x;
}
else
{
find_overlap (ctx, cur_stripe, prev_stripe,
&cur_stripe->delta_x, &cur_stripe->delta_y,
&min_error);
find_overlap (ctx, cur_stripe, prev_stripe, &min_error);
}
total_error += min_error;
@@ -337,10 +327,19 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
{
fpi_frame = l->data;
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
if(reverse)
{
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
}
aes_blit_stripe (ctx, img, fpi_frame, x, y);
if(!reverse)
{
y += fpi_frame->delta_y;
x += fpi_frame->delta_x;
}
}
return img;

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __FPI_ASSEMBLING_H__
#define __FPI_ASSEMBLING_H__
#include <fprint.h>
@@ -115,3 +116,5 @@ struct fpi_line_asmbl_ctx
FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx,
GSList *lines,
size_t num_lines);
#endif

View File

@@ -19,7 +19,8 @@
* Boston, MA 02110-1301, USA.
*/
#pragma once
#ifndef __FPI_BYTE_READER_H__
#define __FPI_BYTE_READER_H__
#include <glib.h>
#include "fpi-byte-utils.h"
@@ -675,3 +676,5 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes)
#endif /* FPI_BYTE_READER_DISABLE_INLINES */
G_END_DECLS
#endif /* __FPI_BYTE_READER_H__ */

View File

@@ -21,7 +21,9 @@
* Boston, MA 02110-1301, USA.
*/
#pragma once
#ifndef __FP_UTILS_H__
#define __FP_UTILS_H__
#include <glib.h>
@@ -483,3 +485,4 @@ FP_WRITE_DOUBLE_BE(guint8 *data, gdouble num)
G_END_DECLS
#endif /* __GTK_DOC_IGNORE__ */
#endif /* __FP_UTILS_H__ */

View File

@@ -18,7 +18,8 @@
* Boston, MA 02110-1301, USA.
*/
#pragma once
#ifndef __FPI_BYTE_WRITER_H__
#define __FPI_BYTE_WRITER_H__
#include "fpi-byte-reader.h"
#include <string.h>
@@ -408,3 +409,5 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size)
#endif
G_END_DECLS
#endif /* __FPI_BYTE_WRITER_H__ */

View File

@@ -1,39 +0,0 @@
/*
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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
*/
#pragma once
#include <glib-object.h>
#if !GLIB_CHECK_VERSION (2, 57, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
#else
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
* the version we depend on currently. */
#undef G_SOURCE_FUNC
#endif
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
#if !GLIB_CHECK_VERSION (2, 63, 3)
typedef struct _FpDeviceClass FpDeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
#endif

View File

@@ -20,16 +20,14 @@
#include <gusb.h>
#include "fp-context.h"
#include "fpi-compat.h"
/**
* fpi_get_driver_types:
* @drivers: #GArray to be filled with all driver types
*
* This function is purely for private used. It is solely part of the public
* API as it is useful during build time.
*
* Stability: private
* Returns: (element-type GType) (transfer container): a #GArray filled with
* all driver types
*/
GArray *fpi_get_driver_types (void);
void fpi_get_driver_types (GArray *drivers);

File diff suppressed because it is too large Load Diff

View File

@@ -65,10 +65,10 @@ struct _FpIdEntry
* @probe: Called immediately for all devices. Most drivers will not need to
* implement this. Drivers should setup the device identifier from the probe
* callback which will be used to verify the compatibility of stored
* #FpPrint's. It is permissible to temporarily open the USB device if this
* #FpPrint's. It is permissable to temporarily open the USB device if this
* is required for the operation. If an error is returned, then the device
* will be destroyed again immediately and never reported to the API user.
* @open: Open the device for further operations. Any of the normal actions are
* @open: Open the device for futher operations. Any of the normal actions are
* guaranteed to only happen when the device is open (this includes delete).
* @close: Close the device again
* @enroll: Start an enroll operation
@@ -142,39 +142,39 @@ typedef void (*FpTimeoutFunc) (FpDevice *device,
gpointer user_data);
/**
* FpiDeviceAction:
* @FPI_DEVICE_ACTION_NONE: No action is active.
* @FPI_DEVICE_ACTION_PROBE: Probe device for support and information.
* @FPI_DEVICE_ACTION_OPEN: Device is currently being opened.
* @FPI_DEVICE_ACTION_CLOSE: Device is currently being closed.
* @FPI_DEVICE_ACTION_ENROLL: Device is currently enrolling.
* @FPI_DEVICE_ACTION_VERIFY: Device is currently verifying.
* @FPI_DEVICE_ACTION_IDENTIFY: Device is currently identifying.
* @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
* @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried.
* @FPI_DEVICE_ACTION_DELETE: Device stored print is being deleted.
* FpDeviceAction:
* @FP_DEVICE_ACTION_NONE: No action is active.
* @FP_DEVICE_ACTION_PROBE: Probe device for support and information.
* @FP_DEVICE_ACTION_OPEN: Device is currently being opened.
* @FP_DEVICE_ACTION_CLOSE: Device is currently being closed.
* @FP_DEVICE_ACTION_ENROLL: Device is currently enrolling.
* @FP_DEVICE_ACTION_VERIFY: Device is currently verifying.
* @FP_DEVICE_ACTION_IDENTIFY: Device is currently identifying.
* @FP_DEVICE_ACTION_CAPTURE: Device is currently capturing an image.
* @FP_DEVICE_ACTION_LIST: Device stored prints are being queried.
* @FP_DEVICE_ACTION_DELETE: Device stored print is being deleted.
*
* Current active action of the device. A driver can retrieve the action.
*/
typedef enum {
FPI_DEVICE_ACTION_NONE = 0,
FPI_DEVICE_ACTION_PROBE,
FPI_DEVICE_ACTION_OPEN,
FPI_DEVICE_ACTION_CLOSE,
FPI_DEVICE_ACTION_ENROLL,
FPI_DEVICE_ACTION_VERIFY,
FPI_DEVICE_ACTION_IDENTIFY,
FPI_DEVICE_ACTION_CAPTURE,
FPI_DEVICE_ACTION_LIST,
FPI_DEVICE_ACTION_DELETE,
} FpiDeviceAction;
FP_DEVICE_ACTION_NONE = 0,
FP_DEVICE_ACTION_PROBE,
FP_DEVICE_ACTION_OPEN,
FP_DEVICE_ACTION_CLOSE,
FP_DEVICE_ACTION_ENROLL,
FP_DEVICE_ACTION_VERIFY,
FP_DEVICE_ACTION_IDENTIFY,
FP_DEVICE_ACTION_CAPTURE,
FP_DEVICE_ACTION_LIST,
FP_DEVICE_ACTION_DELETE,
} FpDeviceAction;
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
const gchar *fpi_device_get_virtual_env (FpDevice *device);
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
FpiDeviceAction fpi_device_get_current_action (FpDevice *device);
FpDeviceAction fpi_device_get_current_action (FpDevice *device);
gboolean fpi_device_action_is_cancelled (FpDevice *device);
GError * fpi_device_retry_new (FpDeviceRetry error);
@@ -229,9 +229,13 @@ void fpi_device_close_complete (FpDevice *device,
void fpi_device_enroll_complete (FpDevice *device,
FpPrint *print,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
void fpi_device_capture_complete (FpDevice *device,
FpImage *image,
@@ -246,13 +250,5 @@ void fpi_device_enroll_progress (FpDevice *device,
gint completed_stages,
FpPrint *print,
GError *error);
void fpi_device_verify_report (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_identify_report (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
G_END_DECLS

View File

@@ -1,650 +0,0 @@
/*
* FpImageDevice - An image based fingerprint reader device - Private APIs
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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 "image_device"
#include "fpi-log.h"
#include "fp-image-device-private.h"
#include "fp-image-device.h"
/**
* SECTION: fpi-image-device
* @title: Internal FpImageDevice
* @short_description: Internal image device functions
*
* Internal image device functions. See #FpImageDevice for public routines.
*/
/* Manually redefine what G_DEFINE_* macro does */
static inline gpointer
fp_image_device_get_instance_private (FpImageDevice *self)
{
FpImageDeviceClass *img_class = g_type_class_peek_static (FP_TYPE_IMAGE_DEVICE);
return G_STRUCT_MEMBER_P (self,
g_type_class_get_instance_private_offset (img_class));
}
/* Private shared functions */
void
fpi_image_device_activate (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
g_assert (!priv->active);
/* We don't have a neutral ACTIVE state, but we always will
* go into WAIT_FINGER_ON afterwards. */
priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
/* We might have been waiting for deactivation to finish before
* starting the next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Activating image device");
cls->activate (self);
}
void
fpi_image_device_deactivate (FpImageDevice *self)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
if (!priv->active || priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* XXX: We currently deactivate both from minutiae scan result
* and finger off report. */
fp_dbg ("Already deactivated, ignoring request.");
return;
}
if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fp_dbg ("Deactivating image device");
cls->deactivate (self);
}
/* Static helper functions */
static void
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_autofree char *prev_state_str = NULL;
g_autofree char *state_str = NULL;
/* Cannot change to inactive using this function. */
g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
/* We might have been waiting for the finger to go OFF to start the
* next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
fp_dbg ("Image device internal state change from %s to %s",
prev_state_str, state_str);
priv->state = state;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
}
static void
fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
if (priv->enroll_await_on_pending)
{
priv->enroll_await_on_pending = FALSE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
else
{
fp_dbg ("Awaiting finger on");
priv->enroll_await_on_pending = TRUE;
}
}
static void
fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
g_autoptr(FpImage) image = FP_IMAGE (source_object);
g_autoptr(FpPrint) print = NULL;
GError *error = NULL;
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv;
FpiDeviceAction action;
/* Note: We rely on the device to not disappear during an operation. */
if (!fp_image_detect_minutiae_finish (image, res, &error))
{
/* Cancel operation . */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
fpi_device_action_error (device, g_steal_pointer (&error));
fpi_image_device_deactivate (self);
return;
}
/* Replace error with a retry condition. */
g_warning ("Failed to detect minutiae: %s", error->message);
g_clear_pointer (&error, g_error_free);
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
}
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
action = fpi_device_get_current_action (device);
if (action == FPI_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
fpi_image_device_deactivate (self);
return;
}
if (!error)
{
print = fp_print_new (device);
fpi_print_set_type (print, FPI_PRINT_NBIS);
if (!fpi_print_add_from_image (print, image, &error))
{
g_clear_object (&print);
if (error->domain != FP_DEVICE_RETRY)
{
fpi_device_action_error (device, error);
fpi_image_device_deactivate (self);
return;
}
}
}
if (action == FPI_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print;
fpi_device_get_enroll_data (device, &enroll_print);
if (print)
{
fpi_print_add_print (enroll_print, print);
priv->enroll_stage += 1;
}
fpi_device_enroll_progress (device, priv->enroll_stage,
g_steal_pointer (&print), error);
/* Start another scan or deactivate. */
if (priv->enroll_stage == IMG_ENROLL_STAGES)
{
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
fpi_image_device_deactivate (self);
}
else
{
fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device));
}
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
FpPrint *template;
FpiMatchResult result;
fpi_device_get_verify_data (device, &template);
if (print)
result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
else
result = FPI_MATCH_ERROR;
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_verify_complete (device, error);
fpi_image_device_deactivate (self);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
gint i;
GPtrArray *templates;
FpPrint *result = NULL;
fpi_device_get_identify_data (device, &templates);
for (i = 0; !error && i < templates->len; i++)
{
FpPrint *template = g_ptr_array_index (templates, i);
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
{
result = template;
break;
}
}
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_identify_complete (device, error);
fpi_image_device_deactivate (self);
}
else
{
/* XXX: This can be hit currently due to a race condition in the enroll code!
* In that case we scan a further image even though the minutiae for the previous
* one have not yet been detected.
* We need to keep track on the pending minutiae detection and the fact that
* it will finish eventually (or we may need to retry on error and activate the
* device again). */
g_assert_not_reached ();
}
}
/*********************************************************/
/* Private API */
/**
* fpi_image_device_set_bz3_threshold:
* @self: a #FpImageDevice imaging fingerprint device
* @bz3_threshold: BZ3 threshold to use
*
* Dynamically adjust the bz3 threshold. This is only needed for drivers
* that support devices with different properties. It should generally be
* called from the probe callback, but is acceptable to call from the open
* callback.
*/
void
fpi_image_device_set_bz3_threshold (FpImageDevice *self,
gint bz3_threshold)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
g_return_if_fail (bz3_threshold > 0);
priv->bz3_threshold = bz3_threshold;
}
/**
* fpi_image_device_report_finger_status:
* @self: a #FpImageDevice imaging fingerprint device
* @present: whether the finger is present on the sensor
*
* Reports from the driver whether the user's finger is on
* the sensor.
*/
void
fpi_image_device_report_finger_status (FpImageDevice *self,
gboolean present)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* Do we really want to always ignore such reports? We could
* also track the state in case the user had the finger on
* the device at initialisation time and the driver reports
* this early.
*/
g_debug ("Ignoring finger presence report as the device is not active!");
return;
}
action = fpi_device_get_current_action (device);
g_assert (action != FPI_DEVICE_ACTION_OPEN);
g_assert (action != FPI_DEVICE_ACTION_CLOSE);
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
}
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
/* We need to deactivate or continue to await finger */
/* There are three possible situations:
* 1. We are deactivating the device and the action is still in progress
* (minutiae detection).
* 2. We are still deactivating the device after an action completed
* 3. We were waiting for finger removal to start the new action
* Either way, we always end up deactivating except for the enroll case.
*
* The enroll case is special as AWAIT_FINGER_ON should only happen after
* minutiae detection to prevent deactivation (without cancellation)
* from the AWAIT_FINGER_ON state.
*/
if (action != FPI_DEVICE_ACTION_ENROLL)
fpi_image_device_deactivate (self);
else
fp_image_device_enroll_maybe_await_finger_on (self);
}
}
/**
* fpi_image_device_image_captured:
* @self: a #FpImageDevice imaging fingerprint device
* @image: whether the finger is present on the sensor
*
* Reports an image capture. Only use this function if the image was
* captured successfully. If there was an issue where the user should
* retry, use fpi_image_device_retry_scan() to report the retry condition.
*
* In the event of a fatal error for the operation use
* fpi_image_device_session_error(). This will abort the entire operation
* including e.g. an enroll operation which captures multiple images during
* one session.
*/
void
fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (image != NULL);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
g_debug ("Image device captured an image");
/* XXX: We also detect minutiae in capture mode, we solely do this
* to normalize the image which will happen as a by-product. */
fp_image_detect_minutiae (image,
fpi_device_get_cancellable (FP_DEVICE (self)),
fpi_image_device_minutiae_detected,
self);
}
/**
* fpi_image_device_retry_scan:
* @self: a #FpImageDevice imaging fingerprint device
* @retry: The #FpDeviceRetry error code to report
*
* Reports a scan failure to the user. This may or may not abort the
* current session. It is the equivalent of fpi_image_device_image_captured()
* in the case of a retryable error condition (e.g. short swipe).
*/
void
fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
GError *error;
action = fpi_device_get_current_action (FP_DEVICE (self));
/* We might be waiting for a finger at this point, so just accept
* all but INACTIVE */
g_return_if_fail (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
error = fpi_device_retry_new (retry);
if (action == FPI_DEVICE_ACTION_ENROLL)
{
g_debug ("Reporting retry during enroll");
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
/* Wait for finger removal and re-touch.
* TODO: Do we need to check that the finger is already off? */
priv->enroll_await_on_pending = TRUE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_verify_complete (FP_DEVICE (self), NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_identify_complete (FP_DEVICE (self), NULL);
}
else
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
}
}
/**
* fpi_image_device_session_error:
* @self: a #FpImageDevice imaging fingerprint device
* @error: The #GError to report
*
* Report an error while interacting with the device. This effectively
* aborts the current ongoing action. Note that doing so will result in
* the deactivation handler to be called and this function must not be
* used to report an error during deactivation.
*/
void
fpi_image_device_session_error (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_return_if_fail (self);
if (!error)
{
g_warning ("Driver did not provide an error, generating a generic one");
error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
}
if (!priv->active)
{
FpiDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
g_warning ("Driver reported session error, but device is inactive.");
if (action != FPI_DEVICE_ACTION_NONE)
{
g_warning ("Translating to activation failure!");
fpi_image_device_activate_complete (self, error);
return;
}
}
else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
fpi_device_action_is_cancelled (FP_DEVICE (self)))
{
/* Ignore cancellation errors here, as we will explicitly deactivate
* anyway (or, may already have done so at this point).
*/
g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring.");
g_clear_error (&error);
return;
}
else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug.");
g_clear_error (&error);
return;
}
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
}
/**
* fpi_image_device_activate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device activation.
*/
void
fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
if (error)
{
g_debug ("Image device activation failed");
fpi_device_action_error (FP_DEVICE (self), error);
return;
}
g_debug ("Image device activation completed");
priv->active = TRUE;
/* We always want to capture at this point, move to AWAIT_FINGER
* state. */
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
/**
* fpi_image_device_deactivate_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of device deactivation.
*/
void
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpiDeviceAction action;
g_return_if_fail (priv->active == TRUE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE);
g_debug ("Image device deactivation completed");
priv->active = FALSE;
/* Deactivation completed. As we deactivate in the background
* there may already be a new task pending. Check whether we
* need to do anything. */
action = fpi_device_get_current_action (FP_DEVICE (self));
/* Special case, if we should be closing, but didn't due to a running
* deactivation, then do so now. */
if (action == FPI_DEVICE_ACTION_CLOSE)
{
cls->img_close (self);
return;
}
/* We might be waiting to be able to activate again. */
if (priv->pending_activation_timeout_id)
{
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
priv->pending_activation_timeout_id =
g_idle_add ((GSourceFunc) fpi_image_device_activate, self);
}
}
/**
* fpi_image_device_open_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of open operation.
*/
void
fpi_image_device_open_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
g_debug ("Image device open completed");
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fpi_device_open_complete (FP_DEVICE (self), error);
}
/**
* fpi_image_device_close_complete:
* @self: a #FpImageDevice imaging fingerprint device
* @error: A #GError or %NULL on success
*
* Reports completion of close operation.
*/
void
fpi_image_device_close_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (FP_DEVICE (self));
g_debug ("Image device close completed");
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (action == FPI_DEVICE_ACTION_CLOSE);
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fpi_device_close_complete (FP_DEVICE (self), error);
}

View File

@@ -23,11 +23,11 @@
#include "fp-image-device.h"
/**
* FpiImageDeviceState:
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
* FpImageDeviceState:
* @FP_IMAGE_DEVICE_STATE_INACTIVE: inactive
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
* @FP_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
* @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
*
* The state of an imaging device while doing a capture. The state is
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
@@ -37,11 +37,11 @@
* unconditionally if the device supports raw capturing.
*/
typedef enum {
FPI_IMAGE_DEVICE_STATE_INACTIVE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
FPI_IMAGE_DEVICE_STATE_CAPTURE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
} FpiImageDeviceState;
FP_IMAGE_DEVICE_STATE_INACTIVE,
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
FP_IMAGE_DEVICE_STATE_CAPTURE,
FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
} FpImageDeviceState;
/**
* FpImageDeviceClass:
@@ -72,8 +72,9 @@ typedef enum {
* fpi_device_action_error() function but doing so is not recommended in most
* usecases.
*
* Image drivers must expect a @deactivate call to happen at any point during
* image capture.
* Drivers *must* also handle cancellation properly for any long running
* operation (i.e. any operation that requires capturing). It is entirely fine
* to ignore cancellation requests for short operations (e.g. open/close).
*
* This API is solely intended for drivers. It is purely internal and neither
* API nor ABI stable.
@@ -89,8 +90,8 @@ struct _FpImageDeviceClass
void (*img_open) (FpImageDevice *dev);
void (*img_close) (FpImageDevice *dev);
void (*activate) (FpImageDevice *dev);
void (*change_state) (FpImageDevice *dev,
FpiImageDeviceState state);
void (*change_state) (FpImageDevice *dev,
FpImageDeviceState state);
void (*deactivate) (FpImageDevice *dev);
};

View File

@@ -1,149 +0,0 @@
/*
* FPrint Image - Private APIs
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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 "image"
#include "fpi-image.h"
#include "fpi-log.h"
#include <nbis.h>
#if HAVE_PIXMAN
#include <pixman.h>
#endif
/**
* SECTION: fpi-image
* @title: Internal FpImage
* @short_description: Internal image handling routines
*
* Internal image handling routines. See #FpImage for public routines.
*/
/**
* fpi_std_sq_dev:
* @buf: buffer (usually bitmap, one byte per pixel)
* @size: size of @buffer
*
* Calculates the squared standard deviation of the individual
* pixels in the buffer, as per the following formula:
* |[<!-- -->
* mean = sum (buf[0..size]) / size
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
* ]|
* This function is usually used to determine whether image
* is empty.
*
* Returns: the squared standard deviation for @buffer
*/
gint
fpi_std_sq_dev (const guint8 *buf,
gint size)
{
guint64 res = 0, mean = 0;
gint i;
for (i = 0; i < size; i++)
mean += buf[i];
mean /= size;
for (i = 0; i < size; i++)
{
int dev = (int) buf[i] - mean;
res += dev * dev;
}
return res / size;
}
/**
* fpi_mean_sq_diff_norm:
* @buf1: buffer (usually bitmap, one byte per pixel)
* @buf2: buffer (usually bitmap, one byte per pixel)
* @size: buffer size of smallest buffer
*
* This function calculates the normalized mean square difference of
* two buffers, usually two lines, as per the following formula:
* |[<!-- -->
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
* ]|
*
* This functions is usually used to get numerical difference
* between two images.
*
* Returns: the normalized mean squared difference between @buf1 and @buf2
*/
gint
fpi_mean_sq_diff_norm (const guint8 *buf1,
const guint8 *buf2,
gint size)
{
int res = 0, i;
for (i = 0; i < size; i++)
{
int dev = (int) buf1[i] - (int) buf2[i];
res += dev * dev;
}
return res / size;
}
#if HAVE_PIXMAN
FpImage *
fpi_image_resize (FpImage *orig_img,
guint w_factor,
guint h_factor)
{
int new_width = orig_img->width * w_factor;
int new_height = orig_img->height * h_factor;
pixman_image_t *orig, *resized;
pixman_transform_t transform;
FpImage *newimg;
orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width);
resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width);
pixman_transform_init_identity (&transform);
pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
pixman_image_set_transform (orig, &transform);
pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
pixman_image_composite32 (PIXMAN_OP_SRC,
orig, /* src */
NULL, /* mask */
resized, /* dst */
0, 0, /* src x y */
0, 0, /* mask x y */
0, 0, /* dst x y */
new_width, new_height /* width height */
);
newimg = fp_image_new (new_width, new_height);
newimg->flags = orig_img->flags;
memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
pixman_image_unref (orig);
pixman_image_unref (resized);
return newimg;
}
#endif

View File

@@ -37,7 +37,6 @@ typedef enum {
FPI_IMAGE_V_FLIPPED = 1 << 0,
FPI_IMAGE_H_FLIPPED = 1 << 1,
FPI_IMAGE_COLORS_INVERTED = 1 << 2,
FPI_IMAGE_PARTIAL = 1 << 3,
} FpiImageFlags;
/**

View File

@@ -17,7 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#ifndef __FPI_LOG_H__
#define __FPI_LOG_H__
/**
* SECTION:fpi-log
@@ -93,3 +94,5 @@
* Same as BUG_ON() but is always true.
*/
#define BUG() BUG_ON (1)
#endif

View File

@@ -1,362 +0,0 @@
/*
* FPrint Print handling - Private APIs
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* 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 "print"
#include "fpi-log.h"
#include "fp-print-private.h"
#include "fpi-device.h"
#include "fpi-compat.h"
/**
* SECTION: fpi-print
* @title: Internal FpPrint
* @short_description: Internal fingerprint handling routines
*
* Interaction with prints and their storage. See also the public
* #FpPrint routines.
*/
/**
* fpi_print_add_print:
* @print: A #FpPrint
* @add: Print to append to @print
*
* Appends the single #FPI_PRINT_NBIS print from @add to the collection of
* prints in @print. Both print objects need to be of type #FPI_PRINT_NBIS
* for this to work.
*/
void
fpi_print_add_print (FpPrint *print, FpPrint *add)
{
g_return_if_fail (print->type == FPI_PRINT_NBIS);
g_return_if_fail (add->type == FPI_PRINT_NBIS);
g_assert (add->prints->len == 1);
g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
}
/**
* fpi_print_set_type:
* @print: A #FpPrint
* @type: The newly type of the print data
*
* This function can only be called exactly once. Drivers should
* call it after creating a new print, or to initialize the template
* print passed during enrollment.
*/
void
fpi_print_set_type (FpPrint *print,
FpiPrintType type)
{
g_return_if_fail (FP_IS_PRINT (print));
/* We only allow setting this once! */
g_return_if_fail (print->type == FPI_PRINT_UNDEFINED);
print->type = type;
if (print->type == FPI_PRINT_NBIS)
{
g_assert_null (print->prints);
print->prints = g_ptr_array_new_with_free_func (g_free);
}
g_object_notify (G_OBJECT (print), "fpi-type");
}
/**
* fpi_print_set_device_stored:
* @print: A #FpPrint
* @device_stored: Whether the print is stored on the device or not
*
* Drivers must set this to %TRUE for any print that is really a handle
* for data that is stored on the device itself.
*/
void
fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored)
{
g_return_if_fail (FP_IS_PRINT (print));
print->device_stored = device_stored;
g_object_notify (G_OBJECT (print), "device-stored");
}
/* XXX: This is the old version, but wouldn't it be smarter to instead
* use the highest quality mintutiae? Possibly just using bz_prune from
* upstream? */
static void
minutiae_to_xyt (struct fp_minutiae *minutiae,
int bwidth,
int bheight,
struct xyt_struct *xyt)
{
int i;
struct fp_minutia *minutia;
struct minutiae_struct c[MAX_FILE_MINUTIAE];
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
for (i = 0; i < nmin; i++)
{
minutia = minutiae->list[i];
lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
minutia, bwidth, bheight);
c[i].col[3] = sround (minutia->reliability * 100.0);
if (c[i].col[2] > 180)
c[i].col[2] -= 360;
}
qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
sort_x_y);
for (i = 0; i < nmin; i++)
{
xyt->xcol[i] = c[i].col[0];
xyt->ycol[i] = c[i].col[1];
xyt->thetacol[i] = c[i].col[2];
}
xyt->nrows = nmin;
}
/**
* fpi_print_add_from_image:
* @print: A #FpPrint
* @image: A #FpImage
* @error: Return location for error
*
* Extracts the minutiae from the given image and adds it to @print of
* type #FPI_PRINT_NBIS.
*
* The @image will be kept so that API users can get retrieve it e.g.
* for debugging purposes.
*
* Returns: %TRUE on success
*/
gboolean
fpi_print_add_from_image (FpPrint *print,
FpImage *image,
GError **error)
{
GPtrArray *minutiae;
struct fp_minutiae _minutiae;
struct xyt_struct *xyt;
if (print->type != FPI_PRINT_NBIS || !image)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"Cannot add print data from image!");
return FALSE;
}
minutiae = fp_image_get_minutiae (image);
if (!minutiae || minutiae->len == 0)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_INVALID_DATA,
"No minutiae found in image or not yet detected!");
return FALSE;
}
_minutiae.num = minutiae->len;
_minutiae.list = (struct fp_minutia **) minutiae->pdata;
_minutiae.alloc = minutiae->len;
xyt = g_new0 (struct xyt_struct, 1);
minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
g_ptr_array_add (print->prints, xyt);
g_clear_object (&print->image);
print->image = g_object_ref (image);
g_object_notify (G_OBJECT (print), "image");
return TRUE;
}
/**
* fpi_print_bz3_match:
* @template: A #FpPrint containing one or more prints
* @print: A newly scanned #FpPrint to test
* @bz3_threshold: The BZ3 match threshold
* @error: Return location for error
*
* Match the newly scanned @print (containing exactly one print) against the
* prints contained in @template which will have been stored during enrollment.
*
* Both @template and @print need to be of type #FPI_PRINT_NBIS for this to
* work.
*
* Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
*/
FpiMatchResult
fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
{
struct xyt_struct *pstruct;
gint probe_len;
gint i;
/* XXX: Use a different error type? */
if (template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"It is only possible to match NBIS type print data");
return FPI_MATCH_ERROR;
}
if (print->prints->len != 1)
{
*error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"New print contains more than one print!");
return FPI_MATCH_ERROR;
}
pstruct = g_ptr_array_index (print->prints, 0);
probe_len = bozorth_probe_init (pstruct);
for (i = 0; i < template->prints->len; i++)
{
struct xyt_struct *gstruct;
gint score;
gstruct = g_ptr_array_index (template->prints, i);
score = bozorth_to_gallery (probe_len, pstruct, gstruct);
fp_dbg ("score %d/%d", score, bz3_threshold);
if (score >= bz3_threshold)
return FPI_MATCH_SUCCESS;
}
return FPI_MATCH_FAIL;
}
/**
* fpi_print_generate_user_id:
* @print: #FpPrint to generate the ID for
*
* Generates a string identifier for the represented print. This identifier
* encodes some metadata about the print. It also includes a random string
* and may be assumed to be unique.
*
* This is useful if devices are able to store a string identifier, but more
* storing more metadata may be desirable. In effect, this means the driver
* can provide somewhat more meaningful data to fp_device_list_prints().
*
* The generated ID may be truncated after 23 characters. However, more space
* is required to include the username, and it is recommended to store at
* at least 31 bytes.
*
* The generated format may change in the future. It is versioned though and
* decoding should remain functional.
*
* Returns: A unique string of 23 + strlen(username) characters
*/
gchar *
fpi_print_generate_user_id (FpPrint *print)
{
const gchar *username = NULL;
gchar *user_id = NULL;
const GDate *date;
gint y = 0, m = 0, d = 0;
gint32 rand_id = 0;
g_assert (print);
date = fp_print_get_enroll_date (print);
if (date && g_date_valid (date))
{
y = g_date_get_year (date);
m = g_date_get_month (date);
d = g_date_get_day (date);
}
username = fp_print_get_username (print);
if (!username)
username = "nobody";
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
rand_id = 0;
else
rand_id = g_random_int ();
user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s",
y, m, d,
fp_print_get_finger (print),
rand_id,
username);
return user_id;
}
/**
* fpi_print_fill_from_user_id:
* @print: #FpPrint to fill metadata into
* @user_id: An ID that was likely encoded using fpi_print_generate_user_id()
*
* This is the reverse operation of fpi_print_generate_user_id(), allowing
* the driver to encode some print metadata in a string.
*
* Returns: Whether a valid ID was found
*/
gboolean
fpi_print_fill_from_user_id (FpPrint *print, const char *user_id)
{
g_return_val_if_fail (user_id, FALSE);
/* The format has 24 bytes at the start and some dashes in the right places */
if (g_str_has_prefix (user_id, "FP1-") && strlen (user_id) >= 24 &&
user_id[12] == '-' && user_id[14] == '-' && user_id[23] == '-')
{
g_autofree gchar *copy = g_strdup (user_id);
g_autoptr(GDate) date = NULL;
gint32 date_ymd;
gint32 finger;
gchar *username;
/* Try to parse information from the string. */
copy[12] = '\0';
date_ymd = g_ascii_strtod (copy + 4, NULL);
if (date_ymd > 0)
date = g_date_new_dmy (date_ymd % 100,
(date_ymd / 100) % 100,
date_ymd / 10000);
else
date = g_date_new ();
fp_print_set_enroll_date (print, date);
copy[14] = '\0';
finger = g_ascii_strtoll (copy + 13, NULL, 16);
fp_print_set_finger (print, finger);
/* We ignore the next chunk, it is just random data.
* Then comes the username; nobody is the default if the metadata
* is unknown */
username = copy + 24;
if (strlen (username) > 0 && g_strcmp0 (username, "nobody") != 0)
fp_print_set_username (print, username);
return TRUE;
}
return FALSE;
}

View File

@@ -7,34 +7,34 @@
G_BEGIN_DECLS
/**
* FpiPrintType:
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
* @FPI_PRINT_RAW: A raw print where the data is directly compared
* @FPI_PRINT_NBIS: NBIS minutiae comparison
* FpPrintType:
* @FP_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
* @FP_PRINT_RAW: A raw print where the data is directly compared
* @FP_PRINT_NBIS: NBIS minutiae comparison
*/
typedef enum {
FPI_PRINT_UNDEFINED = 0,
FPI_PRINT_RAW,
FPI_PRINT_NBIS,
} FpiPrintType;
FP_PRINT_UNDEFINED = 0,
FP_PRINT_RAW,
FP_PRINT_NBIS,
} FpPrintType;
/**
* FpiMatchResult:
* @FPI_MATCH_ERROR: An error occurred during matching
* @FPI_MATCH_FAIL: The prints did not match
* @FPI_MATCH_ERROR: An error occured during matching
* @FPI_MATCH_SUCCESS: The prints matched
* @FPI_MATCH_FAIL: The prints did not match
*/
typedef enum {
FPI_MATCH_ERROR = -1, /* -1 for g_task_propagate_int */
FPI_MATCH_FAIL,
FPI_MATCH_ERROR = 0,
FPI_MATCH_SUCCESS,
FPI_MATCH_FAIL,
} FpiMatchResult;
void fpi_print_add_print (FpPrint *print,
FpPrint *add);
void fpi_print_set_type (FpPrint *print,
FpiPrintType type);
void fpi_print_set_type (FpPrint *print,
FpPrintType type);
void fpi_print_set_device_stored (FpPrint *print,
gboolean device_stored);
@@ -47,9 +47,4 @@ FpiMatchResult fpi_print_bz3_match (FpPrint * template,
gint bz3_threshold,
GError **error);
/* Helpers to encode metadata into user ID strings. */
gchar * fpi_print_generate_user_id (FpPrint *print);
gboolean fpi_print_fill_from_user_id (FpPrint *print,
const char *user_id);
G_END_DECLS

View File

@@ -81,7 +81,6 @@
struct _FpiSsm
{
FpDevice *dev;
const char *name;
FpiSsm *parentsm;
gpointer ssm_data;
GDestroyNotify ssm_data_destroy;
@@ -104,29 +103,13 @@ struct _FpiSsm
*
* Allocate a new ssm, with @nr_states states. The @handler callback
* will be called after each state transition.
* This is a macro that calls fpi_ssm_new_full() using the stringified
* version of @nr_states, so will work better with named parameters.
*
* Returns: a new #FpiSsm state machine
*/
/**
* fpi_ssm_new_full:
* @dev: a #fp_dev fingerprint device
* @handler: the callback function
* @nr_states: the number of states
* @machine_name: the name of the state machine (for debug purposes)
*
* Allocate a new ssm, with @nr_states states. The @handler callback
* will be called after each state transition.
*
* Returns: a new #FpiSsm state machine
*/
FpiSsm *
fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states,
const char *machine_name)
fpi_ssm_new (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states)
{
FpiSsm *machine;
@@ -137,7 +120,6 @@ fpi_ssm_new_full (FpDevice *dev,
machine->handler = handler;
machine->nr_states = nr_states;
machine->dev = dev;
machine->name = g_strdup (machine_name);
machine->completed = TRUE;
return machine;
}
@@ -213,9 +195,6 @@ on_delayed_action_cancelled (GCancellable *cancellable,
{
CancelledActionIdleData *data;
fp_dbg ("[%s] %s cancelled delayed state change",
fp_device_get_driver (machine->dev), machine->name);
g_clear_pointer (&machine->timeout, g_source_destroy);
data = g_new0 (CancelledActionIdleData, 1);
@@ -272,7 +251,6 @@ fpi_ssm_free (FpiSsm *machine)
if (machine->ssm_data_destroy)
g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy);
g_clear_pointer (&machine->error, g_error_free);
g_clear_pointer (&machine->name, g_free);
fpi_ssm_clear_delayed_action (machine);
g_free (machine);
}
@@ -281,8 +259,7 @@ fpi_ssm_free (FpiSsm *machine)
static void
__ssm_call_handler (FpiSsm *machine)
{
fp_dbg ("[%s] %s entering state %d", fp_device_get_driver (machine->dev),
machine->name, machine->cur_state);
fp_dbg ("%p entering state %d", machine, machine->cur_state);
machine->handler (machine, machine->dev);
}
@@ -338,10 +315,7 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
{
BUG_ON (parent->timeout);
child->parentsm = parent;
fpi_ssm_clear_delayed_action (parent);
fpi_ssm_clear_delayed_action (child);
g_clear_pointer (&parent->timeout, g_source_destroy);
fpi_ssm_start (child, __subsm_complete);
}
@@ -363,11 +337,9 @@ fpi_ssm_mark_completed (FpiSsm *machine)
machine->completed = TRUE;
if (machine->error)
fp_dbg ("[%s] %s completed with error: %s", fp_device_get_driver (machine->dev),
machine->name, machine->error->message);
fp_dbg ("%p completed with error: %s", machine, machine->error->message);
else
fp_dbg ("[%s] %s completed successfully", fp_device_get_driver (machine->dev),
machine->name);
fp_dbg ("%p completed successfully", machine);
if (machine->callback)
{
GError *error = machine->error ? g_error_copy (machine->error) : NULL;
@@ -411,9 +383,9 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine,
on_device_timeout_complete, cancellable,
machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %s complete %d",
source_name = g_strdup_printf ("[%s] ssm %p complete %d",
fp_device_get_device_id (machine->dev),
machine->name, machine->cur_state + 1);
machine, machine->cur_state + 1);
g_source_set_name (machine->timeout, source_name);
}
@@ -430,15 +402,12 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error)
g_assert (error);
if (machine->error)
{
fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s",
fp_device_get_driver (machine->dev), machine->name, error->message);
fp_warn ("SSM already has an error set, ignoring new error %s", error->message);
g_error_free (error);
return;
}
fp_dbg ("[%s] SSM %s failed in state %d with error: %s",
fp_device_get_driver (machine->dev), machine->name,
machine->cur_state, error->message);
fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message);
machine->error = g_steal_pointer (&error);
fpi_ssm_mark_completed (machine);
}
@@ -475,9 +444,6 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
BUG_ON (machine->completed);
BUG_ON (machine->timeout == NULL);
fp_dbg ("[%s] %s cancelled delayed state change",
fp_device_get_driver (machine->dev), machine->name);
fpi_ssm_clear_delayed_action (machine);
}
@@ -516,9 +482,9 @@ fpi_ssm_next_state_delayed (FpiSsm *machine,
on_device_timeout_next_state, cancellable,
machine, NULL);
source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d",
source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
fp_device_get_device_id (machine->dev),
machine->name, machine->cur_state + 1);
machine, machine->cur_state + 1);
g_source_set_name (machine->timeout, source_name);
}
@@ -582,7 +548,8 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
g_autofree char *source_name = NULL;
g_return_if_fail (machine != NULL);
BUG_ON (state < 0 || state >= machine->nr_states);
BUG_ON (machine->completed);
BUG_ON (machine->timeout != NULL);
data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
data->machine = machine;
@@ -592,9 +559,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
on_device_timeout_jump_to_state,
cancellable, data, g_free);
source_name = g_strdup_printf ("[%s] ssm %s jump to state %d",
source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
fp_device_get_device_id (machine->dev),
machine->name, state);
machine, state);
g_source_set_name (machine->timeout, source_name);
}

View File

@@ -22,6 +22,7 @@
#pragma once
#include "fp-device.h"
#include "fpi-usb-transfer.h"
/* async drv <--> lib comms */
@@ -38,7 +39,7 @@ typedef struct _FpiSsm FpiSsm;
* FpiSsmCompletedCallback:
* @ssm: a #FpiSsm state machine
* @dev: the #fp_dev fingerprint device
* @error: (transfer full): The #GError or %NULL on successful completion
* @error: The #GError or %NULL on successful completion
*
* The callback called when a state machine completes successfully,
* as set when calling fpi_ssm_start().
@@ -59,12 +60,9 @@ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm,
FpDevice *dev);
/* for library and drivers */
#define fpi_ssm_new(dev, handler, nr_states) \
fpi_ssm_new_full (dev, handler, nr_states, #nr_states)
FpiSsm *fpi_ssm_new_full (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states,
const char *machine_name);
FpiSsm *fpi_ssm_new (FpDevice *dev,
FpiSsmHandlerCallback handler,
int nr_states);
void fpi_ssm_free (FpiSsm *machine);
void fpi_ssm_start (FpiSsm *ssm,
FpiSsmCompletedCallback callback);
@@ -100,8 +98,6 @@ int fpi_ssm_get_cur_state (FpiSsm *machine);
/* Callbacks to be used by the driver instead of implementing their own
* logic.
*/
typedef struct _FpiUsbTransfer FpiUsbTransfer;
void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer unused_data,
@@ -110,5 +106,3 @@ void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer weak_ptr,
GError *error);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free)

View File

@@ -105,7 +105,6 @@ fpi_usb_transfer_new (FpDevice * device)
self = g_slice_new0 (FpiUsbTransfer);
self->ref_count = 1;
self->type = FP_TRANSFER_NONE;
self->device = device;
@@ -299,7 +298,7 @@ fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
transfer->free_buffer = free_func;
}
static void
void
transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
@@ -367,7 +366,7 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
*
* Note that #FpiUsbTransfer will be stolen when this function is called.
* So that all associated data will be free'ed automatically, after the
* callback ran unless fpi_usb_transfer_ref() is explicitly called.
* callback ran unless fpi_usb_transfer_ref() is explictly called.
*/
void
fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
@@ -455,7 +454,6 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
GError **error)
{
gboolean res;
gsize actual_length;
g_return_val_if_fail (transfer, FALSE);
@@ -471,7 +469,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->endpoint,
transfer->buffer,
transfer->length,
&actual_length,
&transfer->actual_length,
timeout_ms,
NULL,
error);
@@ -487,7 +485,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->idx,
transfer->buffer,
transfer->length,
&actual_length,
&transfer->actual_length,
timeout_ms,
NULL,
error);
@@ -498,7 +496,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
transfer->endpoint,
transfer->buffer,
transfer->length,
&actual_length,
&transfer->actual_length,
timeout_ms,
NULL,
error);
@@ -513,8 +511,6 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer,
if (!res)
transfer->actual_length = -1;
else
transfer->actual_length = actual_length;
return res;
}

View File

@@ -30,7 +30,8 @@ G_BEGIN_DECLS
#define FPI_USB_ENDPOINT_OUT 0x00
typedef struct _FpiUsbTransfer FpiUsbTransfer;
typedef struct _FpiSsm FpiSsm;
#include "fpi-ssm.h"
typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
FpDevice *dev,
@@ -47,10 +48,10 @@ typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer,
* Type of the transfer.
*/
typedef enum {
FP_TRANSFER_NONE = -1,
FP_TRANSFER_CONTROL = 0,
FP_TRANSFER_BULK = 2,
FP_TRANSFER_INTERRUPT = 3,
FP_TRANSFER_NONE = 0,
FP_TRANSFER_BULK,
FP_TRANSFER_CONTROL,
FP_TRANSFER_INTERRUPT,
} FpiTransferType;
/**
@@ -61,7 +62,7 @@ typedef enum {
* @length: The requested length of the transfer in bytes.
* @actual_length: The actual length of the transfer
* (see also fpi_usb_transfer_set_short_error())
* @buffer: The transferred data.
* @buffer: The transfered data.
*
* Helper for handling USB transfers.
*/

View File

@@ -2,7 +2,7 @@
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Coypright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,18 +31,23 @@ GHashTable *printed = NULL;
static GList *
insert_drivers (GList *list)
{
g_autoptr(GArray) drivers = fpi_get_driver_types ();
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType));
gint i;
fpi_get_driver_types (drivers);
/* Find the best driver to handle this USB device. */
for (i = 0; i < drivers->len; i++)
{
GType driver = g_array_index (drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB)
continue;
{
g_type_class_unref (cls);
continue;
}
for (entry = cls->id_table; entry->vid; entry++)
{
@@ -60,6 +65,8 @@ insert_drivers (GList *list)
list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name));
}
g_type_class_unref (cls);
}
return list;

View File

@@ -2,7 +2,7 @@
* Copyright (C) 2009 Red Hat <mjg@redhat.com>
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2008 Timo Hoenig <thoenig@suse.de>, <thoenig@nouse.net>
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
* Coypright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -96,20 +96,27 @@ print_driver (const FpDeviceClass *cls)
int
main (int argc, char **argv)
{
g_autoptr(GArray) drivers = fpi_get_driver_types ();
g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType));
guint i;
fpi_get_driver_types (drivers);
printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (i = 0; i < drivers->len; i++)
{
GType driver = g_array_index (drivers, GType, i);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver));
if (cls->type != FP_DEVICE_TYPE_USB)
continue;
{
g_type_class_unref (cls);
continue;
}
print_driver (cls);
g_type_class_unref (cls);
}
print_driver (&whitelist);

View File

@@ -1,6 +1,9 @@
LIBFPRINT_2.0.0 {
global:
fp_*;
/* Needs to be public for the listing commands. */
fpi_get_driver_types;
local:
*;
};

View File

@@ -4,43 +4,29 @@ libfprint_sources = [
'fp-image.c',
'fp-print.c',
'fp-image-device.c',
]
libfprint_private_sources = [
'fpi-assembling.c',
'fpi-byte-reader.c',
'fpi-byte-writer.c',
'fpi-device.c',
'fpi-image-device.c',
'fpi-image.c',
'fpi-print.c',
'fpi-ssm.c',
'fpi-usb-transfer.c',
'fpi-byte-reader.c',
'fpi-byte-writer.c',
]
libfprint_public_headers = [
'fp-context.h',
'fp-device.h',
'fp-image-device.h',
'fp-image.h',
'fp-print.h',
]
libfprint_private_headers = [
'fpi-assembling.h',
'fpi-byte-reader.h',
'fpi-byte-utils.h',
'fpi-byte-writer.h',
'fpi-compat.h',
'fpi-context.h',
'fpi-device.h',
'fpi-image-device.h',
'fpi-image.h',
'fpi-log.h',
'fpi-minutiae.h',
'fpi-image-device.h',
'fpi-print.h',
'fpi-usb-transfer.h',
'fpi-ssm.h',
'fpi-byte-reader.h',
'fpi-byte-writer.h',
'fpi-byte-utils.h',
]
nbis_sources = [
@@ -161,12 +147,6 @@ foreach driver: drivers
'drivers/synaptics/bmkt_message.c',
]
endif
if driver == 'goodixmoc'
drivers_sources += [
'drivers/goodixmoc/goodix.c',
'drivers/goodixmoc/goodix_proto.c',
]
endif
endforeach
if aeslib
@@ -183,125 +163,59 @@ other_sources = []
fp_enums = gnome.mkenums_simple('fp-enums',
sources: libfprint_public_headers,
install_header: true,
install_dir: get_option('includedir') / versioned_libname,
)
install_header : true)
fp_enums_h = fp_enums[1]
fpi_enums = gnome.mkenums_simple('fpi-enums',
sources: libfprint_private_headers,
install_header: false,
)
install_header : true)
fpi_enums_h = fpi_enums[1]
enums_dep = declare_dependency(
sources: [ fp_enums_h, fpi_enums_h ]
)
drivers_sources += configure_file(input: 'empty_file',
output: 'fpi-drivers.c',
output: 'fp-drivers.c',
capture: true,
command: [
'echo',
'\n'.join(drivers_type_list + [] + drivers_type_func)
drivers_type_list + '\n\n' + drivers_type_func
])
deps = [
enums_dep,
gio_dep,
glib_dep,
gobject_dep,
gusb_dep,
imaging_dep,
mathlib_dep,
nss_dep,
]
mapfile = 'libfprint.ver'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
# These are empty and only exist so that the include directories are created
# in the build tree. This silences a build time warning.
subdir('nbis/include')
subdir('nbis/libfprint-include')
deps += declare_dependency(include_directories: [
root_inc,
include_directories('nbis/include'),
include_directories('nbis/libfprint-include'),
])
libnbis = static_library('nbis',
nbis_sources,
dependencies: deps,
c_args: cc.get_supported_arguments([
'-Wno-error=redundant-decls',
'-Wno-redundant-decls',
'-Wno-discarded-qualifiers',
]),
install: false)
libfprint_private = static_library('fprint-private',
sources: [
fpi_enums,
libfprint_private_sources,
],
dependencies: deps,
link_with: libnbis,
install: false)
libfprint_drivers = static_library('fprint-drivers',
sources: drivers_sources,
c_args: drivers_cflags,
dependencies: deps,
link_with: libfprint_private,
install: false)
mapfile = files('libfprint.ver')
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
libfprint = library(versioned_libname.split('lib')[1],
sources: [
fp_enums,
libfprint_sources,
other_sources,
],
deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ]
libfprint = library('fprint',
libfprint_sources + fp_enums + fpi_enums +
drivers_sources + nbis_sources + other_sources,
soversion: soversion,
version: libversion,
c_args: common_cflags + drivers_cflags,
include_directories: [
root_inc,
include_directories('nbis/include'),
],
link_args : vflag,
link_depends : mapfile,
link_with: [libfprint_drivers, libfprint_private],
dependencies: deps,
install: true)
libfprint_dep = declare_dependency(link_with: libfprint,
sources: [ fp_enums_h ],
include_directories: root_inc,
dependencies: [
enums_dep,
gio_dep,
glib_dep,
gobject_dep,
gusb_dep,
])
dependencies: [ glib_dep, gusb_dep, gio_dep ])
install_headers(['fprint.h'] + libfprint_public_headers,
subdir: versioned_libname
)
libfprint_private_dep = declare_dependency(
include_directories: include_directories('.'),
link_with: libfprint_private,
dependencies: [
deps,
libfprint_dep,
]
)
install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint')
udev_rules = executable('fprint-list-udev-rules',
'fprint-list-udev-rules.c',
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
include_directories: [
root_inc,
],
dependencies: [ deps, libfprint_dep ],
install: false)
if get_option('udev_rules')
custom_target('udev-rules',
output: '60-@0@-autosuspend.rules'.format(versioned_libname),
output: '60-fprint-autosuspend.rules',
capture: true,
command: [ udev_rules ],
install: true,
@@ -310,8 +224,10 @@ endif
supported_devices = executable('fprint-list-supported-devices',
'fprint-list-supported-devices.c',
dependencies: libfprint_private_dep,
link_with: libfprint_drivers,
include_directories: [
root_inc,
],
dependencies: [ deps, libfprint_dep ],
install: false)
@@ -322,7 +238,7 @@ if get_option('introspection')
libfprint_public_headers,
libfprint_sources,
],
nsversion : '@0@.0'.format(soversion),
nsversion : '2.0',
namespace : 'FPrint',
symbol_prefix : 'fp_',
identifier_prefix : 'Fp',
@@ -333,7 +249,6 @@ if get_option('introspection')
link_with : libfprint,
dependencies : [
gio_dep,
gobject_dep,
gusb_dep,
],
includes : [

View File

@@ -896,7 +896,7 @@ for ( k = 0; k < np - 1; k++ ) {
for ( i = 0; i < tot; i++ ) {
int colp_value = colp[ bz_y[i]-1 ][0];
int colp_value = colp[ y[i]-1 ][0];
if ( colp_value < 0 ) {
kk += colp_value;
n++;
@@ -933,7 +933,7 @@ for ( k = 0; k < np - 1; k++ ) {
kk = 0;
for ( i = 0; i < tot; i++ ) {
int diff = colp[ bz_y[i]-1 ][0] - jj;
int diff = colp[ y[i]-1 ][0] - jj;
j = SQUARED( diff );
@@ -942,7 +942,7 @@ for ( k = 0; k < np - 1; k++ ) {
if ( j > TXS && j < CTXS )
kk++;
else
bz_y[i-kk] = bz_y[i];
y[i-kk] = y[i];
} /* END FOR i */
tot -= kk; /* Adjust the total edge pairs TOT based on # of edge pairs skipped */
@@ -958,7 +958,7 @@ for ( k = 0; k < np - 1; k++ ) {
for ( i = tot-1 ; i >= 0; i-- ) {
int idx = bz_y[i] - 1;
int idx = y[i] - 1;
if ( rk[idx] == 0 ) {
sc[idx] = -1;
} else {
@@ -976,7 +976,7 @@ for ( k = 0; k < np - 1; k++ ) {
int pd = 0;
for ( i = 0; i < tot; i++ ) {
int idx = bz_y[i] - 1;
int idx = y[i] - 1;
for ( ii = 1; ii < 4; ii++ ) {
@@ -1476,7 +1476,7 @@ return match_score;
/* extern int rk[ RK_SIZE ]; */
/* extern int cp[ CP_SIZE ]; */
/* extern int rp[ RP_SIZE ]; */
/* extern int bz_y[ Y_SIZE ]; */
/* extern int y[ Y_SIZE ]; */
void bz_sift(
int * ww, /* INPUT and OUTPUT; endpoint groups index; *ww may be bumped by one or by two */
@@ -1507,7 +1507,7 @@ if ( n == 0 && t == 0 ) {
if ( sc[kx-1] != ftt ) {
bz_y[ (*tot)++ ] = kx;
y[ (*tot)++ ] = kx;
rk[kx-1] = sc[kx-1];
sc[kx-1] = ftt;
}
@@ -1553,7 +1553,7 @@ if ( n == l ) {
qq[*qh] = kz;
zz[kz-1] = (*qh)++;
}
bz_y[(*tot)++] = kx;
y[(*tot)++] = kx;
rk[kx-1] = sc[kx-1];
sc[kx-1] = ftt;
}
@@ -1697,12 +1697,12 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
}
t = 0;
bz_y[0] = lim;
y[0] = lim;
cp[0] = 1;
b = 0;
n = 1;
do { /* looping until T < 0 ... */
if (bz_y[t] - cp[t] > 1 ) {
if ( y[t] - cp[t] > 1 ) {
k = sct[cp[t]][t];
j = ctt[k] + 1;
for ( i = 0; i < j; i++ ) {
@@ -1715,25 +1715,25 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
do {
while ( rp[jj] < sct[kk][t] && jj < j )
jj++;
while ( rp[jj] > sct[kk][t] && kk < bz_y[t] )
while ( rp[jj] > sct[kk][t] && kk < y[t] )
kk++;
while ( rp[jj] == sct[kk][t] && kk < bz_y[t] && jj < j ) {
while ( rp[jj] == sct[kk][t] && kk < y[t] && jj < j ) {
sct[k][t+1] = sct[kk][t];
k++;
kk++;
jj++;
}
} while ( kk < bz_y[t] && jj < j );
} while ( kk < y[t] && jj < j );
t++;
cp[t] = 1;
bz_y[t] = k;
y[t] = k;
b = t;
n = 1;
} else {
int tot = 0;
lim = bz_y[t];
lim = y[t];
for ( i = n-1; i < lim; i++ ) {
tot += ct[ sct[i][t] ];
}
@@ -1750,7 +1750,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
{
int rk_index = b;
lim = bz_y[t];
lim = y[t];
for ( i = n-1; i < lim; ) {
rk[ rk_index++ ] = sct[ i++ ][ t ];
}
@@ -1760,7 +1760,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of
t--;
if ( t >= 0 ) {
++cp[t];
n = bz_y[t];
n = y[t];
}
} /* END IF */

View File

@@ -102,7 +102,7 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
int rf[RF_SIZE_1][RF_SIZE_2];
int cf[CF_SIZE_1][CF_SIZE_2];
int bz_y[20000];
int y[20000];
#else
int rq[ RQ_SIZE ] = {};
int tq[ TQ_SIZE ] = {};
@@ -122,6 +122,6 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ];
int rf[RF_SIZE_1][RF_SIZE_2] = {};
int cf[CF_SIZE_1][CF_SIZE_2] = {};
int bz_y[20000] = {};
int y[20000] = {};
#endif

Some files were not shown because too many files have changed in this diff Show More