diff --git a/NEWS b/NEWS index 91351eea..34d6cc2e 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,26 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +2018-12-14: v0.99.0 release +* Library: + - All the internal API for device driver writers is now covered by the + documentation and has been enhanced to make it easier to write drivers + - Update internal NBIS fingerprint data processing library to one that's + nearly 10 years newer + - Re-add accessor for minutia coordinates which was used in the very + old fprint_demo program, but also by our new GTK+ test program (see below) + - Fix a crash when too many minutiae were detected in a capture + +* Drivers: + - Support more devices in the Elan driver, stability improvements + +* Tools: + - Add a test GTK+ application that will eventually be used for testing + drivers without modifying the OS installed version. Note that this + application currently requires manually changing permissions of USB + devices, this will be fixed when the infrastructure exists to access + those devices without additional permissions, as a normal user. + 2018-07-15: v0.8.2 release * Drivers: - Add USB ID for TNP Nano USB Fingerprint Reader diff --git a/README b/README index c54fb2c9..fbf76705 100644 --- a/README +++ b/README @@ -39,3 +39,13 @@ We include bozorth3 from the US export controlled distribution. We have determined that it is fine to ship bozorth3 in an open source project, see https://fprint.freedesktop.org/us-export-control.html +## Historical links + +Older versions of libfprint are available at: +https://sourceforge.net/projects/fprint/files/ + +Historical mailing-list archives: +http://www.reactivated.net/fprint_list_archives/ + +Historical website: +http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/ diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c new file mode 100644 index 00000000..b23e38dd --- /dev/null +++ b/demo/gtk-libfprint-test.c @@ -0,0 +1,514 @@ +/* + * Example libfprint GTK+ image capture program + * Copyright (C) 2018 Bastien Nocera + * + * 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 "config.h" + +#include +#include + +#include "loop.h" + +typedef GtkApplication LibfprintDemo; +typedef GtkApplicationClass LibfprintDemoClass; + +G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION) + +typedef enum { + IMAGE_DISPLAY_NONE = 0, + IMAGE_DISPLAY_MINUTIAE = 1 << 0, + IMAGE_DISPLAY_BINARY = 1 << 1 +} ImageDisplayFlags; + +typedef struct { + GtkApplicationWindow parent_instance; + + GtkWidget *header_bar; + GtkWidget *mode_stack; + GtkWidget *capture_button; + GtkWidget *capture_image; + GtkWidget *spinner; + GtkWidget *instructions; + + struct fp_dscv_dev *ddev; + struct fp_dev *dev; + + struct fp_img *img; + ImageDisplayFlags img_flags; +} LibfprintDemoWindow; + +typedef GtkApplicationWindowClass LibfprintDemoWindowClass; + +G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW) + +typedef enum { + EMPTY_MODE, + NOIMAGING_MODE, + CAPTURE_MODE, + SPINNER_MODE, + ERROR_MODE +} LibfprintDemoMode; + +static void libfprint_demo_set_mode (LibfprintDemoWindow *win, + LibfprintDemoMode mode); + +static void +pixbuf_destroy (guchar *pixels, gpointer data) +{ + if (pixels == NULL) + return; + g_free (pixels); +} + +static unsigned char * +img_to_rgbdata (struct fp_img *img, + int width, + int height) +{ + int size = width * height; + unsigned char *imgdata = fp_img_get_data (img); + unsigned char *rgbdata = g_malloc (size * 3); + size_t i; + size_t rgb_offset = 0; + + for (i = 0; i < size; i++) { + unsigned char pixel = imgdata[i]; + + rgbdata[rgb_offset++] = pixel; + rgbdata[rgb_offset++] = pixel; + rgbdata[rgb_offset++] = pixel; + } + + return rgbdata; +} + +static void +plot_minutiae (unsigned char *rgbdata, + int width, + int height, + struct fp_minutia **minlist, + int nr_minutiae) +{ + int i; +#define write_pixel(num) do { \ + rgbdata[((num) * 3)] = 0xff; \ + rgbdata[((num) * 3) + 1] = 0; \ + rgbdata[((num) * 3) + 2] = 0; \ + } while(0) + + for (i = 0; i < nr_minutiae; i++) { + struct fp_minutia *min = minlist[i]; + int x, y; + size_t pixel_offset; + + fp_minutia_get_coords(min, &x, &y); + pixel_offset = (y * width) + x; + write_pixel(pixel_offset - 2); + write_pixel(pixel_offset - 1); + write_pixel(pixel_offset); + write_pixel(pixel_offset + 1); + write_pixel(pixel_offset + 2); + + write_pixel(pixel_offset - (width * 2)); + write_pixel(pixel_offset - (width * 1) - 1); + write_pixel(pixel_offset - (width * 1)); + write_pixel(pixel_offset - (width * 1) + 1); + write_pixel(pixel_offset + (width * 1) - 1); + write_pixel(pixel_offset + (width * 1)); + write_pixel(pixel_offset + (width * 1) + 1); + write_pixel(pixel_offset + (width * 2)); + } +} + +static GdkPixbuf * +img_to_pixbuf (struct fp_img *img, + ImageDisplayFlags flags) +{ + int width; + int height; + unsigned char *rgbdata; + + width = fp_img_get_width (img); + height = fp_img_get_height (img); + + if (flags & IMAGE_DISPLAY_BINARY) { + struct fp_img *binary; + binary = fp_img_binarize (img); + rgbdata = img_to_rgbdata (binary, width, height); + fp_img_free (binary); + } else { + rgbdata = img_to_rgbdata (img, width, height); + } + + if (flags & IMAGE_DISPLAY_MINUTIAE) { + struct fp_minutia **minlist; + int nr_minutiae; + + minlist = fp_img_get_minutiae (img, &nr_minutiae); + plot_minutiae (rgbdata, width, height, minlist, nr_minutiae); + } + + return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB, + FALSE, 8, width, height, + width * 3, pixbuf_destroy, + NULL); +} + +static void +update_image (LibfprintDemoWindow *win) +{ + GdkPixbuf *pixbuf; + + if (win->img == NULL) { + gtk_image_clear (GTK_IMAGE (win->capture_image)); + return; + } + + g_debug ("Updating image, minutiae %s, binary mode %s", + win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden", + win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off"); + pixbuf = img_to_pixbuf (win->img, win->img_flags); + gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf); + g_object_unref (pixbuf); +} + +static void +libfprint_demo_set_spinner_label (LibfprintDemoWindow *win, + const char *message) +{ + char *label; + + label = g_strdup_printf ("%s", message); + gtk_label_set_markup (GTK_LABEL (win->instructions), label); + g_free (label); +} + +static void +libfprint_demo_set_capture_label (LibfprintDemoWindow *win) +{ + struct fp_driver *drv; + enum fp_scan_type scan_type; + const char *message; + + drv = fp_dscv_dev_get_driver (win->ddev); + scan_type = fp_driver_get_scan_type(drv); + + switch (scan_type) { + case FP_SCAN_TYPE_PRESS: + message = "Place your finger on the fingerprint reader"; + break; + case FP_SCAN_TYPE_SWIPE: + message = "Swipe your finger across the fingerprint reader"; + break; + default: + g_assert_not_reached (); + } + + libfprint_demo_set_spinner_label (win, message); +} + +static void +dev_capture_start_cb (struct fp_dev *dev, + int result, + struct fp_img *img, + void *user_data) +{ + LibfprintDemoWindow *win = user_data; + + if (result < 0) { + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } + + fp_async_capture_stop (dev, NULL, NULL); + + win->img = img; + update_image (win); + + libfprint_demo_set_mode (win, CAPTURE_MODE); +} + +static void +dev_open_cb (struct fp_dev *dev, int status, void *user_data) +{ + LibfprintDemoWindow *win = user_data; + int r; + + if (status < 0) { + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } + + libfprint_demo_set_capture_label (win); + + win->dev = dev; + r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data); + if (r < 0) { + g_warning ("fp_async_capture_start failed: %d", r); + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } +} + +static void +activate_capture (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + LibfprintDemoWindow *win = user_data; + int r; + + libfprint_demo_set_mode (win, SPINNER_MODE); + g_clear_pointer (&win->img, fp_img_free); + + if (win->dev != NULL) { + dev_open_cb (win->dev, 0, user_data); + return; + } + + libfprint_demo_set_spinner_label (win, "Opening fingerprint reader"); + + r = fp_async_dev_open (win->ddev, dev_open_cb, user_data); + if (r < 0) { + g_warning ("fp_async_dev_open failed: %d", r); + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } +} + +static void +activate_quit (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GtkApplication *app = user_data; + GtkWidget *win; + GList *list, *next; + + list = gtk_application_get_windows (app); + while (list) + { + win = list->data; + next = list->next; + + gtk_widget_destroy (GTK_WIDGET (win)); + + list = next; + } +} + +static void +activate_show_minutiae (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + LibfprintDemoWindow *win = user_data; + GVariant *state; + gboolean new_state; + + state = g_action_get_state (G_ACTION (action)); + new_state = !g_variant_get_boolean (state); + g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); + g_variant_unref (state); + + if (new_state) + win->img_flags |= IMAGE_DISPLAY_MINUTIAE; + else + win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE; + + update_image (win); +} + +static void +activate_show_binary (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + LibfprintDemoWindow *win = user_data; + GVariant *state; + gboolean new_state; + + state = g_action_get_state (G_ACTION (action)); + new_state = !g_variant_get_boolean (state); + g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); + g_variant_unref (state); + + if (new_state) + win->img_flags |= IMAGE_DISPLAY_BINARY; + else + win->img_flags &= ~IMAGE_DISPLAY_BINARY; + + update_image (win); +} + +static void +change_show_minutiae_state (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + g_simple_action_set_state (action, state); +} + +static void +change_show_binary_state (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + g_simple_action_set_state (action, state); +} + +static GActionEntry app_entries[] = { + { "quit", activate_quit, NULL, NULL, NULL }, +}; + +static GActionEntry win_entries[] = { + { "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state }, + { "show-binary", activate_show_binary, NULL, "false", change_show_binary_state }, + { "capture", activate_capture, NULL, NULL, NULL } +}; + +static void +activate (GApplication *app) +{ + LibfprintDemoWindow *window; + + window = g_object_new (libfprint_demo_window_get_type (), + "application", app, + NULL); + gtk_widget_show (GTK_WIDGET (window)); +} + +static void +libfprint_demo_set_mode (LibfprintDemoWindow *win, + LibfprintDemoMode mode) +{ + struct fp_driver *drv; + char *title; + + switch (mode) { + case EMPTY_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + case NOIMAGING_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + case CAPTURE_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode"); + gtk_widget_set_sensitive (win->capture_button, TRUE); + + drv = fp_dscv_dev_get_driver (win->ddev); + title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv)); + gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title); + g_free (title); + + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + case SPINNER_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_spinner_start (GTK_SPINNER (win->spinner)); + break; + case ERROR_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + default: + g_assert_not_reached (); + } +} + +static void +libfprint_demo_init (LibfprintDemo *app) +{ + g_action_map_add_action_entries (G_ACTION_MAP (app), + app_entries, G_N_ELEMENTS (app_entries), + app); +} + +static void +libfprint_demo_class_init (LibfprintDemoClass *class) +{ + GApplicationClass *app_class = G_APPLICATION_CLASS (class); + + app_class->activate = activate; +} + +static void +libfprint_demo_window_init (LibfprintDemoWindow *window) +{ + struct fp_dscv_dev **discovered_devs; + + gtk_widget_init_template (GTK_WIDGET (window)); + gtk_window_set_default_size (GTK_WINDOW (window), 700, 500); + + g_action_map_add_action_entries (G_ACTION_MAP (window), + win_entries, G_N_ELEMENTS (win_entries), + window); + + if (fp_init () < 0) { + libfprint_demo_set_mode (window, ERROR_MODE); + return; + } + + setup_pollfds (); + + discovered_devs = fp_discover_devs(); + if (!discovered_devs) + return; + + if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) { + libfprint_demo_set_mode (window, NOIMAGING_MODE); + return; + } + + window->ddev = discovered_devs[0]; + libfprint_demo_set_mode (window, CAPTURE_MODE); +} + +static void +libfprint_demo_window_class_init (LibfprintDemoWindowClass *class) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui"); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions); + + //FIXME setup dispose +} + +int main (int argc, char **argv) +{ + GtkApplication *app; + + app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (), + "application-id", "org.freedesktop.libfprint.Demo", + "flags", G_APPLICATION_FLAGS_NONE, + NULL)); + + return g_application_run (G_APPLICATION (app), 0, NULL); +} diff --git a/demo/gtk-libfprint-test.gresource.xml b/demo/gtk-libfprint-test.gresource.xml new file mode 100644 index 00000000..15408374 --- /dev/null +++ b/demo/gtk-libfprint-test.gresource.xml @@ -0,0 +1,6 @@ + + + + gtk-libfprint-test.ui + + diff --git a/demo/gtk-libfprint-test.ui b/demo/gtk-libfprint-test.ui new file mode 100644 index 00000000..0691620d --- /dev/null +++ b/demo/gtk-libfprint-test.ui @@ -0,0 +1,351 @@ + + + + + + + +
+ + Show Minutiae + win.show-minutiae + + + Show Binary + win.show-binary + +
+
+
diff --git a/demo/loop.c b/demo/loop.c new file mode 100644 index 00000000..81dd62ef --- /dev/null +++ b/demo/loop.c @@ -0,0 +1,196 @@ +/* + * fprint D-Bus daemon + * Copyright (C) 2008 Daniel Drake + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "loop.h" + +struct fdsource { + GSource source; + GSList *pollfds; +}; + +static gboolean source_prepare(GSource *source, gint *timeout) +{ + int r; + struct timeval tv; + + r = fp_get_next_timeout(&tv); + if (r == 0) { + *timeout = -1; + return FALSE; + } + + if (!timerisset(&tv)) + return TRUE; + + *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + return FALSE; +} + +static gboolean source_check(GSource *source) +{ + struct fdsource *_fdsource = (struct fdsource *) source; + GSList *l; + struct timeval tv; + int r; + + if (!_fdsource->pollfds) + return FALSE; + + for (l = _fdsource->pollfds; l != NULL; l = l->next) { + GPollFD *pollfd = l->data; + + if (pollfd->revents) + return TRUE; + } + + r = fp_get_next_timeout(&tv); + if (r == 1 && !timerisset(&tv)) + return TRUE; + + return FALSE; +} + +static gboolean source_dispatch(GSource *source, GSourceFunc callback, + gpointer data) +{ + struct timeval zerotimeout = { + .tv_sec = 0, + .tv_usec = 0, + }; + + /* FIXME error handling */ + fp_handle_events_timeout(&zerotimeout); + + /* FIXME whats the return value used for? */ + return TRUE; +} + +static void source_finalize(GSource *source) +{ + struct fdsource *_fdsource = (struct fdsource *) source; + GSList *l; + + if (!_fdsource->pollfds) + return; + + for (l = _fdsource->pollfds; l != NULL; l = l->next) { + GPollFD *pollfd = l->data; + + g_source_remove_poll((GSource *) _fdsource, pollfd); + g_slice_free(GPollFD, pollfd); + _fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l); + } + + g_slist_free(_fdsource->pollfds); +} + +static GSourceFuncs sourcefuncs = { + .prepare = source_prepare, + .check = source_check, + .dispatch = source_dispatch, + .finalize = source_finalize, +}; + +static struct fdsource *fdsource = NULL; + +static void pollfd_add(int fd, short events) +{ + GPollFD *pollfd; + + pollfd = g_slice_new(GPollFD); + pollfd->fd = fd; + pollfd->events = 0; + pollfd->revents = 0; + if (events & POLLIN) + pollfd->events |= G_IO_IN; + if (events & POLLOUT) + pollfd->events |= G_IO_OUT; + + fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd); + g_source_add_poll((GSource *) fdsource, pollfd); +} + +static void pollfd_added_cb(int fd, short events) +{ + g_debug("now monitoring fd %d", fd); + pollfd_add(fd, events); +} + +static void pollfd_removed_cb(int fd) +{ + GSList *l; + + g_debug("no longer monitoring fd %d", fd); + + if (!fdsource->pollfds) { + g_debug("cannot remove from list as list is empty?"); + return; + } + + for (l = fdsource->pollfds; l != NULL; l = l->next) { + GPollFD *pollfd = l->data; + + if (pollfd->fd != fd) + continue; + + g_source_remove_poll((GSource *) fdsource, pollfd); + g_slice_free(GPollFD, pollfd); + fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l); + return; + } + + g_error("couldn't find fd %d in list\n", fd); +} + +int setup_pollfds(void) +{ + ssize_t numfds; + size_t i; + struct fp_pollfd *fpfds; + GSource *gsource; + + gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource)); + fdsource = (struct fdsource *) gsource; + fdsource->pollfds = NULL; + + numfds = fp_get_pollfds(&fpfds); + if (numfds < 0) { + if (fpfds) + free(fpfds); + return (int) numfds; + } else if (numfds > 0) { + for (i = 0; i < numfds; i++) { + struct fp_pollfd *fpfd = &fpfds[i]; + pollfd_add(fpfd->fd, fpfd->events); + } + } + + free(fpfds); + fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb); + g_source_attach(gsource, NULL); + return 0; +} diff --git a/demo/loop.h b/demo/loop.h new file mode 100644 index 00000000..0266bfbd --- /dev/null +++ b/demo/loop.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2008 Daniel Drake + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef POLL_H + +#define POLL_H + +int setup_pollfds(void); + +#endif + diff --git a/demo/meson.build b/demo/meson.build new file mode 100644 index 00000000..1f0b537d --- /dev/null +++ b/demo/meson.build @@ -0,0 +1,30 @@ +gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml', + source_dir : '.', + c_name : 'gtk_test') + +prefix = get_option('prefix') +bindir = join_paths(prefix, get_option('bindir')) +datadir = join_paths(prefix, get_option('datadir')) + +executable('gtk-libfprint-test', + [ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ], + dependencies: [ libfprint_dep, gtk_dep ], + include_directories: [ + root_inc, + ], + c_args: [ common_cflags, + '-DPACKAGE_VERSION="' + meson.project_version() + '"' ], + install: true, + install_dir: bindir) + +appdata = 'org.freedesktop.libfprint.Demo.appdata.xml' +install_data(appdata, + install_dir: join_paths(datadir, 'metainfo')) + +desktop = 'org.freedesktop.libfprint.Demo.desktop' +install_data(desktop, + install_dir: join_paths(datadir, 'applications')) + +icon = 'org.freedesktop.libfprint.Demo.png' +install_data(icon, + install_dir: join_paths(datadir, 'icons')) diff --git a/demo/org.freedesktop.libfprint.Demo.appdata.xml b/demo/org.freedesktop.libfprint.Demo.appdata.xml new file mode 100644 index 00000000..4cf57678 --- /dev/null +++ b/demo/org.freedesktop.libfprint.Demo.appdata.xml @@ -0,0 +1,28 @@ + + + org.freedesktop.libfprint.Demo.desktop + Fingerprint Reader Demo + Test fingerprint readers + CC0-1.0 + LGPL-2.1+ + +

+ Fingerprint Reader Demo is a test application for the libfprint + fingerprint reader library. Its purpose is to test drivers, new and old, + in a sandbox, to make sure that the drivers and associated functions + work correctly. +

+

+ Fingerprint Reader Demo does not modify the system, or replace integration + in desktop environments. +

+
+ https://fprint.freedesktop.org + + https://git.gnome.org/browse/totem/plain/data/appdata/ss-main.png + https://git.gnome.org/browse/totem/plain/data/appdata/ss-music-playlist.png + + hadess@hadess.net + + libfprint +
diff --git a/demo/org.freedesktop.libfprint.Demo.desktop b/demo/org.freedesktop.libfprint.Demo.desktop new file mode 100644 index 00000000..3368b6e3 --- /dev/null +++ b/demo/org.freedesktop.libfprint.Demo.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name=Fingerprint Reader Demo +Comment=Test fingerprint readers +Keywords=finger;print;fingerprint;fprint;demo;driver;reader; +Exec=gtk-libfprint-test +Icon=org.freedesktop.libfprint.Demo +Terminal=false +Type=Application +Categories=GTK;GNOME;Development;System; +StartupNotify=true diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json new file mode 100644 index 00000000..cbb4046f --- /dev/null +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -0,0 +1,51 @@ +{ + "app-id": "org.freedesktop.libfprint.Demo", + "runtime": "org.gnome.Platform", + "runtime-version": "master", + "sdk": "org.gnome.Sdk", + "command": "gtk-libfprint-test", + "finish-args": [ + /* X11 + XShm access */ + "--share=ipc", "--socket=x11", + /* Wayland access */ + "--socket=wayland", + /* OpenGL access */ + "--device=dri", + /* USB access */ + "--device=all" + ], + "cleanup": [ "/include", "/lib/pkgconfig/" ], + "modules": [ + { + "name": "libusb", + "config-opts": [ "--disable-static", "--disable-udev" ], + "cleanup": [ + "/lib/*.la", + "/lib/pkgconfig", + "/include" + ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/libusb/libusb/archive/v1.0.22.tar.gz", + "sha256": "3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48" + } + ], + "post-install": [ + "install -Dm644 COPYING /app/share/licenses/libusb/COPYING" + ] + }, + { + "name": "libfprint", + "buildsystem": "meson", + "config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ], + "sources": [ + { + "type": "git", + "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git", + "branch": "wip/hadess/gtk-example" + } + ] + } + ] +} diff --git a/demo/org.freedesktop.libfprint.Demo.png b/demo/org.freedesktop.libfprint.Demo.png new file mode 100644 index 00000000..b27672a9 Binary files /dev/null and b/demo/org.freedesktop.libfprint.Demo.png differ diff --git a/doc/libfprint-docs.xml b/doc/libfprint-docs.xml index e56f4b77..3ef995b7 100644 --- a/doc/libfprint-docs.xml +++ b/doc/libfprint-docs.xml @@ -24,7 +24,7 @@ - API Documentation + Library API Documentation @@ -36,11 +36,31 @@ - API Index diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt index 77cb0c38..556ea723 100644 --- a/doc/libfprint-sections.txt +++ b/doc/libfprint-sections.txt @@ -1,8 +1,9 @@ -fprint.h
+fprint.h events Initialisation and events handling +LIBFPRINT_DEPRECATED fp_set_debug fp_init fp_exit @@ -17,6 +18,7 @@ fp_set_pollfd_notifiers
+fprint.h discovery Device discovery fp_dscv_dev @@ -32,15 +34,18 @@ fp_dscv_dev_for_dscv_print
+fprint.h drv fp_driver fp_driver_get_name fp_driver_get_full_name fp_driver_get_driver_id fp_driver_get_scan_type +fp_driver_supports_imaging
+fprint.h dev fp_dev fp_scan_type @@ -91,10 +96,10 @@ fp_async_capture_stop
+fprint.h print_data fp_finger fp_print_data -fp_print_data fp_print_data_get_data fp_print_data_from_data fp_print_data_save @@ -107,6 +112,7 @@ fp_print_data_get_devtype
+fprint.h dscv_print fp_dscv_print fp_discover_prints @@ -118,6 +124,7 @@ fp_dscv_print_delete
+fprint.h img fp_img fp_minutia @@ -129,8 +136,136 @@ fp_img_save_to_file fp_img_standardize fp_img_binarize fp_img_get_minutiae +fp_minutia_get_coords
-poll +fpi-log.h +fpi-log +fp_dbg +fp_info +fp_warn +fp_err +BUG_ON +BUG +
+ +
+fpi-ssm.h +fpi-ssm +fpi_ssm +ssm_completed_fn +ssm_handler_fn + +fpi_ssm_new +fpi_ssm_free +fpi_ssm_start +fpi_ssm_start_subsm + +fpi_ssm_next_state +fpi_ssm_next_state_timeout_cb +fpi_ssm_jump_to_state +fpi_ssm_mark_completed +fpi_ssm_mark_failed +fpi_ssm_get_user_data +fpi_ssm_get_error +fpi_ssm_get_cur_state +
+ +
+fpi-poll.h +fpi-poll +fpi_timeout +fpi_timeout_fn +fpi_timeout_add +fpi_timeout_set_name +fpi_timeout_cancel +
+ +
+fpi-dev.h +fpi-dev +fp_img_dev + +FP_DEV +FP_IMG_DEV +fp_dev_set_instance_data +FP_INSTANCE_DATA + +fpi_dev_get_usb_dev +fpi_dev_get_verify_data +fpi_dev_set_nr_enroll_stages +
+ +
+fpi-dev-img.h +fpi-dev-img +fp_imgdev_action +fp_imgdev_state +fp_imgdev_enroll_state + +fpi_imgdev_abort_scan +fpi_imgdev_activate_complete +fpi_imgdev_close_complete +fpi_imgdev_deactivate_complete +fpi_imgdev_get_action +fpi_imgdev_get_action_result +fpi_imgdev_get_action_state +fpi_imgdev_image_captured +fpi_imgdev_open_complete +fpi_imgdev_report_finger_status +fpi_imgdev_session_error +fpi_imgdev_set_action_result +
+ +
+fpi-core.h +fpi-core +usb_id +fp_driver_type +
+ +
+fpi-core.h +fpi-core-img +FpiImgDriverFlags +fp_img_driver +
+ +
+fpi-img.h +fpi-img +FpiImgFlags + +fpi_img_new +fpi_img_new_for_imgdev +fpi_img_realloc +fpi_img_resize + +fpi_std_sq_dev +fpi_mean_sq_diff_norm +
+ +
+fpi-assembling.h +fpi-assembling +fpi_frame +fpi_frame_asmbl_ctx +fpi_line_asmbl_ctx + +fpi_do_movement_estimation +fpi_assemble_frames +fpi_assemble_lines +
+ +
+fpi-usb.h +fpi-usb +fpi_usb_transfer + +fpi_usb_transfer_cb_fn +fpi_usb_alloc +fpi_usb_fill_bulk_transfer +fpi_usb_submit_transfer +fpi_usb_cancel_transfer
diff --git a/doc/meson.build b/doc/meson.build index 48358c8e..37d515d8 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -6,6 +6,9 @@ private_headers = [ 'aeslib.h', 'assembling.h', 'fp_internal.h', + 'nbis-helpers.h', + 'fpi-async.h', + 'fpi-data.h', # Drivers 'aes1660.h', @@ -16,6 +19,7 @@ private_headers = [ 'aesx660.h', 'driver_ids.h', 'elan.h', + 'upek_proto.h', 'upeksonly.h', 'upektc.h', 'upektc_img.h', @@ -32,6 +36,7 @@ private_headers = [ 'log.h', 'bz_array.h', 'lfs.h', + 'mytime.h', ] html_images = [ @@ -54,7 +59,6 @@ gnome.gtkdoc('libfprint', content_files: content_files, expand_content_files: expand_content_files, scan_args: [ - '--rebuild-types', '--ignore-decorators=API_EXPORTED', '--ignore-headers=' + ' '.join(private_headers), ], diff --git a/libfprint/assembling.h b/libfprint/assembling.h deleted file mode 100644 index 5c1c9988..00000000 --- a/libfprint/assembling.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Image assembling routines - * Shared functions between libfprint Authentec drivers - * Copyright (C) 2007 Daniel Drake - * Copyright (C) 2015 Vasily Khoruzhick - * - * 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 - */ - -#ifndef __ASSEMBLING_H__ -#define __ASSEMBLING_H__ - -#include - -struct fpi_frame { - int delta_x; - int delta_y; - unsigned char data[0]; -}; - -struct fpi_frame_asmbl_ctx { - unsigned frame_width; - unsigned frame_height; - unsigned image_width; - unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *frame, - unsigned x, - unsigned y); -}; - -void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t stripes_len); - -struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t stripes_len); - -struct fpi_line_asmbl_ctx { - unsigned line_width; - unsigned max_height; - unsigned resolution; - unsigned median_filter_size; - unsigned max_search_offset; - int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx, - GSList *line1, GSList *line2); - unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx, - GSList *line, - unsigned x); -}; - -struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, - GSList *lines, size_t lines_len); - -#endif diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index f307a3bc..1e7b3b9b 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -44,6 +44,9 @@ static int adjust_gain(unsigned char *buffer, int status); #define BULK_TIMEOUT 4000 +#define FINGER_DETECTION_LEN 19 +#define STRIP_CAPTURE_LEN 665 + /* * The AES1610 is an imaging device using a swipe-type sensor. It samples * the finger at preprogrammed intervals, sending a 128x8 frame to the @@ -101,12 +104,12 @@ static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_ /* check that read succeeded but ignore all data */ static void generic_ignore_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); else fpi_ssm_next_state(ssm); @@ -117,29 +120,22 @@ static void generic_ignore_data_cb(struct libusb_transfer *transfer) static void generic_write_regv_cb(struct fp_img_dev *dev, int result, void *user_data) { - struct fpi_ssm *ssm = user_data; + fpi_ssm *ssm = user_data; if (result == 0) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_aborted(ssm, result); + fpi_ssm_mark_failed(ssm, result); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes) +static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - struct fp_dev *dev; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - data = g_malloc(bytes); - dev = fpi_ssm_get_dev(ssm); libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes, generic_ignore_data_cb, ssm, BULK_TIMEOUT); @@ -147,7 +143,7 @@ static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } @@ -226,14 +222,9 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da return; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - return; - } - - data = g_malloc(19); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 19, + transfer = fpi_usb_alloc(); + data = g_malloc(FINGER_DETECTION_LEN); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN, finger_det_data_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -247,7 +238,7 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da static void start_finger_detection(struct fp_img_dev *dev) { - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (aesdev->deactivating) { complete_deactivation(dev); @@ -557,17 +548,17 @@ enum capture_states { static void capture_read_strip_cb(struct libusb_transfer *transfer) { unsigned char *stripdata; - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; int sum, i; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } else if (transfer->length != transfer->actual_length) { - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } @@ -594,7 +585,7 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer) } if (sum < 0) { - fpi_ssm_mark_aborted(ssm, sum); + fpi_ssm_mark_failed(ssm, sum); goto out; } fp_dbg("sum=%d", sum); @@ -643,10 +634,10 @@ out: libusb_free_transfer(transfer); } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -657,7 +648,7 @@ static void capture_run_state(struct fpi_ssm *ssm) break; case CAPTURE_READ_DATA: fp_dbg("read data"); - generic_read_ignore_data(ssm, 665); + generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN); break; case CAPTURE_REQUEST_STRIP: fp_dbg("request strip"); @@ -668,32 +659,27 @@ static void capture_run_state(struct fpi_ssm *ssm) generic_write_regv_cb, ssm); break; case CAPTURE_READ_STRIP: ; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - - data = g_malloc(665); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 665, + data = g_malloc(STRIP_CAPTURE_LEN); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN, capture_read_strip_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; }; } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev); G_DEBUG_HERE(); if (aesdev->deactivating) @@ -707,17 +693,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; if (aesdev->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -738,9 +723,9 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; /* activation on aes1610 seems much more straightforward compared to aes2501 */ /* verify theres anything missing here */ @@ -753,9 +738,9 @@ static void activate_run_state(struct fpi_ssm *ssm) } /* jump to finger detection */ -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; fp_dbg("status %d", fpi_ssm_get_error(ssm)); fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); @@ -766,10 +751,9 @@ static void activate_sm_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); aesdev->read_regs_retry_count = 0; fpi_ssm_start(ssm, activate_sm_complete); return 0; @@ -777,7 +761,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *dev) { - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* FIXME: audit cancellation points, probably need more, specifically * in error handling paths? */ aesdev->deactivating = TRUE; @@ -785,7 +769,7 @@ static void dev_deactivate(struct fp_img_dev *dev) static void complete_deactivation(struct fp_img_dev *dev) { - struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); /* FIXME: if we're in the middle of a scan, we should cancel the scan. @@ -805,14 +789,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aes1610_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aes1610_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); fpi_imgdev_open_complete(dev, 0); return 0; } @@ -820,9 +804,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { struct aes1610_dev *aesdev; - aesdev = fpi_imgdev_get_user_data(dev); + aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes1660.c b/libfprint/drivers/aes1660.c index bebbf5aa..f27b9bf9 100644 --- a/libfprint/drivers/aes1660.c +++ b/libfprint/drivers/aes1660.c @@ -40,14 +40,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aesX660_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aesX660_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE); aesdev->init_seqs[0] = aes1660_init_1; aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1); @@ -64,10 +64,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev->buffer); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index 87879a46..2a031732 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -36,6 +36,11 @@ static void complete_deactivation(struct fp_img_dev *dev); #define BULK_TIMEOUT 4000 +#define FINGER_DETECTION_LEN 20 +#define READ_REGS_LEN 126 +#define READ_REGS_RESP_LEN 159 +#define STRIP_CAPTURE_LEN 1705 + /* * The AES2501 is an imaging device using a swipe-type sensor. It samples * the finger at preprogrammed intervals, sending a 192x16 frame to the @@ -83,9 +88,12 @@ struct aes2501_read_regs { void *user_data; }; -static void read_regs_data_cb(struct libusb_transfer *transfer) +static void read_regs_data_cb(struct libusb_transfer *transfer, + struct fp_dev *dev, + fpi_ssm *ssm, + void *user_data) { - struct aes2501_read_regs *rdata = transfer->user_data; + struct aes2501_read_regs *rdata = user_data; unsigned char *retdata = NULL; int r; @@ -100,14 +108,12 @@ static void read_regs_data_cb(struct libusb_transfer *transfer) rdata->callback(rdata->dev, r, retdata, rdata->user_data); g_free(rdata); - g_free(transfer->buffer); - libusb_free_transfer(transfer); } static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data) { struct aes2501_read_regs *rdata = user_data; - struct libusb_transfer *transfer; + fpi_usb_transfer *transfer; unsigned char *data; int r; @@ -115,20 +121,18 @@ static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data) if (result != 0) goto err; - transfer = libusb_alloc_transfer(0); - if (!transfer) { - result = -ENOMEM; - goto err; - } + data = g_malloc(READ_REGS_LEN); + transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + NULL, + EP_IN, + data, + READ_REGS_LEN, + read_regs_data_cb, + rdata, + BULK_TIMEOUT); - data = g_malloc(126); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 126, - read_regs_data_cb, rdata, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); + r = fpi_usb_submit_transfer(transfer); if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); result = -EIO; goto err; } @@ -180,53 +184,48 @@ static int regval_from_dump(unsigned char *data, uint8_t target) static void generic_write_regv_cb(struct fp_img_dev *dev, int result, void *user_data) { - struct fpi_ssm *ssm = user_data; + fpi_ssm *ssm = user_data; if (result == 0) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_aborted(ssm, result); + fpi_ssm_mark_failed(ssm, result); } /* check that read succeeded but ignore all data */ -static void generic_ignore_data_cb(struct libusb_transfer *transfer) +static void generic_ignore_data_cb(struct libusb_transfer *transfer, + struct fp_dev *dev, + fpi_ssm *ssm, + void *user_data) { - struct fpi_ssm *ssm = transfer->user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); else fpi_ssm_next_state(ssm); - - g_free(transfer->buffer); - libusb_free_transfer(transfer); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes) +static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + fpi_usb_transfer *transfer; unsigned char *data; - struct fp_dev *dev = fpi_ssm_get_dev(ssm); int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - data = g_malloc(bytes); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes, - generic_ignore_data_cb, ssm, BULK_TIMEOUT); + transfer = fpi_usb_fill_bulk_transfer(dev, + ssm, + EP_IN, + data, + bytes, + generic_ignore_data_cb, + NULL, + BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); - } + r = fpi_usb_submit_transfer(transfer); + if (r < 0) + fpi_ssm_mark_failed(ssm, r); } /****** IMAGE PROCESSING ******/ @@ -282,19 +281,22 @@ static const struct aes_regwrite finger_det_reqs[] = { static void start_finger_detection(struct fp_img_dev *dev); -static void finger_det_data_cb(struct libusb_transfer *transfer) +static void finger_det_data_cb(struct libusb_transfer *transfer, + struct fp_dev *_dev, + fpi_ssm *ssm, + void *user_data) { - struct fp_img_dev *dev = transfer->user_data; + struct fp_img_dev *dev = FP_IMG_DEV(_dev); unsigned char *data = transfer->buffer; int i; int sum = 0; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fpi_imgdev_session_error(dev, -EIO); - goto out; + return; } else if (transfer->length != transfer->actual_length) { fpi_imgdev_session_error(dev, -EPROTO); - goto out; + return; } /* examine histogram to determine finger presence */ @@ -308,16 +310,12 @@ static void finger_det_data_cb(struct libusb_transfer *transfer) /* no finger, poll for a new histogram */ start_finger_detection(dev); } - -out: - g_free(data); - libusb_free_transfer(transfer); } static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data) { - struct libusb_transfer *transfer; + fpi_usb_transfer *transfer; unsigned char *data; int r; @@ -326,27 +324,24 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, return; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - return; - } + data = g_malloc(FINGER_DETECTION_LEN); + transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + NULL, + EP_IN, + data, + FINGER_DETECTION_LEN, + finger_det_data_cb, + NULL, + BULK_TIMEOUT); - data = g_malloc(20); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 20, - finger_det_data_cb, dev, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); + r = fpi_usb_submit_transfer(transfer); + if (r < 0) fpi_imgdev_session_error(dev, r); - } } static void start_finger_detection(struct fp_img_dev *dev) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); if (aesdev->deactivating) { @@ -433,35 +428,37 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_read_strip_cb(struct libusb_transfer *transfer) +static void capture_read_strip_cb(struct libusb_transfer *transfer, + struct fp_dev *_dev, + fpi_ssm *ssm, + void *user_data) { unsigned char *stripdata; - struct fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = FP_IMG_DEV(_dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); unsigned char *data = transfer->buffer; int sum; int threshold; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_aborted(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(ssm, -EIO); + return; } else if (transfer->length != transfer->actual_length) { - fpi_ssm_mark_aborted(ssm, -EPROTO); - goto out; + fpi_ssm_mark_failed(ssm, -EPROTO); + return; } threshold = regval_from_dump(data + 1 + 192*8 + 1 + 16*2 + 1 + 8, AES2501_REG_DATFMT); if (threshold < 0) { - fpi_ssm_mark_aborted(ssm, threshold); - goto out; + fpi_ssm_mark_failed(ssm, threshold); + return; } sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f); if (sum < 0) { - fpi_ssm_mark_aborted(ssm, sum); - goto out; + fpi_ssm_mark_failed(ssm, sum); + return; } fp_dbg("sum=%d", sum); @@ -514,16 +511,12 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer) fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); } - -out: - g_free(data); - libusb_free_transfer(transfer); } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -532,14 +525,14 @@ static void capture_run_state(struct fpi_ssm *ssm) generic_write_regv_cb, ssm); break; case CAPTURE_READ_DATA_1: - generic_read_ignore_data(ssm, 159); + generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN); break; case CAPTURE_WRITE_REQS_2: aes_write_regv(dev, capture_reqs_2, G_N_ELEMENTS(capture_reqs_2), generic_write_regv_cb, ssm); break; case CAPTURE_READ_DATA_2: - generic_read_ignore_data(ssm, 159); + generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN); break; case CAPTURE_REQUEST_STRIP: if (aesdev->deactivating) @@ -549,32 +542,30 @@ static void capture_run_state(struct fpi_ssm *ssm) generic_write_regv_cb, ssm); break; case CAPTURE_READ_STRIP: ; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + fpi_usb_transfer *transfer; unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } + data = g_malloc(STRIP_CAPTURE_LEN); + transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + ssm, + EP_IN, + data, + STRIP_CAPTURE_LEN, + capture_read_strip_cb, + NULL, + BULK_TIMEOUT); - data = g_malloc(1705); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 1705, - capture_read_strip_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); - } + r = fpi_usb_submit_transfer(transfer); + if (r < 0) + fpi_ssm_mark_failed(ssm, r); break; }; } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); G_DEBUG_HERE(); if (aesdev->deactivating) @@ -588,8 +579,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; if (aesdev->deactivating) { complete_deactivation(dev); @@ -599,9 +590,8 @@ static void start_capture(struct fp_img_dev *dev) aesdev->no_finger_cnt = 0; /* Reset gain */ strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -713,11 +703,11 @@ enum activate_states { void activate_read_regs_cb(struct fp_img_dev *dev, int status, unsigned char *regs, void *user_data) { - struct fpi_ssm *ssm = user_data; - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (status != 0) { - fpi_ssm_mark_aborted(ssm, status); + fpi_ssm_mark_failed(ssm, status); } else { fp_dbg("reg 0xaf = %x", regs[0x5f]); if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13) @@ -730,16 +720,16 @@ void activate_read_regs_cb(struct fp_img_dev *dev, int status, static void activate_init3_cb(struct fp_img_dev *dev, int result, void *user_data) { - struct fpi_ssm *ssm = user_data; + fpi_ssm *ssm = user_data; if (result == 0) fpi_ssm_jump_to_state(ssm, READ_REGS); else - fpi_ssm_mark_aborted(ssm, result); + fpi_ssm_mark_failed(ssm, result); } -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; /* This state machine isn't as linear as it may appear. After doing init1 * and init2 register configuration writes, we have to poll a register @@ -767,7 +757,7 @@ static void activate_run_state(struct fpi_ssm *ssm) break; case READ_DATA_1: fp_dbg("read data 1"); - generic_read_ignore_data(ssm, 20); + generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN); break; case WRITE_INIT_2: aes_write_regv(dev, init_2, G_N_ELEMENTS(init_2), @@ -791,9 +781,9 @@ static void activate_run_state(struct fpi_ssm *ssm) } } -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; fp_dbg("status %d", fpi_ssm_get_error(ssm)); fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); @@ -804,10 +794,9 @@ static void activate_sm_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); aesdev->read_regs_retry_count = 0; fpi_ssm_start(ssm, activate_sm_complete); return 0; @@ -815,7 +804,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *dev) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* FIXME: audit cancellation points, probably need more, specifically * in error handling paths? */ aesdev->deactivating = TRUE; @@ -823,7 +812,7 @@ static void dev_deactivate(struct fp_img_dev *dev) static void complete_deactivation(struct fp_img_dev *dev) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); /* FIXME: if we're in the middle of a scan, we should cancel the scan. @@ -842,23 +831,23 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aes2501_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aes2501_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); fpi_imgdev_open_complete(dev, 0); return 0; } static void dev_deinit(struct fp_img_dev *dev) { - struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c index ab4acaab..ce5b6c2b 100644 --- a/libfprint/drivers/aes2550.c +++ b/libfprint/drivers/aes2550.c @@ -125,15 +125,10 @@ static void finger_det_reqs_cb(struct libusb_transfer *t) goto exit_free_transfer; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - goto exit_free_transfer; - } - + transfer = fpi_usb_alloc(); /* 2 bytes of result */ data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, finger_det_data_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -149,7 +144,7 @@ exit_free_transfer: static void start_finger_detection(struct fp_img_dev *dev) { int r; - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); struct libusb_transfer *transfer; G_DEBUG_HERE(); @@ -158,12 +153,8 @@ static void start_finger_detection(struct fp_img_dev *dev) return; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, finger_det_reqs, + transfer = fpi_usb_alloc(); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs, sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { @@ -200,11 +191,10 @@ enum capture_states { }; /* Returns number of processed bytes */ -static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data) +static int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data) { unsigned char *stripdata; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); struct fpi_frame *stripe; int len; @@ -231,22 +221,22 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data) static void capture_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length) && @@ -265,22 +255,22 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer) /* marking machine complete will re-trigger finger detection loop */ fpi_ssm_mark_completed(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void capture_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; int r; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -290,10 +280,10 @@ static void capture_read_data_cb(struct libusb_transfer *transfer) switch (transfer->actual_length) { case AES2550_STRIP_SIZE: - r = process_strip_data(ssm, data); + r = process_strip_data(ssm, dev, data); if (r < 0) { fp_dbg("Processing strip data failed: %d", r); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } aesdev->heartbeat_cnt = 0; @@ -323,73 +313,62 @@ out: libusb_free_transfer(transfer); } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; int r; switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_REQS: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, capture_reqs, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs, sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; case CAPTURE_READ_DATA: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, capture_read_data_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; case CAPTURE_SET_IDLE: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, capture_set_idle_reqs, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs, sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; }; } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev); fp_dbg("Capture completed"); if (aesdev->deactivating) @@ -403,8 +382,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; if (aesdev->deactivating) { complete_deactivation(dev); @@ -412,9 +391,8 @@ static void start_capture(struct fp_img_dev *dev) } aesdev->heartbeat_cnt = 0; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -444,25 +422,25 @@ enum activate_states { static void init_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void init_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } g_free(transfer->buffer); libusb_free_transfer(transfer); @@ -472,105 +450,89 @@ static void init_read_data_cb(struct libusb_transfer *transfer) * need more info for implementaion */ static void calibrate_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } g_free(transfer->buffer); libusb_free_transfer(transfer); } -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; int r; switch (fpi_ssm_get_cur_state(ssm)) { case WRITE_INIT: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, init_reqs, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs, sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; case READ_DATA: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, init_read_data_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; case CALIBRATE: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, calibrate_reqs, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs, sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; case READ_CALIB_TABLE: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, calibrate_read_data_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; } } -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; fp_dbg("status %d", fpi_ssm_get_error(ssm)); fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); @@ -581,23 +543,22 @@ static void activate_sm_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_sm_complete); return 0; } static void dev_deactivate(struct fp_img_dev *dev) { - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); aesdev->deactivating = TRUE; } static void complete_deactivation(struct fp_img_dev *dev) { - struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); aesdev->deactivating = FALSE; @@ -613,14 +574,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aes2550_dev *aes2550_dev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aes2550_dev = g_malloc0(sizeof(struct aes2550_dev)); - fpi_imgdev_set_user_data(dev, aes2550_dev); + fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev); fpi_imgdev_open_complete(dev, 0); return 0; } @@ -628,9 +589,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { struct aes2550_dev *aesdev; - aesdev = fpi_imgdev_get_user_data(dev); + aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes2660.c b/libfprint/drivers/aes2660.c index 99646839..de380e7a 100644 --- a/libfprint/drivers/aes2660.c +++ b/libfprint/drivers/aes2660.c @@ -40,14 +40,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aesX660_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aesX660_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE); /* No scaling for AES2660 */ aesdev->init_seqs[0] = aes2660_init_1; @@ -66,10 +66,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { struct aesX660_dev *aesdev; - aesdev = fpi_imgdev_get_user_data(dev); + aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev->buffer); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes3500.c b/libfprint/drivers/aes3500.c index 5d32f8ab..c083c4ed 100644 --- a/libfprint/drivers/aes3500.c +++ b/libfprint/drivers/aes3500.c @@ -122,14 +122,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aes3k_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aes3k_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); if (!aesdev) return -ENOMEM; @@ -148,9 +148,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/aes3k.c b/libfprint/drivers/aes3k.c index d64efda8..59c91bcc 100644 --- a/libfprint/drivers/aes3k.c +++ b/libfprint/drivers/aes3k.c @@ -63,7 +63,7 @@ static void aes3k_assemble_image(unsigned char *input, size_t width, size_t heig static void img_cb(struct libusb_transfer *transfer) { struct fp_img_dev *dev = transfer->user_data; - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *ptr = transfer->buffer; struct fp_img *tmp; struct fp_img *img; @@ -94,7 +94,7 @@ static void img_cb(struct libusb_transfer *transfer) /* FIXME: this is an ugly hack to make the image big enough for NBIS * to process reliably */ - img = fpi_im_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor); + img = fpi_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor); fp_img_free(tmp); fpi_imgdev_image_captured(dev, img); @@ -112,18 +112,13 @@ err: static void do_capture(struct fp_img_dev *dev) { - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data; int r; - aesdev->img_trf = libusb_alloc_transfer(0); - if (!aesdev->img_trf) { - fpi_imgdev_session_error(dev, -EIO); - return; - } - + aesdev->img_trf = fpi_usb_alloc(); data = g_malloc(aesdev->data_buflen); - libusb_fill_bulk_transfer(aesdev->img_trf, fpi_imgdev_get_usb_dev(dev), EP_IN, data, + libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, aesdev->data_buflen, img_cb, dev, 0); r = libusb_submit_transfer(aesdev->img_trf); @@ -144,14 +139,14 @@ static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data) int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL); return 0; } void aes3k_dev_deactivate(struct fp_img_dev *dev) { - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* FIXME: should wait for cancellation to complete before returning * from deactivation, otherwise app may legally exit before we've diff --git a/libfprint/drivers/aes4000.c b/libfprint/drivers/aes4000.c index c26dc64a..6ea79d15 100644 --- a/libfprint/drivers/aes4000.c +++ b/libfprint/drivers/aes4000.c @@ -119,14 +119,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct aes3k_dev *aesdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } aesdev = g_malloc0(sizeof(struct aes3k_dev)); - fpi_imgdev_set_user_data(dev, aesdev); + fp_dev_set_instance_data(FP_DEV(dev), aesdev); if (!aesdev) return -ENOMEM; @@ -145,9 +145,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { - struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(aesdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/aeslib.c b/libfprint/drivers/aeslib.c similarity index 94% rename from libfprint/aeslib.c rename to libfprint/drivers/aeslib.c index 61811ade..1ff3986d 100644 --- a/libfprint/aeslib.c +++ b/libfprint/drivers/aeslib.c @@ -24,10 +24,10 @@ #include #include -#include #include -#include "assembling.h" +#include "fpi-usb.h" +#include "fpi-assembling.h" #include "aeslib.h" #define MAX_REGWRITES_PER_REQUEST 16 @@ -73,21 +73,16 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound) unsigned char *data = g_malloc(alloc_size); unsigned int i; size_t data_offset = 0; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); int r; - if (!transfer) { - g_free(data); - return -ENOMEM; - } - for (i = offset; i < offset + num; i++) { const struct aes_regwrite *regwrite = &wdata->regs[i]; data[data_offset++] = regwrite->reg; data[data_offset++] = regwrite->value; } - libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data, + libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data, alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { @@ -149,8 +144,10 @@ static void continue_write_regv(struct write_regv_data *wdata) void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, unsigned int num_regs, aes_write_regv_cb callback, void *user_data) { - struct write_regv_data *wdata = g_malloc(sizeof(*wdata)); + struct write_regv_data *wdata; + fp_dbg("write %d regs", num_regs); + wdata = g_malloc(sizeof(*wdata)); wdata->imgdev = dev; wdata->num_regs = num_regs; wdata->regs = regs; @@ -158,6 +155,8 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, wdata->callback = callback; wdata->user_data = user_data; continue_write_regv(wdata); + + g_free(wdata); } unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, diff --git a/libfprint/aeslib.h b/libfprint/drivers/aeslib.h similarity index 100% rename from libfprint/aeslib.h rename to libfprint/drivers/aeslib.h diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c index e443e219..852c7509 100644 --- a/libfprint/drivers/aesx660.c +++ b/libfprint/drivers/aesx660.c @@ -35,52 +35,57 @@ static void complete_deactivation(struct fp_img_dev *dev); #define BULK_TIMEOUT 4000 #define FRAME_HEIGHT AESX660_FRAME_HEIGHT -#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define ID_LEN 8 +#define INIT_LEN 4 +#define CALIBRATE_DATA_LEN 4 +#define FINGER_DET_DATA_LEN 4 -static void aesX660_send_cmd_timeout(struct fpi_ssm *ssm, const unsigned char *cmd, - size_t cmd_len, libusb_transfer_cb_fn callback, int timeout) +static void +aesX660_send_cmd_timeout(fpi_ssm *ssm, + struct fp_dev *_dev, + const unsigned char *cmd, + size_t cmd_len, + libusb_transfer_cb_fn callback, + int timeout) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct fp_img_dev *dev = FP_IMG_DEV(_dev); + struct libusb_transfer *transfer = fpi_usb_alloc(); int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, (unsigned char *)cmd, cmd_len, callback, ssm, timeout); r = libusb_submit_transfer(transfer); if (r < 0) { fp_dbg("failed to submit transfer\n"); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } -static void aesX660_send_cmd(struct fpi_ssm *ssm, const unsigned char *cmd, - size_t cmd_len, libusb_transfer_cb_fn callback) +static void +aesX660_send_cmd(fpi_ssm *ssm, + struct fp_dev *dev, + const unsigned char *cmd, + size_t cmd_len, + libusb_transfer_cb_fn callback) { - return aesX660_send_cmd_timeout(ssm, cmd, cmd_len, callback, BULK_TIMEOUT); + return aesX660_send_cmd_timeout(ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT); } -static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len, - libusb_transfer_cb_fn callback) +static void +aesX660_read_response(fpi_ssm *ssm, + struct fp_dev *_dev, + size_t buf_len, + libusb_transfer_cb_fn callback) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct fp_img_dev *dev = FP_IMG_DEV(_dev); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - data = g_malloc(buf_len); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, buf_len, callback, ssm, BULK_TIMEOUT); @@ -89,13 +94,13 @@ static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len, fp_dbg("Failed to submit rx transfer: %d\n", r); g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } static void aesX660_send_cmd_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { @@ -103,25 +108,25 @@ static void aesX660_send_cmd_cb(struct libusb_transfer *transfer) } else { fp_dbg("tx transfer status: %d, actual_len: %.4x\n", transfer->status, transfer->actual_length); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; unsigned char *data = transfer->buffer; if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } /* Calibrate response was read correctly? */ if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) { fp_dbg("Bogus calibrate response: %.2x\n", data[0]); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } @@ -143,9 +148,9 @@ enum finger_det_states { static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; aesdev->fd_data_transfer = NULL; @@ -159,13 +164,13 @@ static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer) if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("Failed to read FD data\n"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) { fp_dbg("Bogus FD response: %.2x\n", data[0]); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } @@ -184,21 +189,21 @@ out: static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_mark_completed(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } -static void finger_det_sm_complete(struct fpi_ssm *ssm) +static void finger_det_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); int err = fpi_ssm_get_error(ssm); fp_dbg("Finger detection completed"); @@ -215,23 +220,22 @@ static void finger_det_sm_complete(struct fpi_ssm *ssm) } } -static void finger_det_run_state(struct fpi_ssm *ssm) +static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case FINGER_DET_SEND_LED_CMD: - aesX660_send_cmd(ssm, led_blink_cmd, sizeof(led_blink_cmd), + aesX660_send_cmd(ssm, dev, led_blink_cmd, sizeof(led_blink_cmd), aesX660_send_cmd_cb); break; case FINGER_DET_SEND_FD_CMD: - aesX660_send_cmd_timeout(ssm, wait_for_finger_cmd, sizeof(wait_for_finger_cmd), + aesX660_send_cmd_timeout(ssm, dev, wait_for_finger_cmd, sizeof(wait_for_finger_cmd), aesX660_send_cmd_cb, 0); break; case FINGER_DET_READ_FD_DATA: - /* Should return 4 byte of response */ - aesX660_read_response(ssm, 4, finger_det_read_fd_data_cb); + aesX660_read_response(ssm, dev, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb); break; case FINGER_DET_SET_IDLE: - aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + aesX660_send_cmd(ssm, dev, set_idle_cmd, sizeof(set_idle_cmd), finger_det_set_idle_cmd_cb); break; } @@ -239,16 +243,15 @@ static void finger_det_run_state(struct fpi_ssm *ssm) static void start_finger_detection(struct fp_img_dev *dev) { - struct fpi_ssm *ssm; - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm; + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (aesdev->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), finger_det_run_state, FINGER_DET_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), finger_det_run_state, FINGER_DET_NUM_STATES, dev); fpi_ssm_start(ssm, finger_det_sm_complete); } @@ -263,12 +266,11 @@ enum capture_states { }; /* Returns number of processed bytes */ -static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data) +static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data) { struct fpi_frame *stripe; unsigned char *stripdata; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); stripe = g_malloc(aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */ stripdata = stripe->data; @@ -286,17 +288,17 @@ static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data) aesdev->strips = g_slist_prepend(aesdev->strips, stripe); aesdev->strips_len++; return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); - } else { - return 0; } + g_free(stripe); + return 0; } static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { @@ -313,28 +315,28 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer) fpi_imgdev_report_finger_status(dev, FALSE); fpi_ssm_mark_completed(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void capture_read_stripe_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; int finger_missing = 0; size_t copied, actual_len = transfer->actual_length; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } fp_dbg("Got %lu bytes of data", actual_len); do { - copied = min(aesdev->buffer_max - aesdev->buffer_size, actual_len); + copied = MIN(aesdev->buffer_max - aesdev->buffer_size, actual_len); memcpy(aesdev->buffer + aesdev->buffer_size, data, copied); @@ -352,7 +354,7 @@ static void capture_read_stripe_data_cb(struct libusb_transfer *transfer) aesdev->buffer_max); continue; } else { - finger_missing |= process_stripe_data(ssm, aesdev->buffer); + finger_missing |= process_stripe_data(ssm, dev, aesdev->buffer); aesdev->buffer_max = AESX660_HEADER_SIZE; aesdev->buffer_size = 0; } @@ -371,39 +373,38 @@ out: libusb_free_transfer(transfer); } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_SEND_LED_CMD: - aesX660_send_cmd(ssm, led_solid_cmd, sizeof(led_solid_cmd), + aesX660_send_cmd(ssm, _dev, led_solid_cmd, sizeof(led_solid_cmd), aesX660_send_cmd_cb); break; case CAPTURE_SEND_CAPTURE_CMD: aesdev->buffer_size = 0; aesdev->buffer_max = AESX660_HEADER_SIZE; - aesX660_send_cmd(ssm, aesdev->start_imaging_cmd, + aesX660_send_cmd(ssm, _dev, aesdev->start_imaging_cmd, aesdev->start_imaging_cmd_len, aesX660_send_cmd_cb); break; case CAPTURE_READ_STRIPE_DATA: - aesX660_read_response(ssm, AESX660_BULK_TRANSFER_SIZE, + aesX660_read_response(ssm, _dev, AESX660_BULK_TRANSFER_SIZE, capture_read_stripe_data_cb); break; case CAPTURE_SET_IDLE: fp_dbg("Got %lu frames\n", aesdev->strips_len); - aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), capture_set_idle_cmd_cb); break; } } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); int err = fpi_ssm_get_error(ssm); fp_dbg("Capture completed"); @@ -419,17 +420,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; if (aesdev->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -448,15 +448,15 @@ enum activate_states { static void activate_read_id_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("read_id cmd failed\n"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } /* ID was read correctly */ @@ -465,7 +465,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer) data[4], data[3], data[5], data[6], data[7]); } else { fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } @@ -487,7 +487,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer) break; default: fp_dbg("Failed to init device! init status: %.2x\n", data[7]); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); break; } @@ -499,9 +499,9 @@ out: static void activate_read_init_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; fp_dbg("read_init_cb\n"); @@ -509,14 +509,14 @@ static void activate_read_init_cb(struct libusb_transfer *transfer) if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } /* ID was read correctly */ if (data[0] != 0x42 || data[3] != 0x01) { fp_dbg("Bogus read init response: %.2x %.2x\n", data[0], data[3]); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } aesdev->init_cmd_idx++; @@ -534,55 +534,52 @@ out: libusb_free_transfer(transfer); } -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); switch (fpi_ssm_get_cur_state(ssm)) { case ACTIVATE_SET_IDLE: aesdev->init_seq_idx = 0; fp_dbg("Activate: set idle\n"); - aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_SEND_READ_ID_CMD: fp_dbg("Activate: read ID\n"); - aesX660_send_cmd(ssm, read_id_cmd, sizeof(read_id_cmd), + aesX660_send_cmd(ssm, _dev, read_id_cmd, sizeof(read_id_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_READ_ID: - /* Should return 8-byte response */ - aesX660_read_response(ssm, 8, activate_read_id_cb); + aesX660_read_response(ssm, _dev, ID_LEN, activate_read_id_cb); break; case ACTIVATE_SEND_INIT_CMD: fp_dbg("Activate: send init seq #%d cmd #%d\n", aesdev->init_seq_idx, aesdev->init_cmd_idx); - aesX660_send_cmd(ssm, + aesX660_send_cmd(ssm, _dev, aesdev->init_seq[aesdev->init_cmd_idx].cmd, aesdev->init_seq[aesdev->init_cmd_idx].len, aesX660_send_cmd_cb); break; case ACTIVATE_READ_INIT_RESPONSE: fp_dbg("Activate: read init response\n"); - /* Should return 4-byte response */ - aesX660_read_response(ssm, 4, activate_read_init_cb); + aesX660_read_response(ssm, _dev, INIT_LEN, activate_read_init_cb); break; case ACTIVATE_SEND_CALIBRATE_CMD: - aesX660_send_cmd(ssm, calibrate_cmd, sizeof(calibrate_cmd), + aesX660_send_cmd(ssm, _dev, calibrate_cmd, sizeof(calibrate_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_READ_CALIBRATE_DATA: - /* Should return 4-byte response */ - aesX660_read_response(ssm, 4, aesX660_read_calibrate_data_cb); + aesX660_read_response(ssm, _dev, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb); break; } } -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; int err = fpi_ssm_get_error(ssm); fp_dbg("status %d", err); fpi_imgdev_activate_complete(dev, err); @@ -594,16 +591,15 @@ static void activate_sm_complete(struct fpi_ssm *ssm) int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_sm_complete); return 0; } void aesX660_dev_deactivate(struct fp_img_dev *dev) { - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (aesdev->fd_data_transfer) libusb_cancel_transfer(aesdev->fd_data_transfer); @@ -613,7 +609,7 @@ void aesX660_dev_deactivate(struct fp_img_dev *dev) static void complete_deactivation(struct fp_img_dev *dev) { - struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev); + struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); aesdev->deactivating = FALSE; diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index dff75a6d..ed474b05 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -2,6 +2,7 @@ * Elan driver for libfprint * * Copyright (C) 2017 Igor Filatov + * Copyright (C) 2018 Sébastien Béchet * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,11 +19,36 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * The algorithm which libfprint uses to match fingerprints doesn't like small + * images like the ones these drivers produce. There's just not enough minutiae + * (recognizable print-specific points) on them for a reliable match. This means + * that unless another matching algo is found/implemented, these readers will + * not work as good with libfprint as they do with vendor drivers. + * + * To get bigger images the driver expects you to swipe the finger over the + * reader. This works quite well for readers with a rectangular 144x64 sensor. + * Worse than real swipe readers but good enough for day-to-day use. It needs + * a steady and relatively slow swipe. There are also square 96x96 sensors and + * I don't know whether they are in fact usable or not because I don't have one. + * I imagine they'd be less reliable because the resulting image is even + * smaller. If they can't be made usable with libfprint, I might end up dropping + * them because it's better than saying they work when they don't. + */ + #define FP_COMPONENT "elan" #include "drivers_api.h" #include "elan.h" +#define dbg_buf(buf, len) \ + if (len == 1) \ + fp_dbg("%02x", buf[0]); \ + else if (len == 2) \ + fp_dbg("%04x", buf[0] << 8 | buf[1]); \ + else if (len > 2) \ + fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len) + unsigned char elan_get_pixel(struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y) @@ -38,34 +64,49 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { }; struct elan_dev { - gboolean deactivating; + /* device config */ + unsigned short dev_type; + unsigned short fw_ver; + void (*process_frame) (unsigned short *raw_frame, GSList ** frames); + /* end device config */ - const struct elan_cmd *cmds; - size_t cmds_len; - int cmd_idx; + /* commands */ + const struct elan_cmd *cmd; int cmd_timeout; - struct libusb_transfer *cur_transfer; + fpi_usb_transfer *cur_transfer; + /* end commands */ + /* state */ + enum fp_imgdev_state dev_state; + enum fp_imgdev_state 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_width; + unsigned char raw_frame_height; int num_frames; GSList *frames; + /* end state */ }; +int cmp_short(const void *a, const void *b) +{ + return (int)(*(short *)a - *(short *)b); +} + static void elan_dev_reset(struct elan_dev *elandev) { G_DEBUG_HERE(); BUG_ON(elandev->cur_transfer); - elandev->deactivating = FALSE; - - elandev->cmds = NULL; - elandev->cmd_idx = 0; + elandev->cmd = NULL; elandev->cmd_timeout = ELAN_CMD_TIMEOUT; + elandev->calib_status = 0; + g_free(elandev->last_read); elandev->last_read = NULL; @@ -74,36 +115,118 @@ static void elan_dev_reset(struct elan_dev *elandev) elandev->num_frames = 0; } -static void elan_save_frame(struct fp_img_dev *dev) +static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); - unsigned char raw_height = elandev->frame_width; - unsigned char raw_width = elandev->raw_frame_width; - unsigned short *frame = - g_malloc(elandev->frame_width * elandev->frame_height * 2); - G_DEBUG_HERE(); - /* Raw images are vertical and perpendicular to swipe direction of a - * normalized image, which means we need to make them horizontal before - * assembling. We also discard stirpes of ELAN_FRAME_MARGIN along raw - * height. */ - for (int y = 0; y < raw_height; y++) - for (int x = ELAN_FRAME_MARGIN; - x < raw_width - ELAN_FRAME_MARGIN; x++) { - int frame_idx = - y + (x - ELAN_FRAME_MARGIN) * raw_height; - int raw_idx = x + y * raw_width; + /* so far 3 types of readers by sensor dimensions and orientation have been + * seen in the wild: + * 1. 144x64. Raw images are in portrait orientation while readers themselves + * are placed (e.g. built into a touchpad) in landscape orientation. These + * need to be rotated before assembling. + * 2. 96x96 rotated. Like the first type but square. Likewise, need to be + * rotated before assembling. + * 3. 96x96 normal. Square and need NOT be rotated. So far there's only been + * 1 report of a 0c03 of this type. Hopefully this type can be identified + * by device id (and manufacturers don't just install the readers as they + * please). + * we also discard stripes of 'frame_margin' from bottom and top because + * assembling works bad for tall frames */ + + unsigned char frame_width = elandev->frame_width; + unsigned char frame_height = elandev->frame_height; + unsigned char raw_height = elandev->raw_frame_height; + unsigned char frame_margin = (raw_height - elandev->frame_height) / 2; + int frame_idx, raw_idx; + + for (int y = 0; y < frame_height; y++) + for (int x = 0; x < frame_width; x++) { + if (elandev->dev_type & ELAN_NOT_ROTATED) + raw_idx = x + (y + frame_margin) * frame_width; + else + raw_idx = frame_margin + y + x * raw_height; + frame_idx = x + y * frame_width; frame[frame_idx] = ((unsigned short *)elandev->last_read)[raw_idx]; } +} + +static void elan_save_background(struct elan_dev *elandev) +{ + G_DEBUG_HERE(); + + g_free(elandev->background); + elandev->background = + g_malloc(elandev->frame_width * elandev->frame_height * + sizeof(short)); + elan_save_frame(elandev, elandev->background); +} + +/* save a frame as part of the fingerprint image + * background needs to have been captured for this routine to work + * Elantech recommends 2-step non-linear normalization in order to reduce + * 2^14 ADC resolution to 2^8 image: + * + * 1. background is subtracted (done here) + * + * 2. pixels are grouped in 3 groups by intensity and each group is mapped + * separately onto the normalized frame (done in elan_process_frame_*) + * ==== 16383 ____> ======== 255 + * / + * ----- lvl3 __/ + * 35% pixels + * + * ----- lvl2 --------> ======== 156 + * + * 30% pixels + * ----- lvl1 --------> ======== 99 + * + * 35% pixels + * ----- lvl0 __ + * \ + * ======== 0 \____> ======== 0 + * + * For some devices we don't do 2. but instead do a simple linear mapping + * because it seems to produce better results (or at least as good): + * ==== 16383 ___> ======== 255 + * / + * ------ max __/ + * + * + * ------ min __ + * \ + * ======== 0 \___> ======== 0 + */ +static int elan_save_img_frame(struct elan_dev *elandev) +{ + G_DEBUG_HERE(); + + 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; + + for (int i = 0; i < frame_size; i++) { + if (elandev->background[i] > frame[i]) + frame[i] = 0; + else + frame[i] -= elandev->background[i]; + sum += frame[i]; + } + + if (sum == 0) { + fp_dbg + ("frame darker than background; finger present during calibration?"); + return -1; + } elandev->frames = g_slist_prepend(elandev->frames, frame); elandev->num_frames += 1; + return 0; } -/* Transform raw sensor data to normalized 8-bit grayscale image. */ -static void elan_process_frame(unsigned short *raw_frame, GSList ** frames) +static void elan_process_frame_linear(unsigned short *raw_frame, + GSList ** frames) { unsigned int frame_size = assembling_ctx.frame_width * assembling_ctx.frame_height; @@ -120,15 +243,47 @@ static void elan_process_frame(unsigned short *raw_frame, GSList ** frames) max = raw_frame[i]; } + g_assert(max != min); + unsigned short px; for (int i = 0; i < frame_size; i++) { px = raw_frame[i]; - if (px <= min) - px = 0; - else if (px >= max) - px = 0xff; - else - px = (px - min) * 0xff / (max - min); + px = (px - min) * 0xff / (max - min); + frame->data[i] = (unsigned char)px; + } + + *frames = g_slist_prepend(*frames, frame); +} + +static void elan_process_frame_thirds(unsigned short *raw_frame, + GSList ** frames) +{ + G_DEBUG_HERE(); + + unsigned int frame_size = + assembling_ctx.frame_width * assembling_ctx.frame_height; + struct fpi_frame *frame = + g_malloc(frame_size + sizeof(struct fpi_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]; + lvl1 = sorted[frame_size * 3 / 10]; + lvl2 = sorted[frame_size * 65 / 100]; + lvl3 = sorted[frame_size - 1]; + g_free(sorted); + + unsigned short px; + for (int i = 0; i < frame_size; i++) { + px = raw_frame[i]; + if (lvl0 <= px && px < lvl1) + px = (px - lvl0) * 99 / (lvl1 - lvl0); + else if (lvl1 <= px && px < lvl2) + px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1)); + else // (lvl2 <= px && px <= lvl3) + px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2)); frame->data[i] = (unsigned char)px; } @@ -137,7 +292,7 @@ static void elan_process_frame(unsigned short *raw_frame, GSList ** frames) static void elan_submit_image(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); GSList *frames = NULL; struct fp_img *img; @@ -145,415 +300,497 @@ static void elan_submit_image(struct fp_img_dev *dev) for (int i = 0; i < ELAN_SKIP_LAST_FRAMES; i++) elandev->frames = g_slist_next(elandev->frames); + elandev->num_frames -= ELAN_SKIP_LAST_FRAMES; assembling_ctx.frame_width = elandev->frame_width; assembling_ctx.frame_height = elandev->frame_height; assembling_ctx.image_width = elandev->frame_width * 3 / 2; - g_slist_foreach(elandev->frames, (GFunc) elan_process_frame, &frames); + g_slist_foreach(elandev->frames, (GFunc) elandev->process_frame, + &frames); fpi_do_movement_estimation(&assembling_ctx, frames, - elandev->num_frames - ELAN_SKIP_LAST_FRAMES); - img = fpi_assemble_frames(&assembling_ctx, frames, - elandev->num_frames - ELAN_SKIP_LAST_FRAMES); + elandev->num_frames); + img = fpi_assemble_frames(&assembling_ctx, frames, elandev->num_frames); img->flags |= FP_IMG_PARTIAL; fpi_imgdev_image_captured(dev, img); } -static void elan_cmd_done(struct fpi_ssm *ssm) +static void elan_cmd_done(fpi_ssm *ssm) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); - G_DEBUG_HERE(); - - elandev->cmd_idx += 1; - if (elandev->cmd_idx < elandev->cmds_len) - elan_run_next_cmd(ssm); - else - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(ssm); } -static void elan_cmd_cb(struct libusb_transfer *transfer) +static void elan_cmd_cb(struct libusb_transfer *transfer, + struct fp_dev *_dev, + fpi_ssm *ssm, + void *user_data) { - struct fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev; + struct elan_dev *elandev; G_DEBUG_HERE(); + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + fp_dbg("transfer cancelled"); + return; + } + + dev = FP_IMG_DEV(_dev); + elandev = FP_INSTANCE_DATA(_dev); elandev->cur_transfer = NULL; switch (transfer->status) { case LIBUSB_TRANSFER_COMPLETED: if (transfer->length != transfer->actual_length) { - fp_dbg("unexpected transfer length"); + fp_dbg("transfer length error: expected %d, got %d", + transfer->length, transfer->actual_length); elan_dev_reset(elandev); - fpi_ssm_mark_aborted(ssm, -EPROTO); - } else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) + fpi_ssm_mark_failed(ssm, -EPROTO); + } else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) { /* just finished receiving */ + elandev->last_read = g_memdup(transfer->buffer, transfer->actual_length); + dbg_buf(transfer->buffer, transfer->actual_length); elan_cmd_done(ssm); - else { + } else { /* just finished sending */ - if (elandev->cmds[elandev->cmd_idx].response_len) - elan_cmd_read(ssm); - else - elan_cmd_done(ssm); + G_DEBUG_HERE(); + elan_cmd_read(ssm, dev); } break; - case LIBUSB_TRANSFER_CANCELLED: - fp_dbg("transfer cancelled"); - fpi_ssm_mark_aborted(ssm, -ECANCELED); - break; case LIBUSB_TRANSFER_TIMED_OUT: fp_dbg("transfer timed out"); - // elan_dev_reset(elandev); - fpi_ssm_mark_aborted(ssm, -ETIMEDOUT); + fpi_ssm_mark_failed(ssm, -ETIMEDOUT); break; default: fp_dbg("transfer failed: %d", transfer->status); elan_dev_reset(elandev); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } -static void elan_cmd_read(struct fpi_ssm *ssm) +static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); - int response_len = elandev->cmds[elandev->cmd_idx].response_len; + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + int response_len = elandev->cmd->response_len; + unsigned char *buffer; G_DEBUG_HERE(); - if (elandev->cmds[elandev->cmd_idx].cmd == read_cmds[0].cmd) + if (elandev->cmd->response_len == ELAN_CMD_SKIP_READ) { + fp_dbg("skipping read, not expecting anything"); + elan_cmd_done(ssm); + return; + } + + if (elandev->cmd->cmd == get_image_cmd.cmd) /* raw data has 2-byte "pixels" and the frame is vertical */ response_len = - elandev->raw_frame_width * elandev->frame_width * 2; + elandev->raw_frame_height * elandev->frame_width * 2; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - elandev->cur_transfer = transfer; + g_clear_pointer(&elandev->last_read, g_free); + buffer = g_malloc(response_len); - g_free(elandev->last_read); - elandev->last_read = g_malloc(response_len); - - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), - elandev->cmds[elandev->cmd_idx].response_in, - elandev->last_read, response_len, elan_cmd_cb, - ssm, elandev->cmd_timeout); - transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; - int r = libusb_submit_transfer(transfer); + elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + ssm, + elandev->cmd->response_in, + buffer, + response_len, + elan_cmd_cb, + NULL, + elandev->cmd_timeout); + int r = fpi_usb_submit_transfer(elandev->cur_transfer); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } -static void elan_run_next_cmd(struct fpi_ssm *ssm) +static void +elan_run_cmd(fpi_ssm *ssm, + struct fp_img_dev *dev, + const struct elan_cmd *cmd, + int cmd_timeout) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - G_DEBUG_HERE(); + dbg_buf(cmd->cmd, 2); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - elandev->cur_transfer = transfer; - - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), ELAN_EP_CMD_OUT, - (unsigned char *)elandev->cmds[elandev-> - cmd_idx].cmd, - ELAN_CMD_LEN, elan_cmd_cb, ssm, - elandev->cmd_timeout); - transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; - int r = libusb_submit_transfer(transfer); - if (r < 0) - fpi_ssm_mark_aborted(ssm, r); - -} - -static void elan_run_cmds(struct fpi_ssm *ssm, const struct elan_cmd *cmds, - size_t cmds_len, int cmd_timeout) -{ - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); - - G_DEBUG_HERE(); - - elandev->cmds = cmds; - elandev->cmds_len = cmds_len; - elandev->cmd_idx = 0; + elandev->cmd = cmd; if (cmd_timeout != -1) elandev->cmd_timeout = cmd_timeout; - elan_run_next_cmd(ssm); + + if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) { + fp_dbg("skipping for this device"); + elan_cmd_done(ssm); + return; + } + + elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + ssm, + ELAN_EP_CMD_OUT, + g_memdup((char *) cmd->cmd, ELAN_CMD_LEN), + ELAN_CMD_LEN, + elan_cmd_cb, + NULL, + elandev->cmd_timeout); + int r = fpi_usb_submit_transfer(elandev->cur_transfer); + if (r < 0) + fpi_ssm_mark_failed(ssm, r); } -enum deactivate_states { - DEACTIVATE, - DEACTIVATE_NUM_STATES, +enum stop_capture_states { + STOP_CAPTURE, + STOP_CAPTURE_NUM_STATES, }; -static void elan_deactivate_run_state(struct fpi_ssm *ssm) +static void stop_capture_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { + G_DEBUG_HERE(); + switch (fpi_ssm_get_cur_state(ssm)) { - case DEACTIVATE: - elan_run_cmds(ssm, deactivate_cmds, deactivate_cmds_len, - ELAN_CMD_TIMEOUT); + case STOP_CAPTURE: + elan_run_cmd(ssm, FP_IMG_DEV(dev), &stop_cmd, ELAN_CMD_TIMEOUT); break; } } -static void deactivate_complete(struct fpi_ssm *ssm) +static void stop_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; + struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + int error = fpi_ssm_get_error(ssm); - fpi_imgdev_deactivate_complete(dev); + G_DEBUG_HERE(); + + fpi_ssm_free(ssm); + + if (!error) { + fpi_imgdev_report_finger_status(dev, FALSE); + + /* If verify or identify fails because of short swipe, we need to restart + * capture manually. It feels like libfprint or the application should know + * better if they want to retry, but they don't. Unless we've been asked to + * deactivate, try to re-enter the capture loop. Since state change is + * async, there's still a chance to be deactivated by another pending + * event. */ + if (elandev->dev_state_next != IMGDEV_STATE_INACTIVE) + dev_change_state(dev, IMGDEV_STATE_AWAIT_FINGER_ON); + + } else if (error != -ECANCELED) + fpi_imgdev_abort_scan(dev, error); } -static void elan_deactivate(struct fp_img_dev *dev) +static void elan_stop_capture(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); elan_dev_reset(elandev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), elan_deactivate_run_state, - DEACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); - fpi_ssm_start(ssm, deactivate_complete); + fpi_ssm *ssm = + fpi_ssm_new(FP_DEV(dev), stop_capture_run_state, + STOP_CAPTURE_NUM_STATES, dev); + fpi_ssm_start(ssm, stop_capture_complete); } enum capture_states { - CAPTURE_START, + CAPTURE_LED_ON, CAPTURE_WAIT_FINGER, CAPTURE_READ_DATA, - CAPTURE_SAVE_FRAME, + CAPTURE_CHECK_ENOUGH_FRAMES, CAPTURE_NUM_STATES, }; -static void elan_capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + int r; switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_START: - elan_run_cmds(ssm, capture_start_cmds, capture_start_cmds_len, - ELAN_CMD_TIMEOUT); + case CAPTURE_LED_ON: + elan_run_cmd(ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT); break; case CAPTURE_WAIT_FINGER: - elan_run_cmds(ssm, capture_wait_finger_cmds, - capture_wait_finger_cmds_len, -1); + elan_run_cmd(ssm, dev, &pre_scan_cmd, -1); break; case CAPTURE_READ_DATA: /* 0x55 - finger present - * 0xff - device not calibrated */ + * 0xff - device not calibrated (probably) */ if (elandev->last_read && elandev->last_read[0] == 0x55) { - fpi_imgdev_report_finger_status(dev, TRUE); - elan_run_cmds(ssm, read_cmds, read_cmds_len, - ELAN_CMD_TIMEOUT); + if (elandev->dev_state == IMGDEV_STATE_AWAIT_FINGER_ON) + fpi_imgdev_report_finger_status(dev, TRUE); + elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); } else - fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY); + fpi_ssm_mark_failed(ssm, -EBADMSG); break; - case CAPTURE_SAVE_FRAME: - elan_save_frame(dev); - if (elandev->num_frames < ELAN_MAX_FRAMES) { + case CAPTURE_CHECK_ENOUGH_FRAMES: + r = elan_save_img_frame(elandev); + if (r < 0) + fpi_ssm_mark_failed(ssm, r); + else if (elandev->num_frames < ELAN_MAX_FRAMES) { /* quickly stop if finger is removed */ elandev->cmd_timeout = ELAN_FINGER_TIMEOUT; fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER); + } else { + fpi_ssm_next_state(ssm); } break; } } -static void elan_capture_async(void *data) +static void capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - elan_capture((struct fp_img_dev *)data); -} - -static void capture_complete(struct fpi_ssm *ssm) -{ - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); G_DEBUG_HERE(); - if (elandev->deactivating) - elan_deactivate(dev); + if (fpi_ssm_get_error(ssm) == -ECANCELED) { + fpi_ssm_free(ssm); + return; + } /* either max frames captured or timed out waiting for the next frame */ - else if (!fpi_ssm_get_error(ssm) - || (fpi_ssm_get_error(ssm) == -ETIMEDOUT - && fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) - if (elandev->num_frames >= ELAN_MIN_FRAMES) { + if (!fpi_ssm_get_error(ssm) + || (fpi_ssm_get_error(ssm) == -ETIMEDOUT + && fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) + if (elandev->num_frames >= ELAN_MIN_FRAMES) elan_submit_image(dev); - fpi_imgdev_report_finger_status(dev, FALSE); - } else - fpi_imgdev_session_error(dev, - FP_VERIFY_RETRY_TOO_SHORT); + else { + fp_dbg("swipe too short: want >= %d frames, got %d", + ELAN_MIN_FRAMES, elandev->num_frames); + fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT); + } /* other error - * It says "...session_error" but repotring 1 during verification - * makes it successful! */ + * It says "...abort_scan" but reporting 1 during verification makes it + * successful! */ else - fpi_imgdev_session_error(dev, FP_VERIFY_NO_MATCH); - - /* When enrolling the lib won't restart the capture after a stage has - * completed, so we need to keep feeding it images till it's had enough. - * But after that it can't finalize enrollemnt until this callback exits. - * That's why we schedule elan_capture instead of running it directly. */ - if (fpi_dev_get_dev_state(fpi_imgdev_get_dev(dev)) == DEV_STATE_ENROLLING - && !fpi_timeout_add(10, elan_capture_async, dev)) - fpi_imgdev_session_error(dev, -ETIME); + fpi_imgdev_abort_scan(dev, fpi_ssm_get_error(ssm)); fpi_ssm_free(ssm); } static void elan_capture(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); elan_dev_reset(elandev); - struct fpi_ssm *ssm = - fpi_ssm_new(fpi_imgdev_get_dev(dev), elan_capture_run_state, CAPTURE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + fpi_ssm *ssm = + fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); fpi_ssm_start(ssm, capture_complete); } +/* this function needs to have elandev->background and elandev->last_read to be + * the calibration mean */ +static int elan_need_calibration(struct elan_dev *elandev) +{ + G_DEBUG_HERE(); + + unsigned short calib_mean = + elandev->last_read[0] * 0xff + elandev->last_read[1]; + unsigned int bg_mean = 0, delta; + unsigned int frame_size = elandev->frame_width * elandev->frame_height; + + g_assert(frame_size != 0); + + for (int i = 0; i < frame_size; i++) + bg_mean += elandev->background[i]; + bg_mean /= frame_size; + + delta = + bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean; + + fp_dbg("calibration mean: %d, bg mean: %d, delta: %d", calib_mean, + bg_mean, delta); + + return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0; +} + enum calibrate_states { - CALIBRATE_START_1, - CALIBRATE_READ_DATA_1, - CALIBRATE_END_1, - CALIBRATE_START_2, - CALIBRATE_READ_DATA_2, - CALIBRATE_END_2, + CALIBRATE_GET_BACKGROUND, + CALIBRATE_SAVE_BACKGROUND, + CALIBRATE_GET_MEAN, + CALIBRATE_CHECK_NEEDED, + CALIBRATE_GET_STATUS, + CALIBRATE_CHECK_STATUS, + CALIBRATE_REPEAT_STATUS, CALIBRATE_NUM_STATES, }; -static void elan_calibrate_run_state(struct fpi_ssm *ssm) +static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case CALIBRATE_START_1: - case CALIBRATE_START_2: - elan_run_cmds(ssm, calibrate_start_cmds, - calibrate_start_cmds_len, ELAN_CMD_TIMEOUT); - break; - case CALIBRATE_READ_DATA_1: - case CALIBRATE_READ_DATA_2: - elan_run_cmds(ssm, read_cmds, read_cmds_len, ELAN_CMD_TIMEOUT); - break; - case CALIBRATE_END_1: - case CALIBRATE_END_2: - elan_run_cmds(ssm, calibrate_end_cmds, calibrate_end_cmds_len, - ELAN_CMD_TIMEOUT); - } -} - -static void calibrate_complete(struct fpi_ssm *ssm) -{ - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); G_DEBUG_HERE(); - if (elandev->deactivating) - elan_deactivate(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); - else { - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); - elan_capture(dev); + switch (fpi_ssm_get_cur_state(ssm)) { + case CALIBRATE_GET_BACKGROUND: + elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); + break; + case CALIBRATE_SAVE_BACKGROUND: + elan_save_background(elandev); + if (elandev->fw_ver < ELAN_MIN_CALIBRATION_FW) { + fp_dbg("FW does not support calibration"); + fpi_ssm_mark_completed(ssm); + } else + fpi_ssm_next_state(ssm); + break; + case CALIBRATE_GET_MEAN: + elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT); + break; + case CALIBRATE_CHECK_NEEDED: + if (elan_need_calibration(elandev)) { + elandev->calib_status = 0; + fpi_ssm_next_state(ssm); + } else + fpi_ssm_mark_completed(ssm); + break; + case CALIBRATE_GET_STATUS: + elandev->calib_atts_left -= 1; + if (elandev->calib_atts_left) + elan_run_cmd(ssm, dev, &get_calib_status_cmd, + ELAN_CMD_TIMEOUT); + else { + fp_dbg("calibration failed"); + fpi_ssm_mark_failed(ssm, -1); + } + break; + case CALIBRATE_CHECK_STATUS: + /* 0x01 - retry, 0x03 - ok + * It appears that when reading the response soon after 0x4023 the device + * can return 0x03, and only after some time (up to 100 ms) the response + * changes to 0x01. It stays that way for some time and then changes back + * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01 + * first. This is to make sure that a full calibration loop has completed */ + fp_dbg("calibration status: 0x%02x", elandev->last_read[0]); + if (elandev->calib_status == 0x01 + && elandev->last_read[0] == 0x03) { + elandev->calib_status = 0x03; + fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND); + } else { + fpi_timeout *timeout; + + if (elandev->calib_status == 0x00 + && elandev->last_read[0] == 0x01) + elandev->calib_status = 0x01; + timeout = fpi_timeout_add(50, fpi_ssm_next_state_timeout_cb, _dev, ssm); + fpi_timeout_set_name(timeout, "calibrate_run_state"); + } + break; + case CALIBRATE_REPEAT_STATUS: + fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_STATUS); + break; } +} + +static void calibrate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +{ + struct fp_img_dev *dev = user_data; + + G_DEBUG_HERE(); + + + if (fpi_ssm_get_error(ssm) != -ECANCELED) + elan_capture(dev); + fpi_ssm_free(ssm); } static void elan_calibrate(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); elan_dev_reset(elandev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), elan_calibrate_run_state, - CALIBRATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + elandev->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; + + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), calibrate_run_state, + CALIBRATE_NUM_STATES, dev); fpi_ssm_start(ssm, calibrate_complete); } enum activate_states { + ACTIVATE_GET_FW_VER, + ACTIVATE_SET_FW_VER, ACTIVATE_GET_SENSOR_DIM, ACTIVATE_SET_SENSOR_DIM, - ACTIVATE_START, - ACTIVATE_READ_DATA, - ACTIVATE_END, + ACTIVATE_CMD_1, ACTIVATE_NUM_STATES, }; -static void elan_activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + + G_DEBUG_HERE(); switch (fpi_ssm_get_cur_state(ssm)) { - case ACTIVATE_GET_SENSOR_DIM: - elan_run_cmds(ssm, get_sensor_dim_cmds, get_sensor_dim_cmds_len, - ELAN_CMD_TIMEOUT); + case ACTIVATE_GET_FW_VER: + elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT); break; - case ACTIVATE_SET_SENSOR_DIM: - elandev->frame_width = elandev->last_read[2]; - elandev->raw_frame_width = elandev->last_read[0]; - elandev->frame_height = - elandev->raw_frame_width - 2 * ELAN_FRAME_MARGIN; + case ACTIVATE_SET_FW_VER: + elandev->fw_ver = + (elandev->last_read[0] << 8 | elandev->last_read[1]); + fp_dbg("FW ver 0x%04hx", elandev->fw_ver); fpi_ssm_next_state(ssm); break; - case ACTIVATE_START: - elan_run_cmds(ssm, init_start_cmds, init_start_cmds_len, - ELAN_CMD_TIMEOUT); + case ACTIVATE_GET_SENSOR_DIM: + elan_run_cmd(ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT); break; - case ACTIVATE_READ_DATA: - elan_run_cmds(ssm, read_cmds, read_cmds_len, ELAN_CMD_TIMEOUT); + case ACTIVATE_SET_SENSOR_DIM: + /* see elan_save_frame for details */ + if (elandev->dev_type & ELAN_NOT_ROTATED) { + elandev->frame_width = elandev->last_read[0]; + elandev->frame_height = elandev->raw_frame_height = + elandev->last_read[2]; + } else { + elandev->frame_width = elandev->last_read[2]; + elandev->frame_height = elandev->raw_frame_height = + elandev->last_read[0]; + } + if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT) + elandev->frame_height = ELAN_MAX_FRAME_HEIGHT; + fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width, + elandev->raw_frame_height); + fpi_ssm_next_state(ssm); + break; + case ACTIVATE_CMD_1: + /* TODO: find out what this does, if we need it */ + elan_run_cmd(ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT); break; - case ACTIVATE_END: - elan_run_cmds(ssm, init_end_cmds, init_end_cmds_len, - ELAN_CMD_TIMEOUT); } } -static void activate_complete(struct fpi_ssm *ssm) +static void activate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; G_DEBUG_HERE(); - if (elandev->deactivating) - elan_deactivate(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); - else - elan_calibrate(dev); + if (fpi_ssm_get_error(ssm) != -ECANCELED) { + fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); + } + fpi_ssm_free(ssm); } -static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) +static void elan_activate(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); - elan_dev_reset(elandev); - struct fpi_ssm *ssm = - fpi_ssm_new(fpi_imgdev_get_dev(dev), elan_activate_run_state, ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); - fpi_ssm_start(ssm, activate_complete); - return 0; + fpi_ssm *ssm = + fpi_ssm_new(FP_DEV(dev), activate_run_state, ACTIVATE_NUM_STATES, dev); + fpi_ssm_start(ssm, activate_complete); } static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) @@ -563,64 +800,159 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) G_DEBUG_HERE(); - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } elandev = g_malloc0(sizeof(struct elan_dev)); - fpi_imgdev_set_user_data(dev, elandev); + fp_dev_set_instance_data(FP_DEV(dev), elandev); + + /* common params */ + elandev->dev_type = driver_data; + elandev->background = NULL; + elandev->process_frame = elan_process_frame_thirds; + + switch (driver_data) { + case ELAN_0907: + elandev->process_frame = elan_process_frame_linear; + break; + } + fpi_imgdev_open_complete(dev, 0); return 0; } +static void elan_deactivate(struct fp_img_dev *dev) +{ + G_DEBUG_HERE(); + + fpi_imgdev_deactivate_complete(dev); +} + static void dev_deinit(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); elan_dev_reset(elandev); + g_free(elandev->background); g_free(elandev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } +static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) +{ + G_DEBUG_HERE(); + elan_activate(dev); + return 0; +} + +static void elan_change_state(struct fp_img_dev *dev) +{ + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + enum fp_imgdev_state next_state = elandev->dev_state_next; + + if (elandev->dev_state == next_state) { + fp_dbg("already in %d", next_state); + return; + } else + fp_dbg("changing to %d", next_state); + + switch (next_state) { + case IMGDEV_STATE_INACTIVE: + if (elandev->cur_transfer) + /* deactivation will complete in transfer callback */ + fpi_usb_cancel_transfer(elandev->cur_transfer); + else + elan_deactivate(dev); + break; + case IMGDEV_STATE_AWAIT_FINGER_ON: + /* activation completed or another enroll stage started */ + elan_calibrate(dev); + break; + case IMGDEV_STATE_CAPTURE: + /* not used */ + break; + case IMGDEV_STATE_AWAIT_FINGER_OFF: + elan_stop_capture(dev); + } + + elandev->dev_state = next_state; +} + +static void +elan_change_state_async(struct fp_dev *dev, + void *data) +{ + g_message ("state change dev: %p", dev); + elan_change_state(FP_IMG_DEV (dev)); +} + +static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) +{ + struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_timeout *timeout; + + G_DEBUG_HERE(); + + switch (state) { + case IMGDEV_STATE_INACTIVE: + case IMGDEV_STATE_AWAIT_FINGER_ON: + case IMGDEV_STATE_AWAIT_FINGER_OFF: { + char *name; + + /* schedule state change instead of calling it directly to allow all actions + * related to the previous state to complete */ + elandev->dev_state_next = state; + timeout = fpi_timeout_add(10, elan_change_state_async, FP_DEV(dev), NULL); + + name = g_strdup_printf ("dev_change_state to %d", state); + fpi_timeout_set_name(timeout, name); + g_free (name); + + break; + } + case IMGDEV_STATE_CAPTURE: + /* TODO MAYBE: split capture ssm into smaller ssms and use this state */ + elandev->dev_state = state; + elandev->dev_state_next = state; + break; + default: + fp_err("unrecognized state %d", state); + fpi_imgdev_session_error(dev, -EINVAL); + return -EINVAL; + } + + /* as of time of writing libfprint never checks the return value */ + return 0; +} + static void dev_deactivate(struct fp_img_dev *dev) { - struct elan_dev *elandev = fpi_imgdev_get_user_data(dev); - G_DEBUG_HERE(); - elandev->deactivating = TRUE; - - if (elandev->cur_transfer) - libusb_cancel_transfer(elandev->cur_transfer); - else - elan_deactivate(dev); + dev_change_state(dev, IMGDEV_STATE_INACTIVE); } -static const struct usb_id id_table[] = { - {.vendor = 0x04f3,.product = 0x0907}, - {.vendor = 0x04f3,.product = 0x0c26}, - {0, 0, 0,}, -}; - struct fp_img_driver elan_driver = { .driver = { .id = ELAN_ID, .name = FP_COMPONENT, .full_name = "ElanTech Fingerprint Sensor", - .id_table = id_table, + .id_table = elan_id_table, .scan_type = FP_SCAN_TYPE_SWIPE, }, .flags = 0, - .bz3_threshold = 22, + .bz3_threshold = 24, .open = dev_init, .close = dev_deinit, .activate = dev_activate, .deactivate = dev_deactivate, + .change_state = dev_change_state, }; diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index c929287a..853f31de 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -21,17 +21,38 @@ #ifndef __ELAN_H #define __ELAN_H -#include #include -/* number of pixels to discard on left and right (along raw image height) - * because they have different intensity from the rest of the frame */ -#define ELAN_FRAME_MARGIN 12 +#define ELAN_VEND_ID 0x04f3 + +/* a default device type */ +#define ELAN_ALL_DEV 0 + +/* devices with quirks */ +#define ELAN_0907 (1 << 0) +#define ELAN_0C03 (1 << 1) + +/* devices which don't require frame rotation before assembling */ +#define ELAN_NOT_ROTATED ELAN_0C03 + +/* min FW version that supports calibration */ +#define ELAN_MIN_CALIBRATION_FW 0x0138 + +/* max difference between background image mean and calibration mean + * (the response value of get_calib_mean_cmd)*/ +#define ELAN_CALIBRATION_MAX_DELTA 500 + +/* times to retry reading calibration status during one session + * generally prevents calibration from looping indefinitely */ +#define ELAN_CALIBRATION_ATTEMPTS 10 /* min and max frames in a capture */ #define ELAN_MIN_FRAMES 7 #define ELAN_MAX_FRAMES 30 +/* crop frames to this height to improve stitching */ +#define ELAN_MAX_FRAME_HEIGHT 50 + /* number of frames to drop at the end of capture because frames captured * while the finger is being lifted can be bad */ #define ELAN_SKIP_LAST_FRAMES 1 @@ -41,6 +62,9 @@ #define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN) #define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN) +/* used as response length to tell the driver to skip reading response */ +#define ELAN_CMD_SKIP_READ 0 + /* usual command timeout and timeout for when we need to check if the finger is * still on the device */ #define ELAN_CMD_TIMEOUT 10000 @@ -50,127 +74,149 @@ struct elan_cmd { unsigned char cmd[ELAN_CMD_LEN]; int response_len; int response_in; + unsigned short devices; }; -static const struct elan_cmd get_sensor_dim_cmds[] = { - { - .cmd = {0x00, 0x0c}, - .response_len = 0x4, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd get_sensor_dim_cmd = { + .cmd = {0x00, 0x0c}, + .response_len = 0x4, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t get_sensor_dim_cmds_len = -G_N_ELEMENTS(get_sensor_dim_cmds); - -static const struct elan_cmd init_start_cmds[] = { - { - .cmd = {0x40, 0x19}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - }, - { - .cmd = {0x40, 0x2a}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd get_fw_ver_cmd = { + .cmd = {0x40, 0x19}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t init_start_cmds_len = G_N_ELEMENTS(init_start_cmds); +/* unknown, returns 0x0 0x1 on 0907 */ +static const struct elan_cmd activate_cmd_1 = { + .cmd = {0x40, 0x2a}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_0907, +}; -static const struct elan_cmd read_cmds[] = { - /* raw frame sizes are calculated from image dimesions reported by the +static const struct elan_cmd get_image_cmd = { + .cmd = {0x00, 0x09}, + /* raw frame sizes are calculated from image dimensions reported by the * device */ - { - .cmd = {0x00, 0x09}, - .response_len = -1, - .response_in = ELAN_EP_IMG_IN, - }, + .response_len = -1, + .response_in = ELAN_EP_IMG_IN, + .devices = ELAN_ALL_DEV, }; -const size_t read_cmds_len = G_N_ELEMENTS(read_cmds); - -/* issued after data reads during init and calibration */ -static const struct elan_cmd init_end_cmds[] = { - { - .cmd = {0x40, 0x24}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd read_sensor_status_cmd = { + .cmd = {0x40, 0x13}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t init_end_cmds_len = G_N_ELEMENTS(init_end_cmds); - -/* same command 2 times - * original driver may observe return value to determine how many times it - * should be repeated */ -static const struct elan_cmd calibrate_start_cmds[] = { - { - .cmd = {0x40, 0x23}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - }, - { - .cmd = {0x40, 0x23}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd get_calib_status_cmd = { + .cmd = {0x40, 0x23}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t calibrate_start_cmds_len = -G_N_ELEMENTS(calibrate_start_cmds); - -/* issued after data reads during init and calibration */ -static const struct elan_cmd calibrate_end_cmds[] = { - { - .cmd = {0x40, 0x24}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd get_calib_mean_cmd = { + .cmd = {0x40, 0x24}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t calibrate_end_cmds_len = -G_N_ELEMENTS(calibrate_end_cmds); - -static const struct elan_cmd capture_start_cmds[] = { - /* led on */ - { - .cmd = {0x40, 0x31}, - .response_len = 0x0, - .response_in = ELAN_EP_CMD_IN, - }, +static const struct elan_cmd led_on_cmd = { + .cmd = {0x40, 0x31}, + .response_len = ELAN_CMD_SKIP_READ, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static size_t capture_start_cmds_len = G_N_ELEMENTS(capture_start_cmds); - -static const struct elan_cmd capture_wait_finger_cmds[] = { - /* wait for finger - * subsequent read will not complete until finger is placed on the reader */ - { - .cmd = {0x40, 0x3f}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - }, +/* wait for finger + * subsequent read will not complete until finger is placed on the reader */ +static const struct elan_cmd pre_scan_cmd = { + .cmd = {0x40, 0x3f}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static size_t capture_wait_finger_cmds_len = -G_N_ELEMENTS(capture_wait_finger_cmds); - -static const struct elan_cmd deactivate_cmds[] = { - /* led off */ - { - .cmd = {0x00, 0x0b}, - .response_len = 0x0, - .response_in = ELAN_EP_CMD_IN, - }, +/* led off, stop waiting for finger */ +static const struct elan_cmd stop_cmd = { + .cmd = {0x00, 0x0b}, + .response_len = ELAN_CMD_SKIP_READ, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; -static const size_t deactivate_cmds_len = G_N_ELEMENTS(deactivate_cmds); +static const struct usb_id elan_id_table[] = { + {.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907}, + {.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03}, + {.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV}, + {.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV}, + {0, 0, 0,}, +}; -static void elan_cmd_cb(struct libusb_transfer *transfer); -static void elan_cmd_read(struct fpi_ssm *ssm); -static void elan_run_next_cmd(struct fpi_ssm *ssm); +static void elan_cmd_done(fpi_ssm *ssm); +static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev); +static void elan_calibrate(struct fp_img_dev *dev); static void elan_capture(struct fp_img_dev *dev); +static void elan_deactivate(struct fp_img_dev *dev); + +static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state); #endif diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c index fdaf7f20..97b6913b 100644 --- a/libfprint/drivers/etes603.c +++ b/libfprint/drivers/etes603.c @@ -639,14 +639,11 @@ enum { static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb, void *cb_arg) { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *buffer; int length; - if (!transfer) - return -ENOMEM; - if (ep == EP_OUT) { buffer = (unsigned char *)dev->req; length = dev->req_len; @@ -656,7 +653,7 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb, } else { return -EIO; } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(idev), ep, buffer, length, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(idev)), ep, buffer, length, cb, cb_arg, BULK_TIMEOUT); if (libusb_submit_transfer(transfer)) { @@ -669,14 +666,14 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb, static void async_tx_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_warn("transfer is not completed (status=%d)", transfer->status); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); libusb_free_transfer(transfer); } else { unsigned char endpoint = transfer->endpoint; @@ -691,7 +688,7 @@ static void async_tx_cb(struct libusb_transfer *transfer) length, actual_length); /* Chained with the answer */ if (async_tx(idev, EP_IN, async_tx_cb, ssm)) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } else if (endpoint == EP_IN) { dev->ans_len = actual_length; fpi_ssm_next_state(ssm); @@ -699,10 +696,10 @@ static void async_tx_cb(struct libusb_transfer *transfer) } } -static void m_exit_state(struct fpi_ssm *ssm) +static void m_exit_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case EXIT_SET_REGS_REQ: @@ -724,12 +721,12 @@ static void m_exit_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_exit_complete(struct fpi_ssm *ssm) +static void m_exit_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *idev = user_data; if (fpi_ssm_get_error(ssm)) { fp_err("Error switching the device to idle state"); @@ -742,17 +739,16 @@ static void m_exit_complete(struct fpi_ssm *ssm) static void m_exit_start(struct fp_img_dev *idev) { - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_exit_state, - EXIT_NUM_STATES); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), m_exit_state, + EXIT_NUM_STATES, idev); fp_dbg("Switching device to idle mode"); - fpi_ssm_set_user_data(ssm, idev); fpi_ssm_start(ssm, m_exit_complete); } -static void m_capture_state(struct fpi_ssm *ssm) +static void m_capture_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (dev->is_active == FALSE) { fpi_ssm_mark_completed(ssm); @@ -827,13 +823,13 @@ static void m_capture_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_capture_complete(struct fpi_ssm *ssm) +static void m_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (fpi_ssm_get_error(ssm)) { if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) { @@ -852,10 +848,10 @@ static void m_capture_complete(struct fpi_ssm *ssm) } } -static void m_finger_state(struct fpi_ssm *ssm) +static void m_finger_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (dev->is_active == FALSE) { fpi_ssm_mark_completed(ssm); @@ -945,19 +941,18 @@ static void m_finger_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_finger_complete(struct fpi_ssm *ssm) +static void m_finger_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (!fpi_ssm_get_error(ssm)) { - struct fpi_ssm *ssm_cap; - ssm_cap = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_capture_state, - CAP_NUM_STATES); - fpi_ssm_set_user_data(ssm_cap, idev); + fpi_ssm *ssm_cap; + ssm_cap = fpi_ssm_new(FP_DEV(idev), m_capture_state, + CAP_NUM_STATES, idev); fpi_ssm_start(ssm_cap, m_capture_complete); } else { if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) { @@ -973,19 +968,18 @@ static void m_finger_complete(struct fpi_ssm *ssm) static void m_start_fingerdetect(struct fp_img_dev *idev) { - struct fpi_ssm *ssmf; - ssmf = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_finger_state, FGR_NUM_STATES); - fpi_ssm_set_user_data(ssmf, idev); + fpi_ssm *ssmf; + ssmf = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev); fpi_ssm_start(ssmf, m_finger_complete); } /* * Tune value of VRT and VRB for contrast and brightness. */ -static void m_tunevrb_state(struct fpi_ssm *ssm) +static void m_tunevrb_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); float hist[5]; if (dev->is_active == FALSE) { @@ -1131,19 +1125,19 @@ static void m_tunevrb_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_tunevrb_complete(struct fpi_ssm *ssm) +static void m_tunevrb_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *idev = user_data; fpi_imgdev_activate_complete(idev, fpi_ssm_get_error(ssm) != 0); if (!fpi_ssm_get_error(ssm)) { fp_dbg("Tuning is done. Starting finger detection."); m_start_fingerdetect(idev); } else { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); fp_err("Error while tuning VRT"); dev->is_active = FALSE; reset_param(dev); @@ -1156,10 +1150,10 @@ static void m_tunevrb_complete(struct fpi_ssm *ssm) * This function tunes the DCoffset value and adjusts the gain value if * required. */ -static void m_tunedc_state(struct fpi_ssm *ssm) +static void m_tunedc_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (dev->is_active == FALSE) { fpi_ssm_mark_completed(ssm); @@ -1255,21 +1249,20 @@ static void m_tunedc_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_tunedc_complete(struct fpi_ssm *ssm) +static void m_tunedc_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *idev = user_data; if (!fpi_ssm_get_error(ssm)) { - struct fpi_ssm *ssm_tune; - ssm_tune = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_tunevrb_state, - TUNEVRB_NUM_STATES); - fpi_ssm_set_user_data(ssm_tune, idev); + fpi_ssm *ssm_tune; + ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunevrb_state, + TUNEVRB_NUM_STATES, idev); fpi_ssm_start(ssm_tune, m_tunevrb_complete); } else { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); fp_err("Error while tuning DCOFFSET"); dev->is_active = FALSE; reset_param(dev); @@ -1278,10 +1271,10 @@ static void m_tunedc_complete(struct fpi_ssm *ssm) fpi_ssm_free(ssm); } -static void m_init_state(struct fpi_ssm *ssm) +static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); if (dev->is_active == FALSE) { fpi_ssm_mark_completed(ssm); @@ -1375,21 +1368,20 @@ static void m_init_state(struct fpi_ssm *ssm) return; err: - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } -static void m_init_complete(struct fpi_ssm *ssm) +static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *idev = user_data; if (!fpi_ssm_get_error(ssm)) { - struct fpi_ssm *ssm_tune; - ssm_tune = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_tunedc_state, - TUNEDC_NUM_STATES); - fpi_ssm_set_user_data(ssm_tune, idev); + fpi_ssm *ssm_tune; + ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunedc_state, + TUNEDC_NUM_STATES, idev); fpi_ssm_start(ssm_tune, m_tunedc_complete); } else { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); fp_err("Error initializing the device"); dev->is_active = FALSE; reset_param(dev); @@ -1400,8 +1392,8 @@ static void m_init_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); - struct fpi_ssm *ssm; + struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); + fpi_ssm *ssm; g_assert(dev); @@ -1416,16 +1408,14 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) if (dev->dcoffset == 0) { fp_dbg("Tuning device..."); - ssm = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_init_state, INIT_NUM_STATES); - fpi_ssm_set_user_data(ssm, idev); + ssm = fpi_ssm_new(FP_DEV(idev), m_init_state, INIT_NUM_STATES, idev); fpi_ssm_start(ssm, m_init_complete); } else { fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X," "VRB=0x%02X,GAIN=0x%02X).", dev->dcoffset, dev->vrt, dev->vrb, dev->gain); fpi_imgdev_activate_complete(idev, 0); - ssm = fpi_ssm_new(fpi_imgdev_get_dev(idev), m_finger_state, FGR_NUM_STATES); - fpi_ssm_set_user_data(ssm, idev); + ssm = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev); fpi_ssm_start(ssm, m_finger_complete); } return 0; @@ -1433,7 +1423,7 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *idev) { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); fp_dbg("deactivating"); @@ -1450,13 +1440,13 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) struct etes603_dev *dev; dev = g_malloc0(sizeof(struct etes603_dev)); - fpi_imgdev_set_user_data(idev, dev); + fp_dev_set_instance_data(FP_DEV(idev), dev); dev->req = g_malloc(sizeof(struct egis_msg)); dev->ans = g_malloc(FE_SIZE); dev->fp = g_malloc(FE_SIZE * 4); - ret = libusb_claim_interface(fpi_imgdev_get_usb_dev(idev), 0); + ret = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); if (ret != LIBUSB_SUCCESS) { fp_err("libusb_claim_interface failed on interface 0: %s", libusb_error_name(ret)); return ret; @@ -1468,14 +1458,14 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) static void dev_close(struct fp_img_dev *idev) { - struct etes603_dev *dev = fpi_imgdev_get_user_data(idev); + struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); g_free(dev->req); g_free(dev->ans); g_free(dev->fp); g_free(dev); - libusb_release_interface(fpi_imgdev_get_usb_dev(idev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); fpi_imgdev_close_complete(idev); } diff --git a/libfprint/drivers/fdu2000.c b/libfprint/drivers/fdu2000.c index bdd2983d..44b993dc 100644 --- a/libfprint/drivers/fdu2000.c +++ b/libfprint/drivers/fdu2000.c @@ -169,25 +169,25 @@ capture(struct fp_img_dev *dev, gboolean unconditional, image = g_malloc0(RAW_IMAGE_SIZE); - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_ON))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_ON))) { fp_err("Command: LED_ON"); goto out; } - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READY))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READY))) { fp_err("Command: CAPTURE_READY"); goto out; } read: - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READ))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_READ))) { fp_err("Command: CAPTURE_READ"); goto out; } /* Now we are ready to read from dev */ - r = libusb_bulk_transfer(fpi_imgdev_get_usb_dev(dev), &msg, &bytes, BULK_TIMEOUT * 10); + r = libusb_bulk_transfer(fpi_dev_get_usb_dev(FP_DEV(dev)), &msg, &bytes, BULK_TIMEOUT * 10); if (r < 0 || bytes < 1) goto read; @@ -215,7 +215,7 @@ read: p += sizeof SOL + 4; int j; for (j = 0; j < RAW_IMAGE_WIDTH; j++) { - /** + /* * Convert from 4 to 8 bits * The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1 */ @@ -228,12 +228,12 @@ read: } } - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) { fp_err("Command: CAPTURE_END"); goto out; } - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) { fp_err("Command: LED_OFF"); goto out; } @@ -254,27 +254,27 @@ static gint dev_init(struct fp_img_dev *dev, unsigned long driver_data) { gint r; - //if ( (r = usb_set_configuration(fpi_imgdev_get_usb_dev(dev), 1)) < 0 ) + //if ( (r = usb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 ) // goto out; - if ( (r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0)) < 0 ) { + if ( (r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0)) < 0 ) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } - //if ( (r = usb_set_altinterface(fpi_imgdev_get_usb_dev(dev), 1)) < 0 ) + //if ( (r = usb_set_altinterface(fpi_dev_get_usb_dev(FP_DEV(dev)), 1)) < 0 ) // goto out; - //if ( (r = usb_clear_halt(fpi_imgdev_get_usb_dev(dev), EP_CMD)) < 0 ) + //if ( (r = usb_clear_halt(fpi_dev_get_usb_dev(FP_DEV(dev)), EP_CMD)) < 0 ) // goto out; /* Make sure sensor mode is not capture_{ready|read} */ - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END))) { fp_err("Command: CAPTURE_END"); goto out; } - if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) { + if ((r = bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), LED_OFF))) { fp_err("Command: LED_OFF"); goto out; } @@ -289,10 +289,10 @@ out: static void dev_exit(struct fp_img_dev *dev) { - if (bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END)) + if (bulk_write_safe(fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_END)) fp_err("Command: CAPTURE_END"); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); } static const struct usb_id id_table[] = { diff --git a/libfprint/drivers/upek_proto.c b/libfprint/drivers/upek_proto.c new file mode 100644 index 00000000..0ecc4b13 --- /dev/null +++ b/libfprint/drivers/upek_proto.c @@ -0,0 +1,66 @@ +/* + * LGPL CRC code copied from GStreamer-0.10.10: + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) 2004,2006 Thomas Vander Stichele + + * 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; version + * 2.1 of the License. + * + * 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 "upek_proto.h" + +static const uint16_t crc_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +uint16_t +udf_crc(unsigned char *buffer, size_t size) +{ + uint16_t crc = 0; + while (size--) + crc = (uint16_t) ((crc << 8) ^ + crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]); + return crc; +} diff --git a/libfprint/drivers/upek_proto.h b/libfprint/drivers/upek_proto.h new file mode 100644 index 00000000..2c3a617d --- /dev/null +++ b/libfprint/drivers/upek_proto.h @@ -0,0 +1,24 @@ +/* + * LGPL CRC code copied from GStreamer-0.10.10: + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) 2004,2006 Thomas Vander Stichele + + * 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; version + * 2.1 of the License. + * + * 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 +#include + +uint16_t udf_crc(unsigned char *buffer, size_t size); diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c index 9cccb865..99c5ffae 100644 --- a/libfprint/drivers/upeksonly.c +++ b/libfprint/drivers/upeksonly.c @@ -81,7 +81,7 @@ struct sonly_dev { int dev_model; int img_width; - struct fpi_ssm *loopsm; + fpi_ssm *loopsm; struct libusb_transfer *img_transfer[NUM_BULK_TRANSFERS]; struct img_transfer_data *img_transfer_data; int num_flying; @@ -100,18 +100,21 @@ struct sonly_dev { enum sonly_kill_transfers_action killing_transfers; int kill_status_code; union { - struct fpi_ssm *kill_ssm; + fpi_ssm *kill_ssm; void (*kill_cb)(struct fp_img_dev *dev); }; }; -/* Calculade squared standand deviation of sum of two lines */ +/* Calculate squared standard deviation of sum of two lines */ static int upeksonly_get_deviation2(struct fpi_line_asmbl_ctx *ctx, GSList *line1, GSList *line2) { unsigned char *buf1 = line1->data, *buf2 = line2->data; int res = 0, mean = 0, i; + + g_assert (ctx->line_width > 0); + for (i = 0; i < ctx->line_width; i+= 2) mean += (int)buf1[i + 1] + (int)buf2[i]; @@ -176,11 +179,11 @@ static void free_img_transfers(struct sonly_dev *sdev) static void last_transfer_killed(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); switch (sdev->killing_transfers) { case ABORT_SSM: fp_dbg("abort ssm error %d", sdev->kill_status_code); - fpi_ssm_mark_aborted(sdev->kill_ssm, sdev->kill_status_code); + fpi_ssm_mark_failed(sdev->kill_ssm, sdev->kill_status_code); return; case ITERATE_SSM: fp_dbg("iterate ssm"); @@ -197,7 +200,7 @@ static void last_transfer_killed(struct fp_img_dev *dev) static void cancel_img_transfers(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); int i; if (sdev->num_flying == 0) { @@ -224,7 +227,7 @@ static gboolean is_capturing(struct sonly_dev *sdev) static void handoff_img(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); struct fp_img *img; GSList *elem = sdev->rows; @@ -252,7 +255,7 @@ static void handoff_img(struct fp_img_dev *dev) static void row_complete(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); sdev->rowbuf_offset = -1; if (sdev->num_rows > 0) { @@ -340,7 +343,7 @@ static void row_complete(struct fp_img_dev *dev) /* add data to row buffer */ static void add_to_rowbuf(struct fp_img_dev *dev, unsigned char *data, int size) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); memcpy(sdev->rowbuf + sdev->rowbuf_offset, data, size); sdev->rowbuf_offset += size; @@ -374,7 +377,7 @@ static int rowbuf_remaining(struct sonly_dev *sdev) static void handle_packet(struct fp_img_dev *dev, unsigned char *data) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); uint16_t seqnum = data[0] << 8 | data[1]; int abs_base_addr; int for_rowbuf; @@ -470,7 +473,7 @@ static void img_data_cb(struct libusb_transfer *transfer) { struct img_transfer_data *idata = transfer->user_data; struct fp_img_dev *dev = idata->dev; - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); int i; idata->flying = FALSE; @@ -520,7 +523,7 @@ static void img_data_cb(struct libusb_transfer *transfer) /***** STATE MACHINE HELPERS *****/ struct write_regs_data { - struct fpi_ssm *ssm; + fpi_ssm *ssm; struct libusb_transfer *transfer; const struct sonly_regwrite *regs; size_t num_regs; @@ -534,7 +537,7 @@ static void write_regs_finished(struct write_regs_data *wrdata, int result) if (result == 0) fpi_ssm_next_state(wrdata->ssm); else - fpi_ssm_mark_aborted(wrdata->ssm, result); + fpi_ssm_mark_failed(wrdata->ssm, result); g_free(wrdata); } @@ -574,23 +577,18 @@ static void write_regs_cb(struct libusb_transfer *transfer) write_regs_iterate(wrdata); } -static void sm_write_regs(struct fpi_ssm *ssm, - const struct sonly_regwrite *regs, size_t num_regs) +static void +sm_write_regs(fpi_ssm *ssm, + struct fp_dev *dev, + const struct sonly_regwrite *regs, + size_t num_regs) { struct write_regs_data *wrdata = g_malloc(sizeof(*wrdata)); unsigned char *data; - struct fp_dev *dev; - - wrdata->transfer = libusb_alloc_transfer(0); - if (!wrdata->transfer) { - g_free(wrdata); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } + wrdata->transfer = fpi_usb_alloc(); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); libusb_fill_control_setup(data, 0x40, 0x0c, 0, 0, 1); - dev = fpi_ssm_get_dev(ssm); libusb_fill_control_transfer(wrdata->transfer, fpi_dev_get_usb_dev(dev), data, write_regs_cb, wrdata, CTRL_TIMEOUT); @@ -605,31 +603,29 @@ static void sm_write_regs(struct fpi_ssm *ssm, static void sm_write_reg_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; g_free(transfer->buffer); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else fpi_ssm_next_state(ssm); } -static void sm_write_reg(struct fpi_ssm *ssm, uint8_t reg, uint8_t value) +static void +sm_write_reg(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint8_t reg, + uint8_t value) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - fp_dbg("set %02x=%02x", reg, value); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); libusb_fill_control_setup(data, 0x40, 0x0c, 0, reg, 1); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb, ssm, CTRL_TIMEOUT); @@ -641,18 +637,18 @@ static void sm_write_reg(struct fpi_ssm *ssm, uint8_t reg, uint8_t value) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } static void sm_read_reg_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } else { sdev->read_reg_result = libusb_control_transfer_get_data(transfer)[0]; fp_dbg("read reg result = %02x", sdev->read_reg_result); @@ -662,22 +658,19 @@ static void sm_read_reg_cb(struct libusb_transfer *transfer) g_free(transfer->buffer); } -static void sm_read_reg(struct fpi_ssm *ssm, uint8_t reg) +static void +sm_read_reg(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint8_t reg) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - fp_dbg("read reg %02x", reg); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 8); libusb_fill_control_setup(data, 0xc0, 0x0c, 0, reg, 8); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_read_reg_cb, ssm, CTRL_TIMEOUT); transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | @@ -687,19 +680,19 @@ static void sm_read_reg(struct fpi_ssm *ssm, uint8_t reg) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } static void sm_await_intr_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { g_free(transfer->buffer); - fpi_ssm_mark_aborted(ssm, transfer->status); + fpi_ssm_mark_failed(ssm, transfer->status); return; } @@ -713,21 +706,17 @@ static void sm_await_intr_cb(struct libusb_transfer *transfer) fpi_ssm_next_state(ssm); } -static void sm_await_intr(struct fpi_ssm *ssm) +static void +sm_await_intr(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - G_DEBUG_HERE(); data = g_malloc(4); - libusb_fill_interrupt_transfer(transfer, fpi_imgdev_get_usb_dev(dev), + libusb_fill_interrupt_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), 0x83, data, 4, sm_await_intr_cb, ssm, 0); transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | @@ -737,7 +726,7 @@ static void sm_await_intr(struct fpi_ssm *ssm) if (r < 0) { libusb_free_transfer(transfer); g_free(data); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } @@ -763,61 +752,61 @@ enum awfsm_1000_states { AWFSM_1000_NUM_STATES, }; -static void awfsm_2016_run_state(struct fpi_ssm *ssm) +static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case AWFSM_2016_WRITEV_1: - sm_write_regs(ssm, awfsm_2016_writev_1, G_N_ELEMENTS(awfsm_2016_writev_1)); + sm_write_regs(ssm, _dev, awfsm_2016_writev_1, G_N_ELEMENTS(awfsm_2016_writev_1)); break; case AWFSM_2016_READ_01: - sm_read_reg(ssm, 0x01); + sm_read_reg(ssm, dev, 0x01); break; case AWFSM_2016_WRITE_01: if (sdev->read_reg_result != 0xc6) - sm_write_reg(ssm, 0x01, 0x46); + sm_write_reg(ssm, dev, 0x01, 0x46); else - sm_write_reg(ssm, 0x01, 0xc6); + sm_write_reg(ssm, dev, 0x01, 0xc6); break; case AWFSM_2016_WRITEV_2: - sm_write_regs(ssm, awfsm_2016_writev_2, G_N_ELEMENTS(awfsm_2016_writev_2)); + sm_write_regs(ssm, _dev, awfsm_2016_writev_2, G_N_ELEMENTS(awfsm_2016_writev_2)); break; case AWFSM_2016_READ_13: - sm_read_reg(ssm, 0x13); + sm_read_reg(ssm, dev, 0x13); break; case AWFSM_2016_WRITE_13: if (sdev->read_reg_result != 0x45) - sm_write_reg(ssm, 0x13, 0x05); + sm_write_reg(ssm, dev, 0x13, 0x05); else - sm_write_reg(ssm, 0x13, 0x45); + sm_write_reg(ssm, dev, 0x13, 0x45); break; case AWFSM_2016_WRITEV_3: - sm_write_regs(ssm, awfsm_2016_writev_3, G_N_ELEMENTS(awfsm_2016_writev_3)); + sm_write_regs(ssm, _dev, awfsm_2016_writev_3, G_N_ELEMENTS(awfsm_2016_writev_3)); break; case AWFSM_2016_READ_07: - sm_read_reg(ssm, 0x07); + sm_read_reg(ssm, dev, 0x07); break; case AWFSM_2016_WRITE_07: if (sdev->read_reg_result != 0x10 && sdev->read_reg_result != 0x90) fp_warn("odd reg7 value %x", sdev->read_reg_result); - sm_write_reg(ssm, 0x07, sdev->read_reg_result); + sm_write_reg(ssm, dev, 0x07, sdev->read_reg_result); break; case AWFSM_2016_WRITEV_4: - sm_write_regs(ssm, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4)); + sm_write_regs(ssm, _dev, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4)); break; } } -static void awfsm_1000_run_state(struct fpi_ssm *ssm) +static void awfsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case AWFSM_1000_WRITEV_1: - sm_write_regs(ssm, awfsm_1000_writev_1, G_N_ELEMENTS(awfsm_1000_writev_1)); + sm_write_regs(ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS(awfsm_1000_writev_1)); break; case AWFSM_1000_WRITEV_2: - sm_write_regs(ssm, awfsm_1000_writev_2, G_N_ELEMENTS(awfsm_1000_writev_2)); + sm_write_regs(ssm, _dev, awfsm_1000_writev_2, G_N_ELEMENTS(awfsm_1000_writev_2)); break; } } @@ -851,17 +840,19 @@ enum capsm_1001_states { CAPSM_1001_NUM_STATES, }; -static void capsm_fire_bulk(struct fpi_ssm *ssm) +static void +capsm_fire_bulk(fpi_ssm *ssm, + struct fp_dev *_dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = FP_IMG_DEV(_dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); int i; for (i = 0; i < NUM_BULK_TRANSFERS; i++) { int r = libusb_submit_transfer(sdev->img_transfer[i]); if (r < 0) { if (i == 0) { /* first one failed: easy peasy */ - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); return; } @@ -881,10 +872,10 @@ static void capsm_fire_bulk(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); } -static void capsm_2016_run_state(struct fpi_ssm *ssm) +static void capsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_2016_INIT: @@ -899,24 +890,23 @@ static void capsm_2016_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case CAPSM_2016_WRITE_15: - sm_write_reg(ssm, 0x15, 0x20); + sm_write_reg(ssm, dev, 0x15, 0x20); break; case CAPSM_2016_WRITE_30: - sm_write_reg(ssm, 0x30, 0xe0); + sm_write_reg(ssm, dev, 0x30, 0xe0); break; case CAPSM_2016_FIRE_BULK: ; - capsm_fire_bulk (ssm); + capsm_fire_bulk (ssm, _dev); break; case CAPSM_2016_WRITEV: - sm_write_regs(ssm, capsm_2016_writev, G_N_ELEMENTS(capsm_2016_writev)); + sm_write_regs(ssm, _dev, capsm_2016_writev, G_N_ELEMENTS(capsm_2016_writev)); break; } } -static void capsm_1000_run_state(struct fpi_ssm *ssm) +static void capsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_1000_INIT: @@ -931,18 +921,17 @@ static void capsm_1000_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case CAPSM_1000_FIRE_BULK: ; - capsm_fire_bulk (ssm); + capsm_fire_bulk (ssm, _dev); break; case CAPSM_1000_WRITEV: - sm_write_regs(ssm, capsm_1000_writev, G_N_ELEMENTS(capsm_1000_writev)); + sm_write_regs(ssm, _dev, capsm_1000_writev, G_N_ELEMENTS(capsm_1000_writev)); break; } } -static void capsm_1001_run_state(struct fpi_ssm *ssm) +static void capsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_1001_INIT: @@ -957,22 +946,22 @@ static void capsm_1001_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case CAPSM_1001_FIRE_BULK: ; - capsm_fire_bulk (ssm); + capsm_fire_bulk (ssm, _dev); break; case CAPSM_1001_WRITEV_1: - sm_write_regs(ssm, capsm_1001_writev_1, G_N_ELEMENTS(capsm_1001_writev_1)); + sm_write_regs(ssm, _dev, capsm_1001_writev_1, G_N_ELEMENTS(capsm_1001_writev_1)); break; case CAPSM_1001_WRITEV_2: - sm_write_regs(ssm, capsm_1001_writev_2, G_N_ELEMENTS(capsm_1001_writev_2)); + sm_write_regs(ssm, _dev, capsm_1001_writev_2, G_N_ELEMENTS(capsm_1001_writev_2)); break; case CAPSM_1001_WRITEV_3: - sm_write_regs(ssm, capsm_1001_writev_3, G_N_ELEMENTS(capsm_1001_writev_3)); + sm_write_regs(ssm, _dev, capsm_1001_writev_3, G_N_ELEMENTS(capsm_1001_writev_3)); break; case CAPSM_1001_WRITEV_4: - sm_write_regs(ssm, capsm_1001_writev_4, G_N_ELEMENTS(capsm_1001_writev_4)); + sm_write_regs(ssm, _dev, capsm_1001_writev_4, G_N_ELEMENTS(capsm_1001_writev_4)); break; case CAPSM_1001_WRITEV_5: - sm_write_regs(ssm, capsm_1001_writev_5, G_N_ELEMENTS(capsm_1001_writev_5)); + sm_write_regs(ssm, _dev, capsm_1001_writev_5, G_N_ELEMENTS(capsm_1001_writev_5)); break; } } @@ -994,29 +983,29 @@ enum deinitsm_1001_states { DEINITSM_1001_NUM_STATES, }; -static void deinitsm_2016_run_state(struct fpi_ssm *ssm) +static void deinitsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_2016_WRITEV: - sm_write_regs(ssm, deinitsm_2016_writev, G_N_ELEMENTS(deinitsm_2016_writev)); + sm_write_regs(ssm, _dev, deinitsm_2016_writev, G_N_ELEMENTS(deinitsm_2016_writev)); break; } } -static void deinitsm_1000_run_state(struct fpi_ssm *ssm) +static void deinitsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_1000_WRITEV: - sm_write_regs(ssm, deinitsm_1000_writev, G_N_ELEMENTS(deinitsm_1000_writev)); + sm_write_regs(ssm, _dev, deinitsm_1000_writev, G_N_ELEMENTS(deinitsm_1000_writev)); break; } } -static void deinitsm_1001_run_state(struct fpi_ssm *ssm) +static void deinitsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_1001_WRITEV: - sm_write_regs(ssm, deinitsm_1001_writev, G_N_ELEMENTS(deinitsm_1001_writev)); + sm_write_regs(ssm, _dev, deinitsm_1001_writev, G_N_ELEMENTS(deinitsm_1001_writev)); break; } } @@ -1048,62 +1037,62 @@ enum initsm_1001_states { INITSM_1001_NUM_STATES, }; -static void initsm_2016_run_state(struct fpi_ssm *ssm) +static void initsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_2016_WRITEV_1: - sm_write_regs(ssm, initsm_2016_writev_1, G_N_ELEMENTS(initsm_2016_writev_1)); + sm_write_regs(ssm, _dev, initsm_2016_writev_1, G_N_ELEMENTS(initsm_2016_writev_1)); break; case INITSM_2016_READ_09: - sm_read_reg(ssm, 0x09); + sm_read_reg(ssm, dev, 0x09); break; case INITSM_2016_WRITE_09: - sm_write_reg(ssm, 0x09, sdev->read_reg_result & ~0x08); + sm_write_reg(ssm, dev, 0x09, sdev->read_reg_result & ~0x08); break; case INITSM_2016_READ_13: - sm_read_reg(ssm, 0x13); + sm_read_reg(ssm, dev, 0x13); break; case INITSM_2016_WRITE_13: - sm_write_reg(ssm, 0x13, sdev->read_reg_result & ~0x10); + sm_write_reg(ssm, dev, 0x13, sdev->read_reg_result & ~0x10); break; case INITSM_2016_WRITE_04: - sm_write_reg(ssm, 0x04, 0x00); + sm_write_reg(ssm, dev, 0x04, 0x00); break; case INITSM_2016_WRITE_05: - sm_write_reg(ssm, 0x05, 0x00); + sm_write_reg(ssm, dev, 0x05, 0x00); break; } } -static void initsm_1000_run_state(struct fpi_ssm *ssm) +static void initsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_1000_WRITEV_1: - sm_write_regs(ssm, initsm_1000_writev_1, G_N_ELEMENTS(initsm_1000_writev_1)); + sm_write_regs(ssm, _dev, initsm_1000_writev_1, G_N_ELEMENTS(initsm_1000_writev_1)); break; } } -static void initsm_1001_run_state(struct fpi_ssm *ssm) +static void initsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_1001_WRITEV_1: - sm_write_regs(ssm, initsm_1001_writev_1, G_N_ELEMENTS(initsm_1001_writev_1)); + sm_write_regs(ssm, _dev, initsm_1001_writev_1, G_N_ELEMENTS(initsm_1001_writev_1)); break; case INITSM_1001_WRITEV_2: - sm_write_regs(ssm, initsm_1001_writev_2, G_N_ELEMENTS(initsm_1001_writev_2)); + sm_write_regs(ssm, _dev, initsm_1001_writev_2, G_N_ELEMENTS(initsm_1001_writev_2)); break; case INITSM_1001_WRITEV_3: - sm_write_regs(ssm, initsm_1001_writev_3, G_N_ELEMENTS(initsm_1001_writev_3)); + sm_write_regs(ssm, _dev, initsm_1001_writev_3, G_N_ELEMENTS(initsm_1001_writev_3)); break; case INITSM_1001_WRITEV_4: - sm_write_regs(ssm, initsm_1001_writev_4, G_N_ELEMENTS(initsm_1001_writev_4)); + sm_write_regs(ssm, _dev, initsm_1001_writev_4, G_N_ELEMENTS(initsm_1001_writev_4)); break; case INITSM_1001_WRITEV_5: - sm_write_regs(ssm, initsm_1001_writev_5, G_N_ELEMENTS(initsm_1001_writev_5)); + sm_write_regs(ssm, _dev, initsm_1001_writev_5, G_N_ELEMENTS(initsm_1001_writev_5)); break; } } @@ -1120,10 +1109,10 @@ enum loopsm_states { LOOPSM_NUM_STATES, }; -static void loopsm_run_state(struct fpi_ssm *ssm) +static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case LOOPSM_RUN_AWFSM: ; @@ -1139,18 +1128,17 @@ static void loopsm_run_state(struct fpi_ssm *ssm) if (sdev->deactivating) { fpi_ssm_mark_completed(ssm); } else { - struct fpi_ssm *awfsm = NULL; + fpi_ssm *awfsm = NULL; switch (sdev->dev_model) { case UPEKSONLY_2016: - awfsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), awfsm_2016_run_state, - AWFSM_2016_NUM_STATES); + awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_2016_run_state, + AWFSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - awfsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), awfsm_1000_run_state, - AWFSM_1000_NUM_STATES); + awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_1000_run_state, + AWFSM_1000_NUM_STATES, dev); break; } - fpi_ssm_set_user_data(awfsm, dev); fpi_ssm_start_subsm(ssm, awfsm); } break; @@ -1162,49 +1150,47 @@ static void loopsm_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; default: - sm_await_intr(ssm); + sm_await_intr(ssm, dev); break; } break; case LOOPSM_RUN_CAPSM: ; - struct fpi_ssm *capsm = NULL; + fpi_ssm *capsm = NULL; switch (sdev->dev_model) { case UPEKSONLY_2016: - capsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capsm_2016_run_state, - CAPSM_2016_NUM_STATES); + capsm = fpi_ssm_new(FP_DEV(dev), capsm_2016_run_state, + CAPSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - capsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capsm_1000_run_state, - CAPSM_1000_NUM_STATES); + capsm = fpi_ssm_new(FP_DEV(dev), capsm_1000_run_state, + CAPSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - capsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capsm_1001_run_state, - CAPSM_1001_NUM_STATES); + capsm = fpi_ssm_new(FP_DEV(dev), capsm_1001_run_state, + CAPSM_1001_NUM_STATES, dev); break; } - fpi_ssm_set_user_data(capsm, dev); fpi_ssm_start_subsm(ssm, capsm); break; case LOOPSM_CAPTURE: break; case LOOPSM_RUN_DEINITSM: ; - struct fpi_ssm *deinitsm = NULL; + fpi_ssm *deinitsm = NULL; switch (sdev->dev_model) { case UPEKSONLY_2016: - deinitsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), deinitsm_2016_run_state, - DEINITSM_2016_NUM_STATES); + deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_2016_run_state, + DEINITSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - deinitsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), deinitsm_1000_run_state, - DEINITSM_1000_NUM_STATES); + deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1000_run_state, + DEINITSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - deinitsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), deinitsm_1001_run_state, - DEINITSM_1001_NUM_STATES); + deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1001_run_state, + DEINITSM_1001_NUM_STATES, dev); break; } sdev->capturing = FALSE; - fpi_ssm_set_user_data(deinitsm, dev); fpi_ssm_start_subsm(ssm, deinitsm); break; case LOOPSM_FINAL: @@ -1218,7 +1204,7 @@ static void loopsm_run_state(struct fpi_ssm *ssm) static void deactivate_done(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); free_img_transfers(sdev); @@ -1235,7 +1221,7 @@ static void deactivate_done(struct fp_img_dev *dev) static void dev_deactivate(struct fp_img_dev *dev) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (!sdev->capturing) { deactivate_done(dev); @@ -1248,10 +1234,10 @@ static void dev_deactivate(struct fp_img_dev *dev) cancel_img_transfers(dev); } -static void loopsm_complete(struct fpi_ssm *ssm) +static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); int r = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -1267,10 +1253,10 @@ static void loopsm_complete(struct fpi_ssm *ssm) } } -static void initsm_complete(struct fpi_ssm *ssm) +static void initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); int r = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -1278,15 +1264,14 @@ static void initsm_complete(struct fpi_ssm *ssm) if (r != 0) return; - sdev->loopsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), loopsm_run_state, LOOPSM_NUM_STATES); - fpi_ssm_set_user_data(sdev->loopsm, dev); + sdev->loopsm = fpi_ssm_new(FP_DEV(dev), loopsm_run_state, LOOPSM_NUM_STATES, dev); fpi_ssm_start(sdev->loopsm, loopsm_complete); } static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct sonly_dev *sdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = NULL; + struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = NULL; int i; sdev->deactivating = FALSE; @@ -1299,31 +1284,26 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) sdev->num_flying = 0; for (i = 0; i < NUM_BULK_TRANSFERS; i++) { unsigned char *data; - sdev->img_transfer[i] = libusb_alloc_transfer(0); - if (!sdev->img_transfer[i]) { - free_img_transfers(sdev); - return -ENOMEM; - } + sdev->img_transfer[i] = fpi_usb_alloc(); sdev->img_transfer_data[i].idx = i; sdev->img_transfer_data[i].dev = dev; data = g_malloc(4096); - libusb_fill_bulk_transfer(sdev->img_transfer[i], fpi_imgdev_get_usb_dev(dev), + libusb_fill_bulk_transfer(sdev->img_transfer[i], fpi_dev_get_usb_dev(FP_DEV(dev)), 0x81, data, 4096, img_data_cb, &sdev->img_transfer_data[i], 0); } switch (sdev->dev_model) { case UPEKSONLY_2016: - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), initsm_2016_run_state, INITSM_2016_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), initsm_2016_run_state, INITSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), initsm_1000_run_state, INITSM_1000_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), initsm_1000_run_state, INITSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), initsm_1001_run_state, INITSM_1001_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), initsm_1001_run_state, INITSM_1001_NUM_STATES, dev); break; } - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, initsm_complete); return 0; } @@ -1333,9 +1313,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data); static void dev_deinit(struct fp_img_dev *dev) { void *user_data; - user_data = fpi_imgdev_get_user_data(dev); + user_data = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(user_data); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } @@ -1387,20 +1367,20 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct sonly_dev *sdev; - r = libusb_set_configuration(fpi_imgdev_get_usb_dev(dev), 1); + r = libusb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1); if (r < 0) { fp_err("could not set configuration 1"); return r; } - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } sdev = g_malloc0(sizeof(struct sonly_dev)); - fpi_imgdev_set_user_data(dev, sdev); + fp_dev_set_instance_data(FP_DEV(dev), sdev); sdev->dev_model = (int)driver_data; switch (driver_data) { case UPEKSONLY_1000: diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c index ffa31f33..0042833e 100644 --- a/libfprint/drivers/upektc.c +++ b/libfprint/drivers/upektc.c @@ -56,10 +56,11 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void upektc_next_init_cmd(struct fpi_ssm *ssm) +static void +upektc_next_init_cmd(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); upekdev->init_idx += 1; if (upekdev->init_idx == upekdev->setup_commands_len) @@ -70,70 +71,63 @@ static void upektc_next_init_cmd(struct fpi_ssm *ssm) static void write_init_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { if (upekdev->setup_commands[upekdev->init_idx].response_len) fpi_ssm_next_state(ssm); else - upektc_next_init_cmd(ssm); + upektc_next_init_cmd(ssm, dev); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void read_init_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - upektc_next_init_cmd(ssm); + upektc_next_init_cmd(ssm, dev); else - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); g_free(transfer->buffer); libusb_free_transfer(transfer); } -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { case WRITE_INIT: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, (unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd, UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; case READ_DATA: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, upekdev->setup_commands[upekdev->init_idx].response_len, read_init_data_cb, ssm, BULK_TIMEOUT); @@ -141,16 +135,16 @@ static void activate_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; } } -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; fp_dbg("status %d", fpi_ssm_get_error(ssm)); fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); @@ -181,7 +175,7 @@ static int finger_present(unsigned char *img, size_t len, int sum_threshold) static void finger_det_data_cb(struct libusb_transfer *transfer) { struct fp_img_dev *dev = transfer->user_data; - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = transfer->buffer; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { @@ -214,7 +208,7 @@ static void finger_det_cmd_cb(struct libusb_transfer *t) unsigned char *data; int r; struct fp_img_dev *dev = t->user_data; - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (t->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("req transfer status %d\n", t->status); @@ -226,14 +220,9 @@ static void finger_det_cmd_cb(struct libusb_transfer *t) goto exit_free_transfer; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - goto exit_free_transfer; - } - + transfer = fpi_usb_alloc(); data = g_malloc(IMAGE_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data, IMAGE_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE, finger_det_data_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -249,7 +238,7 @@ exit_free_transfer: static void start_finger_detection(struct fp_img_dev *dev) { int r; - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); struct libusb_transfer *transfer; G_DEBUG_HERE(); @@ -258,12 +247,8 @@ static void start_finger_detection(struct fp_img_dev *dev) return; } - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_imgdev_session_error(dev, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out, + transfer = fpi_usb_alloc(); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, (unsigned char *)scan_cmd, UPEKTC_CMD_LEN, finger_det_cmd_cb, dev, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -283,31 +268,31 @@ enum capture_states { static void capture_cmd_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } libusb_free_transfer(transfer); } static void capture_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); unsigned char *data = transfer->buffer; struct fp_img *img; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } else if (transfer->length != transfer->actual_length) { fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length); - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); goto out; } @@ -321,59 +306,51 @@ out: libusb_free_transfer(transfer); } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_CMD: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out, + struct libusb_transfer *transfer = fpi_usb_alloc(); + + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, (unsigned char *)scan_cmd, UPEKTC_CMD_LEN, capture_cmd_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); } } break; case CAPTURE_READ_DATA: { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - data = g_malloc(IMAGE_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data, IMAGE_SIZE, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE, capture_read_data_cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; }; } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); fp_dbg("Capture completed"); if (upekdev->deactivating) @@ -387,26 +364,24 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; if (upekdev->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, capture_sm_complete); } static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); upekdev->init_idx = 0; fpi_ssm_start(ssm, activate_sm_complete); return 0; @@ -414,14 +389,14 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *dev) { - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); upekdev->deactivating = TRUE; } static void complete_deactivation(struct fp_img_dev *dev) { - struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); upekdev->deactivating = FALSE; @@ -434,14 +409,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct upektc_dev *upekdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } upekdev = g_malloc0(sizeof(struct upektc_dev)); - fpi_imgdev_set_user_data(dev, upekdev); + fp_dev_set_instance_data(FP_DEV(dev), upekdev); switch (driver_data) { case UPEKTC_2015: upekdev->ep_in = UPEKTC_EP_IN; @@ -460,7 +435,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) default: fp_err("Device variant %lu is not known\n", driver_data); g_free(upekdev); - fpi_imgdev_set_user_data(dev, NULL); + fp_dev_set_instance_data(FP_DEV(dev), NULL); return -ENODEV; break; } @@ -471,9 +446,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { void *user_data; - user_data = fpi_imgdev_get_user_data(dev); + user_data = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(user_data); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c index f0f2f18c..d749ac51 100644 --- a/libfprint/drivers/upektc_img.c +++ b/libfprint/drivers/upektc_img.c @@ -20,6 +20,7 @@ #define FP_COMPONENT "upektc_img" #include "drivers_api.h" +#include "upek_proto.h" #include "aeslib.h" #include "upektc_img.h" @@ -51,50 +52,6 @@ struct upektc_img_dev { /****** HELPERS ******/ -static const uint16_t crc_table[256] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - -static uint16_t udf_crc(unsigned char *buffer, size_t size) -{ - uint16_t crc = 0; - while (size--) - crc = (uint16_t) ((crc << 8) ^ - crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]); - return crc; -} - static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq) { uint8_t byte; @@ -114,61 +71,58 @@ static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size) cmd_buf[size - 1] = (crc & 0xff00) >> 8; } -static void upektc_img_submit_req(struct fpi_ssm *ssm, - const unsigned char *buf, size_t buf_size, unsigned char seq, - libusb_transfer_cb_fn cb) +static void +upektc_img_submit_req(fpi_ssm *ssm, + struct fp_img_dev *dev, + const unsigned char *buf, + size_t buf_size, + unsigned char seq, + libusb_transfer_cb_fn cb) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + struct libusb_transfer *transfer = fpi_usb_alloc(); int r; BUG_ON(buf_size > MAX_CMD_SIZE); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; memcpy(upekdev->cmd, buf, buf_size); upektc_img_cmd_fix_seq(upekdev->cmd, seq); upektc_img_cmd_update_crc(upekdev->cmd, buf_size); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, upekdev->cmd, buf_size, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, upekdev->cmd, buf_size, cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } -static void upektc_img_read_data(struct fpi_ssm *ssm, size_t buf_size, size_t buf_offset, libusb_transfer_cb_fn cb) +static void +upektc_img_read_data(fpi_ssm *ssm, + struct fp_img_dev *dev, + size_t buf_size, + size_t buf_offset, + libusb_transfer_cb_fn cb) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct libusb_transfer *transfer = fpi_usb_alloc(); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - BUG_ON(buf_size > MAX_RESPONSE_SIZE); transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, upekdev->response + buf_offset, buf_size, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, upekdev->response + buf_offset, buf_size, cb, ssm, BULK_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } @@ -187,11 +141,11 @@ enum capture_states { static void capture_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || (transfer->length != transfer->actual_length)) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } switch (fpi_ssm_get_cur_state(ssm)) { @@ -224,16 +178,16 @@ static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned cha static void capture_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *data = upekdev->response; struct fp_img *img; size_t response_size; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -334,7 +288,7 @@ static void capture_read_data_cb(struct libusb_transfer *transfer) break; default: fp_err("Uknown response!\n"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); break; } break; @@ -343,51 +297,51 @@ static void capture_read_data_cb(struct libusb_transfer *transfer) break; default: fp_err("Not handled response!\n"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } -static void capture_run_state(struct fpi_ssm *ssm) +static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_INIT_CAPTURE: - upektc_img_submit_req(ssm, upek2020_init_capture, sizeof(upek2020_init_capture), + upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture), upekdev->seq, capture_reqs_cb); upekdev->seq++; break; case CAPTURE_READ_DATA: case CAPTURE_READ_DATA_TERM: if (!upekdev->response_rest) - upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); + upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); else - upektc_img_read_data(ssm, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, + upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, SHORT_RESPONSE_SIZE, capture_read_data_cb); break; case CAPTURE_ACK_00_28: case CAPTURE_ACK_00_28_TERM: - upektc_img_submit_req(ssm, upek2020_ack_00_28, sizeof(upek2020_ack_00_28), + upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28), upekdev->seq, capture_reqs_cb); upekdev->seq++; break; case CAPTURE_ACK_08: - upektc_img_submit_req(ssm, upek2020_ack_08, sizeof(upek2020_ack_08), + upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08), 0, capture_reqs_cb); break; case CAPTURE_ACK_FRAME: - upektc_img_submit_req(ssm, upek2020_ack_frame, sizeof(upek2020_ack_frame), + upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame), upekdev->seq, capture_reqs_cb); upekdev->seq++; break; }; } -static void capture_sm_complete(struct fpi_ssm *ssm) +static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); int err = fpi_ssm_get_error(ssm); fp_dbg("Capture completed, %d", err); @@ -403,13 +357,12 @@ static void capture_sm_complete(struct fpi_ssm *ssm) static void start_capture(struct fp_img_dev *dev) { - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; upekdev->image_size = 0; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -423,49 +376,49 @@ enum deactivate_states { static void deactivate_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } /* TODO: process response properly */ static void deactivate_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_mark_completed(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } -static void deactivate_run_state(struct fpi_ssm *ssm) +static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case DEACTIVATE_DEINIT: - upektc_img_submit_req(ssm, upek2020_deinit, sizeof(upek2020_deinit), + upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit), upekdev->seq, deactivate_reqs_cb); upekdev->seq++; break; case DEACTIVATE_READ_DEINIT_DATA: - upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); + upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); break; }; } -static void deactivate_sm_complete(struct fpi_ssm *ssm) +static void deactivate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); int err = fpi_ssm_get_error(ssm); fp_dbg("Deactivate completed"); @@ -482,13 +435,12 @@ static void deactivate_sm_complete(struct fpi_ssm *ssm) static void start_deactivation(struct fp_img_dev *dev) { - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; upekdev->image_size = 0; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), deactivate_run_state, DEACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), deactivate_run_state, DEACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, deactivate_sm_complete); } @@ -510,45 +462,44 @@ enum activate_states { static void init_reqs_ctrl_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } static void init_reqs_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (transfer->length == transfer->actual_length)) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } /* TODO: process response properly */ static void init_read_data_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { fpi_ssm_next_state(ssm); } else { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } -static void activate_run_state(struct fpi_ssm *ssm) +static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { struct libusb_transfer *transfer; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(idev); - struct fp_dev *dev = fpi_ssm_get_dev(ssm); + struct fp_img_dev *idev = user_data; + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -557,11 +508,7 @@ static void activate_run_state(struct fpi_ssm *ssm) { unsigned char *data; - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } + transfer = fpi_usb_alloc(); transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; @@ -574,24 +521,24 @@ static void activate_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } break; case ACTIVATE_INIT_1: - upektc_img_submit_req(ssm, upek2020_init_1, sizeof(upek2020_init_1), + upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1), 0, init_reqs_cb); break; case ACTIVATE_INIT_2: - upektc_img_submit_req(ssm, upek2020_init_2, sizeof(upek2020_init_2), + upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2), 0, init_reqs_cb); break; case ACTIVATE_INIT_3: - upektc_img_submit_req(ssm, upek2020_init_3, sizeof(upek2020_init_3), + upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3), 0, init_reqs_cb); break; case ACTIVATE_INIT_4: - upektc_img_submit_req(ssm, upek2020_init_4, sizeof(upek2020_init_4), + upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4), upekdev->seq, init_reqs_cb); /* Seq should be updated after 4th init */ upekdev->seq++; @@ -602,14 +549,14 @@ static void activate_run_state(struct fpi_ssm *ssm) case ACTIVATE_READ_INIT_2_RESP: case ACTIVATE_READ_INIT_3_RESP: case ACTIVATE_READ_INIT_4_RESP: - upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, init_read_data_cb); + upektc_img_read_data(ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb); break; } } -static void activate_sm_complete(struct fpi_ssm *ssm) +static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; int err = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -622,10 +569,9 @@ static void activate_sm_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state, - ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); upekdev->seq = 0; fpi_ssm_start(ssm, activate_sm_complete); return 0; @@ -633,7 +579,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *dev) { - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); upekdev->deactivating = TRUE; } @@ -644,23 +590,23 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; struct upektc_img_dev *upekdev; - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { fp_err("could not claim interface 0: %s", libusb_error_name(r)); return r; } upekdev = g_malloc0(sizeof(struct upektc_img_dev)); - fpi_imgdev_set_user_data(dev, upekdev); + fp_dev_set_instance_data(FP_DEV(dev), upekdev); fpi_imgdev_open_complete(dev, 0); return 0; } static void dev_deinit(struct fp_img_dev *dev) { - struct upektc_img_dev *upekdev = fpi_imgdev_get_user_data(dev); + struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(upekdev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index b448e364..476ef34c 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -28,6 +28,8 @@ #define FP_COMPONENT "upekts" #include "drivers_api.h" +#include "fpi-async.h" +#include "upek_proto.h" #define EP_IN (1 | LIBUSB_ENDPOINT_IN) #define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) @@ -43,49 +45,7 @@ struct upekts_dev { uint8_t seq; /* FIXME: improve/automate seq handling */ }; -static const uint16_t crc_table[256] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; -static uint16_t udf_crc(unsigned char *buffer, size_t size) -{ - uint16_t crc = 0; - while (size--) - crc = (uint16_t) ((crc << 8) ^ - crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]); - return crc; -} /* * MESSAGE FORMAT @@ -131,7 +91,7 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev, unsigned char seq_a, unsigned char seq_b, const unsigned char *data, uint16_t len, libusb_transfer_cb_fn callback, void *user_data) { - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); uint16_t crc; const char *ciao = "Ciao"; @@ -140,9 +100,6 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev, size_t urblen = len + 9; unsigned char *buf; - if (!transfer) - return NULL; - if (!data && len > 0) { fp_err("len>0 but no data?"); return NULL; @@ -178,7 +135,7 @@ static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev, uint16_t _innerlen = innerlen; size_t len = innerlen + 6; unsigned char *buf = g_malloc0(len); - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT; struct libusb_transfer *ret; @@ -408,12 +365,9 @@ static void read_msg_cb(struct libusb_transfer *transfer) * to read the remainder. This is handled below. */ if (len > MAX_DATA_IN_READ_BUF) { int needed = len - MAX_DATA_IN_READ_BUF; - struct libusb_transfer *etransfer = libusb_alloc_transfer(0); + struct libusb_transfer *etransfer = fpi_usb_alloc(); int r; - if (!transfer) - goto err; - fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed); data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed); @@ -448,14 +402,9 @@ out: static int __read_msg_async(struct read_msg_data *udata) { unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); int r; - if (!transfer) { - g_free(buf); - return -ENOMEM; - } - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, buf, MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT); r = libusb_submit_transfer(transfer); @@ -525,25 +474,28 @@ enum initsm_states { INITSM_NUM_STATES, }; -static void initsm_read_msg_response_cb(struct fpi_ssm *ssm, - enum read_msg_status status, uint8_t seq, - unsigned char expect_subcmd, unsigned char subcmd) +static void +initsm_read_msg_response_cb(fpi_ssm *ssm, + struct fp_dev *dev, + enum read_msg_status status, + uint8_t seq, + unsigned char expect_subcmd, + unsigned char subcmd) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (status != READ_MSG_RESPONSE) { fp_err("expected response, got %d seq=%x in state %d", status, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else if (subcmd != expect_subcmd) { fp_warn("expected response to subcmd 0x%02x, got response to %02x in " "state %d", expect_subcmd, subcmd, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else if (seq != upekdev->seq) { fp_err("expected response to cmd seq=%02x, got response to %02x " "in state %d", upekdev->seq, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else { fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm)); fpi_ssm_next_state(ssm); @@ -554,7 +506,7 @@ static void read28_0b_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq, + initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, 0x0b, subcmd); } @@ -562,7 +514,7 @@ static void read28_0c_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq, + initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, 0x0c, subcmd); } @@ -570,7 +522,7 @@ static void read28_08_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq, + initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, 0x08, subcmd); } @@ -578,7 +530,7 @@ static void read28_07_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq, + initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, 0x07, subcmd); } @@ -586,30 +538,33 @@ static void read28_06_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq, + initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, 0x06, subcmd); } -static void initsm_read_msg_cmd_cb(struct fpi_ssm *ssm, - enum read_msg_status status, uint8_t expect_seq, uint8_t seq) +static void +initsm_read_msg_cmd_cb(fpi_ssm *ssm, + struct fp_dev *dev, + enum read_msg_status status, + uint8_t expect_seq, + uint8_t seq) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (status == READ_MSG_ERROR) { - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } else if (status != READ_MSG_CMD) { fp_err("expected command, got %d seq=%x in state %d", status, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } upekdev->seq = seq; if (seq != expect_seq) { fp_err("expected seq=%x, got %x in state %d", expect_seq, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } @@ -620,41 +575,43 @@ static void read_msg05_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 5, seq); + initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 5, seq); } static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq); + initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 3, seq); } static void ctrl400_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; /* FIXME check length? */ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); g_free(transfer->buffer); libusb_free_transfer(transfer); } -static void initsm_read_msg_handler(struct fpi_ssm *ssm, - read_msg_cb_fn callback) +static void +initsm_read_msg_handler(fpi_ssm *ssm, + struct fp_dev *dev, + read_msg_cb_fn callback) { - int r = read_msg_async(fpi_ssm_get_dev(ssm), callback, ssm); + int r = read_msg_async(dev, callback, ssm); if (r < 0) { fp_err("async read msg failed in state %d", fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } static void initsm_send_msg_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status == LIBUSB_TRANSFER_COMPLETED && transfer->length == transfer->actual_length) { fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm)); @@ -662,22 +619,25 @@ static void initsm_send_msg_cb(struct libusb_transfer *transfer) } else { fp_err("failed, state=%d rqlength=%d actual_length=%d", fpi_ssm_get_cur_state(ssm), transfer->length, transfer->actual_length); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } libusb_free_transfer(transfer); } -static void initsm_send_msg28_handler(struct fpi_ssm *ssm, - unsigned char subcmd, const unsigned char *data, uint16_t innerlen) +static void +initsm_send_msg28_handler(fpi_ssm *ssm, + struct fp_dev *dev, + unsigned char subcmd, + const unsigned char *data, + uint16_t innerlen) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); struct libusb_transfer *transfer; int r; transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen, initsm_send_msg_cb, ssm); if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); return; } @@ -686,14 +646,13 @@ static void initsm_send_msg28_handler(struct fpi_ssm *ssm, fp_err("urb submission failed error %d in state %d", r, fpi_ssm_get_cur_state(ssm)); g_free(transfer->buffer); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } -static void initsm_run_state(struct fpi_ssm *ssm) +static void initsm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); struct libusb_transfer *transfer; int r; @@ -701,12 +660,7 @@ static void initsm_run_state(struct fpi_ssm *ssm) case WRITE_CTRL400: ; unsigned char *data; - transfer = libusb_alloc_transfer(0); - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - break; - } - + transfer = fpi_usb_alloc(); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); libusb_fill_control_setup(data, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1); @@ -717,17 +671,17 @@ static void initsm_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; case READ_MSG03: - initsm_read_msg_handler(ssm, read_msg03_cb); + initsm_read_msg_handler(ssm, dev, read_msg03_cb); break; case SEND_RESP03: ; transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq, init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm); if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); break; } @@ -735,51 +689,52 @@ static void initsm_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(transfer->buffer); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; case READ_MSG05: - initsm_read_msg_handler(ssm, read_msg05_cb); + initsm_read_msg_handler(ssm, dev, read_msg05_cb); break; case SEND28_06: ; unsigned char dummy28_06 = 0x04; upekdev->seq = 0xf0; - initsm_send_msg28_handler(ssm, 0x06, &dummy28_06, 1); + initsm_send_msg28_handler(ssm, dev, 0x06, &dummy28_06, 1); break; case READ28_06: - initsm_read_msg_handler(ssm, read28_06_cb); + initsm_read_msg_handler(ssm, dev, read28_06_cb); break; case SEND28_07: ; unsigned char dummy28_07 = 0x04; - initsm_send_msg28_handler(ssm, 0x07, &dummy28_07, 1); + initsm_send_msg28_handler(ssm, dev, 0x07, &dummy28_07, 1); break; case READ28_07: - initsm_read_msg_handler(ssm, read28_07_cb); + initsm_read_msg_handler(ssm, dev, read28_07_cb); break; case SEND28_08: - initsm_send_msg28_handler(ssm, 0x08, init28_08, sizeof(init28_08)); + initsm_send_msg28_handler(ssm, dev, 0x08, init28_08, sizeof(init28_08)); break; case READ28_08: - initsm_read_msg_handler(ssm, read28_08_cb); + initsm_read_msg_handler(ssm, dev, read28_08_cb); break; case SEND28_0C: - initsm_send_msg28_handler(ssm, 0x0c, init28_0c, sizeof(init28_0c)); + initsm_send_msg28_handler(ssm, dev, 0x0c, init28_0c, sizeof(init28_0c)); break; case READ28_0C: - initsm_read_msg_handler(ssm, read28_0c_cb); + initsm_read_msg_handler(ssm, dev, read28_0c_cb); break; case SEND28_0B: - initsm_send_msg28_handler(ssm, 0x0b, init28_0b, sizeof(init28_0b)); + initsm_send_msg28_handler(ssm, dev, 0x0b, init28_0b, sizeof(init28_0b)); break; case READ28_0B: - initsm_read_msg_handler(ssm, read28_0b_cb); + initsm_read_msg_handler(ssm, dev, read28_0b_cb); break; } } -static struct fpi_ssm *initsm_new(struct fp_dev *dev) +static fpi_ssm *initsm_new(struct fp_dev *dev, + void *user_data) { - return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES); + return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, user_data); } enum deinitsm_states { @@ -790,11 +745,11 @@ enum deinitsm_states { static void send_resp07_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); else fpi_ssm_next_state(ssm); libusb_free_transfer(transfer); @@ -804,30 +759,29 @@ static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - struct fpi_ssm *ssm = user_data; - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (status == READ_MSG_ERROR) { - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } else if (status != READ_MSG_CMD) { fp_err("expected command, got %d seq=%x", status, seq); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } upekdev->seq = seq; if (seq != 1) { fp_err("expected seq=1, got %x", seq); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); return; } fpi_ssm_next_state(ssm); } -static void deinitsm_state_handler(struct fpi_ssm *ssm) +static void deinitsm_state_handler(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -838,7 +792,7 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm) transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1, send_resp07_cb, ssm); if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); break; } @@ -846,20 +800,20 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm) if (r < 0) { g_free(transfer->buffer); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; case READ_MSG01: ; r = read_msg_async(dev, read_msg01_cb, ssm); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); break; } } -static struct fpi_ssm *deinitsm_new(struct fp_dev *dev) +static fpi_ssm *deinitsm_new(struct fp_dev *dev) { - return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES); + return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); } static int dev_init(struct fp_dev *dev, unsigned long driver_data) @@ -875,7 +829,7 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data) upekdev = g_malloc(sizeof(*upekdev)); upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */ - fpi_dev_set_user_data(dev, upekdev); + fp_dev_set_instance_data(dev, upekdev); fpi_dev_set_nr_enroll_stages(dev, 3); fpi_drvcb_open_complete(dev, 0); @@ -884,10 +838,10 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data) static void dev_exit(struct fp_dev *dev) { - void *user_data; + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + libusb_release_interface(fpi_dev_get_usb_dev(dev), 0); - user_data = fpi_dev_get_user_data(dev); - g_free(user_data); + g_free(upekdev); fpi_drvcb_close_complete(dev); } @@ -909,14 +863,14 @@ enum enroll_start_sm_states { }; /* Called when the device initialization state machine completes */ -static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm) +static void enroll_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data) { - struct fpi_ssm *enroll_start_ssm = fpi_ssm_get_user_data(initsm); + fpi_ssm *enroll_start_ssm = user_data; int error = fpi_ssm_get_error(initsm); fpi_ssm_free(initsm); if (error) - fpi_ssm_mark_aborted(enroll_start_ssm, error); + fpi_ssm_mark_failed(enroll_start_ssm, error); else fpi_ssm_next_state(enroll_start_ssm); } @@ -924,11 +878,11 @@ static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm) /* called when enroll init URB has completed */ static void enroll_start_sm_cb_init(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); else fpi_ssm_next_state(ssm); libusb_free_transfer(transfer); @@ -938,34 +892,32 @@ static void enroll_start_sm_cb_msg28(struct fp_dev *dev, enum read_msg_status status, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); - struct fpi_ssm *ssm = user_data; + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + fpi_ssm *ssm = user_data; if (status != READ_MSG_RESPONSE) { fp_err("expected response, got %d seq=%x", status, seq); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else if (subcmd != 0) { fp_warn("expected response to subcmd 0, got response to %02x", subcmd); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else if (seq != upekdev->seq) { fp_err("expected response to cmd seq=%02x, got response to %02x", upekdev->seq, seq); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else { fpi_ssm_next_state(ssm); } } -static void enroll_start_sm_run_state(struct fpi_ssm *ssm) +static void enroll_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); int r; switch (fpi_ssm_get_cur_state(ssm)) { case RUN_INITSM: ; - struct fpi_ssm *initsm = initsm_new(dev); - fpi_ssm_set_user_data(initsm, ssm); + fpi_ssm *initsm = initsm_new(dev, ssm); fpi_ssm_start(initsm, enroll_start_sm_cb_initsm); break; case ENROLL_INIT: ; @@ -973,7 +925,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm) transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init, sizeof(enroll_init), enroll_start_sm_cb_init, ssm); if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); break; } @@ -981,7 +933,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(transfer->buffer); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; case READ_ENROLL_MSG28: ; @@ -991,7 +943,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm) * include a 30 01 poll somewhere? */ r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); break; } } @@ -1001,7 +953,7 @@ static void enroll_iterate(struct fp_dev *dev); static void e_handle_resp00(struct fp_dev *dev, unsigned char *data, size_t data_len) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); unsigned char status; int result = 0; @@ -1090,7 +1042,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data, item = fpi_print_data_item_new(data_len - sizeof(scan_comp)); memcpy(item->data, data + sizeof(scan_comp), data_len - sizeof(scan_comp)); - fdata->prints = g_slist_prepend(fdata->prints, item); + fpi_print_data_add_item(fdata, item); result = FP_ENROLL_COMPLETE; } @@ -1153,9 +1105,8 @@ static void enroll_iterate(struct fp_dev *dev) } } -static void enroll_started(struct fpi_ssm *ssm) +static void enroll_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); fpi_drvcb_enroll_started(dev, fpi_ssm_get_error(ssm)); if (!fpi_ssm_get_error(ssm)) @@ -1166,41 +1117,41 @@ static void enroll_started(struct fpi_ssm *ssm) static int enroll_start(struct fp_dev *dev) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); /* do_init state machine first */ - struct fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state, - ENROLL_START_NUM_STATES); + fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state, + ENROLL_START_NUM_STATES, NULL); upekdev->enroll_passed = FALSE; fpi_ssm_start(ssm, enroll_started); return 0; } -static void enroll_stop_deinit_cb(struct fpi_ssm *ssm) +static void enroll_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { /* don't really care about errors */ - fpi_drvcb_enroll_stopped(fpi_ssm_get_dev(ssm)); + fpi_drvcb_enroll_stopped(dev); fpi_ssm_free(ssm); } static int enroll_stop(struct fp_dev *dev) { - struct fpi_ssm *ssm = deinitsm_new(dev); + fpi_ssm *ssm = deinitsm_new(dev); fpi_ssm_start(ssm, enroll_stop_deinit_cb); return 0; } -static void verify_stop_deinit_cb(struct fpi_ssm *ssm) +static void verify_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { /* don't really care about errors */ - fpi_drvcb_verify_stopped(fpi_ssm_get_dev(ssm)); + fpi_drvcb_verify_stopped(dev); fpi_ssm_free(ssm); } static void do_verify_stop(struct fp_dev *dev) { - struct fpi_ssm *ssm = deinitsm_new(dev); + fpi_ssm *ssm = deinitsm_new(dev); fpi_ssm_start(ssm, verify_stop_deinit_cb); } @@ -1217,14 +1168,14 @@ enum { }; /* Called when the device initialization state machine completes */ -static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm) +static void verify_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data) { - struct fpi_ssm *verify_start_ssm = fpi_ssm_get_user_data(initsm); + fpi_ssm *verify_start_ssm = user_data; int err; err = fpi_ssm_get_error(initsm); if (err) - fpi_ssm_mark_aborted(verify_start_ssm, err); + fpi_ssm_mark_failed(verify_start_ssm, err); else fpi_ssm_next_state(verify_start_ssm); fpi_ssm_free(initsm); @@ -1232,30 +1183,28 @@ static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm) static void verify_init_2803_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_aborted(ssm, -EPROTO); + fpi_ssm_mark_failed(ssm, -EPROTO); else fpi_ssm_next_state(ssm); libusb_free_transfer(transfer); } -static void verify_start_sm_run_state(struct fpi_ssm *ssm) +static void verify_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); int r; switch (fpi_ssm_get_cur_state(ssm)) { case VERIFY_RUN_INITSM: ; - struct fpi_ssm *initsm = initsm_new(dev); - fpi_ssm_set_user_data(initsm, ssm); + fpi_ssm *initsm = initsm_new(dev, ssm); fpi_ssm_start(initsm, verify_start_sm_cb_initsm); break; case VERIFY_INIT: ; struct fp_print_data *print = fpi_dev_get_verify_data(dev); - struct fp_print_data_item *item = print->prints->data; + struct fp_print_data_item *item = fpi_print_data_get_item(print); size_t data_len = sizeof(verify_hdr) + item->length; unsigned char *data = g_malloc(data_len); struct libusb_transfer *transfer; @@ -1266,7 +1215,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm) verify_init_2803_cb, ssm); g_free(data); if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); break; } @@ -1274,7 +1223,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm) if (r < 0) { g_free(transfer->buffer); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } break; } @@ -1360,7 +1309,7 @@ static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat, uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, void *user_data) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (msgstat != READ_MSG_RESPONSE) { fp_err("expected response, got %d seq=%x", msgstat, seq); @@ -1399,7 +1348,7 @@ static void verify_wr2800_cb(struct libusb_transfer *transfer) static void verify_iterate(struct fp_dev *dev) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (upekdev->stop_verify) { do_verify_stop(dev); @@ -1432,10 +1381,9 @@ static void verify_iterate(struct fp_dev *dev) } } -static void verify_started(struct fpi_ssm *ssm) +static void verify_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) { - struct fp_dev *dev = fpi_ssm_get_dev(ssm); - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); fpi_drvcb_verify_started(dev, fpi_ssm_get_error(ssm)); if (!fpi_ssm_get_error(ssm)) { @@ -1448,9 +1396,9 @@ static void verify_started(struct fpi_ssm *ssm) static int verify_start(struct fp_dev *dev) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state, - VERIFY_NUM_STATES); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state, + VERIFY_NUM_STATES, NULL); upekdev->stop_verify = FALSE; fpi_ssm_start(ssm, verify_started); return 0; @@ -1458,7 +1406,7 @@ static int verify_start(struct fp_dev *dev) static int verify_stop(struct fp_dev *dev, gboolean iterating) { - struct upekts_dev *upekdev = fpi_dev_get_user_data(dev); + struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); if (!iterating) do_verify_stop(dev); diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 080edf72..7830c562 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -120,9 +120,10 @@ struct uru4k_dev { unsigned char last_reg_rd[16]; unsigned char last_hwstat; - struct libusb_transfer *irq_transfer; - struct libusb_transfer *img_transfer; + fpi_usb_transfer *irq_transfer; + fpi_usb_transfer *img_transfer; void *img_data; + int img_data_actual_length; uint16_t img_lines_done, img_block; uint32_t img_enc_seed; @@ -135,7 +136,7 @@ struct uru4k_dev { unsigned char powerup_hwstat; int scanpwr_irq_timeouts; - struct fpi_timeout *scanpwr_irq_timeout; + fpi_timeout *scanpwr_irq_timeout; int fwfixer_offset; unsigned char fwfixer_value; @@ -186,13 +187,10 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg, void *user_data) { struct write_regs_data *wrdata; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) - return -ENOMEM; - wrdata = g_malloc(sizeof(*wrdata)); wrdata->dev = dev; wrdata->callback = callback; @@ -201,7 +199,7 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg, data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs); memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs); libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, write_regs_cb, + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, write_regs_cb, wrdata, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -253,13 +251,10 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, uint16_t num_regs, read_regs_cb_fn callback, void *user_data) { struct read_regs_data *rrdata; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) - return -ENOMEM; - rrdata = g_malloc(sizeof(*rrdata)); rrdata->dev = dev; rrdata->callback = callback; @@ -267,7 +262,7 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs); libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, read_regs_cb, + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, read_regs_cb, rrdata, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); @@ -301,30 +296,30 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, * * BIT 1: IRQ PENDING * Just had a brainwave. This bit is set when the device is trying to deliver - * and interrupt to the host. Maybe? + * an interrupt to the host. Maybe? */ static void response_cb(struct fp_img_dev *dev, int status, void *user_data) { - struct fpi_ssm *ssm = user_data; + fpi_ssm *ssm = user_data; if (status == 0) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_aborted(ssm, status); + fpi_ssm_mark_failed(ssm, status); } static void challenge_cb(struct fp_img_dev *dev, int status, uint16_t num_regs, unsigned char *data, void *user_data) { - struct fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *respdata; PK11Context *ctx; int r, outlen; r = status; if (status != 0) { - fpi_ssm_mark_aborted(ssm, status); + fpi_ssm_mark_failed(ssm, status); return; } @@ -346,7 +341,7 @@ static void challenge_cb(struct fp_img_dev *dev, int status, g_free(respdata); } if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } /* @@ -354,15 +349,16 @@ static void challenge_cb(struct fp_img_dev *dev, int status, * authentication scheme, where the device challenges the authenticity of the * driver. */ -static void sm_do_challenge_response(struct fpi_ssm *ssm) +static void +sm_do_challenge_response(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); int r; G_DEBUG_HERE(); r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } /***** INTERRUPT HANDLING *****/ @@ -371,10 +367,13 @@ static void sm_do_challenge_response(struct fpi_ssm *ssm) static int start_irq_handler(struct fp_img_dev *dev); -static void irq_handler(struct libusb_transfer *transfer) +static void irq_handler(struct libusb_transfer *transfer, + struct fp_dev *_dev, + fpi_ssm *ssm, + void *user_data) { - struct fp_img_dev *dev = transfer->user_data; - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = FP_IMG_DEV(_dev); + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); unsigned char *data = transfer->buffer; uint16_t type; int r = 0; @@ -396,8 +395,6 @@ static void irq_handler(struct libusb_transfer *transfer) type = GUINT16_FROM_BE(*((uint16_t *) data)); fp_dbg("recv irq type %04x", type); - g_free(data); - libusb_free_transfer(transfer); /* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer) * of the next scan. It still appears on occasion. */ @@ -413,47 +410,43 @@ static void irq_handler(struct libusb_transfer *transfer) if (r == 0) return; - transfer = NULL; - data = NULL; err: if (urudev->irq_cb) urudev->irq_cb(dev, r, 0, urudev->irq_cb_data); out: - g_free(data); - libusb_free_transfer(transfer); urudev->irq_transfer = NULL; } static int start_irq_handler(struct fp_img_dev *dev) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_usb_transfer *transfer; unsigned char *data; int r; - if (!transfer) - return -ENOMEM; - data = g_malloc(IRQ_LENGTH); - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_INTR, data, IRQ_LENGTH, - irq_handler, dev, 0); + transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + NULL, + EP_INTR, + data, + IRQ_LENGTH, + irq_handler, + NULL, + 0); urudev->irq_transfer = transfer; - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); + r = fpi_usb_submit_transfer(transfer); + if (r < 0) urudev->irq_transfer = NULL; - } return r; } static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); - struct libusb_transfer *transfer = urudev->irq_transfer; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_usb_transfer *transfer = urudev->irq_transfer; if (transfer) { - libusb_cancel_transfer(transfer); + fpi_usb_cancel_transfer(transfer); urudev->irqs_stopped_cb = cb; } } @@ -484,7 +477,7 @@ static void change_state_write_reg_cb(struct fp_img_dev *dev, int status, static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); switch (state) { case IMGDEV_STATE_INACTIVE: @@ -508,37 +501,43 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data) { - struct fpi_ssm *ssm = user_data; + fpi_ssm *ssm = user_data; if (result) - fpi_ssm_mark_aborted(ssm, result); + fpi_ssm_mark_failed(ssm, result); else fpi_ssm_next_state(ssm); } -static void sm_write_regs(struct fpi_ssm *ssm, uint16_t first_reg, uint16_t num_regs, - void *data) +static void +sm_write_regs(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint16_t first_reg, + uint16_t num_regs, + void *data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } -static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg, - unsigned char value) +static void +sm_write_reg(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint16_t reg, + unsigned char value) { - sm_write_regs(ssm, reg, 1, &value); + sm_write_regs(ssm, dev, reg, 1, &value); } static void sm_read_reg_cb(struct fp_img_dev *dev, int result, uint16_t num_regs, unsigned char *data, void *user_data) { - struct fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); if (result) { - fpi_ssm_mark_aborted(ssm, result); + fpi_ssm_mark_failed(ssm, result); } else { memcpy(urudev->last_reg_rd, data, num_regs); fp_dbg("reg value %x", urudev->last_reg_rd[0]); @@ -546,32 +545,42 @@ static void sm_read_reg_cb(struct fp_img_dev *dev, int result, } } -static void sm_read_regs(struct fpi_ssm *ssm, uint16_t reg, uint16_t num_regs) +#define member_size(type, member) sizeof(((type *)0)->member) + +static void +sm_read_regs(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint16_t reg, + uint16_t num_regs) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); int r; - if (num_regs > sizeof(urudev->last_reg_rd)) { - fpi_ssm_mark_aborted(ssm, -EIO); + if (num_regs > member_size(struct uru4k_dev, last_reg_rd)) { + fpi_ssm_mark_failed(ssm, -EIO); return; } fp_dbg("read %d regs at %x", num_regs, reg); r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm); if (r < 0) - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } -static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg) +static void +sm_read_reg(fpi_ssm *ssm, + struct fp_img_dev *dev, + uint16_t reg) { - sm_read_regs(ssm, reg, 1); + sm_read_regs(ssm, dev, reg, 1); } -static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value) +static void +sm_set_hwstat(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned char value) { fp_dbg("set %02x", value); - sm_write_reg(ssm, REG_HWSTAT, value); + sm_write_reg(ssm, dev, REG_HWSTAT, value); } /***** IMAGING LOOP *****/ @@ -585,28 +594,6 @@ enum imaging_states { IMAGING_NUM_STATES }; -static void image_transfer_cb(struct libusb_transfer *transfer) -{ - struct fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - fp_dbg("cancelled"); - fpi_ssm_mark_aborted(ssm, -ECANCELED); - } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("error"); - fpi_ssm_mark_aborted(ssm, -EIO); - } else { - fpi_ssm_next_state(ssm); - } -} - -enum { - BLOCKF_CHANGE_KEY = 0x80, - BLOCKF_NO_KEY_UPDATE = 0x04, - BLOCKF_ENCRYPTED = 0x02, - BLOCKF_NOT_PRESENT = 0x01, -}; - struct uru4k_image { uint8_t unknown_00[4]; uint16_t num_lines; @@ -620,6 +607,33 @@ struct uru4k_image { uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; }; +static void image_transfer_cb(struct libusb_transfer *transfer, + struct fp_dev *dev, + fpi_ssm *ssm, + void *user_data) +{ + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + fp_dbg("cancelled"); + fpi_ssm_mark_failed(ssm, -ECANCELED); + } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + fp_dbg("error"); + fpi_ssm_mark_failed(ssm, -EIO); + } else { + struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); + + urudev->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image)); + urudev->img_data_actual_length = transfer->actual_length; + fpi_ssm_next_state(ssm); + } +} + +enum { + BLOCKF_CHANGE_KEY = 0x80, + BLOCKF_NO_KEY_UPDATE = 0x04, + BLOCKF_ENCRYPTED = 0x02, + BLOCKF_NOT_PRESENT = 0x01, +}; + static uint32_t update_key(uint32_t key) { /* linear feedback shift register @@ -687,10 +701,10 @@ static int calc_dev2(struct uru4k_image *img) return res / IMAGE_WIDTH; } -static void imaging_run_state(struct fpi_ssm *ssm) +static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); struct uru4k_image *img = urudev->img_data; struct fp_img *fpimg; uint32_t key; @@ -702,20 +716,20 @@ static void imaging_run_state(struct fpi_ssm *ssm) case IMAGING_CAPTURE: urudev->img_lines_done = 0; urudev->img_block = 0; - libusb_fill_bulk_transfer(urudev->img_transfer, fpi_imgdev_get_usb_dev(dev), EP_DATA, - urudev->img_data, sizeof(struct uru4k_image), image_transfer_cb, ssm, 0); - r = libusb_submit_transfer(urudev->img_transfer); - if (r < 0) - fpi_ssm_mark_aborted(ssm, -EIO); + r = fpi_usb_submit_transfer(urudev->img_transfer); + if (r < 0) { + urudev->img_transfer = NULL; + fpi_ssm_mark_failed(ssm, -EIO); + } break; case IMAGING_SEND_INDEX: fp_dbg("hw header lines %d", img->num_lines); if (img->num_lines >= IMAGE_HEIGHT || - urudev->img_transfer->actual_length < img->num_lines * IMAGE_WIDTH + 64) { + urudev->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) { fp_err("bad captured image (%d lines) or size mismatch %d < %d", img->num_lines, - urudev->img_transfer->actual_length, + urudev->img_data_actual_length, img->num_lines * IMAGE_WIDTH + 64); fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); return; @@ -734,10 +748,10 @@ static void imaging_run_state(struct fpi_ssm *ssm) buf[2] = urudev->img_enc_seed >> 8; buf[3] = urudev->img_enc_seed >> 16; buf[4] = urudev->img_enc_seed >> 24; - sm_write_regs(ssm, REG_SCRAMBLE_DATA_INDEX, 5, buf); + sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf); break; case IMAGING_READ_KEY: - sm_read_regs(ssm, REG_SCRAMBLE_DATA_KEY, 4); + sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4); break; case IMAGING_DECODE: key = urudev->last_reg_rd[0]; @@ -810,10 +824,10 @@ static void imaging_run_state(struct fpi_ssm *ssm) } } -static void imaging_complete(struct fpi_ssm *ssm) +static void imaging_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); int r = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -823,11 +837,12 @@ static void imaging_complete(struct fpi_ssm *ssm) if (r) fpi_imgdev_session_error(dev, r); + /* Freed by callback or cancellation */ + urudev->img_transfer = NULL; + g_free(urudev->img_data); urudev->img_data = NULL; - - libusb_free_transfer(urudev->img_transfer); - urudev->img_transfer = NULL; + urudev->img_data_actual_length = 0; r = execute_state_change(dev); if (r) @@ -840,7 +855,7 @@ static void imaging_complete(struct fpi_ssm *ssm) * confused state and returns hwstat 0x85. On next app run, we don't get the * 56aa interrupt. This is the best way I've found to fix it: mess around * with hwstat until it starts returning more recognisable values. This - * doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2 + * doesn't happen on my other devices: uru4000, uru4000b, ms fp rdr v2 * * The windows driver copes with this OK, but then again it uploads firmware * right after reading the 0x85 hwstat, allowing some time to pass before it @@ -860,32 +875,33 @@ enum rebootpwr_states { REBOOTPWR_NUM_STATES, }; -static void rebootpwr_pause_cb(void *data) +static void +rebootpwr_pause_cb(struct fp_dev *dev, + void *data) { - struct fpi_ssm *ssm = data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); if (!--urudev->rebootpwr_ctr) { fp_err("could not reboot device power"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } else { fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT); } } -static void rebootpwr_run_state(struct fpi_ssm *ssm) +static void rebootpwr_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case REBOOTPWR_SET_HWSTAT: urudev->rebootpwr_ctr = 100; - sm_set_hwstat(ssm, urudev->last_hwstat & 0xf); + sm_set_hwstat(ssm, dev, urudev->last_hwstat & 0xf); break; case REBOOTPWR_GET_HWSTAT: - sm_read_reg(ssm, REG_HWSTAT); + sm_read_reg(ssm, dev, REG_HWSTAT); break; case REBOOTPWR_CHECK_HWSTAT: urudev->last_hwstat = urudev->last_reg_rd[0]; @@ -895,16 +911,16 @@ static void rebootpwr_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case REBOOTPWR_PAUSE: - if (fpi_timeout_add(10, rebootpwr_pause_cb, ssm) == NULL) - fpi_ssm_mark_aborted(ssm, -ETIME); + if (fpi_timeout_add(10, rebootpwr_pause_cb, _dev, ssm) == NULL) + fpi_ssm_mark_failed(ssm, -ETIME); break; } } -/* After messing with the device firmware in it's low-power state, we have to +/* After messing with the device firmware in its low-power state, we have to * power it back up and wait for interrupt notification. It's not quite as easy * as that: the combination of both modifying firmware *and* doing C-R auth on - * my ms fp v2 device causes us not to get to get the 56aa interrupt and + * my ms fp v2 device causes us not to get the 56aa interrupt and * for the hwstat write not to take effect. We have to loop a few times, * authenticating each time, until the device wakes up. * @@ -937,15 +953,16 @@ enum powerup_states { POWERUP_NUM_STATES, }; -static void powerup_pause_cb(void *data) +static void +powerup_pause_cb(struct fp_dev *dev, + void *data) { - struct fpi_ssm *ssm = data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); if (!--urudev->powerup_ctr) { fp_err("could not power device up"); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } else if (!urudev->profile->auth_cr) { fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); } else { @@ -953,10 +970,10 @@ static void powerup_pause_cb(void *data) } } -static void powerup_run_state(struct fpi_ssm *ssm) +static void powerup_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case POWERUP_INIT: @@ -965,10 +982,10 @@ static void powerup_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case POWERUP_SET_HWSTAT: - sm_set_hwstat(ssm, urudev->powerup_hwstat); + sm_set_hwstat(ssm, dev, urudev->powerup_hwstat); break; case POWERUP_GET_HWSTAT: - sm_read_reg(ssm, REG_HWSTAT); + sm_read_reg(ssm, dev, REG_HWSTAT); break; case POWERUP_CHECK_HWSTAT: urudev->last_hwstat = urudev->last_reg_rd[0]; @@ -978,11 +995,11 @@ static void powerup_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case POWERUP_PAUSE: - if (fpi_timeout_add(10, powerup_pause_cb, ssm) == NULL) - fpi_ssm_mark_aborted(ssm, -ETIME); + if (fpi_timeout_add(10, powerup_pause_cb, _dev, ssm) == NULL) + fpi_ssm_mark_failed(ssm, -ETIME); break; case POWERUP_CHALLENGE_RESPONSE: - sm_do_challenge_response(ssm); + sm_do_challenge_response(ssm, dev); break; case POWERUP_CHALLENGE_RESPONSE_SUCCESS: fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); @@ -1024,11 +1041,11 @@ enum init_states { static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status, uint16_t type, void *user_data) { - struct fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); if (status) - fpi_ssm_mark_aborted(ssm, status); + fpi_ssm_mark_failed(ssm, status); else if (type != IRQDATA_SCANPWR_ON) fp_dbg("ignoring interrupt"); else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) { @@ -1040,11 +1057,12 @@ static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status, } } -static void init_scanpwr_timeout(void *user_data) +static void +init_scanpwr_timeout(struct fp_dev *dev, + void *user_data) { - struct fpi_ssm *ssm = user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + fpi_ssm *ssm = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); fp_warn("powerup timed out"); urudev->irq_cb = NULL; @@ -1052,20 +1070,20 @@ static void init_scanpwr_timeout(void *user_data) if (++urudev->scanpwr_irq_timeouts >= 3) { fp_err("powerup timed out 3 times, giving up"); - fpi_ssm_mark_aborted(ssm, -ETIMEDOUT); + fpi_ssm_mark_failed(ssm, -ETIMEDOUT); } else { fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT); } } -static void init_run_state(struct fpi_ssm *ssm) +static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case INIT_GET_HWSTAT: - sm_read_reg(ssm, REG_HWSTAT); + sm_read_reg(ssm, dev, REG_HWSTAT); break; case INIT_CHECK_HWSTAT_REBOOT: urudev->last_hwstat = urudev->last_reg_rd[0]; @@ -1075,28 +1093,26 @@ static void init_run_state(struct fpi_ssm *ssm) fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN); break; case INIT_REBOOT_POWER: ; - struct fpi_ssm *rebootsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), rebootpwr_run_state, - REBOOTPWR_NUM_STATES); - fpi_ssm_set_user_data(rebootsm, dev); + fpi_ssm *rebootsm = fpi_ssm_new(FP_DEV(dev), rebootpwr_run_state, + REBOOTPWR_NUM_STATES, dev); fpi_ssm_start_subsm(ssm, rebootsm); break; case INIT_CHECK_HWSTAT_POWERDOWN: if ((urudev->last_hwstat & 0x80) == 0) - sm_set_hwstat(ssm, urudev->last_hwstat | 0x80); + sm_set_hwstat(ssm, dev, urudev->last_hwstat | 0x80); else fpi_ssm_next_state(ssm); break; case INIT_POWERUP: ; if (!IRQ_HANDLER_IS_RUNNING(urudev)) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); break; } urudev->irq_cb_data = ssm; urudev->irq_cb = init_scanpwr_irq_cb; - struct fpi_ssm *powerupsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), powerup_run_state, - POWERUP_NUM_STATES); - fpi_ssm_set_user_data(powerupsm, dev); + fpi_ssm *powerupsm = fpi_ssm_new(FP_DEV(dev), powerup_run_state, + POWERUP_NUM_STATES, dev); fpi_ssm_start_subsm(ssm, powerupsm); break; case INIT_AWAIT_SCAN_POWER: @@ -1109,9 +1125,10 @@ static void init_run_state(struct fpi_ssm *ssm) * so we include this timeout loop to retry the whole process 3 times * if we don't get an irq any time soon. */ urudev->scanpwr_irq_timeout = fpi_timeout_add(300, - init_scanpwr_timeout, ssm); + init_scanpwr_timeout, + _dev, ssm); if (!urudev->scanpwr_irq_timeout) { - fpi_ssm_mark_aborted(ssm, -ETIME); + fpi_ssm_mark_failed(ssm, -ETIME); break; } break; @@ -1125,7 +1142,7 @@ static void init_run_state(struct fpi_ssm *ssm) fpi_ssm_next_state(ssm); break; case INIT_GET_VERSION: - sm_read_regs(ssm, REG_DEVICE_INFO, 16); + sm_read_regs(ssm, dev, REG_DEVICE_INFO, 16); break; case INIT_REPORT_VERSION: /* Likely hardware revision, and firmware version. @@ -1138,9 +1155,9 @@ static void init_run_state(struct fpi_ssm *ssm) } } -static void activate_initsm_complete(struct fpi_ssm *ssm) +static void activate_initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; int r = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -1159,8 +1176,8 @@ static void activate_initsm_complete(struct fpi_ssm *ssm) * call. */ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; int r; r = start_irq_handler(dev); @@ -1169,8 +1186,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) urudev->scanpwr_irq_timeouts = 0; urudev->activate_state = state; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), init_run_state, INIT_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), init_run_state, INIT_NUM_STATES, dev); fpi_ssm_start(ssm, activate_initsm_complete); return 0; } @@ -1195,8 +1211,9 @@ static void dev_deactivate(struct fp_img_dev *dev) static int execute_state_change(struct fp_img_dev *dev) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; + void *img_data; switch (urudev->activate_state) { case IMGDEV_STATE_INACTIVE: @@ -1219,12 +1236,18 @@ static int execute_state_change(struct fp_img_dev *dev) fp_dbg("starting capture"); urudev->irq_cb = NULL; - urudev->img_transfer = libusb_alloc_transfer(0); - urudev->img_data = g_malloc(sizeof(struct uru4k_image)); + ssm = fpi_ssm_new(FP_DEV(dev), imaging_run_state, IMAGING_NUM_STATES, dev); + img_data = g_malloc(sizeof(struct uru4k_image)); urudev->img_enc_seed = rand(); + urudev->img_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), + ssm, + EP_DATA, + img_data, + sizeof(struct uru4k_image), + image_transfer_cb, + NULL, + 0); - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), imaging_run_state, IMAGING_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); fpi_ssm_start(ssm, imaging_complete); return write_reg(dev, REG_MODE, MODE_CAPTURE, @@ -1257,7 +1280,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) int r; /* Find fingerprint interface */ - r = libusb_get_config_descriptor(libusb_get_device(fpi_imgdev_get_usb_dev(dev)), 0, &config); + r = libusb_get_config_descriptor(libusb_get_device(fpi_dev_get_usb_dev(FP_DEV(dev))), 0, &config); if (r < 0) { fp_err("Failed to get config descriptor"); return r; @@ -1311,7 +1334,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) /* Device looks like a supported reader */ - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), iface_desc->bInterfaceNumber); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), iface_desc->bInterfaceNumber); if (r < 0) { fp_err("interface claim failed: %s", libusb_error_name(r)); goto out; @@ -1325,6 +1348,8 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) } urudev = g_malloc0(sizeof(*urudev)); + fp_dev_set_instance_data(FP_DEV(dev), urudev); + urudev->profile = &uru4k_dev_info[driver_data]; urudev->interface = iface_desc->bInterfaceNumber; @@ -1351,7 +1376,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) } urudev->param = PK11_ParamFromIV(urudev->cipher, NULL); - fpi_imgdev_set_user_data(dev, urudev); fpi_imgdev_open_complete(dev, 0); out: @@ -1361,14 +1385,14 @@ out: static void dev_deinit(struct fp_img_dev *dev) { - struct uru4k_dev *urudev = fpi_imgdev_get_user_data(dev); + struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); if (urudev->symkey) PK11_FreeSymKey (urudev->symkey); if (urudev->param) SECITEM_FreeItem(urudev->param, PR_TRUE); if (urudev->slot) PK11_FreeSlot(urudev->slot); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), urudev->interface); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), urudev->interface); g_free(urudev); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c index cbd03751..4ed71f69 100644 --- a/libfprint/drivers/vcom5s.c +++ b/libfprint/drivers/vcom5s.c @@ -74,10 +74,10 @@ enum v5s_cmd { static void sm_write_reg_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else fpi_ssm_next_state(ssm); @@ -85,38 +85,35 @@ static void sm_write_reg_cb(struct libusb_transfer *transfer) libusb_free_transfer(transfer); } -static void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg, - unsigned char value) +static void +sm_write_reg(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned char reg, + unsigned char value) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - fp_dbg("set %02x=%02x", reg, value); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, sm_write_reg_cb, + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } static void sm_exec_cmd_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); else fpi_ssm_next_state(ssm); @@ -124,29 +121,26 @@ static void sm_exec_cmd_cb(struct libusb_transfer *transfer) libusb_free_transfer(transfer); } -static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd, - unsigned char param) +static void +sm_exec_cmd(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned char cmd, + unsigned char param) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); unsigned char *data; int r; - - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } fp_dbg("cmd %02x param %02x", cmd, param); data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0); - libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, sm_exec_cmd_cb, + libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb, ssm, CTRL_TIMEOUT); r = libusb_submit_transfer(transfer); if (r < 0) { g_free(data); libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } @@ -187,16 +181,16 @@ static gboolean finger_is_present(unsigned char *data) /***** IMAGE ACQUISITION *****/ -static void capture_iterate(struct fpi_ssm *ssm); +static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev); static void capture_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -211,47 +205,44 @@ static void capture_cb(struct libusb_transfer *transfer) fpi_imgdev_image_captured(dev, img); fpi_ssm_next_state(ssm); } else { - capture_iterate(ssm); + capture_iterate(ssm, dev); } out: libusb_free_transfer(transfer); } -static void capture_iterate(struct fpi_ssm *ssm) +static void +capture_iterate(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); int iteration = vdev->capture_iteration; - struct libusb_transfer *transfer = libusb_alloc_transfer(0); + struct libusb_transfer *transfer = fpi_usb_alloc(); int r; - if (!transfer) { - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE, capture_cb, ssm, CTRL_TIMEOUT); transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK; r = libusb_submit_transfer(transfer); if (r < 0) { libusb_free_transfer(transfer); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } } -static void sm_do_capture(struct fpi_ssm *ssm) +static void +sm_do_capture(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); vdev->capture_img = fpi_img_new_for_imgdev(dev); vdev->capture_iteration = 0; - capture_iterate(ssm); + capture_iterate(ssm, dev); } /***** CAPTURE LOOP *****/ @@ -265,27 +256,27 @@ enum loop_states { LOOP_NUM_STATES, }; -static void loop_run_state(struct fpi_ssm *ssm) +static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case LOOP_SET_CONTRAST: - sm_write_reg(ssm, REG_CONTRAST, 0x01); + sm_write_reg(ssm, dev, REG_CONTRAST, 0x01); break; case LOOP_SET_GAIN: - sm_write_reg(ssm, REG_GAIN, 0x29); + sm_write_reg(ssm, dev, REG_GAIN, 0x29); break; case LOOP_CMD_SCAN: if (vdev->deactivating) { fp_dbg("deactivating, marking completed"); fpi_ssm_mark_completed(ssm); } else - sm_exec_cmd(ssm, CMD_SCAN, 0x00); + sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00); break; case LOOP_CAPTURE: - sm_do_capture(ssm); + sm_do_capture(ssm, dev); break; case LOOP_CAPTURE_DONE: fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN); @@ -293,10 +284,10 @@ static void loop_run_state(struct fpi_ssm *ssm) } } -static void loopsm_complete(struct fpi_ssm *ssm) +static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev); int r = fpi_ssm_get_error(ssm); fpi_ssm_free(ssm); @@ -313,10 +304,9 @@ static void loopsm_complete(struct fpi_ssm *ssm) static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), loop_run_state, - LOOP_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state, + LOOP_NUM_STATES, dev); vdev->deactivating = FALSE; fpi_ssm_start(ssm, loopsm_complete); vdev->loop_running = TRUE; @@ -326,7 +316,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *dev) { - struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev); + struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); if (vdev->loop_running) vdev->deactivating = TRUE; else @@ -339,9 +329,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) struct v5s_dev *v5s_dev; v5s_dev = g_malloc0(sizeof(struct v5s_dev)); - fpi_imgdev_set_user_data(dev, v5s_dev); + fp_dev_set_instance_data(FP_DEV(dev), v5s_dev); - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) fp_err("could not claim interface 0: %s", libusb_error_name(r)); @@ -354,9 +344,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static void dev_deinit(struct fp_img_dev *dev) { struct v5s_dev *v5s_dev; - v5s_dev = fpi_imgdev_get_user_data(dev); + v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(v5s_dev); - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); fpi_imgdev_close_complete(dev); } diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c index dcf5d693..a437df4f 100644 --- a/libfprint/drivers/vfs0050.c +++ b/libfprint/drivers/vfs0050.c @@ -27,7 +27,7 @@ /* Callback for async_write */ static void async_write_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); int transferred = transfer->actual_length, error = @@ -36,14 +36,14 @@ static void async_write_callback(struct libusb_transfer *transfer) if (error != 0) { fp_err("USB write transfer: %s", libusb_error_name(error)); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } if (transferred != len) { fp_err("Written only %d of %d bytes", transferred, len); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -51,13 +51,16 @@ static void async_write_callback(struct libusb_transfer *transfer) } /* Send data to EP1, the only out endpoint */ -static void async_write(struct fpi_ssm *ssm, void *data, int len) +static void +async_write(fpi_ssm *ssm, + struct fp_img_dev *dev, + void *data, + int len) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_imgdev_get_usb_dev(idev); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(dev)); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - vdev->transfer = libusb_alloc_transfer(0); + vdev->transfer = fpi_usb_alloc(); vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x01, data, len, async_write_callback, ssm, VFS_USB_TIMEOUT); @@ -67,7 +70,7 @@ static void async_write(struct fpi_ssm *ssm, void *data, int len) /* Callback for async_read */ static void async_read_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); int transferred = transfer->actual_length, error = @@ -78,14 +81,14 @@ static void async_read_callback(struct libusb_transfer *transfer) fp_err("USB read transfer on endpoint %d: %s", ep - 0x80, libusb_error_name(error)); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } if (transferred != len) { fp_err("Received %d instead of %d bytes", transferred, len); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -93,15 +96,20 @@ static void async_read_callback(struct libusb_transfer *transfer) } /* Receive data from the given ep and compare with expected */ -static void async_read(struct fpi_ssm *ssm, int ep, void *data, int len) +static void +async_read(fpi_ssm *ssm, + struct fp_img_dev *dev, + int ep, + void *data, + int len) { struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_imgdev_get_usb_dev(idev); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); ep |= LIBUSB_ENDPOINT_IN; - vdev->transfer = libusb_alloc_transfer(0); + vdev->transfer = fpi_usb_alloc(); vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; /* 0x83 is the only interrupt endpoint */ @@ -119,7 +127,7 @@ static void async_read(struct fpi_ssm *ssm, int ep, void *data, int len) /* Callback for async_read */ static void async_abort_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); int transferred = transfer->actual_length, error = transfer->status; @@ -134,7 +142,7 @@ static void async_abort_callback(struct libusb_transfer *transfer) if (error != 0) { fp_err("USB write transfer: %s", libusb_error_name(error)); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -147,18 +155,18 @@ static void async_abort_callback(struct libusb_transfer *transfer) } /* Receive data from the given ep and compare with expected */ -static void async_abort(struct fpi_ssm *ssm, int ep) +static void async_abort(fpi_ssm *ssm, int ep) { struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_imgdev_get_usb_dev(idev); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); int len = VFS_USB_BUFFER_SIZE; unsigned char *data = g_malloc(VFS_USB_BUFFER_SIZE); ep |= LIBUSB_ENDPOINT_IN; - vdev->transfer = libusb_alloc_transfer(0); + vdev->transfer = fpi_usb_alloc(); vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER; @@ -259,7 +267,7 @@ static struct fp_img *prepare_image(struct vfs_dev_t *vdev) /* Processes and submits image after fingerprint received */ static void submit_image(struct fp_img_dev *idev) { - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); /* We were not asked to submit image actually */ if (!vdev->active) @@ -279,20 +287,21 @@ static void submit_image(struct fp_img_dev *idev) /* Proto functions */ /* SSM loop for clear_ep2 */ -static void clear_ep2_ssm(struct fpi_ssm *ssm) +static void +clear_ep2_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *idev = user_data; short result; char command04 = 0x04; switch (fpi_ssm_get_cur_state(ssm)) { case SUBSM1_COMMAND_04: - async_write(ssm, &command04, sizeof(command04)); + async_write(ssm, idev, &command04, sizeof(command04)); break; case SUBSM1_RETURN_CODE: - async_read(ssm, 1, &result, sizeof(result)); + async_read(ssm, idev, 1, &result, sizeof(result)); break; case SUBSM1_ABORT_2: @@ -302,36 +311,35 @@ static void clear_ep2_ssm(struct fpi_ssm *ssm) default: fp_err("Unknown SUBSM1 state"); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } /* Send command to clear EP2 */ -static void clear_ep2(struct fpi_ssm *ssm) +static void +clear_ep2(fpi_ssm *ssm, + struct fp_img_dev *idev) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - - struct fpi_ssm *subsm = - fpi_ssm_new(fpi_imgdev_get_dev(idev), clear_ep2_ssm, SUBSM1_STATES); - fpi_ssm_set_user_data(subsm, idev); + fpi_ssm *subsm = + fpi_ssm_new(FP_DEV(idev), clear_ep2_ssm, SUBSM1_STATES, idev); fpi_ssm_start_subsm(ssm, subsm); } -static void send_control_packet_ssm(struct fpi_ssm *ssm) +static void send_control_packet_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); short result; unsigned char *commit_result = NULL; switch (fpi_ssm_get_cur_state(ssm)) { case SUBSM2_SEND_CONTROL: - async_write(ssm, vdev->control_packet, VFS_CONTROL_PACKET_SIZE); + async_write(ssm, idev, vdev->control_packet, VFS_CONTROL_PACKET_SIZE); break; case SUBSM2_RETURN_CODE: - async_read(ssm, 1, &result, sizeof(result)); + async_read(ssm, idev, 1, &result, sizeof(result)); break; case SUBSM2_SEND_COMMIT: @@ -342,19 +350,19 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm) break; } /* commit_out in Windows differs in each commit, but I send the same each time */ - async_write(ssm, commit_out, sizeof(commit_out)); + async_write(ssm, idev, commit_out, sizeof(commit_out)); break; case SUBSM2_COMMIT_RESPONSE: commit_result = g_malloc(VFS_COMMIT_RESPONSE_SIZE); - async_read(ssm, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE); + async_read(ssm, idev, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE); break; case SUBSM2_READ_EMPTY_INTERRUPT: /* I don't know how to check result, it could be different */ g_free(commit_result); - async_read(ssm, 3, vdev->interrupt, VFS_INTERRUPT_SIZE); + async_read(ssm, idev, 3, vdev->interrupt, VFS_INTERRUPT_SIZE); break; case SUBSM2_ABORT_3: @@ -363,7 +371,7 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm) (vdev->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) { fp_err("Unknown SUBSM2 state"); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); break; } async_abort(ssm, 3); @@ -372,7 +380,7 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm) case SUBSM2_CLEAR_EP2: /* After turn_on Windows doesn't clear EP2 */ if (vdev->control_packet != turn_on) - clear_ep2(ssm); + clear_ep2(ssm, idev); else fpi_ssm_next_state(ssm); break; @@ -380,18 +388,17 @@ static void send_control_packet_ssm(struct fpi_ssm *ssm) default: fp_err("Unknown SUBSM2 state"); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } /* Send device state control packet */ -static void send_control_packet(struct fpi_ssm *ssm) +static void +send_control_packet(fpi_ssm *ssm, + struct fp_img_dev *idev) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - - struct fpi_ssm *subsm = - fpi_ssm_new(fpi_imgdev_get_dev(idev), send_control_packet_ssm, SUBSM2_STATES); - fpi_ssm_set_user_data(subsm, idev); + fpi_ssm *subsm = + fpi_ssm_new(FP_DEV(idev), send_control_packet_ssm, SUBSM2_STATES, idev); fpi_ssm_start_subsm(ssm, subsm); } @@ -406,9 +413,9 @@ static void clear_data(struct vfs_dev_t *vdev) /* After receiving interrupt from EP3 */ static void interrupt_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); char *interrupt = vdev->interrupt; int error = transfer->status, transferred = transfer->actual_length; @@ -423,7 +430,7 @@ static void interrupt_callback(struct libusb_transfer *transfer) fp_err("USB read interrupt transfer: %s", libusb_error_name(error)); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -432,7 +439,7 @@ static void interrupt_callback(struct libusb_transfer *transfer) fp_err("Unknown interrupt size %d", transferred); /* Abort ssm */ fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -461,14 +468,14 @@ static void interrupt_callback(struct libusb_transfer *transfer) /* Abort ssm */ fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } static void receive_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); int transferred = transfer->actual_length, error = transfer->status; @@ -476,7 +483,7 @@ static void receive_callback(struct libusb_transfer *transfer) fp_err("USB read transfer: %s", libusb_error_name(error)); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } @@ -492,11 +499,12 @@ static void receive_callback(struct libusb_transfer *transfer) } /* Stub to keep SSM alive when waiting an interrupt */ -static void wait_interrupt(void *data) +static void +wait_interrupt(struct fp_dev *dev, + void *data) { - struct fpi_ssm *ssm = data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + fpi_ssm *ssm = data; + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(dev); /* Keep sleeping while this flag is on */ if (vdev->wait_interrupt) @@ -504,25 +512,20 @@ static void wait_interrupt(void *data) } /* SSM stub to prepare device to another scan after orange light was on */ -static void another_scan(void *data) +static void +another_scan(struct fp_dev *dev, + void *data) { - struct fpi_ssm *ssm = data; + fpi_ssm *ssm = data; fpi_ssm_jump_to_state(ssm, SSM_TURN_ON); } -/* Another SSM stub to continue after waiting for probable vdev->active changes */ -static void scan_completed(void *data) -{ - struct fpi_ssm *ssm = data; - fpi_ssm_next_state(ssm); -} - /* Main SSM loop */ -static void activate_ssm(struct fpi_ssm *ssm) +static void activate_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_imgdev_get_usb_dev(idev); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct fp_img_dev *idev = user_data; + struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case SSM_INITIAL_ABORT_1: @@ -538,14 +541,14 @@ static void activate_ssm(struct fpi_ssm *ssm) break; case SSM_CLEAR_EP2: - clear_ep2(ssm); + clear_ep2(ssm, idev); break; case SSM_TURN_OFF: /* Set control_packet argument */ vdev->control_packet = turn_off; - send_control_packet(ssm); + send_control_packet(ssm, idev); break; case SSM_TURN_ON: @@ -562,7 +565,7 @@ static void activate_ssm(struct fpi_ssm *ssm) /* Set control_packet argument */ vdev->control_packet = turn_on; - send_control_packet(ssm); + send_control_packet(ssm, idev); break; case SSM_ASK_INTERRUPT: @@ -575,7 +578,7 @@ static void activate_ssm(struct fpi_ssm *ssm) } /* Asyncronously enquire an interrupt */ - vdev->transfer = libusb_alloc_transfer(0); + vdev->transfer = fpi_usb_alloc(); vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, 0x83, vdev->interrupt, @@ -601,7 +604,7 @@ static void activate_ssm(struct fpi_ssm *ssm) } if (vdev->wait_interrupt) - fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, ssm); + fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, _dev, ssm); break; case SSM_RECEIVE_FINGER: @@ -625,7 +628,7 @@ static void activate_ssm(struct fpi_ssm *ssm) } /* Receive chunk of data */ - vdev->transfer = libusb_alloc_transfer(0); + vdev->transfer = fpi_usb_alloc(); vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x82, (void *)vdev->lines_buffer + @@ -640,7 +643,7 @@ static void activate_ssm(struct fpi_ssm *ssm) clear_data(vdev); /* Wait for probable vdev->active changing */ - fpi_timeout_add(VFS_SSM_TIMEOUT, scan_completed, ssm); + fpi_timeout_add(VFS_SSM_TIMEOUT, fpi_ssm_next_state_timeout_cb, _dev, ssm); break; case SSM_NEXT_RECEIVE: @@ -653,28 +656,27 @@ static void activate_ssm(struct fpi_ssm *ssm) /* Set control_packet argument */ vdev->control_packet = next_receive_1; - send_control_packet(ssm); + send_control_packet(ssm, idev); break; case SSM_WAIT_ANOTHER_SCAN: /* Orange light is on now */ - fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, ssm); + fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, _dev, ssm); break; default: fp_err("Unknown state"); fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } /* Driver functions */ /* Callback for dev_activate ssm */ -static void dev_activate_callback(struct fpi_ssm *ssm) +static void dev_activate_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); vdev->ssm_active = 0; @@ -684,15 +686,14 @@ static void dev_activate_callback(struct fpi_ssm *ssm) /* Activate device */ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) { - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); /* Initialize flags */ vdev->active = 1; vdev->need_report = 1; vdev->ssm_active = 1; - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(idev), activate_ssm, SSM_STATES); - fpi_ssm_set_user_data(ssm, idev); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev); fpi_ssm_start(ssm, dev_activate_callback); return 0; } @@ -700,7 +701,7 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) /* Deactivate device */ static void dev_deactivate(struct fp_img_dev *idev) { - struct vfs_dev_t *vdev = fpi_imgdev_get_user_data(idev); + struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); if (!vdev->ssm_active) { fpi_imgdev_deactivate_complete(idev); @@ -713,10 +714,10 @@ static void dev_deactivate(struct fp_img_dev *idev) } /* Callback for dev_open ssm */ -static void dev_open_callback(struct fpi_ssm *ssm) +static void dev_open_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { /* Notify open complete */ - fpi_imgdev_open_complete(fpi_ssm_get_user_data(ssm), 0); + fpi_imgdev_open_complete(user_data, 0); fpi_ssm_free(ssm); } @@ -726,7 +727,7 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) struct vfs_dev_t *vdev; /* Claim usb interface */ - int error = libusb_claim_interface(fpi_imgdev_get_usb_dev(idev), 0); + int error = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); if (error < 0) { /* Interface not claimed, return error */ fp_err("could not claim interface 0"); @@ -735,11 +736,10 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) /* Initialize private structure */ vdev = g_malloc0(sizeof(struct vfs_dev_t)); - fpi_imgdev_set_user_data(idev, vdev); + fp_dev_set_instance_data(FP_DEV(idev), vdev); /* Clearing previous device state */ - struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(idev), activate_ssm, SSM_STATES); - fpi_ssm_set_user_data(ssm, idev); + fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev); fpi_ssm_start(ssm, dev_open_callback); return 0; } @@ -750,11 +750,11 @@ static void dev_close(struct fp_img_dev *idev) struct vfs_dev_t *vdev; /* Release private structure */ - vdev = fpi_imgdev_get_user_data(idev); + vdev = FP_INSTANCE_DATA(FP_DEV(idev)); g_free(vdev); /* Release usb interface */ - libusb_release_interface(fpi_imgdev_get_usb_dev(idev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); /* Notify close complete */ fpi_imgdev_close_complete(idev); diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c index 3304b1f9..8faaa230 100644 --- a/libfprint/drivers/vfs101.c +++ b/libfprint/drivers/vfs101.c @@ -56,7 +56,7 @@ #define VFS_IMG_MIN_IMAGE_LEVEL 144 /* Best image contrast */ -#define VFS_IMG_BEST_CONRAST 128 +#define VFS_IMG_BEST_CONTRAST 128 /* Device parameters address */ #define VFS_PAR_000E 0x000e @@ -105,9 +105,6 @@ struct vfs101_dev /* Ignore usb error */ int ignore_error; - /* Timeout */ - struct fpi_timeout *timeout; - /* Loop counter */ int counter; @@ -199,9 +196,9 @@ static int result_code(struct fp_img_dev *dev, int result) /* Callback of asynchronous send */ static void async_send_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* Cleanup transfer */ vdev->transfer = NULL; @@ -214,7 +211,7 @@ static void async_send_cb(struct libusb_transfer *transfer) /* Transfer not completed, return IO error */ fp_err("transfer not completed, status = %d", transfer->status); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -224,7 +221,7 @@ static void async_send_cb(struct libusb_transfer *transfer) fp_err("length mismatch, got %d, expected %d", transfer->actual_length, transfer->length); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } } @@ -242,22 +239,15 @@ out: } /* Submit asynchronous send */ -static void async_send(struct fpi_ssm *ssm) +static void +async_send(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); int r; /* Allocation of transfer */ - vdev->transfer = libusb_alloc_transfer(0); - if (!vdev->transfer) - { - /* Allocation transfer failed, return no memory error */ - fp_err("allocation of usb transfer failed"); - fpi_imgdev_session_error(dev, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } + vdev->transfer = fpi_usb_alloc(); /* Put sequential number into the buffer */ vdev->seqnum++; @@ -265,7 +255,7 @@ static void async_send(struct fpi_ssm *ssm) vdev->buffer[1] = byte(1, vdev->seqnum); /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT(1), vdev->buffer, vdev->length, async_send_cb, ssm, BULK_TIMEOUT); + libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT(1), vdev->buffer, vdev->length, async_send_cb, ssm, BULK_TIMEOUT); /* Submit transfer */ r = libusb_submit_transfer(vdev->transfer); @@ -275,7 +265,7 @@ static void async_send(struct fpi_ssm *ssm) libusb_free_transfer(vdev->transfer); fp_err("submit of usb transfer failed"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } } @@ -283,9 +273,9 @@ static void async_send(struct fpi_ssm *ssm) /* Callback of asynchronous recv */ static void async_recv_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* Cleanup transfer */ vdev->transfer = NULL; @@ -298,7 +288,7 @@ static void async_recv_cb(struct libusb_transfer *transfer) /* Transfer not completed, return IO error */ fp_err("transfer not completed, status = %d", transfer->status); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -308,7 +298,7 @@ static void async_recv_cb(struct libusb_transfer *transfer) fp_err("seqnum mismatch, got %04x, expected %04x", get_seqnum(vdev->buffer[1], vdev->buffer[0]), vdev->seqnum); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } } @@ -329,25 +319,18 @@ out: } /* Submit asynchronous recv */ -static void async_recv(struct fpi_ssm *ssm) +static void +async_recv(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); int r; /* Allocation of transfer */ - vdev->transfer = libusb_alloc_transfer(0); - if (!vdev->transfer) - { - /* Allocation transfer failed, return no memory error */ - fp_err("allocation of usb transfer failed"); - fpi_imgdev_session_error(dev, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } + vdev->transfer = fpi_usb_alloc(); /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_imgdev_get_usb_dev(dev), EP_IN(1), vdev->buffer, 0x0f, async_recv_cb, ssm, BULK_TIMEOUT); + libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN(1), vdev->buffer, 0x0f, async_recv_cb, ssm, BULK_TIMEOUT); /* Submit transfer */ r = libusb_submit_transfer(vdev->transfer); @@ -357,19 +340,19 @@ static void async_recv(struct fpi_ssm *ssm) libusb_free_transfer(vdev->transfer); fp_err("submit of usb transfer failed"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } } -static void async_load(struct fpi_ssm *ssm); +static void async_load(fpi_ssm *ssm, struct fp_img_dev *dev); /* Callback of asynchronous load */ static void async_load_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* Cleanup transfer */ vdev->transfer = NULL; @@ -382,7 +365,7 @@ static void async_load_cb(struct libusb_transfer *transfer) /* Transfer not completed */ fp_err("transfer not completed, status = %d, length = %d", transfer->status, vdev->length); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -391,7 +374,7 @@ static void async_load_cb(struct libusb_transfer *transfer) /* Received incomplete frame, return protocol error */ fp_err("received incomplete frame"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } } @@ -406,12 +389,12 @@ static void async_load_cb(struct libusb_transfer *transfer) /* Buffer full, image too large, return no memory error */ fp_err("buffer full, image too large"); fpi_imgdev_session_error(dev, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); + fpi_ssm_mark_failed(ssm, -ENOMEM); goto out; } else /* Image load not completed, submit another asynchronous load */ - async_load(ssm); + async_load(ssm, dev); } else { @@ -430,29 +413,22 @@ out: } /* Submit asynchronous load */ -static void async_load(struct fpi_ssm *ssm) +static void +async_load(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); unsigned char *buffer; int r; /* Allocation of transfer */ - vdev->transfer = libusb_alloc_transfer(0); - if (!vdev->transfer) - { - /* Allocation transfer failed, return no memory error */ - fp_err("allocation of usb transfer failed"); - fpi_imgdev_session_error(dev, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } + vdev->transfer = fpi_usb_alloc(); /* Append new data into the buffer */ buffer = vdev->buffer + vdev->length; /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_imgdev_get_usb_dev(dev), EP_IN(2), buffer, VFS_BLOCK_SIZE, async_load_cb, ssm, BULK_TIMEOUT); + libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN(2), buffer, VFS_BLOCK_SIZE, async_load_cb, ssm, BULK_TIMEOUT); /* Submit transfer */ r = libusb_submit_transfer(vdev->transfer); @@ -462,39 +438,23 @@ static void async_load(struct fpi_ssm *ssm) libusb_free_transfer(vdev->transfer); fp_err("submit of usb transfer failed"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); return; } } -/* Callback of asynchronous sleep */ -static void async_sleep_cb(void *data) -{ - struct fpi_ssm *ssm = data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); - - /* Cleanup timeout */ - vdev->timeout = NULL; - - fpi_ssm_next_state(ssm); -} - /* Submit asynchronous sleep */ -static void async_sleep(unsigned int msec, struct fpi_ssm *ssm) +static void +async_sleep(unsigned int msec, + fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); - - /* Add timeout */ - vdev->timeout = fpi_timeout_add(msec, async_sleep_cb, ssm); - - if (vdev->timeout == NULL) + if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) { /* Failed to add timeout */ fp_err("failed to add timeout"); fpi_imgdev_session_error(dev, -ETIME); - fpi_ssm_mark_aborted(ssm, -ETIME); + fpi_ssm_mark_failed(ssm, -ETIME); } } @@ -507,28 +467,31 @@ enum }; /* Exec swap sequential state machine */ -static void m_swap_state(struct fpi_ssm *ssm) +static void m_swap_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case M_SWAP_SEND: /* Send data */ - async_send(ssm); + async_send(ssm, user_data); break; case M_SWAP_RECV: /* Recv response */ - async_recv(ssm); + async_recv(ssm, user_data); break; } } /* Start swap sequential state machine */ -static void m_swap(struct fpi_ssm *ssm, unsigned char *data, size_t length) +static void +m_swap(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned char *data, + size_t length) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *subsm; + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *subsm; /* Prepare data for sending */ memcpy(vdev->buffer, data, length); @@ -536,13 +499,16 @@ static void m_swap(struct fpi_ssm *ssm, unsigned char *data, size_t length) vdev->length = length; /* Start swap ssm */ - subsm = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_swap_state, M_SWAP_NUM_STATES); - fpi_ssm_set_user_data(subsm, dev); + subsm = fpi_ssm_new(FP_DEV(dev), m_swap_state, M_SWAP_NUM_STATES, dev); fpi_ssm_start_subsm(ssm, subsm); } /* Retrieve fingerprint image */ -static void vfs_get_print(struct fpi_ssm *ssm, unsigned int param, int type) +static void +vfs_get_print(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned int param, + int type) { unsigned char data[2][0x0e] = { { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, @@ -558,11 +524,15 @@ static void vfs_get_print(struct fpi_ssm *ssm, unsigned int param, int type) data[type][7] = byte(1, param); /* Run swap sequential state machine */ - m_swap(ssm, data[type], 0x0e); + m_swap(ssm, dev, data[type], 0x0e); } /* Set a parameter value on the device */ -static void vfs_set_param(struct fpi_ssm *ssm, unsigned int param, unsigned int value) +static void +vfs_set_param(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned int param, + unsigned int value) { unsigned char data[0x0a] = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -575,22 +545,29 @@ static void vfs_set_param(struct fpi_ssm *ssm, unsigned int param, unsigned int data[9] = byte(1, value); /* Run swap sequential state machine */ - m_swap(ssm, data, 0x0a); + m_swap(ssm, dev, data, 0x0a); } /* Abort previous print */ -static void vfs_abort_print(struct fpi_ssm *ssm) +static void +vfs_abort_print(fpi_ssm *ssm, + struct fp_img_dev *dev) { unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 }; G_DEBUG_HERE(); /* Run swap sequential state machine */ - m_swap (ssm, data, 0x06); + m_swap (ssm, dev, data, 0x06); } /* Poke a value on a region */ -static void vfs_poke(struct fpi_ssm *ssm, unsigned int addr, unsigned int value, unsigned int size) +static void +vfs_poke(fpi_ssm *ssm, + struct fp_img_dev *dev, + unsigned int addr, + unsigned int value, + unsigned int size) { unsigned char data[0x0f] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -608,25 +585,28 @@ static void vfs_poke(struct fpi_ssm *ssm, unsigned int addr, unsigned int value, data[14] = byte(0, size); /* Run swap sequential state machine */ - m_swap(ssm, data, 0x0f); + m_swap(ssm, dev, data, 0x0f); } /* Get current finger state */ -static void vfs_get_finger_state(struct fpi_ssm *ssm) +static void +vfs_get_finger_state(fpi_ssm *ssm, + struct fp_img_dev *dev) { unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 }; G_DEBUG_HERE(); /* Run swap sequential state machine */ - m_swap (ssm, data, 0x06); + m_swap (ssm, dev, data, 0x06); } /* Load raw image from reader */ -static void vfs_img_load(struct fpi_ssm *ssm) +static void +vfs_img_load(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); G_DEBUG_HERE(); @@ -638,16 +618,16 @@ static void vfs_img_load(struct fpi_ssm *ssm) vdev->height = -1; /* Asynchronous load */ - async_load(ssm); + async_load(ssm, dev); } /* Check if action is completed */ static int action_completed(struct fp_img_dev *dev) { - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); if ((fpi_imgdev_get_action(dev) == IMG_ACTION_ENROLL) && - (vdev->enroll_stage < fpi_dev_get_nr_enroll_stages(fpi_imgdev_get_dev(dev)))) + (vdev->enroll_stage < fp_dev_get_nr_enroll_stages(FP_DEV(dev)))) /* Enroll not completed, return false */ return FALSE; @@ -754,10 +734,11 @@ static void img_copy(struct vfs101_dev *vdev, struct fp_img *img) } /* Extract fingerpint image from raw data */ -static void img_extract(struct fpi_ssm *ssm) +static void +img_extract(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); struct fp_img *img; /* Screen image to remove noise and find top and bottom line */ @@ -786,6 +767,11 @@ static void img_extract(struct fpi_ssm *ssm) /* Notify image captured */ fpi_imgdev_image_captured(dev, img); + /* FIXME + * What is this for? The action result, and the enroll stages should + * already be handled in fpi_imgdev_image_captured() + */ + /* Check captured result */ if (fpi_imgdev_get_action_result(dev) >= 0 && fpi_imgdev_get_action_result(dev) != FP_ENROLL_RETRY && @@ -870,7 +856,7 @@ static void vfs_check_contrast(struct vfs101_dev *vdev) fp_dbg("contrast = %d, level = %ld", vdev->contrast, count); - if (abs(count - VFS_IMG_BEST_CONRAST) < abs(vdev->best_clevel - VFS_IMG_BEST_CONRAST)) + if (labs(count - VFS_IMG_BEST_CONTRAST) < abs(vdev->best_clevel - VFS_IMG_BEST_CONTRAST)) { /* Better contrast found, use it */ vdev->best_contrast = vdev->contrast; @@ -912,10 +898,10 @@ enum }; /* Exec loop sequential state machine */ -static void m_loop_state(struct fpi_ssm *ssm) +static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); /* Check action state */ if (!vdev->active) @@ -929,17 +915,17 @@ static void m_loop_state(struct fpi_ssm *ssm) { case M_LOOP_0_GET_PRINT: /* Send get print command to the reader */ - vfs_get_print(ssm, VFS_BUFFER_HEIGHT, 1); + vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); break; case M_LOOP_0_SLEEP: /* Wait fingerprint scanning */ - async_sleep(50, ssm); + async_sleep(50, ssm, dev); break; case M_LOOP_0_GET_STATE: /* Get finger state */ - vfs_get_finger_state(ssm); + vfs_get_finger_state(ssm, dev); break; case M_LOOP_0_LOAD_IMAGE: @@ -954,14 +940,14 @@ static void m_loop_state(struct fpi_ssm *ssm) case VFS_FINGER_PRESENT: /* Load image from reader */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; default: /* Unknown state */ fp_err("unknown device state 0x%02x", vdev->buffer[0x0a]); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); break; } break; @@ -970,10 +956,10 @@ static void m_loop_state(struct fpi_ssm *ssm) /* Check if image is loaded */ if (vdev->height > 0) /* Fingerprint is loaded, extract image from raw data */ - img_extract(ssm); + img_extract(ssm, dev); /* Wait handling image */ - async_sleep(10, ssm); + async_sleep(10, ssm, dev); break; case M_LOOP_0_CHECK_ACTION: @@ -993,7 +979,7 @@ static void m_loop_state(struct fpi_ssm *ssm) case M_LOOP_1_GET_STATE: /* Get finger state */ - vfs_get_finger_state(ssm); + vfs_get_finger_state(ssm, dev); break; case M_LOOP_1_CHECK_STATE: @@ -1011,14 +997,14 @@ static void m_loop_state(struct fpi_ssm *ssm) /* Wait removing finger */ vdev->counter++; - async_sleep(250, ssm); + async_sleep(250, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("finger not removed from the scanner"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } else @@ -1049,13 +1035,13 @@ static void m_loop_state(struct fpi_ssm *ssm) case M_LOOP_1_GET_PRINT: /* Send get print command to the reader */ - vfs_get_print(ssm, VFS_BUFFER_HEIGHT, 1); + vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); break; case M_LOOP_1_LOAD_IMAGE: /* Load image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_LOOP_1_LOOP: @@ -1065,29 +1051,29 @@ static void m_loop_state(struct fpi_ssm *ssm) case M_LOOP_1_SLEEP: /* Wait fingerprint scanning */ - async_sleep(10, ssm); + async_sleep(10, ssm, dev); break; case M_LOOP_2_ABORT_PRINT: /* Abort print command */ - vfs_abort_print(ssm); + vfs_abort_print(ssm, dev); break; case M_LOOP_2_LOAD_IMAGE: /* Load abort image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_LOOP_3_GET_PRINT: /* Get empty image */ - vfs_get_print(ssm, 0x000a, 0); + vfs_get_print(ssm, dev, 0x000a, 0); break; case M_LOOP_3_LOAD_IMAGE: /* Load abort image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_LOOP_3_CHECK_IMAGE: @@ -1101,14 +1087,14 @@ static void m_loop_state(struct fpi_ssm *ssm) { /* Wait aborting */ vdev->counter++; - async_sleep(100, ssm); + async_sleep(100, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("waiting abort reach max loop counter"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } break; @@ -1120,7 +1106,7 @@ static void m_loop_state(struct fpi_ssm *ssm) } /* Complete loop sequential state machine */ -static void m_loop_complete(struct fpi_ssm *ssm) +static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { /* Free sequential state machine */ fpi_ssm_free(ssm); @@ -1176,10 +1162,10 @@ enum }; /* Exec init sequential state machine */ -static void m_init_state(struct fpi_ssm *ssm) +static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); /* Check action state */ if (!vdev->active) @@ -1194,29 +1180,29 @@ static void m_init_state(struct fpi_ssm *ssm) case M_INIT_0_RECV_DIRTY: /* Recv eventualy dirty data */ vdev->ignore_error = TRUE; - async_recv(ssm); + async_recv(ssm, dev); break; case M_INIT_0_ABORT_PRINT: /* Abort print command */ - vfs_abort_print(ssm); + vfs_abort_print(ssm, dev); break; case M_INIT_0_LOAD_IMAGE: /* Load abort image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_INIT_1_GET_PRINT: /* Get empty image */ - vfs_get_print(ssm, 0x000a, 0); + vfs_get_print(ssm, dev, 0x000a, 0); break; case M_INIT_1_LOAD_IMAGE: /* Load abort image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_INIT_1_CHECK_IMAGE: @@ -1230,14 +1216,14 @@ static void m_init_state(struct fpi_ssm *ssm) { /* Wait aborting */ vdev->counter++; - async_sleep(100, ssm); + async_sleep(100, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("waiting abort reach max loop counter"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } break; @@ -1248,7 +1234,7 @@ static void m_init_state(struct fpi_ssm *ssm) case M_INIT_2_GET_STATE: /* Get finger state */ - vfs_get_finger_state(ssm); + vfs_get_finger_state(ssm, dev); break; case M_INIT_2_CHECK_STATE: @@ -1266,14 +1252,14 @@ static void m_init_state(struct fpi_ssm *ssm) /* Wait removing finger */ vdev->counter++; - async_sleep(250, ssm); + async_sleep(250, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("finger not removed from the scanner"); fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); } } else @@ -1293,13 +1279,13 @@ static void m_init_state(struct fpi_ssm *ssm) case M_INIT_2_GET_PRINT: /* Send get print command to the reader */ - vfs_get_print(ssm, VFS_BUFFER_HEIGHT, 1); + vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); break; case M_INIT_2_LOAD_IMAGE: /* Load unexpected image */ vdev->ignore_error = TRUE; - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_INIT_2_LOOP: @@ -1309,68 +1295,68 @@ static void m_init_state(struct fpi_ssm *ssm) case M_INIT_3_SET_000E: /* Set param 0x000e, required for take image */ - vfs_set_param(ssm, VFS_PAR_000E, VFS_VAL_000E); + vfs_set_param(ssm, dev, VFS_PAR_000E, VFS_VAL_000E); break; case M_INIT_3_SET_0011: /* Set param 0x0011, required for take image */ - vfs_set_param(ssm, VFS_PAR_0011, VFS_VAL_0011); + vfs_set_param(ssm, dev, VFS_PAR_0011, VFS_VAL_0011); break; case M_INIT_3_SET_0076: /* Set param 0x0076, required for use info line */ - vfs_set_param(ssm, VFS_PAR_0076, VFS_VAL_0076); + vfs_set_param(ssm, dev, VFS_PAR_0076, VFS_VAL_0076); break; case M_INIT_3_SET_0078: /* Set param 0x0078, required for use info line */ - vfs_set_param(ssm, VFS_PAR_0078, VFS_VAL_0078); + vfs_set_param(ssm, dev, VFS_PAR_0078, VFS_VAL_0078); break; case M_INIT_3_SET_THRESHOLD: /* Set threshold */ - vfs_set_param(ssm, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD); + vfs_set_param(ssm, dev, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD); break; case M_INIT_3_SET_STATE3_COUNT: /* Set state 3 count */ - vfs_set_param(ssm, VFS_PAR_STATE_3, VFS_VAL_STATE_3); + vfs_set_param(ssm, dev, VFS_PAR_STATE_3, VFS_VAL_STATE_3); break; case M_INIT_3_SET_STATE5_COUNT: /* Set state 5 count */ - vfs_set_param(ssm, VFS_PAR_STATE_5, VFS_VAL_STATE_5); + vfs_set_param(ssm, dev, VFS_PAR_STATE_5, VFS_VAL_STATE_5); break; case M_INIT_3_SET_INFO_CONTRAST: /* Set info line contrast */ - vfs_set_param(ssm, VFS_PAR_INFO_CONTRAST, 10); + vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, 10); break; case M_INIT_3_SET_INFO_RATE: /* Set info line rate */ - vfs_set_param(ssm, VFS_PAR_INFO_RATE, 32); + vfs_set_param(ssm, dev, VFS_PAR_INFO_RATE, 32); break; case M_INIT_4_SET_EXPOSURE: /* Set exposure level of reader */ - vfs_poke(ssm, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02); + vfs_poke(ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02); vdev->counter = 1; break; case M_INIT_4_SET_CONTRAST: /* Set contrast level of reader */ - vfs_poke(ssm, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); + vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); break; case M_INIT_4_GET_PRINT: /* Get empty image */ - vfs_get_print(ssm, 0x000a, 0); + vfs_get_print(ssm, dev, 0x000a, 0); break; case M_INIT_4_LOAD_IMAGE: /* Load empty image */ - vfs_img_load(ssm); + vfs_img_load(ssm, dev); break; case M_INIT_4_CHECK_CONTRAST: @@ -1396,32 +1382,32 @@ static void m_init_state(struct fpi_ssm *ssm) case M_INIT_5_SET_EXPOSURE: /* Set exposure level of reader */ - vfs_poke(ssm, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02); + vfs_poke(ssm, dev, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02); break; case M_INIT_5_SET_CONTRAST: /* Set contrast level of reader */ - vfs_poke(ssm, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); + vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); break; case M_INIT_5_SET_INFO_CONTRAST: /* Set info line contrast */ - vfs_set_param(ssm, VFS_PAR_INFO_CONTRAST, vdev->contrast); + vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, vdev->contrast); break; case M_INIT_5_SET_INFO_RATE: /* Set info line rate */ - vfs_set_param(ssm, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE); + vfs_set_param(ssm, dev, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE); break; } } /* Complete init sequential state machine */ -static void m_init_complete(struct fpi_ssm *ssm) +static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm_loop; + struct fp_img_dev *dev = user_data; + struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); + fpi_ssm *ssm_loop; if (!fpi_ssm_get_error(ssm) && vdev->active) { @@ -1429,8 +1415,7 @@ static void m_init_complete(struct fpi_ssm *ssm) fpi_imgdev_activate_complete(dev, 0); /* Start loop ssm */ - ssm_loop = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_loop_state, M_LOOP_NUM_STATES); - fpi_ssm_set_user_data(ssm_loop, dev); + ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev); fpi_ssm_start(ssm_loop, m_loop_complete); } @@ -1441,8 +1426,8 @@ static void m_init_complete(struct fpi_ssm *ssm) /* Activate device */ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); - struct fpi_ssm *ssm; + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + fpi_ssm *ssm; /* Check if already active */ if (vdev->active) @@ -1464,8 +1449,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) vdev->enroll_stage = 0; /* Start init ssm */ - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_init_state, M_INIT_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, M_INIT_NUM_STATES, dev); fpi_ssm_start(ssm, m_init_complete); return 0; @@ -1474,13 +1458,13 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) /* Deactivate device */ static void dev_deactivate(struct fp_img_dev *dev) { - struct vfs101_dev *vdev = fpi_imgdev_get_user_data(dev); + struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); /* Reset active state */ vdev->active = FALSE; /* Handle eventualy existing events */ - while (vdev->transfer || vdev->timeout) + while (vdev->transfer) fp_handle_events(); /* Notify deactivate complete */ @@ -1494,7 +1478,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) int r; /* Claim usb interface */ - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { /* Interface not claimed, return error */ @@ -1505,7 +1489,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) /* Initialize private structure */ vdev = g_malloc0(sizeof(struct vfs101_dev)); vdev->seqnum = -1; - fpi_imgdev_set_user_data(dev, vdev); + fp_dev_set_instance_data(FP_DEV(dev), vdev); /* Notify open complete */ fpi_imgdev_open_complete(dev, 0); @@ -1519,11 +1503,11 @@ static void dev_close(struct fp_img_dev *dev) struct vfs101_dev *vdev; /* Release private structure */ - vdev = fpi_imgdev_get_user_data(dev); + vdev = FP_INSTANCE_DATA(FP_DEV(dev)); g_free(vdev); /* Release usb interface */ - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); /* Notify close complete */ fpi_imgdev_close_complete(dev); diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c index a34ee31c..4116e71e 100644 --- a/libfprint/drivers/vfs301.c +++ b/libfprint/drivers/vfs301.c @@ -26,35 +26,26 @@ /************************** GENERIC STUFF *************************************/ -/* Callback of asynchronous sleep */ -static void async_sleep_cb(void *data) -{ - struct fpi_ssm *ssm = data; - - fpi_ssm_next_state(ssm); -} - /* Submit asynchronous sleep */ -static void async_sleep(unsigned int msec, struct fpi_ssm *ssm) +static void +async_sleep(unsigned int msec, + fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct fpi_timeout *timeout; - /* Add timeout */ - timeout = fpi_timeout_add(msec, async_sleep_cb, ssm); - - if (timeout == NULL) { + if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) { /* Failed to add timeout */ fp_err("failed to add timeout"); fpi_imgdev_session_error(dev, -ETIME); - fpi_ssm_mark_aborted(ssm, -ETIME); + fpi_ssm_mark_failed(ssm, -ETIME); } } -static int submit_image(struct fpi_ssm *ssm) +static int +submit_image(fpi_ssm *ssm, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev); + vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); int height; struct fp_img *img; @@ -80,7 +71,7 @@ static int submit_image(struct fpi_ssm *ssm) img->width = VFS301_FP_OUTPUT_WIDTH; img->height = height; - img = fpi_img_resize(img, img->height * img->width); + img = fpi_img_realloc(img, img->height * img->width); fpi_imgdev_image_captured(dev, img); return 1; @@ -103,24 +94,24 @@ enum }; /* Exec loop sequential state machine */ -static void m_loop_state(struct fpi_ssm *ssm) +static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case M_REQUEST_PRINT: - vfs301_proto_request_fingerprint(fpi_imgdev_get_usb_dev(dev), vdev); + vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); fpi_ssm_next_state(ssm); break; case M_WAIT_PRINT: /* Wait fingerprint scanning */ - async_sleep(200, ssm); + async_sleep(200, ssm, dev); break; case M_CHECK_PRINT: - if (!vfs301_proto_peek_event(fpi_imgdev_get_usb_dev(dev), vdev)) + if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev)) fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT); else fpi_ssm_next_state(ssm); @@ -128,18 +119,18 @@ static void m_loop_state(struct fpi_ssm *ssm) case M_READ_PRINT_START: fpi_imgdev_report_finger_status(dev, TRUE); - vfs301_proto_process_event_start(fpi_imgdev_get_usb_dev(dev), vdev); + vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); fpi_ssm_next_state(ssm); break; case M_READ_PRINT_WAIT: /* Wait fingerprint scanning */ - async_sleep(200, ssm); + async_sleep(200, ssm, dev); break; case M_READ_PRINT_POLL: { - int rv = vfs301_proto_process_event_poll(fpi_imgdev_get_usb_dev(dev), vdev); + int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); g_assert(rv != VFS301_FAILURE); if (rv == VFS301_ONGOING) fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT); @@ -149,7 +140,7 @@ static void m_loop_state(struct fpi_ssm *ssm) break; case M_SUBMIT_PRINT: - if (submit_image(ssm)) { + if (submit_image(ssm, dev)) { fpi_ssm_mark_completed(ssm); /* NOTE: finger off is expected only after submitting image... */ fpi_imgdev_report_finger_status(dev, FALSE); @@ -161,38 +152,37 @@ static void m_loop_state(struct fpi_ssm *ssm) } /* Complete loop sequential state machine */ -static void m_loop_complete(struct fpi_ssm *ssm) +static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { /* Free sequential state machine */ fpi_ssm_free(ssm); } /* Exec init sequential state machine */ -static void m_init_state(struct fpi_ssm *ssm) +static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev); + struct fp_img_dev *dev = user_data; + vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev); g_assert(fpi_ssm_get_cur_state(ssm) == 0); - vfs301_proto_init(fpi_imgdev_get_usb_dev(dev), vdev); + vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); fpi_ssm_mark_completed(ssm); } /* Complete init sequential state machine */ -static void m_init_complete(struct fpi_ssm *ssm) +static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct fpi_ssm *ssm_loop; + struct fp_img_dev *dev = user_data; + fpi_ssm *ssm_loop; if (!fpi_ssm_get_error(ssm)) { /* Notify activate complete */ fpi_imgdev_activate_complete(dev, 0); /* Start loop ssm */ - ssm_loop = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_loop_state, M_LOOP_NUM_STATES); - fpi_ssm_set_user_data(ssm_loop, dev); + ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev); fpi_ssm_start(ssm_loop, m_loop_complete); } @@ -203,11 +193,10 @@ static void m_init_complete(struct fpi_ssm *ssm) /* Activate device */ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { - struct fpi_ssm *ssm; + fpi_ssm *ssm; /* Start init ssm */ - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_init_state, 1); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev); fpi_ssm_start(ssm, m_init_complete); return 0; @@ -216,6 +205,10 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) /* Deactivate device */ static void dev_deactivate(struct fp_img_dev *dev) { + vfs301_dev_t *vdev; + + vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); fpi_imgdev_deactivate_complete(dev); } @@ -225,7 +218,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) int r; /* Claim usb interface */ - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r < 0) { /* Interface not claimed, return error */ fp_err("could not claim interface 0: %s", libusb_error_name(r)); @@ -234,7 +227,7 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) /* Initialize private structure */ vdev = g_malloc0(sizeof(vfs301_dev_t)); - fpi_imgdev_set_user_data(dev, vdev); + fp_dev_set_instance_data(FP_DEV(dev), vdev); vdev->scanline_buf = malloc(0); vdev->scanline_count = 0; @@ -250,12 +243,12 @@ static void dev_close(struct fp_img_dev *dev) vfs301_dev_t *vdev; /* Release private structure */ - vdev = fpi_imgdev_get_user_data(dev); + vdev = FP_INSTANCE_DATA(FP_DEV(dev)); free(vdev->scanline_buf); g_free(vdev); /* Release usb interface */ - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); /* Notify close complete */ fpi_imgdev_close_complete(dev); diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c index f96f411a..7564f56d 100644 --- a/libfprint/drivers/vfs301_proto.c +++ b/libfprint/drivers/vfs301_proto.c @@ -33,8 +33,8 @@ #include #include #include -#include +#include "fpi-usb.h" #include "vfs301_proto.h" #include "vfs301_proto_fragments.h" @@ -499,12 +499,7 @@ void vfs301_proto_process_event_start( USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 64); /* now read the fingerprint data, while there are some */ - transfer = libusb_alloc_transfer(0); - if (!transfer) { - dev->recv_progress = VFS301_FAILURE; - return; - } - + transfer = fpi_usb_alloc(); dev->recv_progress = VFS301_ONGOING; dev->recv_exp_amt = VFS301_FP_RECV_LEN_1; diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c index 8b460acf..2fcb822a 100644 --- a/libfprint/drivers/vfs5011.c +++ b/libfprint/drivers/vfs5011.c @@ -75,14 +75,14 @@ static void start_scan(struct fp_img_dev *dev); static void async_send_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct usbexchange_data *data = fpi_ssm_get_user_data(ssm); struct usb_action *action; if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { fp_err("Radiation detected!"); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); goto out; } @@ -90,7 +90,7 @@ static void async_send_cb(struct libusb_transfer *transfer) if (action->type != ACTION_SEND) { fp_err("Radiation detected!"); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); goto out; } @@ -98,7 +98,7 @@ static void async_send_cb(struct libusb_transfer *transfer) /* Transfer not completed, return IO error */ fp_err("transfer not completed, status = %d", transfer->status); fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } if (transfer->length != transfer->actual_length) { @@ -106,7 +106,7 @@ static void async_send_cb(struct libusb_transfer *transfer) fp_err("length mismatch, got %d, expected %d", transfer->actual_length, transfer->length); fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } @@ -119,7 +119,7 @@ out: static void async_recv_cb(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = transfer->user_data; + fpi_ssm *ssm = transfer->user_data; struct usbexchange_data *data = fpi_ssm_get_user_data(ssm); struct usb_action *action; @@ -127,14 +127,14 @@ static void async_recv_cb(struct libusb_transfer *transfer) /* Transfer not completed, return IO error */ fp_err("transfer not completed, status = %d", transfer->status); fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { fp_err("Radiation detected!"); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); goto out; } @@ -142,7 +142,7 @@ static void async_recv_cb(struct libusb_transfer *transfer) if (action->type != ACTION_RECEIVE) { fp_err("Radiation detected!"); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); goto out; } @@ -152,14 +152,14 @@ static void async_recv_cb(struct libusb_transfer *transfer) transfer->actual_length, action->correct_reply_size); fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } if (memcmp(transfer->buffer, action->data, action->correct_reply_size) != 0) { fp_dbg("Wrong reply:"); fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_aborted(ssm, -EIO); + fpi_ssm_mark_failed(ssm, -EIO); goto out; } } else @@ -171,14 +171,14 @@ out: libusb_free_transfer(transfer); } -static void usbexchange_loop(struct fpi_ssm *ssm) +static void usbexchange_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct usbexchange_data *data = fpi_ssm_get_user_data(ssm); + struct usbexchange_data *data = user_data; if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { fp_err("Bug detected: state %d out of range, only %d steps", fpi_ssm_get_cur_state(ssm), data->stepcount); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); return; } @@ -189,14 +189,8 @@ static void usbexchange_loop(struct fpi_ssm *ssm) switch (action->type) { case ACTION_SEND: fp_dbg("Sending %s", action->name); - transfer = libusb_alloc_transfer(0); - if (transfer == NULL) { - fp_err("Failed to allocate transfer"); - fpi_imgdev_session_error(data->device, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(data->device), + transfer = fpi_usb_alloc(); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)), action->endpoint, action->data, action->size, async_send_cb, ssm, data->timeout); @@ -205,14 +199,8 @@ static void usbexchange_loop(struct fpi_ssm *ssm) case ACTION_RECEIVE: fp_dbg("Receiving %d bytes", action->size); - transfer = libusb_alloc_transfer(0); - if (transfer == NULL) { - fp_err("Failed to allocate transfer"); - fpi_imgdev_session_error(data->device, -ENOMEM); - fpi_ssm_mark_aborted(ssm, -ENOMEM); - return; - } - libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(data->device), + transfer = fpi_usb_alloc(); + libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)), action->endpoint, data->receive_buf, action->size, async_recv_cb, ssm, data->timeout); @@ -222,24 +210,24 @@ static void usbexchange_loop(struct fpi_ssm *ssm) default: fp_err("Bug detected: invalid action %d", action->type); fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_aborted(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, -EINVAL); return; } if (ret != 0) { fp_err("USB transfer error: %s", strerror(ret)); fpi_imgdev_session_error(data->device, ret); - fpi_ssm_mark_aborted(ssm, ret); + fpi_ssm_mark_failed(ssm, ret); } } -static void usb_exchange_async(struct fpi_ssm *ssm, +static void usb_exchange_async(fpi_ssm *ssm, struct usbexchange_data *data) { - struct fpi_ssm *subsm = fpi_ssm_new(fpi_imgdev_get_dev(data->device), - usbexchange_loop, - data->stepcount); - fpi_ssm_set_user_data(subsm, data); + fpi_ssm *subsm = fpi_ssm_new(FP_DEV(data->device), + usbexchange_loop, + data->stepcount, + data); fpi_ssm_start_subsm(ssm, subsm); } @@ -395,9 +383,11 @@ static int process_chunk(struct vfs5011_data *data, int transferred) return 0; } -void submit_image(struct fpi_ssm *ssm, struct vfs5011_data *data) +static void +submit_image(fpi_ssm *ssm, + struct vfs5011_data *data, + struct fp_img_dev *dev) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); struct fp_img *img; if (data->lines_recorded == 0) { @@ -422,11 +412,11 @@ void submit_image(struct fpi_ssm *ssm, struct vfs5011_data *data) static void chunk_capture_callback(struct libusb_transfer *transfer) { - struct fpi_ssm *ssm = (struct fpi_ssm *)transfer->user_data; + fpi_ssm *ssm = (fpi_ssm *)transfer->user_data; struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(FP_DEV(dev)); if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) || (transfer->status == LIBUSB_TRANSFER_TIMED_OUT)) { @@ -441,7 +431,7 @@ static void chunk_capture_callback(struct libusb_transfer *transfer) } else { if (!data->deactivating) { fp_err("Failed to capture data"); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } else { fpi_ssm_mark_completed(ssm); } @@ -452,7 +442,7 @@ static void chunk_capture_callback(struct libusb_transfer *transfer) static int capture_chunk_async(struct vfs5011_data *data, libusb_device_handle *handle, int nline, - int timeout, struct fpi_ssm *ssm) + int timeout, fpi_ssm *ssm) { fp_dbg("capture_chunk_async: capture %d lines, already have %d", nline, data->lines_recorded); @@ -462,7 +452,7 @@ static int capture_chunk_async(struct vfs5011_data *data, STOP_CHECK_LINES = 50 }; - data->flying_transfer = libusb_alloc_transfer(0); + data->flying_transfer = fpi_usb_alloc(); libusb_fill_bulk_transfer(data->flying_transfer, handle, VFS5011_IN_ENDPOINT_DATA, data->capture_buffer, nline * VFS5011_LINE_SIZE, @@ -470,13 +460,6 @@ static int capture_chunk_async(struct vfs5011_data *data, return libusb_submit_transfer(data->flying_transfer); } -static void async_sleep_cb(void *data) -{ - struct fpi_ssm *ssm = data; - - fpi_ssm_next_state(ssm); -} - /* * Device initialization. Windows driver only does it when the device is * plugged in, but it doesn't harm to do this every time before scanning the @@ -665,16 +648,16 @@ struct usb_action vfs5011_initiate_capture[] = { /* ====================== lifprint interface ======================= */ -static void activate_loop(struct fpi_ssm *ssm) +static void activate_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { enum {READ_TIMEOUT = 0}; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; struct vfs5011_data *data; int r; - struct fpi_timeout *timeout; + fpi_timeout *timeout; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(_dev); fp_dbg("main_loop: state %d", fpi_ssm_get_cur_state(ssm)); @@ -707,23 +690,23 @@ static void activate_loop(struct fpi_ssm *ssm) break; case DEV_ACTIVATE_READ_DATA: - r = capture_chunk_async(data, fpi_imgdev_get_usb_dev(dev), CAPTURE_LINES, + r = capture_chunk_async(data, fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_LINES, READ_TIMEOUT, ssm); if (r != 0) { fp_err("Failed to capture data"); fpi_imgdev_session_error(dev, r); - fpi_ssm_mark_aborted(ssm, r); + fpi_ssm_mark_failed(ssm, r); } break; case DEV_ACTIVATE_DATA_COMPLETE: - timeout = fpi_timeout_add(1, async_sleep_cb, ssm); + timeout = fpi_timeout_add(1, fpi_ssm_next_state_timeout_cb, _dev, ssm); if (timeout == NULL) { /* Failed to add timeout */ fp_err("failed to add timeout"); fpi_imgdev_session_error(dev, -1); - fpi_ssm_mark_aborted(ssm, -1); + fpi_ssm_mark_failed(ssm, -1); } break; @@ -742,20 +725,20 @@ static void activate_loop(struct fpi_ssm *ssm) } } -static void activate_loop_complete(struct fpi_ssm *ssm) +static void activate_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; struct vfs5011_data *data; int r = fpi_ssm_get_error(ssm); - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(_dev); fp_dbg("finishing"); if (data->init_sequence.receive_buf != NULL) g_free(data->init_sequence.receive_buf); data->init_sequence.receive_buf = NULL; if (!data->deactivating && !r) { - submit_image(ssm, data); + submit_image(ssm, data, dev); fpi_imgdev_report_finger_status(dev, FALSE); } fpi_ssm_free(ssm); @@ -772,12 +755,12 @@ static void activate_loop_complete(struct fpi_ssm *ssm) } -static void open_loop(struct fpi_ssm *ssm) +static void open_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case DEV_OPEN_START: @@ -793,12 +776,12 @@ static void open_loop(struct fpi_ssm *ssm) }; } -static void open_loop_complete(struct fpi_ssm *ssm) +static void open_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + struct fp_img_dev *dev = user_data; struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(_dev); g_free(data->init_sequence.receive_buf); data->init_sequence.receive_buf = NULL; @@ -815,23 +798,22 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) data = (struct vfs5011_data *)g_malloc0(sizeof(*data)); data->capture_buffer = (unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE); - fpi_imgdev_set_user_data(dev, data); + fp_dev_set_instance_data(FP_DEV(dev), data); - r = libusb_reset_device(fpi_imgdev_get_usb_dev(dev)); + r = libusb_reset_device(fpi_dev_get_usb_dev(FP_DEV(dev))); if (r != 0) { fp_err("Failed to reset the device"); return r; } - r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0); + r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); if (r != 0) { fp_err("Failed to claim interface: %s", libusb_error_name(r)); return r; } - struct fpi_ssm *ssm; - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), open_loop, DEV_OPEN_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + fpi_ssm *ssm; + ssm = fpi_ssm_new(FP_DEV(dev), open_loop, DEV_OPEN_NUM_STATES, dev); fpi_ssm_start(ssm, open_loop_complete); return 0; @@ -839,9 +821,9 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) static void dev_close(struct fp_img_dev *dev) { - libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0); + libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(FP_DEV(dev)); if (data != NULL) { g_free(data->capture_buffer); g_slist_free_full(data->rows, g_free); @@ -853,13 +835,12 @@ static void dev_close(struct fp_img_dev *dev) static void start_scan(struct fp_img_dev *dev) { struct vfs5011_data *data; - struct fpi_ssm *ssm; + fpi_ssm *ssm; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(FP_DEV(dev)); data->loop_running = TRUE; fp_dbg("creating ssm"); - ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_loop, DEV_ACTIVATE_NUM_STATES); - fpi_ssm_set_user_data(ssm, dev); + ssm = fpi_ssm_new(FP_DEV(dev), activate_loop, DEV_ACTIVATE_NUM_STATES, dev); fp_dbg("starting ssm"); fpi_ssm_start(ssm, activate_loop_complete); fp_dbg("ssm done, getting out"); @@ -869,7 +850,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) { struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(FP_DEV(dev)); fp_dbg("device initialized"); data->deactivating = FALSE; @@ -883,7 +864,7 @@ static void dev_deactivate(struct fp_img_dev *dev) int r; struct vfs5011_data *data; - data = fpi_imgdev_get_user_data(dev); + data = FP_INSTANCE_DATA(FP_DEV(dev)); if (data->loop_running) { data->deactivating = TRUE; if (data->flying_transfer) { diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h index 2679c778..7867e346 100644 --- a/libfprint/drivers_api.h +++ b/libfprint/drivers_api.h @@ -23,288 +23,17 @@ #include -#ifdef FP_COMPONENT -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "libfprint-"FP_COMPONENT -#endif - -#include -#include -#include -#include - #include "fprint.h" -#include "assembling.h" +#include "fpi-log.h" +#include "fpi-dev.h" +#include "fpi-dev-img.h" +#include "fpi-core.h" +#include "fpi-ssm.h" +#include "fpi-poll.h" +#include "fpi-dev.h" +#include "fpi-usb.h" +#include "fpi-img.h" +#include "fpi-assembling.h" #include "drivers/driver_ids.h" -#define fp_dbg g_debug -#define fp_info g_debug -#define fp_warn g_warning -#define fp_err g_warning - -#define BUG_ON(condition) G_STMT_START \ - if (condition) { \ - char *s; \ - s = g_strconcat ("BUG: (", #condition, ")", NULL); \ - g_warning ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \ - g_free (s); \ - } G_STMT_END -#define BUG() BUG_ON(1) - -enum fp_dev_state { - DEV_STATE_INITIAL = 0, - DEV_STATE_ERROR, - DEV_STATE_INITIALIZING, - DEV_STATE_INITIALIZED, - DEV_STATE_DEINITIALIZING, - DEV_STATE_DEINITIALIZED, - DEV_STATE_ENROLL_STARTING, - DEV_STATE_ENROLLING, - DEV_STATE_ENROLL_STOPPING, - DEV_STATE_VERIFY_STARTING, - DEV_STATE_VERIFYING, - DEV_STATE_VERIFY_DONE, - DEV_STATE_VERIFY_STOPPING, - DEV_STATE_IDENTIFY_STARTING, - DEV_STATE_IDENTIFYING, - DEV_STATE_IDENTIFY_DONE, - DEV_STATE_IDENTIFY_STOPPING, - DEV_STATE_CAPTURE_STARTING, - DEV_STATE_CAPTURING, - DEV_STATE_CAPTURE_DONE, - DEV_STATE_CAPTURE_STOPPING, -}; - -struct fp_dev; -libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev); -void *fpi_dev_get_user_data (struct fp_dev *dev); -void fpi_dev_set_user_data (struct fp_dev *dev, void *user_data); -int fpi_dev_get_nr_enroll_stages(struct fp_dev *dev); -void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, int nr_enroll_stages); -struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev); -enum fp_dev_state fpi_dev_get_dev_state(struct fp_dev *dev); - -enum fp_imgdev_state { - IMGDEV_STATE_INACTIVE, - IMGDEV_STATE_AWAIT_FINGER_ON, - IMGDEV_STATE_CAPTURE, - IMGDEV_STATE_AWAIT_FINGER_OFF, -}; - -enum fp_imgdev_action { - IMG_ACTION_NONE = 0, - IMG_ACTION_ENROLL, - IMG_ACTION_VERIFY, - IMG_ACTION_IDENTIFY, - IMG_ACTION_CAPTURE, -}; - -enum fp_imgdev_enroll_state { - IMG_ACQUIRE_STATE_NONE = 0, - IMG_ACQUIRE_STATE_ACTIVATING, - IMG_ACQUIRE_STATE_AWAIT_FINGER_ON, - IMG_ACQUIRE_STATE_AWAIT_IMAGE, - IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF, - IMG_ACQUIRE_STATE_DONE, - IMG_ACQUIRE_STATE_DEACTIVATING, -}; - -enum fp_imgdev_verify_state { - IMG_VERIFY_STATE_NONE = 0, - IMG_VERIFY_STATE_ACTIVATING -}; - -struct fp_img_dev; -libusb_device_handle *fpi_imgdev_get_usb_dev(struct fp_img_dev *dev); -void fpi_imgdev_set_user_data(struct fp_img_dev *imgdev, - void *user_data); -void *fpi_imgdev_get_user_data(struct fp_img_dev *imgdev); -struct fp_dev *fpi_imgdev_get_dev(struct fp_img_dev *imgdev); -enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev); -enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev); -int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev); -void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result); -int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev); -int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev); - -struct usb_id { - uint16_t vendor; - uint16_t product; - unsigned long driver_data; -}; - -enum fp_driver_type { - DRIVER_PRIMITIVE = 0, - DRIVER_IMAGING = 1, -}; - -struct fp_driver { - const uint16_t id; - const char *name; - const char *full_name; - const struct usb_id * const id_table; - enum fp_driver_type type; - enum fp_scan_type scan_type; - - void *priv; - - /* Device operations */ - int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); - int (*open)(struct fp_dev *dev, unsigned long driver_data); - void (*close)(struct fp_dev *dev); - int (*enroll_start)(struct fp_dev *dev); - int (*enroll_stop)(struct fp_dev *dev); - int (*verify_start)(struct fp_dev *dev); - int (*verify_stop)(struct fp_dev *dev, gboolean iterating); - int (*identify_start)(struct fp_dev *dev); - int (*identify_stop)(struct fp_dev *dev, gboolean iterating); - int (*capture_start)(struct fp_dev *dev); - int (*capture_stop)(struct fp_dev *dev); -}; - -/* flags for fp_img_driver.flags */ -#define FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE (1 << 0) - -struct fp_img_driver { - struct fp_driver driver; - uint16_t flags; - int img_width; - int img_height; - int bz3_threshold; - - /* Device operations */ - int (*open)(struct fp_img_dev *dev, unsigned long driver_data); - void (*close)(struct fp_img_dev *dev); - int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state); - int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state); - void (*deactivate)(struct fp_img_dev *dev); -}; - -enum fp_print_data_type { - PRINT_DATA_RAW = 0, /* memset-imposed default */ - PRINT_DATA_NBIS_MINUTIAE, -}; - -struct fp_print_data_item { - size_t length; - unsigned char data[0]; -}; - -struct fp_print_data { - uint16_t driver_id; - uint32_t devtype; - enum fp_print_data_type type; - GSList *prints; -}; - -struct fp_print_data *fpi_print_data_new(struct fp_dev *dev); -struct fp_print_data_item *fpi_print_data_item_new(size_t length); -gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, - enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, - enum fp_print_data_type type2); - -struct fp_minutiae; - -/* bit values for fp_img.flags */ -#define FP_IMG_V_FLIPPED (1<<0) -#define FP_IMG_H_FLIPPED (1<<1) -#define FP_IMG_COLORS_INVERTED (1<<2) -#define FP_IMG_BINARIZED_FORM (1<<3) -#define FP_IMG_PARTIAL (1<<4) - -#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \ - | FP_IMG_COLORS_INVERTED) - -struct fp_img { - int width; - int height; - size_t length; - uint16_t flags; - struct fp_minutiae *minutiae; - unsigned char *binarized; - unsigned char data[0]; -}; - -struct fp_img *fpi_img_new(size_t length); -struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *dev); -struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize); -struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor); - -/* polling and timeouts */ - -typedef void (*fpi_timeout_fn)(void *data); - -struct fpi_timeout; -struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback, - void *data); -void fpi_timeout_cancel(struct fpi_timeout *timeout); - -/* async drv <--> lib comms */ - -struct fpi_ssm; -typedef void (*ssm_completed_fn)(struct fpi_ssm *ssm); -typedef void (*ssm_handler_fn)(struct fpi_ssm *ssm); - -/* sequential state machine: state machine that iterates sequentially over - * a predefined series of states. can be aborted by either completion or - * abortion error conditions. */ - -/* for library and drivers */ -struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler, - int nr_states); -void fpi_ssm_free(struct fpi_ssm *machine); -void fpi_ssm_start(struct fpi_ssm *machine, ssm_completed_fn callback); -void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child); - -/* for drivers */ -void fpi_ssm_next_state(struct fpi_ssm *machine); -void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state); -void fpi_ssm_mark_completed(struct fpi_ssm *machine); -void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error); -struct fp_dev *fpi_ssm_get_dev(struct fpi_ssm *machine); -void fpi_ssm_set_user_data(struct fpi_ssm *machine, - void *user_data); -void *fpi_ssm_get_user_data(struct fpi_ssm *machine); -int fpi_ssm_get_error(struct fpi_ssm *machine); -int fpi_ssm_get_cur_state(struct fpi_ssm *machine); - -void fpi_drvcb_open_complete(struct fp_dev *dev, int status); -void fpi_drvcb_close_complete(struct fp_dev *dev); - -void fpi_drvcb_enroll_started(struct fp_dev *dev, int status); -void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result, - struct fp_print_data *data, struct fp_img *img); -void fpi_drvcb_enroll_stopped(struct fp_dev *dev); - -void fpi_drvcb_verify_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result, - struct fp_img *img); -void fpi_drvcb_verify_stopped(struct fp_dev *dev); - -void fpi_drvcb_identify_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result, - size_t match_offset, struct fp_img *img); -void fpi_drvcb_identify_stopped(struct fp_dev *dev); - -void fpi_drvcb_capture_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result, - struct fp_img *img); -void fpi_drvcb_capture_stopped(struct fp_dev *dev); - -/* for image drivers */ -void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status); -void fpi_imgdev_close_complete(struct fp_img_dev *imgdev); -void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status); -void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev); -void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, - gboolean present); -void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img); -void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result); -void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error); - -/* utils */ -int fpi_std_sq_dev(const unsigned char *buf, int size); -int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size); - #endif - diff --git a/libfprint/drv.c b/libfprint/drv.c deleted file mode 100644 index d5507453..00000000 --- a/libfprint/drv.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Functions to assist with asynchronous driver <---> library communications - * Copyright (C) 2007-2008 Daniel Drake - * - * 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 "drv" - -#include "fp_internal.h" - -#include -#include - -/* SSM: sequential state machine - * Asynchronous driver design encourages some kind of state machine behind it. - * In most cases, the state machine is entirely linear - you only go to the - * next state, you never jump or go backwards. The SSM functions help you - * implement such a machine. - * - * e.g. S1 --> S2 --> S3 --> S4 - * S1 is the start state - * There is also an implicit error state and an implicit accepting state - * (both with implicit edges from every state). - * - * You can also jump to any arbitrary state (while marking completion of the - * current state) while the machine is running. In other words there are - * implicit edges linking one state to every other state. OK, we're stretching - * the "state machine" description at this point. - * - * To create a ssm, you pass a state handler function and the total number of - * states (4 in the above example). - * - * To start a ssm, you pass in a completion callback function which gets - * called when the ssm completes (both on error and on failure). - * - * To iterate to the next state, call fpi_ssm_next_state(). It is legal to - * attempt to iterate beyond the final state - this is equivalent to marking - * the ssm as successfully completed. - * - * To mark successful completion of a SSM, either iterate beyond the final - * state or call fpi_ssm_mark_completed() from any state. - * - * To mark failed completion of a SSM, call fpi_ssm_mark_aborted() from any - * state. You must pass a non-zero error code. - * - * Your state handling function looks at ssm->cur_state in order to determine - * the current state and hence which operations to perform (a switch statement - * is appropriate). - * Typically, the state handling function fires off an asynchronous libusb - * transfer, and the callback function iterates the machine to the next state - * upon success (or aborts the machine on transfer failure). - * - * Your completion callback should examine ssm->error in order to determine - * whether the ssm completed or failed. An error code of zero indicates - * successful completion. - */ - -/* Allocate a new ssm */ -struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler, - int nr_states) -{ - struct fpi_ssm *machine; - BUG_ON(nr_states < 1); - - machine = g_malloc0(sizeof(*machine)); - machine->handler = handler; - machine->nr_states = nr_states; - machine->dev = dev; - machine->completed = TRUE; - return machine; -} - -struct fp_dev * -fpi_ssm_get_dev(struct fpi_ssm *machine) -{ - return machine->dev; -} - -void -fpi_ssm_set_user_data(struct fpi_ssm *machine, - void *user_data) -{ - machine->priv = user_data; -} - -void * -fpi_ssm_get_user_data(struct fpi_ssm *machine) -{ - return machine->priv; -} - -/* Free a ssm */ -void fpi_ssm_free(struct fpi_ssm *machine) -{ - if (!machine) - return; - g_free(machine); -} - -/* Invoke the state handler */ -static void __ssm_call_handler(struct fpi_ssm *machine) -{ - fp_dbg("%p entering state %d", machine, machine->cur_state); - machine->handler(machine); -} - -/* Start a ssm. You can also restart a completed or aborted ssm. */ -void fpi_ssm_start(struct fpi_ssm *ssm, ssm_completed_fn callback) -{ - BUG_ON(!ssm->completed); - ssm->callback = callback; - ssm->cur_state = 0; - ssm->completed = FALSE; - ssm->error = 0; - __ssm_call_handler(ssm); -} - -static void __subsm_complete(struct fpi_ssm *ssm) -{ - struct fpi_ssm *parent = ssm->parentsm; - BUG_ON(!parent); - if (ssm->error) - fpi_ssm_mark_aborted(parent, ssm->error); - else - fpi_ssm_next_state(parent); - fpi_ssm_free(ssm); -} - -/* start a SSM as a child of another. if the child completes successfully, the - * parent will be advanced to the next state. if the child aborts, the parent - * will be aborted with the same error code. the child will be automatically - * freed upon completion/abortion. */ -void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child) -{ - child->parentsm = parent; - fpi_ssm_start(child, __subsm_complete); -} - -/* Mark a ssm as completed successfully. */ -void fpi_ssm_mark_completed(struct fpi_ssm *machine) -{ - BUG_ON(machine->completed); - machine->completed = TRUE; - fp_dbg("%p completed with status %d", machine, machine->error); - if (machine->callback) - machine->callback(machine); -} - -/* Mark a ssm as aborted with error. */ -void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error) -{ - fp_dbg("error %d from state %d", error, machine->cur_state); - BUG_ON(error == 0); - machine->error = error; - fpi_ssm_mark_completed(machine); -} - -/* Iterate to next state of a ssm */ -void fpi_ssm_next_state(struct fpi_ssm *machine) -{ - BUG_ON(machine->completed); - machine->cur_state++; - if (machine->cur_state == machine->nr_states) { - fpi_ssm_mark_completed(machine); - } else { - __ssm_call_handler(machine); - } -} - -void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state) -{ - BUG_ON(machine->completed); - BUG_ON(state >= machine->nr_states); - machine->cur_state = state; - __ssm_call_handler(machine); -} - -int fpi_ssm_get_cur_state(struct fpi_ssm *machine) -{ - return machine->cur_state; -} - -int fpi_ssm_get_error(struct fpi_ssm *machine) -{ - return machine->error; -} diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index e7501824..5c89e184 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -22,37 +22,39 @@ #include -#ifdef FP_COMPONENT -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "libfprint-"FP_COMPONENT -#endif - #include #include #include #include +#include "nbis-helpers.h" #include "fprint.h" +#include "fpi-dev.h" +#include "fpi-core.h" +#include "fpi-log.h" +#include "fpi-dev-img.h" +#include "fpi-data.h" +#include "fpi-img.h" #include "drivers/driver_ids.h" -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) +/* Global variables */ +extern libusb_context *fpi_usb_ctx; +extern GSList *opened_devices; -#define fp_dbg g_debug -#define fp_info g_debug -#define fp_warn g_warning -#define fp_err g_warning +/* fp_print_data structure definition */ +enum fp_print_data_type { + PRINT_DATA_RAW = 0, /* memset-imposed default */ + PRINT_DATA_NBIS_MINUTIAE +}; -#define BUG_ON(condition) G_STMT_START \ - if (condition) { \ - char *s; \ - s = g_strconcat ("BUG: (", #condition, ")", NULL); \ - g_warning ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \ - g_free (s); \ - } G_STMT_END -#define BUG() BUG_ON(1) +struct fp_print_data { + uint16_t driver_id; + uint32_t devtype; + enum fp_print_data_type type; + GSList *prints; +}; +/* fp_dev structure definition */ enum fp_dev_state { DEV_STATE_INITIAL = 0, DEV_STATE_ERROR, @@ -77,16 +79,20 @@ enum fp_dev_state { DEV_STATE_CAPTURE_STOPPING, }; -struct fp_driver **fprint_get_drivers (void); - struct fp_dev { struct fp_driver *drv; - libusb_device_handle *udev; uint32_t devtype; - void *priv; + + /* only valid if drv->type == DRIVER_IMAGING */ + struct fp_img_dev *img_dev; + /* Link to the instance specific struct */ + void *instance_data; int nr_enroll_stages; + /* FIXME: This will eventually have a bus type */ + libusb_device_handle *udev; + /* read-only to drivers */ struct fp_print_data *verify_data; @@ -122,39 +128,10 @@ struct fp_dev { struct fp_print_data **identify_gallery; }; -enum fp_imgdev_state { - IMGDEV_STATE_INACTIVE, - IMGDEV_STATE_AWAIT_FINGER_ON, - IMGDEV_STATE_CAPTURE, - IMGDEV_STATE_AWAIT_FINGER_OFF, -}; - -enum fp_imgdev_action { - IMG_ACTION_NONE = 0, - IMG_ACTION_ENROLL, - IMG_ACTION_VERIFY, - IMG_ACTION_IDENTIFY, - IMG_ACTION_CAPTURE, -}; - -enum fp_imgdev_enroll_state { - IMG_ACQUIRE_STATE_NONE = 0, - IMG_ACQUIRE_STATE_ACTIVATING, - IMG_ACQUIRE_STATE_AWAIT_FINGER_ON, - IMG_ACQUIRE_STATE_AWAIT_IMAGE, - IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF, - IMG_ACQUIRE_STATE_DONE, - IMG_ACQUIRE_STATE_DEACTIVATING, -}; - -enum fp_imgdev_verify_state { - IMG_VERIFY_STATE_NONE = 0, - IMG_VERIFY_STATE_ACTIVATING -}; - +/* fp_img_dev structure definition */ struct fp_img_dev { - struct fp_dev *dev; - libusb_device_handle *udev; + struct fp_dev *parent; + enum fp_imgdev_action action; int action_state; @@ -166,78 +143,18 @@ struct fp_img_dev { /* FIXME: better place to put this? */ size_t identify_match_offset; - - void *priv; }; -int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev); -int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev); - -struct usb_id { - uint16_t vendor; - uint16_t product; - unsigned long driver_data; -}; - -enum fp_driver_type { - DRIVER_PRIMITIVE = 0, - DRIVER_IMAGING = 1, -}; - -struct fp_driver { - const uint16_t id; - const char *name; - const char *full_name; - const struct usb_id * const id_table; - enum fp_driver_type type; - enum fp_scan_type scan_type; - - void *priv; - - /* Device operations */ - int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); - int (*open)(struct fp_dev *dev, unsigned long driver_data); - void (*close)(struct fp_dev *dev); - int (*enroll_start)(struct fp_dev *dev); - int (*enroll_stop)(struct fp_dev *dev); - int (*verify_start)(struct fp_dev *dev); - int (*verify_stop)(struct fp_dev *dev, gboolean iterating); - int (*identify_start)(struct fp_dev *dev); - int (*identify_stop)(struct fp_dev *dev, gboolean iterating); - int (*capture_start)(struct fp_dev *dev); - int (*capture_stop)(struct fp_dev *dev); -}; - -enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv); - -/* flags for fp_img_driver.flags */ -#define FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE (1 << 0) - -struct fp_img_driver { - struct fp_driver driver; - uint16_t flags; - int img_width; - int img_height; - int bz3_threshold; - - /* Device operations */ - int (*open)(struct fp_img_dev *dev, unsigned long driver_data); - void (*close)(struct fp_img_dev *dev); - int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state); - int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state); - void (*deactivate)(struct fp_img_dev *dev); -}; - -#include "drivers_definitions.h" - -extern libusb_context *fpi_usb_ctx; -extern GSList *opened_devices; - -void fpi_img_driver_setup(struct fp_img_driver *idriver); +/* fp_driver structure definition */ +/* fp_img_driver structure definition */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) #define fpi_driver_to_img_driver(drv) \ container_of((drv), struct fp_img_driver, driver) +/* fp_dscv_dev structure definition */ struct fp_dscv_dev { struct libusb_device *udev; struct fp_driver *drv; @@ -245,6 +162,7 @@ struct fp_dscv_dev { uint32_t devtype; }; +/* fp_dscv_print structure definition */ struct fp_dscv_print { uint16_t driver_id; uint32_t devtype; @@ -252,43 +170,7 @@ struct fp_dscv_print { char *path; }; -enum fp_print_data_type { - PRINT_DATA_RAW = 0, /* memset-imposed default */ - PRINT_DATA_NBIS_MINUTIAE, -}; - -struct fp_print_data_item { - size_t length; - unsigned char data[0]; -}; - -struct fp_print_data { - uint16_t driver_id; - uint32_t devtype; - enum fp_print_data_type type; - GSList *prints; -}; - -struct fpi_print_data_fp2 { - char prefix[3]; - uint16_t driver_id; - uint32_t devtype; - unsigned char data_type; - unsigned char data[0]; -} __attribute__((__packed__)); - -struct fpi_print_data_item_fp2 { - uint32_t length; - unsigned char data[0]; -} __attribute__((__packed__)); - -void fpi_data_exit(void); -struct fp_print_data *fpi_print_data_new(struct fp_dev *dev); -struct fp_print_data_item *fpi_print_data_item_new(size_t length); -gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, - enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, - enum fp_print_data_type type2); - +/* fp_minutia structure definition */ struct fp_minutia { int x; int y; @@ -304,34 +186,32 @@ struct fp_minutia { int num_nbrs; }; +/* fp_minutiae structure definition */ struct fp_minutiae { int alloc; int num; struct fp_minutia **list; }; -/* bit values for fp_img.flags */ -#define FP_IMG_V_FLIPPED (1<<0) -#define FP_IMG_H_FLIPPED (1<<1) -#define FP_IMG_COLORS_INVERTED (1<<2) -#define FP_IMG_BINARIZED_FORM (1<<3) -#define FP_IMG_PARTIAL (1<<4) +/* Defined in fpi-dev-img.c */ +void fpi_img_driver_setup(struct fp_img_driver *idriver); +int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev); +int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev); -#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \ - | FP_IMG_COLORS_INVERTED) +/* Exported for use in command-line tools + * Defined in fpi-core.c */ +struct fp_driver **fprint_get_drivers (void); -struct fp_img { - int width; - int height; - size_t length; - uint16_t flags; - struct fp_minutiae *minutiae; - unsigned char *binarized; - unsigned char data[0]; -}; +/* Defined in fpi-core.c */ +enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv); -struct fp_img *fpi_img_new(size_t length); -struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize); +/* Defined in fpi-data.c */ +void fpi_data_exit(void); +gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, + enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, + enum fp_print_data_type type2); + +/* Defined in fpi-img.c */ gboolean fpi_img_is_sane(struct fp_img *img); int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img, struct fp_print_data **ret); @@ -339,71 +219,23 @@ int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, struct fp_print_data *new_print); int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print, struct fp_print_data **gallery, int match_threshold, size_t *match_offset); -struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor); - -/* polling and timeouts */ +/* Defined in fpi-poll.c */ +void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev); void fpi_poll_init(void); void fpi_poll_exit(void); -typedef void (*fpi_timeout_fn)(void *data); - -/* async drv <--> lib comms */ - -struct fpi_ssm; -typedef void (*ssm_completed_fn)(struct fpi_ssm *ssm); -typedef void (*ssm_handler_fn)(struct fpi_ssm *ssm); - -/* sequential state machine: state machine that iterates sequentially over - * a predefined series of states. can be aborted by either completion or - * abortion error conditions. */ -struct fpi_ssm { - struct fp_dev *dev; - struct fpi_ssm *parentsm; - void *priv; - int nr_states; - int cur_state; - gboolean completed; - int error; - ssm_completed_fn callback; - ssm_handler_fn handler; -}; - - -/* for library and drivers */ -struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler, - int nr_states); -void fpi_ssm_free(struct fpi_ssm *machine); -void fpi_ssm_start(struct fpi_ssm *machine, ssm_completed_fn callback); - -/* for drivers */ -void fpi_ssm_next_state(struct fpi_ssm *machine); -void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state); -void fpi_ssm_mark_completed(struct fpi_ssm *machine); -void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error); - -void fpi_drvcb_open_complete(struct fp_dev *dev, int status); -void fpi_drvcb_close_complete(struct fp_dev *dev); - -void fpi_drvcb_enroll_started(struct fp_dev *dev, int status); -void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result, - struct fp_print_data *data, struct fp_img *img); -void fpi_drvcb_enroll_stopped(struct fp_dev *dev); - -void fpi_drvcb_verify_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result, +/* Defined in fpi-async.c */ +void fpi_drvcb_capture_started(struct fp_dev *dev, int status); +void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result, struct fp_img *img); -void fpi_drvcb_verify_stopped(struct fp_dev *dev); +void fpi_drvcb_capture_stopped(struct fp_dev *dev); void fpi_drvcb_identify_started(struct fp_dev *dev, int status); void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result, size_t match_offset, struct fp_img *img); void fpi_drvcb_identify_stopped(struct fp_dev *dev); -void fpi_drvcb_capture_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result, - struct fp_img *img); -void fpi_drvcb_capture_stopped(struct fp_dev *dev); +#include "drivers_definitions.h" #endif - diff --git a/libfprint/assembling.c b/libfprint/fpi-assembling.c similarity index 78% rename from libfprint/assembling.c rename to libfprint/fpi-assembling.c index de8cb342..e33dafe5 100644 --- a/libfprint/assembling.c +++ b/libfprint/fpi-assembling.c @@ -29,7 +29,18 @@ #include #include -#include "assembling.h" +#include "fpi-assembling.h" + +/** + * SECTION:fpi-assembling + * @title: Image frame assembly + * @short_description: Image frame assembly helpers + * + * Those are the helpers to manipulate capture data from fingerprint readers + * into a uniform image that can be further processed. This is usually used + * by drivers for devices which have a small sensor and thus need to capture + * data in small stripes. + */ static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *first_frame, @@ -152,6 +163,22 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, return total_error / num_stripes; } +/** + * fpi_do_movement_estimation: + * @ctx: #fpi_frame_asmbl_ctx - frame assembling context + * @stripes: a singly-linked list of #fpi_frame + * @num_stripes: number of items in @stripes to process + * + * fpi_do_movement_estimation() estimates the movement between adjacent + * frames, populating @delta_x and @delta_y values for each #fpi_frame. + * + * This function is used for devices that don't do movement estimation + * in hardware. If hardware movement estimation is supported, the driver + * should populate @delta_x and @delta_y instead. + * + * Note that @num_stripes might be shorter than the length of the list, + * if some stripes should be skipped. + */ void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, GSList *stripes, size_t num_stripes) { @@ -225,8 +252,22 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx, } } +/** + * fpi_assemble_frames: + * @ctx: #fpi_frame_asmbl_ctx - frame assembling context + * @stripes: linked list of #fpi_frame + * @num_stripes: number of items in @stripes to process + * + * fpi_assemble_frames() assembles individual frames into a single image. + * It expects @delta_x and @delta_y of #fpi_frame to be populated. + * + * Note that @num_stripes might be shorter than the length of the list, + * if some stripes should be skipped. + * + * Returns: a newly allocated #fp_img. + */ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t stripes_len) + GSList *stripes, size_t num_stripes) { GSList *stripe; struct fp_img *img; @@ -235,7 +276,8 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, gboolean reverse = FALSE; struct fpi_frame *fpi_frame; - BUG_ON(stripes_len == 0); + //FIXME g_return_if_fail + BUG_ON(num_stripes == 0); BUG_ON(ctx->image_width < ctx->frame_width); /* Calculate height */ @@ -252,7 +294,7 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, height += fpi_frame->delta_y; i++; stripe = g_slist_next(stripe); - } while (i < stripes_len); + } while (i < num_stripes); fp_dbg("height is %d", height); @@ -294,7 +336,7 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, stripe = g_slist_next(stripe); i++; - } while (i < stripes_len); + } while (i < num_stripes); return img; } @@ -350,34 +392,45 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx, } } -static int min(int a, int b) {return (a < b) ? a : b; } - -/* Rescale image to account for variable swiping speed */ +/** + * fpi_assemble_lines: + * @ctx: #fpi_frame_asmbl_ctx - frame assembling context + * @lines: linked list of lines + * @num_lines: number of items in @lines to process + * + * #fpi_assemble_lines assembles individual lines into a single image. + * It also rescales image to account variable swiping speed. + * + * Note that @num_lines might be shorter than the length of the list, + * if some lines should be skipped. + * + * Returns: a newly allocated #fp_img. + */ struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, - GSList *lines, size_t lines_len) + GSList *lines, size_t num_lines) { /* Number of output lines per distance between two scanners */ int i; GSList *row1, *row2; float y = 0.0; int line_ind = 0; - int *offsets = (int *)g_malloc0((lines_len / 2) * sizeof(int)); + int *offsets = (int *)g_malloc0((num_lines / 2) * sizeof(int)); unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height); struct fp_img *img; g_return_val_if_fail (lines != NULL, NULL); - g_return_val_if_fail (lines_len > 0, NULL); + g_return_val_if_fail (num_lines >= 2, NULL); fp_dbg("%"G_GINT64_FORMAT, g_get_real_time()); row1 = lines; - for (i = 0; (i < lines_len - 1) && row1; i += 2) { + for (i = 0; (i < num_lines - 1) && row1; i += 2) { int bestmatch = i; int bestdiff = 0; int j, firstrow, lastrow; firstrow = i + 1; - lastrow = min(i + ctx->max_search_offset, lines_len - 1); + lastrow = MIN(i + ctx->max_search_offset, num_lines - 1); row2 = g_slist_next(row1); for (j = firstrow; j <= lastrow; j++) { @@ -397,13 +450,13 @@ struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, row1 = g_slist_next(row1); } - median_filter(offsets, (lines_len / 2) - 1, ctx->median_filter_size); + median_filter(offsets, (num_lines / 2) - 1, ctx->median_filter_size); fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time()); - for (i = 0; i <= (lines_len / 2) - 1; i++) + for (i = 0; i <= (num_lines / 2) - 1; i++) fp_dbg("%d", offsets[i]); row1 = lines; - for (i = 0; i < lines_len - 1; i++, row1 = g_slist_next(row1)) { + for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next(row1)) { int offset = offsets[i/2]; if (offset > 0) { float ynext = y + (float)ctx->resolution / offset; diff --git a/libfprint/fpi-assembling.h b/libfprint/fpi-assembling.h new file mode 100644 index 00000000..d2a66515 --- /dev/null +++ b/libfprint/fpi-assembling.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2015 Vasily Khoruzhick + * + * 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 + */ + +#ifndef __FPI_ASSEMBLING_H__ +#define __FPI_ASSEMBLING_H__ + +#include + +/** + * fpi_frame: + * @delta_x: X offset of the frame + * @delta_y: Y offset of the frame + * @data: bitmap + * + * #fpi_frame is used to store frames for swipe sensors. Drivers should + * populate delta_x and delta_y if the device supports hardware movement + * estimation. + */ +struct fpi_frame { + int delta_x; + int delta_y; + unsigned char data[0]; +}; + +/** + * fpi_frame_asmbl_ctx: + * @frame_width: width of the frame + * @frame_height: height of the frame + * @image_width: resulting image width + * @get_pixel: pixel accessor, returns pixel brightness at x,y of frame + * + * #fpi_frame_asmbl_ctx is a structure holding the context for frame + * assembling routines. + * + * Drivers should define their own #fpi_frame_asmbl_ctx depending on + * hardware parameters of scanner. @image_width is usually 25% wider than + * @frame_width to take horizontal movement into account. + */ +struct fpi_frame_asmbl_ctx { + unsigned int frame_width; + unsigned int frame_height; + unsigned int image_width; + unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, + unsigned int x, + unsigned int y); +}; + +void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, size_t num_stripes); + +struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, size_t num_stripes); + +/** + * fpi_line_asmbl_ctx: + * @line_width: width of line + * @max_height: maximal height of assembled image + * @resolution: scale factor used for line assembling routines. + * @median_filter_size: size of median filter for movement estimation + * @max_search_offset: the number of lines to search for the next line + * @get_deviation: pointer to a function that returns the numerical difference + * between two lines + * @get_pixel: pixel accessor, returns pixel brightness at x of line + * + * #fpi_line_asmbl_ctx is a structure holding the context for line assembling + * routines. + * + * Drivers should define their own #fpi_line_asmbl_ctx depending on + * the hardware parameters of the scanner. Swipe scanners of this type usually + * return two lines, the second line is often narrower than first and is used + * for movement estimation. + * + * The @max_search_offset value indicates how many lines forward the assembling + * routines should look while searching for next line. This value depends on + * how fast the hardware sends frames. + * + * The function pointed to by @get_deviation should return the numerical difference + * between two lines. Higher values means lines are more different. If the reader + * returns two lines at a time, this function should be used to estimate the + * difference between pairs of lines. + */ +struct fpi_line_asmbl_ctx { + unsigned int line_width; + unsigned int max_height; + unsigned int resolution; + unsigned int median_filter_size; + unsigned int max_search_offset; + int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx, + GSList *line1, GSList *line2); + unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx, + GSList *line, + unsigned int x); +}; + +struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, + GSList *lines, size_t num_lines); + +#endif diff --git a/libfprint/async.c b/libfprint/fpi-async.c similarity index 75% rename from libfprint/async.c rename to libfprint/fpi-async.c index 7051ee70..ddf5230b 100644 --- a/libfprint/async.c +++ b/libfprint/fpi-async.c @@ -20,11 +20,21 @@ #define FP_COMPONENT "async" #include "fp_internal.h" +#include "fpi-async.h" #include #include #include +/* + * SECTION:fpi-async + * @title: Asynchronous operations reporting + * @short_description: Asynchronous operations reporting functions + * + * Those functions are used by primitive drivers to report back their + * current status. Most drivers, imaging ones, do not need to use them. + */ + /* Drivers call this when device initialisation has completed */ void fpi_drvcb_open_complete(struct fp_dev *dev, int status) { @@ -38,11 +48,18 @@ void fpi_drvcb_open_complete(struct fp_dev *dev, int status) /** * fp_async_dev_open: - * @ddev: - * @callback: - * @user_data + * @ddev: the struct #fp_dscv_dev discovered device to open + * @callback: the callback to call when the device has been opened + * @user_data: user data to pass to the callback * - * Returns: + * Opens and initialises a device. This is the function you call in order + * to convert a #fp_dscv_dev discovered device into an actual device handle + * that you can perform operations with. + * + * The error status of the opening will be provided as an argument to the + * #fp_dev_open_cb callback. + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback, void *user_data) @@ -53,6 +70,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call int r; g_return_val_if_fail(ddev != NULL, -ENODEV); + g_return_val_if_fail (callback != NULL, -EINVAL); drv = ddev->drv; @@ -93,6 +111,7 @@ void fpi_drvcb_close_complete(struct fp_dev *dev) G_DEBUG_HERE(); BUG_ON(dev->state != DEV_STATE_DEINITIALIZING); dev->state = DEV_STATE_DEINITIALIZED; + fpi_timeout_cancel_all_for_dev(dev); libusb_close(dev->udev); if (dev->close_cb) dev->close_cb(dev, dev->close_cb_data); @@ -101,9 +120,12 @@ void fpi_drvcb_close_complete(struct fp_dev *dev) /** * fp_async_dev_close: - * @dev: - * @callback: - * @user_data + * @dev: the struct #fp_dev device + * @callback: the callback to call when the device has been closed + * @user_data: user data to pass to the callback + * + * Closes a device. You must call this function when you have finished using + * a fingerprint device. */ API_EXPORTED void fp_async_dev_close(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data) @@ -147,11 +169,15 @@ void fpi_drvcb_enroll_started(struct fp_dev *dev, int status) /** * fp_async_enroll_start: - * @dev: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @callback: the callback to call for each stage of the enrollment + * @user_data: user data to pass to the callback * - * Returns: + * Starts an enrollment and calls @callback for each enrollment stage. + * See [Enrolling](libfprint-Devices-operations.html#enrolling) + * for an explanation of enroll stages. + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback, void *user_data) @@ -160,6 +186,7 @@ API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev, int r; g_return_val_if_fail(dev != NULL, -ENODEV); + g_return_val_if_fail (callback != NULL, -EINVAL); drv = dev->drv; @@ -213,11 +240,13 @@ void fpi_drvcb_enroll_stopped(struct fp_dev *dev) /** * fp_async_enroll_stop: - * @dev: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @callback: the callback to call when the enrollment has been cancelled + * @user_data: user data to pass to the callback * - * Returns: + * Stops an ongoing enrollment started with fp_async_enroll_start(). + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data) @@ -254,12 +283,17 @@ API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev, /** * fp_async_verify_start: - * @dev: - * @data: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @data: the print to verify against. Must have been previously + * enrolled with a device compatible to the device selected to perform the scan + * @callback: the callback to call when the verification has finished + * @user_data: user data to pass to the callback * - * Returns: + * Starts a verification and calls @callback when the verification has + * finished. See fp_verify_finger_img() for the synchronous API. When the + * @callback has been called, you must call fp_async_verify_stop(). + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data, fp_img_operation_cb callback, void *user_data) @@ -268,6 +302,7 @@ API_EXPORTED int fp_async_verify_start(struct fp_dev *dev, int r; g_return_val_if_fail(dev != NULL, -ENODEV); + g_return_val_if_fail (callback != NULL, -EINVAL); drv = dev->drv; @@ -335,11 +370,13 @@ void fpi_drvcb_verify_stopped(struct fp_dev *dev) /** * fp_async_verify_stop: - * @dev: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @callback: the callback to call to finish a verification + * @user_data: user data to pass to the callback * - * Returns: + * Finishes an ongoing verification started with fp_async_verify_start(). + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data) @@ -380,12 +417,17 @@ API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev, /** * fp_async_identify_start: - * @dev: - * @gallery: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @gallery: NULL-terminated array of pointers to the prints to + * identify against. Each one must have been previously enrolled with a device + * compatible to the device selected to perform the scan + * @callback: the callback to call when the identification has finished + * @user_data: user data to pass to the callback * - * Returns: + * Performs a new scan and verifies it against a previously enrolled print. + * See also: fp_verify_finger_img() + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery, fp_identify_cb callback, void *user_data) @@ -394,6 +436,7 @@ API_EXPORTED int fp_async_identify_start(struct fp_dev *dev, int r; g_return_val_if_fail(dev != NULL, -ENODEV); + g_return_val_if_fail (callback != NULL, -EINVAL); drv = dev->drv; @@ -451,11 +494,13 @@ void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result, /** * fp_async_identify_stop: - * @dev: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @callback: the callback to call when the identification has stopped + * @user_data: user data to pass to the callback * - * Returns: + * Stops an ongoing identification started with fp_async_identify_start(). + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data) @@ -506,12 +551,17 @@ void fpi_drvcb_identify_stopped(struct fp_dev *dev) /** * fp_async_capture_start: - * @dev: - * @unconditional: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected + * @callback: the callback to call when the capture has finished + * @user_data: user data to pass to the callback * - * Returns: + * Start the capture of an #fp_img from a device. When the @callback has been called, + * you must call fp_async_capture_stop(). + * + * Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the + * @unconditional flag was set but the device does not support this, or that the• + * device does not support imaging */ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operation_cb callback, void *user_data) @@ -520,6 +570,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional, int r; g_return_val_if_fail(dev != NULL, -ENODEV); + g_return_val_if_fail (callback != NULL, -EINVAL); drv = dev->drv; @@ -536,7 +587,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional, if (r < 0) { dev->capture_cb = NULL; dev->state = DEV_STATE_ERROR; - fp_err("failed to start verification, error %d", r); + fp_err("failed to start capture, error %d", r); } return r; } @@ -586,11 +637,13 @@ void fpi_drvcb_capture_stopped(struct fp_dev *dev) /** * fp_async_capture_stop: - * @dev: - * @callback: - * @user_data: + * @dev: the struct #fp_dev device + * @callback: the callback to call when the capture has been stopped + * @user_data: user data to pass to the callback * - * Returns: + * Stops an ongoing verification started with fp_async_capture_start(). + * + * Returns: 0 on success, non-zero on error */ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data) @@ -622,7 +675,7 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev, r = drv->capture_stop(dev); if (r < 0) { - fp_err("failed to stop verification"); + fp_err("failed to stop capture"); dev->capture_stop_cb = NULL; } return r; diff --git a/libfprint/fpi-async.h b/libfprint/fpi-async.h new file mode 100644 index 00000000..cf6fa32e --- /dev/null +++ b/libfprint/fpi-async.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_ASYNC_H__ +#define __FPI_ASYNC_H__ + +#include "fpi-dev.h" +#include "fpi-data.h" + +void fpi_drvcb_open_complete(struct fp_dev *dev, int status); +void fpi_drvcb_close_complete(struct fp_dev *dev); + +void fpi_drvcb_enroll_started(struct fp_dev *dev, int status); +void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result, + struct fp_print_data *data, struct fp_img *img); +void fpi_drvcb_enroll_stopped(struct fp_dev *dev); + +void fpi_drvcb_verify_started(struct fp_dev *dev, int status); +void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result, + struct fp_img *img); +void fpi_drvcb_verify_stopped(struct fp_dev *dev); + +#endif diff --git a/libfprint/core.c b/libfprint/fpi-core.c similarity index 90% rename from libfprint/core.c rename to libfprint/fpi-core.c index 2c42ad51..2b5d3c6f 100644 --- a/libfprint/core.c +++ b/libfprint/fpi-core.c @@ -33,6 +33,7 @@ GSList *opened_devices = NULL; /** * SECTION:discovery * @title: Device discovery + * @short_description: Device discovery functions * * These functions allow you to scan the system for supported fingerprint * scanning hardware. This is your starting point when integrating libfprint @@ -47,6 +48,7 @@ GSList *opened_devices = NULL; /** * SECTION:drv * @title: Driver operations + * @short_description: Driver operation functions * * Internally, libfprint is abstracted into various drivers to communicate * with the different types of supported fingerprint readers. libfprint works @@ -61,6 +63,7 @@ GSList *opened_devices = NULL; /** * SECTION:dev * @title: Devices operations + * @short_description: Device operation functions * * In order to interact with fingerprint scanners, your software will * interface primarily with libfprint's representation of devices, detailed @@ -111,6 +114,27 @@ GSList *opened_devices = NULL; * verification) on some devices which do not provide images. */ +/** + * SECTION:fpi-core + * @title: Driver structures + * @short_description: Driver structures + * + * Driver structures need to be defined inside each driver in + * order for the core library to know what function to call, and the capabilities + * of the driver and the devices it supports. + */ + +/** + * SECTION:fpi-core-img + * @title: Image driver structures + * @short_description: Image driver structures + * + * Image driver structures need to be defined inside each image driver in + * order for the core library to know what function to call, and the capabilities + * of the driver and the devices it supports. Its structure is based off the + * #fp_driver struct. + */ + static GSList *registered_drivers = NULL; static void register_driver(struct fp_driver *drv) @@ -248,7 +272,7 @@ static struct fp_dscv_dev *discover_dev(libusb_device *udev) * Scans the system and returns a list of discovered devices. This is your * entry point into finding a fingerprint reader to operate. * - * Returns: a %NULL-terminated list of discovered devices. Must be freed with + * Returns: a nul-terminated list of discovered devices. Must be freed with * fp_dscv_devs_free() after use. */ API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void) @@ -259,8 +283,7 @@ API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void) int r; int i = 0; - if (registered_drivers == NULL) - return NULL; + g_return_val_if_fail (registered_drivers != NULL, NULL); r = libusb_get_device_list(fpi_usb_ctx, &devs); if (r < 0) { @@ -328,7 +351,10 @@ API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev) * fp_dscv_dev_get_driver_id: * @dev: a discovered fingerprint device * - * Returns: the ID for the underlying driver for that device + * Returns a unique driver identifier for the underlying driver + * for that device. + * + * Returns: the ID for #dev */ API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev) { @@ -454,7 +480,7 @@ API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev * /** * fp_dev_get_driver: - * @dev: the device + * @dev: the struct #fp_dev device * * Get the #fp_driver for a fingerprint device. * @@ -467,7 +493,7 @@ API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev) /** * fp_dev_get_nr_enroll_stages: - * @dev: the device + * @dev: the struct #fp_dev device * * Gets the number of [enroll stages](intro.html#enrollment) required to enroll a * fingerprint with the device. @@ -481,7 +507,7 @@ API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev) /** * fp_dev_get_devtype: - * @dev: the device + * @dev: the struct #fp_dev device * * Gets the [devtype](advanced-topics.html#device-types) for a device. * @@ -494,7 +520,7 @@ API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev) /** * fp_dev_supports_print_data: - * @dev: the device + * @dev: the struct #fp_dev device * @data: the stored print * * Determines if a stored print is compatible with a certain device. @@ -511,7 +537,7 @@ API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev, /** * fp_dev_supports_dscv_print: - * @dev: the device + * @dev: the struct #fp_dev device * @print: the discovered print * * Determines if a #fp_dscv_print discovered print appears to be compatible @@ -528,50 +554,6 @@ API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev, 0, print->driver_id, print->devtype, 0); } -libusb_device_handle * -fpi_dev_get_usb_dev(struct fp_dev *dev) -{ - return dev->udev; -} - -void * -fpi_dev_get_user_data (struct fp_dev *dev) -{ - return dev->priv; -} - -void -fpi_dev_set_user_data (struct fp_dev *dev, - void *user_data) -{ - dev->priv = user_data; -} - -int -fpi_dev_get_nr_enroll_stages(struct fp_dev *dev) -{ - return dev->nr_enroll_stages; -} - -void -fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, - int nr_enroll_stages) -{ - dev->nr_enroll_stages = nr_enroll_stages; -} - -struct fp_print_data * -fpi_dev_get_verify_data(struct fp_dev *dev) -{ - return dev->verify_data; -} - -enum fp_dev_state -fpi_dev_get_dev_state(struct fp_dev *dev) -{ - return dev->state; -} - /** * fp_driver_get_name: * @drv: the driver @@ -624,16 +606,27 @@ API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv) return drv->scan_type; } -static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev) +/** + * fp_driver_supports_imaging: + * @drv: the driver + * + * Determines if a driver has imaging capabilities. If a driver has imaging + * capabilities you are able to perform imaging operations such as retrieving + * scan images using fp_dev_img_capture(). However, not all drivers support + * imaging devices – some do all processing in hardware. This function will + * indicate which class a device in question falls into. + * + * Returns: 1 if the device is an imaging device, 0 if the device does not + * provide images to the host computer + */ +API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv) { - if (dev->drv->type != DRIVER_IMAGING) - return NULL; - return dev->priv; + return drv->capture_start != NULL; } /** * fp_dev_supports_imaging: - * @dev: the fingerprint device + * @dev: the struct #fp_dev device * * Determines if a device has imaging capabilities. If a device has imaging * capabilities you are able to perform imaging operations such as retrieving @@ -651,7 +644,7 @@ API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev) /** * fp_dev_supports_identification: - * @dev: the fingerprint device + * @dev: the struct #fp_dev device * * Determines if a device is capable of [identification](intro.html#identification) * through fp_identify_finger() and similar. Not all devices support this @@ -666,7 +659,7 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev) /** * fp_dev_get_img_width: - * @dev: the fingerprint device + * @dev: the struct #fp_dev device * * Gets the expected width of images that will be captured from the device. * This function will return -1 for devices that are not @@ -678,18 +671,17 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev) */ API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev) { - struct fp_img_dev *imgdev = dev_to_img_dev(dev); - if (!imgdev) { + if (!dev->img_dev) { fp_dbg("get image width for non-imaging device"); return -1; } - return fpi_imgdev_get_img_width(imgdev); + return fpi_imgdev_get_img_width(dev->img_dev); } /** * fp_dev_get_img_height: - * @dev: the fingerprint device + * @dev: the struct #fp_dev device * * Gets the expected height of images that will be captured from the device. * This function will return -1 for devices that are not @@ -701,13 +693,12 @@ API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev) */ API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev) { - struct fp_img_dev *imgdev = dev_to_img_dev(dev); - if (!imgdev) { + if (!dev->img_dev) { fp_dbg("get image height for non-imaging device"); return -1; } - return fpi_imgdev_get_img_height(imgdev); + return fpi_imgdev_get_img_height(dev->img_dev); } /** diff --git a/libfprint/fpi-core.h b/libfprint/fpi-core.h new file mode 100644 index 00000000..a5a0a44d --- /dev/null +++ b/libfprint/fpi-core.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_CORE_H__ +#define __FPI_CORE_H__ + +#include +#include "fpi-dev-img.h" + +/** + * usb_id: + * @vendor: the USB vendor ID + * @product: the USB product ID + * @driver_data: data to differentiate devices of different + * vendor and product IDs. + * + * The struct #usb_id is used to declare devices supported by a + * particular driver. The @driver_data information is used to + * differentiate different models of devices which only need + * small changes compared to the default driver behaviour to function. + * + * For example, a device might have a different initialisation from + * the stock device, so the driver could do: + * + * |[ + * if (driver_data == MY_DIFFERENT_DEVICE_QUIRK) { + * ... + * } else { + * ... + * } + * ]| + * + * The default value is zero, so the @driver_data needs to be a + * non-zero to be useful. + */ +struct usb_id { + uint16_t vendor; + uint16_t product; + unsigned long driver_data; +}; + +/** + * fp_driver_type: + * @DRIVER_PRIMITIVE: primitive, non-imaging, driver + * @DRIVER_IMAGING: imaging driver + * + * The type of device the driver supports. + */ +enum fp_driver_type { + DRIVER_PRIMITIVE = 0, + DRIVER_IMAGING = 1, +}; + +struct fp_driver { + const uint16_t id; + const char *name; + const char *full_name; + const struct usb_id * const id_table; + enum fp_driver_type type; + enum fp_scan_type scan_type; + + /* Device operations */ + int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); + int (*open)(struct fp_dev *dev, unsigned long driver_data); + void (*close)(struct fp_dev *dev); + int (*enroll_start)(struct fp_dev *dev); + int (*enroll_stop)(struct fp_dev *dev); + int (*verify_start)(struct fp_dev *dev); + int (*verify_stop)(struct fp_dev *dev, gboolean iterating); + int (*identify_start)(struct fp_dev *dev); + int (*identify_stop)(struct fp_dev *dev, gboolean iterating); + int (*capture_start)(struct fp_dev *dev); + int (*capture_stop)(struct fp_dev *dev); +}; + +/** + * FpiImgDriverFlags: + * @FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE: Whether the driver supports + * unconditional image capture. No driver currently does. + * + * Flags used in the #fp_img_driver to advertise the capabilities of drivers. + */ +typedef enum { + FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE = 1 << 0 +} FpiImgDriverFlags; + +struct fp_img_driver { + struct fp_driver driver; + FpiImgDriverFlags flags; + int img_width; + int img_height; + int bz3_threshold; + + /* Device operations */ + int (*open)(struct fp_img_dev *dev, unsigned long driver_data); + void (*close)(struct fp_img_dev *dev); + int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state); + int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state); + void (*deactivate)(struct fp_img_dev *dev); +}; + +#endif diff --git a/libfprint/data.c b/libfprint/fpi-data.c similarity index 94% rename from libfprint/data.c rename to libfprint/fpi-data.c index 62a5fea5..0ac0f987 100644 --- a/libfprint/data.c +++ b/libfprint/fpi-data.c @@ -32,9 +32,23 @@ #define DIR_PERMS 0700 +struct fpi_print_data_fp2 { + char prefix[3]; + uint16_t driver_id; + uint32_t devtype; + unsigned char data_type; + unsigned char data[0]; +} __attribute__((__packed__)); + +struct fpi_print_data_item_fp2 { + uint32_t length; + unsigned char data[0]; +} __attribute__((__packed__)); + /** * SECTION: print_data * @title: Stored prints + * @short_description: Stored prints functions * * Stored prints are represented by a structure named #fp_print_data. * Stored prints are originally obtained from an enrollment function such as @@ -50,6 +64,16 @@ * in any fashion that suits you. */ +/* + * SECTION: fpi-data + * @title: Stored prints creation + * @short_description: Stored prints creation functions + * + * Stored print can be loaded and created by certain drivers which do their own + * print matching in hardware. Most drivers will not be using those functions. + * See #fp_print_data for the public API counterpart. + */ + static char *base_store = NULL; static void storage_setup(void) @@ -106,7 +130,7 @@ static struct fp_print_data *print_data_new(uint16_t driver_id, return data; } -void fpi_print_data_item_free(struct fp_print_data_item *item) +static void fpi_print_data_item_free(struct fp_print_data_item *item) { g_free(item); } @@ -125,6 +149,19 @@ struct fp_print_data *fpi_print_data_new(struct fp_dev *dev) fpi_driver_get_data_type(dev->drv)); } +struct fp_print_data_item * +fpi_print_data_get_item(struct fp_print_data *data) +{ + return data->prints->data; +} + +void +fpi_print_data_add_item(struct fp_print_data *data, + struct fp_print_data_item *item) +{ + data->prints = g_slist_prepend(data->prints, item); +} + /** * fp_print_data_get_data: * @data: the stored print @@ -354,6 +391,7 @@ API_EXPORTED int fp_print_data_save(struct fp_print_data *data, r = g_mkdir_with_parents(dirpath, DIR_PERMS); if (r < 0) { fp_err("couldn't create storage directory"); + free(buf); g_free(path); g_free(dirpath); return r; @@ -445,7 +483,7 @@ API_EXPORTED int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger, struct fp_print_data **data) { gchar *path; - struct fp_print_data *fdata; + struct fp_print_data *fdata = NULL; int r; if (!base_store) @@ -560,6 +598,7 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data) /** * SECTION:dscv_print * @title: Print discovery (deprecated) + * @short_description: Print discovery functions * * The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API * for storing per-device prints for a single user, namely @@ -695,9 +734,7 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void) GError *err = NULL; GSList *tmplist = NULL; GSList *elem; - unsigned int tmplist_len; - struct fp_dscv_print **list; - unsigned int i; + GPtrArray *array; if (!base_store) storage_setup(); @@ -732,15 +769,17 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void) } g_dir_close(dir); - tmplist_len = g_slist_length(tmplist); - list = g_malloc(sizeof(*list) * (tmplist_len + 1)); - elem = tmplist; - for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem)) - list[i] = elem->data; - list[tmplist_len] = NULL; /* NULL-terminate */ + + if (tmplist == NULL) + return NULL; + + array = g_ptr_array_new(); + for (elem = tmplist; elem != NULL; elem = elem->next) + g_ptr_array_add(array, elem->data); + g_ptr_array_add(array, NULL); g_slist_free(tmplist); - return list; + return (struct fp_dscv_print **) g_ptr_array_free(array, FALSE); } /** diff --git a/libfprint/fpi-data.h b/libfprint/fpi-data.h new file mode 100644 index 00000000..37a7911a --- /dev/null +++ b/libfprint/fpi-data.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_DATA_H__ +#define __FPI_DATA_H__ + +struct fp_print_data; +struct fp_print_data_item { + size_t length; + unsigned char data[0]; +}; + +struct fp_print_data *fpi_print_data_new(struct fp_dev *dev); +struct fp_print_data_item *fpi_print_data_item_new(size_t length); +struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data); +void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item); + +#endif diff --git a/libfprint/imgdev.c b/libfprint/fpi-dev-img.c similarity index 69% rename from libfprint/imgdev.c rename to libfprint/fpi-dev-img.c index 030109b9..93f1f47e 100644 --- a/libfprint/imgdev.c +++ b/libfprint/fpi-dev-img.c @@ -21,25 +21,93 @@ #include +#include "fpi-dev-img.h" +#include "fpi-async.h" #include "fp_internal.h" +/** + * SECTION:fpi-dev-img + * @title: Image device operations + * @short_description: Image device operation functions + * + * As drivers work through different operations, they need to report back + * to the core as to their internal state, so errors and successes can be + * reported back to front-ends. + */ + #define MIN_ACCEPTABLE_MINUTIAE 10 #define BOZORTH3_DEFAULT_THRESHOLD 40 #define IMG_ENROLL_STAGES 5 +/** + * fpi_imgdev_get_action_state: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Returns the state of an imaging device while enrolling a fingerprint. + * + * Returns: a enum #fp_imgdev_enroll_state + */ +enum fp_imgdev_enroll_state +fpi_imgdev_get_action_state(struct fp_img_dev *imgdev) +{ + return imgdev->action_state; +} + +/** + * fpi_imgdev_get_action: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Returns the current action being performed by an imaging device. + * + * Returns: a enum #fp_imgdev_action + */ +enum fp_imgdev_action +fpi_imgdev_get_action(struct fp_img_dev *imgdev) +{ + return imgdev->action; +} + +/** + * fpi_imgdev_get_action_result: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Returns an integer representing the result of an action. Which enum + * the result code is taken from depends on the current action being performed. + * See #fp_capture_result, #fp_enroll_result and #fp_verify_result. + */ +int +fpi_imgdev_get_action_result(struct fp_img_dev *imgdev) +{ + return imgdev->action_result; +} + +/** + * fpi_imgdev_set_action_result: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @action_result: an action result + * + * Drivers should use fpi_imgdev_image_captured() instead. This function + * should not be used, and will be removed soon. + */ +void +fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, + int action_result) +{ + imgdev->action_result = action_result; +} + static int img_dev_open(struct fp_dev *dev, unsigned long driver_data) { struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev)); struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv); int r = 0; - imgdev->dev = dev; - imgdev->enroll_stage = 0; - dev->priv = imgdev; - dev->nr_enroll_stages = IMG_ENROLL_STAGES; + /* Set up back pointers */ + dev->img_dev = imgdev; + imgdev->parent = dev; - /* for consistency in driver code, allow udev access through imgdev */ - imgdev->udev = dev->udev; + imgdev->enroll_stage = 0; + dev->nr_enroll_stages = IMG_ENROLL_STAGES; if (imgdrv->open) { r = imgdrv->open(imgdev, driver_data); @@ -55,32 +123,45 @@ err: return r; } +/** + * fpi_imgdev_open_complete: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @status: an error code + * + * Function to call when the device has been opened, whether + * successfully of not. + */ void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status) { - fpi_drvcb_open_complete(imgdev->dev, status); + fpi_drvcb_open_complete(FP_DEV(imgdev), status); } static void img_dev_close(struct fp_dev *dev) { - struct fp_img_dev *imgdev = dev->priv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv); if (imgdrv->close) - imgdrv->close(imgdev); + imgdrv->close(dev->img_dev); else fpi_drvcb_close_complete(dev); } +/** + * fpi_imgdev_close_complete: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Function to call when the device has been closed. + */ void fpi_imgdev_close_complete(struct fp_img_dev *imgdev) { - fpi_drvcb_close_complete(imgdev->dev); + fpi_drvcb_close_complete(FP_DEV(imgdev)); g_free(imgdev); } static int dev_change_state(struct fp_img_dev *imgdev, enum fp_imgdev_state state) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); if (!imgdrv->change_state) @@ -92,7 +173,7 @@ static int dev_change_state(struct fp_img_dev *imgdev, * image after freeing the old one. */ static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); struct fp_img *img = *_img; @@ -118,6 +199,14 @@ static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img) return 0; } +/** + * fpi_imgdev_report_finger_status: + * @imgdev: a #fp_img_dev 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_imgdev_report_finger_status(struct fp_img_dev *imgdev, gboolean present) { @@ -150,7 +239,7 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, if (r == FP_ENROLL_COMPLETE) { imgdev->enroll_data = NULL; } - fpi_drvcb_enroll_stage_completed(imgdev->dev, r, + fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), r, r == FP_ENROLL_COMPLETE ? data : NULL, img); /* the callback can cancel enrollment, so recheck current @@ -163,18 +252,18 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, } break; case IMG_ACTION_VERIFY: - fpi_drvcb_report_verify_result(imgdev->dev, r, img); + fpi_drvcb_report_verify_result(FP_DEV(imgdev), r, img); imgdev->action_result = 0; fp_print_data_free(data); break; case IMG_ACTION_IDENTIFY: - fpi_drvcb_report_identify_result(imgdev->dev, r, + fpi_drvcb_report_identify_result(FP_DEV(imgdev), r, imgdev->identify_match_offset, img); imgdev->action_result = 0; fp_print_data_free(data); break; case IMG_ACTION_CAPTURE: - fpi_drvcb_report_capture_result(imgdev->dev, r, img); + fpi_drvcb_report_capture_result(FP_DEV(imgdev), r, img); imgdev->action_result = 0; break; default: @@ -185,14 +274,14 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, static void verify_process_img(struct fp_img_dev *imgdev) { - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv); + struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); int match_score = imgdrv->bz3_threshold; int r; if (match_score == 0) match_score = BOZORTH3_DEFAULT_THRESHOLD; - r = fpi_img_compare_print_data(imgdev->dev->verify_data, + r = fpi_img_compare_print_data(FP_DEV(imgdev)->verify_data, imgdev->acquire_data); if (r >= match_score) @@ -205,7 +294,7 @@ static void verify_process_img(struct fp_img_dev *imgdev) static void identify_process_img(struct fp_img_dev *imgdev) { - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv); + struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); int match_score = imgdrv->bz3_threshold; size_t match_offset; int r; @@ -214,12 +303,20 @@ static void identify_process_img(struct fp_img_dev *imgdev) match_score = BOZORTH3_DEFAULT_THRESHOLD; r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data, - imgdev->dev->identify_gallery, match_score, &match_offset); + FP_DEV(imgdev)->identify_gallery, match_score, &match_offset); imgdev->action_result = r; imgdev->identify_match_offset = match_offset; } +/** + * fpi_imgdev_abort_scan: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @result: the scan result + * + * Aborts a scan after an error, and set the action result. See + * fpi_imgdev_get_action_result() for possible values. + */ void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result) { imgdev->action_result = result; @@ -227,9 +324,16 @@ void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result) dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF); } +/** + * fpi_imgdev_image_captured: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @img: an #fp_img image + * + * Report to the core that the driver captured this image from the sensor. + */ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img) { - struct fp_print_data *print; + struct fp_print_data *print = NULL; int r; G_DEBUG_HERE(); @@ -272,7 +376,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img) switch (imgdev->action) { case IMG_ACTION_ENROLL: if (!imgdev->enroll_data) { - imgdev->enroll_data = fpi_print_data_new(imgdev->dev); + imgdev->enroll_data = fpi_print_data_new(FP_DEV(imgdev)); } BUG_ON(g_slist_length(print->prints) != 1); /* Move print data from acquire data into enroll_data */ @@ -283,7 +387,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img) fp_print_data_free(imgdev->acquire_data); imgdev->acquire_data = NULL; imgdev->enroll_stage++; - if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages) + if (imgdev->enroll_stage == FP_DEV(imgdev)->nr_enroll_stages) imgdev->action_result = FP_ENROLL_COMPLETE; else imgdev->action_result = FP_ENROLL_PASS; @@ -307,22 +411,29 @@ next_state: dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF); } +/** + * fpi_imgdev_session_error: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @error: an error code + * + * Report an error that occurred in the driver. + */ void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error) { fp_dbg("error %d", error); BUG_ON(error == 0); switch (imgdev->action) { case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL); + fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), error, NULL, NULL); break; case IMG_ACTION_VERIFY: - fpi_drvcb_report_verify_result(imgdev->dev, error, NULL); + fpi_drvcb_report_verify_result(FP_DEV(imgdev), error, NULL); break; case IMG_ACTION_IDENTIFY: - fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL); + fpi_drvcb_report_identify_result(FP_DEV(imgdev), error, 0, NULL); break; case IMG_ACTION_CAPTURE: - fpi_drvcb_report_capture_result(imgdev->dev, error, NULL); + fpi_drvcb_report_capture_result(FP_DEV(imgdev), error, NULL); break; default: fp_err("unhandled action %d", imgdev->action); @@ -330,22 +441,30 @@ void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error) } } +/** + * fpi_imgdev_activate_complete: + * @imgdev: a #fp_img_dev imaging fingerprint device + * @status: the activation result + * + * Marks an activation as complete, whether successful or not. + * See fpi_imgdev_get_action_result() for possible values. + */ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status) { fp_dbg("status %d", status); switch (imgdev->action) { case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_started(imgdev->dev, status); + fpi_drvcb_enroll_started(FP_DEV(imgdev), status); break; case IMG_ACTION_VERIFY: - fpi_drvcb_verify_started(imgdev->dev, status); + fpi_drvcb_verify_started(FP_DEV(imgdev), status); break; case IMG_ACTION_IDENTIFY: - fpi_drvcb_identify_started(imgdev->dev, status); + fpi_drvcb_identify_started(FP_DEV(imgdev), status); break; case IMG_ACTION_CAPTURE: - fpi_drvcb_capture_started(imgdev->dev, status); + fpi_drvcb_capture_started(FP_DEV(imgdev), status); break; default: fp_err("unhandled action %d", imgdev->action); @@ -358,22 +477,28 @@ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status) } } +/** + * fpi_imgdev_deactivate_complete: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Marks a deactivation as complete. + */ void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev) { G_DEBUG_HERE(); switch (imgdev->action) { case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_stopped(imgdev->dev); + fpi_drvcb_enroll_stopped(FP_DEV(imgdev)); break; case IMG_ACTION_VERIFY: - fpi_drvcb_verify_stopped(imgdev->dev); + fpi_drvcb_verify_stopped(FP_DEV(imgdev)); break; case IMG_ACTION_IDENTIFY: - fpi_drvcb_identify_stopped(imgdev->dev); + fpi_drvcb_identify_stopped(FP_DEV(imgdev)); break; case IMG_ACTION_CAPTURE: - fpi_drvcb_capture_stopped(imgdev->dev); + fpi_drvcb_capture_stopped(FP_DEV(imgdev)); break; default: fp_err("unhandled action %d", imgdev->action); @@ -386,7 +511,7 @@ void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev) int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); int width = imgdrv->img_width; @@ -398,7 +523,7 @@ int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev) int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); int height = imgdrv->img_height; @@ -410,7 +535,7 @@ int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev) static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); if (!imgdrv->activate) @@ -420,7 +545,7 @@ static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state) static void dev_deactivate(struct fp_img_dev *imgdev) { - struct fp_driver *drv = imgdev->dev->drv; + struct fp_driver *drv = FP_DEV(imgdev)->drv; struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); if (!imgdrv->deactivate) @@ -430,7 +555,7 @@ static void dev_deactivate(struct fp_img_dev *imgdev) static int generic_acquire_start(struct fp_dev *dev, int action) { - struct fp_img_dev *imgdev = dev->priv; + struct fp_img_dev *imgdev = dev->img_dev; int r; fp_dbg("action %d", action); imgdev->action = action; @@ -484,7 +609,7 @@ static int img_dev_capture_start(struct fp_dev *dev) static int img_dev_enroll_stop(struct fp_dev *dev) { - struct fp_img_dev *imgdev = dev->priv; + struct fp_img_dev *imgdev = dev->img_dev; BUG_ON(imgdev->action != IMG_ACTION_ENROLL); generic_acquire_stop(imgdev); return 0; @@ -492,7 +617,7 @@ static int img_dev_enroll_stop(struct fp_dev *dev) static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating) { - struct fp_img_dev *imgdev = dev->priv; + struct fp_img_dev *imgdev = dev->img_dev; BUG_ON(imgdev->action != IMG_ACTION_VERIFY); generic_acquire_stop(imgdev); return 0; @@ -500,7 +625,7 @@ static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating) static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating) { - struct fp_img_dev *imgdev = dev->priv; + struct fp_img_dev *imgdev = dev->img_dev; BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY); generic_acquire_stop(imgdev); imgdev->identify_match_offset = 0; @@ -509,7 +634,7 @@ static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating) static int img_dev_capture_stop(struct fp_dev *dev) { - struct fp_img_dev *imgdev = dev->priv; + struct fp_img_dev *imgdev = dev->img_dev; BUG_ON(imgdev->action != IMG_ACTION_CAPTURE); generic_acquire_stop(imgdev); return 0; diff --git a/libfprint/fpi-dev-img.h b/libfprint/fpi-dev-img.h new file mode 100644 index 00000000..0b0d48bc --- /dev/null +++ b/libfprint/fpi-dev-img.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_DEV_IMG_H__ +#define __FPI_DEV_IMG_H__ + +#include "fpi-dev.h" +#include "fpi-img.h" + +/** + * fp_imgdev_action: + * @IMG_ACTION_NONE: no action + * @IMG_ACTION_ENROLL: device action is enrolling + * @IMG_ACTION_VERIFY: device action is verifying + * @IMG_ACTION_IDENTIFY: device action is identifying + * @IMG_ACTION_CAPTURE: device action is capturing + * + * The current action being performed by an imaging device. The current + * action can be gathered inside the driver using fpi_imgdev_get_action(). + */ +enum fp_imgdev_action { + IMG_ACTION_NONE = 0, + IMG_ACTION_ENROLL, + IMG_ACTION_VERIFY, + IMG_ACTION_IDENTIFY, + IMG_ACTION_CAPTURE, +}; + +/** + * fp_imgdev_state: + * @IMGDEV_STATE_INACTIVE: inactive + * @IMGDEV_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped + * @IMGDEV_STATE_CAPTURE: capturing an image + * @IMGDEV_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. + */ +enum fp_imgdev_state { + IMGDEV_STATE_INACTIVE, + IMGDEV_STATE_AWAIT_FINGER_ON, + IMGDEV_STATE_CAPTURE, + IMGDEV_STATE_AWAIT_FINGER_OFF, +}; + +/** + * fp_imgdev_enroll_state: + * @IMG_ACQUIRE_STATE_NONE: doing nothing + * @IMG_ACQUIRE_STATE_ACTIVATING: activating the device + * @IMG_ACQUIRE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped + * @IMG_ACQUIRE_STATE_AWAIT_IMAGE: waiting for the image to be captured + * @IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed + * @IMG_ACQUIRE_STATE_DONE: enrollment has all the images it needs + * @IMG_ACQUIRE_STATE_DEACTIVATING: deactivating the device + * + * The state of an imaging device while enrolling a fingerprint. Given that enrollment + * requires multiple captures, a number of those states will be repeated before + * the state is @IMG_ACQUIRE_STATE_DONE. + */ +enum fp_imgdev_enroll_state { + IMG_ACQUIRE_STATE_NONE = 0, + IMG_ACQUIRE_STATE_ACTIVATING, + IMG_ACQUIRE_STATE_AWAIT_FINGER_ON, + IMG_ACQUIRE_STATE_AWAIT_IMAGE, + IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF, + IMG_ACQUIRE_STATE_DONE, + IMG_ACQUIRE_STATE_DEACTIVATING, +}; + +void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status); +void fpi_imgdev_close_complete(struct fp_img_dev *imgdev); +void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status); +void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev); +void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, + gboolean present); +void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img); +void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result); +void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error); + +enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev); +enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev); +int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev); +void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result); + +#endif diff --git a/libfprint/fpi-dev.c b/libfprint/fpi-dev.c new file mode 100644 index 00000000..219a2a1a --- /dev/null +++ b/libfprint/fpi-dev.c @@ -0,0 +1,150 @@ +/* + * fp_dev types manipulation + * Copyright (C) 2018 Bastien Nocera + * + * 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 "fp_internal.h" +#include + +/** + * SECTION:fpi-dev + * @title: Device operations + * @short_description: Device operation functions + * + * Those macros and functions will help get access to and from struct #fp_dev, + * and struct #fp_img_dev types, as well as get and set the instance struct + * data, eg. the structure containing the data specific to each driver. + */ + +/** + * FP_DEV: + * @dev: a struct #fp_img_dev + * + * Returns the struct #fp_dev associated with @dev, or %NULL on failure. + * + * Returns: a struct #fp_dev or %NULL + */ +struct fp_dev * +FP_DEV(struct fp_img_dev *dev) +{ + struct fp_img_dev *imgdev; + + g_return_val_if_fail (dev, NULL); + imgdev = (struct fp_img_dev *) dev; + return imgdev->parent; +} + +/** + * FP_IMG_DEV: + * @dev: a struct #fp_dev representing an imaging device. + * + * Returns a struct #fp_img_dev associated with @dev, or %NULL on failure. + * + * Returns: a struct #fp_img_dev or %NULL + */ +struct fp_img_dev * +FP_IMG_DEV(struct fp_dev *dev) +{ + g_return_val_if_fail (dev, NULL); + g_return_val_if_fail (dev->drv, NULL); + g_return_val_if_fail (dev->drv->type == DRIVER_IMAGING, NULL); + return dev->img_dev; +} + +/** + * fp_dev_set_instance_data: + * @dev: a struct #fp_dev + * @instance_data: a pointer to the instance data + * + * Set the instance data for a struct #fp_dev. This is usually a structure + * private to the driver used to keep state and pass it as user_data to + * asynchronous functions. + * + * The core does not do any memory management for this data, so the driver + * itself will have to create and free its own structure when appropriate. + */ +void +fp_dev_set_instance_data (struct fp_dev *dev, + void *instance_data) +{ + g_return_if_fail (dev); + g_return_if_fail (instance_data != NULL); + g_return_if_fail (dev->instance_data == NULL); + + dev->instance_data = instance_data; +} + +/** + * FP_INSTANCE_DATA: + * @dev: a struct #fp_dev + * + * Returns the instance data set using fp_dev_set_instance_data(). + */ +void * +FP_INSTANCE_DATA (struct fp_dev *dev) +{ + g_return_val_if_fail (dev, NULL); + + return dev->instance_data; +} + +/** + * fpi_dev_get_usb_dev: + * @dev: a struct #fp_dev + * + * Returns the #libusb_device_handle associated with @dev or %NULL + * if none are associated. + * + * Returns: a #libusb_device_handle pointer or %NULL + */ +libusb_device_handle * +fpi_dev_get_usb_dev(struct fp_dev *dev) +{ + return dev->udev; +} + +/** + * fpi_dev_set_nr_enroll_stages: + * @dev: a struct #fp_dev + * @nr_enroll_stages: the number of enroll stages + * + * Sets the number of enroll stages that this device uses. This is + * usually only necessary for primitive devices which have a hard-coded + * number of enroll stages baked into their protocol. + */ +void +fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, + int nr_enroll_stages) +{ + dev->nr_enroll_stages = nr_enroll_stages; +} + +/** + * fpi_dev_get_verify_data: + * @dev: a struct #fp_dev + * + * Returns the verify data associated with @dev. + * This is usually only necessary for primitive devices which need to + * have access to the raw verify data as it might have been stored on disk. + * + * Returns: a struct #fp_print_data pointer or %NULL + */ +struct fp_print_data * +fpi_dev_get_verify_data(struct fp_dev *dev) +{ + return dev->verify_data; +} diff --git a/libfprint/fpi-dev.h b/libfprint/fpi-dev.h new file mode 100644 index 00000000..98433912 --- /dev/null +++ b/libfprint/fpi-dev.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_DEV_H__ +#define __FPI_DEV_H__ + +#include +#include + +struct fp_dev; + +/** + * fp_img_dev: + * + * #fp_img_dev is an opaque structure type. You must access it using the + * appropriate functions. + */ +struct fp_img_dev; + +struct fp_dev *FP_DEV (struct fp_img_dev *dev); +struct fp_img_dev *FP_IMG_DEV (struct fp_dev *dev); + +void fp_dev_set_instance_data (struct fp_dev *dev, + void *instance_data); +void *FP_INSTANCE_DATA (struct fp_dev *dev); + +libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev); +void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, + int nr_enroll_stages); +struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev); + +#endif diff --git a/libfprint/pixman.c b/libfprint/fpi-img-pixman.c similarity index 81% rename from libfprint/pixman.c rename to libfprint/fpi-img-pixman.c index 1b4ca06f..1c1bedb9 100644 --- a/libfprint/pixman.c +++ b/libfprint/fpi-img-pixman.c @@ -23,7 +23,19 @@ #include "fp_internal.h" -struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor) +/** + * fpi_img_resize: + * @img: an #fp_img image + * @w_factor: horizontal factor to resize the image by + * @h_factor: vertical factor to resize the image by + * + * Resizes the #fp_img image by scaling it by @w_factor times horizontally + * and @h_factor times vertically. + * + * Returns: a newly allocated #fp_img, the original @img will not be modified + * and will also need to be freed + */ +struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor) { int new_width = img->width * w_factor; int new_height = img->height * h_factor; diff --git a/libfprint/img.c b/libfprint/fpi-img.c similarity index 78% rename from libfprint/img.c rename to libfprint/fpi-img.c index 2f195af4..f5ebea7f 100644 --- a/libfprint/img.c +++ b/libfprint/fpi-img.c @@ -31,6 +31,7 @@ /** * SECTION:img * @title: Image operations + * @short_description: Image operation functions * * libfprint offers several ways of retrieving images from imaging devices, * one example being the fp_dev_img_capture() function. The functions @@ -48,6 +49,25 @@ * natural upright orientation. */ +/** + * SECTION:fpi-img + * @title: Driver Image operations + * @short_description: Driver image operation functions + * + * Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's + * documentation for more information about data formats, and their uses in + * front-end applications. + */ + +/** + * fpi_img_new: + * @length: the length of data to allocate + * + * Creates a new #fp_img structure with @length bytes of data allocated + * to hold the image. + * + * Returns: a new #fp_img to free with fp_img_free() + */ struct fp_img *fpi_img_new(size_t length) { struct fp_img *img = g_malloc0(sizeof(*img) + length); @@ -56,9 +76,19 @@ struct fp_img *fpi_img_new(size_t length) return img; } +/** + * fpi_img_new_for_imgdev: + * @imgdev: a #fp_img_dev imaging fingerprint device + * + * Creates a new #fp_img structure, like fpi_img_new(), but uses the + * driver's advertised height and width to calculate the size of the + * length of data to allocate. + * + * Returns: a new #fp_img to free with fp_img_free() + */ struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev) { - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv); + struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); int width = imgdrv->img_width; int height = imgdrv->img_height; struct fp_img *img = fpi_img_new(width * height); @@ -67,27 +97,53 @@ struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev) return img; } +/** + * fpi_img_is_sane: + * @img: a #fp_img image + * + * Checks whether an #fp_img structure passes some basic checks, such + * as length, width and height being non-zero, and the buffer being + * big enough to hold the image of said size. + * + * Returns: %TRUE if the image is sane, %FALSE otherwise + */ gboolean fpi_img_is_sane(struct fp_img *img) { + guint len; + /* basic checks */ - if (!img->length || !img->width || !img->height) + if (!img->length || img->width <= 0 || img->height <= 0) return FALSE; - /* buffer is big enough? */ - if ((img->length * img->height) < img->length) + /* Are width and height just too big? */ + if (!g_uint_checked_mul(&len, img->width, img->height) || + len > G_MAXINT) + return FALSE; + + /* buffer big enough? */ + if (len > img->length) return FALSE; return TRUE; } -struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize) +/** + * fpi_img_realloc: + * @img: an #fp_img image + * @newsize: the new length of the image + * + * Changes the size of the data part of the #fp_img. + * + * Returns: the modified #fp_img, the same as the first argument to this function + */ +struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize) { return g_realloc(img, sizeof(*img) + newsize); } /** * fp_img_free: - * @img: the image to destroy. If NULL, function simply returns. + * @img: the image to destroy. If %NULL, function simply returns. * * Frees an image. Must be called when you are finished working with an image. */ @@ -262,9 +318,8 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth, struct minutiae_struct c[MAX_FILE_MINUTIAE]; struct xyt_struct *xyt = (struct xyt_struct *) buf; - /* FIXME: only considers first 150 minutiae (MAX_FILE_MINUTIAE) */ - /* nist does weird stuff with 150 vs 1000 limits */ - int nmin = min(minutiae->num, 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]; @@ -288,6 +343,9 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth, xyt->nrows = nmin; } +#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \ + | FP_IMG_COLORS_INVERTED) + static int fpi_img_detect_minutiae(struct fp_img *img) { struct fp_minutiae *minutiae; @@ -300,13 +358,10 @@ static int fpi_img_detect_minutiae(struct fp_img *img) GTimer *timer; if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) { - fp_err("cant detect minutiae for non-standardized image"); + fp_err("Cannot detect minutiae for non-standardized images"); return -EINVAL; } - /* Remove perimeter points from partial image */ - g_lfsparms_V2.remove_perimeter_pts = img->flags & FP_IMG_PARTIAL ? TRUE : FALSE; - /* 25.4 mm per inch */ timer = g_timer_new(); r = get_minutiae(&minutiae, &quality_map, &direction_map, @@ -352,7 +407,7 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img, /* FIXME: space is wasted if we dont hit the max minutiae count. would * be good to make this dynamic. */ - print = fpi_print_data_new(imgdev->dev); + print = fpi_print_data_new(FP_DEV(imgdev)); item = fpi_print_data_item_new(sizeof(struct xyt_struct)); print->type = PRINT_DATA_NBIS_MINUTIAE; minutiae_to_xyt(img->minutiae, img->width, img->height, item->data); @@ -536,57 +591,46 @@ API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, return img->minutiae->list; } -libusb_device_handle * -fpi_imgdev_get_usb_dev(struct fp_img_dev *dev) +/** + * fp_minutia_get_coords: + * @minutia: a struct #fp_minutia + * @coord_x: the return variable for the X coordinate of the minutia + * @coord_y: the return variable for the Y coordinate of the minutia + * + * Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it + * can be presented in a more verbose user interface. This is usually only + * used for debugging purposes. + * + * Returns: 0 on success, -1 on error. + */ +API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y) { - return dev->udev; + g_return_val_if_fail (minutia != NULL, -1); + g_return_val_if_fail (coord_x != NULL, -1); + g_return_val_if_fail (coord_y != NULL, -1); + + *coord_x = minutia->x; + *coord_y = minutia->y; + + return 0; } -void -fpi_imgdev_set_user_data(struct fp_img_dev *imgdev, - void *user_data) -{ - imgdev->priv = user_data; -} - -void * -fpi_imgdev_get_user_data(struct fp_img_dev *imgdev) -{ - return imgdev->priv; -} - -struct fp_dev * -fpi_imgdev_get_dev(struct fp_img_dev *imgdev) -{ - return imgdev->dev; -} - -enum fp_imgdev_enroll_state -fpi_imgdev_get_action_state(struct fp_img_dev *imgdev) -{ - return imgdev->action_state; -} - -enum fp_imgdev_action -fpi_imgdev_get_action(struct fp_img_dev *imgdev) -{ - return imgdev->action; -} - -int -fpi_imgdev_get_action_result(struct fp_img_dev *imgdev) -{ - return imgdev->action_result; -} - -void -fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, - int action_result) -{ - imgdev->action_result = action_result; -} - -/* Calculate squared standand deviation */ +/** + * 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 + */ int fpi_std_sq_dev(const unsigned char *buf, int size) { int res = 0, mean = 0, i; @@ -609,7 +653,23 @@ int fpi_std_sq_dev(const unsigned char *buf, int size) return res / size; } -/* Calculate normalized mean square difference of two lines */ +/** + * 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 + */ int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size) { int res = 0, i; diff --git a/libfprint/fpi-img.h b/libfprint/fpi-img.h new file mode 100644 index 00000000..4ebc3f39 --- /dev/null +++ b/libfprint/fpi-img.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_IMG_H__ +#define __FPI_IMG_H__ + +#include + +struct fp_minutiae; + +/** + * FpiImgFlags: + * @FP_IMG_V_FLIPPED: the image is vertically flipped + * @FP_IMG_H_FLIPPED: the image is horizontally flipped + * @FP_IMG_COLORS_INVERTED: the colours are inverted + * @FP_IMG_BINARIZED_FORM: binarised image, see fp_img_binarize() + * @FP_IMG_PARTIAL: the image is partial, useful for driver to keep track + * of incomplete captures + * + * Flags used in the #fp_img structure to describe the image contained + * into the structure. Note that a number of functions will refuse to + * handle images which haven't been standardised through fp_img_standardize() + * (meaning the @FP_IMG_V_FLIPPED, @FP_IMG_H_FLIPPED and @FP_IMG_COLORS_INVERTED + * should all be unset when the image needs to be analysed). + */ +typedef enum { + FP_IMG_V_FLIPPED = 1 << 0, + FP_IMG_H_FLIPPED = 1 << 1, + FP_IMG_COLORS_INVERTED = 1 << 2, + FP_IMG_BINARIZED_FORM = 1 << 3, + FP_IMG_PARTIAL = 1 << 4 +} FpiImgFlags; + +/** + * fp_img: + * @width: the width of the image + * @height: the height of the image + * @length: the length of the data associated with the image + * @flags: @FpiImgFlags flags describing the image contained in the structure + * @minutiae: an opaque structure representing the detected minutiae + * @binarized: the binarized image data + * @data: the start of the image data, which will be of @length size. + * + * A structure representing a captured, or processed image. The @flags member + * will show its current state, including whether whether the binarized form + * if present, whether it is complete, and whether it needs particular changes + * before being processed. + */ +struct fp_img { + int width; + int height; + size_t length; + FpiImgFlags flags; + /*< private >*/ + struct fp_minutiae *minutiae; + /*< public >*/ + unsigned char *binarized; + unsigned char data[0]; +}; + +struct fp_img *fpi_img_new(size_t length); +struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev); +struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize); +struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor); + +int fpi_std_sq_dev(const unsigned char *buf, int size); +int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size); + +#endif diff --git a/libfprint/fpi-log.h b/libfprint/fpi-log.h new file mode 100644 index 00000000..177e0f7e --- /dev/null +++ b/libfprint/fpi-log.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_LOG_H__ +#define __FPI_LOG_H__ + +/** + * SECTION:fpi-log + * @title: Logging + * @short_description: Logging functions + * + * Logging in libfprint is handled through GLib's logging system, and behave the same + * way as in the GLib [Message Output and Debugging Functions](https://developer.gnome.org/glib/stable/glib-Message-Logging.html) + * documentation. + * + * You should include `fpi-log.h` as early as possible in your sources, just after + * setting the `FP_COMPONENT` define to a string unique to your sources. This will + * set the suffix of the `G_LOG_DOMAIN` used for printing. + */ + +#ifdef FP_COMPONENT +#undef G_LOG_DOMAIN +#ifndef __GTK_DOC_IGNORE__ +#define G_LOG_DOMAIN "libfprint-"FP_COMPONENT +#endif +#endif + +#include + +/** + * fp_dbg: + * + * Same as g_debug(). + * + */ +#define fp_dbg g_debug + +/** + * fp_info: + * + * Same as g_debug(). + */ +#define fp_info g_debug + +/** + * fp_warn: + * + * Same as g_warning(). + */ +#define fp_warn g_warning + +/** + * fp_err: + * + * Same as g_warning(). In the future, this might be changed to a + * g_assert() instead, so bear this in mind when adding those calls + * to your driver. + */ +#define fp_err g_warning + +/** + * BUG_ON: + * @condition: the condition to check + * + * Uses fp_err() to print an error if the @condition is true. + */ +#define BUG_ON(condition) G_STMT_START \ + if (condition) { \ + char *s; \ + s = g_strconcat ("BUG: (", #condition, ")", NULL); \ + fp_err ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \ + g_free (s); \ + } G_STMT_END + +/** + * BUG: + * + * Same as BUG_ON() but is always true. + */ +#define BUG() BUG_ON(1) + +#endif diff --git a/libfprint/poll.c b/libfprint/fpi-poll.c similarity index 72% rename from libfprint/poll.c rename to libfprint/fpi-poll.c index 615ba40f..af0c4bee 100644 --- a/libfprint/poll.c +++ b/libfprint/fpi-poll.c @@ -20,6 +20,7 @@ #define FP_COMPONENT "poll" #include "fp_internal.h" +#include "fpi-poll.h" #include #include @@ -32,6 +33,7 @@ /** * SECTION:events * @title: Initialisation and events handling + * @short_description: Initialisation and events handling functions * * These functions are only applicable to users of libfprint's asynchronous * API. @@ -63,6 +65,16 @@ * your main loop. */ +/** + * SECTION:fpi-poll + * @title: Timeouts + * @short_description: Timeout handling helpers + * + * Helper functions to schedule a function call to be made after a timeout. This + * is useful to avoid making blocking calls while waiting for hardware to answer + * for example. + */ + /* this is a singly-linked list of pending timers, sorted with the timer that * is expiring soonest at the head. */ static GSList *active_timers = NULL; @@ -74,13 +86,17 @@ static fp_pollfd_removed_cb fd_removed_cb = NULL; struct fpi_timeout { struct timeval expiry; fpi_timeout_fn callback; + struct fp_dev *dev; void *data; + char *name; }; +static gboolean fpi_poll_is_setup(void); + static int timeout_sort_fn(gconstpointer _a, gconstpointer _b) { - struct fpi_timeout *a = (struct fpi_timeout *) _a; - struct fpi_timeout *b = (struct fpi_timeout *) _b; + fpi_timeout *a = (fpi_timeout *) _a; + fpi_timeout *b = (fpi_timeout *) _b; struct timeval *tv_a = &a->expiry; struct timeval *tv_b = &b->expiry; @@ -92,27 +108,79 @@ static int timeout_sort_fn(gconstpointer _a, gconstpointer _b) return 0; } -/* A timeout is the asynchronous equivalent of sleeping. You create a timeout +static void +fpi_timeout_free(fpi_timeout *timeout) +{ + if (timeout == NULL) + return; + + g_free(timeout->name); + g_free(timeout); +} + +/** + * fpi_timeout_set_name: + * @timeout: a #fpi_timeout + * @name: the name to give the timeout + * + * Sets a name for a timeout, allowing that name to be printed + * along with any timeout related debug. + */ +void +fpi_timeout_set_name(fpi_timeout *timeout, + const char *name) +{ + g_return_if_fail (timeout != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (timeout->name == NULL); + + timeout->name = g_strdup(name); +} + +/** + * fpi_timeout_add: + * @msec: the time before calling the function, in milliseconds (1/1000ths of a second) + * @callback: function to callback + * @dev: a struct #fp_dev + * @data: data to pass to @callback, or %NULL + * + * A timeout is the asynchronous equivalent of sleeping. You create a timeout * saying that you'd like to have a function invoked at a certain time in - * the future. */ -struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback, - void *data) + * the future. + * + * Note that you should hold onto the return value of this function to cancel it + * use fpi_timeout_cancel(), otherwise the callback could be called while the driver + * is being torn down. + * + * This function can be considered to never fail. + * + * Returns: an #fpi_timeout structure + */ +fpi_timeout *fpi_timeout_add(unsigned int msec, + fpi_timeout_fn callback, + struct fp_dev *dev, + void *data) { struct timespec ts; struct timeval add_msec; - struct fpi_timeout *timeout; + fpi_timeout *timeout; int r; + g_return_val_if_fail (dev != NULL, NULL); + g_return_val_if_fail (fpi_poll_is_setup(), NULL); + fp_dbg("in %dms", msec); r = clock_gettime(CLOCK_MONOTONIC, &ts); if (r < 0) { fp_err("failed to read monotonic clock, errno=%d", errno); + BUG(); return NULL; } - timeout = g_malloc(sizeof(*timeout)); + timeout = g_new0(fpi_timeout, 1); timeout->callback = callback; + timeout->dev = dev; timeout->data = data; TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts); @@ -128,11 +196,38 @@ struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback, return timeout; } -void fpi_timeout_cancel(struct fpi_timeout *timeout) +/** + * fpi_timeout_cancel: + * @timeout: an #fpi_timeout structure + * + * Cancels a timeout scheduled with fpi_timeout_add(), and frees the + * @timeout structure. + */ +void fpi_timeout_cancel(fpi_timeout *timeout) { G_DEBUG_HERE(); active_timers = g_slist_remove(active_timers, timeout); - g_free(timeout); + fpi_timeout_free(timeout); +} + +void +fpi_timeout_cancel_for_dev(struct fp_dev *dev) +{ + GSList *l; + + g_return_if_fail (dev != NULL); + + l = active_timers; + while (l) { + struct fpi_timeout *timeout = l->data; + GSList *current = l; + + l = l->next; + if (timeout->dev == dev) { + fpi_timeout_free (timeout); + active_timers = g_slist_delete_link (active_timers, current); + } + } } /* get the expiry time and optionally the timeout structure for the next @@ -163,11 +258,18 @@ static int get_next_timeout_expiry(struct timeval *out, *out_timeout = next_timeout; if (timercmp(&tv, &next_timeout->expiry, >=)) { - fp_dbg("first timeout already expired"); + if (next_timeout->name) + fp_dbg("first timeout '%s' already expired", next_timeout->name); + else + fp_dbg("first timeout already expired"); timerclear(out); } else { timersub(&next_timeout->expiry, &tv, out); - fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec); + if (next_timeout->name) + fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name, + out->tv_sec, out->tv_usec); + else + fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec); } return 1; @@ -177,9 +279,9 @@ static int get_next_timeout_expiry(struct timeval *out, static void handle_timeout(struct fpi_timeout *timeout) { G_DEBUG_HERE(); - timeout->callback(timeout->data); + timeout->callback(timeout->dev, timeout->data); active_timers = g_slist_remove(active_timers, timeout); - g_free(timeout); + fpi_timeout_free(timeout); } static int handle_timeouts(void) @@ -263,7 +365,7 @@ API_EXPORTED int fp_handle_events(void) /** * fp_get_next_timeout: - * @tv: a %timeval structure containing the duration to the next timeout. + * @tv: a #timeval structure containing the duration to the next timeout. * * A zero filled @tv timeout means events are to be handled immediately * @@ -271,8 +373,8 @@ API_EXPORTED int fp_handle_events(void) */ API_EXPORTED int fp_get_next_timeout(struct timeval *tv) { - struct timeval fprint_timeout; - struct timeval libusb_timeout; + struct timeval fprint_timeout = { 0, 0 }; + struct timeval libusb_timeout = { 0, 0 }; int r_fprint; int r_libusb; @@ -281,7 +383,7 @@ API_EXPORTED int fp_get_next_timeout(struct timeval *tv) /* if we have no pending timeouts and the same is true for libusb, * indicate that we have no pending timouts */ - if (r_fprint == 0 && r_libusb == 0) + if (r_fprint <= 0 && r_libusb <= 0) return 0; /* if fprint have no pending timeouts return libusb timeout */ @@ -321,6 +423,8 @@ API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds) ssize_t cnt = 0; size_t i = 0; + g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO); + usbfds = libusb_get_pollfds(fpi_usb_ctx); if (!usbfds) { *pollfds = NULL; @@ -376,10 +480,35 @@ void fpi_poll_init(void) void fpi_poll_exit(void) { - g_slist_free(active_timers); + g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free); active_timers = NULL; fd_added_cb = NULL; fd_removed_cb = NULL; libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL); } +static gboolean +fpi_poll_is_setup(void) +{ + return (fd_added_cb != NULL && fd_removed_cb != NULL); +} + +void +fpi_timeout_cancel_all_for_dev(struct fp_dev *dev) +{ + GSList *l; + + g_return_if_fail (dev != NULL); + + l = active_timers; + while (l) { + struct fpi_timeout *timeout = l->data; + GSList *current = l; + + l = l->next; + if (timeout->dev == dev) { + g_free (timeout); + active_timers = g_slist_delete_link (active_timers, current); + } + } +} diff --git a/libfprint/fpi-poll.h b/libfprint/fpi-poll.h new file mode 100644 index 00000000..2682f277 --- /dev/null +++ b/libfprint/fpi-poll.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_POLL_H__ +#define __FPI_POLL_H__ + +#include "fprint.h" + +/** + * fpi_timeout_fn: + * @dev: the struct #fp_dev passed to fpi_timeout_add() + * @data: the data passed to fpi_timeout_add() + * + * The prototype of the callback function for fpi_timeout_add(). + * Note that after the callback is called, the #fpi_timeout structure will + * be freed. + */ +typedef void (*fpi_timeout_fn)(struct fp_dev *dev, void *data); + +/** + * fpi_timeout: + * + * An opaque structure representing a scheduled function call, created with + * fpi_timeout_add(). + */ +typedef struct fpi_timeout fpi_timeout; +fpi_timeout *fpi_timeout_add(unsigned int msec, + fpi_timeout_fn callback, + struct fp_dev *dev, + void *data); +void fpi_timeout_set_name(fpi_timeout *timeout, + const char *name); +void fpi_timeout_cancel(fpi_timeout *timeout); + +#endif diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c new file mode 100644 index 00000000..64430c16 --- /dev/null +++ b/libfprint/fpi-ssm.c @@ -0,0 +1,317 @@ +/* + * Functions to assist with asynchronous driver <---> library communications + * Copyright (C) 2007-2008 Daniel Drake + * + * 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 "drv" + +#include "fp_internal.h" +#include "fpi-ssm.h" + +#include +#include + +/** + * SECTION:fpi-ssm + * @title: Sequential state machine + * @short_description: State machine helpers + * + * Asynchronous driver design encourages some kind of state machine behind it. + * In most cases, the state machine is entirely linear - you only go to the + * next state, you never jump or go backwards. The #fpi_ssm functions help you + * implement such a machine. + * + * e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4` + * + * `S1` is the start state + * There is also an implicit error state and an implicit accepting state + * (both with implicit edges from every state). + * + * You can also jump to any arbitrary state (while marking completion of the + * current state) while the machine is running. In other words there are + * implicit edges linking one state to every other state. + * + * To create an #fpi_ssm, you pass a state handler function and the total number of + * states (4 in the above example) to fpi_ssm_new(). Note that the state numbers + * start at zero, making them match the first value in a C enumeration. + * + * To start a ssm, you pass in a completion callback function to fpi_ssm_start() + * which gets called when the ssm completes (both on error and on failure). + * + * To iterate to the next state, call fpi_ssm_next_state(). It is legal to + * attempt to iterate beyond the final state - this is equivalent to marking + * the ssm as successfully completed. + * + * To mark successful completion of a SSM, either iterate beyond the final + * state or call fpi_ssm_mark_completed() from any state. + * + * To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any + * state. You must pass a non-zero error code. + * + * Your state handling function looks at the return value of + * fpi_ssm_get_cur_state() in order to determine the current state and hence + * which operations to perform (a switch statement is appropriate). + * + * Typically, the state handling function fires off an asynchronous + * communication with the device (such as a libsub transfer), and the + * callback function iterates the machine to the next state + * upon success (or fails). + * + * Your completion callback should examine the return value of + * fpi_ssm_get_error() in order to determine whether the #fpi_ssm completed or + * failed. An error code of zero indicates successful completion. + */ + +struct fpi_ssm { + struct fp_dev *dev; + fpi_ssm *parentsm; + void *user_data; + int nr_states; + int cur_state; + gboolean completed; + int error; + ssm_completed_fn callback; + ssm_handler_fn handler; +}; + +/** + * fpi_ssm_new: + * @dev: a #fp_dev fingerprint device + * @handler: the callback function + * @nr_states: the number of states + * @user_data: the user data to pass to callbacks + * + * Allocate a new ssm, with @nr_states states. The @handler callback + * will be called after each state transition. + * + * Returns: a new #fpi_ssm state machine + */ +fpi_ssm *fpi_ssm_new(struct fp_dev *dev, + ssm_handler_fn handler, + int nr_states, + void *user_data) +{ + fpi_ssm *machine; + BUG_ON(nr_states < 1); + + machine = g_malloc0(sizeof(*machine)); + machine->handler = handler; + machine->nr_states = nr_states; + machine->dev = dev; + machine->completed = TRUE; + machine->user_data = user_data; + return machine; +} + +/** + * fpi_ssm_get_user_data: + * @machine: an #fpi_ssm state machine + * + * Retrieve the pointer to user data set when fpi_ssm_new() + * is called. + * + * Returns: a pointer + */ +void * +fpi_ssm_get_user_data(fpi_ssm *machine) +{ + return machine->user_data; +} + +/** + * fpi_ssm_free: + * @machine: an #fpi_ssm state machine + * + * Frees a state machine. This does not call any error or success + * callbacks, so you need to do this yourself. + */ +void fpi_ssm_free(fpi_ssm *machine) +{ + if (!machine) + return; + g_free(machine); +} + +/* Invoke the state handler */ +static void __ssm_call_handler(fpi_ssm *machine) +{ + fp_dbg("%p entering state %d", machine, machine->cur_state); + machine->handler(machine, machine->dev, machine->user_data); +} + +/** + * fpi_ssm_start: + * @ssm: an #fpi_ssm state machine + * @callback: the #ssm_completed_fn callback to call on completion + * + * Starts a state machine. You can also use this function to restart + * a completed or failed state machine. The @callback will be called + * on completion. + */ +void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback) +{ + BUG_ON(!ssm->completed); + ssm->callback = callback; + ssm->cur_state = 0; + ssm->completed = FALSE; + ssm->error = 0; + __ssm_call_handler(ssm); +} + +static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +{ + fpi_ssm *parent = ssm->parentsm; + BUG_ON(!parent); + if (ssm->error) + fpi_ssm_mark_failed(parent, ssm->error); + else + fpi_ssm_next_state(parent); + fpi_ssm_free(ssm); +} + +/** + * fpi_ssm_start_subsm: + * @parent: an #fpi_ssm state machine + * @child: an #fpi_ssm state machine + * + * Starts a state machine as a child of another. if the child completes + * successfully, the parent will be advanced to the next state. if the + * child fails, the parent will be marked as failed with the same error code. + * + * The child will be automatically freed upon completion or failure. + */ +void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child) +{ + child->parentsm = parent; + fpi_ssm_start(child, __subsm_complete); +} + +/** + * fpi_ssm_mark_completed: + * @machine: an #fpi_ssm state machine + * + * Mark a ssm as completed successfully. The callback set when creating + * the state machine with fpi_ssm_new() will be called synchronously. + */ +void fpi_ssm_mark_completed(fpi_ssm *machine) +{ + BUG_ON(machine->completed); + machine->completed = TRUE; + fp_dbg("%p completed with status %d", machine, machine->error); + if (machine->callback) + machine->callback(machine, machine->dev, machine->user_data); +} + +/** + * fpi_ssm_mark_failed: + * @machine: an #fpi_ssm state machine + * @error: the error code + * + * Mark a state machine as failed with @error as the error code. + */ +void fpi_ssm_mark_failed(fpi_ssm *machine, int error) +{ + fp_dbg("error %d from state %d", error, machine->cur_state); + BUG_ON(error == 0); + machine->error = error; + fpi_ssm_mark_completed(machine); +} + +/** + * fpi_ssm_next_state: + * @machine: an #fpi_ssm state machine + * + * Iterate to next state of a state machine. If the current state is the + * last state, then the state machine will be marked as completed, as + * if calling fpi_ssm_mark_completed(). + */ +void fpi_ssm_next_state(fpi_ssm *machine) +{ + g_return_if_fail (machine != NULL); + + BUG_ON(machine->completed); + machine->cur_state++; + if (machine->cur_state == machine->nr_states) { + fpi_ssm_mark_completed(machine); + } else { + __ssm_call_handler(machine); + } +} + +/** + * fpi_ssm_next_state_timeout_cb: + * @dev: a struct #fp_dev + * @data: a pointer to an #fpi_ssm state machine + * + * Same as fpi_ssm_next_state(), but to be used as a callback + * for an fpi_timeout_add() callback, when the state change needs + * to happen after a timeout. + * + * Make sure to pass the #fpi_ssm as the `user_data` argument + * for that fpi_timeout_add() call. + */ +void +fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, + void *data) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (data != NULL); + + fpi_ssm_next_state(data); +} + +/** + * fpi_ssm_jump_to_state: + * @machine: an #fpi_ssm state machine + * @state: the state to jump to + * + * Jump to the @state state, bypassing intermediary states. + */ +void fpi_ssm_jump_to_state(fpi_ssm *machine, int state) +{ + BUG_ON(machine->completed); + BUG_ON(state >= machine->nr_states); + machine->cur_state = state; + __ssm_call_handler(machine); +} + +/** + * fpi_ssm_get_cur_state: + * @machine: an #fpi_ssm state machine + * + * Returns the value of the current state. Note that states are + * 0-indexed, so a value of 0 means “the first state”. + * + * Returns: the current state. + */ +int fpi_ssm_get_cur_state(fpi_ssm *machine) +{ + return machine->cur_state; +} + +/** + * fpi_ssm_get_error: + * @machine: an #fpi_ssm state machine + * + * Returns the error code set by fpi_ssm_mark_failed(). + * + * Returns: a error code + */ +int fpi_ssm_get_error(fpi_ssm *machine) +{ + return machine->error; +} diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h new file mode 100644 index 00000000..a619d42c --- /dev/null +++ b/libfprint/fpi-ssm.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_SSM_H__ +#define __FPI_SSM_H__ + +#include +#include +#include +#include +#include +#include + +/* async drv <--> lib comms */ + +/** + * fpi_ssm: + * + * Sequential state machine that iterates sequentially over + * a predefined series of states. Can be terminated by either completion or + * failure error conditions. + */ +typedef struct fpi_ssm fpi_ssm; + +/** + * ssm_completed_fn: + * @ssm: a #fpi_ssm state machine + * @dev: the #fp_dev fingerprint device + * @user_data: the user data passed to fpi_ssm_new() + * + * The callback called when a state machine completes successfully, + * as set when calling fpi_ssm_start(). + */ +typedef void (*ssm_completed_fn)(fpi_ssm *ssm, + struct fp_dev *dev, + void *user_data); + +/** + * ssm_handler_fn: + * @ssm: a #fpi_ssm state machine + * @dev: the #fp_dev fingerprint device + * @user_data: the user data passed to fpi_ssm_new() + * + * The callback called when a state machine transitions from one + * state to the next, as set when calling fpi_ssm_new(). + */ +typedef void (*ssm_handler_fn)(fpi_ssm *ssm, + struct fp_dev *dev, + void *user_data); + +/* for library and drivers */ +fpi_ssm *fpi_ssm_new(struct fp_dev *dev, + ssm_handler_fn handler, + int nr_states, + void *user_data); +void fpi_ssm_free(fpi_ssm *machine); +void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback); +void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child); + +/* for drivers */ +void fpi_ssm_next_state(fpi_ssm *machine); +void fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, void *data); +void fpi_ssm_jump_to_state(fpi_ssm *machine, int state); +void fpi_ssm_mark_completed(fpi_ssm *machine); +void fpi_ssm_mark_failed(fpi_ssm *machine, int error); +void *fpi_ssm_get_user_data(fpi_ssm *machine); +int fpi_ssm_get_error(fpi_ssm *machine); +int fpi_ssm_get_cur_state(fpi_ssm *machine); + +#endif diff --git a/libfprint/sync.c b/libfprint/fpi-sync.c similarity index 95% rename from libfprint/sync.c rename to libfprint/fpi-sync.c index c194f5ca..e5a64f81 100644 --- a/libfprint/sync.c +++ b/libfprint/fpi-sync.c @@ -20,6 +20,7 @@ #define FP_COMPONENT "sync" #include "fp_internal.h" +#include "fpi-dev.h" #include #include @@ -39,7 +40,7 @@ static void sync_open_cb(struct fp_dev *dev, int status, void *user_data) /** * fp_dev_open: - * @ddev: the discovered device to open + * @ddev: the struct #fp_dscv_dev discovered device to open * * Opens and initialises a device. This is the function you call in order * to convert a #fp_dscv_dev discovered device into an actual device handle @@ -81,9 +82,9 @@ static void sync_close_cb(struct fp_dev *dev, void *user_data) /** * fp_dev_close: - * @dev: the device to close. If %NULL, function simply returns. + * @dev: the struct #fp_dev device to close. If %NULL, function simply returns * - * Close a device. You must call this function when you are finished using + * Closes a device. You must call this function when you have finished using * a fingerprint device. */ API_EXPORTED void fp_dev_close(struct fp_dev *dev) @@ -127,12 +128,12 @@ static void enroll_stop_cb(struct fp_dev *dev, void *user_data) /** * fp_enroll_finger_img: - * @dev: the device + * @dev: the struct #fp_dev device * @print_data: a location to return the resultant enrollment data from - * the final stage. Must be freed with fp_print_data_free() after use. + * the final stage. Must be freed with fp_print_data_free() after use * @img: location to store the scan image. accepts %NULL for no image * storage. If an image is returned, it must be freed with fp_img_free() after - * use. + * use * * Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling) * for an explanation of enroll stages. @@ -289,9 +290,9 @@ err: /** * fp_enroll_finger: - * @dev: the device + * @dev: the struct #fp_dev device * @print_data: a location to return the resultant enrollment data from - * the final stage. Must be freed with fp_print_data_free() after use. + * the final stage. Must be freed with fp_print_data_free() after use * * Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling) * for an explanation of enroll stages. This function is just a shortcut to @@ -330,14 +331,14 @@ static void verify_stop_cb(struct fp_dev *dev, void *user_data) /** * fp_verify_finger_img: - * @dev: the device to perform the scan. + * @dev: the struct #fp_dev device to perform the scan on * @enrolled_print: the print to verify against. Must have been previously - * enrolled with a device compatible to the device selected to perform the scan. + * enrolled with a device compatible to the device selected to perform the scan * @img: location to store the scan image. accepts %NULL for no image * storage. If an image is returned, it must be freed with fp_img_free() after - * use. + * use - * Performs a new scan and verify it against a previously enrolled print. + * Performs a new scan and verifies it against a previously enrolled print. * If the device is an imaging device, it can also return the image from * the scan, even when the verify fails with a RETRY code. It is legal to * call this function even on non-imaging devices, just don't expect them to @@ -422,9 +423,9 @@ err: /** * fp_verify_finger: - * @dev: the device to perform the scan. + * @dev: the struct #fp_dev device to perform the scan on * @enrolled_print: the print to verify against. Must have been previously - * enrolled with a device compatible to the device selected to perform the scan. + * enrolled with a device compatible to the device selected to perform the scan * * Performs a new scan and verify it against a previously enrolled print. This * function is just a shortcut to calling fp_verify_finger_img() with a NULL @@ -466,16 +467,16 @@ static void identify_stop_cb(struct fp_dev *dev, void *user_data) /** * fp_identify_finger_img: - * @dev: the device to perform the scan. + * @dev: the struct #fp_dev device to perform the scan on * @print_gallery: NULL-terminated array of pointers to the prints to * identify against. Each one must have been previously enrolled with a device - * compatible to the device selected to perform the scan. + * compatible to the device selected to perform the scan * @match_offset: output location to store the array index of the matched * gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was - * returned. + * returned * @img: location to store the scan image. accepts %NULL for no image * storage. If an image is returned, it must be freed with fp_img_free() after - * use. + * use * Performs a new scan and attempts to identify the scanned finger against * a collection of previously enrolled fingerprints. @@ -564,13 +565,13 @@ err: /** * fp_identify_finger: - * @dev: the device to perform the scan. + * @dev: the struct #fp_dev device to perform the scan on * @print_gallery: %NULL-terminated array of pointers to the prints to * identify against. Each one must have been previously enrolled with a device - * compatible to the device selected to perform the scan. + * compatible to the device selected to perform the scan * @match_offset: output location to store the array index of the matched * gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was - * returned. + * returned * Performs a new scan and attempts to identify the scanned finger against a * collection of previously enrolled fingerprints. This function is just a @@ -610,10 +611,10 @@ static void capture_stop_cb(struct fp_dev *dev, void *user_data) } /** * fp_dev_img_capture: - * @dev: the device + * @dev: the struct #fp_dev device * @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected * @img: a location to return the captured image. Must be freed with - * fp_img_free() after use. + * fp_img_free() after use * * Captures a #fp_img from a device. The returned image is the raw * image provided by the device, you may wish to [standardize](libfprint-Image-operations.html#img_std) it. @@ -627,7 +628,7 @@ static void capture_stop_cb(struct fp_dev *dev, void *user_data) * * Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the * @unconditional flag was set but the device does not support this, or that the - * device does not support imaging. + * device does not support imaging */ API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional, struct fp_img **img) diff --git a/libfprint/fpi-usb.c b/libfprint/fpi-usb.c new file mode 100644 index 00000000..b140d7ef --- /dev/null +++ b/libfprint/fpi-usb.c @@ -0,0 +1,236 @@ +/* + * Driver API definitions + * Copyright (C) 2018 Bastien Nocera + * + * 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 "fpi-usb.h" +#include "drivers_api.h" + +/** + * SECTION:fpi-usb + * @title: Helpers for libusb + * @short_description: libusb-related helpers + * + * A collection of [libusb helpers](http://libusb.sourceforge.net/api-1.0/group__poll.html#details) + * to make driver development easier. Please refer to the libusb API documentation for more + * information about the original API. + */ + +/* Helpers from glib */ +#include +#include +#include +#include +#include + +/* special helpers to avoid gmessage.c dependency */ +static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2); +#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0) + +static void +mem_error (const char *format, + ...) +{ + const char *pname; + va_list args; + /* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */ + fputs ("\n***MEMORY-ERROR***: ", stderr); + pname = g_get_prgname(); + g_fprintf (stderr, "%s[%ld]: ", pname ? pname : "", (long)getpid()); + va_start (args, format); + g_vfprintf (stderr, format, args); + va_end (args); + fputs ("\n", stderr); + abort(); + _exit (1); +} + +struct fpi_usb_transfer { + struct libusb_transfer *transfer; + fpi_ssm *ssm; + struct fp_dev *dev; + fpi_usb_transfer_cb_fn callback; + void *user_data; +}; + +/** + * fpi_usb_alloc: + * + * Returns a struct libusb_transfer, similar to calling + * `libusb_alloc_transfer(0)`[[1](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]. As libfprint uses GLib internally, + * and [memory allocation failures will make applications fail](https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#glib-Memory-Allocation.description), + * this helper will assert when the libusb call fails. + */ +struct libusb_transfer * +fpi_usb_alloc(void) +{ + struct libusb_transfer *transfer; + + transfer = libusb_alloc_transfer(0); + mem_assert(transfer); + + return transfer; +} + +static fpi_usb_transfer * +fpi_usb_transfer_new(struct fp_dev *dev, + fpi_ssm *ssm, + fpi_usb_transfer_cb_fn callback, + void *user_data) +{ + fpi_usb_transfer *transfer; + + transfer = g_new0(fpi_usb_transfer, 1); + transfer->transfer = fpi_usb_alloc(); + transfer->dev = dev; + transfer->ssm = ssm; + transfer->callback = callback; + transfer->user_data = user_data; + + return transfer; +} + +void +fpi_usb_transfer_free(fpi_usb_transfer *transfer) +{ + if (transfer == NULL) + return; + + g_free(transfer->transfer->buffer); + libusb_free_transfer(transfer->transfer); + g_free(transfer); +} + +static void +fpi_usb_transfer_cb (struct libusb_transfer *transfer) +{ + fpi_usb_transfer *t; + + g_assert(transfer); + g_assert(transfer->user_data); + + t = transfer->user_data; + BUG_ON(transfer->callback == NULL); + (t->callback) (transfer, t->dev, t->ssm, t->user_data); + fpi_usb_transfer_free(t); +} + +/** + * fpi_usb_fill_bulk_transfer: + * @dev: a struct #fp_dev fingerprint device + * @ssm: the current #fpi_ssm state machine + * @endpoint: the USB end point + * @buffer: a buffer allocated with g_malloc() or another GLib function. + * Note that the returned #fpi_usb_transfer will own this buffer, so it + * should not be freed manually. + * @length: the size of @buffer + * @callback: the callback function that will be called once the fpi_usb_submit_transfer() + * call finishes. + * @user_data: a user data pointer to pass to the callback + * @timeout: timeout for the transfer in milliseconds, or 0 for no timeout + * + * This function is similar to calling [`libusb_alloc_transfer(0)`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)] + * followed by calling [`libusb_fill_bulk_transfer()`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gad4ddb1a5c6c7fefc979a44d7300b95d7). + * The #fpi_usb_transfer_cb_fn callback will however provide more arguments + * relevant to libfprint drivers, making it a good replacement for the raw libusb + * calls. + * + * Returns: a #fpi_usb_transfer transfer struct, to be passed to + * fpi_usb_submit_transfer(). + */ +fpi_usb_transfer * +fpi_usb_fill_bulk_transfer (struct fp_dev *dev, + fpi_ssm *ssm, + unsigned char endpoint, + unsigned char *buffer, + int length, + fpi_usb_transfer_cb_fn callback, + void *user_data, + unsigned int timeout) +{ + fpi_usb_transfer *transfer; + + g_return_val_if_fail (dev != NULL, NULL); + g_return_val_if_fail (callback != NULL, NULL); + + transfer = fpi_usb_transfer_new(dev, + ssm, + callback, + user_data); + + libusb_fill_bulk_transfer(transfer->transfer, + fpi_dev_get_usb_dev(dev), + endpoint, + buffer, + length, + fpi_usb_transfer_cb, + transfer, + timeout); + + return transfer; +} + +/** + * fpi_usb_submit_transfer: + * @transfer: a #fpi_usb_transfer struct + * + * Start a transfer to the device with the provided #fpi_usb_transfer. + * On error, the #fpi_usb_transfer struct will be freed, otherwise it will + * be freed once the callback provided to fpi_usb_fill_bulk_transfer() has + * been called. + * + * Returns: 0 on success, or the same errors as [libusb_submit_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gabb0932601f2c7dad2fee4b27962848ce) + * on failure. + */ +int +fpi_usb_submit_transfer(fpi_usb_transfer *transfer) +{ + int r; + + g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_INVALID_PARAM); + + r = libusb_submit_transfer(transfer->transfer); + if (r < 0) + fpi_usb_transfer_free(transfer); + + return r; +} + +/** + * fpi_usb_cancel_transfer: + * @transfer: a #fpi_usb_transfer struct + * + * Cancel a transfer to the device with the provided #fpi_usb_transfer. + * Note that this will not complete the cancellation, as your transfer + * callback will be called with the `LIBUSB_TRANSFER_CANCELLED` status, + * as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54) + * would. + * + * You should not access anything but the given struct #libusb_transfer + * in the callback before checking whether `LIBUSB_TRANSFER_CANCELLED` has + * been called, as that might cause memory access violations. + * + * Returns: 0 on success, or the same errors as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54) + * on failure. + */ +int +fpi_usb_cancel_transfer(fpi_usb_transfer *transfer) +{ + g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_NOT_FOUND); + + return libusb_cancel_transfer(transfer->transfer); +} diff --git a/libfprint/fpi-usb.h b/libfprint/fpi-usb.h new file mode 100644 index 00000000..822b6124 --- /dev/null +++ b/libfprint/fpi-usb.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 Bastien Nocera + * + * 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 + */ + +#ifndef __FPI_USB_H__ +#define __FPI_USB_H__ + +#include +#include "fpi-dev.h" +#include "fpi-ssm.h" + +/** + * fpi_usb_transfer: + * + * A structure containing the arguments passed to fpi_usb_fill_bulk_transfer() + * to be used with fpi_usb_submit_transfer(). + */ +typedef struct fpi_usb_transfer fpi_usb_transfer; + +/** + * fpi_usb_transfer_cb_fn: + * @transfer: a struct #libusb_transfer + * @dev: the struct #fp_dev on which the operation was performed + * @ssm: the #fpi_ssm state machine + * @user_data: the user data passed to fpi_usb_fill_bulk_transfer() + * + * This callback will be called in response to a libusb bulk transfer + * triggered via fpi_usb_fill_bulk_transfer() finishing. Note that the + * struct #libusb_transfer does not need to be freed, as it will be + * freed after the callback returns, similarly to + * the [LIBUSB_TRANSFER_FREE_TRANSFER flag](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gga1fb47dd0f7c209b60a3609ff0c03d56dacf3f064997b283a14097c9f4d6f8ccc1). + * + * Note that the cancelled status of the transfer should be checked + * first thing, as the @dev, @ssm and @user_data pointers might not + * be pointing to valid values anymore. See fpi_usb_cancel_transfer() + * for more information. + */ +typedef void(*fpi_usb_transfer_cb_fn) (struct libusb_transfer *transfer, + struct fp_dev *dev, + fpi_ssm *ssm, + void *user_data); + +struct libusb_transfer *fpi_usb_alloc(void) __attribute__((returns_nonnull)); + +fpi_usb_transfer *fpi_usb_fill_bulk_transfer (struct fp_dev *dev, + fpi_ssm *ssm, + unsigned char endpoint, + unsigned char *buffer, + int length, + fpi_usb_transfer_cb_fn callback, + void *user_data, + unsigned int timeout); +int fpi_usb_submit_transfer (fpi_usb_transfer *transfer); +int fpi_usb_cancel_transfer (fpi_usb_transfer *transfer); + +#endif diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c index f78ede19..de291f11 100644 --- a/libfprint/fprint-list-udev-rules.c +++ b/libfprint/fprint-list-udev-rules.c @@ -24,10 +24,6 @@ #include "fp_internal.h" static const struct usb_id whitelist_id_table[] = { - /* Unsupported (for now) Elantech finger print readers */ - { .vendor = 0x04f3, .product = 0x0c03 }, - { .vendor = 0x04f3, .product = 0x0c16 }, - { .vendor = 0x04f3, .product = 0x0c26 }, /* Unsupported (for now) Validity Sensors finger print readers */ { .vendor = 0x138a, .product = 0x0090 }, /* Found on e.g. Lenovo T460s */ { .vendor = 0x138a, .product = 0x0091 }, diff --git a/libfprint/fprint.h b/libfprint/fprint.h index be94a540..b9b09092 100644 --- a/libfprint/fprint.h +++ b/libfprint/fprint.h @@ -25,15 +25,24 @@ extern "C" { #endif #include +#include +#include #include +/** + * LIBFPRINT_DEPRECATED: + * + * Expands to the GNU C deprecated attribute if the compiler is `gcc`. When + * called with the `-Wdeprecated-declarations` option, `gcc` will generate warnings + * when deprecated interfaces are used. + */ #define LIBFPRINT_DEPRECATED __attribute__((__deprecated__)) /** * fp_dscv_dev: * * #fp_dscv_dev is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_dscv_dev; @@ -41,7 +50,7 @@ struct fp_dscv_dev; * fp_dscv_print: * * #fp_dscv_print is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_dscv_print; @@ -49,7 +58,7 @@ struct fp_dscv_print; * fp_dev: * * #fp_dev is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_dev; @@ -57,7 +66,7 @@ struct fp_dev; * fp_driver: * * #fp_driver is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_driver; @@ -65,7 +74,7 @@ struct fp_driver; * fp_print_data: * * #fp_print_data is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_print_data; @@ -73,7 +82,7 @@ struct fp_print_data; * fp_img: * * #fp_img is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_img; @@ -128,6 +137,7 @@ const char *fp_driver_get_name(struct fp_driver *drv); const char *fp_driver_get_full_name(struct fp_driver *drv); uint16_t fp_driver_get_driver_id(struct fp_driver *drv); enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv); +int fp_driver_supports_imaging(struct fp_driver *drv); /* Device discovery */ struct fp_dscv_dev **fp_discover_devs(void); @@ -163,11 +173,10 @@ int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print) /** * fp_capture_result: - * Whether a capture failed or completed. - * * @FP_CAPTURE_COMPLETE: Capture completed successfully, the capture data has been returned to the caller. * @FP_CAPTURE_FAIL: Capture failed * + * Whether a capture failed or completed. */ enum fp_capture_result { FP_CAPTURE_COMPLETE = 0, @@ -284,7 +293,7 @@ uint32_t fp_print_data_get_devtype(struct fp_print_data *data); * fp_minutia: * * #fp_minutia is an opaque structure type. You must access it using the - * functions below. + * functions in this section. */ struct fp_minutia; @@ -295,6 +304,7 @@ int fp_img_save_to_file(struct fp_img *img, char *path); void fp_img_standardize(struct fp_img *img); struct fp_img *fp_img_binarize(struct fp_img *img); struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, int *nr_minutiae); +int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y); void fp_img_free(struct fp_img *img); /* Polling and timing */ @@ -304,12 +314,12 @@ void fp_img_free(struct fp_img *img); * @fd: a file descriptor * @events: Event flags to poll for from `` * - * A structure representing a file descriptor and the events to poll + * A structure representing a file descriptor and the @events to poll * for, as returned by fp_get_pollfds(). */ struct fp_pollfd { int fd; - short events; + short int events; }; int fp_handle_events_timeout(struct timeval *timeout); @@ -326,7 +336,7 @@ int fp_get_next_timeout(struct timeval *tv); * event source is added. The @events argument is a flag as defined in * `` such as `POLLIN`, or `POLLOUT`. See fp_set_pollfd_notifiers(). */ -typedef void (*fp_pollfd_added_cb)(int fd, short events); +typedef void (*fp_pollfd_added_cb)(int fd, short int events); /** * fp_pollfd_removed_cb: @@ -348,7 +358,7 @@ void fp_set_debug(int level) LIBFPRINT_DEPRECATED; /** * fp_operation_stop_cb: - * @dev: the #fp_dev device + * @dev: the struct #fp_dev device * @user_data: user data passed to the callback * * Type definition for a function that will be called when fp_async_dev_close(), @@ -359,7 +369,7 @@ typedef void (*fp_operation_stop_cb)(struct fp_dev *dev, void *user_data); /** * fp_img_operation_cb: - * @dev: the #fp_dev device + * @dev: the struct #fp_dev device * @result: an #fp_verify_result for fp_async_verify_start(), or an #fp_capture_result * for fp_async_capture_start(), or a negative value on error * @img: the captured #fp_img if capture or verification was successful @@ -373,7 +383,7 @@ typedef void (*fp_img_operation_cb)(struct fp_dev *dev, int result, /** * fp_dev_open_cb: - * @dev: the #fp_dev device + * @dev: the struct #fp_dev device * @status: 0 on success, or a negative value on error * @user_data: user data passed to the callback * @@ -390,14 +400,15 @@ void fp_async_dev_close(struct fp_dev *dev, fp_operation_stop_cb callback, /** * fp_enroll_stage_cb: - * @dev: the #fp_dev device + * @dev: the struct #fp_dev device * @result: a #fp_enroll_result on success, or a negative value on failure * @print: the enrollment data from the final stage * @img: an #fp_img to free with fp_img_free() * @user_data: user data passed to the callback * * Type definition for a function that will be called when - * fp_async_enroll_start() finishes. + * fp_async_enroll_start() finishes. See fp_enroll_finger_img() for + * the expected behaviour of your program based on the @result. */ typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result, struct fp_print_data *print, struct fp_img *img, void *user_data); @@ -416,7 +427,7 @@ int fp_async_verify_stop(struct fp_dev *dev, fp_operation_stop_cb callback, /** * fp_identify_cb: - * @dev: the #fp_dev device + * @dev: the struct #fp_dev device * @result: a #fp_verify_result on success, or a negative value on error. * @match_offset: the array index of the matched gallery print (if any was found). * Only valid if %FP_VERIFY_MATCH was returned. diff --git a/libfprint/meson.build b/libfprint/meson.build index 8689c9f2..abd00054 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -1,16 +1,29 @@ libfprint_sources = [ 'fp_internal.h', + 'nbis-helpers.h', 'drivers_api.h', - 'async.c', - 'core.c', - 'data.c', - 'drv.c', - 'img.c', - 'imgdev.c', - 'poll.c', - 'sync.c', - 'assembling.c', - 'assembling.h', + 'fpi-async.c', + 'fpi-async.h', + 'fpi-assembling.c', + 'fpi-assembling.h', + 'fpi-core.c', + 'fpi-core.h', + 'fpi-data.c', + 'fpi-data.h', + 'fpi-dev.c', + 'fpi-dev.h', + 'fpi-dev-img.c', + 'fpi-dev-img.h', + 'fpi-img.c', + 'fpi-img.h', + 'fpi-log.h', + 'fpi-ssm.c', + 'fpi-ssm.h', + 'fpi-sync.c', + 'fpi-poll.h', + 'fpi-poll.c', + 'fpi-usb.h', + 'fpi-usb.c', 'drivers/driver_ids.h', ] @@ -30,14 +43,17 @@ nbis_sources = [ 'nbis/bozorth3/bz_sort.c', 'nbis/mindtct/binar.c', 'nbis/mindtct/block.c', + 'nbis/mindtct/chaincod.c', 'nbis/mindtct/contour.c', 'nbis/mindtct/detect.c', 'nbis/mindtct/dft.c', 'nbis/mindtct/free.c', + 'nbis/mindtct/getmin.c', 'nbis/mindtct/globals.c', 'nbis/mindtct/imgutil.c', 'nbis/mindtct/init.c', 'nbis/mindtct/line.c', + 'nbis/mindtct/link.c', 'nbis/mindtct/log.c', 'nbis/mindtct/loop.c', 'nbis/mindtct/maps.c', @@ -50,6 +66,7 @@ nbis_sources = [ 'nbis/mindtct/shape.c', 'nbis/mindtct/sort.c', 'nbis/mindtct/util.c', + 'nbis/mindtct/xytreps.c', ] aeslib = false @@ -62,7 +79,7 @@ foreach driver: drivers drivers_sources += [ 'drivers/upekts.c' ] endif if driver == 'upektc' - drivers_sources += [ 'drivers/upektc.c', 'drivers/upektc.h' ] + drivers_sources += [ 'drivers/upektc.c', 'drivers/upektc.h', 'drivers/upek_proto.c', 'drivers/upek_proto.h' ] endif if driver == 'upeksonly' drivers_sources += [ 'drivers/upeksonly.c', 'drivers/upeksonly.h' ] @@ -118,7 +135,7 @@ foreach driver: drivers drivers_sources += [ 'drivers/vfs5011.c', 'drivers/vfs5011_proto.h' ] endif if driver == 'upektc_img' - drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upektc_img.h' ] + drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upektc_img.h', 'drivers/upek_proto.c', 'drivers/upek_proto.h' ] endif if driver == 'etes603' drivers_sources += [ 'drivers/etes603.c' ] @@ -132,7 +149,7 @@ foreach driver: drivers endforeach if aeslib - drivers_sources += [ 'aeslib.c', 'aeslib.h' ] + drivers_sources += [ 'drivers/aeslib.c', 'drivers/aeslib.h' ] endif if aesx660 drivers_sources += ['drivers/aesx660.c', 'drivers/aesx660.h' ] @@ -143,7 +160,7 @@ endif other_sources = [] if imaging_dep.found() - other_sources += [ 'pixman.c' ] + other_sources += [ 'fpi-img-pixman.c' ] endif libfprint_sources += configure_file(input: 'empty_file', diff --git a/libfprint/nbis-helpers.h b/libfprint/nbis-helpers.h new file mode 100644 index 00000000..eab861e1 --- /dev/null +++ b/libfprint/nbis-helpers.h @@ -0,0 +1,33 @@ +/* + * Helpers to use within the NBIS copy/paste library + * Copyright (C) 2018 Bastien Nocera + * + * 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 + +#define ASSERT_SIZE_MUL(a,b) \ + { \ + gsize dest; \ + g_assert(g_size_checked_mul(&dest, a, b)); \ + } + +#define ASSERT_INT_MUL(a, b) \ + { \ + gsize dest; \ + g_assert(g_size_checked_mul(&dest, a, b)); \ + g_assert(dest < G_MAXINT); \ + } diff --git a/libfprint/nbis/bozorth3/bozorth3.c b/libfprint/nbis/bozorth3/bozorth3.c index 54514e73..0a8b0ff7 100644 --- a/libfprint/nbis/bozorth3/bozorth3.c +++ b/libfprint/nbis/bozorth3/bozorth3.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -89,9 +81,6 @@ identified are necessarily the best available for the purpose. #include #include -static const int verbose_bozorth = 0; -static const int m1_xyt = 0; - /***********************************************************************/ void bz_comp( int npoints, /* INPUT: # of points */ @@ -160,7 +149,7 @@ for ( k = 0; k < npoints - 1; k++ ) { else { double dz; - if ( m1_xyt ) + if ( 0 ) dz = ( 180.0F / PI_SINGLE ) * atanf( (float) -dy / (float) dx ); else dz = ( 180.0F / PI_SINGLE ) * atanf( (float) dy / (float) dx ); @@ -261,7 +250,7 @@ for ( k = 0; k < npoints - 1; k++ ) { if ( table_index == 19999 ) { #ifndef NOVERBOSE - if ( verbose_bozorth ) + if ( 0 ) printf( "bz_comp(): breaking loop to avoid table overflow\n" ); #endif goto COMP_END; @@ -392,7 +381,7 @@ static int * rtp[ ROT_SIZE_1 ]; /* extern int * scolpt[ SCOLPT_SIZE ]; INPUT */ /* extern int * fcolpt[ FCOLPT_SIZE ]; INPUT */ /* extern int colp[ COLP_SIZE_1 ][ COLP_SIZE_2 ]; OUTPUT */ -/* extern int verbose_bozorth; */ +/* extern int 0; */ /* extern FILE * stderr; */ /* extern char * get_progname( void ); */ /* extern char * get_probe_filename( void ); */ @@ -401,6 +390,7 @@ static int * rtp[ ROT_SIZE_1 ]; + st = 1; edge_pair_index = 0; rotptr = &rot[0][0]; @@ -570,7 +560,7 @@ for ( k = 1; k < probe_ptrlist_len; k++ ) { if ( edge_pair_index == 19999 ) { #ifndef NOVERBOSE - if ( verbose_bozorth ) + if ( 0 ) fprintf( stderr, "%s: bz_match(): WARNING: list is full, breaking loop early [p=%s; g=%s]\n", get_progname(), get_probe_filename(), get_gallery_filename() ); #endif @@ -652,13 +642,13 @@ int avv[ AVV_SIZE_1 ][ AVV_SIZE_2 ]; if ( pstruct->nrows < MIN_COMPUTABLE_BOZORTH_MINUTIAE ) { #ifndef NOVERBOSE if ( gstruct->nrows < MIN_COMPUTABLE_BOZORTH_MINUTIAE ) { - if ( verbose_bozorth ) + if ( 0 ) fprintf( stderr, "%s: bz_match_score(): both probe and gallery file have too few minutiae (%d,%d) to compute a real Bozorth match score; min. is %d [p=%s; g=%s]\n", get_progname(), pstruct->nrows, gstruct->nrows, MIN_COMPUTABLE_BOZORTH_MINUTIAE, get_probe_filename(), get_gallery_filename() ); } else { - if ( verbose_bozorth ) + if ( 0 ) fprintf( stderr, "%s: bz_match_score(): probe file has too few minutiae (%d) to compute a real Bozorth match score; min. is %d [p=%s; g=%s]\n", get_progname(), pstruct->nrows, MIN_COMPUTABLE_BOZORTH_MINUTIAE, @@ -672,7 +662,7 @@ if ( pstruct->nrows < MIN_COMPUTABLE_BOZORTH_MINUTIAE ) { if ( gstruct->nrows < MIN_COMPUTABLE_BOZORTH_MINUTIAE ) { #ifndef NOVERBOSE - if ( verbose_bozorth ) + if ( 0 ) fprintf( stderr, "%s: bz_match_score(): gallery file has too few minutiae (%d) to compute a real Bozorth match score; min. is %d [p=%s; g=%s]\n", get_progname(), gstruct->nrows, MIN_COMPUTABLE_BOZORTH_MINUTIAE, @@ -711,7 +701,6 @@ tp = 0; p1 = 0; tot = 0; ftt = 0; -kx = 0; match_score = 0; for ( k = 0; k < np - 1; k++ ) { @@ -765,7 +754,7 @@ for ( k = 0; k < np - 1; k++ ) { } #ifndef NOVERBOSE - if ( verbose_bozorth ) + if ( 0 ) printf( "x1 %d %d %d %d %d %d\n", kx, colp[kx][0], colp[kx][1], colp[kx][2], colp[kx][3], colp[kx][4] ); #endif @@ -827,7 +816,6 @@ for ( k = 0; k < np - 1; k++ ) { - l = 1; t = np + 1; b = kq; @@ -1167,7 +1155,7 @@ for ( k = 0; k < np - 1; k++ ) { if ( ll ) { - if ( m1_xyt ) + if ( 0 ) fi = ( 180.0F / PI_SINGLE ) * atanf( (float) -jj / (float) ll ); else fi = ( 180.0F / PI_SINGLE ) * atanf( (float) jj / (float) ll ); @@ -1187,7 +1175,7 @@ for ( k = 0; k < np - 1; k++ ) { jj += 360; } else { - if ( m1_xyt ) { + if ( 0 ) { if ( jj > 0 ) jj = -90; else @@ -1204,7 +1192,7 @@ for ( k = 0; k < np - 1; k++ ) { if ( kk ) { - if ( m1_xyt ) + if ( 0 ) fi = ( 180.0F / PI_SINGLE ) * atanf( (float) -j / (float) kk ); else fi = ( 180.0F / PI_SINGLE ) * atanf( (float) j / (float) kk ); @@ -1224,7 +1212,7 @@ for ( k = 0; k < np - 1; k++ ) { j += 360; } else { - if ( m1_xyt ) { + if ( 0 ) { if ( j > 0 ) j = -90; else @@ -1611,7 +1599,7 @@ if ( n ) { notfound = 1; #ifndef NOVERBOSE - if ( verbose_bozorth ) { + if ( 0 ) { int * llptr = lptr; printf( "bz_sift(): n: looking for l=%d in [", l ); for ( i = 0; i < lim; i++ ) { @@ -1657,7 +1645,7 @@ if ( t ) { notfound = 1; #ifndef NOVERBOSE - if ( verbose_bozorth ) { + if ( 0 ) { int * llptr = lptr; printf( "bz_sift(): t: looking for kz=%d in [", kz ); for ( i = 0; i < lim; i++ ) { diff --git a/libfprint/nbis/bozorth3/bz_alloc.c b/libfprint/nbis/bozorth3/bz_alloc.c index 5118282a..e4ac9918 100644 --- a/libfprint/nbis/bozorth3/bz_alloc.c +++ b/libfprint/nbis/bozorth3/bz_alloc.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -77,43 +69,6 @@ identified are necessarily the best available for the purpose. /***********************************************************************/ -char * malloc_or_exit( int nbytes, const char * what ) -{ -char * p; - -/* These are now externally defined in bozorth.h */ -/* extern FILE * stderr; */ -/* extern char * get_progname( void ); */ - - -p = malloc( (size_t) nbytes ); -if ( p == CNULL ) { - fprintf( stderr, "%s: ERROR: malloc() of %d bytes for %s failed: %s\n", - get_progname(), - nbytes, - what, - strerror( errno ) - ); - exit(1); -} -return p; -} /***********************************************************************/ /* returns CNULL on error */ -char * malloc_or_return_error( int nbytes, const char * what ) -{ -char * p; - -p = malloc( (size_t) nbytes ); -if ( p == CNULL ) { - fprintf( stderr, "%s: ERROR: malloc() of %d bytes for %s failed: %s\n", - get_progname(), - nbytes, - what, - strerror( errno ) - ); - return(CNULL); -} -return p; -} diff --git a/libfprint/nbis/bozorth3/bz_drvrs.c b/libfprint/nbis/bozorth3/bz_drvrs.c index 03f7171c..8904f0fc 100644 --- a/libfprint/nbis/bozorth3/bz_drvrs.c +++ b/libfprint/nbis/bozorth3/bz_drvrs.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -177,47 +169,3 @@ return bz_match_score( np, pstruct, gstruct ); /**************************************************************************/ -int bozorth_main( - struct xyt_struct * pstruct, - struct xyt_struct * gstruct - ) -{ -int ms; -int np; -int probe_len; -int gallery_len; - - - -#ifdef DEBUG - printf( "PROBE_INIT() called\n" ); -#endif -probe_len = bozorth_probe_init( pstruct ); - - -#ifdef DEBUG - printf( "GALLERY_INIT() called\n" ); -#endif -gallery_len = bozorth_gallery_init( gstruct ); - - -#ifdef DEBUG - printf( "BZ_MATCH() called\n" ); -#endif -np = bz_match( probe_len, gallery_len ); - - -#ifdef DEBUG - printf( "BZ_MATCH() returned %d edge pairs\n", np ); - printf( "COMPUTE() called\n" ); -#endif -ms = bz_match_score( np, pstruct, gstruct ); - - -#ifdef DEBUG - printf( "COMPUTE() returned %d\n", ms ); -#endif - - -return ms; -} diff --git a/libfprint/nbis/bozorth3/bz_gbls.c b/libfprint/nbis/bozorth3/bz_gbls.c index 0ecd081d..dd828dc3 100644 --- a/libfprint/nbis/bozorth3/bz_gbls.c +++ b/libfprint/nbis/bozorth3/bz_gbls.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -91,23 +83,45 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ]; /**************************************************************************/ /* Globals used significantly by sift() */ /**************************************************************************/ -int rq[ RQ_SIZE ] = {}; -int tq[ TQ_SIZE ] = {}; -int zz[ ZZ_SIZE ] = {}; +#ifdef TARGET_OS + int rq[ RQ_SIZE ]; + int tq[ TQ_SIZE ]; + int zz[ ZZ_SIZE ]; -int rx[ RX_SIZE ] = {}; -int mm[ MM_SIZE ] = {}; -int nn[ NN_SIZE ] = {}; + int rx[ RX_SIZE ]; + int mm[ MM_SIZE ]; + int nn[ NN_SIZE ]; -int qq[ QQ_SIZE ] = {}; + int qq[ QQ_SIZE ]; -int rk[ RK_SIZE ] = {}; + int rk[ RK_SIZE ]; -int cp[ CP_SIZE ] = {}; -int rp[ RP_SIZE ] = {}; + int cp[ CP_SIZE ]; + int rp[ RP_SIZE ]; -int rf[RF_SIZE_1][RF_SIZE_2] = {}; -int cf[CF_SIZE_1][CF_SIZE_2] = {}; + int rf[RF_SIZE_1][RF_SIZE_2]; + int cf[CF_SIZE_1][CF_SIZE_2]; -int y[20000] = {}; + int y[20000]; +#else + int rq[ RQ_SIZE ] = {}; + int tq[ TQ_SIZE ] = {}; + int zz[ ZZ_SIZE ] = {}; + + int rx[ RX_SIZE ] = {}; + int mm[ MM_SIZE ] = {}; + int nn[ NN_SIZE ] = {}; + + int qq[ QQ_SIZE ] = {}; + + int rk[ RK_SIZE ] = {}; + + int cp[ CP_SIZE ] = {}; + int rp[ RP_SIZE ] = {}; + + int rf[RF_SIZE_1][RF_SIZE_2] = {}; + int cf[CF_SIZE_1][CF_SIZE_2] = {}; + + int y[20000] = {}; +#endif diff --git a/libfprint/nbis/bozorth3/bz_io.c b/libfprint/nbis/bozorth3/bz_io.c index e5dc3bb9..5d2f8634 100644 --- a/libfprint/nbis/bozorth3/bz_io.c +++ b/libfprint/nbis/bozorth3/bz_io.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -57,6 +49,9 @@ identified are necessarily the best available for the purpose. MODIFICATIONS: Michael D. Garris (NIST) Stan Janet (NIST) DATE: 09/21/2004 + UPDATED: 01/11/2012 by Kenneth Ko + UPDATED: 03/08/2012 by Kenneth Ko + UPDATED: 07/10/2014 by Kenneth Ko Contains routines responsible for supporting command line processing, file and data input to, and output from the @@ -100,50 +95,7 @@ identified are necessarily the best available for the purpose. #include #include -static const int verbose_load = 0; -static const int verbose_main = 0; - /***********************************************************************/ -int parse_line_range( const char * sb, int * begin, int * end ) -{ -int ib, ie; -char * se; - - -if ( ! isdigit(*sb) ) - return -1; -ib = atoi( sb ); - -se = strchr( sb, '-' ); -if ( se != (char *) NULL ) { - se++; - if ( ! isdigit(*se) ) - return -2; - ie = atoi( se ); -} else { - ie = ib; -} - -if ( ib <= 0 ) { - if ( ie <= 0 ) { - return -3; - } else { - return -4; - } -} - -if ( ie <= 0 ) { - return -5; -} - -if ( ib > ie ) - return -6; - -*begin = ib; -*end = ie; - -return 0; -} /***********************************************************************/ @@ -153,25 +105,10 @@ static char * pfile; static char * gfile; /***********************************************************************/ -void set_progname( int use_pid, char * basename, pid_t pid ) -{ -if ( use_pid ) - sprintf( program_buffer, "%s pid %ld", basename, (long) pid ); -else - sprintf( program_buffer, "%s", basename ); -} /***********************************************************************/ -void set_probe_filename( char * filename ) -{ -pfile = filename; -} /***********************************************************************/ -void set_gallery_filename( char * filename ) -{ -gfile = filename; -} /***********************************************************************/ char * get_progname( void ) @@ -192,171 +129,15 @@ return gfile; } /***********************************************************************/ -char * get_next_file( - char * fixed_file, - FILE * list_fp, - FILE * mates_fp, - int * done_now, - int * done_afterwards, - char * line, - int argc, - char ** argv, - int * optind, - - int * lineno, - int begin, - int end - ) -{ -char * p; -FILE * fp; - - - -if ( fixed_file != (char *) NULL ) { - if ( verbose_main ) - fprintf( stderr, "returning fixed filename: %s\n", fixed_file ); - return fixed_file; -} - - -fp = list_fp; -if ( fp == (FILE *) NULL ) - fp = mates_fp; -if ( fp != (FILE *) NULL ) { - while (1) { - if ( fgets( line, MAX_LINE_LENGTH, fp ) == (char *) NULL ) { - *done_now = 1; - if ( verbose_main ) - fprintf( stderr, "returning NULL -- reached EOF\n" ); - return (char *) NULL; - } - ++*lineno; - - if ( begin <= 0 ) /* no line number range was specified */ - break; - if ( *lineno > end ) { - *done_now = 1; - if ( verbose_main ) - fprintf( stderr, "returning NULL -- current line (%d) > end line (%d)\n", - *lineno, end ); - return (char *) NULL; - } - if ( *lineno >= begin ) { - break; - } - /* Otherwise ( *lineno < begin ) so read another line */ - } - - p = strchr( line, '\n' ); - if ( p == (char *) NULL ) { - *done_now = 1; - if ( verbose_main ) - fprintf( stderr, "returning NULL -- missing newline character\n" ); - return (char *) NULL; - } - *p = '\0'; - - p = line; - if ( verbose_main ) - fprintf( stderr, "returning filename from next line: %s\n", p ); - return p; -} - - -p = argv[*optind]; -++*optind; -if ( *optind >= argc ) - *done_afterwards = 1; -if ( verbose_main ) - fprintf( stderr, "returning next argv: %s [done_afterwards=%d]\n", p, *done_afterwards ); -return p; -} /***********************************************************************/ /* returns CNULL on error */ -char * get_score_filename( const char * outdir, const char * listfile ) -{ -const char * basename; -int baselen; -int dirlen; -int extlen; -char * outfile; - -/* These are now exteranlly defined in bozorth.h */ -/* extern FILE * stderr; */ -/* extern char * get_progname( void ); */ - - - -basename = strrchr( listfile, '/' ); -if ( basename == CNULL ) { - basename = listfile; -} else { - ++basename; -} -baselen = strlen( basename ); -if ( baselen == 0 ) { - fprintf( stderr, "%s: ERROR: couldn't find basename of %s\n", get_progname(), listfile ); - return(CNULL); -} -dirlen = strlen( outdir ); -if ( dirlen == 0 ) { - fprintf( stderr, "%s: ERROR: illegal output directory %s\n", get_progname(), outdir ); - return(CNULL); -} - -extlen = strlen( SCOREFILE_EXTENSION ); -outfile = malloc_or_return_error( dirlen + baselen + extlen + 2, "output filename" ); -if ( outfile == CNULL) - return(CNULL); - -sprintf( outfile, "%s/%s%s", outdir, basename, SCOREFILE_EXTENSION ); - -return outfile; -} /***********************************************************************/ -char * get_score_line( - const char * probe_file, - const char * gallery_file, - int n, - int static_flag, - const char * fmt - ) -{ -int nchars; -char * bufptr; -static char linebuf[1024]; - -nchars = 0; -bufptr = &linebuf[0]; -while ( *fmt ) { - if ( nchars++ > 0 ) - *bufptr++ = ' '; - switch ( *fmt++ ) { - case 's': - sprintf( bufptr, "%d", n ); - break; - case 'p': - sprintf( bufptr, "%s", probe_file ); - break; - case 'g': - sprintf( bufptr, "%s", gallery_file ); - break; - default: - return (char *) NULL; - } - bufptr = strchr( bufptr, '\0' ); -} -*bufptr++ = '\n'; -*bufptr = '\0'; - -return static_flag ? &linebuf[0] : strdup( linebuf ); -} /************************************************************************ -Load a 3-4 column (X,Y,T[,Q]) set of minutiae from the specified file. +Load a 3-4 column (X,Y,T[,Q]) set of minutiae from the specified file +and return a XYT sturcture. Row 3's value is an angle which is normalized to the interval (-180,180]. A maximum of MAX_BOZORTH_MINUTIAE minutiae can be returned -- fewer if "DEFAULT_BOZORTH_MINUTIAE" is smaller. If the file contains more minutiae than are @@ -364,241 +145,14 @@ to be returned, the highest-quality minutiae are returned. *************************************************************************/ /***********************************************************************/ -struct xyt_struct * bz_load( const char * xyt_file ) -{ -int nminutiae; -int j; -int m; -int nargs_expected; -FILE * fp; -struct xyt_struct * s; -int * xptr; -int * yptr; -int * tptr; -int * qptr; -struct minutiae_struct c[MAX_FILE_MINUTIAE]; -int xvals_lng[MAX_FILE_MINUTIAE], /* Temporary lists to store all the minutaie from a file */ - yvals_lng[MAX_FILE_MINUTIAE], - tvals_lng[MAX_FILE_MINUTIAE], - qvals_lng[MAX_FILE_MINUTIAE]; -int order[MAX_FILE_MINUTIAE]; /* The ranked order, after sort, for each index */ -int xvals[MAX_BOZORTH_MINUTIAE], /* Temporary lists to hold input coordinates */ - yvals[MAX_BOZORTH_MINUTIAE], - tvals[MAX_BOZORTH_MINUTIAE], - qvals[MAX_BOZORTH_MINUTIAE]; -char xyt_line[ MAX_LINE_LENGTH ]; -/* This is now externally defined in bozorth.h */ -/* extern FILE * stderr; */ - - - -#define C1 0 -#define C2 1 - - - -fp = fopen( xyt_file, "r" ); -if ( fp == (FILE *) NULL ) { - fprintf( stderr, "%s: ERROR: fopen() of minutiae file \"%s\" failed: %s\n", - get_progname(), xyt_file, strerror(errno) ); - return XYT_NULL; -} - -nminutiae = 0; -nargs_expected = 0; -while ( fgets( xyt_line, sizeof xyt_line, fp ) != CNULL ) { - - m = sscanf( xyt_line, "%d %d %d %d", - &xvals_lng[nminutiae], - &yvals_lng[nminutiae], - &tvals_lng[nminutiae], - &qvals_lng[nminutiae] ); - if ( nminutiae == 0 ) { - if ( m != 3 && m != 4 ) { - fprintf( stderr, "%s: ERROR: sscanf() failed on line %u in minutiae file \"%s\"\n", - get_progname(), nminutiae+1, xyt_file ); - return XYT_NULL; - } - nargs_expected = m; - } else { - if ( m != nargs_expected ) { - fprintf( stderr, "%s: ERROR: inconsistent argument count on line %u of minutiae file \"%s\"\n", - get_progname(), nminutiae+1, xyt_file ); - return XYT_NULL; - } - } - if ( m == 3 ) - qvals_lng[nminutiae] = 1; - - - - if ( tvals_lng[nminutiae] > 180 ) - tvals_lng[nminutiae] -= 360; - - /* - if ( C1 ) { - c[nminutiae].col[0] = xvals_lng[nminutiae]; - c[nminutiae].col[1] = yvals_lng[nminutiae]; - c[nminutiae].col[2] = tvals_lng[nminutiae]; - c[nminutiae].col[3] = qvals_lng[nminutiae]; - } - */ - - ++nminutiae; - if ( nminutiae == MAX_FILE_MINUTIAE ) - break; -} - -if ( fclose(fp) != 0 ) { - fprintf( stderr, "%s: ERROR: fclose() of minutiae file \"%s\" failed: %s\n", - get_progname(), xyt_file, strerror(errno) ); - return XYT_NULL; -} - - - - -if ( nminutiae > DEFAULT_BOZORTH_MINUTIAE ) { - if ( verbose_load ) - fprintf( stderr, "%s: WARNING: bz_load(): trimming minutiae to the %d of highest quality\n", - get_progname(), DEFAULT_BOZORTH_MINUTIAE ); - - if ( verbose_load ) - fprintf( stderr, "Before quality sort:\n" ); - if ( sort_order_decreasing( qvals_lng, nminutiae, order )) { - fprintf( stderr, "%s: ERROR: sort failed and returned on error\n", get_progname()); - return XYT_NULL; - } - - for ( j = 0; j < nminutiae; j++ ) { - - if ( verbose_load ) - fprintf( stderr, " %3d: %3d %3d %3d ---> order = %3d\n", - j, xvals_lng[j], yvals_lng[j], qvals_lng[j], order[j] ); - - if ( j == 0 ) - continue; - if ( qvals_lng[order[j]] > qvals_lng[order[j-1]] ) { - fprintf( stderr, "%s: ERROR: sort failed: j=%d; qvals_lng[%d] > qvals_lng[%d]\n", - get_progname(), j, order[j], order[j-1] ); - return XYT_NULL; - } - } - - - if ( verbose_load ) - fprintf( stderr, "\nAfter quality sort:\n" ); - for ( j = 0; j < DEFAULT_BOZORTH_MINUTIAE; j++ ) { - xvals[j] = xvals_lng[order[j]]; - yvals[j] = yvals_lng[order[j]]; - tvals[j] = tvals_lng[order[j]]; - qvals[j] = qvals_lng[order[j]]; - if ( verbose_load ) - fprintf( stderr, " %3d: %3d %3d %3d\n", j, xvals[j], yvals[j], qvals[j] ); - } - - - if ( C1 ) { - if ( verbose_load ) - fprintf( stderr, "\nAfter qsort():\n" ); - qsort( (void *) &c, (size_t) nminutiae, sizeof(struct minutiae_struct), sort_quality_decreasing ); - for ( j = 0; j < nminutiae; j++ ) { - - if ( verbose_load ) - fprintf( stderr, "Q %3d: %3d %3d %3d\n", - j, c[j].col[0], c[j].col[1], c[j].col[3] ); - - if ( j > 0 && c[j].col[3] > c[j-1].col[3] ) { - fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[3] > c[%d].col[3]\n", - get_progname(), j, j-1 ); - return XYT_NULL; - } - } - } - - if ( verbose_load ) - fprintf( stderr, "\n" ); - - xptr = xvals; - yptr = yvals; - tptr = tvals; - qptr = qvals; - - nminutiae = DEFAULT_BOZORTH_MINUTIAE; -} else{ - xptr = xvals_lng; - yptr = yvals_lng; - tptr = tvals_lng; - qptr = qvals_lng; -} - - - -for ( j=0; j < nminutiae; j++ ) { - c[j].col[0] = xptr[j]; - c[j].col[1] = yptr[j]; - c[j].col[2] = tptr[j]; - c[j].col[3] = qptr[j]; -} -qsort( (void *) &c, (size_t) nminutiae, sizeof(struct minutiae_struct), sort_x_y ); - - - - -if ( verbose_load ) { - fprintf( stderr, "\nSorted on increasing x, then increasing y\n" ); - for ( j = 0; j < nminutiae; j++ ) { - fprintf( stderr, "%d : %3d, %3d, %3d, %3d\n", j, c[j].col[0], c[j].col[1], c[j].col[2], c[j].col[3] ); - if ( j > 0 ) { - if ( c[j].col[0] < c[j-1].col[0] ) { - fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[0]=%d > c[%d].col[0]=%d\n", - get_progname(), - j, c[j].col[0], j-1, c[j-1].col[0] - ); - return XYT_NULL; - } - if ( c[j].col[0] == c[j-1].col[0] && c[j].col[1] < c[j-1].col[1] ) { - fprintf( stderr, "%s: ERROR: sort failed: c[%d].col[0]=%d == c[%d].col[0]=%d; c[%d].col[0]=%d == c[%d].col[0]=%d\n", - get_progname(), - j, c[j].col[0], j-1, c[j-1].col[0], - j, c[j].col[1], j-1, c[j-1].col[1] - ); - return XYT_NULL; - } - } - } -} - - - -s = (struct xyt_struct *) malloc( sizeof( struct xyt_struct ) ); -if ( s == XYT_NULL ) { - fprintf( stderr, "%s: ERROR: malloc() failure while loading minutiae file \"%s\" failed: %s\n", - get_progname(), - xyt_file, - strerror(errno) - ); - return XYT_NULL; -} - - - -for ( j = 0; j < nminutiae; j++ ) { - s->xcol[j] = c[j].col[0]; - s->ycol[j] = c[j].col[1]; - s->thetacol[j] = c[j].col[2]; -} -s->nrows = nminutiae; - - - - -if ( verbose_load ) - fprintf( stderr, "Loaded %s\n", xyt_file ); - -return s; -} +/************************************************************************ +Load a XYTQ structure and return a XYT struct. +Row 3's value is an angle which is normalized to the interval (-180,180]. +A maximum of MAX_BOZORTH_MINUTIAE minutiae can be returned -- fewer if +"DEFAULT_BOZORTH_MINUTIAE" is smaller. If the file contains more minutiae than are +to be returned, the highest-quality minutiae are returned. +*************************************************************************/ /***********************************************************************/ #ifdef PARALLEL_SEARCH @@ -617,13 +171,13 @@ tv.tv_usec = 0; retval = select( fd+1, &rfds, NULL, NULL, &tv ); if ( retval < 0 ) { - perror( "select() failed" ); - return 0; + perror( "select() failed" ); + return 0; } if ( FD_ISSET( fd, &rfds ) ) { - /*fprintf( stderr, "data is available now.\n" );*/ - return 1; + /*fprintf( stderr, "data is available now.\n" );*/ + return 1; } /* fprintf( stderr, "no data is available\n" ); */ diff --git a/libfprint/nbis/bozorth3/bz_sort.c b/libfprint/nbis/bozorth3/bz_sort.c index 01371e5b..b51a82ed 100644 --- a/libfprint/nbis/bozorth3/bz_sort.c +++ b/libfprint/nbis/bozorth3/bz_sort.c @@ -1,51 +1,43 @@ -/****************************************************************************** - -This file is part of the Export Control subset of the United States NIST -Biometric Image Software (NBIS) distribution: - http://fingerprint.nist.gov/NBIS/index.html - -It is our understanding that this falls within ECCN 3D980, which covers -software associated with the development, production or use of certain -equipment controlled in accordance with U.S. concerns about crime control -practices in specific countries. - -Therefore, this file should not be exported, or made available on fileservers, -except as allowed by U.S. export control laws. - -Do not remove this notice. - -******************************************************************************/ - -/* NOTE: Despite the above notice (which I have not removed), this file is - * being legally distributed within libfprint; the U.S. Export Administration - * Regulations do not place export restrictions upon distribution of - * "publicly available technology and software", as stated in EAR section - * 734.3(b)(3)(i). libfprint qualifies as publicly available technology as per - * the definition in section 734.7(a)(1). - * - * For further information, see https://fprint.freedesktop.org/us-export-control.html - */ - /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -78,23 +70,10 @@ identified are necessarily the best available for the purpose. #include /* These are now externally defined in bozorth.h */ +/* extern FILE * stderr; */ /* extern char * get_progname( void ); */ /***********************************************************************/ -int sort_quality_decreasing( const void * a, const void * b ) -{ -struct minutiae_struct * af; -struct minutiae_struct * bf; - -af = (struct minutiae_struct *) a; -bf = (struct minutiae_struct *) b; - -if ( af->col[3] > bf->col[3] ) - return -1; -if ( af->col[3] < bf->col[3] ) - return 1; -return 0; -} /***********************************************************************/ int sort_x_y( const void * a, const void * b ) @@ -124,67 +103,18 @@ qsort_decreasing() - quicksort an array of integers in decreasing and Ted Zwiesler, 1986] ********************************************************/ /* Used by custom quicksort code below */ -static int stack[BZ_STACKSIZE]; -static int * stack_pointer = stack; /***********************************************************************/ /* return values: 0 == successful, 1 == error */ -static int popstack( int *popval ) -{ -if ( --stack_pointer < stack ) { - fprintf( stderr, "%s: ERROR: popstack(): stack underflow\n", get_progname() ); - return 1; -} - -*popval = *stack_pointer; -return 0; -} /***********************************************************************/ /* return values: 0 == successful, 1 == error */ -static int pushstack( int position ) -{ -*stack_pointer++ = position; -if ( stack_pointer > ( stack + BZ_STACKSIZE ) ) { - fprintf( stderr, "%s: ERROR: pushstack(): stack overflow\n", get_progname() ); - return 1; -} -return 0; -} /***********************************************************************/ /******************************************************************* select_pivot() selects a pivot from a list being sorted using the Singleton Method. *******************************************************************/ -static int select_pivot( struct cell v[], int left, int right ) -{ -int midpoint; - - -midpoint = ( left + right ) / 2; -if ( v[left].index <= v[midpoint].index ) { - if ( v[midpoint].index <= v[right].index ) { - return midpoint; - } else { - if ( v[right].index > v[left].index ) { - return right; - } else { - return left; - } - } -} else { - if ( v[left].index < v[right].index ) { - return left; - } else { - if ( v[right].index < v[midpoint].index ) { - return midpoint; - } else { - return right; - } - } -} -} /***********************************************************************/ /******************************************************** @@ -192,41 +122,6 @@ partition_dec() Inputs a pivot element making comparisons and swaps with other elements in a list, until pivot resides at its correct position in the list. ********************************************************/ -static void partition_dec( struct cell v[], int *llen, int *rlen, int *ll, int *lr, int *rl, int *rr, int p, int l, int r ) -{ -#define iswap(a,b) { int itmp = (a); a = (b); b = itmp; } - -*ll = l; -*rr = r; -while ( 1 ) { - if ( l < p ) { - if ( v[l].index < v[p].index ) { - iswap( v[l].index, v[p].index ) - iswap( v[l].item, v[p].item ) - p = l; - } else { - l++; - } - } else { - if ( r > p ) { - if ( v[r].index > v[p].index ) { - iswap( v[r].index, v[p].index ) - iswap( v[r].item, v[p].item ) - p = r; - l++; - } else { - r--; - } - } else { - *lr = p - 1; - *rl = p + 1; - *llen = *lr - *ll + 1; - *rlen = *rr - *rl + 1; - break; - } - } -} -} /***********************************************************************/ /******************************************************** @@ -236,80 +131,6 @@ sorted, a left subscript pointing to where the sort is to begin in the index ar subscript where to end. This module invokes a decreasing quick-sort sorting the index array from l to r. ********************************************************/ /* return values: 0 == successful, 1 == error */ -static int qsort_decreasing( struct cell v[], int left, int right ) -{ -int pivot; -int llen, rlen; -int lleft, lright, rleft, rright; - - -if ( pushstack( left )) - return 1; -if ( pushstack( right )) - return 2; -while ( stack_pointer != stack ) { - if (popstack(&right)) - return 3; - if (popstack(&left )) - return 4; - if ( right - left > 0 ) { - pivot = select_pivot( v, left, right ); - partition_dec( v, &llen, &rlen, &lleft, &lright, &rleft, &rright, pivot, left, right ); - if ( llen > rlen ) { - if ( pushstack( lleft )) - return 5; - if ( pushstack( lright )) - return 6; - if ( pushstack( rleft )) - return 7; - if ( pushstack( rright )) - return 8; - } else{ - if ( pushstack( rleft )) - return 9; - if ( pushstack( rright )) - return 10; - if ( pushstack( lleft )) - return 11; - if ( pushstack( lright )) - return 12; - } - } -} -return 0; -} /***********************************************************************/ /* return values: 0 == successful, 1 == error */ -int sort_order_decreasing( - int values[], /* INPUT: the unsorted values themselves */ - int num, /* INPUT: the number of values */ - int order[] /* OUTPUT: the order for each of the values if sorted */ - ) -{ -int i; -struct cell * cells; - - -cells = (struct cell *) malloc( num * sizeof(struct cell) ); -if ( cells == (struct cell *) NULL ){ - fprintf( stderr, "%s: ERROR: malloc(): struct cell\n", get_progname() ); - return 1; -} - -for( i = 0; i < num; i++ ) { - cells[i].index = values[i]; - cells[i].item = i; -} - -if ( qsort_decreasing( cells, 0, num-1 ) < 0) - return 2; - -for( i = 0; i < num; i++ ) { - order[i] = cells[i].item; -} - -free( (void *) cells ); - -return 0; -} diff --git a/libfprint/nbis/include/bozorth.h b/libfprint/nbis/include/bozorth.h index dbac4094..08ec4b1c 100644 --- a/libfprint/nbis/include/bozorth.h +++ b/libfprint/nbis/include/bozorth.h @@ -1,23 +1,43 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -163,7 +183,7 @@ struct cell { }; /**************************************************************************/ -/* In BZ_IO : Supports the loading and manipulation of XYT data */ +/* In BZ_IO : Supports the loading and manipulation of XYT and XYTQ data */ /**************************************************************************/ #define MAX_FILE_MINUTIAE 1000 /* bz_load() */ @@ -174,7 +194,17 @@ struct xyt_struct { int thetacol[ MAX_BOZORTH_MINUTIAE ]; }; +struct xytq_struct { + int nrows; + int xcol[ MAX_FILE_MINUTIAE ]; + int ycol[ MAX_FILE_MINUTIAE ]; + int thetacol[ MAX_FILE_MINUTIAE ]; + int qualitycol[ MAX_FILE_MINUTIAE ]; +}; + + #define XYT_NULL ( (struct xyt_struct *) NULL ) /* bz_load() */ +#define XYTQ_NULL ( (struct xytq_struct *) NULL ) /* bz_load() */ /**************************************************************************/ @@ -187,6 +217,8 @@ struct xyt_struct { /**************************************************************************/ /* Globals supporting command line options */ extern int verbose_threshold; +/* Global supporting error reporting */ +extern FILE *stderr; /**************************************************************************/ /* In: BZ_GBLS.C */ @@ -247,6 +279,7 @@ extern char *get_next_file(char *, FILE *, FILE *, int *, int *, char *, extern char *get_score_filename(const char *, const char *); extern char *get_score_line(const char *, const char *, int, int, const char *); extern struct xyt_struct *bz_load(const char *); +extern struct xyt_struct *bz_prune(struct xytq_struct *, int); extern int fd_readable(int); /* In: BZ_SORT.C */ extern int sort_quality_decreasing(const void *, const void *); diff --git a/libfprint/nbis/include/bz_array.h b/libfprint/nbis/include/bz_array.h index 19b7da09..296f6746 100644 --- a/libfprint/nbis/include/bz_array.h +++ b/libfprint/nbis/include/bz_array.h @@ -1,23 +1,43 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ diff --git a/libfprint/nbis/include/defs.h b/libfprint/nbis/include/defs.h index 1e982d04..f2953d36 100644 --- a/libfprint/nbis/include/defs.h +++ b/libfprint/nbis/include/defs.h @@ -1,23 +1,43 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -53,7 +73,6 @@ identified are necessarily the best available for the purpose. #define min(a, b) ((a) < (b) ? (a) : (b)) #define sround(x) ((int) (((x)<0) ? (x)-0.5 : (x)+0.5)) #define sround_uint(x) ((unsigned int) (((x)<0) ? (x)-0.5 : (x)+0.5)) -#define xor(a, b) (!(a && b) && (a || b)) #define align_to_16(_v_) ((((_v_)+15)>>4)<<4) #define align_to_32(_v_) ((((_v_)+31)>>5)<<5) #ifndef CHUNKS diff --git a/libfprint/nbis/include/lfs.h b/libfprint/nbis/include/lfs.h index 9ff01b22..ae7aee5c 100644 --- a/libfprint/nbis/include/lfs.h +++ b/libfprint/nbis/include/lfs.h @@ -1,23 +1,43 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ @@ -33,6 +53,9 @@ identified are necessarily the best available for the purpose. Comments added to guide changes to blocksize or number of detected directions. UPDATED: 03/11/2005 by MDG + UPDATED: 01/31/2008 by Kenneth Ko + UPDATED: 09/04/2008 by Kenneth Ko + UPDATED: 01/11/2012 by Kenneth Ko FILE: LFS.H @@ -160,7 +183,7 @@ typedef struct shape{ /* Parameters used by LFS for setting thresholds and */ /* defining testing criterion. */ -typedef struct lfsparms{ +typedef struct g_lfsparms{ /* Image Controls */ int pad_value; int join_line_radius; @@ -236,8 +259,6 @@ typedef struct lfsparms{ int pores_steps_bwd; double pores_min_dist2; double pores_max_ratio; - int remove_perimeter_pts; - int min_pp_distance; /* Ridge Counting Controls */ int max_nbrs; @@ -382,7 +403,7 @@ typedef struct lfsparms{ /* Thresholds and factors used by HO39. Renamed */ /* here to give more meaning. */ /* HO39 Name=Value */ -/* Minimum DFT power allowable in any one direction. */ +/* Minimum DFT power allowable in any one direction. */ #define POWMAX_MIN 100000.0 /* thrhf=1e5f */ /* Minimum normalized power allowable in any one */ @@ -587,9 +608,6 @@ typedef struct lfsparms{ /* contour points to be considered a pore. */ #define PORES_MAX_RATIO 2.25 -/* Points which are closer than this distance to scan perimeter will be removed */ -#define PERIMETER_PTS_DISTANCE 10 - /***** RIDGE COUNTING CONSTANTS *****/ @@ -689,15 +707,24 @@ typedef struct lfsparms{ /*************************************************************************/ /* binar.c */ +extern int binarize(unsigned char **, int *, int *, + unsigned char *, const int, const int, + int *, const int, const int, + const ROTGRIDS *, const LFSPARMS *); extern int binarize_V2(unsigned char **, int *, int *, unsigned char *, const int, const int, int *, const int, const int, const ROTGRIDS *, const LFSPARMS *); +extern int binarize_image(unsigned char **, int *, int *, + unsigned char *, const int, const int, + const int *, const int, const int, const int, + const ROTGRIDS *, const int); extern int binarize_image_V2(unsigned char **, int *, int *, unsigned char *, const int, const int, const int *, const int, const int, const int, const ROTGRIDS *); extern int dirbinarize(const unsigned char *, const int, const ROTGRIDS *); +extern int isobinarize(unsigned char *, const int, const int, const int); /* block.c */ extern int block_offsets(int **, int *, int *, const int, const int, @@ -709,9 +736,12 @@ extern int find_valid_block(int *, int *, int *, int *, int *, const int, const int); extern void set_margin_blocks(int *, const int, const int, const int); +/* chaincod.c */ +extern int chain_code_loop(int **, int *, const int *, const int *, const int); +extern int is_chain_clockwise(const int *, const int, const int); + /* contour.c */ -int allocate_contour(int **ocontour_x, int **ocontour_y, - int **ocontour_ex, int **ocontour_ey, const int ncontour); +extern int allocate_contour(int **, int **, int **, int **, const int); extern void free_contour(int *, int *, int *, int *); extern int get_high_curvature_contour(int **, int **, int **, int **, int *, const int, const int, const int, const int, const int, @@ -726,6 +756,11 @@ extern int trace_contour(int **, int **, int **, int **, int *, extern int search_contour(const int, const int, const int, const int, const int, const int, const int, const int, unsigned char *, const int, const int); +extern int next_contour_pixel(int *, int *, int *, int *, + const int, const int, const int, const int, const int, + unsigned char *, const int, const int); +extern int start_scan_nbr(const int, const int, const int, const int); +extern int next_scan_nbr(const int, const int); extern int min_contour_theta(int *, double *, const int, const int *, const int *, const int); extern void contour_limits(int *, int *, int *, int *, const int *, @@ -734,18 +769,29 @@ extern void fix_edge_pixel_pair(int *, int *, int *, int *, unsigned char *, const int, const int); /* detect.c */ -extern int get_minutiae(MINUTIAE **, int **, int **, int **, - int **, int **, int *, int *, - unsigned char **, int *, int *, int *, - unsigned char *, const int, const int, - const int, const double, const LFSPARMS *); +extern int lfs_detect_minutiae( MINUTIAE **, + int **, int **, int *, int *, + unsigned char **, int *, int *, + unsigned char *, const int, const int, + const LFSPARMS *); + +extern int lfs_detect_minutiae_V2(MINUTIAE **, + int **, int **, int **, int **, int *, int *, + unsigned char **, int *, int *, + unsigned char *, const int, const int, + const LFSPARMS *); /* dft.c */ extern int dft_dir_powers(double **, unsigned char *, const int, const int, const int, const DFTWAVES *, const ROTGRIDS *); +extern void sum_rot_block_rows(int *, const unsigned char *, const int *, + const int); +extern void dft_power(double *, const int *, const DFTWAVE *, const int); extern int dft_power_stats(int *, double *, int *, double *, double **, const int, const int, const int); +extern void get_max_norm(double *, int *, double *, const double *, const int); +extern int sort_dft_waves(int *, const double *, const double *, const int); /* free.c */ extern void free_dir2rad(DIR2RAD *); @@ -753,6 +799,13 @@ extern void free_dftwaves(DFTWAVES *); extern void free_rotgrids(ROTGRIDS *); extern void free_dir_powers(double **, const int); +/* getmin.c */ +extern int get_minutiae(MINUTIAE **, int **, int **, int **, + int **, int **, int *, int *, + unsigned char **, int *, int *, int *, + unsigned char *, const int, const int, + const int, const double, const LFSPARMS *); + /* imgutil.c */ extern void bits_6to8(unsigned char *, const int, const int); extern void bits_8to6(unsigned char *, const int, const int); @@ -771,15 +824,41 @@ extern int search_in_direction(int *, int *, int *, int *, const int, /* init.c */ extern int init_dir2rad(DIR2RAD **, const int); extern int init_dftwaves(DFTWAVES **, const double *, const int, const int); +extern int get_max_padding(const int, const int, const int, const int); extern int get_max_padding_V2(const int, const int, const int, const int); extern int init_rotgrids(ROTGRIDS **, const int, const int, const int, const double, const int, const int, const int, const int); extern int alloc_dir_powers(double ***, const int, const int); extern int alloc_power_stats(int **, double **, int **, double **, const int); +/* isempty.c */ +extern int is_image_empty(int *, const int, const int); +extern int is_qmap_empty(int *, const int, const int); + + /* line.c */ extern int line_points(int **, int **, int *, const int, const int, const int, const int); +extern int bresenham_line_points(int **, int **, int *, + const int, const int, const int, const int); + +/* link.c */ +extern int link_minutiae(MINUTIAE *, unsigned char *, const int, const int, + int *, const int, const int, const LFSPARMS *); +extern int create_link_table(int **, int **, int **, int *, int *, int *, + const int, const int, const MINUTIAE *, const int *, + int *, const int, const int, unsigned char *, + const int, const int, const LFSPARMS *); +extern int update_link_table(int *, int *, int *, int *, int *, int *, + const int, int *, int *, int *, int *, + const int, const int, const int); +extern int order_link_table(int *, int *, int *, const int, const int, + const int, const int, const MINUTIAE *, const int); +extern int process_link_table(const int *, const int *, const int *, + const int, const int, const int, const int, MINUTIAE *, + int *, unsigned char *, const int, const int, + const LFSPARMS *); +extern double link_score(const double, const double, const LFSPARMS *); /* loop.c */ extern int get_loop_list(int **, MINUTIAE *, const int, unsigned char *, @@ -799,8 +878,16 @@ extern int process_loop_V2(MINUTIAE *, const int *, const int *, const int *, const int *, const int, unsigned char *, const int, const int, int *, const LFSPARMS *); +extern void get_loop_aspect(int *, int *, double *, int *, int *, double *, + const int *, const int *, const int); extern int fill_loop(const int *, const int *, const int, unsigned char *, const int, const int); +extern void fill_partial_row(const int, const int, const int, const int, + unsigned char *, const int, const int); +extern void flood_loop(const int *, const int *, const int, + unsigned char *, const int, const int); +extern void flood_fill4(const int, const int, const int, + unsigned char *, const int, const int); /* maps.c */ extern int gen_image_maps(int **, int **, int **, int **, int *, int *, @@ -820,6 +907,10 @@ extern void smooth_direction_map(int *, int *, const int, const int, const DIR2RAD *, const LFSPARMS *); extern int gen_high_curve_map(int **, int *, const int, const int, const LFSPARMS *); +extern int gen_imap(int **, int *, int *, + unsigned char *, const int, const int, + const DIR2RAD *, const DFTWAVES *, const ROTGRIDS *, + const LFSPARMS *); extern int gen_initial_imap(int **, int *, const int, const int, unsigned char *, const int, const int, const DFTWAVES *, const ROTGRIDS *, const LFSPARMS *); @@ -850,6 +941,7 @@ extern void average_8nbr_dir(int *, double *, int *, int *, const int, extern int num_valid_8nbrs(int *, const int, const int, const int, const int); extern void smooth_imap(int *, const int, const int, const DIR2RAD *, const LFSPARMS *); +extern int gen_nmap(int **, int *, const int, const int, const LFSPARMS *); extern int vorticity(int *, const int, const int, const int, const int, const int); extern void accum_nbr_vorticity(int *, const int, const int, const int); @@ -868,6 +960,9 @@ extern void skip_repeated_vertical_pair(int *, const int, /* minutia.c */ extern int alloc_minutiae(MINUTIAE **, const int); extern int realloc_minutiae(MINUTIAE *, const int); +extern int detect_minutiae(MINUTIAE *, unsigned char *, const int, const int, + const int *, const int *, const int, const int, + const LFSPARMS *); extern int detect_minutiae_V2(MINUTIAE *, unsigned char *, const int, const int, int *, int *, int *, const int, const int, @@ -972,8 +1067,6 @@ extern int adjust_high_curvature_minutia_V2(int *, int *, int *, int *, MINUTIAE *, const LFSPARMS *); extern int get_low_curvature_direction(const int, const int, const int, const int); -void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot, - const MINUTIA *minutia, const int iw, const int ih); /* quality.c */ extern int gen_quality_map(int **, int *, int *, int *, int *, @@ -981,6 +1074,12 @@ extern int gen_quality_map(int **, int *, int *, int *, int *, extern int combined_minutia_quality(MINUTIAE *, int *, const int, const int, const int, unsigned char *, const int, const int, const int, const double); +double grayscale_reliability(MINUTIA *, unsigned char *, + const int, const int, const int); +extern void get_neighborhood_stats(double *, double *, MINUTIA *, + unsigned char *, const int, const int, const int); +extern int reliability_fr_quality_map(MINUTIAE *, int *, const int, + const int, const int, const int, const int); /* remove.c */ extern int remove_false_minutia(MINUTIAE *, @@ -990,15 +1089,93 @@ extern int remove_false_minutia_V2(MINUTIAE *, unsigned char *, const int, const int, int *, int *, int *, const int, const int, const LFSPARMS *); +extern int remove_holes(MINUTIAE *, unsigned char *, const int, const int, + const LFSPARMS *); +extern int remove_hooks(MINUTIAE *, + unsigned char *, const int, const int, const LFSPARMS *); +extern int remove_hooks_islands_lakes_overlaps(MINUTIAE *, unsigned char *, + const int, const int, const LFSPARMS *); +extern int remove_islands_and_lakes(MINUTIAE *, + unsigned char *, const int, const int, const LFSPARMS *); +extern int remove_malformations(MINUTIAE *, + unsigned char *, const int, const int, + int *, const int, const int, const LFSPARMS *); +extern int remove_near_invblock(MINUTIAE *, int *, const int, const int, + const LFSPARMS *); +extern int remove_near_invblock_V2(MINUTIAE *, int *, + const int, const int, const LFSPARMS *); +extern int remove_pointing_invblock(MINUTIAE *, int *, const int, const int, + const LFSPARMS *); +extern int remove_pointing_invblock_V2(MINUTIAE *, + int *, const int, const int, const LFSPARMS *); +extern int remove_overlaps(MINUTIAE *, + unsigned char *, const int, const int, const LFSPARMS *); +extern int remove_pores(MINUTIAE *, + unsigned char *, const int, const int, + int *, const int, const int, const LFSPARMS *); +extern int remove_pores_V2(MINUTIAE *, + unsigned char *, const int, const int, + int *, int *, int *, const int, const int, + const LFSPARMS *); +extern int remove_or_adjust_side_minutiae(MINUTIAE *, unsigned char *, + const int, const int, const LFSPARMS *); +extern int remove_or_adjust_side_minutiae_V2(MINUTIAE *, + unsigned char *, const int, const int, + int *, const int, const int, const LFSPARMS *); + +/* results.c */ +extern int write_text_results(char *, const int, const int, const int, + const MINUTIAE *, int *, int *, int *, int *, int *, + const int, const int); +extern int write_minutiae_XYTQ(char *ofile, const int, + const MINUTIAE *, const int, const int); +extern void dump_map(FILE *, int *, const int, const int); +extern int drawimap(int *, const int, const int, unsigned char *, + const int, const int, const ROTGRIDS *, const int); +extern void drawimap2(int *, const int *, const int, const int, + unsigned char *, const int, const int, + const double, const int, const int); +extern void drawblocks(const int *, const int, const int, + unsigned char *, const int, const int, const int ); +extern int drawrotgrid(const ROTGRIDS *, const int, unsigned char *, + const int, const int, const int, const int); +extern void dump_link_table(FILE *, const int *, const int *, const int *, + const int, const int, const int, const MINUTIAE *); +extern int draw_direction_map(char *, int *, + int *, const int, const int, const int, + unsigned char *, const int, const int, const int); +extern int draw_TF_map(char *, int *, + int *, const int, const int, const int, + unsigned char *, const int, const int, const int); /* ridges.c */ extern int count_minutiae_ridges(MINUTIAE *, unsigned char *, const int, const int, const LFSPARMS *); +extern int count_minutia_ridges(const int, MINUTIAE *, + unsigned char *, const int, const int, + const LFSPARMS *); +extern int find_neighbors(int **, int *, const int, const int, MINUTIAE *); +extern int update_nbr_dists(int *, double *, int *, const int, + const int, const int, MINUTIAE *); +extern int insert_neighbor(const int, const int, const double, + int *, double *, int *, const int); +extern int sort_neighbors(int *, const int, const int, MINUTIAE *); +extern int ridge_count(const int, const int, MINUTIAE *, + unsigned char *, const int, const int, const LFSPARMS *); +extern int find_transition(int *, const int, const int, + const int *, const int *, const int, + unsigned char *, const int, const int); +extern int validate_ridge_crossing(const int, const int, + const int *, const int *, const int, + unsigned char *, const int, const int, const int); /* shape.c */ +extern int alloc_shape(SHAPE **, const int, const int, const int, const int); extern void free_shape(SHAPE *); +extern void dump_shape(FILE *, const SHAPE *); extern int shape_from_contour(SHAPE **, const int *, const int *, const int); +extern void sort_row_on_x(ROW *); /* sort.c */ extern int sort_indices_int_inc(int **, int *, const int); @@ -1023,6 +1200,12 @@ extern int line2direction(const int, const int, const int, const int, const int); extern int closest_dir_dist(const int, const int, const int); +/* xytreps.c */ +extern void lfs2nist_minutia_XYT(int *, int *, int *, + const MINUTIA *, const int, const int); +extern void lfs2m1_minutia_XYT(int *, int *, int *, const MINUTIA *); +extern void lfs2nist_format(MINUTIAE *, int, int); + /*************************************************************************/ /* EXTERNAL GLOBAL VARIABLE DEFINITIONS */ /*************************************************************************/ diff --git a/libfprint/nbis/include/log.h b/libfprint/nbis/include/log.h index a9cd6030..4fd7e75b 100644 --- a/libfprint/nbis/include/log.h +++ b/libfprint/nbis/include/log.h @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + #ifndef _LOG_H #define _LOG_H @@ -36,10 +57,6 @@ identified are necessarily the best available for the purpose. #define LOG_FILE "log.txt" #endif -extern FILE *g_logfp; -extern int g_avrdir; -extern float g_dir_strength; -extern int g_nvalid; extern int open_logfile(void); extern int close_logfile(void); diff --git a/libfprint/nbis/include/morph.h b/libfprint/nbis/include/morph.h index 782d331b..944bd2aa 100644 --- a/libfprint/nbis/include/morph.h +++ b/libfprint/nbis/include/morph.h @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + #ifndef __MORPH_H__ #define __MORPH_H__ diff --git a/libfprint/nbis/include/mytime.h b/libfprint/nbis/include/mytime.h new file mode 100644 index 00000000..e052a251 --- /dev/null +++ b/libfprint/nbis/include/mytime.h @@ -0,0 +1,106 @@ +/******************************************************************************* + +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. + +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. + +*******************************************************************************/ + + +#ifndef _MYTIME_H +#define _MYTIME_H + +/* this file needed to support timer and ticks */ +/* UPDATED: 03/16/2005 by MDG */ + +#ifdef TIMER +#include +#endif + +#ifdef __MSYS__ +#include +#else +#include +#endif + +#ifdef TIMER +#define set_timer(_timer_); \ + { \ + _timer_ = ticks(); +#else +#define set_timer(_timer_); +#endif + +#ifdef TIMER +#define time_accum(_timer_, _var_); \ + _var_ += (ticks() - _timer_)/(float)ticksPerSec(); \ + } +#else +#define time_accum(_timer_, _var_); +#endif + +#ifdef TIMER +#define print_time(_fp_, _fmt_, _var_); \ + fprintf(_fp_, _fmt_, _var_); +#else +#define print_time(_fp_, _fmt_, _var_); +#endif + +extern clock_t ticks(void); +extern int ticksPerSec(void); + +extern clock_t total_timer; +extern float total_time; + +extern clock_t imap_timer; +extern float imap_time; + +extern clock_t bin_timer; +extern float bin_time; + +extern clock_t minutia_timer; +extern float minutia_time; + +extern clock_t rm_minutia_timer; +extern float rm_minutia_time; + +extern clock_t ridge_count_timer; +extern float ridge_count_time; + +#endif + diff --git a/libfprint/nbis/include/sunrast.h b/libfprint/nbis/include/sunrast.h index 3d7deeaa..61c035f4 100644 --- a/libfprint/nbis/include/sunrast.h +++ b/libfprint/nbis/include/sunrast.h @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + #ifndef _SUNRAST_H #define _SUNRAST_H diff --git a/libfprint/nbis/lfs.h.patch b/libfprint/nbis/lfs.h.patch new file mode 100644 index 00000000..2be6ebf8 --- /dev/null +++ b/libfprint/nbis/lfs.h.patch @@ -0,0 +1,58 @@ +--- include/lfs.h 2018-08-24 15:31:54.535579623 +0200 ++++ include/lfs.h.orig 2018-08-24 15:31:48.781587933 +0200 +@@ -66,7 +43,7 @@ of the software. + + #include + #include +-#include /* Needed by to_type9.c */ ++#include + + /*************************************************************************/ + /* OUTPUT FILE EXTENSIONS */ +@@ -154,26 +131,8 @@ typedef struct rotgrids{ + #define DISAPPEARING 0 + #define APPEARING 1 + +-typedef struct minutia{ +- int x; +- int y; +- int ex; +- int ey; +- int direction; +- double reliability; +- int type; +- int appearing; +- int feature_id; +- int *nbrs; +- int *ridge_counts; +- int num_nbrs; +-} MINUTIA; +- +-typedef struct minutiae{ +- int alloc; +- int num; +- MINUTIA **list; +-} MINUTIAE; ++typedef struct fp_minutia MINUTIA; ++typedef struct fp_minutiae MINUTIAE; + + typedef struct feature_pattern{ + int type; +@@ -1185,17 +1185,6 @@ extern void bubble_sort_double_inc_2(double *, int *, const int); + extern void bubble_sort_double_dec_2(double *, int *, const int); + extern void bubble_sort_int_inc(int *, const int); + +-/* to_type9.c */ +-extern int minutiae2type_9(RECORD **, const int, MINUTIAE *, const int, +- const int, const double); +-extern int mintiae2field_12(FIELD **, MINUTIAE *, const int, const int, +- const double); +- +-/* update.c */ +-extern int update_ANSI_NIST_lfs_results(ANSI_NIST *, MINUTIAE *, +- unsigned char *, const int, const int, +- const int, const double, const int, const int); +- + /* util.c */ + extern int maxv(const int *, const int); + extern int minv(const int *, const int); diff --git a/libfprint/nbis/mindtct/binar.c b/libfprint/nbis/mindtct/binar.c index 916d56e2..fb2be224 100644 --- a/libfprint/nbis/mindtct/binar.c +++ b/libfprint/nbis/mindtct/binar.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -36,16 +57,44 @@ identified are necessarily the best available for the purpose. *********************************************************************** ROUTINES: + binarize() binarize_V2() + binarize_image() binarize_image_V2() dirbinarize() + isobinarize() ***********************************************************************/ #include -#include #include +/************************************************************************* +************************************************************************** +#cat: binarize - Takes a padded grayscale input image and its associated ridge +#cat: direction flow NMAP and produces a binarized version of the +#cat: image. It then fills horizontal and vertical "holes" in the +#cat: binary image results. + + Input: + pdata - padded input grayscale image + pw - padded width (in pixels) of input image + ph - padded height (in pixels) of input image + nmap - 2-D vector of IMAP directions and other codes + mw - width (in blocks) of the NMAP + mh - height (in blocks) of the NMAP + dirbingrids - set of rotated grid offsets used for directional + binarization + lfsparms - parameters and thresholds for controlling LFS + Output: + optr - points to created (unpadded) binary image + ow - width of binary image + oh - height of binary image + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: binarize_V2 - Takes a padded grayscale input image and its associated @@ -101,6 +150,32 @@ int binarize_V2(unsigned char **odata, int *ow, int *oh, return(0); } +/************************************************************************* +************************************************************************** +#cat: binarize_image - Takes a grayscale input image and its associated +#cat: NMAP and generates a binarized version of the image. + + Input: + pdata - padded input grayscale image + pw - padded width (in pixels) of input image + ph - padded height (in pixels) of input image + nmap - 2-D vector of IMAP directions and other codes + mw - width (in blocks) of the NMAP + mh - height (in blocks) of the NMAP + imap_blocksize - dimension (in pixels) of each NMAP block + dirbingrids - set of rotated grid offsets used for directional + binarization + isobin_grid_dim - dimension (in pixels) of grid used for isotropic + binarization + Output: + optr - points to binary image results + ow - points to binary image width + oh - points to binary image height + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: binarize_image_V2 - Takes a grayscale input image and its associated @@ -247,3 +322,27 @@ int dirbinarize(const unsigned char *pptr, const int idir, return(WHITE_PIXEL); } +/************************************************************************* +************************************************************************** +#cat: isobinarize - Determines the binary value of a grayscale pixel based +#cat: on comparing the grayscale value with a surrounding +#cat: neighborhood grid of pixels. If the current pixel (treated +#cat: as an average) is less than the sum of the pixels in +#cat: the neighborhood, then the binary value is set to BLACK, +#cat: otherwise it is set to WHITE. This binarization technique +#cat: is used when there is no VALID IMAP direction for the +#cat: block in which the current pixel resides. + + CAUTION: The image to which the input pixel points must be appropriately + padded to account for the radius of the neighborhood. Otherwise, + this routine may access "unkown" memory. + + Input: + pptr - pointer to curent grayscale pixel + pw - padded width (in pixels) of the grayscale image + ph - padded height (in pixels) of the grayscale image + isobin_grid_dim - dimension (in pixels) of the neighborhood + Return Code: + BLACK_PIXEL - pixel intensity for BLACK + WHITE_PIXEL - pixel intensity of WHITE +**************************************************************************/ diff --git a/libfprint/nbis/mindtct/block.c b/libfprint/nbis/mindtct/block.c index be0b3f97..f530f94d 100644 --- a/libfprint/nbis/mindtct/block.c +++ b/libfprint/nbis/mindtct/block.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -44,8 +65,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include -#include #include /************************************************************************* @@ -96,7 +115,7 @@ int block_offsets(int **optr, int *ow, int *oh, return(-80); } - /* Compute padded width and height of image */ + /* Compute padded width of image */ pad2 = pad<<1; pw = iw + pad2; diff --git a/libfprint/nbis/mindtct/chaincod.c b/libfprint/nbis/mindtct/chaincod.c new file mode 100644 index 00000000..dd5d779c --- /dev/null +++ b/libfprint/nbis/mindtct/chaincod.c @@ -0,0 +1,211 @@ +/******************************************************************************* + +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. + +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. + +*******************************************************************************/ + + +/*********************************************************************** + LIBRARY: LFS - NIST Latent Fingerprint System + + FILE: CHAINCODE.C + AUTHOR: Michael D. Garris + DATE: 05/11/1999 + + Contains routines responsible for generating and manipulating + chain codes as part of the NIST Latent Fingerprint System (LFS). + +*********************************************************************** + ROUTINES: + chain_code_loop() + is_chain_clockwise() +***********************************************************************/ + +#include +#include + +/************************************************************************* +************************************************************************** +#cat: chain_code_loop - Converts a feature's contour points into an +#cat: 8-connected chain code vector. This encoding represents +#cat: the direction taken between each adjacent point in the +#cat: contour. Chain codes may be used for many purposes, such +#cat: as computing the perimeter or area of an object, and they +#cat: may be used in object detection and recognition. + + Input: + contour_x - x-coord list for feature's contour points + contour_y - y-coord list for feature's contour points + ncontour - number of points in contour + Output: + ochain - resulting vector of chain codes + onchain - number of codes in chain + (same as number of points in contour) + Return Code: + Zero - chain code successful derived + Negative - system error +**************************************************************************/ +int chain_code_loop(int **ochain, int *onchain, + const int *contour_x, const int *contour_y, const int ncontour) +{ + int *chain; + int i, j, dx, dy; + + /* If we don't have at least 3 points in the contour ... */ + if(ncontour <= 3){ + /* Then we don't have a loop, so set chain length to 0 */ + /* and return without any allocations. */ + *onchain = 0; + return(0); + } + + /* Allocate chain code vector. It will be the same length as the */ + /* number of points in the contour. There will be one chain code */ + /* between each point on the contour including a code between the */ + /* last to the first point on the contour (completing the loop). */ + chain = (int *)malloc(ncontour * sizeof(int)); + /* If the allocation fails ... */ + if(chain == (int *)NULL){ + fprintf(stderr, "ERROR : chain_code_loop : malloc : chain\n"); + return(-170); + } + + /* For each neighboring point in the list (with "i" pointing to the */ + /* previous neighbor and "j" pointing to the next neighbor... */ + for(i = 0, j=1; i < ncontour-1; i++, j++){ + /* Compute delta in X between neighbors. */ + dx = contour_x[j] - contour_x[i]; + /* Compute delta in Y between neighbors. */ + dy = contour_y[j] - contour_y[i]; + /* Derive chain code index from neighbor deltas. */ + /* The deltas are on the range [-1..1], so to use them as indices */ + /* into the code list, they must first be incremented by one. */ + chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); + } + + /* Now derive chain code between last and first points in the */ + /* contour list. */ + dx = contour_x[0] - contour_x[i]; + dy = contour_y[0] - contour_y[i]; + chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); + + /* Store results to the output pointers. */ + *ochain = chain; + *onchain = ncontour; + + /* Return normally. */ + return(0); +} + +/************************************************************************* +************************************************************************** +#cat: is_chain_clockwise - Takes an 8-connected chain code vector and +#cat: determines if the codes are ordered clockwise or +#cat: counter-clockwise. +#cat: The routine also requires a default return value be +#cat: specified in the case the the routine is not able to +#cat: definitively determine the chains direction. This allows +#cat: the default response to be application-specific. + + Input: + chain - chain code vector + nchain - number of codes in chain + default_ret - default return code (used when we can't tell the order) + Return Code: + TRUE - chain determined to be ordered clockwise + FALSE - chain determined to be ordered counter-clockwise + Default - could not determine the order of the chain +**************************************************************************/ +int is_chain_clockwise(const int *chain, const int nchain, + const int default_ret) +{ + int i, j, d, sum; + + /* Initialize turn-accumulator to 0. */ + sum = 0; + + /* Foreach neighboring code in chain, compute the difference in */ + /* direction and accumulate. Left-hand turns increment, whereas */ + /* right-hand decrement. */ + for(i = 0, j =1; i < nchain-1; i++, j++){ + /* Compute delta in neighbor direction. */ + d = chain[j] - chain[i]; + /* Make the delta the "inner" distance. */ + /* If delta >= 4, for example if chain_i==2 and chain_j==7 (which */ + /* means the contour went from a step up to step down-to-the-right) */ + /* then 5=(7-2) which is >=4, so -3=(5-8) which means that the */ + /* change in direction is a righ-hand turn of 3 units). */ + if(d >= 4) + d -= 8; + /* If delta <= -4, for example if chain_i==7 and chain_j==2 (which */ + /* means the contour went from a step down-to-the-right to step up) */ + /* then -5=(2-7) which is <=-4, so 3=(-5+8) which means that the */ + /* change in direction is a left-hand turn of 3 units). */ + else if (d <= -4) + d += 8; + + /* The delta direction is then accumulated. */ + sum += d; + } + + /* Now we need to add in the final delta direction between the last */ + /* and first codes in the chain. */ + d = chain[0] - chain[i]; + if(d >= 4) + d -= 8; + else if (d <= -4) + d += 8; + sum += d; + + /* If the final turn_accumulator == 0, then we CAN'T TELL the */ + /* direction of the chain code, so return the default return value. */ + if(sum == 0) + return(default_ret); + /* Otherwise, if the final turn-accumulator is positive ... */ + else if(sum > 0) + /* Then we had a greater amount of left-hand turns than right-hand */ + /* turns, so the chain is in COUNTER-CLOCKWISE order, so return FALSE. */ + return(FALSE); + /* Otherwise, the final turn-accumulator is negative ... */ + else + /* So we had a greater amount of right-hand turns than left-hand */ + /* turns, so the chain is in CLOCKWISE order, so return TRUE. */ + return(TRUE); +} diff --git a/libfprint/nbis/mindtct/contour.c b/libfprint/nbis/mindtct/contour.c index 92e77f50..5d802c28 100644 --- a/libfprint/nbis/mindtct/contour.c +++ b/libfprint/nbis/mindtct/contour.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -50,7 +71,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* @@ -87,6 +107,8 @@ int allocate_contour(int **ocontour_x, int **ocontour_y, { int *contour_x, *contour_y, *contour_ex, *contour_ey; + ASSERT_SIZE_MUL(ncontour, sizeof(int)); + /* Allocate contour's x-coord list. */ contour_x = (int *)malloc(ncontour*sizeof(int)); /* If allocation error... */ @@ -497,6 +519,8 @@ int get_centered_contour(int **ocontour_x, int **ocontour_y, /* If system error occurred on 2nd trace ... */ if(ret < 0){ + /* Deallocate loop's contour. */ + free_contour(half1_x, half1_y, half1_ex, half1_ey); /* Return error code. */ return(ret); } @@ -591,236 +615,6 @@ int get_centered_contour(int **ocontour_x, int **ocontour_y, return(0); } -/************************************************************************* -************************************************************************** -#cat: start_scan_nbr - Takes a two pixel coordinates that are either -#cat: aligned north-to-south or east-to-west, and returns the -#cat: position the second pixel is in realtionship to the first. -#cat: The positions returned are based on 8-connectedness. -#cat: NOTE, this routine does NOT account for diagonal positions. - - Input: - x_prev - x-coord of first point - y_prev - y-coord of first point - x_next - x-coord of second point - y_next - y-coord of second point - Return Code: - NORTH - second pixel above first - SOUTH - second pixel below first - EAST - second pixel right of first - WEST - second pixel left of first -**************************************************************************/ -static int start_scan_nbr(const int x_prev, const int y_prev, - const int x_next, const int y_next) -{ - if((x_prev==x_next) && (y_next > y_prev)) - return(SOUTH); - else if ((x_prev==x_next) && (y_next < y_prev)) - return(NORTH); - else if ((x_next > x_prev) && (y_prev==y_next)) - return(EAST); - else if ((x_next < x_prev) && (y_prev==y_next)) - return(WEST); - - /* Added by MDG on 03-16-05 */ - /* Should never reach here. Added to remove compiler warning. */ - return(INVALID_DIR); /* -1 */ -} - -/************************************************************************* -************************************************************************** -#cat: next_scan_nbr - Advances the given 8-connected neighbor index -#cat: on location in the specifiec direction (clockwise or -#cat: counter-clockwise). - - Input: - nbr_i - current 8-connected neighbor index - scan_clock - direction in which the neighbor index is to be advanced - Return Code: - Next neighbor - 8-connected index of next neighbor -**************************************************************************/ -static int next_scan_nbr(const int nbr_i, const int scan_clock) -{ - int new_i; - - /* If scanning neighbors clockwise ... */ - if(scan_clock == SCAN_CLOCKWISE) - /* Advance one neighbor clockwise. */ - new_i = (nbr_i+1)%8; - /* Otherwise, scanning neighbors counter-clockwise ... */ - else - /* Advance one neighbor counter-clockwise. */ - /* There are 8 pixels in the neighborhood, so to */ - /* decrement with wrapping from 0 around to 7, add */ - /* the nieghbor index by 7 and mod with 8. */ - new_i = (nbr_i+7)%8; - - /* Return the new neighbor index. */ - return(new_i); -} - -/************************************************************************* -************************************************************************** -#cat: next_contour_pixel - Takes a pixel coordinate of a point determined -#cat: to be on the interior edge of a feature (ridge or valley- -#cat: ending), and attempts to locate a neighboring pixel on the -#cat: feature's contour. Neighbors of the current feature pixel -#cat: are searched in a specified direction (clockwise or counter- -#cat: clockwise) and the first pair of adjacent/neigboring pixels -#cat: found with the first pixel having the color of the feature -#cat: and the second the opposite color are returned as the next -#cat: point on the contour. One exception happens when the new -#cat: point is on an "exposed" corner. - - Input: - cur_x_loc - x-pixel coord of current point on feature's - interior contour - cur_y_loc - y-pixel coord of current point on feature's - interior contour - cur_x_edge - x-pixel coord of corresponding edge pixel - (exterior to feature) - cur_y_edge - y-pixel coord of corresponding edge pixel - (exterior to feature) - scan_clock - direction in which neighboring pixels are to be scanned - for the next contour pixel - bdata - binary image data (0==while & 1==black) - iw - width (in pixels) of image - ih - height (in pixels) of image - Output: - next_x_loc - x-pixel coord of next point on feature's interior contour - next_y_loc - y-pixel coord of next point on feature's interior contour - next_x_edge - x-pixel coord of corresponding edge (exterior to feature) - next_y_edge - y-pixel coord of corresponding edge (exterior to feature) - Return Code: - TRUE - next contour point found and returned - FALSE - next contour point NOT found -**************************************************************************/ -/*************************************************************************/ -static int next_contour_pixel(int *next_x_loc, int *next_y_loc, - int *next_x_edge, int *next_y_edge, - const int cur_x_loc, const int cur_y_loc, - const int cur_x_edge, const int cur_y_edge, - const int scan_clock, - unsigned char *bdata, const int iw, const int ih) -{ - int feature_pix, edge_pix; - int prev_nbr_pix, prev_nbr_x, prev_nbr_y; - int cur_nbr_pix, cur_nbr_x, cur_nbr_y; - int ni, nx, ny, npix; - int nbr_i, i; - - /* Get the feature's pixel value. */ - feature_pix = *(bdata + (cur_y_loc * iw) + cur_x_loc); - /* Get the feature's edge pixel value. */ - edge_pix = *(bdata + (cur_y_edge * iw) + cur_x_edge); - - /* Get the nieghbor position of the feature's edge pixel in relationship */ - /* to the feature's actual position. */ - /* REMEBER: The feature's position is always interior and on a ridge */ - /* ending (black pixel) or (for bifurcations) on a valley ending (white */ - /* pixel). The feature's edge pixel is an adjacent pixel to the feature */ - /* pixel that is exterior to the ridge or valley ending and opposite in */ - /* pixel value. */ - nbr_i = start_scan_nbr(cur_x_loc, cur_y_loc, cur_x_edge, cur_y_edge); - - /* Set current neighbor scan pixel to the feature's edge pixel. */ - cur_nbr_x = cur_x_edge; - cur_nbr_y = cur_y_edge; - cur_nbr_pix = edge_pix; - - /* Foreach pixel neighboring the feature pixel ... */ - for(i = 0; i < 8; i++){ - - /* Set current neighbor scan pixel to previous scan pixel. */ - prev_nbr_x = cur_nbr_x; - prev_nbr_y = cur_nbr_y; - prev_nbr_pix = cur_nbr_pix; - - /* Bump pixel neighbor index clockwise or counter-clockwise. */ - nbr_i = next_scan_nbr(nbr_i, scan_clock); - - /* Set current scan pixel to the new neighbor. */ - /* REMEMBER: the neighbors are being scanned around the original */ - /* feature point. */ - cur_nbr_x = cur_x_loc + g_nbr8_dx[nbr_i]; - cur_nbr_y = cur_y_loc + g_nbr8_dy[nbr_i]; - - /* If new neighbor is not within image boundaries... */ - if((cur_nbr_x < 0) || (cur_nbr_x >= iw) || - (cur_nbr_y < 0) || (cur_nbr_y >= ih)) - /* Return (FALSE==>Failure) if neighbor out of bounds. */ - return(FALSE); - - /* Get the new neighbor's pixel value. */ - cur_nbr_pix = *(bdata + (cur_nbr_y * iw) + cur_nbr_x); - - /* If the new neighbor's pixel value is the same as the feature's */ - /* pixel value AND the previous neighbor's pixel value is the same */ - /* as the features's edge, then we have "likely" found our next */ - /* contour pixel. */ - if((cur_nbr_pix == feature_pix) && (prev_nbr_pix == edge_pix)){ - - /* Check to see if current neighbor is on the corner of the */ - /* neighborhood, and if so, test to see if it is "exposed". */ - /* The neighborhood corners have odd neighbor indicies. */ - if(nbr_i % 2){ - /* To do this, look ahead one more neighbor pixel. */ - ni = next_scan_nbr(nbr_i, scan_clock); - nx = cur_x_loc + g_nbr8_dx[ni]; - ny = cur_y_loc + g_nbr8_dy[ni]; - /* If new neighbor is not within image boundaries... */ - if((nx < 0) || (nx >= iw) || - (ny < 0) || (ny >= ih)) - /* Return (FALSE==>Failure) if neighbor out of bounds. */ - return(FALSE); - npix = *(bdata + (ny * iw) + nx); - - /* If the next neighbor's value is also the same as the */ - /* feature's pixel, then corner is NOT exposed... */ - if(npix == feature_pix){ - /* Assign the current neighbor pair to the output pointers. */ - *next_x_loc = cur_nbr_x; - *next_y_loc = cur_nbr_y; - *next_x_edge = prev_nbr_x; - *next_y_edge = prev_nbr_y; - /* Return TRUE==>Success. */ - return(TRUE); - } - /* Otherwise, corner pixel is "exposed" so skip it. */ - else{ - /* Skip current corner neighbor by resetting it to the */ - /* next neighbor, which upon the iteration will immediately */ - /* become the previous neighbor. */ - cur_nbr_x = nx; - cur_nbr_y = ny; - cur_nbr_pix = npix; - /* Advance neighbor index. */ - nbr_i = ni; - /* Advance neighbor count. */ - i++; - } - } - /* Otherwise, current neighbor is not a corner ... */ - else{ - /* Assign the current neighbor pair to the output pointers. */ - *next_x_loc = cur_nbr_x; - *next_y_loc = cur_nbr_y; - *next_x_edge = prev_nbr_x; - *next_y_edge = prev_nbr_y; - /* Return TRUE==>Success. */ - return(TRUE); - } - } - } - - /* If we get here, then we did not find the next contour pixel */ - /* within the 8 neighbors of the current feature pixel so */ - /* return (FALSE==>Failure). */ - /* NOTE: This must mean we found a single isolated pixel. */ - /* Perhaps this should be filled? */ - return(FALSE); -} - /************************************************************************* ************************************************************************** #cat: trace_contour - Takes the pixel coordinate of a detected minutia @@ -1046,6 +840,236 @@ int search_contour(const int x_search, const int y_search, return(NOT_FOUND); } +/************************************************************************* +************************************************************************** +#cat: next_contour_pixel - Takes a pixel coordinate of a point determined +#cat: to be on the interior edge of a feature (ridge or valley- +#cat: ending), and attempts to locate a neighboring pixel on the +#cat: feature's contour. Neighbors of the current feature pixel +#cat: are searched in a specified direction (clockwise or counter- +#cat: clockwise) and the first pair of adjacent/neigboring pixels +#cat: found with the first pixel having the color of the feature +#cat: and the second the opposite color are returned as the next +#cat: point on the contour. One exception happens when the new +#cat: point is on an "exposed" corner. + + Input: + cur_x_loc - x-pixel coord of current point on feature's + interior contour + cur_y_loc - y-pixel coord of current point on feature's + interior contour + cur_x_edge - x-pixel coord of corresponding edge pixel + (exterior to feature) + cur_y_edge - y-pixel coord of corresponding edge pixel + (exterior to feature) + scan_clock - direction in which neighboring pixels are to be scanned + for the next contour pixel + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + Output: + next_x_loc - x-pixel coord of next point on feature's interior contour + next_y_loc - y-pixel coord of next point on feature's interior contour + next_x_edge - x-pixel coord of corresponding edge (exterior to feature) + next_y_edge - y-pixel coord of corresponding edge (exterior to feature) + Return Code: + TRUE - next contour point found and returned + FALSE - next contour point NOT found +**************************************************************************/ +/*************************************************************************/ +int next_contour_pixel(int *next_x_loc, int *next_y_loc, + int *next_x_edge, int *next_y_edge, + const int cur_x_loc, const int cur_y_loc, + const int cur_x_edge, const int cur_y_edge, + const int scan_clock, + unsigned char *bdata, const int iw, const int ih) +{ + int feature_pix, edge_pix; + int prev_nbr_pix, prev_nbr_x, prev_nbr_y; + int cur_nbr_pix, cur_nbr_x, cur_nbr_y; + int ni, nx, ny, npix; + int nbr_i, i; + + /* Get the feature's pixel value. */ + feature_pix = *(bdata + (cur_y_loc * iw) + cur_x_loc); + /* Get the feature's edge pixel value. */ + edge_pix = *(bdata + (cur_y_edge * iw) + cur_x_edge); + + /* Get the nieghbor position of the feature's edge pixel in relationship */ + /* to the feature's actual position. */ + /* REMEBER: The feature's position is always interior and on a ridge */ + /* ending (black pixel) or (for bifurcations) on a valley ending (white */ + /* pixel). The feature's edge pixel is an adjacent pixel to the feature */ + /* pixel that is exterior to the ridge or valley ending and opposite in */ + /* pixel value. */ + nbr_i = start_scan_nbr(cur_x_loc, cur_y_loc, cur_x_edge, cur_y_edge); + + /* Set current neighbor scan pixel to the feature's edge pixel. */ + cur_nbr_x = cur_x_edge; + cur_nbr_y = cur_y_edge; + cur_nbr_pix = edge_pix; + + /* Foreach pixel neighboring the feature pixel ... */ + for(i = 0; i < 8; i++){ + + /* Set current neighbor scan pixel to previous scan pixel. */ + prev_nbr_x = cur_nbr_x; + prev_nbr_y = cur_nbr_y; + prev_nbr_pix = cur_nbr_pix; + + /* Bump pixel neighbor index clockwise or counter-clockwise. */ + nbr_i = next_scan_nbr(nbr_i, scan_clock); + + /* Set current scan pixel to the new neighbor. */ + /* REMEMBER: the neighbors are being scanned around the original */ + /* feature point. */ + cur_nbr_x = cur_x_loc + g_nbr8_dx[nbr_i]; + cur_nbr_y = cur_y_loc + g_nbr8_dy[nbr_i]; + + /* If new neighbor is not within image boundaries... */ + if((cur_nbr_x < 0) || (cur_nbr_x >= iw) || + (cur_nbr_y < 0) || (cur_nbr_y >= ih)) + /* Return (FALSE==>Failure) if neighbor out of bounds. */ + return(FALSE); + + /* Get the new neighbor's pixel value. */ + cur_nbr_pix = *(bdata + (cur_nbr_y * iw) + cur_nbr_x); + + /* If the new neighbor's pixel value is the same as the feature's */ + /* pixel value AND the previous neighbor's pixel value is the same */ + /* as the features's edge, then we have "likely" found our next */ + /* contour pixel. */ + if((cur_nbr_pix == feature_pix) && (prev_nbr_pix == edge_pix)){ + + /* Check to see if current neighbor is on the corner of the */ + /* neighborhood, and if so, test to see if it is "exposed". */ + /* The neighborhood corners have odd neighbor indicies. */ + if(nbr_i % 2){ + /* To do this, look ahead one more neighbor pixel. */ + ni = next_scan_nbr(nbr_i, scan_clock); + nx = cur_x_loc + g_nbr8_dx[ni]; + ny = cur_y_loc + g_nbr8_dy[ni]; + /* If new neighbor is not within image boundaries... */ + if((nx < 0) || (nx >= iw) || + (ny < 0) || (ny >= ih)) + /* Return (FALSE==>Failure) if neighbor out of bounds. */ + return(FALSE); + npix = *(bdata + (ny * iw) + nx); + + /* If the next neighbor's value is also the same as the */ + /* feature's pixel, then corner is NOT exposed... */ + if(npix == feature_pix){ + /* Assign the current neighbor pair to the output pointers. */ + *next_x_loc = cur_nbr_x; + *next_y_loc = cur_nbr_y; + *next_x_edge = prev_nbr_x; + *next_y_edge = prev_nbr_y; + /* Return TRUE==>Success. */ + return(TRUE); + } + /* Otherwise, corner pixel is "exposed" so skip it. */ + else{ + /* Skip current corner neighbor by resetting it to the */ + /* next neighbor, which upon the iteration will immediately */ + /* become the previous neighbor. */ + cur_nbr_x = nx; + cur_nbr_y = ny; + cur_nbr_pix = npix; + /* Advance neighbor index. */ + nbr_i = ni; + /* Advance neighbor count. */ + i++; + } + } + /* Otherwise, current neighbor is not a corner ... */ + else{ + /* Assign the current neighbor pair to the output pointers. */ + *next_x_loc = cur_nbr_x; + *next_y_loc = cur_nbr_y; + *next_x_edge = prev_nbr_x; + *next_y_edge = prev_nbr_y; + /* Return TRUE==>Success. */ + return(TRUE); + } + } + } + + /* If we get here, then we did not find the next contour pixel */ + /* within the 8 neighbors of the current feature pixel so */ + /* return (FALSE==>Failure). */ + /* NOTE: This must mean we found a single isolated pixel. */ + /* Perhaps this should be filled? */ + return(FALSE); +} + +/************************************************************************* +************************************************************************** +#cat: start_scan_nbr - Takes a two pixel coordinates that are either +#cat: aligned north-to-south or east-to-west, and returns the +#cat: position the second pixel is in realtionship to the first. +#cat: The positions returned are based on 8-connectedness. +#cat: NOTE, this routine does NOT account for diagonal positions. + + Input: + x_prev - x-coord of first point + y_prev - y-coord of first point + x_next - x-coord of second point + y_next - y-coord of second point + Return Code: + NORTH - second pixel above first + SOUTH - second pixel below first + EAST - second pixel right of first + WEST - second pixel left of first +**************************************************************************/ +int start_scan_nbr(const int x_prev, const int y_prev, + const int x_next, const int y_next) +{ + if((x_prev==x_next) && (y_next > y_prev)) + return(SOUTH); + else if ((x_prev==x_next) && (y_next < y_prev)) + return(NORTH); + else if ((x_next > x_prev) && (y_prev==y_next)) + return(EAST); + else if ((x_next < x_prev) && (y_prev==y_next)) + return(WEST); + + /* Added by MDG on 03-16-05 */ + /* Should never reach here. Added to remove compiler warning. */ + return(INVALID_DIR); /* -1 */ +} + +/************************************************************************* +************************************************************************** +#cat: next_scan_nbr - Advances the given 8-connected neighbor index +#cat: on location in the specifiec direction (clockwise or +#cat: counter-clockwise). + + Input: + nbr_i - current 8-connected neighbor index + scan_clock - direction in which the neighbor index is to be advanced + Return Code: + Next neighbor - 8-connected index of next neighbor +**************************************************************************/ +int next_scan_nbr(const int nbr_i, const int scan_clock) +{ + int new_i; + + /* If scanning neighbors clockwise ... */ + if(scan_clock == SCAN_CLOCKWISE) + /* Advance one neighbor clockwise. */ + new_i = (nbr_i+1)%8; + /* Otherwise, scanning neighbors counter-clockwise ... */ + else + /* Advance one neighbor counter-clockwise. */ + /* There are 8 pixels in the neighborhood, so to */ + /* decrement with wrapping from 0 around to 7, add */ + /* the nieghbor index by 7 and mod with 8. */ + new_i = (nbr_i+7)%8; + + /* Return the new neighbor index. */ + return(new_i); +} + /************************************************************************* ************************************************************************** #cat: min_contour_theta - Takes a contour list and analyzes it locating the diff --git a/libfprint/nbis/mindtct/detect.c b/libfprint/nbis/mindtct/detect.c index deadf291..10ed85c5 100644 --- a/libfprint/nbis/mindtct/detect.c +++ b/libfprint/nbis/mindtct/detect.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -35,16 +56,46 @@ identified are necessarily the best available for the purpose. *********************************************************************** ROUTINES: + lfs_detect_minutiae() lfs_detect_minutiae_V2() - get_minutiae() ***********************************************************************/ #include -#include #include +#include #include +/************************************************************************* +#cat: lfs_detect_minutiae - Takes a grayscale fingerprint image (of arbitrary +#cat: size), and returns a map of directional ridge flow in the image +#cat: (2 versions), a binarized image designating ridges from valleys, +#cat: and a list of minutiae (including position, type, direction, +#cat: neighbors, and ridge counts to neighbors). + + Input: + idata - input 8-bit grayscale fingerprint image data + iw - width (in pixels) of the image + ih - height (in pixels) of the image + lfsparms - parameters and thresholds for controlling LFS + Output: + ominutiae - resulting list of minutiae + oimap - resulting IMAP + {invalid (-1) or valid ridge directions} + onmap - resulting NMAP + {invalid (-1), high-curvature (-2), blanked blocks {-3} or + valid ridge directions} + omw - width (in blocks) of image maps + omh - height (in blocks) of image maps + obdata - resulting binarized image + {0 = black pixel (ridge) and 255 = white pixel (valley)} + obw - width (in pixels) of the binary image + obh - height (in pixels) of the binary image + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* #cat: lfs_detect_minutiae_V2 - Takes a grayscale fingerprint image (of #cat: arbitrary size), and returns a set of image block maps, @@ -81,7 +132,7 @@ identified are necessarily the best available for the purpose. Zero - successful completion Negative - system error **************************************************************************/ -static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, +int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, int **odmap, int **olcmap, int **olfmap, int **ohcmap, int *omw, int *omh, unsigned char **obdata, int *obw, int *obh, @@ -99,6 +150,8 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, int ret, maxpad; MINUTIAE *minutiae; + set_timer(total_timer); + /******************/ /* INITIALIZATION */ /******************/ @@ -181,6 +234,7 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, /******************/ /* MAPS */ /******************/ + set_timer(imap_timer); /* Generate block maps from the input image. */ if((ret = gen_image_maps(&direction_map, &low_contrast_map, @@ -200,9 +254,12 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, print2log("\nMAPS DONE\n"); + time_accum(imap_timer, imap_time); + /******************/ /* BINARIZARION */ /******************/ + set_timer(bin_timer); /* Initialize lookup table for pixel offsets to rotated grids */ /* used for directional binarization. */ @@ -254,9 +311,12 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, print2log("\nBINARIZATION DONE\n"); + time_accum(bin_timer, bin_time); + /******************/ /* DETECTION */ /******************/ + set_timer(minutia_timer); /* Convert 8-bit grayscale binary image [0,255] to */ /* 8-bit binary image [0,1]. */ @@ -281,6 +341,10 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, return(ret); } + time_accum(minutia_timer, minutia_time); + + set_timer(rm_minutia_timer); + if((ret = remove_false_minutia_V2(minutiae, bdata, iw, ih, direction_map, low_flow_map, high_curve_map, mw, mh, lfsparms))){ @@ -297,9 +361,13 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, print2log("\nMINUTIA DETECTION DONE\n"); + time_accum(rm_minutia_timer, rm_minutia_time); + /******************/ /* RIDGE COUNTS */ /******************/ + set_timer(ridge_count_timer); + if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){ /* Free memory allocated to this point. */ free(pdata); @@ -314,6 +382,8 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, print2log("\nNEIGHBOR RIDGE COUNT DONE\n"); + time_accum(ridge_count_timer, ridge_count_time); + /******************/ /* WRAP-UP */ /******************/ @@ -337,6 +407,28 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, *obh = bh; *ominutiae = minutiae; + time_accum(total_timer, total_time); + + /******************/ + /* PRINT TIMINGS */ + /******************/ + /* These Timings will print when TIMER is defined. */ + /* print MAP generation timing statistics */ + print_time(stderr, "TIMER: MAPS time = %f (secs)\n", imap_time); + /* print binarization timing statistics */ + print_time(stderr, "TIMER: Binarization time = %f (secs)\n", bin_time); + /* print minutia detection timing statistics */ + print_time(stderr, "TIMER: Minutia Detection time = %f (secs)\n", + minutia_time); + /* print minutia removal timing statistics */ + print_time(stderr, "TIMER: Minutia Removal time = %f (secs)\n", + rm_minutia_time); + /* print neighbor ridge count timing statistics */ + print_time(stderr, "TIMER: Neighbor Ridge Counting time = %f (secs)\n", + ridge_count_time); + /* print total timing statistics */ + print_time(stderr, "TIMER: Total time = %f (secs)\n", total_time); + /* If LOG_REPORT defined, close log report file. */ if((ret = close_logfile())) return(ret); @@ -344,112 +436,3 @@ static int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, return(0); } -/************************************************************************* -************************************************************************** -#cat: get_minutiae - Takes a grayscale fingerprint image, binarizes the input -#cat: image, and detects minutiae points using LFS Version 2. -#cat: The routine passes back the detected minutiae, the -#cat: binarized image, and a set of image quality maps. - - Input: - idata - grayscale fingerprint image data - iw - width (in pixels) of the grayscale image - ih - height (in pixels) of the grayscale image - id - pixel depth (in bits) of the grayscale image - ppmm - the scan resolution (in pixels/mm) of the grayscale image - lfsparms - parameters and thresholds for controlling LFS - Output: - ominutiae - points to a structure containing the - detected minutiae - oquality_map - resulting integrated image quality map - odirection_map - resulting direction map - olow_contrast_map - resulting low contrast map - olow_flow_map - resulting low ridge flow map - ohigh_curve_map - resulting high curvature map - omap_w - width (in blocks) of image maps - omap_h - height (in blocks) of image maps - obdata - points to binarized image data - obw - width (in pixels) of binarized image - obh - height (in pixels) of binarized image - obd - pixel depth (in bits) of binarized image - Return Code: - Zero - successful completion - Negative - system error -**************************************************************************/ -int get_minutiae(MINUTIAE **ominutiae, int **oquality_map, - int **odirection_map, int **olow_contrast_map, - int **olow_flow_map, int **ohigh_curve_map, - int *omap_w, int *omap_h, - unsigned char **obdata, int *obw, int *obh, int *obd, - unsigned char *idata, const int iw, const int ih, - const int id, const double ppmm, const LFSPARMS *lfsparms) -{ - int ret; - MINUTIAE *minutiae = NULL; - int *direction_map = NULL, *low_contrast_map = NULL, *low_flow_map = NULL; - int *high_curve_map = NULL, *quality_map = NULL; - int map_w = 0, map_h = 0; - unsigned char *bdata = NULL; - int bw = 0, bh = 0; - - /* If input image is not 8-bit grayscale ... */ - if(id != 8){ - fprintf(stderr, "ERROR : get_minutiae : input image pixel "); - fprintf(stderr, "depth = %d != 8.\n", id); - return(-2); - } - - /* Detect minutiae in grayscale fingerpeint image. */ - if((ret = lfs_detect_minutiae_V2(&minutiae, - &direction_map, &low_contrast_map, - &low_flow_map, &high_curve_map, - &map_w, &map_h, - &bdata, &bw, &bh, - idata, iw, ih, lfsparms))){ - return(ret); - } - - /* Build integrated quality map. */ - if((ret = gen_quality_map(&quality_map, - direction_map, low_contrast_map, - low_flow_map, high_curve_map, map_w, map_h))){ - free_minutiae(minutiae); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(bdata); - return(ret); - } - - /* Assign reliability from quality map. */ - if((ret = combined_minutia_quality(minutiae, quality_map, map_w, map_h, - lfsparms->blocksize, - idata, iw, ih, id, ppmm))){ - free_minutiae(minutiae); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(quality_map); - free(bdata); - return(ret); - } - - /* Set output pointers. */ - *ominutiae = minutiae; - *oquality_map = quality_map; - *odirection_map = direction_map; - *olow_contrast_map = low_contrast_map; - *olow_flow_map = low_flow_map; - *ohigh_curve_map = high_curve_map; - *omap_w = map_w; - *omap_h = map_h; - *obdata = bdata; - *obw = bw; - *obh = bh; - *obd = id; - - /* Return normally. */ - return(0); -} diff --git a/libfprint/nbis/mindtct/dft.c b/libfprint/nbis/mindtct/dft.c index af136536..be485864 100644 --- a/libfprint/nbis/mindtct/dft.c +++ b/libfprint/nbis/mindtct/dft.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -44,87 +65,8 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include -/************************************************************************* -************************************************************************** -#cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling -#cat: the current image block at a given orientation. The -#cat: sampling is conducted using a precomputed set of rotated -#cat: pixel offsets (called a grid) relative to the orgin of -#cat: the image block. - - Input: - blkptr - the pixel address of the origin of the current image block - grid_offsets - the rotated pixel offsets for a block-sized grid - rotated according to a specific orientation - blocksize - the width and height of the image block and thus the size - of the rotated grid - Output: - rowsums - the resulting vector of pixel row sums -**************************************************************************/ -static void sum_rot_block_rows(int *rowsums, const unsigned char *blkptr, - const int *grid_offsets, const int blocksize) -{ - int ix, iy, gi; - - /* Initialize rotation offset index. */ - gi = 0; - - /* For each row in block ... */ - for(iy = 0; iy < blocksize; iy++){ - /* The sums are accumlated along the rotated rows of the grid, */ - /* so initialize row sum to 0. */ - rowsums[iy] = 0; - /* Foreach column in block ... */ - for(ix = 0; ix < blocksize; ix++){ - /* Accumulate pixel value at rotated grid position in image */ - rowsums[iy] += *(blkptr + grid_offsets[gi]); - gi++; - } - } -} - -/************************************************************************* -************************************************************************** -#cat: dft_power - Computes the DFT power by applying a specific wave form -#cat: frequency to a vector of pixel row sums computed from a -#cat: specific orientation of the block image - - Input: - rowsums - accumulated rows of pixels from within a rotated grid - overlaying an input image block - wave - the wave form (cosine and sine components) at a specific - frequency - wavelen - the length of the wave form (must match the height of the - image block which is the length of the rowsum vector) - Output: - power - the computed DFT power for the given wave form at the - given orientation within the image block -**************************************************************************/ -static void dft_power(double *power, const int *rowsums, - const DFTWAVE *wave, const int wavelen) -{ - int i; - double cospart, sinpart; - - /* Initialize accumulators */ - cospart = 0.0; - sinpart = 0.0; - - /* Accumulate cos and sin components of DFT. */ - for(i = 0; i < wavelen; i++){ - /* Multiply each rotated row sum by its */ - /* corresponding cos or sin point in DFT wave. */ - cospart += (rowsums[i] * wave->cos[i]); - sinpart += (rowsums[i] * wave->sin[i]); - } - - /* Power is the sum of the squared cos and sin components */ - *power = (cospart * cospart) + (sinpart * sinpart); -} - /************************************************************************* ************************************************************************** #cat: dft_dir_powers - Conducts the DFT analysis on a block of image data. @@ -176,6 +118,7 @@ int dft_dir_powers(double **powers, unsigned char *pdata, fprintf(stderr, "ERROR : dft_dir_powers : malloc : rowsums\n"); return(-91); } + memset(rowsums, 0, dftgrids->grid_w * sizeof(int)); /* Foreach direction ... */ for(dir = 0; dir < dftgrids->ngrids; dir++){ @@ -199,105 +142,80 @@ int dft_dir_powers(double **powers, unsigned char *pdata, /************************************************************************* ************************************************************************** -#cat: get_max_norm - Analyses a DFT power vector for a specific wave form -#cat: applied at different orientations (directions) to the -#cat: current image block. The routine retuns the maximum -#cat: power value in the vector, the direction at which the -#cat: maximum occurs, and a normalized power value. The -#cat: normalized power is computed as the maximum power divided -#cat: by the average power across all the directions. These -#cat: simple statistics are fundamental to the selection of -#cat: a dominant direction flow for the image block. +#cat: sum_rot_block_rows - Computes a vector or pixel row sums by sampling +#cat: the current image block at a given orientation. The +#cat: sampling is conducted using a precomputed set of rotated +#cat: pixel offsets (called a grid) relative to the orgin of +#cat: the image block. Input: - power_vector - the DFT power values derived form a specific wave form - applied at different directions - ndirs - the number of directions to which the wave form was applied + blkptr - the pixel address of the origin of the current image block + grid_offsets - the rotated pixel offsets for a block-sized grid + rotated according to a specific orientation + blocksize - the width and height of the image block and thus the size + of the rotated grid Output: - powmax - the maximum power value in the DFT power vector - powmax_dir - the direciton at which the maximum power value occured - pownorm - the normalized power corresponding to the maximum power + rowsums - the resulting vector of pixel row sums **************************************************************************/ -static void get_max_norm(double *powmax, int *powmax_dir, - double *pownorm, const double *power_vector, const int ndirs) +void sum_rot_block_rows(int *rowsums, const unsigned char *blkptr, + const int *grid_offsets, const int blocksize) { - int dir; - double max_v, powsum; - int max_i; - double powmean; + int ix, iy, gi; - /* Find max power value and store corresponding direction */ - max_v = power_vector[0]; - max_i = 0; + /* Initialize rotation offset index. */ + gi = 0; - /* Sum the total power in a block at a given direction */ - powsum = power_vector[0]; - - /* For each direction ... */ - for(dir = 1; dir < ndirs; dir++){ - powsum += power_vector[dir]; - if(power_vector[dir] > max_v){ - max_v = power_vector[dir]; - max_i = dir; + /* For each row in block ... */ + for(iy = 0; iy < blocksize; iy++){ + /* The sums are accumlated along the rotated rows of the grid, */ + /* so initialize row sum to 0. */ + rowsums[iy] = 0; + /* Foreach column in block ... */ + for(ix = 0; ix < blocksize; ix++){ + /* Accumulate pixel value at rotated grid position in image */ + rowsums[iy] += *(blkptr + grid_offsets[gi]); + gi++; } } - - *powmax = max_v; - *powmax_dir = max_i; - - /* Powmean is used as denominator for pownorm, so setting */ - /* a non-zero minimum avoids possible division by zero. */ - powmean = max(powsum, MIN_POWER_SUM)/(double)ndirs; - - *pownorm = *powmax / powmean; } /************************************************************************* ************************************************************************** -#cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics -#cat: by sorting on the normalized squared maximum power. +#cat: dft_power - Computes the DFT power by applying a specific wave form +#cat: frequency to a vector of pixel row sums computed from a +#cat: specific orientation of the block image Input: - powmaxs - maximum DFT power for each wave form used to derive - statistics - pownorms - normalized maximum power corresponding to values in powmaxs - nstats - number of wave forms used to derive statistics (N Wave - 1) + rowsums - accumulated rows of pixels from within a rotated grid + overlaying an input image block + wave - the wave form (cosine and sine components) at a specific + frequency + wavelen - the length of the wave form (must match the height of the + image block which is the length of the rowsum vector) Output: - wis - sorted list of indices corresponding to the ranked set of - wave form statistics. These indices will be used as - indirect addresses when processing the power statistics - in descending order of "dominance" - Return Code: - Zero - successful completion - Negative - system error + power - the computed DFT power for the given wave form at the + given orientation within the image block **************************************************************************/ -static int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms, - const int nstats) +void dft_power(double *power, const int *rowsums, + const DFTWAVE *wave, const int wavelen) { int i; - double *pownorms2; + double cospart, sinpart; - /* Allocate normalized power^2 array */ - pownorms2 = (double *)malloc(nstats * sizeof(double)); - if(pownorms2 == (double *)NULL){ - fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n"); - return(-100); + /* Initialize accumulators */ + cospart = 0.0; + sinpart = 0.0; + + /* Accumulate cos and sin components of DFT. */ + for(i = 0; i < wavelen; i++){ + /* Multiply each rotated row sum by its */ + /* corresponding cos or sin point in DFT wave. */ + cospart += (rowsums[i] * wave->cos[i]); + sinpart += (rowsums[i] * wave->sin[i]); } - for(i = 0; i < nstats; i++){ - /* Wis will hold the sorted statistic indices when all is done. */ - wis[i] = i; - /* This is normalized squared max power. */ - pownorms2[i] = powmaxs[i] * pownorms[i]; - } - - /* Sort the statistic indices on the normalized squared power. */ - bubble_sort_double_dec_2(pownorms2, wis, nstats); - - /* Deallocate the working memory. */ - free(pownorms2); - - return(0); + /* Power is the sum of the squared cos and sin components */ + *power = (cospart * cospart) + (sinpart * sinpart); } /************************************************************************* @@ -356,3 +274,106 @@ int dft_power_stats(int *wis, double *powmaxs, int *powmax_dirs, return(0); } +/************************************************************************* +************************************************************************** +#cat: get_max_norm - Analyses a DFT power vector for a specific wave form +#cat: applied at different orientations (directions) to the +#cat: current image block. The routine retuns the maximum +#cat: power value in the vector, the direction at which the +#cat: maximum occurs, and a normalized power value. The +#cat: normalized power is computed as the maximum power divided +#cat: by the average power across all the directions. These +#cat: simple statistics are fundamental to the selection of +#cat: a dominant direction flow for the image block. + + Input: + power_vector - the DFT power values derived form a specific wave form + applied at different directions + ndirs - the number of directions to which the wave form was applied + Output: + powmax - the maximum power value in the DFT power vector + powmax_dir - the direciton at which the maximum power value occured + pownorm - the normalized power corresponding to the maximum power +**************************************************************************/ +void get_max_norm(double *powmax, int *powmax_dir, + double *pownorm, const double *power_vector, const int ndirs) +{ + int dir; + double max_v, powsum; + int max_i; + double powmean; + + /* Find max power value and store corresponding direction */ + max_v = power_vector[0]; + max_i = 0; + + /* Sum the total power in a block at a given direction */ + powsum = power_vector[0]; + + /* For each direction ... */ + for(dir = 1; dir < ndirs; dir++){ + powsum += power_vector[dir]; + if(power_vector[dir] > max_v){ + max_v = power_vector[dir]; + max_i = dir; + } + } + + *powmax = max_v; + *powmax_dir = max_i; + + /* Powmean is used as denominator for pownorm, so setting */ + /* a non-zero minimum avoids possible division by zero. */ + powmean = max(powsum, MIN_POWER_SUM)/(double)ndirs; + + *pownorm = *powmax / powmean; +} + +/************************************************************************* +************************************************************************** +#cat: sort_dft_waves - Creates a ranked list of DFT wave form statistics +#cat: by sorting on the normalized squared maximum power. + + Input: + powmaxs - maximum DFT power for each wave form used to derive + statistics + pownorms - normalized maximum power corresponding to values in powmaxs + nstats - number of wave forms used to derive statistics (N Wave - 1) + Output: + wis - sorted list of indices corresponding to the ranked set of + wave form statistics. These indices will be used as + indirect addresses when processing the power statistics + in descending order of "dominance" + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ +int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms, + const int nstats) +{ + int i; + double *pownorms2; + + /* Allocate normalized power^2 array */ + pownorms2 = (double *)malloc(nstats * sizeof(double)); + if(pownorms2 == (double *)NULL){ + fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n"); + return(-100); + } + + for(i = 0; i < nstats; i++){ + /* Wis will hold the sorted statistic indices when all is done. */ + wis[i] = i; + /* This is normalized squared max power. */ + pownorms2[i] = powmaxs[i] * pownorms[i]; + } + + /* Sort the statistic indices on the normalized squared power. */ + bubble_sort_double_dec_2(pownorms2, wis, nstats); + + /* Deallocate the working memory. */ + free(pownorms2); + + return(0); +} + diff --git a/libfprint/nbis/mindtct/free.c b/libfprint/nbis/mindtct/free.c index fd7612e4..adaeeb9a 100644 --- a/libfprint/nbis/mindtct/free.c +++ b/libfprint/nbis/mindtct/free.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -40,7 +61,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* diff --git a/libfprint/nbis/mindtct/getmin.c b/libfprint/nbis/mindtct/getmin.c new file mode 100644 index 00000000..08a087d8 --- /dev/null +++ b/libfprint/nbis/mindtct/getmin.c @@ -0,0 +1,175 @@ +/******************************************************************************* + +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. + +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. + +*******************************************************************************/ + + +/*********************************************************************** + LIBRARY: LFS - NIST Latent Fingerprint System + + FILE: GETMIN.C + AUTHOR: Michael D. Garris + DATE: 09/10/2004 + UPDATED: 03/16/2005 by MDG + + Takes an 8-bit grayscale fingerpinrt image and detects minutiae + as part of the NIST Latent Fingerprint System (LFS), returning + minutiae with final reliabilities and maps including a merged + quality map. + +*********************************************************************** + ROUTINES: + get_minutiae() + +***********************************************************************/ + +#include +#include + +/************************************************************************* +************************************************************************** +#cat: get_minutiae - Takes a grayscale fingerprint image, binarizes the input +#cat: image, and detects minutiae points using LFS Version 2. +#cat: The routine passes back the detected minutiae, the +#cat: binarized image, and a set of image quality maps. + + Input: + idata - grayscale fingerprint image data + iw - width (in pixels) of the grayscale image + ih - height (in pixels) of the grayscale image + id - pixel depth (in bits) of the grayscale image + ppmm - the scan resolution (in pixels/mm) of the grayscale image + lfsparms - parameters and thresholds for controlling LFS + Output: + ominutiae - points to a structure containing the + detected minutiae + oquality_map - resulting integrated image quality map + odirection_map - resulting direction map + olow_contrast_map - resulting low contrast map + olow_flow_map - resulting low ridge flow map + ohigh_curve_map - resulting high curvature map + omap_w - width (in blocks) of image maps + omap_h - height (in blocks) of image maps + obdata - points to binarized image data + obw - width (in pixels) of binarized image + obh - height (in pixels) of binarized image + obd - pixel depth (in bits) of binarized image + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ +int get_minutiae(MINUTIAE **ominutiae, int **oquality_map, + int **odirection_map, int **olow_contrast_map, + int **olow_flow_map, int **ohigh_curve_map, + int *omap_w, int *omap_h, + unsigned char **obdata, int *obw, int *obh, int *obd, + unsigned char *idata, const int iw, const int ih, + const int id, const double ppmm, const LFSPARMS *lfsparms) +{ + int ret; + MINUTIAE *minutiae; + int *direction_map, *low_contrast_map, *low_flow_map; + int *high_curve_map, *quality_map; + int map_w, map_h; + unsigned char *bdata; + int bw, bh; + + /* If input image is not 8-bit grayscale ... */ + if(id != 8){ + fprintf(stderr, "ERROR : get_minutiae : input image pixel "); + fprintf(stderr, "depth = %d != 8.\n", id); + return(-2); + } + + /* Detect minutiae in grayscale fingerpeint image. */ + if((ret = lfs_detect_minutiae_V2(&minutiae, + &direction_map, &low_contrast_map, + &low_flow_map, &high_curve_map, + &map_w, &map_h, + &bdata, &bw, &bh, + idata, iw, ih, lfsparms))){ + return(ret); + } + + /* Build integrated quality map. */ + if((ret = gen_quality_map(&quality_map, + direction_map, low_contrast_map, + low_flow_map, high_curve_map, map_w, map_h))){ + free_minutiae(minutiae); + free(direction_map); + free(low_contrast_map); + free(low_flow_map); + free(high_curve_map); + free(bdata); + return(ret); + } + + /* Assign reliability from quality map. */ + if((ret = combined_minutia_quality(minutiae, quality_map, map_w, map_h, + lfsparms->blocksize, + idata, iw, ih, id, ppmm))){ + free_minutiae(minutiae); + free(direction_map); + free(low_contrast_map); + free(low_flow_map); + free(high_curve_map); + free(quality_map); + free(bdata); + return(ret); + } + + /* Set output pointers. */ + *ominutiae = minutiae; + *oquality_map = quality_map; + *odirection_map = direction_map; + *olow_contrast_map = low_contrast_map; + *olow_flow_map = low_flow_map; + *ohigh_curve_map = high_curve_map; + *omap_w = map_w; + *omap_h = map_h; + *obdata = bdata; + *obw = bw; + *obh = bh; + *obd = id; + + /* Return normally. */ + return(0); +} diff --git a/libfprint/nbis/mindtct/globals.c b/libfprint/nbis/mindtct/globals.c index e17c7dc9..da10c152 100644 --- a/libfprint/nbis/mindtct/globals.c +++ b/libfprint/nbis/mindtct/globals.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -40,7 +61,7 @@ identified are necessarily the best available for the purpose. /*************************************************************************/ #ifdef LOG_REPORT -FILE *g_logfp; +FILE *logfp; #endif /* Constants (C) for defining 4 DFT frequencies, where */ @@ -129,8 +150,6 @@ LFSPARMS g_lfsparms = { PORES_STEPS_BWD, PORES_MIN_DIST2, PORES_MAX_RATIO, - FALSE, /* not removing perimeter points by default */ - PERIMETER_PTS_DISTANCE, /* Ridge Counting Controls */ MAX_NBRS, @@ -215,8 +234,6 @@ LFSPARMS g_lfsparms_V2 = { PORES_STEPS_BWD, PORES_MIN_DIST2, PORES_MAX_RATIO, - FALSE, /* not removing perimeter points by default */ - PERIMETER_PTS_DISTANCE, /* Ridge Counting Controls */ MAX_NBRS, diff --git a/libfprint/nbis/mindtct/imgutil.c b/libfprint/nbis/mindtct/imgutil.c index c4fa8689..50cf7666 100644 --- a/libfprint/nbis/mindtct/imgutil.c +++ b/libfprint/nbis/mindtct/imgutil.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -45,7 +66,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include #include @@ -65,18 +85,6 @@ identified are necessarily the best available for the purpose. Output: idata - contains the bit-shifted results **************************************************************************/ -void bits_6to8(unsigned char *idata, const int iw, const int ih) -{ - int i, isize; - unsigned char *iptr; - - isize = iw * ih; - iptr = idata; - for(i = 0; i < isize; i++){ - /* Multiply every pixel value by 4 so that [0..64) -> [0..255) */ - *iptr++ <<= 2; - } -} /************************************************************************* ************************************************************************** diff --git a/libfprint/nbis/mindtct/init.c b/libfprint/nbis/mindtct/init.c index 50dc0d7e..90152283 100644 --- a/libfprint/nbis/mindtct/init.c +++ b/libfprint/nbis/mindtct/init.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -37,6 +58,7 @@ identified are necessarily the best available for the purpose. ROUTINES: init_dir2rad() init_dftwaves() + get_max_padding() get_max_padding_V2() init_rotgrids() alloc_dir_powers() @@ -44,7 +66,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* @@ -242,6 +263,33 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs, return(0); } +/************************************************************************* +************************************************************************** +#cat: get_max_padding - Deterines the maximum amount of image pixel padding +#cat: required by all LFS processes. Padding is currently +#cat: required by the rotated grids used in DFT analyses, +#cat: rotated grids used in directional binarization, +#cat: and in the grid used for isotropic binarization. +#cat: The NIST generalized code enables the parameters +#cat: governing these processes to be redefined, so a check +#cat: at runtime is required to determine which process +#cat: requires the most padding. By using the maximum as +#cat: the padding factor, all processes will run safely +#cat: with a single padding of the input image avoiding the +#cat: need to repad for further processes. + + Input: + imap_blocksize - the size (in pixels) of each IMAP block in the image + dirbin_grid_w - the width (in pixels) of the rotated grids used in + directional binarization + dirbin_grid_h - the height (in pixels) of the rotated grids used in + directional binarization + isobin_grid_dim - the dimension (in pixels) of the square grid used in + isotropic binarization + Return Code: + Non-negative - the maximum padding required for all processes +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: get_max_padding_V2 - Deterines the maximum amount of image pixel padding @@ -645,6 +693,9 @@ int alloc_power_stats(int **owis, double **opowmaxs, int **opowmax_dirs, int *wis, *powmax_dirs; double *powmaxs, *pownorms; + ASSERT_SIZE_MUL(nstats, sizeof(int)); + ASSERT_SIZE_MUL(nstats, sizeof(double)); + /* Allocate DFT wave index vector */ wis = (int *)malloc(nstats * sizeof(int)); if(wis == (int *)NULL){ @@ -677,7 +728,7 @@ int alloc_power_stats(int **owis, double **opowmaxs, int **opowmax_dirs, /* Free memory allocated to this point. */ free(wis); free(powmaxs); - free(pownorms); + free(powmax_dirs); fprintf(stderr, "ERROR : alloc_power_stats : malloc : pownorms\n"); return(-53); } diff --git a/libfprint/nbis/mindtct/line.c b/libfprint/nbis/mindtct/line.c index 5d9a8ed5..07edf18d 100644 --- a/libfprint/nbis/mindtct/line.c +++ b/libfprint/nbis/mindtct/line.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -38,7 +59,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* diff --git a/libfprint/nbis/mindtct/link.c b/libfprint/nbis/mindtct/link.c new file mode 100644 index 00000000..22e568a9 --- /dev/null +++ b/libfprint/nbis/mindtct/link.c @@ -0,0 +1,254 @@ +/******************************************************************************* + +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. + +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. + +*******************************************************************************/ + + +/*********************************************************************** + LIBRARY: LFS - NIST Latent Fingerprint System + + FILE: LINK.C + AUTHOR: Michael D. Garris + DATE: 08/02/1999 + UPDATED: 10/04/1999 Version 2 by MDG + UPDATED: 03/16/2005 by MDG + + Contains routines responsible for linking compatible minutiae + together as part of the NIST Latent Fingerprint System (LFS). + +*********************************************************************** + ROUTINES: + link_minutiae() + create_link_table() + update_link_table() + order_link_table() + process_link_table() + link_score() +***********************************************************************/ + +#include +#include +#include + +/************************************************************************* +************************************************************************** +#cat: link_minutiae - Clusters minutiae that are sufficiently close to each +#cat: other and have compatible directions to be considered part +#cat: of the same ridge or valley and then links them together. +#cat: In linking two minutia, the respective minutia features +#cat: in the image are joined by drawing pixels and the points +#cat: are removed from the list. + + Input: + minutiae - list of true and false minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + bdata - edited binary image with breaks in ridges and valleys filled + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: create_link_table - Builds a 2D minutia link table where each cell in the +#cat: table represents a potential linking of 2 different +#cat: minutia points. Minutia IDs are stored on each axes +#cat: and scores representing the degree of compatibility +#cat: between 2 minutia are stored in each cell. Note that +#cat: the table is sparsely filled with scores. + + Input: + tbldim - dimension of each axes of the link table + start - index position of starting minutia point in input list + minutiae - list of minutia + onloop - list of loop flags (on flag for each minutia point in list) + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS + Output: + olink_table - sparse 2D table containing scores of potentially + linked minutia pairs + ox_axis - minutia IDs registered along x-axis + oy_axis - minutia IDs registered along y-axis + onx_axis - number of minutia registered along x-axis + ony_axis - number of minutia registered along y-axis + on_entries - number of scores currently entered in the table + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: update_link_table - Takes the indices of 2 minutia and their link +#cat: compatibility score and updates the 2D link table. +#cat: The input minutia are registered to positions along +#cat: different axes, if they are not already in the table, +#cat: and a queue is maintained so that a cluster of +#cat: potentially linked points may be gathered. + + Input: + link_table - sparse 2D table containing scores of potentially linked + minutia pairs + x_axis - minutia IDs registered along x-axis + y_axis - minutia IDs registered along y-axis + nx_axis - number of minutia registered along x-axis + ny_axis - number of minutia registered along y-axis + n_entries - number of scores currently entered in the table + tbldim - dimension of each axes of the link table + queue - list of clustered minutiae yet to be used to locate + other compatible minutiae + head - head of the queue + tail - tail of the queue + inqueue - flag for each minutia point in minutiae list to signify if + it has been clustered with the points in this current link + table + first - index position of first minutia of current link pair + second - index position of second minutia of current link pair + score - degree of link compatibility of current link pair + Output: + link_table - updated sparse 2D table containing scores of potentially + linked minutia pairs + x_axis - updated minutia IDs registered along x-axis + y_axis - updated minutia IDs registered along y-axis + nx_axis - updated number of minutia registered along x-axis + ny_axis - updated number of minutia registered along y-axis + n_entries - updated number of scores currently entered in the table + queue - updated list of clustered minutiae yet to be used to locate + other compatible minutiae + tail - updated tail of the queue + inqueue - updated list of flags, one for each minutia point in + minutiae list to signify if it has been clustered with + the points in this current link table + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: order_link_table - Puts the link table in sorted order based on x and +#cat: then y-axis entries. These minutia are sorted based +#cat: on their point of perpendicular intersection with a +#cat: line running from the origin at an angle equal to the +#cat: average direction of all entries in the link table. + + Input: + link_table - sparse 2D table containing scores of potentially linked + minutia pairs + x_axis - minutia IDs registered along x-axis + y_axis - minutia IDs registered along y-axis + nx_axis - number of minutia registered along x-axis + ny_axis - number of minutia registered along y-axis + n_entries - number of scores currently entered in the table + tbldim - dimension of each axes of the link table + minutiae - list of minutia + ndirs - number of IMAP directions (in semicircle) + Output: + link_table - sorted sparse 2D table containing scores of potentially + linked minutia pairs + x_axis - sorted minutia IDs registered along x-axis + y_axis - sorted minutia IDs registered along y-axis + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: process_link_table - Processes the link table deciding which minutia +#cat: pairs in the table should be linked (ie. joined in +#cat: the image and removed from the minutiae list (and +#cat: from onloop). + + Input: + link_table - sparse 2D table containing scores of potentially linked + minutia pairs + x_axis - minutia IDs registered along x-axis + y_axis - minutia IDs registered along y-axis + nx_axis - number of minutia registered along x-axis + ny_axis - number of minutia registered along y-axis + n_entries - number of scores currently entered in the table + tbldim - dimension of each axes of the link table + minutiae - list of minutia + onloop - list of flags signifying which minutia lie on small lakes + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + onloop - updated loop flags + bdata - edited image with minutia features joined + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: link_score - Takes 2 parameters, a 'join angle' and a 'join distance' +#cat: computed between 2 minutia and combines these to compute +#cat: a score representing the degree of link compatibility +#cat: between the 2 minutiae. + + Input: + jointheta - angle measured between 2 minutiae + joindist - distance between 2 minutiae + lfsparms - parameters and thresholds for controlling LFS + Return Code: + Score - degree of link compatibility +**************************************************************************/ + diff --git a/libfprint/nbis/mindtct/log.c b/libfprint/nbis/mindtct/log.c index d3aafbf9..b1dcaadf 100644 --- a/libfprint/nbis/mindtct/log.c +++ b/libfprint/nbis/mindtct/log.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -42,17 +63,12 @@ identified are necessarily the best available for the purpose. /* If logging is on, declare global file pointer and supporting */ /* global variable for logging intermediate results. */ -FILE *logfp; -int avrdir; -float dir_strength; -int nvalid; /***************************************************************************/ /***************************************************************************/ int open_logfile() { #ifdef LOG_REPORT - if((logfp = fopen(LOG_FILE, "wb")) == NULL){ fprintf(stderr, "ERROR : open_logfile : fopen : %s\n", LOG_FILE); return(-1); } @@ -69,7 +85,6 @@ void print2log(char *fmt, ...) va_list ap; va_start(ap, fmt); - vfprintf(logfp, fmt, ap); va_end(ap); #endif } @@ -79,7 +94,6 @@ void print2log(char *fmt, ...) int close_logfile() { #ifdef LOG_REPORT - if(fclose(logfp)){ fprintf(stderr, "ERROR : close_logfile : fclose : %s\n", LOG_FILE); return(-1); } diff --git a/libfprint/nbis/mindtct/loop.c b/libfprint/nbis/mindtct/loop.c index 3792b88d..2142d181 100644 --- a/libfprint/nbis/mindtct/loop.c +++ b/libfprint/nbis/mindtct/loop.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -36,8 +57,6 @@ identified are necessarily the best available for the purpose. *********************************************************************** ROUTINES: - chain_code_loop() - is_chain_clockwise() get_loop_list() on_loop() on_island_lake() @@ -48,161 +67,13 @@ identified are necessarily the best available for the purpose. get_loop_aspect() fill_loop() fill_partial_row() + flood_loop() + flood_fill4() ***********************************************************************/ #include -#include #include -/************************************************************************* -************************************************************************** -#cat: chain_code_loop - Converts a feature's contour points into an -#cat: 8-connected chain code vector. This encoding represents -#cat: the direction taken between each adjacent point in the -#cat: contour. Chain codes may be used for many purposes, such -#cat: as computing the perimeter or area of an object, and they -#cat: may be used in object detection and recognition. - - Input: - contour_x - x-coord list for feature's contour points - contour_y - y-coord list for feature's contour points - ncontour - number of points in contour - Output: - ochain - resulting vector of chain codes - onchain - number of codes in chain - (same as number of points in contour) - Return Code: - Zero - chain code successful derived - Negative - system error -**************************************************************************/ -static int chain_code_loop(int **ochain, int *onchain, - const int *contour_x, const int *contour_y, const int ncontour) -{ - int *chain; - int i, j, dx, dy; - - /* If we don't have at least 3 points in the contour ... */ - if(ncontour <= 3){ - /* Then we don't have a loop, so set chain length to 0 */ - /* and return without any allocations. */ - *onchain = 0; - return(0); - } - - /* Allocate chain code vector. It will be the same length as the */ - /* number of points in the contour. There will be one chain code */ - /* between each point on the contour including a code between the */ - /* last to the first point on the contour (completing the loop). */ - chain = (int *)malloc(ncontour * sizeof(int)); - /* If the allocation fails ... */ - if(chain == (int *)NULL){ - fprintf(stderr, "ERROR : chain_code_loop : malloc : chain\n"); - return(-170); - } - - /* For each neighboring point in the list (with "i" pointing to the */ - /* previous neighbor and "j" pointing to the next neighbor... */ - for(i = 0, j=1; i < ncontour-1; i++, j++){ - /* Compute delta in X between neighbors. */ - dx = contour_x[j] - contour_x[i]; - /* Compute delta in Y between neighbors. */ - dy = contour_y[j] - contour_y[i]; - /* Derive chain code index from neighbor deltas. */ - /* The deltas are on the range [-1..1], so to use them as indices */ - /* into the code list, they must first be incremented by one. */ - chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); - } - - /* Now derive chain code between last and first points in the */ - /* contour list. */ - dx = contour_x[0] - contour_x[i]; - dy = contour_y[0] - contour_y[i]; - chain[i] = *(g_chaincodes_nbr8+((dy+1)*NBR8_DIM)+dx+1); - - /* Store results to the output pointers. */ - *ochain = chain; - *onchain = ncontour; - - /* Return normally. */ - return(0); -} - -/************************************************************************* -************************************************************************** -#cat: is_chain_clockwise - Takes an 8-connected chain code vector and -#cat: determines if the codes are ordered clockwise or -#cat: counter-clockwise. -#cat: The routine also requires a default return value be -#cat: specified in the case the the routine is not able to -#cat: definitively determine the chains direction. This allows -#cat: the default response to be application-specific. - - Input: - chain - chain code vector - nchain - number of codes in chain - default_ret - default return code (used when we can't tell the order) - Return Code: - TRUE - chain determined to be ordered clockwise - FALSE - chain determined to be ordered counter-clockwise - Default - could not determine the order of the chain -**************************************************************************/ -static int is_chain_clockwise(const int *chain, const int nchain, - const int default_ret) -{ - int i, j, d, sum; - - /* Initialize turn-accumulator to 0. */ - sum = 0; - - /* Foreach neighboring code in chain, compute the difference in */ - /* direction and accumulate. Left-hand turns increment, whereas */ - /* right-hand decrement. */ - for(i = 0, j =1; i < nchain-1; i++, j++){ - /* Compute delta in neighbor direction. */ - d = chain[j] - chain[i]; - /* Make the delta the "inner" distance. */ - /* If delta >= 4, for example if chain_i==2 and chain_j==7 (which */ - /* means the contour went from a step up to step down-to-the-right) */ - /* then 5=(7-2) which is >=4, so -3=(5-8) which means that the */ - /* change in direction is a righ-hand turn of 3 units). */ - if(d >= 4) - d -= 8; - /* If delta <= -4, for example if chain_i==7 and chain_j==2 (which */ - /* means the contour went from a step down-to-the-right to step up) */ - /* then -5=(2-7) which is <=-4, so 3=(-5+8) which means that the */ - /* change in direction is a left-hand turn of 3 units). */ - else if (d <= -4) - d += 8; - - /* The delta direction is then accumulated. */ - sum += d; - } - - /* Now we need to add in the final delta direction between the last */ - /* and first codes in the chain. */ - d = chain[0] - chain[i]; - if(d >= 4) - d -= 8; - else if (d <= -4) - d += 8; - sum += d; - - /* If the final turn_accumulator == 0, then we CAN'T TELL the */ - /* direction of the chain code, so return the default return value. */ - if(sum == 0) - return(default_ret); - /* Otherwise, if the final turn-accumulator is positive ... */ - else if(sum > 0) - /* Then we had a greater amount of left-hand turns than right-hand */ - /* turns, so the chain is in COUNTER-CLOCKWISE order, so return FALSE. */ - return(FALSE); - /* Otherwise, the final turn-accumulator is negative ... */ - else - /* So we had a greater amount of right-hand turns than left-hand */ - /* turns, so the chain is in CLOCKWISE order, so return TRUE. */ - return(TRUE); -} - /************************************************************************* ************************************************************************** #cat: get_loop_list - Takes a list of minutia points and determines which @@ -228,78 +99,6 @@ static int is_chain_clockwise(const int *chain, const int nchain, Zero - successful completion Negative - system error **************************************************************************/ -int get_loop_list(int **oonloop, MINUTIAE *minutiae, const int loop_len, - unsigned char *bdata, const int iw, const int ih) -{ - int i, ret; - int *onloop; - MINUTIA *minutia; - - /* Allocate a list of onloop flags (one for each minutia in list). */ - onloop = (int *)malloc(minutiae->num * sizeof(int)); - if(onloop == (int *)NULL){ - fprintf(stderr, "ERROR : get_loop_list : malloc : onloop\n"); - return(-320); - } - - i = 0; - /* Foreach minutia remaining in list ... */ - while(i < minutiae->num){ - /* Assign a temporary pointer. */ - minutia = minutiae->list[i]; - /* If current minutia is a bifurcation ... */ - if(minutia->type == BIFURCATION){ - /* Check to see if it is on a loop of specified length. */ - ret = on_loop(minutia, loop_len, bdata, iw, ih); - /* If minutia is on a loop... */ - if(ret == LOOP_FOUND){ - /* Then set the onloop flag to TRUE. */ - onloop[i] = TRUE; - /* Advance to next minutia in the list. */ - i++; - } - /* If on loop test IGNORED ... */ - else if (ret == IGNORE){ - /* Remove the current minutia from the list. */ - if((ret = remove_minutia(i, minutiae))){ - /* Deallocate working memory. */ - free(onloop); - /* Return error code. */ - return(ret); - } - /* No need to advance because next minutia has "slid" */ - /* into position pointed to by 'i'. */ - } - /* If the minutia is NOT on a loop... */ - else if (ret == FALSE){ - /* Then set the onloop flag to FALSE. */ - onloop[i] = FALSE; - /* Advance to next minutia in the list. */ - i++; - } - /* Otherwise, an ERROR occurred while looking for loop. */ - else{ - /* Deallocate working memory. */ - free(onloop); - /* Return error code. */ - return(ret); - } - } - /* Otherwise, the current minutia is a ridge-ending... */ - else{ - /* Ridge-endings will never be on a loop, so set flag to FALSE. */ - onloop[i] = FALSE; - /* Advance to next minutia in the list. */ - i++; - } - } - - /* Store flag list to output pointer. */ - *oonloop = onloop; - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -558,7 +357,7 @@ int on_hook(const MINUTIA *minutia1, const MINUTIA *minutia2, /* If trace had an error in following the contour ... */ if(ret != 0) return(ret); - + /* Otherwise, the trace successfully followed the contour, but did */ /* not encounter the 2nd minutia point within the specified number */ @@ -648,107 +447,6 @@ int is_loop_clockwise(const int *contour_x, const int *contour_y, return(ret); } -/************************************************************************* -************************************************************************** -#cat: get_loop_aspect - Takes a contour list (determined to form a complete -#cat: loop) and measures the loop's aspect (the largest and smallest -#cat: distances across the loop) and returns the points on the -#cat: loop where these distances occur. - - Input: - contour_x - x-coord list for loop's contour points - contour_y - y-coord list for loop's contour points - ncontour - number of points in contour - Output: - omin_fr - contour point index where minimum aspect occurs - omin_to - opposite contour point index where minimum aspect occurs - omin_dist - the minimum distance across the loop - omax_fr - contour point index where maximum aspect occurs - omax_to - contour point index where maximum aspect occurs - omax_dist - the maximum distance across the loop -**************************************************************************/ -static void get_loop_aspect(int *omin_fr, int *omin_to, double *omin_dist, - int *omax_fr, int *omax_to, double *omax_dist, - const int *contour_x, const int *contour_y, const int ncontour) -{ - int halfway, limit; - int i, j; - double dist; - double min_dist, max_dist; - int min_i, max_i, min_j, max_j; - - /* Compute half the perimeter of the loop. */ - halfway = ncontour>>1; - - /* Take opposite points on the contour and walk half way */ - /* around the loop. */ - i = 0; - j = halfway; - /* Compute squared distance between opposite points on loop. */ - dist = squared_distance(contour_x[i], contour_y[i], - contour_x[j], contour_y[j]); - - /* Initialize running minimum and maximum distances along loop. */ - min_dist = dist; - min_i = i; - min_j = j; - max_dist = dist; - max_i = i; - max_j = j; - /* Bump to next pair of opposite points. */ - i++; - /* Make sure j wraps around end of list. */ - j++; - j %= ncontour; - - /* If the loop is of even length, then we only need to walk half */ - /* way around as the other half will be exactly redundant. If */ - /* the loop is of odd length, then the second half will not be */ - /* be exactly redundant and the difference "may" be meaningful. */ - /* If execution speed is an issue, then probably get away with */ - /* walking only the fist half of the loop under ALL conditions. */ - - /* If loop has odd length ... */ - if(ncontour % 2) - /* Walk the loop's entire perimeter. */ - limit = ncontour; - /* Otherwise the loop has even length ... */ - else - /* Only walk half the perimeter. */ - limit = halfway; - - /* While we have not reached our perimeter limit ... */ - while(i < limit){ - /* Compute squared distance between opposite points on loop. */ - dist = squared_distance(contour_x[i], contour_y[i], - contour_x[j], contour_y[j]); - /* Check the running minimum and maximum distances. */ - if(dist < min_dist){ - min_dist = dist; - min_i = i; - min_j = j; - } - if(dist > max_dist){ - max_dist = dist; - max_i = i; - max_j = j; - } - /* Bump to next pair of opposite points. */ - i++; - /* Make sure j wraps around end of list. */ - j++; - j %= ncontour; - } - - /* Assign minimum and maximum distances to output pointers. */ - *omin_fr = min_i; - *omin_to = min_j; - *omin_dist = min_dist; - *omax_fr = max_i; - *omax_to = max_j; - *omax_dist = max_dist; -} - /************************************************************************* ************************************************************************** #cat: process_loop - Takes a contour list that has been determined to form @@ -776,131 +474,6 @@ static void get_loop_aspect(int *omin_fr, int *omin_to, double *omin_dist, Zero - loop processed successfully Negative - system error **************************************************************************/ -int process_loop(MINUTIAE *minutiae, - const int *contour_x, const int *contour_y, - const int *contour_ex, const int *contour_ey, const int ncontour, - unsigned char *bdata, const int iw, const int ih, - const LFSPARMS *lfsparms) -{ - int idir, type, appearing; - double min_dist, max_dist; - int min_fr, max_fr, min_to, max_to; - int mid_x, mid_y, mid_pix; - int feature_pix; - int ret; - MINUTIA *minutia; - - /* If contour is empty, then just return. */ - if(ncontour <= 0) - return(0); - - /* If loop is large enough ... */ - if(ncontour > lfsparms->min_loop_len){ - /* Get pixel value of feature's interior. */ - feature_pix = *(bdata + (contour_y[0] * iw) + contour_x[0]); - - /* Get the aspect dimensions of the loop in units of */ - /* squared distance. */ - get_loop_aspect(&min_fr, &min_to, &min_dist, - &max_fr, &max_to, &max_dist, - contour_x, contour_y, ncontour); - - /* If loop passes aspect ratio tests ... loop is sufficiently */ - /* narrow or elongated ... */ - if((min_dist < lfsparms->min_loop_aspect_dist) || - ((max_dist/min_dist) >= lfsparms->min_loop_aspect_ratio)){ - - /* Update minutiae list with opposite points of max distance */ - /* on the loop. */ - - /* First, check if interior point has proper pixel value. */ - mid_x = (contour_x[max_fr]+contour_x[max_to])>>1; - mid_y = (contour_y[max_fr]+contour_y[max_to])>>1; - mid_pix = *(bdata + (mid_y * iw) + mid_x); - /* If interior point is the same as the feature... */ - if(mid_pix == feature_pix){ - - /* 1. Treat maximum distance point as a potential minutia. */ - - /* Compute direction from maximum loop point to its */ - /* opposite point. */ - idir = line2direction(contour_x[max_fr], contour_y[max_fr], - contour_x[max_to], contour_y[max_to], - lfsparms->num_directions); - /* Get type of minutia: BIFURCATION or RIDGE_ENDING. */ - type = minutia_type(feature_pix); - /* Determine if minutia is appearing or disappearing. */ - if((appearing = is_minutia_appearing( - contour_x[max_fr], contour_y[max_fr], - contour_ex[max_fr], contour_ey[max_fr])) < 0){ - /* Return system error code. */ - return(appearing); - } - /* Create new minutia object. */ - if((ret = create_minutia(&minutia, - contour_x[max_fr], contour_y[max_fr], - contour_ex[max_fr], contour_ey[max_fr], - idir, DEFAULT_RELIABILITY, - type, appearing, LOOP_ID))){ - /* Return system error code. */ - return(ret); - } - /* Update the minutiae list with potential new minutia. */ - ret = update_minutiae(minutiae, minutia, bdata, iw, ih, lfsparms); - - /* If minuitia IGNORED and not added to the minutia list ... */ - if(ret == IGNORE) - /* Deallocate the minutia. */ - free_minutia(minutia); - - /* 2. Treat point opposite of maximum distance point as */ - /* a potential minutia. */ - - /* Flip the direction 180 degrees. Make sure new direction */ - /* is on the range [0..(ndirsX2)]. */ - idir += lfsparms->num_directions; - idir %= (lfsparms->num_directions<<1); - - /* The type of minutia will stay the same. */ - - /* Determine if minutia is appearing or disappearing. */ - if((appearing = is_minutia_appearing( - contour_x[max_to], contour_y[max_to], - contour_ex[max_to], contour_ey[max_to])) < 0){ - /* Return system error code. */ - return(appearing); - } - /* Create new minutia object. */ - if((ret = create_minutia(&minutia, - contour_x[max_to], contour_y[max_to], - contour_ex[max_to], contour_ey[max_to], - idir, DEFAULT_RELIABILITY, - type, appearing, LOOP_ID))){ - /* Return system error code. */ - return(ret); - } - /* Update the minutiae list with potential new minutia. */ - ret = update_minutiae(minutiae, minutia, bdata, iw, ih, lfsparms); - - /* If minuitia IGNORED and not added to the minutia list ... */ - if(ret == IGNORE) - /* Deallocate the minutia. */ - free_minutia(minutia); - - /* Done successfully processing this loop, so return normally. */ - return(0); - - } /* Otherwise, loop interior has problems. */ - } /* Otherwise, loop is not the right shape for minutiae. */ - } /* Otherwise, loop's perimeter is too small for minutiae. */ - - /* If we get here, we have a loop that is assumed to not contain */ - /* minutiae, so remove the loop from the image. */ - ret = fill_loop(contour_x, contour_y, ncontour, bdata, iw, ih); - - /* Return either an error code from fill_loop or return normally. */ - return(ret); -} /************************************************************************* ************************************************************************** @@ -1087,39 +660,103 @@ int process_loop_V2(MINUTIAE *minutiae, /************************************************************************* ************************************************************************** -#cat: fill_partial_row - Fills a specified range of contiguous pixels on -#cat: a specified row of an 8-bit pixel image with a specified -#cat: pixel value. NOTE, the pixel coordinates are assumed to -#cat: be within the image boundaries. +#cat: get_loop_aspect - Takes a contour list (determined to form a complete +#cat: loop) and measures the loop's aspect (the largest and smallest +#cat: distances across the loop) and returns the points on the +#cat: loop where these distances occur. Input: - fill_pix - pixel value to fill with (should be on range [0..255] - frx - x-pixel coord where fill should begin - tox - x-pixel coord where fill should end (inclusive) - y - y-pixel coord of current row being filled - bdata - 8-bit image data - iw - width (in pixels) of image - ih - height (in pixels) of image + contour_x - x-coord list for loop's contour points + contour_y - y-coord list for loop's contour points + ncontour - number of points in contour Output: - bdata - 8-bit image data with partial row filled. + omin_fr - contour point index where minimum aspect occurs + omin_to - opposite contour point index where minimum aspect occurs + omin_dist - the minimum distance across the loop + omax_fr - contour point index where maximum aspect occurs + omax_to - contour point index where maximum aspect occurs + omax_dist - the maximum distance across the loop **************************************************************************/ -static void fill_partial_row(const int fill_pix, const int frx, const int tox, - const int y, unsigned char *bdata, const int iw, const int ih) +void get_loop_aspect(int *omin_fr, int *omin_to, double *omin_dist, + int *omax_fr, int *omax_to, double *omax_dist, + const int *contour_x, const int *contour_y, const int ncontour) { - int x; - unsigned char *bptr; + int halfway, limit; + int i, j; + double dist; + double min_dist, max_dist; + int min_i, max_i, min_j, max_j; - /* Set pixel pointer to starting x-coord on current row. */ - bptr = bdata+(y*iw)+frx; + /* Compute half the perimeter of the loop. */ + halfway = ncontour>>1; - /* Foreach pixel between starting and ending x-coord on row */ - /* (including the end points) ... */ - for(x = frx; x <= tox; x++){ - /* Set current pixel with fill pixel value. */ - *bptr = fill_pix; - /* Bump to next pixel in the row. */ - bptr++; + /* Take opposite points on the contour and walk half way */ + /* around the loop. */ + i = 0; + j = halfway; + /* Compute squared distance between opposite points on loop. */ + dist = squared_distance(contour_x[i], contour_y[i], + contour_x[j], contour_y[j]); + + /* Initialize running minimum and maximum distances along loop. */ + min_dist = dist; + min_i = i; + min_j = j; + max_dist = dist; + max_i = i; + max_j = j; + /* Bump to next pair of opposite points. */ + i++; + /* Make sure j wraps around end of list. */ + j++; + j %= ncontour; + + /* If the loop is of even length, then we only need to walk half */ + /* way around as the other half will be exactly redundant. If */ + /* the loop is of odd length, then the second half will not be */ + /* be exactly redundant and the difference "may" be meaningful. */ + /* If execution speed is an issue, then probably get away with */ + /* walking only the fist half of the loop under ALL conditions. */ + + /* If loop has odd length ... */ + if(ncontour % 2) + /* Walk the loop's entire perimeter. */ + limit = ncontour; + /* Otherwise the loop has even length ... */ + else + /* Only walk half the perimeter. */ + limit = halfway; + + /* While we have not reached our perimeter limit ... */ + while(i < limit){ + /* Compute squared distance between opposite points on loop. */ + dist = squared_distance(contour_x[i], contour_y[i], + contour_x[j], contour_y[j]); + /* Check the running minimum and maximum distances. */ + if(dist < min_dist){ + min_dist = dist; + min_i = i; + min_j = j; + } + if(dist > max_dist){ + max_dist = dist; + max_i = i; + max_j = j; + } + /* Bump to next pair of opposite points. */ + i++; + /* Make sure j wraps around end of list. */ + j++; + j %= ncontour; } + + /* Assign minimum and maximum distances to output pointers. */ + *omin_fr = min_i; + *omin_to = min_j; + *omin_dist = min_dist; + *omax_fr = max_i; + *omax_to = max_j; + *omax_dist = max_dist; } /************************************************************************* @@ -1253,3 +890,119 @@ int fill_loop(const int *contour_x, const int *contour_y, return(0); } +/************************************************************************* +************************************************************************** +#cat: fill_partial_row - Fills a specified range of contiguous pixels on +#cat: a specified row of an 8-bit pixel image with a specified +#cat: pixel value. NOTE, the pixel coordinates are assumed to +#cat: be within the image boundaries. + + Input: + fill_pix - pixel value to fill with (should be on range [0..255] + frx - x-pixel coord where fill should begin + tox - x-pixel coord where fill should end (inclusive) + y - y-pixel coord of current row being filled + bdata - 8-bit image data + iw - width (in pixels) of image + ih - height (in pixels) of image + Output: + bdata - 8-bit image data with partial row filled. +**************************************************************************/ +void fill_partial_row(const int fill_pix, const int frx, const int tox, + const int y, unsigned char *bdata, const int iw, const int ih) +{ + int x; + unsigned char *bptr; + + /* Set pixel pointer to starting x-coord on current row. */ + bptr = bdata+(y*iw)+frx; + + /* Foreach pixel between starting and ending x-coord on row */ + /* (including the end points) ... */ + for(x = frx; x <= tox; x++){ + /* Set current pixel with fill pixel value. */ + *bptr = fill_pix; + /* Bump to next pixel in the row. */ + bptr++; + } +} + +/************************************************************************* +************************************************************************** +#cat: flood_loop - Fills a given contour (determined to form a complete loop) +#cat: with a specified pixel value using a recursive flood-fill +#cat: technique. +#cat: NOTE, this fill approach will NOT always work with the +#cat: contours generated in this application because they +#cat: are NOT guaranteed to be ENTIRELY surrounded by 8-connected +#cat: pixels not equal to the fill pixel value. This is unfortunate +#cat: because the flood-fill is a simple algorithm that will handle +#cat: complex/concaved shapes. + + Input: + contour_x - x-coord list for loop's contour points + contour_y - y-coord list for loop's contour points + ncontour - number of points in contour + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + Output: + bdata - binary image data with loop filled +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: flood_fill4 - Recursively floods a region of an 8-bit pixel image with a +#cat: specified pixel value given a starting (seed) point. The +#cat: recursion is based neighbors being 4-connected. + + Input: + fill_pix - 8-bit pixel value to be filled with (on range [0..255] + x - starting x-pixel coord + y - starting y-pixel coord + bdata - 8-bit pixel image data + iw - width (in pixels) of image + ih - height (in pixels) of image + Output: + bdata - 8-bit pixel image data with region filled +**************************************************************************/ +void flood_fill4(const int fill_pix, const int x, const int y, + unsigned char *bdata, const int iw, const int ih) +{ + unsigned char *pptr; + int y_north, y_south, x_east, x_west; + + /* Get address of current pixel. */ + pptr = bdata + (y*iw) + x; + /* If pixel needs to be filled ... */ + if(*pptr != fill_pix){ + /* Fill the current pixel. */ + *pptr = fill_pix; + + /* Recursively invoke flood on the pixel's 4 neighbors. */ + /* Test to make sure neighbors are within image boudaries */ + /* before invoking each flood. */ + y_north = y-1; + y_south = y+1; + x_west = x-1; + x_east = x+1; + + /* Invoke North */ + if(y_north >= 0) + flood_fill4(fill_pix, x, y_north, bdata, iw, ih); + + /* Invoke East */ + if(x_east < iw) + flood_fill4(fill_pix, x_east, y, bdata, iw, ih); + + /* Invoke South */ + if(y_south < ih) + flood_fill4(fill_pix, x, y_south, bdata, iw, ih); + + /* Invoke West */ + if(x_west >= 0) + flood_fill4(fill_pix, x_west, y, bdata, iw, ih); + } + + /* Otherwise, there is nothing to be done. */ +} diff --git a/libfprint/nbis/mindtct/maps.c b/libfprint/nbis/mindtct/maps.c index 43929a4b..ac3b82da 100644 --- a/libfprint/nbis/mindtct/maps.c +++ b/libfprint/nbis/mindtct/maps.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -46,6 +67,7 @@ identified are necessarily the best available for the purpose. pixelize_map() smooth_direction_map() gen_high_curve_map() + gen_imap() gen_initial_imap() primary_dir_test() secondary_fork_test() @@ -58,6 +80,7 @@ identified are necessarily the best available for the purpose. average_8nbr_dir() num_valid_8nbrs() smooth_imap() + gen_nmap() vorticity() accum_nbr_vorticity() curvature() @@ -65,8 +88,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include -#include #include #include #include @@ -138,6 +159,9 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, } if((ret = morph_TF_map(low_flow_map, mw, mh, lfsparms))){ + free(direction_map); + free(low_contrast_map); + free(low_flow_map); return(ret); } @@ -152,6 +176,9 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, /* 5. Interpolate INVALID direction blocks with their valid neighbors. */ if((ret = interpolate_direction_map(direction_map, low_contrast_map, mw, mh, lfsparms))){ + free(direction_map); + free(low_contrast_map); + free(low_flow_map); return(ret); } @@ -171,6 +198,9 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, /* 9. Generate High Curvature Map from interpolated Direction Map. */ if((ret = gen_high_curve_map(&high_curve_map, direction_map, mw, mh, lfsparms))){ + free(direction_map); + free(low_contrast_map); + free(low_flow_map); return(ret); } @@ -242,6 +272,7 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, print2log("INITIAL MAP\n"); /* Compute total number of blocks in map */ + ASSERT_INT_MUL(mw, mh); bsize = mw * mh; /* Allocate Direction Map memory */ @@ -307,10 +338,6 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, xmaxlimit = pw - dftgrids->pad - lfsparms->windowsize - 1; ymaxlimit = ph - dftgrids->pad - lfsparms->windowsize - 1; - /* max limits should not be negative */ - xmaxlimit = MAX(xmaxlimit, 0); - ymaxlimit = MAX(ymaxlimit, 0); - /* Foreach block in image ... */ for(bi = 0; bi < bsize; bi++){ /* Adjust block offset from pointing to block origin to pointing */ @@ -393,9 +420,9 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, { int _w; fprintf(logfp, " Power\n"); for(_w = 0; _w < nstats; _w++){ - /* Add 1 to wis[w] to create index to original dft_coefs[] */ + /* Add 1 to wis[w] to create index to original g_dft_coefs[] */ fprintf(logfp, " wis[%d] %d %12.3f %2d %9.3f %12.3f\n", - _w, wis[_w]+1, + _w, wis[_w]+1, powmaxs[wis[_w]], powmax_dirs[wis[_w]], pownorms[wis[_w]], powers[0][powmax_dirs[wis[_w]]]); } @@ -476,6 +503,8 @@ int interpolate_direction_map(int *direction_map, int *low_contrast_map, print2log("INTERPOLATE DIRECTION MAP\n"); /* Allocate output (interpolated) Direction Map. */ + ASSERT_SIZE_MUL(mw, mh); + ASSERT_SIZE_MUL(mw * mh, sizeof(int)); omap = (int *)malloc(mw*mh*sizeof(int)); if(omap == (int *)NULL){ fprintf(stderr, @@ -647,7 +676,8 @@ int morph_TF_map(int *tfmap, const int mw, const int mh, unsigned char *cimage, *mimage, *cptr; int *mptr; int i; - + + ASSERT_INT_MUL(mw, mh); /* Convert TRUE/FALSE map into a binary byte image. */ cimage = (unsigned char *)malloc(mw*mh); @@ -658,6 +688,7 @@ int morph_TF_map(int *tfmap, const int mw, const int mh, mimage = (unsigned char *)malloc(mw*mh); if(mimage == (unsigned char *)NULL){ + free(cimage); fprintf(stderr, "ERROR : morph_TF_map : malloc : mimage\n"); return(-661); } @@ -712,6 +743,9 @@ int pixelize_map(int **omap, const int iw, const int ih, int *blkoffs, bw, bh, bi; int *spptr, *pptr; + ASSERT_SIZE_MUL(iw, ih); + ASSERT_SIZE_MUL(iw * ih, sizeof(int)); + pmap = (int *)malloc(iw*ih*sizeof(int)); if(pmap == (int *)NULL){ fprintf(stderr, "ERROR : pixelize_map : malloc : pmap\n"); @@ -719,11 +753,13 @@ int pixelize_map(int **omap, const int iw, const int ih, } if((ret = block_offsets(&blkoffs, &bw, &bh, iw, ih, 0, blocksize))){ + free(pmap); return(ret); } if((bw != mw) || (bh != mh)){ free(blkoffs); + free(pmap); fprintf(stderr, "ERROR : pixelize_map : block dimensions do not match\n"); return(-591); @@ -869,9 +905,11 @@ int gen_high_curve_map(int **ohcmap, int *direction_map, int bx, by; int nvalid, cmeasure, vmeasure; + ASSERT_INT_MUL(mw, mh); mapsize = mw*mh; /* Allocate High Curvature Map. */ + ASSERT_SIZE_MUL(mapsize, sizeof(int)); high_curve_map = (int *)malloc(mapsize * sizeof(int)); if(high_curve_map == (int *)NULL){ fprintf(stderr, @@ -925,13 +963,37 @@ int gen_high_curve_map(int **ohcmap, int *direction_map, } /* bx */ } /* by */ - /* Assign High Curvature Map to output pointer. */ + /* Assign High Curvature Map to output pointer. */ *ohcmap = high_curve_map; /* Return normally. */ return(0); } +/************************************************************************* +************************************************************************** +#cat: gen_imap - Computes an IMAP, which is a 2D vector of integer directions, +#cat: where each direction represents the dominant ridge flow in +#cat: a block of the input grayscale image. This routine will +#cat: generate an IMAP for arbitrarily sized, non-square, images. + + Input: + pdata - padded input image data (8 bits [0..256) grayscale) + pw - padded width (in pixels) of the input image + ph - padded height (in pixels) of the input image + dir2rad - lookup table for converting integer directions + dftwaves - structure containing the DFT wave forms + dftgrids - structure containing the rotated pixel grid offsets + lfsparms - parameters and thresholds for controlling LFS + Output: + optr - points to the created IMAP + ow - width (in blocks) of the IMAP + oh - height (in blocks) of the IMAP + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: gen_initial_imap - Creates an initial IMAP from the given input image. @@ -959,126 +1021,6 @@ int gen_high_curve_map(int **ohcmap, int *direction_map, Zero - successful completion Negative - system error **************************************************************************/ -int gen_initial_imap(int **optr, int *blkoffs, const int mw, const int mh, - unsigned char *pdata, const int pw, const int ph, - const DFTWAVES *dftwaves, const ROTGRIDS *dftgrids, - const LFSPARMS *lfsparms) -{ - int *imap; - int bi, bsize, blkdir; - int *wis, *powmax_dirs; - double **powers, *powmaxs, *pownorms; - int nstats; - int ret; /* return code */ - - print2log("INITIAL MAP\n"); - - /* Compute total number of blocks in IMAP */ - bsize = mw * mh; - - /* Allocate IMAP memory */ - imap = (int *)malloc(bsize * sizeof(int)); - if(imap == (int *)NULL){ - fprintf(stderr, "ERROR : gen_initial_imap : malloc : imap\n"); - return(-70); - } - - /* Allocate DFT directional power vectors */ - if((ret = alloc_dir_powers(&powers, dftwaves->nwaves, dftgrids->ngrids))){ - /* Free memory allocated to this point. */ - free(imap); - return(ret); - } - - /* Allocate DFT power statistic arrays */ - /* Compute length of statistics arrays. Statistics not needed */ - /* for the first DFT wave, so the length is number of waves - 1. */ - nstats = dftwaves->nwaves - 1; - if((ret = alloc_power_stats(&wis, &powmaxs, &powmax_dirs, - &pownorms, nstats))){ - /* Free memory allocated to this point. */ - free(imap); - free_dir_powers(powers, dftwaves->nwaves); - return(ret); - } - - /* Initialize the imap to -1 */ - memset(imap, INVALID_DIR, bsize * sizeof(int)); - - /* Foreach block in imap ... */ - for(bi = 0; bi < bsize; bi++){ - - print2log(" BLOCK %2d (%2d, %2d)\n", bi, bi%mw, bi/mw); - - /* Compute DFT powers */ - if((ret = dft_dir_powers(powers, pdata, blkoffs[bi], pw, ph, - dftwaves, dftgrids))){ - /* Free memory allocated to this point. */ - free(imap); - free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); - return(ret); - } - - /* Compute DFT power statistics, skipping first applied DFT */ - /* wave. This is dependent on how the primary and secondary */ - /* direction tests work below. */ - if((ret = dft_power_stats(wis, powmaxs, powmax_dirs, pownorms, powers, - 1, dftwaves->nwaves, dftgrids->ngrids))){ - /* Free memory allocated to this point. */ - free(imap); - free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); - return(ret); - } - -#ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ - { int _w; - fprintf(logfp, " Power\n"); - for(_w = 0; _w < nstats; _w++){ - /* Add 1 to wis[w] to create index to original dft_coefs[] */ - fprintf(logfp, " wis[%d] %d %12.3f %2d %9.3f %12.3f\n", - _w, wis[_w]+1, - powmaxs[wis[_w]], powmax_dirs[wis[_w]], pownorms[wis[_w]], - powers[0][powmax_dirs[wis[_w]]]); - } - } -#endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - - /* Conduct primary direction test */ - blkdir = primary_dir_test(powers, wis, powmaxs, powmax_dirs, - pownorms, nstats, lfsparms); - - if(blkdir != INVALID_DIR) - imap[bi] = blkdir; - else{ - /* Conduct secondary (fork) direction test */ - blkdir = secondary_fork_test(powers, wis, powmaxs, powmax_dirs, - pownorms, nstats, lfsparms); - if(blkdir != INVALID_DIR) - imap[bi] = blkdir; - } - - /* Otherwise current block direction in IMAP remains INVALID */ - - } /* bi */ - - /* Deallocate working memory */ - free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); - - *optr = imap; - return(0); -} /************************************************************************* ************************************************************************** @@ -1093,7 +1035,7 @@ int gen_initial_imap(int **optr, int *blkoffs, const int mw, const int mh, powmaxs - maximum power for each of the highest N-1 frequencies powmax_dirs - directions associated with each of the N-1 maximum powers pownorms - normalized power for each of the highest N-1 frequencies - nstats - N-1 wave frequencies (where N is the length of dft_coefs) + nstats - N-1 wave frequencies (where N is the length of g_dft_coefs) lfsparms - parameters and thresholds for controlling LFS Return Code: Zero or Positive - The selected IMAP integer direction @@ -1120,7 +1062,7 @@ int primary_dir_test(double **powers, const int *wis, (powers[0][powmax_dirs[wis[w]]] <= lfsparms->powmax_max)){ #ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ - /* Add 1 to wis[w] to create index to original dft_coefs[] */ + /* Add 1 to wis[w] to create index to original g_dft_coefs[] */ fprintf(logfp, " Selected Wave = %d\n", wis[w]+1); fprintf(logfp, @@ -1177,7 +1119,7 @@ int primary_dir_test(double **powers, const int *wis, powmaxs - maximum power for each of the highest N-1 frequencies powmax_dirs - directions associated with each of the N-1 maximum powers pownorms - normalized power for each of the highest N-1 frequencies - nstats - N-1 wave frequencies (where N is the length of dft_coefs) + nstats - N-1 wave frequencies (where N is the length of g_dft_coefs) lfsparms - parameters and thresholds for controlling LFS Return Code: Zero or Positive - The selected IMAP integer direction @@ -2022,76 +1964,29 @@ int num_valid_8nbrs(int *imap, const int mx, const int my, Output: imap - vector of smoothed input values **************************************************************************/ -void smooth_imap(int *imap, const int mw, const int mh, - const DIR2RAD *dir2rad, const LFSPARMS *lfsparms) -{ - int mx, my; - int *iptr; - int avrdir, nvalid; - double dir_strength; - print2log("SMOOTH MAP\n"); +/************************************************************************* +************************************************************************** +#cat: gen_nmap - Computes an NMAP from its associated 2D vector of integer +#cat: directions (IMAP). Each value in the NMAP either represents +#cat: a direction of dominant ridge flow in a block of the input +#cat: grayscale image, or it contains a codes describing why such +#cat: a direction was not procuded. +#cat: For example, blocks near areas of high-curvature (such as +#cat: with cores and deltas) will not produce reliable IMAP +#cat: directions. - iptr = imap; - for(my = 0; my < mh; my++){ - for(mx = 0; mx < mw; mx++){ - /* Compute average direction from neighbors, returning the */ - /* number of valid neighbors used in the computation, and */ - /* the "strength" of the average direction. */ - average_8nbr_dir(&avrdir, &dir_strength, &nvalid, - imap, mx, my, mw, mh, dir2rad); - - /* If average direction strength is strong enough */ - /* (Ex. thresh==0.2)... */ - if(dir_strength >= lfsparms->dir_strength_min){ - /* If IMAP direction is valid ... */ - if(*iptr != INVALID_DIR){ - /* Conduct valid neighbor test (Ex. thresh==3)... */ - if(nvalid >= lfsparms->rmv_valid_nbr_min){ - -#ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ - fprintf(logfp, " BLOCK %2d (%2d, %2d)\n", - mx+(my*mw), mx, my); - fprintf(logfp, " Average NBR : %2d %6.3f %d\n", - avrdir, dir_strength, nvalid); - fprintf(logfp, " 1. Valid NBR (%d >= %d)\n", - nvalid, lfsparms->rmv_valid_nbr_min); - fprintf(logfp, " Valid Direction = %d\n", *iptr); - fprintf(logfp, " Smoothed Direction = %d\n", avrdir); -#endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - - /* Reassign valid IMAP direction with average direction. */ - *iptr = avrdir; - } - } - /* Otherwise IMAP direction is invalid ... */ - else{ - /* Even if IMAP value is invalid, if number of valid */ - /* neighbors is big enough (Ex. thresh==7)... */ - if(nvalid >= lfsparms->smth_valid_nbr_min){ - -#ifdef LOG_REPORT /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ - fprintf(logfp, " BLOCK %2d (%2d, %2d)\n", - mx+(my*mw), mx, my); - fprintf(logfp, " Average NBR : %2d %6.3f %d\n", - avrdir, dir_strength, nvalid); - fprintf(logfp, " 2. Invalid NBR (%d >= %d)\n", - nvalid, lfsparms->smth_valid_nbr_min); - fprintf(logfp, " Invalid Direction = %d\n", *iptr); - fprintf(logfp, " Smoothed Direction = %d\n", avrdir); -#endif /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ - - /* Assign invalid IMAP direction with average direction. */ - *iptr = avrdir; - } - } - } - - /* Bump to next IMAP direction. */ - iptr++; - } - } -} + Input: + imap - associated input vector of IMAP directions + mw - the width (in blocks) of the IMAP + mh - the height (in blocks) of the IMAP + lfsparms - parameters and thresholds for controlling LFS + Output: + optr - points to the created NMAP + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ /************************************************************************* ************************************************************************** diff --git a/libfprint/nbis/mindtct/matchpat.c b/libfprint/nbis/mindtct/matchpat.c index 04bb27b8..290d00c5 100644 --- a/libfprint/nbis/mindtct/matchpat.c +++ b/libfprint/nbis/mindtct/matchpat.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -46,14 +67,14 @@ identified are necessarily the best available for the purpose. /************************************************************************* ************************************************************************** -#cat: match_1st_pair - Determines which of the feature_patterns[] have their +#cat: match_1st_pair - Determines which of the g_feature_patterns[] have their #cat: first pixel pair match the specified pixel pair. Input: p1 - first pixel value of pair p2 - second pixel value of pair Output: - possible - list of matching feature_patterns[] indices + possible - list of matching g_feature_patterns[] indices nposs - number of matches Return Code: nposs - number of matches @@ -84,16 +105,16 @@ int match_1st_pair(unsigned char p1, unsigned char p2, /************************************************************************* ************************************************************************** -#cat: match_2nd_pair - Determines which of the passed feature_patterns[] have +#cat: match_2nd_pair - Determines which of the passed g_feature_patterns[] have #cat: their second pixel pair match the specified pixel pair. Input: p1 - first pixel value of pair p2 - second pixel value of pair - possible - list of potentially-matching feature_patterns[] indices + possible - list of potentially-matching g_feature_patterns[] indices nposs - number of potential matches Output: - possible - list of matching feature_patterns[] indices + possible - list of matching g_feature_patterns[] indices nposs - number of matches Return Code: nposs - number of matches @@ -132,16 +153,16 @@ int match_2nd_pair(unsigned char p1, unsigned char p2, /************************************************************************* ************************************************************************** -#cat: match_3rd_pair - Determines which of the passed feature_patterns[] have +#cat: match_3rd_pair - Determines which of the passed g_feature_patterns[] have #cat: their third pixel pair match the specified pixel pair. Input: p1 - first pixel value of pair p2 - second pixel value of pair - possible - list of potentially-matching feature_patterns[] indices + possible - list of potentially-matching g_feature_patterns[] indices nposs - number of potential matches Output: - possible - list of matching feature_patterns[] indices + possible - list of matching g_feature_patterns[] indices nposs - number of matches Return Code: nposs - number of matches diff --git a/libfprint/nbis/mindtct/minutia.c b/libfprint/nbis/mindtct/minutia.c index 497336b1..ca0d551c 100644 --- a/libfprint/nbis/mindtct/minutia.c +++ b/libfprint/nbis/mindtct/minutia.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -37,6 +58,7 @@ identified are necessarily the best available for the purpose. ROUTINES: alloc_minutiae() realloc_minutiae() + detect_minutiae() detect_minutiae_V2() update_minutiae() update_minutiae_V2() @@ -73,30 +95,26 @@ identified are necessarily the best available for the purpose. adjust_high_curvature_minutia() adjust_high_curvature_minutia_V2() get_low_curvature_direction() - lfs2nist_minutia_XYT() ***********************************************************************/ #include -#include #include - - /************************************************************************* ************************************************************************** #cat: alloc_minutiae - Allocates and initializes a minutia list based on the #cat: specified maximum number of minutiae to be detected. Input: - max_minutiae - number of minutia to be allocated in list + DEFAULT_BOZORTH_MINUTIAE - number of minutia to be allocated in list Output: ominutiae - points to the allocated minutiae list Return Code: Zero - successful completion Negative - system error **************************************************************************/ -int alloc_minutiae(MINUTIAE **ominutiae, const int max_minutiae) +int alloc_minutiae(MINUTIAE **ominutiae, const int DEFAULT_BOZORTH_MINUTIAE) { MINUTIAE *minutiae; @@ -105,13 +123,13 @@ int alloc_minutiae(MINUTIAE **ominutiae, const int max_minutiae) fprintf(stderr, "ERROR : alloc_minutiae : malloc : minutiae\n"); exit(-430); } - minutiae->list = (MINUTIA **)malloc(max_minutiae * sizeof(MINUTIA *)); + minutiae->list = (MINUTIA **)malloc(DEFAULT_BOZORTH_MINUTIAE * sizeof(MINUTIA *)); if(minutiae->list == (MINUTIA **)NULL){ fprintf(stderr, "ERROR : alloc_minutiae : malloc : minutiae->list\n"); exit(-431); } - minutiae->alloc = max_minutiae; + minutiae->alloc = DEFAULT_BOZORTH_MINUTIAE; minutiae->num = 0; *ominutiae = minutiae; @@ -126,7 +144,7 @@ int alloc_minutiae(MINUTIAE **ominutiae, const int max_minutiae) Input: minutiae - previously allocated list of minutiae points - max_minutiae - number of minutia to be allocated in list + DEFAULT_BOZORTH_MINUTIAE - number of minutia to be allocated in list Output: minutiae - extended list of minutiae points Return Code: @@ -146,6 +164,29 @@ int realloc_minutiae(MINUTIAE *minutiae, const int incr_minutiae) return(0); } +/************************************************************************* +************************************************************************** +#cat: detect_minutiae - Takes a binary image and its associated IMAP and +#cat: NMAP matrices and scans each image block for potential +#cat: minutia points. + + Input: + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + imap - matrix of ridge flow directions + nmap - IMAP augmented with blocks of HIGH-CURVATURE and + blocks which have no neighboring valid directions. + mw - width (in blocks) of IMAP and NMAP matrices. + mh - height (in blocks) of IMAP and NMAP matrices. + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - points to a list of detected minutia structures + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: detect_minutiae_V2 - Takes a binary image and its associated @@ -666,40 +707,6 @@ int rm_dup_minutiae(MINUTIAE *minutiae) Output: fpout - open file pointer **************************************************************************/ -void dump_minutiae(FILE *fpout, const MINUTIAE *minutiae) -{ - int i, j; - - fprintf(fpout, "\n%d Minutiae Detected\n\n", minutiae->num); - - for(i = 0; i < minutiae->num; i++){ - /* Precision of reliablity added one decimal position */ - /* on 09-13-04 */ - fprintf(fpout, "%4d : %4d, %4d : %2d : %6.3f :", i, - minutiae->list[i]->x, minutiae->list[i]->y, - minutiae->list[i]->direction, minutiae->list[i]->reliability); - if(minutiae->list[i]->type == RIDGE_ENDING) - fprintf(fpout, "RIG : "); - else - fprintf(fpout, "BIF : "); - - if(minutiae->list[i]->appearing) - fprintf(fpout, "APP : "); - else - fprintf(fpout, "DIS : "); - - fprintf(fpout, "%2d ", minutiae->list[i]->feature_id); - - for(j = 0; j < minutiae->list[i]->num_nbrs; j++){ - fprintf(fpout, ": %4d,%4d; %2d ", - minutiae->list[minutiae->list[i]->nbrs[j]]->x, - minutiae->list[minutiae->list[i]->nbrs[j]]->y, - minutiae->list[i]->ridge_counts[j]); - } - - fprintf(fpout, "\n"); - } -} /************************************************************************* ************************************************************************** @@ -712,20 +719,6 @@ void dump_minutiae(FILE *fpout, const MINUTIAE *minutiae) Output: fpout - open file pointer **************************************************************************/ -void dump_minutiae_pts(FILE *fpout, const MINUTIAE *minutiae) -{ - int i; - - /* First line in the output file contians the number of minutia */ - /* points to be written to the file. */ - fprintf(fpout, "%d\n", minutiae->num); - - /* Foreach minutia in list... */ - for(i = 0; i < minutiae->num; i++){ - /* Write the minutia's coordinate point to the file pointer. */ - fprintf(fpout, "%4d %4d\n", minutiae->list[i]->x, minutiae->list[i]->y); - } -} /************************************************************************* @@ -741,32 +734,6 @@ void dump_minutiae_pts(FILE *fpout, const MINUTIAE *minutiae) Output: fpout - open file pointer **************************************************************************/ -void dump_reliable_minutiae_pts(FILE *fpout, const MINUTIAE *minutiae, - const double reliability) -{ - int i, count; - - /* First count the number of qualifying minutiae so that the */ - /* MFS header may be written. */ - count = 0; - /* Foreach minutia in list... */ - for(i = 0; i < minutiae->num; i++){ - if(minutiae->list[i]->reliability == reliability) - count++; - } - - /* First line in the output file contians the number of minutia */ - /* points to be written to the file. */ - fprintf(fpout, "%d\n", count); - - /* Foreach minutia in list... */ - for(i = 0; i < minutiae->num; i++){ - if(minutiae->list[i]->reliability == reliability) - /* Write the minutia's coordinate point to the file pointer. */ - fprintf(fpout, "%4d %4d\n", - minutiae->list[i]->x, minutiae->list[i]->y); - } -} /************************************************************************* ************************************************************************** @@ -782,7 +749,7 @@ void dump_reliable_minutiae_pts(FILE *fpout, const MINUTIAE *minutiae, reliability - floating point measure of minutia's reliability type - type of the minutia (ridge-ending or bifurcation) appearing - designates the minutia as appearing or disappearing - feature_id - index of minutia's matching feature_patterns[] + feature_id - index of minutia's matching g_feature_patterns[] Output: ominutia - ponter to an allocated and initialized minutia structure Return Code: @@ -927,119 +894,6 @@ int remove_minutia(const int index, MINUTIAE *minutiae) Zero - successful completion Negative - system error **************************************************************************/ -int join_minutia(const MINUTIA *minutia1, const MINUTIA *minutia2, - unsigned char *bdata, const int iw, const int ih, - const int with_boundary, const int line_radius) -{ - int dx_gte_dy, delta_x, delta_y; - int *x_list, *y_list, num; - int minutia_pix, boundary_pix; - int i, j, ret; - int x1, y1, x2, y2; - - /* Compute X and Y deltas between minutia points. */ - delta_x = abs(minutia1->x - minutia2->x); - delta_y = abs(minutia1->y - minutia2->y); - - /* Set flag based on |DX| >= |DY|. */ - /* If flag is true then add additional pixel width to the join line */ - /* by adding pixels neighboring top and bottom. */ - /* If flag is false then add additional pixel width to the join line */ - /* by adding pixels neighboring left and right. */ - if(delta_x >= delta_y) - dx_gte_dy = 1; - else - dx_gte_dy = 0; - - /* Compute points along line segment between the two minutia points. */ - if((ret = line_points(&x_list, &y_list, &num, - minutia1->x, minutia1->y, minutia2->x, minutia2->y))) - /* If error with line routine, return error code. */ - return(ret); - - /* Determine pixel color of minutia and boundary. */ - if(minutia1->type == RIDGE_ENDING){ - /* To connect 2 ridge-endings, draw black. */ - minutia_pix = 1; - boundary_pix = 0; - } - else{ - /* To connect 2 bifurcations, draw white. */ - minutia_pix = 0; - boundary_pix = 1; - } - - /* Foreach point on line connecting the minutiae points ... */ - for(i = 1; i < num-1; i++){ - /* Draw minutia pixel at current point on line. */ - *(bdata+(y_list[i]*iw)+x_list[i]) = minutia_pix; - - /* Initialize starting corrdinates for adding width to the */ - /* join line to the current point on the line. */ - x1 = x_list[i]; - y1 = y_list[i]; - x2 = x1; - y2 = y1; - /* Foreach pixel of added radial width ... */ - for(j = 0; j < line_radius; j++){ - - /* If |DX|>=|DY|, we want to add width to line by writing */ - /* to pixels neighboring above and below. */ - /* x1 -= (0=(1-1)); y1 -= 1 ==> ABOVE */ - /* x2 += (0=(1-1)); y2 += 1 ==> BELOW */ - /* If |DX|<|DY|, we want to add width to line by writing */ - /* to pixels neighboring left and right. */ - /* x1 -= (1=(1-0)); y1 -= 0 ==> LEFT */ - /* x2 += (1=(1-0)); y2 += 0 ==> RIGHT */ - - /* Advance 1st point along width dimension. */ - x1 -= (1 - dx_gte_dy); - y1 -= dx_gte_dy; - /* If pixel 1st point is within image boundaries ... */ - if((x1 >= 0) && (x1 < iw) && - (y1 >= 0) && (y1 < ih)) - /* Write the pixel ABOVE or LEFT. */ - *(bdata+(y1*iw)+x1) = minutia_pix; - - /* Advance 2nd point along width dimension. */ - x2 += (1 - dx_gte_dy); - y2 += dx_gte_dy; - /* If pixel 2nd point is within image boundaries ... */ - if((x2 >= 0) && (x2 < iw) && - /* Write the pixel BELOW or RIGHT. */ - (y2 >= 0) && (y2 < ih)) - *(bdata+(y2*iw)+x2) = minutia_pix; - } - - /* If boundary flag is set ... draw the boundary pixels.*/ - if(with_boundary){ - /* Advance 1st point along width dimension. */ - x1 -= (1 - dx_gte_dy); - y1 -= dx_gte_dy; - /* If pixel 1st point is within image boundaries ... */ - if((x1 >= 0) && (x1 < iw) && - (y1 >= 0) && (y1 < ih)) - /* Write the pixel ABOVE or LEFT of opposite color. */ - *(bdata+(y1*iw)+x1) = boundary_pix; - - /* Advance 2nd point along width dimension. */ - x2 += (1 - dx_gte_dy); - y2 += dx_gte_dy; - /* If pixel 2nd point is within image boundaries ... */ - if((x2 >= 0) && (x2 < iw) && - (y2 >= 0) && (y2 < ih)) - /* Write the pixel BELOW or RIGHT of opposite color. */ - *(bdata+(y2*iw)+x2) = boundary_pix; - } - } - - /* Deallocate points along connecting line. */ - free(x_list); - free(y_list); - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1178,61 +1032,6 @@ int choose_scan_direction(const int imapval, const int ndirs) Zero - successful completion Negative - system error **************************************************************************/ -int scan4minutiae(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int *imap, const int *nmap, - const int blk_x, const int blk_y, const int mw, const int mh, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, const int scan_dir, - const LFSPARMS *lfsparms) -{ - int blk_i, ret; - - /* Compute block index from block coordinates. */ - blk_i = (blk_y*mw) + blk_x; - - /* Conduct primary scan for minutiae horizontally. */ - if(scan_dir == SCAN_HORIZONTAL){ - - if((ret = scan4minutiae_horizontally(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - scan_x, scan_y, scan_w, scan_h, lfsparms))){ - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } - - /* Rescan block vertically. */ - if((ret = rescan4minutiae_vertically(minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))){ - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } - } - - /* Otherwise, conduct primary scan for minutiae vertically. */ - else{ - if((ret = scan4minutiae_vertically(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - scan_x, scan_y, scan_w, scan_h, lfsparms))){ - /* Return resulting code. */ - return(ret); - } - - /* Rescan block horizontally. */ - if((ret = rescan4minutiae_horizontally(minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))){ - /* Return resulting code. */ - return(ret); - } - } - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1262,116 +1061,6 @@ int scan4minutiae(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int scan4minutiae_horizontally(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int imapval, const int nmapval, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int sx, sy, ex, ey, cx, cy, x2; - unsigned char *p1ptr, *p2ptr; - int possible[NFEATURES], nposs; - int ret; - - /* NOTE!!! Minutia that "straddle" region boundaries may be missed! */ - - /* If possible, overlap left and right of current scan region */ - /* by 2 pixel columns to help catch some minutia that straddle the */ - /* the scan region boundaries. */ - sx = max(0, scan_x-2); - ex = min(iw, scan_x+scan_w+2); - - /* If possible, overlap the scan region below by 1 pixel row. */ - sy = scan_y; - ey = min(ih, scan_y+scan_h+1); - - /* For now, we will not adjust for IMAP edge, as the binary image */ - /* was properly padded at its edges so as not to cause anomallies. */ - - /* Start at first row in region. */ - cy = sy; - /* While second scan row not outside the bottom of the scan region... */ - while(cy+1 < ey){ - /* Start at beginning of new scan row in region. */ - cx = sx; - /* While not at end of region's current scan row. */ - while(cx < ex){ - /* Get pixel pair from current x position in current and next */ - /* scan rows. */ - p1ptr = bdata+(cy*iw)+cx; - p2ptr = bdata+((cy+1)*iw)+cx; - /* If scan pixel pair matches first pixel pair of */ - /* 1 or more features... */ - if(match_1st_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Bump forward to next scan pixel pair. */ - cx++; - p1ptr++; - p2ptr++; - /* If not at end of region's current scan row... */ - if(cx < ex){ - /* If scan pixel pair matches second pixel pair of */ - /* 1 or more features... */ - if(match_2nd_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Store current x location. */ - x2 = cx; - /* Skip repeated pixel pairs. */ - skip_repeated_horizontal_pair(&cx, ex, &p1ptr, &p2ptr, - iw, ih); - /* If not at end of region's current scan row... */ - if(cx < ex){ - /* If scan pixel pair matches third pixel pair of */ - /* a single feature... */ - if(match_3rd_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Process detected minutia point. */ - if((ret = process_horizontal_scan_minutia(minutiae, - cx, cy, x2, possible[0], - bdata, iw, ih, - imapval, nmapval, lfsparms))){ - /* Return code may be: */ - /* 1. ret< 0 (implying system error) */ - /* 2. ret==IGNORE (ignore current feature) */ - if(ret < 0) - return(ret); - /* Otherwise, IGNORE and continue. */ - } - } - - /* Set up to resume scan. */ - /* Test to see if 3rd pair can slide into 2nd pair. */ - /* The values of the 2nd pair MUST be different. */ - /* If 3rd pair values are different ... */ - if(*p1ptr != *p2ptr){ - /* Set next first pair to last of repeated */ - /* 2nd pairs, ie. back up one pair. */ - cx--; - } - - /* Otherwise, 3rd pair can't be a 2nd pair, so */ - /* keep pointing to 3rd pair so that it is used */ - /* in the next first pair test. */ - - } /* Else, at end of current scan row. */ - } - - /* Otherwise, 2nd pair failed, so keep pointing to it */ - /* so that it is used in the next first pair test. */ - - } /* Else, at end of current scan row. */ - } - /* Otherwise, 1st pair failed... */ - else{ - /* Bump forward to next pixel pair. */ - cx++; - } - } /* While not at end of current scan row. */ - /* Bump forward to next scan row. */ - cy++; - } /* While not out of scan rows. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1497,7 +1186,7 @@ int scan4minutiae_horizontally_V2(MINUTIAE *minutiae, /************************************************************************* ************************************************************************** -#cat: scan4minutiae_vertically - Scans a specified region of binary image data +#cat: scan4minutiae_vertically - Scans a specified region of binary image data #cat: vertically, detecting potential minutiae points. #cat: Minutia detected via the vetical scan process are #cat: by nature horizontally oriented (orthogonal to the scan). @@ -1523,116 +1212,6 @@ int scan4minutiae_horizontally_V2(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int scan4minutiae_vertically(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int imapval, const int nmapval, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int sx, sy, ex, ey, cx, cy, y2; - unsigned char *p1ptr, *p2ptr; - int possible[NFEATURES], nposs; - int ret; - - /* NOTE!!! Minutia that "straddle" region boundaries may be missed! */ - - /* If possible, overlap scan region to the right by 1 pixel column. */ - sx = scan_x; - ex = min(iw, scan_x+scan_w+1); - - /* If possible, overlap top and bottom of current scan region */ - /* by 2 pixel rows to help catch some minutia that straddle the */ - /* the scan region boundaries. */ - sy = max(0, scan_y-2); - ey = min(ih, scan_y+scan_h+2); - - /* For now, we will not adjust for IMAP edge, as the binary image */ - /* was properly padded at its edges so as not to cause anomalies. */ - - /* Start at first column in region. */ - cx = sx; - /* While second scan column not outside the right of the region ... */ - while(cx+1 < ex){ - /* Start at beginning of new scan column in region. */ - cy = sy; - /* While not at end of region's current scan column. */ - while(cy < ey){ - /* Get pixel pair from current y position in current and next */ - /* scan columns. */ - p1ptr = bdata+(cy*iw)+cx; - p2ptr = p1ptr+1; - /* If scan pixel pair matches first pixel pair of */ - /* 1 or more features... */ - if(match_1st_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Bump forward to next scan pixel pair. */ - cy++; - p1ptr+=iw; - p2ptr+=iw; - /* If not at end of region's current scan column... */ - if(cy < ey){ - /* If scan pixel pair matches second pixel pair of */ - /* 1 or more features... */ - if(match_2nd_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Store current y location. */ - y2 = cy; - /* Skip repeated pixel pairs. */ - skip_repeated_vertical_pair(&cy, ey, &p1ptr, &p2ptr, - iw, ih); - /* If not at end of region's current scan column... */ - if(cy < ey){ - /* If scan pixel pair matches third pixel pair of */ - /* a single feature... */ - if(match_3rd_pair(*p1ptr, *p2ptr, possible, &nposs)){ - /* Process detected minutia point. */ - if((ret = process_vertical_scan_minutia(minutiae, - cx, cy, y2, possible[0], - bdata, iw, ih, - imapval, nmapval, lfsparms))){ - /* Return code may be: */ - /* 1. ret< 0 (implying system error) */ - /* 2. ret==IGNORE (ignore current feature) */ - if(ret < 0) - return(ret); - /* Otherwise, IGNORE and continue. */ - } - } - - /* Set up to resume scan. */ - /* Test to see if 3rd pair can slide into 2nd pair. */ - /* The values of the 2nd pair MUST be different. */ - /* If 3rd pair values are different ... */ - if(*p1ptr != *p2ptr){ - /* Set next first pair to last of repeated */ - /* 2nd pairs, ie. back up one pair. */ - cy--; - } - - /* Otherwise, 3rd pair can't be a 2nd pair, so */ - /* keep pointing to 3rd pair so that it is used */ - /* in the next first pair test. */ - - } /* Else, at end of current scan row. */ - } - - /* Otherwise, 2nd pair failed, so keep pointing to it */ - /* so that it is used in the next first pair test. */ - - } /* Else, at end of current scan column. */ - } - /* Otherwise, 1st pair failed... */ - else{ - /* Bump forward to next pixel pair. */ - cy++; - } - } /* While not at end of current scan column. */ - /* Bump forward to next scan column. */ - cx++; - } /* While not out of scan columns. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1785,62 +1364,6 @@ int scan4minutiae_vertically_V2(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int rescan4minutiae_horizontally(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int *imap, const int *nmap, - const int blk_x, const int blk_y, - const int mw, const int mh, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int blk_i, ret; - - /* Compute block index from block coordinates. */ - blk_i = (blk_y*mw)+blk_x; - - /* If high-curve block... */ - if(nmap[blk_i] == HIGH_CURVATURE){ - /* Rescan entire block in orthogonal direction. */ - if((ret = scan4minutiae_horizontally(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - scan_x, scan_y, scan_w, scan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } - /* Otherwise, block is low-curvature. */ - else{ - /* 1. Rescan horizontally to the North. */ - if((ret = rescan_partial_horizontally(NORTH, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - - /* 2. Rescan horizontally to the East. */ - if((ret = rescan_partial_horizontally(EAST, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - - /* 3. Rescan horizontally to the South. */ - if((ret = rescan_partial_horizontally(SOUTH, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - - /* 4. Rescan horizontally to the West. */ - if((ret = rescan_partial_horizontally(WEST, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - } /* End low-curvature rescan. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1871,62 +1394,6 @@ int rescan4minutiae_horizontally(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int rescan4minutiae_vertically(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int *imap, const int *nmap, - const int blk_x, const int blk_y, - const int mw, const int mh, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int blk_i, ret; - - /* Compute block index from block coordinates. */ - blk_i = (blk_y*mw)+blk_x; - - /* If high-curve block... */ - if(nmap[blk_i] == HIGH_CURVATURE){ - /* Rescan entire block in orthogonal direction. */ - if((ret = scan4minutiae_vertically(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - scan_x, scan_y, scan_w, scan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } - /* Otherwise, block is low-curvature. */ - else{ - /* 1. Rescan vertically to the North. */ - if((ret = rescan_partial_vertically(NORTH, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - - /* 2. Rescan vertically to the East. */ - if((ret = rescan_partial_vertically(EAST, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - - /* 3. Rescan vertically to the South. */ - if((ret = rescan_partial_vertically(SOUTH, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - - /* 4. Rescan vertically to the West. */ - if((ret = rescan_partial_vertically(WEST, minutiae, bdata, iw, ih, - imap, nmap, blk_x, blk_y, mw, mh, - scan_x, scan_y, scan_w, scan_h, lfsparms))) - return(ret); - } /* End low-curvature rescan. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -1957,70 +1424,6 @@ int rescan4minutiae_vertically(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int rescan_partial_horizontally(const int nbr_dir, MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int *imap, const int *nmap, - const int blk_x, const int blk_y, - const int mw, const int mh, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int nblk_i, blk_i; - int rescan_dir; - int rescan_x, rescan_y, rescan_w, rescan_h; - int ret; - - /* Neighbor will either be NORTH, SOUTH, EAST, OR WEST. */ - ret = get_nbr_block_index(&nblk_i, nbr_dir, blk_x, blk_y, mw, mh); - /* Will return: */ - /* 1. Neighbor index found == FOUND */ - /* 2. Neighbor not found == NOT_FOUND */ - /* 3. System error < 0 */ - - /* If system error ... */ - if(ret < 0) - /* Return the error code. */ - return(ret); - - /* If neighbor not found ... */ - if(ret == NOT_FOUND) - /* Nothing to do, so return normally. */ - return(0); - - /* Otherwise, neighboring block found ... */ - - /* If neighbor block is VALID... */ - if(imap[nblk_i] != INVALID_DIR){ - - /* Compute block index from current (not neighbor) block coordinates. */ - blk_i = (blk_y*mw)+blk_x; - - /* Select feature scan direction based on neighbor IMAP. */ - rescan_dir = choose_scan_direction(imap[nblk_i], - lfsparms->num_directions); - /* If new scan direction is HORIZONTAL... */ - if(rescan_dir == SCAN_HORIZONTAL){ - /* Adjust scan_x, scan_y, scan_w, scan_h for rescan. */ - if((ret = adjust_horizontal_rescan(nbr_dir, &rescan_x, &rescan_y, - &rescan_w, &rescan_h, - scan_x, scan_y, scan_w, scan_h, lfsparms->blocksize))) - /* Return system error code. */ - return(ret); - /* Rescan specified region in block vertically. */ - /* Pass IMAP direction for the block, NOT its neighbor. */ - if((ret = scan4minutiae_horizontally(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - rescan_x, rescan_y, rescan_w, rescan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } /* Otherwise, block has already been scanned vertically. */ - } /* Otherwise, neighbor has INVALID IMAP, so ignore rescan. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2051,70 +1454,6 @@ int rescan_partial_horizontally(const int nbr_dir, MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -int rescan_partial_vertically(const int nbr_dir, MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const int *imap, const int *nmap, - const int blk_x, const int blk_y, - const int mw, const int mh, - const int scan_x, const int scan_y, - const int scan_w, const int scan_h, - const LFSPARMS *lfsparms) -{ - int nblk_i, blk_i; - int rescan_dir; - int rescan_x, rescan_y, rescan_w, rescan_h; - int ret; - - /* Neighbor will either be NORTH, SOUTH, EAST, OR WEST. */ - ret = get_nbr_block_index(&nblk_i, nbr_dir, blk_x, blk_y, mw, mh); - /* Will return: */ - /* 1. Neighbor index found == FOUND */ - /* 2. Neighbor not found == NOT_FOUND */ - /* 3. System error < 0 */ - - /* If system error ... */ - if(ret < 0) - /* Return the error code. */ - return(ret); - - /* If neighbor not found ... */ - if(ret == NOT_FOUND) - /* Nothing to do, so return normally. */ - return(0); - - /* Otherwise, neighboring block found ... */ - - /* If neighbor block is VALID... */ - if(imap[nblk_i] != INVALID_DIR){ - - /* Compute block index from current (not neighbor) block coordinates. */ - blk_i = (blk_y*mw)+blk_x; - - /* Select feature scan direction based on neighbor IMAP. */ - rescan_dir = choose_scan_direction(imap[nblk_i], - lfsparms->num_directions); - /* If new scan direction is VERTICAL... */ - if(rescan_dir == SCAN_VERTICAL){ - /* Adjust scan_x, scan_y, scan_w, scan_h for rescan. */ - if((ret = adjust_vertical_rescan(nbr_dir, &rescan_x, &rescan_y, - &rescan_w, &rescan_h, - scan_x, scan_y, scan_w, scan_h, lfsparms->blocksize))) - /* Return system error code. */ - return(ret); - /* Rescan specified region in block vertically. */ - /* Pass IMAP direction for the block, NOT its neighbor. */ - if((ret = scan4minutiae_vertically(minutiae, bdata, iw, ih, - imap[blk_i], nmap[blk_i], - rescan_x, rescan_y, rescan_w, rescan_h, lfsparms))) - /* Return code may be: */ - /* 1. ret<0 (implying system error) */ - return(ret); - } /* Otherwise, block has already been scanned horizontally. */ - } /* Otherwise, neighbor has INVALID IMAP, so ignore rescan. */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2134,56 +1473,6 @@ int rescan_partial_vertically(const int nbr_dir, MINUTIAE *minutiae, FOUND - neighbor index exists and returned Negative - system error **************************************************************************/ -int get_nbr_block_index(int *oblk_i, const int nbr_dir, - const int blk_x, const int blk_y, const int mw, const int mh) -{ - int nx, ny, ni; - - switch(nbr_dir){ - case NORTH: - /* If neighbor doesn't exist above... */ - if((ny = blk_y-1) < 0) - /* Done, so return normally. */ - return(NOT_FOUND); - /* Get neighbor's block index. */ - ni = (ny*mw)+blk_x; - break; - case EAST: - /* If neighbor doesn't exist to the right... */ - if((nx = blk_x+1) >= mw) - /* Done, so return normally. */ - return(NOT_FOUND); - /* Get neighbor's block index. */ - ni = (blk_y*mw)+nx; - break; - case SOUTH: - /* If neighbor doesn't exist below... */ - if((ny = blk_y+1) >= mh) - /* Return normally. */ - return(NOT_FOUND); - /* Get neighbor's block index. */ - ni = (ny*mw)+blk_x; - break; - case WEST: - /* If neighbor doesn't exist to the left... */ - if((nx = blk_x-1) < 0) - /* Return normally. */ - return(NOT_FOUND); - /* Get neighbor's block index. */ - ni = (blk_y*mw)+nx; - break; - default: - fprintf(stderr, - "ERROR : get_nbr_block_index : illegal neighbor direction\n"); - return(-200); - } - - /* Assign output pointer. */ - *oblk_i = ni; - - /* Return neighbor FOUND. */ - return(FOUND); -} /************************************************************************* ************************************************************************** @@ -2206,126 +1495,6 @@ int get_nbr_block_index(int *oblk_i, const int nbr_dir, Zero - successful completion Negative - system error **************************************************************************/ -int adjust_horizontal_rescan(const int nbr_dir, int *rescan_x, int *rescan_y, - int *rescan_w, int *rescan_h, const int scan_x, const int scan_y, - const int scan_w, const int scan_h, const int blocksize) -{ - int half_blocksize, qtr_blocksize; - - /* Compute half of blocksize. */ - half_blocksize = blocksize>>1; - /* Compute quarter of blocksize. */ - qtr_blocksize = blocksize>>2; - - /* Neighbor will either be NORTH, SOUTH, EAST, OR WEST. */ - switch(nbr_dir){ - case NORTH: - /* - ************************* - * RESCAN NORTH * - * AREA * - ************************* - | | - | | - | | - | | - | | - | | - ------------------------- - */ - /* Rescan origin stays the same. */ - *rescan_x = scan_x; - *rescan_y = scan_y; - /* Rescan width stays the same. */ - *rescan_w = scan_w; - /* Rescan height is reduced to "qtr_blocksize" */ - /* if scan_h is larger. */ - *rescan_h = min(qtr_blocksize, scan_h); - break; - case EAST: - /* - ------------************* - | * * - | * * - | * E R * - | * A E * - | * S S * - | * T C * - | * A * - | * N * - | * * - | * * - ------------************* - */ - /* Rescan x-orign is set to half_blocksize from right edge of */ - /* block if scan width is larger. */ - *rescan_x = max(scan_x+scan_w-half_blocksize, scan_x); - /* Rescan y-origin stays the same. */ - *rescan_y = scan_y; - /* Rescan width is reduced to "half_blocksize" */ - /* if scan width is larger. */ - *rescan_w = min(half_blocksize, scan_w); - /* Rescan height stays the same. */ - *rescan_h = scan_h; - break; - case SOUTH: - /* - ------------------------- - | | - | | - | | - | | - | | - | | - ************************* - * RESCAN SOUTH * - * AREA * - ************************* - */ - /* Rescan x-origin stays the same. */ - *rescan_x = scan_x; - /* Rescan y-orign is set to qtr_blocksize from bottom edge of */ - /* block if scan height is larger. */ - *rescan_y = max(scan_y+scan_h-qtr_blocksize, scan_y); - /* Rescan width stays the same. */ - *rescan_w = scan_w; - /* Rescan height is reduced to "qtr_blocksize" */ - /* if scan height is larger. */ - *rescan_h = min(qtr_blocksize, scan_h); - break; - case WEST: - /* - *************------------ - * * | - * * | - * W R * | - * E E * | - * S S * | - * T C * | - * A * | - * N * | - * * | - * * | - *************------------ - */ - /* Rescan origin stays the same. */ - *rescan_x = scan_x; - *rescan_y = scan_y; - /* Rescan width is reduced to "half_blocksize" */ - /* if scan width is larger. */ - *rescan_w = min(half_blocksize, scan_w); - /* Rescan height stays the same. */ - *rescan_h = scan_h; - break; - default: - fprintf(stderr, - "ERROR : adjust_horizontal_rescan : illegal neighbor direction\n"); - return(-210); - } - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2348,128 +1517,6 @@ int adjust_horizontal_rescan(const int nbr_dir, int *rescan_x, int *rescan_y, Zero - successful completion Negative - system error **************************************************************************/ -int adjust_vertical_rescan(const int nbr_dir, int *rescan_x, int *rescan_y, - int *rescan_w, int *rescan_h, const int scan_x, const int scan_y, - const int scan_w, const int scan_h, const int blocksize) -{ - int half_blocksize, qtr_blocksize; - - /* Compute half of blocksize. */ - half_blocksize = blocksize>>1; - /* Compute quarter of blocksize. */ - qtr_blocksize = blocksize>>2; - - /* Neighbor will either be NORTH, SOUTH, EAST, OR WEST. */ - switch(nbr_dir){ - case NORTH: - /* - ************************* - * * - * RESCAN NORTH * - * AREA * - * * - ************************* - | | - | | - | | - | | - | | - ------------------------- - */ - /* Rescan origin stays the same. */ - *rescan_x = scan_x; - *rescan_y = scan_y; - /* Rescan width stays the same. */ - *rescan_w = scan_w; - /* Rescan height is reduced to "half_blocksize" */ - /* if scan_h is larger. */ - *rescan_h = min(half_blocksize, scan_h); - break; - case EAST: - /* - ------------------******* - | * * - | * * - | * E R * - | * A E * - | * S S * - | * T C * - | * A * - | * N * - | * * - | * * - ------------------******* - */ - /* Rescan x-orign is set to qtr_blocksize from right edge of */ - /* block if scan width is larger. */ - *rescan_x = max(scan_x+scan_w-qtr_blocksize, scan_x); - /* Rescan y-origin stays the same. */ - *rescan_y = scan_y; - /* Rescan width is reduced to "qtr_blocksize" */ - /* if scan width is larger. */ - *rescan_w = min(qtr_blocksize, scan_w); - /* Rescan height stays the same. */ - *rescan_h = scan_h; - break; - case SOUTH: - /* - ------------------------- - | | - | | - | | - | | - | | - ************************* - * * - * RESCAN SOUTH * - * AREA * - * * - ************************* - */ - /* Rescan x-origin stays the same. */ - *rescan_x = scan_x; - /* Rescan y-orign is set to half_blocksize from bottom edge of */ - /* block if scan height is larger. */ - *rescan_y = max(scan_y+scan_h-half_blocksize, scan_y); - /* Rescan width stays the same. */ - *rescan_w = scan_w; - /* Rescan height is reduced to "half_blocksize" */ - /* if scan height is larger. */ - *rescan_h = min(half_blocksize, scan_h); - break; - case WEST: - /* - *******------------------ - * * | - * * | - * W R * | - * E E * | - * S S * | - * T C * | - * A * | - * N * | - * * | - * * | - *******------------------ - */ - /* Rescan origin stays the same. */ - *rescan_x = scan_x; - *rescan_y = scan_y; - /* Rescan width is reduced to "qtr_blocksize" */ - /* if scan width is larger. */ - *rescan_w = min(qtr_blocksize, scan_w); - /* Rescan height stays the same. */ - *rescan_h = scan_h; - break; - default: - fprintf(stderr, - "ERROR : adjust_vertical_rescan : illegal neighbor direction\n"); - return(-220); - } - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2484,7 +1531,7 @@ int adjust_vertical_rescan(const int nbr_dir, int *rescan_x, int *rescan_y, cx - x-pixel coord where 3rd pattern pair of mintuia was detected cy - y-pixel coord where 3rd pattern pair of mintuia was detected y2 - y-pixel coord where 2nd pattern pair of mintuia was detected - feature_id - type of minutia (ex. index into feature_patterns[] list) + feature_id - type of minutia (ex. index into g_feature_patterns[] list) bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image @@ -2498,81 +1545,6 @@ int adjust_vertical_rescan(const int nbr_dir, int *rescan_x, int *rescan_y, IGNORE - minutia is to be ignored Negative - system error **************************************************************************/ -int process_horizontal_scan_minutia(MINUTIAE *minutiae, - const int cx, const int cy, - const int x2, const int feature_id, - unsigned char *bdata, const int iw, const int ih, - const int imapval, const int nmapval, - const LFSPARMS *lfsparms) -{ - MINUTIA *minutia; - int x_loc, y_loc; - int x_edge, y_edge; - int idir, ret; - - /* Set x location of minutia point to be half way between */ - /* first position of second feature pair and position of */ - /* third feature pair. */ - x_loc = (cx + x2)>>1; - - /* Set same x location to neighboring edge pixel. */ - x_edge = x_loc; - - /* Feature location should always point to either ending */ - /* of ridge or (for bifurcations) ending of valley. */ - /* So, if detected feature is APPEARING... */ - if(g_feature_patterns[feature_id].appearing){ - /* Set y location to second scan row. */ - y_loc = cy+1; - /* Set y location of neighboring edge pixel to the first scan row. */ - y_edge = cy; - } - /* Otherwise, feature is DISAPPEARING... */ - else{ - /* Set y location to first scan row. */ - y_loc = cy; - /* Set y location of neighboring edge pixel to the second scan row. */ - y_edge = cy+1; - } - - /* If current minutia is in a high-curvature block... */ - if(nmapval == HIGH_CURVATURE){ - /* Adjust location and direction locally. */ - if((ret = adjust_high_curvature_minutia(&idir, &x_loc, &y_loc, - &x_edge, &y_edge, x_loc, y_loc, x_edge, y_edge, - bdata, iw, ih, minutiae, lfsparms))){ - /* Could be a system error or IGNORE minutia. */ - return(ret); - } - /* Otherwise, we have our high-curvature minutia attributes. */ - } - /* Otherwise, minutia is in fairly low-curvature block... */ - else{ - /* Get minutia direction based on current IMAP value. */ - idir = get_low_curvature_direction(SCAN_HORIZONTAL, - g_feature_patterns[feature_id].appearing, - imapval, lfsparms->num_directions); - } - - /* Create a minutia object based on derived attributes. */ - if((ret = create_minutia(&minutia, x_loc, y_loc, x_edge, y_edge, idir, - DEFAULT_RELIABILITY, - g_feature_patterns[feature_id].type, - g_feature_patterns[feature_id].appearing, feature_id))) - /* Return system error. */ - return(ret); - - /* Update the minutiae list with potential new minutia. */ - ret = update_minutiae(minutiae, minutia, bdata, iw, ih, lfsparms); - - /* If minuitia IGNORED and not added to the minutia list ... */ - if(ret == IGNORE) - /* Deallocate the minutia. */ - free_minutia(minutia); - - /* Otherwise, return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2587,7 +1559,7 @@ int process_horizontal_scan_minutia(MINUTIAE *minutiae, cx - x-pixel coord where 3rd pattern pair of mintuia was detected cy - y-pixel coord where 3rd pattern pair of mintuia was detected y2 - y-pixel coord where 2nd pattern pair of mintuia was detected - feature_id - type of minutia (ex. index into feature_patterns[] list) + feature_id - type of minutia (ex. index into g_feature_patterns[] list) bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image @@ -2626,7 +1598,7 @@ int process_horizontal_scan_minutia_V2(MINUTIAE *minutiae, /* Feature location should always point to either ending */ /* of ridge or (for bifurcations) ending of valley. */ - /* So, if detected feature is APPEARING... */ + /* So, if detected feature is APPEARING... */ if(g_feature_patterns[feature_id].appearing){ /* Set y location to second scan row. */ y_loc = cy+1; @@ -2711,7 +1683,7 @@ int process_horizontal_scan_minutia_V2(MINUTIAE *minutiae, cx - x-pixel coord where 3rd pattern pair of mintuia was detected cy - y-pixel coord where 3rd pattern pair of mintuia was detected x2 - x-pixel coord where 2nd pattern pair of mintuia was detected - feature_id - type of minutia (ex. index into feature_patterns[] list) + feature_id - type of minutia (ex. index into g_feature_patterns[] list) bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image @@ -2725,80 +1697,6 @@ int process_horizontal_scan_minutia_V2(MINUTIAE *minutiae, IGNORE - minutia is to be ignored Negative - system error **************************************************************************/ -int process_vertical_scan_minutia(MINUTIAE *minutiae, - const int cx, const int cy, - const int y2, const int feature_id, - unsigned char *bdata, const int iw, const int ih, - const int imapval, const int nmapval, - const LFSPARMS *lfsparms) -{ - MINUTIA *minutia; - int x_loc, y_loc; - int x_edge, y_edge; - int idir, ret; - - /* Feature location should always point to either ending */ - /* of ridge or (for bifurcations) ending of valley. */ - /* So, if detected feature is APPEARING... */ - if(g_feature_patterns[feature_id].appearing){ - /* Set x location to second scan column. */ - x_loc = cx+1; - /* Set x location of neighboring edge pixel to the first scan column. */ - x_edge = cx; - } - /* Otherwise, feature is DISAPPEARING... */ - else{ - /* Set x location to first scan column. */ - x_loc = cx; - /* Set x location of neighboring edge pixel to the second scan column. */ - x_edge = cx+1; - } - - /* Set y location of minutia point to be half way between */ - /* first position of second feature pair and position of */ - /* third feature pair. */ - y_loc = (cy + y2)>>1; - /* Set same y location to neighboring edge pixel. */ - y_edge = y_loc; - - /* If current minutia is in a high-curvature block... */ - if(nmapval == HIGH_CURVATURE){ - /* Adjust location and direction locally. */ - if((ret = adjust_high_curvature_minutia(&idir, &x_loc, &y_loc, - &x_edge, &y_edge, x_loc, y_loc, x_edge, y_edge, - bdata, iw, ih, minutiae, lfsparms))){ - /* Could be a system error or IGNORE minutia. */ - return(ret); - } - /* Otherwise, we have our high-curvature minutia attributes. */ - } - /* Otherwise, minutia is in fairly low-curvature block... */ - else{ - /* Get minutia direction based on current IMAP value. */ - idir = get_low_curvature_direction(SCAN_VERTICAL, - g_feature_patterns[feature_id].appearing, - imapval, lfsparms->num_directions); - } - - /* Create a minutia object based on derived attributes. */ - if((ret = create_minutia(&minutia, x_loc, y_loc, x_edge, y_edge, idir, - DEFAULT_RELIABILITY, - g_feature_patterns[feature_id].type, - g_feature_patterns[feature_id].appearing, feature_id))) - /* Return system error. */ - return(ret); - - /* Update the minutiae list with potential new minutia. */ - ret = update_minutiae(minutiae, minutia, bdata, iw, ih, lfsparms); - - /* If minuitia IGNORED and not added to the minutia list ... */ - if(ret == IGNORE) - /* Deallocate the minutia. */ - free_minutia(minutia); - - /* Otherwise, return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -2813,7 +1711,7 @@ int process_vertical_scan_minutia(MINUTIAE *minutiae, cx - x-pixel coord where 3rd pattern pair of mintuia was detected cy - y-pixel coord where 3rd pattern pair of mintuia was detected x2 - x-pixel coord where 2nd pattern pair of mintuia was detected - feature_id - type of minutia (ex. index into feature_patterns[] list) + feature_id - type of minutia (ex. index into g_feature_patterns[] list) bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image @@ -2844,7 +1742,7 @@ int process_vertical_scan_minutia_V2(MINUTIAE *minutiae, /* Feature location should always point to either ending */ /* of ridge or (for bifurcations) ending of valley. */ - /* So, if detected feature is APPEARING... */ + /* So, if detected feature is APPEARING... */ if(g_feature_patterns[feature_id].appearing){ /* Set x location to second scan column. */ x_loc = cx+1; @@ -2884,7 +1782,7 @@ int process_vertical_scan_minutia_V2(MINUTIAE *minutiae, /* Could be a system error or IGNORE minutia. */ return(ret); } - /* Otherwise, we have our high-curvature minutia attributes. */ + /* Otherwise, we have our high-curvature minutia attributes. */ } /* Otherwise, minutia is in fairly low-curvature block... */ else{ @@ -2959,167 +1857,6 @@ int process_vertical_scan_minutia_V2(MINUTIAE *minutiae, IGNORE - minutia point is to be ignored Negative - system error **************************************************************************/ -int adjust_high_curvature_minutia(int *oidir, int *ox_loc, int *oy_loc, - int *ox_edge, int *oy_edge, - const int x_loc, const int y_loc, - const int x_edge, const int y_edge, - unsigned char *bdata, const int iw, const int ih, - MINUTIAE *minutiae, const LFSPARMS *lfsparms) -{ - int ret; - int *contour_x, *contour_y, *contour_ex, *contour_ey, ncontour; - int min_i; - double min_theta; - int feature_pix; - int mid_x, mid_y, mid_pix; - int idir; - int half_contour, angle_edge; - - /* Set variable from parameter structure. */ - half_contour = lfsparms->high_curve_half_contour; - - /* Set edge length for computing contour's angle of curvature */ - /* to one quarter of desired pixel length of entire contour. */ - /* Ex. If half_contour==14, then contour length==29=(2X14)+1 */ - /* and angle_edge==7=(14/2). */ - angle_edge = half_contour>>1; - - /* Get the pixel value of current feature. */ - feature_pix = *(bdata + (y_loc * iw) + x_loc); - - /* Extract feature's contour. */ - if((ret = get_high_curvature_contour(&contour_x, &contour_y, - &contour_ex, &contour_ey, &ncontour, half_contour, - x_loc, y_loc, x_edge, y_edge, bdata, iw, ih))){ - /* Returns with: */ - /* 1. Successful or empty contour == 0 */ - /* If contour is empty, then contour lists are not allocated. */ - /* 2. Contour forms loop == LOOP_FOUND */ - /* 3. Sysetm error < 0 */ - - /* If the contour forms a loop... */ - if(ret == LOOP_FOUND){ - - /* If the order of the contour is clockwise, then the loops's */ - /* contour pixels are outside the corresponding edge pixels. We */ - /* definitely do NOT want to fill based on the feature pixel in */ - /* this case, because it is OUTSIDE the loop. For now we will */ - /* ignore the loop and the minutia that triggered its tracing. */ - /* It is likely that other minutia on the loop will be */ - /* detected that create a contour on the "inside" of the loop. */ - /* There is another issue here that could be addressed ... */ - /* It seems that many/multiple minutia are often detected within */ - /* the same loop, which currently requires retracing the loop, */ - /* locating minutia on opposite ends of the major axis of the */ - /* loop, and then determining that the minutia have already been */ - /* entered into the minutiae list upon processing the very first */ - /* minutia detected in the loop. There is a lot of redundant */ - /* work being done here! */ - /* Is_loop_clockwise takes a default value to be returned if the */ - /* routine is unable to determine the direction of the contour. */ - /* In this case, we want to IGNORE the loop if we can't tell its */ - /* direction so that we do not inappropriately fill the loop, so */ - /* we are passing the default value TRUE. */ - if((ret = is_loop_clockwise(contour_x, contour_y, ncontour, TRUE))){ - /* Deallocate contour lists. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - /* If we had a system error... */ - if(ret < 0) - /* Return the error code. */ - return(ret); - /* Otherwise, loop is clockwise, so return IGNORE. */ - return(IGNORE); - } - - /* Otherwise, process the clockwise-ordered contour of the loop */ - /* as it may contain minutia. If no minutia found, then it is */ - /* filled in. */ - ret = process_loop(minutiae, contour_x, contour_y, - contour_ex, contour_ey, ncontour, - bdata, iw, ih, lfsparms); - /* Returns with: */ - /* 1. Successful processing of loop == 0 */ - /* 2. System error < 0 */ - - /* Deallocate contour lists. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - - /* If loop processed successfully ... */ - if(ret == 0) - /* Then either a minutia pair was extracted or the loop was */ - /* filled. Either way we want to IGNORE the minutia that */ - /* started the whole loop processing in the beginning. */ - return(IGNORE); - - /* Otherwise, there was a system error. */ - /* Return the resulting code. */ - return(ret); - } - - /* Otherwise not a loop, so get_high_curvature_contour incurred */ - /* a system error. Return the error code. */ - return(ret); - } - - /* If contour is empty ... then contour lists were not allocated, so */ - /* simply return IGNORE. The contour comes back empty when there */ - /* were not a sufficient number of points found on the contour. */ - if(ncontour == 0) - return(IGNORE); - - /* Otherwise, there are contour points to process. */ - - /* Given the contour, determine the point of highest curvature */ - /* (ie. forming the minimum angle between contour walls). */ - if((ret = min_contour_theta(&min_i, &min_theta, angle_edge, - contour_x, contour_y, ncontour))){ - /* Deallocate contour lists. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - /* Returns IGNORE or system error. Either way */ - /* free the contour and return the code. */ - return(ret); - } - - /* If the minimum theta found along the contour is too large... */ - if(min_theta >= lfsparms->max_high_curve_theta){ - /* Deallocate contour lists. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - /* Reject the high-curvature minutia, and return IGNORE. */ - return(IGNORE); - } - - /* Test to see if interior of curvature is OK. Compute midpoint */ - /* between left and right points symmetrically distant (angle_edge */ - /* pixels) from the contour's point of minimum theta. */ - mid_x = (contour_x[min_i-angle_edge] + contour_x[min_i+angle_edge])>>1; - mid_y = (contour_y[min_i-angle_edge] + contour_y[min_i+angle_edge])>>1; - mid_pix = *(bdata + (mid_y * iw) + mid_x); - /* If the interior pixel value is not the same as the feature's... */ - if(mid_pix != feature_pix){ - /* Deallocate contour lists. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - /* Reject the high-curvature minutia and return IGNORE. */ - return(IGNORE); - } - - /* Compute new direction based on line connecting adjusted feature */ - /* location and the midpoint in the feature's interior. */ - idir = line2direction(contour_x[min_i], contour_y[min_i], - mid_x, mid_y, lfsparms->num_directions); - - /* Set minutia location to minimum theta position on the contour. */ - *oidir = idir; - *ox_loc = contour_x[min_i]; - *oy_loc = contour_y[min_i]; - *ox_edge = contour_ex[min_i]; - *oy_edge = contour_ey[min_i]; - - /* Deallocate contour buffers. */ - free_contour(contour_x, contour_y, contour_ex, contour_ey); - - /*Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -3464,48 +2201,3 @@ int get_low_curvature_direction(const int scan_dir, const int appearing, return(idir); } -/************************************************************************* -************************************************************************** -#cat: lfs2nist_minutia_XYT - Converts XYT minutiae attributes in LFS native -#cat: representation to NIST internal representation - - Input: - minutia - LFS minutia structure containing attributes to be converted - Output: - ox - NIST internal based x-pixel coordinate - oy - NIST internal based y-pixel coordinate - ot - NIST internal based minutia direction/orientation - Return Code: - Zero - successful completion - Negative - system error -**************************************************************************/ -void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot, - const MINUTIA *minutia, const int iw, const int ih) -{ - int x, y, t; - float degrees_per_unit; - - /* XYT's according to NIST internal rep: */ - /* 1. pixel coordinates with origin bottom-left */ - /* 2. orientation in degrees on range [0..360] */ - /* with 0 pointing east and increasing counter */ - /* clockwise (same as M1) */ - /* 3. direction pointing out and away from the */ - /* ridge ending or bifurcation valley */ - /* (opposite direction from M1) */ - - x = minutia->x; - y = ih - minutia->y; - - degrees_per_unit = 180 / (float)NUM_DIRECTIONS; - - t = (270 - sround(minutia->direction * degrees_per_unit)) % 360; - if(t < 0){ - t += 360; - } - - *ox = x; - *oy = y; - *ot = t; -} - diff --git a/libfprint/nbis/mindtct/morph.c b/libfprint/nbis/mindtct/morph.c index d4ec85f3..1399b0d8 100644 --- a/libfprint/nbis/mindtct/morph.c +++ b/libfprint/nbis/mindtct/morph.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -69,13 +90,13 @@ void erode_charimage_2(unsigned char *inp, unsigned char *out, { int row, col; unsigned char *itr = inp, *otr = out; - + memcpy(out, inp, iw*ih); - + /* for true pixels. kill pixel if there is at least one false neighbor */ for ( row = 0 ; row < ih ; row++ ) for ( col = 0 ; col < iw ; col++ ) - { + { if (*itr) /* erode only operates on true pixels */ { /* more efficient with C's left to right evaluation of */ @@ -87,7 +108,7 @@ void erode_charimage_2(unsigned char *inp, unsigned char *out, *otr = 0; } itr++ ; otr++; - } + } } /************************************************************************* @@ -109,13 +130,13 @@ void dilate_charimage_2(unsigned char *inp, unsigned char *out, { int row, col; unsigned char *itr = inp, *otr = out; - + memcpy(out, inp, iw*ih); - + /* for all pixels. set pixel if there is at least one true neighbor */ for ( row = 0 ; row < ih ; row++ ) for ( col = 0 ; col < iw ; col++ ) - { + { if (!*itr) /* pixel is already true, neighbors irrelevant */ { /* more efficient with C's left to right evaluation of */ @@ -127,7 +148,7 @@ void dilate_charimage_2(unsigned char *inp, unsigned char *out, *otr = 1; } itr++ ; otr++; - } + } } /************************************************************************* @@ -151,8 +172,8 @@ char get_south8_2(char *ptr, const int row, const int iw, const int ih, { if (row >= ih-1) /* catch case where image is undefined southwards */ return failcode; /* use plane geometry and return code. */ - else - return *(ptr+iw); + + return *(ptr+iw); } /************************************************************************* @@ -175,8 +196,8 @@ char get_north8_2(char *ptr, const int row, const int iw, { if (row < 1) /* catch case where image is undefined northwards */ return failcode; /* use plane geometry and return code. */ - else - return *(ptr-iw); + + return *(ptr-iw); } /************************************************************************* @@ -199,8 +220,8 @@ char get_east8_2(char *ptr, const int col, const int iw, { if (col >= iw-1) /* catch case where image is undefined eastwards */ return failcode; /* use plane geometry and return code. */ - else - return *(ptr+ 1); + + return *(ptr+ 1); } /************************************************************************* @@ -221,6 +242,6 @@ char get_west8_2(char *ptr, const int col, const int failcode) { if (col < 1) /* catch case where image is undefined westwards */ return failcode; /* use plane geometry and return code. */ - else - return *(ptr- 1); + + return *(ptr- 1); } diff --git a/libfprint/nbis/mindtct/quality.c b/libfprint/nbis/mindtct/quality.c index 5dcabc2a..94e9b63a 100644 --- a/libfprint/nbis/mindtct/quality.c +++ b/libfprint/nbis/mindtct/quality.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -39,12 +60,11 @@ identified are necessarily the best available for the purpose. combined_minutia_quality() grayscale_reliability() get_neighborhood_stats() + reliability_fr_quality_map() ***********************************************************************/ #include -#include -#include #include #include @@ -95,6 +115,9 @@ int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map, int arrayPos, arrayPos2; int QualOffset; + ASSERT_SIZE_MUL(map_w, map_h); + ASSERT_SIZE_MUL(map_w * map_h, sizeof(int)); + QualMap = (int *)malloc(map_w * map_h * sizeof(int)); if(QualMap == (int *)NULL){ fprintf(stderr, "ERROR : gen_quality_map : malloc : QualMap\n"); @@ -172,120 +195,6 @@ int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map, return(0); } -/*********************************************************************** -************************************************************************ -#cat: get_neighborhood_stats - Given a minutia point, computes the mean -#cat: and stdev of the 8-bit grayscale pixels values in a -#cat: surrounding neighborhood with specified radius. - - Code originally written by Austin Hicklin for FBI ATU - Modified by Michael D. Garris (NIST) Sept. 25, 2000 - - Input: - minutia - structure containing detected minutia - idata - 8-bit grayscale fingerprint image - iw - width (in pixels) of the image - ih - height (in pixels) of the image - radius_pix - pixel radius of surrounding neighborhood - Output: - mean - mean of neighboring pixels - stdev - standard deviation of neighboring pixels -************************************************************************/ -static void get_neighborhood_stats(double *mean, double *stdev, MINUTIA *minutia, - unsigned char *idata, const int iw, const int ih, - const int radius_pix) -{ - int i, x, y, rows, cols; - int n = 0, sumX = 0, sumXX = 0; - int histogram[256]; - - /* Zero out histogram. */ - memset(histogram, 0, 256 * sizeof(int)); - - /* Set minutia's coordinate variables. */ - x = minutia->x; - y = minutia->y; - - - /* If minutiae point is within sampleboxsize distance of image border, */ - /* a value of 0 reliability is returned. */ - if ((x < radius_pix) || (x > iw-radius_pix-1) || - (y < radius_pix) || (y > ih-radius_pix-1)) { - *mean = 0.0; - *stdev = 0.0; - return; - - } - - /* Foreach row in neighborhood ... */ - for(rows = y - radius_pix; - rows <= y + radius_pix; - rows++){ - /* Foreach column in neighborhood ... */ - for(cols = x - radius_pix; - cols <= x + radius_pix; - cols++){ - /* Bump neighbor's pixel value bin in histogram. */ - histogram[*(idata+(rows * iw)+cols)]++; - } - } - - /* Foreach grayscale pixel bin ... */ - for(i = 0; i < 256; i++){ - if(histogram[i]){ - /* Accumulate Sum(X[i]) */ - sumX += (i * histogram[i]); - /* Accumulate Sum(X[i]^2) */ - sumXX += (i * i * histogram[i]); - /* Accumulate N samples */ - n += histogram[i]; - } - } - - /* Mean = Sum(X[i])/N */ - *mean = sumX/(double)n; - /* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */ - *stdev = sqrt((sumXX/(double)n) - ((*mean)*(*mean))); -} - -/*********************************************************************** -************************************************************************ -#cat: grayscale_reliability - Given a minutia point, computes a reliability -#cat: measure from the stdev and mean of its pixel neighborhood. - - Code originally written by Austin Hicklin for FBI ATU - Modified by Michael D. Garris (NIST) Sept. 25, 2000 - - GrayScaleReliability - reasonable reliability heuristic, returns - 0.0 .. 1.0 based on stdev and Mean of a localized histogram where - "ideal" stdev is >=64; "ideal" Mean is 127. In a 1 ridge radius - (11 pixels), if the bytevalue (shade of gray) in the image has a - stdev of >= 64 & a mean of 127, returns 1.0 (well defined - light & dark areas in equal proportions). - - Input: - minutia - structure containing detected minutia - idata - 8-bit grayscale fingerprint image - iw - width (in pixels) of the image - ih - height (in pixels) of the image - radius_pix - pixel radius of surrounding neighborhood - Return Value: - reliability - computed reliability measure -************************************************************************/ -static double grayscale_reliability(MINUTIA *minutia, unsigned char *idata, - const int iw, const int ih, const int radius_pix) -{ - double mean, stdev; - double reliability; - - get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix); - - reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV), - (1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN))); - - return(reliability); -} - /*********************************************************************** ************************************************************************ #cat: combined_minutia_quality - Combines quality measures derived from @@ -391,3 +300,137 @@ int combined_minutia_quality(MINUTIAE *minutiae, return(0); } + +/*********************************************************************** +************************************************************************ +#cat: grayscale_reliability - Given a minutia point, computes a reliability +#cat: measure from the stdev and mean of its pixel neighborhood. + + Code originally written by Austin Hicklin for FBI ATU + Modified by Michael D. Garris (NIST) Sept. 25, 2000 + + GrayScaleReliability - reasonable reliability heuristic, returns + 0.0 .. 1.0 based on stdev and Mean of a localized histogram where + "ideal" stdev is >=64; "ideal" Mean is 127. In a 1 ridge radius + (11 pixels), if the bytevalue (shade of gray) in the image has a + stdev of >= 64 & a mean of 127, returns 1.0 (well defined + light & dark areas in equal proportions). + + Input: + minutia - structure containing detected minutia + idata - 8-bit grayscale fingerprint image + iw - width (in pixels) of the image + ih - height (in pixels) of the image + radius_pix - pixel radius of surrounding neighborhood + Return Value: + reliability - computed reliability measure +************************************************************************/ +double grayscale_reliability(MINUTIA *minutia, unsigned char *idata, + const int iw, const int ih, const int radius_pix) +{ + double mean, stdev; + double reliability; + + get_neighborhood_stats(&mean, &stdev, minutia, idata, iw, ih, radius_pix); + + reliability = min((stdev>IDEALSTDEV ? 1.0 : stdev/(double)IDEALSTDEV), + (1.0-(fabs(mean-IDEALMEAN)/(double)IDEALMEAN))); + + return(reliability); +} + + +/*********************************************************************** +************************************************************************ +#cat: get_neighborhood_stats - Given a minutia point, computes the mean +#cat: and stdev of the 8-bit grayscale pixels values in a +#cat: surrounding neighborhood with specified radius. + + Code originally written by Austin Hicklin for FBI ATU + Modified by Michael D. Garris (NIST) Sept. 25, 2000 + + Input: + minutia - structure containing detected minutia + idata - 8-bit grayscale fingerprint image + iw - width (in pixels) of the image + ih - height (in pixels) of the image + radius_pix - pixel radius of surrounding neighborhood + Output: + mean - mean of neighboring pixels + stdev - standard deviation of neighboring pixels +************************************************************************/ +void get_neighborhood_stats(double *mean, double *stdev, MINUTIA *minutia, + unsigned char *idata, const int iw, const int ih, + const int radius_pix) +{ + int i, x, y, rows, cols; + int n = 0, sumX = 0, sumXX = 0; + int histogram[256]; + + /* Zero out histogram. */ + memset(histogram, 0, 256 * sizeof(int)); + + /* Set minutia's coordinate variables. */ + x = minutia->x; + y = minutia->y; + + + /* If minutiae point is within sampleboxsize distance of image border, */ + /* a value of 0 reliability is returned. */ + if ((x < radius_pix) || (x > iw-radius_pix-1) || + (y < radius_pix) || (y > ih-radius_pix-1)) { + *mean = 0.0; + *stdev = 0.0; + return; + + } + + /* Foreach row in neighborhood ... */ + for(rows = y - radius_pix; + rows <= y + radius_pix; + rows++){ + /* Foreach column in neighborhood ... */ + for(cols = x - radius_pix; + cols <= x + radius_pix; + cols++){ + /* Bump neighbor's pixel value bin in histogram. */ + histogram[*(idata+(rows * iw)+cols)]++; + } + } + + /* Foreach grayscale pixel bin ... */ + for(i = 0; i < 256; i++){ + if(histogram[i]){ + /* Accumulate Sum(X[i]) */ + sumX += (i * histogram[i]); + /* Accumulate Sum(X[i]^2) */ + sumXX += (i * i * histogram[i]); + /* Accumulate N samples */ + n += histogram[i]; + } + } + + /* Mean = Sum(X[i])/N */ + *mean = sumX/(double)n; + /* Stdev = sqrt((Sum(X[i]^2)/N) - Mean^2) */ + *stdev = sqrt((sumXX/(double)n) - ((*mean)*(*mean))); +} + +/*********************************************************************** +************************************************************************ +#cat: reliability_fr_quality_map - Takes a set of minutiae and assigns +#cat: each one a reliability measure based on 1 of 5 possible +#cat: quality levels from its location in a quality map. + + Input: + minutiae - structure contining the detected minutia + quality_map - map with blocks assigned 1 of 5 quality levels + map_w - width (in blocks) of the map + map_h - height (in blocks) of the map + blocksize - size (in pixels) of each block in the map + Output: + minutiae - updated reliability members + Return Code: + Zero - successful completion + Negative - system error +************************************************************************/ diff --git a/libfprint/nbis/mindtct/remove.c b/libfprint/nbis/mindtct/remove.c index 6863ecf3..faa6607e 100644 --- a/libfprint/nbis/mindtct/remove.c +++ b/libfprint/nbis/mindtct/remove.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -35,15 +56,21 @@ identified are necessarily the best available for the purpose. *********************************************************************** ROUTINES: + remove_false_minutia() remove_false_minutia_V2() remove_holes() remove_hooks() + remove_hooks_islands_overlaps() remove_islands_and_lakes() remove_malformations() - remove_near_invblock_V2() + remove_near_invblocks() + remove_near_invblocks_V2() + remove_pointing_invblock() remove_pointing_invblock_V2() remove_overlaps() + remove_pores() remove_pores_V2() + remove_or_adjust_side_minutiae() remove_or_adjust_side_minutiae_V2() ***********************************************************************/ @@ -52,6 +79,125 @@ identified are necessarily the best available for the purpose. #include #include +/************************************************************************* +************************************************************************** +#cat: remove_false_minutia - Takes a list of true and false minutiae and +#cat: attempts to detect and remove the false minutiae based +#cat: on a series of tests. + + Input: + minutiae - list of true and false minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: remove_false_minutia_V2 - Takes a list of true and false minutiae and +#cat: attempts to detect and remove the false minutiae based +#cat: on a series of tests. + + Input: + minutiae - list of true and false minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + direction_map - map of image blocks containing directional ridge flow + low_flow_map - map of image blocks flagged as LOW RIDGE FLOW + high_curve_map - map of image blocks flagged as HIGH CURVATURE + mw - width in blocks of the maps + mh - height in blocks of the maps + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ +int remove_false_minutia_V2(MINUTIAE *minutiae, + unsigned char *bdata, const int iw, const int ih, + int *direction_map, int *low_flow_map, int *high_curve_map, + const int mw, const int mh, const LFSPARMS *lfsparms) +{ + int ret; + + /* 1. Sort minutiae points top-to-bottom and left-to-right. */ + if((ret = sort_minutiae_y_x(minutiae, iw, ih))){ + return(ret); + } + + /* 2. Remove minutiae on lakes (filled with white pixels) and */ + /* islands (filled with black pixels), both defined by a pair of */ + /* minutia points. */ + if((ret = remove_islands_and_lakes(minutiae, bdata, iw, ih, lfsparms))){ + return(ret); + } + + /* 3. Remove minutiae on holes in the binary image defined by a */ + /* single point. */ + if((ret = remove_holes(minutiae, bdata, iw, ih, lfsparms))){ + return(ret); + } + + /* 4. Remove minutiae that point sufficiently close to a block with */ + /* INVALID direction. */ + if((ret = remove_pointing_invblock_V2(minutiae, direction_map, mw, mh, + lfsparms))){ + return(ret); + } + + /* 5. Remove minutiae that are sufficiently close to a block with */ + /* INVALID direction. */ + if((ret = remove_near_invblock_V2(minutiae, direction_map, mw, mh, + lfsparms))){ + return(ret); + } + + /* 6. Remove or adjust minutiae that reside on the side of a ridge */ + /* or valley. */ + if((ret = remove_or_adjust_side_minutiae_V2(minutiae, bdata, iw, ih, + direction_map, mw, mh, lfsparms))){ + return(ret); + } + + /* 7. Remove minutiae that form a hook on the side of a ridge or valley. */ + if((ret = remove_hooks(minutiae, bdata, iw, ih, lfsparms))){ + return(ret); + } + + /* 8. Remove minutiae that are on opposite sides of an overlap. */ + if((ret = remove_overlaps(minutiae, bdata, iw, ih, lfsparms))){ + return(ret); + } + + /* 9. Remove minutiae that are "irregularly" shaped. */ + if((ret = remove_malformations(minutiae, bdata, iw, ih, + low_flow_map, mw, mh, lfsparms))){ + return(ret); + } + + /* 10. Remove minutiae that form long, narrow, loops in the */ + /* "unreliable" regions in the binary image. */ + if((ret = remove_pores_V2(minutiae, bdata, iw, ih, + direction_map, low_flow_map, high_curve_map, + mw, mh, lfsparms))){ + return(ret); + } + + return(0); +} + /************************************************************************* ************************************************************************** #cat: remove_holes - Removes minutia points on small loops around valleys. @@ -68,7 +214,7 @@ identified are necessarily the best available for the purpose. Zero - successful completion Negative - system error **************************************************************************/ -static int remove_holes(MINUTIAE *minutiae, +int remove_holes(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, const LFSPARMS *lfsparms) { @@ -139,7 +285,7 @@ static int remove_holes(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_hooks(MINUTIAE *minutiae, +int remove_hooks(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, const LFSPARMS *lfsparms) { @@ -341,6 +487,29 @@ static int remove_hooks(MINUTIAE *minutiae, return(0); } +/************************************************************************* +************************************************************************** +#cat: remove_hooks_islands_lakes_overlaps - Removes minutia points on hooks, +#cat: islands, lakes, and overlaps and fills in small small +#cat: loops in the binary image and joins minutia features in +#cat: the image on opposite sides of an overlap. So, this +#cat: routine not only prunes minutia points but it edits the +#cat: binary input image as well. + + Input: + minutiae - list of true and false minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + bdata - edited binary image with loops filled and overlaps removed + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: remove_islands_and_lakes - Takes a list of true and false minutiae and @@ -362,7 +531,7 @@ static int remove_hooks(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_islands_and_lakes(MINUTIAE *minutiae, +int remove_islands_and_lakes(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, const LFSPARMS *lfsparms) { @@ -616,7 +785,7 @@ static int remove_islands_and_lakes(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_malformations(MINUTIAE *minutiae, +int remove_malformations(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, int *low_flow_map, const int mw, const int mh, const LFSPARMS *lfsparms) @@ -647,7 +816,7 @@ static int remove_malformations(MINUTIAE *minutiae, /* Return error code. */ return(ret); } - + /* If trace was not possible OR loop found OR */ /* contour is incomplete ... */ if((ret == IGNORE) || @@ -803,6 +972,26 @@ static int remove_malformations(MINUTIAE *minutiae, return(0); } +/************************************************************************* +************************************************************************** +#cat: remove_near_invblocks - Removes minutia points from the given list +#cat: that are sufficiently close to a block with invalid +#cat: ridge flow or to the edge of the image. + + Input: + minutiae - list of true and false minutiae + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: remove_near_invblocks_V2 - Removes minutia points from the given list @@ -821,7 +1010,7 @@ static int remove_malformations(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map, +int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map, const int mw, const int mh, const LFSPARMS *lfsparms) { int i, ret; @@ -1032,6 +1221,26 @@ static int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map, return(0); } +/************************************************************************* +************************************************************************** +#cat: remove_pointing_invblock - Removes minutia points that are relatively +#cat: close in the direction opposite the minutia to an NMAP +#cat: block with invalid ridge flow. + + Input: + minutiae - list of true and false minutiae + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: remove_pointing_invblock_V2 - Removes minutia points that are relatively @@ -1050,7 +1259,7 @@ static int remove_near_invblock_V2(MINUTIAE *minutiae, int *direction_map, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_pointing_invblock_V2(MINUTIAE *minutiae, +int remove_pointing_invblock_V2(MINUTIAE *minutiae, int *direction_map, const int mw, const int mh, const LFSPARMS *lfsparms) { @@ -1140,7 +1349,7 @@ static int remove_pointing_invblock_V2(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_overlaps(MINUTIAE *minutiae, +int remove_overlaps(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, const LFSPARMS *lfsparms) { @@ -1350,32 +1559,20 @@ static int remove_overlaps(MINUTIAE *minutiae, return(0); } -static void mark_minutiae_in_range(MINUTIAE *minutiae, int *to_remove, int x, int y, - const LFSPARMS *lfsparms) -{ - int i, dist; - for (i = 0; i < minutiae->num; i++) { - if (to_remove[i]) - continue; - dist = (int)sqrt((x - minutiae->list[i]->x) * (x - minutiae->list[i]->x) + - (y - minutiae->list[i]->y) * (y - minutiae->list[i]->y)); - if (dist < lfsparms->min_pp_distance) { - to_remove[i] = 1; - } - } -} - /************************************************************************* ************************************************************************** -#cat: remove_perimeter_pts - Takes a list of true and false minutiae and -#cat: attempts to detect and remove those false minutiae that -#cat: belong to image edge +#cat: remove_pores - Attempts to detect and remove minutia points located on +#cat: pore-shaped valleys. Input: minutiae - list of true and false minutiae bdata - binary image data (0==while & 1==black) iw - width (in pixels) of image ih - height (in pixels) of image + nmap - IMAP ridge flow matrix with invalid, high-curvature, + and no-valid-neighbor regions identified + mw - width in blocks of the NMAP + mh - height in blocks of the NMAP lfsparms - parameters and thresholds for controlling LFS Output: minutiae - list of pruned minutiae @@ -1383,125 +1580,6 @@ static void mark_minutiae_in_range(MINUTIAE *minutiae, int *to_remove, int x, in Zero - successful completion Negative - system error **************************************************************************/ -static int remove_perimeter_pts(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const LFSPARMS *lfsparms) -{ - int i, j, ret, *to_remove; - int *left, *left_up, *left_down; - int *right, *right_up, *right_down; - int removed = 0; - int left_min, right_max; - - if (!lfsparms->remove_perimeter_pts) - return(0); - - to_remove = calloc(minutiae->num, sizeof(int)); - left = calloc(ih, sizeof(int)); - left_up = calloc(ih, sizeof(int)); - left_down = calloc(ih, sizeof(int)); - right = calloc(ih, sizeof(int)); - right_up = calloc(ih, sizeof(int)); - right_down = calloc(ih, sizeof(int)); - - /* Pass downwards */ - left_min = iw - 1; - right_max = 0; - for (i = 0; i < ih; i++) { - for (j = 0; j < left_min; j++) { - if ((bdata[i * iw + j] != 0)) { - left_min = j; - break; - } - } - if (left_min == (iw - 1)) - left_down[i] = -1; - else - left_down[i] = left_min; - for (j = iw - 1; j >= right_max; j--) { - if ((bdata[i * iw + j] != 0)) { - right_max = j; - break; - } - } - if (right_max == 0) - right_down[i] = -1; - else - right_down[i] = right_max; - } - - /* Pass upwards */ - left_min = iw - 1; - right_max = 0; - for (i = ih - 1; i >= 0; i--) { - for (j = 0; j < left_min; j++) { - if ((bdata[i * iw + j] != 0)) { - left_min = j; - break; - } - } - if (left_min == (iw - 1)) - left_up[i] = -1; - else - left_up[i] = left_min; - for (j = iw - 1; j >= right_max; j--) { - if ((bdata[i * iw + j] != 0)) { - right_max = j; - break; - } - } - if (right_max == 0) - right_up[i] = -1; - else - right_up[i] = right_max; - } - - /* Merge */ - left_min = left_down[ih - 1]; - right_max = right_down[ih - 1]; - for (i = 0; i < ih; i++) { - if (left_down[i] != left_min) - left[i] = left_down[i]; - else - left[i] = left_up[i]; - - if (right_down[i] != right_max) - right[i] = right_down[i]; - else - right[i] = right_up[i]; - } - free(left_up); - free(left_down); - free(right_up); - free(right_down); - - /* Mark minitiae close to the edge */ - for (i = 0; i < ih; i++) { - if (left[i] != -1) - mark_minutiae_in_range(minutiae, to_remove, left[i], i, lfsparms); - if (right[i] != -1) - mark_minutiae_in_range(minutiae, to_remove, right[i], i, lfsparms); - } - - free(left); - free(right); - - for (i = minutiae->num - 1; i >= 0; i--) { - /* If the current minutia index is flagged for removal ... */ - if (to_remove[i]){ - removed ++; - /* Remove the minutia from the minutiae list. */ - if((ret = remove_minutia(i, minutiae))){ - free(to_remove); - return(ret); - } - } - } - - free(to_remove); - - return (0); -} /************************************************************************* ************************************************************************** @@ -1527,7 +1605,7 @@ static int remove_perimeter_pts(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_pores_V2(MINUTIAE *minutiae, +int remove_pores_V2(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, int *direction_map, int *low_flow_map, int *high_curve_map, const int mw, const int mh, @@ -1777,7 +1855,7 @@ static int remove_pores_V2(MINUTIAE *minutiae, /* counter-clockwise scan and step along a */ /* specified number of steps (ex. 8). */ ret = trace_contour(&contour_x, &contour_y, - &contour_ex, &contour_ey, &ncontour, + &contour_ex, &contour_ey, &ncontour, lfsparms->pores_steps_bwd, qx, qy, qx, qy, qex, qey, SCAN_COUNTER_CLOCKWISE, bdata, iw, ih); @@ -1896,6 +1974,26 @@ static int remove_pores_V2(MINUTIAE *minutiae, return(0); } +/************************************************************************* +************************************************************************** +#cat: remove_or_adjust_side_minutiae - Removes loops or minutia points that +#cat: are not on complete contours of specified length. If the +#cat: contour is complete, then the minutia is adjusted based +#cat: on a minmax analysis of the rotated y-coords of the contour. + + Input: + minutiae - list of true and false minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS + Output: + minutiae - list of pruned minutiae + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ + /************************************************************************* ************************************************************************** #cat: remove_or_adjust_side_minutiae_V2 - Removes loops or minutia points that @@ -1918,7 +2016,7 @@ static int remove_pores_V2(MINUTIAE *minutiae, Zero - successful completion Negative - system error **************************************************************************/ -static int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, +int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, unsigned char *bdata, const int iw, const int ih, int *direction_map, const int mw, const int mh, const LFSPARMS *lfsparms) @@ -2164,104 +2262,3 @@ static int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, return(0); } -/************************************************************************* -************************************************************************** -#cat: remove_false_minutia_V2 - Takes a list of true and false minutiae and -#cat: attempts to detect and remove the false minutiae based -#cat: on a series of tests. - - Input: - minutiae - list of true and false minutiae - bdata - binary image data (0==while & 1==black) - iw - width (in pixels) of image - ih - height (in pixels) of image - direction_map - map of image blocks containing directional ridge flow - low_flow_map - map of image blocks flagged as LOW RIDGE FLOW - high_curve_map - map of image blocks flagged as HIGH CURVATURE - mw - width in blocks of the maps - mh - height in blocks of the maps - lfsparms - parameters and thresholds for controlling LFS - Output: - minutiae - list of pruned minutiae - Return Code: - Zero - successful completion - Negative - system error -**************************************************************************/ -int remove_false_minutia_V2(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - int *direction_map, int *low_flow_map, int *high_curve_map, - const int mw, const int mh, const LFSPARMS *lfsparms) -{ - int ret; - - /* 1. Sort minutiae points top-to-bottom and left-to-right. */ - if((ret = sort_minutiae_y_x(minutiae, iw, ih))){ - return(ret); - } - - /* 2. Remove minutiae on lakes (filled with white pixels) and */ - /* islands (filled with black pixels), both defined by a pair of */ - /* minutia points. */ - if((ret = remove_islands_and_lakes(minutiae, bdata, iw, ih, lfsparms))){ - return(ret); - } - - /* 3. Remove minutiae on holes in the binary image defined by a */ - /* single point. */ - if((ret = remove_holes(minutiae, bdata, iw, ih, lfsparms))){ - return(ret); - } - - /* 4. Remove minutiae that point sufficiently close to a block with */ - /* INVALID direction. */ - if((ret = remove_pointing_invblock_V2(minutiae, direction_map, mw, mh, - lfsparms))){ - return(ret); - } - - /* 5. Remove minutiae that are sufficiently close to a block with */ - /* INVALID direction. */ - if((ret = remove_near_invblock_V2(minutiae, direction_map, mw, mh, - lfsparms))){ - return(ret); - } - - /* 6. Remove or adjust minutiae that reside on the side of a ridge */ - /* or valley. */ - if((ret = remove_or_adjust_side_minutiae_V2(minutiae, bdata, iw, ih, - direction_map, mw, mh, lfsparms))){ - return(ret); - } - - /* 7. Remove minutiae that form a hook on the side of a ridge or valley. */ - if((ret = remove_hooks(minutiae, bdata, iw, ih, lfsparms))){ - return(ret); - } - - /* 8. Remove minutiae that are on opposite sides of an overlap. */ - if((ret = remove_overlaps(minutiae, bdata, iw, ih, lfsparms))){ - return(ret); - } - - /* 9. Remove minutiae that are "irregularly" shaped. */ - if((ret = remove_malformations(minutiae, bdata, iw, ih, - low_flow_map, mw, mh, lfsparms))){ - return(ret); - } - - /* 10. Remove minutiae that form long, narrow, loops in the */ - /* "unreliable" regions in the binary image. */ - if((ret = remove_pores_V2(minutiae, bdata, iw, ih, - direction_map, low_flow_map, high_curve_map, - mw, mh, lfsparms))){ - return(ret); - } - - /* 11. Remove minutiae on image edge */ - if((ret = remove_perimeter_pts(minutiae, bdata, iw, ih, lfsparms))) { - return (ret); - } - - return(0); -} - diff --git a/libfprint/nbis/mindtct/ridges.c b/libfprint/nbis/mindtct/ridges.c index 9fb110f2..8f69fb24 100644 --- a/libfprint/nbis/mindtct/ridges.c +++ b/libfprint/nbis/mindtct/ridges.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -52,156 +73,137 @@ identified are necessarily the best available for the purpose. /************************************************************************* ************************************************************************** -#cat: insert_neighbor - Takes a minutia index and its squared distance to a -#cat: primary minutia point, and inserts them in the specified -#cat: position of their respective lists, shifting previously -#cat: stored values down and off the lists as necessary. +#cat: count_minutiae_ridges - Takes a list of minutiae, and for each one, +#cat: determines its closest neighbors and counts the number +#cat: of interveining ridges between the minutia point and +#cat: each of its neighbors. Input: - pos - postions where values are to be inserted in lists - nbr_index - index of minutia being inserted - nbr_dist2 - squared distance of minutia to its primary point - nbr_list - current list of nearest neighbor minutia indices - nbr_sqr_dists - corresponding squared euclidean distance of each - neighbor to the primary minutia point - nnbrs - number of neighbors currently in the list - max_nbrs - maximum number of closest neighbors to be returned + minutiae - list of minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS Output: - nbr_list - updated list of nearest neighbor indices - nbr_sqr_dists - updated list of nearest neighbor distances - nnbrs - number of neighbors in the update lists + minutiae - list of minutiae augmented with neighbors and ridge counts Return Code: - Zero - successful completion - Negative - system error + Zero - successful completion + Negative - system error **************************************************************************/ -static int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2, - int *nbr_list, double *nbr_sqr_dists, - int *nnbrs, const int max_nbrs) +int count_minutiae_ridges(MINUTIAE *minutiae, + unsigned char *bdata, const int iw, const int ih, + const LFSPARMS *lfsparms) { + int ret; int i; - /* If the desired insertion position is beyond one passed the last */ - /* neighbor in the lists OR greater than equal to the maximum ... */ - /* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */ - if((pos > *nnbrs) || - (pos >= max_nbrs)){ - fprintf(stderr, - "ERROR : insert_neighbor : insertion point exceeds lists\n"); - return(-480); + print2log("\nFINDING NBRS AND COUNTING RIDGES:\n"); + + /* Sort minutia points on x then y (column-oriented). */ + if((ret = sort_minutiae_x_y(minutiae, iw, ih))){ + return(ret); } - /* If the neighbor lists are NOT full ... */ - if(*nnbrs < max_nbrs){ - /* Then we have room to shift everything down to make room for new */ - /* neighbor and increase the number of neighbors stored by 1. */ - i = *nnbrs-1; - (*nnbrs)++; - } - /* Otherwise, the neighbors lists are full ... */ - else if(*nnbrs == max_nbrs) - /* So, we must bump the last neighbor in the lists off to make */ - /* room for the new neighbor (ignore last neighbor in lists). */ - i = *nnbrs-2; - /* Otherwise, there is a list overflow error condition */ - /* (shouldn't ever happen, but just in case) ... */ - else{ - fprintf(stderr, - "ERROR : insert_neighbor : overflow in neighbor lists\n"); - return(-481); + /* Remove any duplicate minutia points from the list. */ + if((ret = rm_dup_minutiae(minutiae))){ + return(ret); } - /* While we havn't reached the desired insertion point ... */ - while(i >= pos){ - /* Shift the current neighbor down the list 1 positon. */ - nbr_list[i+1] = nbr_list[i]; - nbr_sqr_dists[i+1] = nbr_sqr_dists[i]; - i--; + /* Foreach remaining sorted minutia in list ... */ + for(i = 0; i < minutiae->num-1; i++){ + /* Located neighbors and count number of ridges in between. */ + /* NOTE: neighbor and ridge count results are stored in */ + /* minutiae->list[i]. */ + if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){ + return(ret); + } } - /* We are now ready to put our new neighbor in the position where */ - /* we shifted everything down from to make room. */ - nbr_list[pos] = nbr_index; - nbr_sqr_dists[pos] = nbr_dist2; - /* Return normally. */ return(0); } /************************************************************************* ************************************************************************** -#cat: update_nbr_dists - Takes the current list of neighbors along with a -#cat: primary minutia and a potential new neighbor, and -#cat: determines if the new neighbor is sufficiently close -#cat: to be added to the list of nearest neighbors. If added, -#cat: it is placed in the list in its proper order based on -#cat: squared distance to the primary point. +#cat: count_minutia_ridges - Takes a minutia, and determines its closest +#cat: neighbors and counts the number of interveining ridges +#cat: between the minutia point and each of its neighbors. Input: - nbr_list - current list of nearest neighbor minutia indices - nbr_sqr_dists - corresponding squared euclidean distance of each - neighbor to the primary minutia point - nnbrs - number of neighbors currently in the list - max_nbrs - maximum number of closest neighbors to be returned - first - index of the primary minutia point - second - index of the secondary (new neighbor) point - minutiae - list of minutiae + minutia - input minutia + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS Output: - nbr_list - updated list of nearest neighbor indices - nbr_sqr_dists - updated list of nearest neighbor distances - nnbrs - number of neighbors in the update lists + minutiae - minutia augmented with neighbors and ridge counts Return Code: - Zero - successful completion - Negative - system error + Zero - successful completion + Negative - system error **************************************************************************/ -static int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists, - int *nnbrs, const int max_nbrs, - const int first, const int second, MINUTIAE *minutiae) +int count_minutia_ridges(const int first, MINUTIAE *minutiae, + unsigned char *bdata, const int iw, const int ih, + const LFSPARMS *lfsparms) { - double dist2; - MINUTIA *minutia1, *minutia2; - int pos, last_nbr; + int i, ret, *nbr_list, *nbr_nridges, nnbrs; - /* Compute position of maximum last neighbor stored. */ - last_nbr = max_nbrs - 1; + /* Find up to the maximum number of qualifying neighbors. */ + nbr_list = NULL; + if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs, + first, minutiae))){ + if (nbr_list != NULL) + free(nbr_list); + return(ret); + } - /* Assigne temporary minutia pointers. */ - minutia1 = minutiae->list[first]; - minutia2 = minutiae->list[second]; + print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x, + minutiae->list[first]->y, nnbrs); - /* Compute squared euclidean distance between minutia pair. */ - dist2 = squared_distance(minutia1->x, minutia1->y, - minutia2->x, minutia2->y); - - /* If maximum number of neighbors not yet stored in lists OR */ - /* if the squared distance to current secondary is less */ - /* than the largest stored neighbor distance ... */ - if((*nnbrs < max_nbrs) || - (dist2 < nbr_sqr_dists[last_nbr])){ - - /* Find insertion point in neighbor lists. */ - pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs); - /* If the position returned is >= maximum list length (this should */ - /* never happen, but just in case) ... */ - if(pos >= max_nbrs){ - fprintf(stderr, - "ERROR : update_nbr_dists : illegal position for new neighbor\n"); - return(-470); - } - /* Insert the new neighbor into the neighbor lists at the */ - /* specified location. */ - if(insert_neighbor(pos, second, dist2, - nbr_list, nbr_sqr_dists, nnbrs, max_nbrs)) - return(-471); - - /* Otherwise, neighbor inserted successfully, so return normally. */ + /* If no neighors found ... */ + if(nnbrs == 0){ + /* Then no list returned and no ridges to count. */ return(0); } - /* Otherwise, the new neighbor is not sufficiently close to be */ - /* added or inserted into the neighbor lists, so ignore the neighbor */ - /* and return normally. */ - else - return(0); + /* Sort neighbors on delta dirs. */ + if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){ + free(nbr_list); + return(ret); + } + + /* Count ridges between first and neighbors. */ + /* List of ridge counts, one for each neighbor stored. */ + nbr_nridges = (int *)malloc(nnbrs * sizeof(int)); + if(nbr_nridges == (int *)NULL){ + free(nbr_list); + fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n"); + return(-450); + } + + /* Foreach neighbor found and sorted in list ... */ + for(i = 0; i < nnbrs; i++){ + /* Count the ridges between the primary minutia and the neighbor. */ + ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms); + /* If system error ... */ + if(ret < 0){ + /* Deallocate working memories. */ + free(nbr_list); + free(nbr_nridges); + /* Return error code. */ + return(ret); + } + + /* Otherwise, ridge count successful, so store ridge count to list. */ + nbr_nridges[i] = ret; + } + + /* Assign neighbor indices and ridge counts to primary minutia. */ + minutiae->list[first]->nbrs = nbr_list; + minutiae->list[first]->ridge_counts = nbr_nridges; + minutiae->list[first]->num_nbrs = nnbrs; + + /* Return normally. */ + return(0); } /************************************************************************* @@ -224,7 +226,7 @@ static int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists, Zero - successful completion Negative - system error **************************************************************************/ -static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, +int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, const int first, MINUTIAE *minutiae) { int ret, second, last_nbr; @@ -279,6 +281,7 @@ static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs, first, second, minutiae))){ free(nbr_sqr_dists); + free(nbr_list); return(ret); } } @@ -312,6 +315,160 @@ static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, return(0); } +/************************************************************************* +************************************************************************** +#cat: update_nbr_dists - Takes the current list of neighbors along with a +#cat: primary minutia and a potential new neighbor, and +#cat: determines if the new neighbor is sufficiently close +#cat: to be added to the list of nearest neighbors. If added, +#cat: it is placed in the list in its proper order based on +#cat: squared distance to the primary point. + + Input: + nbr_list - current list of nearest neighbor minutia indices + nbr_sqr_dists - corresponding squared euclidean distance of each + neighbor to the primary minutia point + nnbrs - number of neighbors currently in the list + max_nbrs - maximum number of closest neighbors to be returned + first - index of the primary minutia point + second - index of the secondary (new neighbor) point + minutiae - list of minutiae + Output: + nbr_list - updated list of nearest neighbor indices + nbr_sqr_dists - updated list of nearest neighbor distances + nnbrs - number of neighbors in the update lists + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ +int update_nbr_dists(int *nbr_list, double *nbr_sqr_dists, + int *nnbrs, const int max_nbrs, + const int first, const int second, MINUTIAE *minutiae) +{ + double dist2; + MINUTIA *minutia1, *minutia2; + int pos, last_nbr; + + /* Compute position of maximum last neighbor stored. */ + last_nbr = max_nbrs - 1; + + /* Assigne temporary minutia pointers. */ + minutia1 = minutiae->list[first]; + minutia2 = minutiae->list[second]; + + /* Compute squared euclidean distance between minutia pair. */ + dist2 = squared_distance(minutia1->x, minutia1->y, + minutia2->x, minutia2->y); + + /* If maximum number of neighbors not yet stored in lists OR */ + /* if the squared distance to current secondary is less */ + /* than the largest stored neighbor distance ... */ + if((*nnbrs < max_nbrs) || + (dist2 < nbr_sqr_dists[last_nbr])){ + + /* Find insertion point in neighbor lists. */ + pos = find_incr_position_dbl(dist2, nbr_sqr_dists, *nnbrs); + /* If the position returned is >= maximum list length (this should */ + /* never happen, but just in case) ... */ + if(pos >= max_nbrs){ + fprintf(stderr, + "ERROR : update_nbr_dists : illegal position for new neighbor\n"); + return(-470); + } + /* Insert the new neighbor into the neighbor lists at the */ + /* specified location. */ + if(insert_neighbor(pos, second, dist2, + nbr_list, nbr_sqr_dists, nnbrs, max_nbrs)) + return(-471); + + /* Otherwise, neighbor inserted successfully, so return normally. */ + return(0); + } + /* Otherwise, the new neighbor is not sufficiently close to be */ + /* added or inserted into the neighbor lists, so ignore the neighbor */ + /* and return normally. */ + else + return(0); + +} + +/************************************************************************* +************************************************************************** +#cat: insert_neighbor - Takes a minutia index and its squared distance to a +#cat: primary minutia point, and inserts them in the specified +#cat: position of their respective lists, shifting previously +#cat: stored values down and off the lists as necessary. + + Input: + pos - postions where values are to be inserted in lists + nbr_index - index of minutia being inserted + nbr_dist2 - squared distance of minutia to its primary point + nbr_list - current list of nearest neighbor minutia indices + nbr_sqr_dists - corresponding squared euclidean distance of each + neighbor to the primary minutia point + nnbrs - number of neighbors currently in the list + max_nbrs - maximum number of closest neighbors to be returned + Output: + nbr_list - updated list of nearest neighbor indices + nbr_sqr_dists - updated list of nearest neighbor distances + nnbrs - number of neighbors in the update lists + Return Code: + Zero - successful completion + Negative - system error +**************************************************************************/ +int insert_neighbor(const int pos, const int nbr_index, const double nbr_dist2, + int *nbr_list, double *nbr_sqr_dists, + int *nnbrs, const int max_nbrs) +{ + int i; + + /* If the desired insertion position is beyond one passed the last */ + /* neighbor in the lists OR greater than equal to the maximum ... */ + /* NOTE: pos is zero-oriented while nnbrs and max_nbrs are 1-oriented. */ + if((pos > *nnbrs) || + (pos >= max_nbrs)){ + fprintf(stderr, + "ERROR : insert_neighbor : insertion point exceeds lists\n"); + return(-480); + } + + /* If the neighbor lists are NOT full ... */ + if(*nnbrs < max_nbrs){ + /* Then we have room to shift everything down to make room for new */ + /* neighbor and increase the number of neighbors stored by 1. */ + i = *nnbrs-1; + (*nnbrs)++; + } + /* Otherwise, the neighbors lists are full ... */ + else if(*nnbrs == max_nbrs) + /* So, we must bump the last neighbor in the lists off to make */ + /* room for the new neighbor (ignore last neighbor in lists). */ + i = *nnbrs-2; + /* Otherwise, there is a list overflow error condition */ + /* (shouldn't ever happen, but just in case) ... */ + else{ + fprintf(stderr, + "ERROR : insert_neighbor : overflow in neighbor lists\n"); + return(-481); + } + + /* While we havn't reached the desired insertion point ... */ + while(i >= pos){ + /* Shift the current neighbor down the list 1 positon. */ + nbr_list[i+1] = nbr_list[i]; + nbr_sqr_dists[i+1] = nbr_sqr_dists[i]; + i--; + } + + /* We are now ready to put our new neighbor in the position where */ + /* we shifted everything down from to make room. */ + nbr_list[pos] = nbr_index; + nbr_sqr_dists[pos] = nbr_dist2; + + /* Return normally. */ + return(0); +} + /************************************************************************* ************************************************************************** #cat: sort_neighbors - Takes a list of primary minutia and its neighboring @@ -331,7 +488,7 @@ static int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, Zero - successful completion Negative - system error **************************************************************************/ -static int sort_neighbors(int *nbr_list, const int nnbrs, const int first, +int sort_neighbors(int *nbr_list, const int nnbrs, const int first, MINUTIAE *minutiae) { double *join_thetas, theta; @@ -369,7 +526,164 @@ static int sort_neighbors(int *nbr_list, const int nnbrs, const int first, free(join_thetas); /* Return normally. */ - return(0); + return(0); +} + +/************************************************************************* +************************************************************************** +#cat: ridge_count - Takes a pair of minutiae, and counts the number of +#cat: ridges crossed along the linear trajectory connecting +#cat: the 2 points in the image. + + Input: + first - index of primary minutia + second - index of secondary (neighbor) minutia + minutiae - list of minutiae + bdata - binary image data (0==while & 1==black) + iw - width (in pixels) of image + ih - height (in pixels) of image + lfsparms - parameters and thresholds for controlling LFS + Return Code: + Zero or Positive - number of ridges counted + Negative - system error +**************************************************************************/ +int ridge_count(const int first, const int second, MINUTIAE *minutiae, + unsigned char *bdata, const int iw, const int ih, + const LFSPARMS *lfsparms) +{ + MINUTIA *minutia1, *minutia2; + int i, ret, found; + int *xlist, *ylist, num; + int ridge_count, ridge_start, ridge_end; + int prevpix, curpix; + + minutia1 = minutiae->list[first]; + minutia2 = minutiae->list[second]; + + /* If the 2 mintuia have identical pixel coords ... */ + if((minutia1->x == minutia2->x) && + (minutia1->y == minutia2->y)) + /* Then zero ridges between points. */ + return(0); + + /* Compute linear trajectory of contiguous pixels between first */ + /* and second minutia points. */ + if((ret = line_points(&xlist, &ylist, &num, + minutia1->x, minutia1->y, minutia2->x, minutia2->y))){ + return(ret); + } + + /* It there are no points on the line trajectory, then no ridges */ + /* to count (this should not happen, but just in case) ... */ + if(num == 0){ + free(xlist); + free(ylist); + return(0); + } + + /* Find first pixel opposite type along linear trajectory from */ + /* first minutia. */ + prevpix = *(bdata+(ylist[0]*iw)+xlist[0]); + i = 1; + found = FALSE; + while(i < num){ + curpix = *(bdata+(ylist[i]*iw)+xlist[i]); + if(curpix != prevpix){ + found = TRUE; + break; + } + i++; + } + + /* If opposite pixel not found ... then no ridges to count */ + if(!found){ + free(xlist); + free(ylist); + return(0); + } + + /* Ready to count ridges, so initialize counter to 0. */ + ridge_count = 0; + + print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y, + minutia2->x, minutia2->y); + + /* While not at the end of the trajectory ... */ + while(i < num){ + /* If 0-to-1 transition not found ... */ + if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){ + /* Then we are done looking for ridges. */ + free(xlist); + free(ylist); + + print2log("\n"); + + /* Return number of ridges counted to this point. */ + return(ridge_count); + } + /* Otherwise, we found a new ridge start transition, so store */ + /* its location (the location of the 1 in 0-to-1 transition). */ + ridge_start = i; + + print2log(": RS %d,%d ", xlist[i], ylist[i]); + + /* If 1-to-0 transition not found ... */ + if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){ + /* Then we are done looking for ridges. */ + free(xlist); + free(ylist); + + print2log("\n"); + + /* Return number of ridges counted to this point. */ + return(ridge_count); + } + /* Otherwise, we found a new ridge end transition, so store */ + /* its location (the location of the 0 in 1-to-0 transition). */ + ridge_end = i; + + print2log("; RE %d,%d ", xlist[i], ylist[i]); + + /* Conduct the validation, tracing the contour of the ridge */ + /* from the ridge ending point a specified number of steps */ + /* scanning for neighbors clockwise and counter-clockwise. */ + /* If the ridge starting point is encounted during the trace */ + /* then we can assume we do not have a valid ridge crossing */ + /* and instead we are walking on and off the edge of the */ + /* side of a ridge. */ + ret = validate_ridge_crossing(ridge_start, ridge_end, + xlist, ylist, num, bdata, iw, ih, + lfsparms->max_ridge_steps); + + /* If system error ... */ + if(ret < 0){ + free(xlist); + free(ylist); + /* Return the error code. */ + return(ret); + } + + print2log("; V%d ", ret); + + /* If validation result is TRUE ... */ + if(ret){ + /* Then assume we have found a valid ridge crossing and bump */ + /* the ridge counter. */ + ridge_count++; + } + + /* Otherwise, ignore the current ridge start and end transitions */ + /* and go back and search for new ridge start. */ + } + + /* Deallocate working memories. */ + free(xlist); + free(ylist); + + print2log("\n"); + + /* Return the number of ridges counted. */ + return(ridge_count); } /************************************************************************* @@ -395,7 +709,7 @@ static int sort_neighbors(int *nbr_list, const int nnbrs, const int first, TRUE - pixel pair transition found FALSE - pixel pair transition not found **************************************************************************/ -static int find_transition(int *iptr, const int pix1, const int pix2, +int find_transition(int *iptr, const int pix1, const int pix2, const int *xlist, const int *ylist, const int num, unsigned char *bdata, const int iw, const int ih) { @@ -456,7 +770,7 @@ static int find_transition(int *iptr, const int pix1, const int pix2, FALSE - ridge corssing INVALID Negative - system error **************************************************************************/ -static int validate_ridge_crossing(const int ridge_start, const int ridge_end, +int validate_ridge_crossing(const int ridge_start, const int ridge_end, const int *xlist, const int *ylist, const int num, unsigned char *bdata, const int iw, const int ih, const int max_ridge_steps) @@ -482,7 +796,7 @@ static int validate_ridge_crossing(const int ridge_start, const int ridge_end, /* position is on the white (of a black to white transition) and */ /* the ridge start is on the black (of a black to white trans), */ /* so the edge trace needs to look for the what pixel (not the */ - /* black one) of the ridge start transition. */ + /* black one) of the ridge start transition. */ ret = trace_contour(&contour_x, &contour_y, &contour_ex, &contour_ey, &ncontour, max_ridge_steps, @@ -535,298 +849,7 @@ static int validate_ridge_crossing(const int ridge_start, const int ridge_end, /* Otherwise, second trace returned IGNORE or ridge start found. */ } /* Otherwise, first trace returned IGNORE or ridge start found. */ - + /* If we get here, then we failed to validate a ridge crossing. */ return(FALSE); } - -/************************************************************************* -************************************************************************** -#cat: ridge_count - Takes a pair of minutiae, and counts the number of -#cat: ridges crossed along the linear trajectory connecting -#cat: the 2 points in the image. - - Input: - first - index of primary minutia - second - index of secondary (neighbor) minutia - minutiae - list of minutiae - bdata - binary image data (0==while & 1==black) - iw - width (in pixels) of image - ih - height (in pixels) of image - lfsparms - parameters and thresholds for controlling LFS - Return Code: - Zero or Positive - number of ridges counted - Negative - system error -**************************************************************************/ -static int ridge_count(const int first, const int second, MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const LFSPARMS *lfsparms) -{ - MINUTIA *minutia1, *minutia2; - int i, ret, found; - int *xlist, *ylist, num; - int ridge_cnt, ridge_start, ridge_end; - int prevpix, curpix; - - minutia1 = minutiae->list[first]; - minutia2 = minutiae->list[second]; - - /* If the 2 mintuia have identical pixel coords ... */ - if((minutia1->x == minutia2->x) && - (minutia1->y == minutia2->y)) - /* Then zero ridges between points. */ - return(0); - - /* Compute linear trajectory of contiguous pixels between first */ - /* and second minutia points. */ - if((ret = line_points(&xlist, &ylist, &num, - minutia1->x, minutia1->y, minutia2->x, minutia2->y))){ - return(ret); - } - - /* It there are no points on the line trajectory, then no ridges */ - /* to count (this should not happen, but just in case) ... */ - if(num == 0){ - free(xlist); - free(ylist); - return(0); - } - - /* Find first pixel opposite type along linear trajectory from */ - /* first minutia. */ - prevpix = *(bdata+(ylist[0]*iw)+xlist[0]); - i = 1; - found = FALSE; - while(i < num){ - curpix = *(bdata+(ylist[i]*iw)+xlist[i]); - if(curpix != prevpix){ - found = TRUE; - break; - } - i++; - } - - /* If opposite pixel not found ... then no ridges to count */ - if(!found){ - free(xlist); - free(ylist); - return(0); - } - - /* Ready to count ridges, so initialize counter to 0. */ - ridge_cnt = 0; - - print2log("RIDGE COUNT: %d,%d to %d,%d ", minutia1->x, minutia1->y, - minutia2->x, minutia2->y); - - /* While not at the end of the trajectory ... */ - while(i < num){ - /* If 0-to-1 transition not found ... */ - if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){ - /* Then we are done looking for ridges. */ - free(xlist); - free(ylist); - - print2log("\n"); - - /* Return number of ridges counted to this point. */ - return(ridge_cnt); - } - /* Otherwise, we found a new ridge start transition, so store */ - /* its location (the location of the 1 in 0-to-1 transition). */ - ridge_start = i; - - print2log(": RS %d,%d ", xlist[i], ylist[i]); - - /* If 1-to-0 transition not found ... */ - if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){ - /* Then we are done looking for ridges. */ - free(xlist); - free(ylist); - - print2log("\n"); - - /* Return number of ridges counted to this point. */ - return(ridge_cnt); - } - /* Otherwise, we found a new ridge end transition, so store */ - /* its location (the location of the 0 in 1-to-0 transition). */ - ridge_end = i; - - print2log("; RE %d,%d ", xlist[i], ylist[i]); - - /* Conduct the validation, tracing the contour of the ridge */ - /* from the ridge ending point a specified number of steps */ - /* scanning for neighbors clockwise and counter-clockwise. */ - /* If the ridge starting point is encounted during the trace */ - /* then we can assume we do not have a valid ridge crossing */ - /* and instead we are walking on and off the edge of the */ - /* side of a ridge. */ - ret = validate_ridge_crossing(ridge_start, ridge_end, - xlist, ylist, num, bdata, iw, ih, - lfsparms->max_ridge_steps); - - /* If system error ... */ - if(ret < 0){ - free(xlist); - free(ylist); - /* Return the error code. */ - return(ret); - } - - print2log("; V%d ", ret); - - /* If validation result is TRUE ... */ - if(ret){ - /* Then assume we have found a valid ridge crossing and bump */ - /* the ridge counter. */ - ridge_cnt++; - } - - /* Otherwise, ignore the current ridge start and end transitions */ - /* and go back and search for new ridge start. */ - } - - /* Deallocate working memories. */ - free(xlist); - free(ylist); - - print2log("\n"); - - /* Return the number of ridges counted. */ - return(ridge_cnt); -} - -/************************************************************************* -************************************************************************** -#cat: count_minutia_ridges - Takes a minutia, and determines its closest -#cat: neighbors and counts the number of interveining ridges -#cat: between the minutia point and each of its neighbors. - - Input: - minutia - input minutia - bdata - binary image data (0==while & 1==black) - iw - width (in pixels) of image - ih - height (in pixels) of image - lfsparms - parameters and thresholds for controlling LFS - Output: - minutiae - minutia augmented with neighbors and ridge counts - Return Code: - Zero - successful completion - Negative - system error -**************************************************************************/ -static int count_minutia_ridges(const int first, MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const LFSPARMS *lfsparms) -{ - int i, ret, *nbr_list = NULL, *nbr_nridges, nnbrs; - - /* Find up to the maximum number of qualifying neighbors. */ - if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs, - first, minutiae))){ - free(nbr_list); - return(ret); - } - - print2log("NBRS FOUND: %d,%d = %d\n", minutiae->list[first]->x, - minutiae->list[first]->y, nnbrs); - - /* If no neighors found ... */ - if(nnbrs == 0){ - /* Then no list returned and no ridges to count. */ - return(0); - } - - /* Sort neighbors on delta dirs. */ - if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){ - free(nbr_list); - return(ret); - } - - /* Count ridges between first and neighbors. */ - /* List of ridge counts, one for each neighbor stored. */ - nbr_nridges = (int *)malloc(nnbrs * sizeof(int)); - if(nbr_nridges == (int *)NULL){ - free(nbr_list); - fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n"); - return(-450); - } - - /* Foreach neighbor found and sorted in list ... */ - for(i = 0; i < nnbrs; i++){ - /* Count the ridges between the primary minutia and the neighbor. */ - ret = ridge_count(first, nbr_list[i], minutiae, bdata, iw, ih, lfsparms); - /* If system error ... */ - if(ret < 0){ - /* Deallocate working memories. */ - free(nbr_list); - free(nbr_nridges); - /* Return error code. */ - return(ret); - } - - /* Otherwise, ridge count successful, so store ridge count to list. */ - nbr_nridges[i] = ret; - } - - /* Assign neighbor indices and ridge counts to primary minutia. */ - minutiae->list[first]->nbrs = nbr_list; - minutiae->list[first]->ridge_counts = nbr_nridges; - minutiae->list[first]->num_nbrs = nnbrs; - - /* Return normally. */ - return(0); -} - -/************************************************************************* -************************************************************************** -#cat: count_minutiae_ridges - Takes a list of minutiae, and for each one, -#cat: determines its closest neighbors and counts the number -#cat: of interveining ridges between the minutia point and -#cat: each of its neighbors. - - Input: - minutiae - list of minutiae - bdata - binary image data (0==while & 1==black) - iw - width (in pixels) of image - ih - height (in pixels) of image - lfsparms - parameters and thresholds for controlling LFS - Output: - minutiae - list of minutiae augmented with neighbors and ridge counts - Return Code: - Zero - successful completion - Negative - system error -**************************************************************************/ -int count_minutiae_ridges(MINUTIAE *minutiae, - unsigned char *bdata, const int iw, const int ih, - const LFSPARMS *lfsparms) -{ - int ret; - int i; - - print2log("\nFINDING NBRS AND COUNTING RIDGES:\n"); - - /* Sort minutia points on x then y (column-oriented). */ - if((ret = sort_minutiae_x_y(minutiae, iw, ih))){ - return(ret); - } - - /* Remove any duplicate minutia points from the list. */ - if((ret = rm_dup_minutiae(minutiae))){ - return(ret); - } - - /* Foreach remaining sorted minutia in list ... */ - for(i = 0; i < minutiae->num-1; i++){ - /* Located neighbors and count number of ridges in between. */ - /* NOTE: neighbor and ridge count results are stored in */ - /* minutiae->list[i]. */ - if((ret = count_minutia_ridges(i, minutiae, bdata, iw, ih, lfsparms))){ - return(ret); - } - } - - /* Return normally. */ - return(0); -} - diff --git a/libfprint/nbis/mindtct/shape.c b/libfprint/nbis/mindtct/shape.c index 4e8ea8fd..5f9e7bcb 100644 --- a/libfprint/nbis/mindtct/shape.c +++ b/libfprint/nbis/mindtct/shape.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -36,12 +57,12 @@ identified are necessarily the best available for the purpose. ROUTINES: alloc_shape() free_shape() + dump_shape() shape_from_contour() sort_row_on_x() ***********************************************************************/ #include -#include #include /************************************************************************* @@ -60,7 +81,7 @@ identified are necessarily the best available for the purpose. Zero - Shape successfully allocated and initialized Negative - System error **************************************************************************/ -static int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, +int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, const int xmax, const int ymax) { SHAPE *shape; @@ -180,21 +201,14 @@ void free_shape(SHAPE *shape) /************************************************************************* ************************************************************************** -#cat: sort_row_on_x - Takes a row structure and sorts its points left-to- -#cat: right on X. +#cat: dump_shape - Takes an initialized shape structure and dumps its contents +#cat: as formatted text to the specified open file pointer. Input: - row - row structure to be sorted + shape - shape structure to be dumped Output: - row - row structure with points in sorted order + fpout - open file pointer to be written to **************************************************************************/ -static void sort_row_on_x(ROW *row) -{ - /* Conduct a simple increasing bubble sort on the x-coords */ - /* in the given row. A bubble sort is satisfactory as the */ - /* number of points will be relatively small. */ - bubble_sort_int_inc(row->xs, row->npts); -} /************************************************************************* ************************************************************************** @@ -246,6 +260,7 @@ int shape_from_contour(SHAPE **oshape, const int *contour_x, if(row->npts >= row->alloc){ /* This should never happen becuase we have allocated */ /* based on shape bounding limits. */ + free(shape); fprintf(stderr, "ERROR : shape_from_contour : row overflow\n"); return(-260); @@ -270,3 +285,21 @@ int shape_from_contour(SHAPE **oshape, const int *contour_x, return(0); } +/************************************************************************* +************************************************************************** +#cat: sort_row_on_x - Takes a row structure and sorts its points left-to- +#cat: right on X. + + Input: + row - row structure to be sorted + Output: + row - row structure with points in sorted order +**************************************************************************/ +void sort_row_on_x(ROW *row) +{ + /* Conduct a simple increasing bubble sort on the x-coords */ + /* in the given row. A bubble sort is satisfactory as the */ + /* number of points will be relatively small. */ + bubble_sort_int_inc(row->xs, row->npts); +} + diff --git a/libfprint/nbis/mindtct/sort.c b/libfprint/nbis/mindtct/sort.c index 3a0f47c9..9080ce0d 100644 --- a/libfprint/nbis/mindtct/sort.c +++ b/libfprint/nbis/mindtct/sort.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -43,7 +64,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* @@ -104,29 +124,6 @@ int sort_indices_int_inc(int **optr, int *ranks, const int num) Zero - successful completion Negative - system error **************************************************************************/ -int sort_indices_double_inc(int **optr, double *ranks, const int num) -{ - int *order; - int i; - - /* Allocate list of sequential indices. */ - order = (int *)malloc(num * sizeof(int)); - if(order == (int *)NULL){ - fprintf(stderr, "ERROR : sort_indices_double_inc : malloc : order\n"); - return(-400); - } - /* Initialize list of sequential indices. */ - for(i = 0; i < num; i++) - order[i] = i; - - /* Sort the indicies into rank order. */ - bubble_sort_double_inc_2(ranks, order, num); - - /* Set output pointer to the resulting order of sorted indices. */ - *optr = order; - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -176,7 +173,7 @@ void bubble_sort_int_inc_2(int *ranks, int *items, const int len) } /* Decrement the ending index. */ n--; - } + } } /************************************************************************* @@ -228,7 +225,7 @@ void bubble_sort_double_inc_2(double *ranks, int *items, const int len) } /* Decrement the ending index. */ n--; - } + } } /*************************************************************************** @@ -271,7 +268,7 @@ void bubble_sort_double_dec_2(double *ranks, int *items, const int len) } } n--; - } + } } /************************************************************************* @@ -315,6 +312,6 @@ void bubble_sort_int_inc(int *ranks, const int len) } /* Decrement the ending index. */ n--; - } + } } diff --git a/libfprint/nbis/mindtct/util.c b/libfprint/nbis/mindtct/util.c index a4e98da9..1662e629 100644 --- a/libfprint/nbis/mindtct/util.c +++ b/libfprint/nbis/mindtct/util.c @@ -1,26 +1,47 @@ /******************************************************************************* -License: -This software was developed at the National Institute of Standards and -Technology (NIST) by employees of the Federal Government in the course -of their official duties. Pursuant to title 17 Section 105 of the -United States Code, this software is not subject to copyright protection -and is in the public domain. NIST assumes no responsibility whatsoever for -its use by other parties, and makes no guarantees, expressed or implied, -about its quality, reliability, or any other characteristic. +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. -Disclaimer: -This software was developed to promote biometric standards and biometric -technology testing for the Federal Government in accordance with the USA -PATRIOT Act and the Enhanced Border Security and Visa Entry Reform Act. -Specific hardware and software products identified in this software were used -in order to perform the software development. In no case does such -identification imply recommendation or endorsement by the National Institute -of Standards and Technology, nor does it imply that the products and equipment -identified are necessarily the best available for the purpose. +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. *******************************************************************************/ + /*********************************************************************** LIBRARY: LFS - NIST Latent Fingerprint System @@ -47,7 +68,6 @@ identified are necessarily the best available for the purpose. ***********************************************************************/ #include -#include #include /************************************************************************* @@ -142,7 +162,7 @@ int minmaxs(int **ominmax_val, int **ominmax_type, int **ominmax_i, int i, diff, state, start, loc; int *minmax_val, *minmax_type, *minmax_i, minmax_alloc, minmax_num; - + /* Determine maximum length for allocation of buffers. */ /* If there are fewer than 3 items ... */ if(num < 3){ @@ -427,27 +447,6 @@ int in_int_list(const int item, const int *list, const int len) Zero - successful completion Negative - system error **************************************************************************/ -int remove_from_int_list(const int index, int *list, const int num) -{ - int fr, to; - - /* Make sure the requested index is within range. */ - if((index < 0) && (index >= num)){ - fprintf(stderr, "ERROR : remove_from_int_list : index out of range\n"); - return(-370); - } - - /* Slide the remaining list of integers up over top of the */ - /* position of the integer being removed. */ - for(to = index, fr = index+1; fr < num; to++, fr++) - list[to] = list[fr]; - - /* NOTE: Decrementing the number of integers remaining in the list is */ - /* the responsibility of the caller! */ - - /* Return normally. */ - return(0); -} /************************************************************************* ************************************************************************** @@ -561,7 +560,7 @@ int line2direction(const int fx, const int fy, /* Make sure on range [0..(ndirsX2)]. */ idir %= full_ndirs; - /* Return the integer direction. */ + /* Return the integer direction. */ return(idir); } diff --git a/libfprint/nbis/mindtct/xytreps.c b/libfprint/nbis/mindtct/xytreps.c new file mode 100644 index 00000000..7310f98b --- /dev/null +++ b/libfprint/nbis/mindtct/xytreps.c @@ -0,0 +1,136 @@ +/******************************************************************************* + +License: +This software and/or related materials was developed at the National Institute +of Standards and Technology (NIST) by employees of the Federal Government +in the course of their official duties. Pursuant to title 17 Section 105 +of the United States Code, this software is not subject to copyright +protection and is in the public domain. + +This software and/or related materials have been determined to be not subject +to the EAR (see Part 734.3 of the EAR for exact details) because it is +a publicly available technology and software, and is freely distributed +to any interested party with no licensing requirements. Therefore, it is +permissible to distribute this software as a free download from the internet. + +Disclaimer: +This software and/or related materials was developed to promote biometric +standards and biometric technology testing for the Federal Government +in accordance with the USA PATRIOT Act and the Enhanced Border Security +and Visa Entry Reform Act. Specific hardware and software products identified +in this software were used in order to perform the software development. +In no case does such identification imply recommendation or endorsement +by the National Institute of Standards and Technology, nor does it imply that +the products and equipment identified are necessarily the best available +for the purpose. + +This software and/or related materials are provided "AS-IS" without warranty +of any kind including NO WARRANTY OF PERFORMANCE, MERCHANTABILITY, +NO WARRANTY OF NON-INFRINGEMENT OF ANY 3RD PARTY INTELLECTUAL PROPERTY +or FITNESS FOR A PARTICULAR PURPOSE or for any purpose whatsoever, for the +licensed product, however used. In no event shall NIST be liable for any +damages and/or costs, including but not limited to incidental or consequential +damages of any kind, including economic damage or injury to property and lost +profits, regardless of whether NIST shall be advised, have reason to know, +or in fact shall know of the possibility. + +By using this software, you agree to bear all risk relating to quality, +use and performance of the software and/or related materials. You agree +to hold the Government harmless from any claim arising from your use +of the software. + +*******************************************************************************/ + + +/*********************************************************************** + LIBRARY: LFS - NIST Latent Fingerprint System + + FILE: XYTREPS.C + AUTHOR: Michael D. Garris + DATE: 09/16/2004 + UPDATED: 01/11/2012 + + Contains routines useful in converting minutiae in LFS "native" + representation into other representations, such as + M1 (ANSI INCITS 378-2004) & NIST internal representations. + +*********************************************************************** + ROUTINES: + lfs2nist_minutia_XTY() + lfs2m1_minutia_XTY() + lfs2nist_format() + +***********************************************************************/ + +#include +#include + +/************************************************************************* +************************************************************************** +#cat: lfs2nist_minutia_XYT - Converts XYT minutiae attributes in LFS native +#cat: representation to NIST internal representation + + Input: + minutia - LFS minutia structure containing attributes to be converted + Output: + ox - NIST internal based x-pixel coordinate + oy - NIST internal based y-pixel coordinate + ot - NIST internal based minutia direction/orientation +**************************************************************************/ +void lfs2nist_minutia_XYT(int *ox, int *oy, int *ot, + const MINUTIA *minutia, const int iw, const int ih) +{ + int x, y, t; + float degrees_per_unit; + + /* XYT's according to NIST internal rep: */ + /* 1. pixel coordinates with origin bottom-left */ + /* 2. orientation in degrees on range [0..360] */ + /* with 0 pointing east and increasing counter */ + /* clockwise (same as M1) */ + /* 3. direction pointing out and away from the */ + /* ridge ending or bifurcation valley */ + /* (opposite direction from M1) */ + + x = minutia->x; + y = ih - minutia->y; + + degrees_per_unit = 180 / (float)NUM_DIRECTIONS; + + t = (270 - sround(minutia->direction * degrees_per_unit)) % 360; + if(t < 0){ + t += 360; + } + + *ox = x; + *oy = y; + *ot = t; +} + +/************************************************************************* +************************************************************************** +#cat: lfs2m1_minutia_XYT - Converts XYT minutiae attributes in LFS native +#cat: representation to M1 (ANSI INCITS 378-2004) representation + + Input: + minutia - LFS minutia structure containing attributes to be converted + Output: + ox - M1 based x-pixel coordinate + oy - M1 based y-pixel coordinate + ot - M1 based minutia direction/orientation +**************************************************************************/ + +/************************************************************************* +************************************************************************** +#cat: lfs2nist_format - Takes a minutiae data structure and converts +#cat: the XYT minutiae attributes in LFS native +#cat: representation to NIST internal representation + Input: + iminutiae - minutiae data structure + iw - width (in pixels) of the grayscale image + ih - height (in pixels) of the grayscale image + Output: + iminutiae - overwrite each minutia element in the minutiae data + sturcture convernt to nist internal minutiae format +**************************************************************************/ + diff --git a/libfprint/nbis/remove-function.lua b/libfprint/nbis/remove-function.lua new file mode 100755 index 00000000..408fb66b --- /dev/null +++ b/libfprint/nbis/remove-function.lua @@ -0,0 +1,82 @@ +#!/bin/lua + +function read_all(file) + local f = io.open(file, "r") + if not f then return nil end + local t = f:read("*all") + f:close() + return t +end + +function write_all(file, content) + local f = io.open(file, "w") + f:write(content) + f:close() +end + +-- From http://lua-users.org/wiki/SplitJoin +function split_lines(str) + local t = {} + local function helper(line) + table.insert(t, line) + return "" + end + helper((str:gsub("(.-)\r?\n", helper))) + return t +end + +function remove_func_content(func, content) + local lines = split_lines(content) + local res = {} + local in_func = false + local num_braces = 0 + local found_func = false + for k, v in ipairs(lines) do + if in_func == true then + local orig_braces = num_braces + local _, count = string.gsub(v, "{", "") + num_braces = num_braces + count + _, count = string.gsub(v, "}", "") + num_braces = num_braces - count + if orig_braces ~= 0 and num_braces == 0 then + print (func .. ' finished line '.. k) + in_func = false + end + elseif (v:match(' '..func..'%(%a+') or + v:match(' '..func..' %(%a+') or + v:match(' '..func..'%( %a+') or + v:match(' '..func..'%($')) and + not v:match('= '..func..'%(%a+') then + print (func .. ' started line ' .. k) + found_func = true + in_func = true + else + table.insert(res, v) + end + end + + if not found_func then + return nil + end + return table.concat(res, '\n') +end + +function remove_func_file(func, file) + content = read_all(file) + content = remove_func_content(func, content) + if not content then + error('Could not find function '..func..'() in '..file) + else + write_all(file, content) + end +end + +local func +for k, v in ipairs(arg) do + if k == 1 then + func = v + else + remove_func_file(func, v) + end +end + diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh new file mode 100755 index 00000000..bd3a59b9 --- /dev/null +++ b/libfprint/nbis/update-from-nbis.sh @@ -0,0 +1,181 @@ +#!/bin/sh -e + +help() +{ + echo "Usage:" + echo " `basename $0` [NBIS directory]" + exit +} + +replace_global() +{ + if [ ! -f "$2" ] ; then + FILES=`find -name *.[ch]` + else + FILES=$2 + fi + sed -i "s/$1/g_$1/" $FILES +} + +rename_variable() +{ + if [ ! -f "$3" ] ; then + FILES=`find -name *.[ch]` + else + FILES=$3 + fi + sed -i "s/$1/$2/" $FILES +} + +remove_function() +{ + if [ ! -f "$2" ] ; then + FILES=`find -name *.[ch]` + else + FILES=$2 + fi + ./remove-function.lua $1 $FILES +} + +if [ $# -ne 1 ] ; then echo "*** Wrong number of arguments ***" ; help ; fi +if [ ! -d $1 ] ; then echo "*** $1 not a directory ***" ; help ; fi + +DIR="$1" + +if [ ! -d $DIR/bozorth3 ] ; then echo "*** $DIR not an NBIS source directory ***" ; help ; fi +if [ ! -d $DIR/mindtct ] ; then echo "*** $DIR not an NBIS source directory ***" ; help ; fi + +# Update files +for i in bozorth3/*.c ; do + cp -a $DIR/bozorth3/src/lib/bozorth3/`basename $i` bozorth3/ + chmod 0644 bozorth3/`basename $i` +done + +for i in mindtct/*.c chaincod.c getmin.c link.c xytreps.c; do + cp -a $DIR/mindtct/src/lib/mindtct/`basename $i` mindtct/ + chmod 0644 mindtct/`basename $i` +done + +for i in include/*.h mytime.h ; do + FILE=`basename $i` + ORIG=`find $DIR -name $FILE | grep -v misc/ | grep -v exports/` + + cp -a -f $ORIG include/ + chmod 0644 include/$FILE +done + +# Replace global variables +replace_global dft_coefs include/lfs.h +replace_global dft_coefs mindtct/globals.c +replace_global dft_coefs mindtct/maps.c +replace_global dft_coefs mindtct/detect.c +# Also does lfsparms_V2 +replace_global lfsparms include/lfs.h +replace_global lfsparms mindtct/globals.c +replace_global nbr8_dx +replace_global nbr8_dy +replace_global chaincodes_nbr8 +replace_global feature_patterns +rename_variable errorfp stderr + +# Remove command-line options globals +for i in m1_xyt max_minutiae min_computable_minutiae verbose_bozorth verbose_main verbose_load; do + sed -i "/$i/d" include/bozorth.h +done +rename_variable max_minutiae DEFAULT_BOZORTH_MINUTIAE +rename_variable m1_xyt 0 +rename_variable min_computable_minutiae MIN_COMPUTABLE_BOZORTH_MINUTIAE +rename_variable verbose_bozorth 0 +rename_variable verbose_main 0 +rename_variable verbose_load 0 +# Remove logging globals +for i in logfp avrdir dir_strength nvalid ; do + sed -i "/$i/d" mindtct/log.c + sed -i "/$i/d" include/log.h +done +# Remove an unused static variable +sed -i "/stack_pointer = stack/d" bozorth3/bz_sort.c +sed -i "/stack\[BZ_STACKSIZE\]/d" bozorth3/bz_sort.c + +# +extern int verbose_load; +# extern int verbose_threshold; +# +/* Global supporting error reporting */ +# +extern FILE *stderr; + +# Remove unused functions +patch -p0 < lfs.h.patch +remove_function binarize mindtct/binar.c +remove_function binarize_image mindtct/binar.c +remove_function isobinarize mindtct/binar.c +remove_function lfs_detect_minutiae mindtct/detect.c +remove_function bits_6to8 mindtct/imgutil.c +remove_function bozorth_main bozorth3/bz_drvrs.c +remove_function bz_load bozorth3/bz_io.c +remove_function bz_prune bozorth3/bz_io.c +remove_function get_next_file bozorth3/bz_io.c +remove_function get_score_filename bozorth3/bz_io.c +remove_function get_score_line bozorth3/bz_io.c +remove_function parse_line_range bozorth3/bz_io.c +remove_function set_gallery_filename bozorth3/bz_io.c +remove_function set_probe_filename bozorth3/bz_io.c +remove_function set_progname bozorth3/bz_io.c +remove_function detect_minutiae mindtct/minutia.c +remove_function dump_minutiae_pts mindtct/minutia.c +remove_function dump_minutiae mindtct/minutia.c +remove_function dump_reliable_minutiae_pts mindtct/minutia.c +remove_function scan4minutiae mindtct/minutia.c +remove_function scan4minutiae_horizontally mindtct/minutia.c +remove_function scan4minutiae_vertically mindtct/minutia.c +remove_function rescan4minutiae_horizontally mindtct/minutia.c +remove_function rescan4minutiae_vertically mindtct/minutia.c +remove_function process_horizontal_scan_minutia mindtct/minutia.c +remove_function process_vertical_scan_minutia mindtct/minutia.c +remove_function get_nbr_block_index mindtct/minutia.c +remove_function join_minutia mindtct/minutia.c +remove_function rescan_partial_horizontally mindtct/minutia.c +remove_function rescan_partial_vertically mindtct/minutia.c +remove_function adjust_high_curvature_minutia mindtct/minutia.c +remove_function adjust_horizontal_rescan mindtct/minutia.c +remove_function adjust_vertical_rescan mindtct/minutia.c +remove_function dump_shape mindtct/shape.c +remove_function flood_loop mindtct/loop.c +remove_function get_loop_list mindtct/loop.c +remove_function process_loop mindtct/loop.c +remove_function gen_imap mindtct/maps.c +remove_function gen_nmap mindtct/maps.c +remove_function gen_initial_imap mindtct/maps.c +remove_function smooth_imap mindtct/maps.c +remove_function get_max_padding mindtct/init.c +remove_function lfs2m1_minutia_XYT mindtct/xytreps.c +remove_function lfs2nist_format mindtct/xytreps.c +remove_function malloc_or_exit bozorth3/bz_alloc.c +remove_function malloc_or_return_error bozorth3/bz_alloc.c +remove_function reliability_fr_quality_map mindtct/quality.c +remove_function remove_false_minutia mindtct/remove.c +remove_function remove_pores mindtct/remove.c +remove_function remove_pointing_invblock mindtct/remove.c +remove_function remove_hooks_islands_lakes_overlaps mindtct/remove.c +remove_function remove_near_invblock mindtct/remove.c +remove_function remove_or_adjust_side_minutiae mindtct/remove.c +remove_function sort_quality_decreasing bozorth3/bz_sort.c +remove_function sort_order_decreasing bozorth3/bz_sort.c +remove_function qsort_decreasing bozorth3/bz_sort.c +remove_function partition_dec bozorth3/bz_sort.c +remove_function popstack bozorth3/bz_sort.c +remove_function pushstack bozorth3/bz_sort.c +remove_function select_pivot bozorth3/bz_sort.c +remove_function sort_indices_double_inc mindtct/sort.c +remove_function link_minutiae mindtct/link.c +remove_function create_link_table mindtct/link.c +remove_function order_link_table mindtct/link.c +remove_function process_link_table mindtct/link.c +remove_function update_link_table mindtct/link.c +remove_function link_score mindtct/link.c +remove_function remove_from_int_list mindtct/util.c + +# Remove trailing spaces +sed -i 's/[ \t]*$//' `find -name "*.[ch]"` + +# Remove usebsd.h +sed -i '/usebsd.h/d' `find -name "*.[ch]"` + diff --git a/meson.build b/meson.build index c5c691d4..db5008f1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '0.8.2', + version: '0.99.0', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', @@ -52,8 +52,12 @@ if drivers == [ 'all' ] drivers = all_drivers endif -nss_dep = [] -imaging_dep = [] +if drivers.length() == 0 or drivers[0] == '' + error('Cannot build libfprint without drivers, please specify a valid value for the drivers option') +endif + +nss_dep = dependency('', required: false) +imaging_dep = dependency('', required: false) foreach driver: drivers if driver == 'uru4000' nss_dep = dependency('nss', required: false) @@ -107,6 +111,15 @@ if get_option('x11-examples') endif endif +if get_option('gtk-examples') + gnome = import('gnome') + + gtk_dep = dependency('gtk+-3.0', required: false) + if not gtk_dep.found() + error('GTK+ 3.x is required for GTK+ examples') + endif +endif + libfprint_conf.set('API_EXPORTED', '__attribute__((visibility("default")))') configure_file(output: 'config.h', configuration: libfprint_conf) @@ -116,6 +129,9 @@ if get_option('doc') gnome = import('gnome') subdir('doc') endif +if get_option('gtk-examples') + subdir('demo') +endif pkgconfig = import('pkgconfig') pkgconfig.generate( diff --git a/meson_options.txt b/meson_options.txt index f847bff0..3e63304b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -14,6 +14,10 @@ option('x11-examples', description: 'Whether to build X11 example applications', type: 'boolean', value: true) +option('gtk-examples', + description: 'Whether to build GTK+ example applications', + type: 'boolean', + value: true) option('doc', description: 'Whether to build the API documentation', type: 'boolean',